diff --git a/.github/workflows/matrix_build.yml b/.github/workflows/matrix_build.yml index 738a32ad..f33aee60 100644 --- a/.github/workflows/matrix_build.yml +++ b/.github/workflows/matrix_build.yml @@ -249,9 +249,6 @@ jobs: - platform: ak3916ev300 release: lite custom: onlyci - - platform: ak3918ev200 - release: lite - custom: onlyci - platform: ak3918ev300 release: lite custom: onlyci diff --git a/br-ext-chip-anyka/Config.in b/br-ext-chip-anyka/Config.in index a1df7188..834193cd 100644 --- a/br-ext-chip-anyka/Config.in +++ b/br-ext-chip-anyka/Config.in @@ -1,5 +1,4 @@ source "$BR2_EXTERNAL_ANYKA_PATH/linux/Config.ext.in" -source "$BR2_EXTERNAL_ANYKA_PATH/package/anyka-osdrv-ak3918ev200/Config.in" source "$BR2_EXTERNAL_ANYKA_PATH/package/anyka_patcher/Config.in" source "$BR2_EXTERNAL_ANYKA_PATH/package/aura-httpd/Config.in" source "$BR2_EXTERNAL_ANYKA_PATH/package/dropbear-openipc/Config.in" diff --git a/br-ext-chip-anyka/board/ak3918ev200/kernel/ak3918ev200.generic.config b/br-ext-chip-anyka/board/ak3918ev200/kernel/ak3918ev200.generic.config deleted file mode 100644 index ade9e5e8..00000000 --- a/br-ext-chip-anyka/board/ak3918ev200/kernel/ak3918ev200.generic.config +++ /dev/null @@ -1,1741 +0,0 @@ -# -# Automatically generated file; DO NOT EDIT. -# Linux/arm 3.4.35 Kernel Configuration -# -CONFIG_ARM=y -CONFIG_SYS_SUPPORTS_APM_EMULATION=y -CONFIG_GENERIC_GPIO=y -CONFIG_ARCH_USES_GETTIMEOFFSET=y -CONFIG_KTIME_SCALAR=y -CONFIG_HAVE_PROC_CPU=y -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_HAVE_LATENCYTOP_SUPPORT=y -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -CONFIG_HARDIRQS_SW_RESEND=y -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_ARCH_HAS_CPUFREQ=y -CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_VECTORS_BASE=0xffff0000 -# CONFIG_ARM_PATCH_PHYS_VIRT is not set -CONFIG_PHYS_OFFSET=0x81000000 -CONFIG_GENERIC_BUG=y -CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -CONFIG_HAVE_IRQ_WORK=y - -# -# General setup -# -# CONFIG_EXPERIMENTAL is not set -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 -CONFIG_CROSS_COMPILE="" -CONFIG_LOCALVERSION="" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_HAVE_KERNEL_GZIP=y -CONFIG_HAVE_KERNEL_LZMA=y -CONFIG_HAVE_KERNEL_XZ=y -CONFIG_HAVE_KERNEL_LZO=y -# CONFIG_KERNEL_GZIP is not set -# CONFIG_KERNEL_LZMA is not set -CONFIG_KERNEL_XZ=y -# CONFIG_KERNEL_LZO is not set -CONFIG_DEFAULT_HOSTNAME="(none)" -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y -# CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_FHANDLE is not set -# CONFIG_TASKSTATS is not set -# CONFIG_AUDIT is not set -CONFIG_HAVE_GENERIC_HARDIRQS=y - -# -# IRQ subsystem -# -CONFIG_GENERIC_HARDIRQS=y -CONFIG_GENERIC_IRQ_SHOW=y - -# -# RCU Subsystem -# -CONFIG_TINY_RCU=y -# CONFIG_PREEMPT_RCU is not set -# CONFIG_TREE_RCU_TRACE is not set -# CONFIG_IKCONFIG is not set -CONFIG_LOG_BUF_SHIFT=16 -# CONFIG_CGROUPS is not set -# CONFIG_CHECKPOINT_RESTORE is not set -# CONFIG_NAMESPACES is not set -# CONFIG_SCHED_AUTOGROUP is not set -# CONFIG_SYSFS_DEPRECATED is not set -# CONFIG_RELAY is not set -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_RD_GZIP=y -# CONFIG_RD_BZIP2 is not set -# CONFIG_RD_LZMA is not set -# CONFIG_RD_XZ is not set -# CONFIG_RD_LZO is not set -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSCTL=y -CONFIG_ANON_INODES=y -CONFIG_PANIC_TIMEOUT=0 -CONFIG_EXPERT=y -CONFIG_UID16=y -# CONFIG_SYSCTL_SYSCALL is not set -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL 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_SIGNALFD=y -CONFIG_TIMERFD=y -CONFIG_EVENTFD=y -# CONFIG_SHMEM is not set -CONFIG_AIO=y -CONFIG_EMBEDDED=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_PERF_USE_VMALLOC=y - -# -# Kernel Performance Events And Counters -# -# CONFIG_PERF_EVENTS is not set -# CONFIG_PERF_COUNTERS is not set -# CONFIG_VM_EVENT_COUNTERS is not set -# CONFIG_SLUB_DEBUG is not set -CONFIG_COMPAT_BRK=y -# CONFIG_SLAB is not set -CONFIG_SLUB=y -# CONFIG_SLOB is not set -# CONFIG_PROFILING is not set -CONFIG_HAVE_OPROFILE=y -# CONFIG_KPROBES is not set -CONFIG_JUMP_LABEL=y -CONFIG_HAVE_KPROBES=y -CONFIG_HAVE_KRETPROBES=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y - -# -# GCOV-based kernel profiling -# -CONFIG_HAVE_GENERIC_DMA_COHERENT=y -CONFIG_RT_MUTEXES=y -CONFIG_BASE_SMALL=0 -CONFIG_MODULES=y -# CONFIG_MODULE_FORCE_LOAD is not set -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -CONFIG_BLOCK=y -# CONFIG_LBDAF is not set -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_BLK_DEV_BSGLIB is not set -# CONFIG_BLK_DEV_INTEGRITY is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_DEADLINE is not set -CONFIG_IOSCHED_CFQ=y -CONFIG_DEFAULT_CFQ=y -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="cfq" -# CONFIG_INLINE_SPIN_TRYLOCK is not set -# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -# CONFIG_INLINE_SPIN_LOCK is not set -# CONFIG_INLINE_SPIN_LOCK_BH is not set -# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -# CONFIG_INLINE_READ_TRYLOCK is not set -# CONFIG_INLINE_READ_LOCK is not set -# CONFIG_INLINE_READ_LOCK_BH is not set -# CONFIG_INLINE_READ_LOCK_IRQ is not set -# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y -# CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y -# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -# CONFIG_INLINE_WRITE_TRYLOCK is not set -# CONFIG_INLINE_WRITE_LOCK is not set -# CONFIG_INLINE_WRITE_LOCK_BH is not set -# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y -# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -# CONFIG_MUTEX_SPIN_ON_OWNER is not set -CONFIG_FREEZER=y - -# -# System Type -# -CONFIG_MMU=y -# CONFIG_ARCH_INTEGRATOR is not set -# CONFIG_ARCH_REALVIEW is not set -# CONFIG_ARCH_VERSATILE is not set -# CONFIG_ARCH_VEXPRESS is not set -# CONFIG_ARCH_AT91 is not set -# CONFIG_ARCH_BCMRING is not set -# CONFIG_ARCH_HIGHBANK is not set -# CONFIG_ARCH_CLPS711X is not set -# CONFIG_ARCH_CNS3XXX is not set -# CONFIG_ARCH_GEMINI is not set -# CONFIG_ARCH_PRIMA2 is not set -# CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_EP93XX is not set -# CONFIG_ARCH_FOOTBRIDGE is not set -# CONFIG_ARCH_MXC is not set -# CONFIG_ARCH_MXS is not set -# CONFIG_ARCH_NETX is not set -# CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_IOP13XX is not set -# CONFIG_ARCH_IOP32X is not set -# CONFIG_ARCH_IOP33X is not set -# CONFIG_ARCH_IXP23XX is not set -# CONFIG_ARCH_IXP2000 is not set -# CONFIG_ARCH_IXP4XX is not set -# CONFIG_ARCH_DOVE is not set -# CONFIG_ARCH_KIRKWOOD is not set -# CONFIG_ARCH_LPC32XX is not set -# CONFIG_ARCH_MV78XX0 is not set -# CONFIG_ARCH_ORION5X is not set -# CONFIG_ARCH_MMP is not set -# CONFIG_ARCH_KS8695 is not set -# CONFIG_ARCH_W90X900 is not set -# CONFIG_ARCH_TEGRA is not set -# CONFIG_ARCH_PICOXCELL is not set -# CONFIG_ARCH_PNX4008 is not set -# CONFIG_ARCH_PXA is not set -# CONFIG_ARCH_MSM is not set -# CONFIG_ARCH_SHMOBILE is not set -# CONFIG_ARCH_RPC is not set -# CONFIG_ARCH_SA1100 is not set -# CONFIG_ARCH_S3C24XX is not set -# CONFIG_ARCH_S3C64XX is not set -# CONFIG_ARCH_S5P64X0 is not set -# CONFIG_ARCH_S5PC100 is not set -# CONFIG_ARCH_S5PV210 is not set -# CONFIG_ARCH_EXYNOS is not set -# CONFIG_ARCH_SHARK is not set -# CONFIG_ARCH_U300 is not set -# CONFIG_ARCH_U8500 is not set -# CONFIG_ARCH_NOMADIK is not set -# CONFIG_ARCH_DAVINCI is not set -# CONFIG_ARCH_OMAP is not set -# CONFIG_PLAT_SPEAR is not set -# CONFIG_ARCH_VT8500 is not set -# CONFIG_ARCH_ZYNQ is not set -CONFIG_ARCH_AK39=y -# CONFIG_GPIO_PCA953X is not set -# CONFIG_KEYBOARD_GPIO_POLLED is not set - -# -# System MMU -# -CONFIG_CPU_AK3918=y -# CONFIG_ARCH_SDK3910 is not set -# CONFIG_ARCH_AIMER39_AK3916 is not set -CONFIG_ARCH_AIMER39_AK3918=y -CONFIG_ASIC_FREQ_VALUE=90000000 - -# -# Power management -# -# CONFIG_AK39_PM is not set -# CONFIG_AK39_PWM_TIMER is not set -CONFIG_PLAT_ANYKA=y - -# -# Processor Type -# -CONFIG_CPU_ARM926T=y -CONFIG_CPU_32v5=y -CONFIG_CPU_ABRT_EV5TJ=y -CONFIG_CPU_PABRT_LEGACY=y -CONFIG_CPU_CACHE_VIVT=y -CONFIG_CPU_COPY_V4WB=y -CONFIG_CPU_TLB_V4WBI=y -CONFIG_CPU_CP15=y -CONFIG_CPU_CP15_MMU=y -CONFIG_CPU_USE_DOMAINS=y - -# -# Processor Features -# -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -# CONFIG_ARM_THUMB is not set -# CONFIG_CPU_ICACHE_DISABLE is not set -# CONFIG_CPU_DCACHE_DISABLE is not set -# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -# CONFIG_CPU_CACHE_ROUND_ROBIN is not set -# CONFIG_CACHE_L2X0 is not set -CONFIG_ARM_L1_CACHE_SHIFT=5 -CONFIG_ARM_NR_BANKS=8 -# CONFIG_FIQ_DEBUGGER is not set - -# -# Bus support -# -# CONFIG_PCI_SYSCALL is not set -# CONFIG_ARCH_SUPPORTS_MSI is not set -# CONFIG_PCCARD is not set - -# -# Kernel Features -# -CONFIG_VMSPLIT_3G=y -# CONFIG_VMSPLIT_2G is not set -# CONFIG_VMSPLIT_1G is not set -CONFIG_PAGE_OFFSET=0xC0000000 -CONFIG_ARCH_NR_GPIO=0 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_HZ=100 -CONFIG_AEABI=y -# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -CONFIG_HAVE_ARCH_PFN_VALID=y -# CONFIG_HIGHMEM is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -CONFIG_HAVE_MEMBLOCK=y -CONFIG_PAGEFLAGS_EXTENDED=y -CONFIG_SPLIT_PTLOCK_CPUS=999999 -# CONFIG_COMPACTION is not set -# CONFIG_PHYS_ADDR_T_64BIT is not set -CONFIG_ZONE_DMA_FLAG=0 -CONFIG_VIRT_TO_BUS=y -# CONFIG_KSM is not set -CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -CONFIG_NEED_PER_CPU_KM=y -# CONFIG_CLEANCACHE is not set -CONFIG_FORCE_MAX_ZONEORDER=11 -CONFIG_ALIGNMENT_TRAP=y -# CONFIG_SECCOMP is not set -# CONFIG_DEPRECATED_PARAM_STRUCT is not set -CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y - -# -# Boot options -# -# CONFIG_USE_OF is not set -CONFIG_ZBOOT_ROM_TEXT=0 -CONFIG_ZBOOT_ROM_BSS=0 -CONFIG_CMDLINE="" -# CONFIG_XIP_KERNEL is not set -# CONFIG_AUTO_ZRELADDR is not set -CONFIG_RAM_BASE=0x80000000 -CONFIG_VIDEO_RESERVED_MEM_SIZE=0x1000000 - -# -# CPU Power Management -# - -# -# CPU Frequency scaling -# -# CONFIG_CPU_FREQ is not set -# CONFIG_CPU_IDLE is not set -# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set - -# -# Floating point emulation -# - -# -# At least one emulation must be selected -# -# CONFIG_VFP is not set - -# -# Userspace binary formats -# -CONFIG_BINFMT_ELF=y -CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -CONFIG_HAVE_AOUT=y -# CONFIG_BINFMT_AOUT is not set -# CONFIG_BINFMT_MISC is not set - -# -# Power management options -# -CONFIG_SUSPEND=y -CONFIG_SUSPEND_FREEZER=y -CONFIG_HAS_WAKELOCK=y -CONFIG_WAKELOCK=y -CONFIG_PM_SLEEP=y -# CONFIG_PM_AUTOSLEEP is not set -# CONFIG_PM_WAKELOCKS is not set -# CONFIG_PM_RUNTIME is not set -CONFIG_PM=y -# CONFIG_PM_DEBUG is not set -# CONFIG_APM_EMULATION is not set -CONFIG_PM_CLK=y -CONFIG_CPU_PM=y -# CONFIG_SUSPEND_TIME is not set -CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARM_CPU_SUSPEND=y -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_UNIX_DIAG=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE_DEMUX is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -CONFIG_INET_LRO=y -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -CONFIG_INET_UDP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_CUBIC=y -CONFIG_DEFAULT_TCP_CONG="cubic" -CONFIG_IPV6=y -# CONFIG_IPV6_PRIVACY is not set -# CONFIG_IPV6_ROUTER_PREF is not set -# CONFIG_INET6_AH is not set -# CONFIG_INET6_ESP is not set -# CONFIG_INET6_IPCOMP is not set -# CONFIG_INET6_XFRM_TUNNEL is not set -# CONFIG_INET6_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set -# CONFIG_IPV6_SIT is not set -# CONFIG_IPV6_TUNNEL is not set -# CONFIG_ANDROID_PARANOID_NETWORK is not set -CONFIG_NET_ACTIVITY_STATS=y -# CONFIG_NETWORK_SECMARK is not set -# CONFIG_NETFILTER is not set -# CONFIG_ATM is not set -# CONFIG_L2TP is not set -CONFIG_BRIDGE=y -# 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_PHONET is not set -# CONFIG_NET_SCHED is not set -# CONFIG_DCB is not set -# CONFIG_BATMAN_ADV is not set -# CONFIG_OPENVSWITCH is not set -CONFIG_BQL=y -CONFIG_HAVE_BPF_JIT=y -# CONFIG_BPF_JIT is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_HAMRADIO is not set -# CONFIG_CAN is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_WIRELESS=y -CONFIG_WEXT_CORE=y -CONFIG_WEXT_PROC=y -CONFIG_CFG80211=m -# CONFIG_NL80211_TESTMODE is not set -# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -# CONFIG_CFG80211_REG_DEBUG is not set -CONFIG_CFG80211_DEFAULT_PS=y -# CONFIG_CFG80211_INTERNAL_REGDB is not set -CONFIG_CFG80211_WEXT=y -CONFIG_WIRELESS_EXT_SYSFS=y -CONFIG_LIB80211=y -# CONFIG_LIB80211_DEBUG is not set -CONFIG_CFG80211_ALLOW_RECONNECT=y -CONFIG_MAC80211=m -CONFIG_MAC80211_HAS_RC=y -# CONFIG_MAC80211_RC_PID is not set -CONFIG_MAC80211_RC_MINSTREL=y -CONFIG_MAC80211_RC_MINSTREL_HT=y -CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -# CONFIG_MAC80211_LEDS is not set -# CONFIG_MAC80211_DEBUG_MENU is not set -# CONFIG_WIMAX is not set -# CONFIG_RFKILL is not set -# CONFIG_NET_9P is not set -# CONFIG_CAIF is not set - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=y -CONFIG_FIRMWARE_IN_KERNEL=y -CONFIG_EXTRA_FIRMWARE="" -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_SYS_HYPERVISOR is not set -# CONFIG_GENERIC_CPU_DEVICES is not set -CONFIG_DMA_SHARED_BUFFER=y -# CONFIG_SYNC is not set -# CONFIG_CONNECTOR is not set -CONFIG_MTD=y -# CONFIG_MTD_TESTS is not set -# CONFIG_MTD_REDBOOT_PARTS is not set -CONFIG_MTD_CMDLINE_PARTS=y -# CONFIG_MTD_AFS_PARTS is not set -# CONFIG_MTD_AR7_PARTS is not set - -# -# User Modules And Translation Layers -# -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLKDEVS=y -CONFIG_MTD_BLOCK=y -# CONFIG_FTL is not set -# CONFIG_NFTL is not set -# CONFIG_INFTL is not set -# CONFIG_RFD_FTL is not set -# CONFIG_SSFDC is not set -# CONFIG_MTD_OOPS is not set - -# -# RAM/ROM/Flash chip drivers -# -# CONFIG_MTD_CFI is not set -# CONFIG_MTD_JEDECPROBE is not set -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y -# CONFIG_MTD_CFI_I4 is not set -# CONFIG_MTD_CFI_I8 is not set -# CONFIG_MTD_RAM is not set -# CONFIG_MTD_ROM is not set -# CONFIG_MTD_ABSENT is not set - -# -# Mapping drivers for chip access -# -# CONFIG_MTD_COMPLEX_MAPPINGS is not set -# CONFIG_MTD_PLATRAM is not set - -# -# Self-contained MTD device drivers -# -# CONFIG_MTD_SST25L 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_DOCG3 is not set -CONFIG_MTD_AK_SPIFLASH=y -# CONFIG_MTD_NAND_IDS is not set -# CONFIG_MTD_NAND is not set -# CONFIG_MTD_ONENAND is not set - -# -# LPDDR flash memory drivers -# -# CONFIG_MTD_LPDDR is not set -# CONFIG_MTD_UBI is not set -# CONFIG_PARPORT is not set -CONFIG_BLK_DEV=y -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -# CONFIG_BLK_DEV_CRYPTOLOOP is not set - -# -# DRBD disabled because PROC_FS, INET or CONNECTOR not selected -# -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_UB is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -# CONFIG_BLK_DEV_XIP is not set -# CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set -# CONFIG_MG_DISK is not set - -# -# Misc devices -# -# CONFIG_SENSORS_LIS3LV02D is not set -# CONFIG_AD525X_DPOT is not set -# CONFIG_ATMEL_PWM is not set -# CONFIG_ENCLOSURE_SERVICES is not set -# CONFIG_APDS9802ALS is not set -# CONFIG_ISL29003 is not set -# CONFIG_ISL29020 is not set -# CONFIG_SENSORS_TSL2550 is not set -# CONFIG_SENSORS_BH1780 is not set -# CONFIG_SENSORS_BH1770 is not set -# CONFIG_SENSORS_APDS990X is not set -# CONFIG_HMC6352 is not set -# CONFIG_SENSORS_AK8975 is not set -# CONFIG_TI_DAC7512 is not set -# CONFIG_UID_STAT is not set -# CONFIG_BMP085 is not set -# CONFIG_USB_SWITCH_FSA9480 is not set -CONFIG_AK_SERIAL_NUMBER=y -CONFIG_AK_MOTOR=y - -# -# user space generic gpio controller -# -CONFIG_GPIOS_AKCUSTOM=y - -# -# EEPROM support -# -# CONFIG_EEPROM_AT24 is not set -# CONFIG_EEPROM_AT25 is not set -# CONFIG_EEPROM_LEGACY is not set -# CONFIG_EEPROM_93CX6 is not set -# CONFIG_EEPROM_93XX46 is not set - -# -# Texas Instruments shared transport line discipline -# -# CONFIG_TI_ST is not set -# CONFIG_SENSORS_LIS3_SPI is not set -# CONFIG_SENSORS_LIS3_I2C is not set - -# -# Altera FPGA firmware download module -# -# CONFIG_ALTERA_STAPL is not set - -# -# SCSI device support -# -CONFIG_SCSI_MOD=y -# CONFIG_RAID_ATTRS is not set -CONFIG_SCSI=y -CONFIG_SCSI_DMA=y -# CONFIG_SCSI_NETLINK is not set -# CONFIG_SCSI_PROC_FS is not set - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set -# CONFIG_CHR_DEV_SCH is not set -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set -# CONFIG_SCSI_SCAN_ASYNC is not set -# CONFIG_SCSI_WAIT_SCAN is not set - -# -# SCSI Transports -# -# CONFIG_SCSI_SPI_ATTRS is not set -# CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set -# CONFIG_SCSI_SAS_LIBSAS is not set -# CONFIG_SCSI_SRP_ATTRS is not set -# CONFIG_SCSI_LOWLEVEL is not set -# CONFIG_SCSI_DH is not set -# CONFIG_SCSI_OSD_INITIATOR is not set -# CONFIG_ATA is not set -# CONFIG_MD is not set -# CONFIG_TARGET_CORE is not set -CONFIG_NETDEVICES=y -CONFIG_NET_CORE=y -# CONFIG_BONDING is not set -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -# CONFIG_MII is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -CONFIG_TUN=m -# CONFIG_VETH is not set - -# -# CAIF transport drivers -# -CONFIG_ETHERNET=y -# CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_NET_CALXEDA_XGMAC is not set -# CONFIG_NET_VENDOR_CHELSIO is not set -# CONFIG_NET_VENDOR_CIRRUS is not set -# CONFIG_DM9000 is not set -# CONFIG_DNET is not set -# CONFIG_NET_VENDOR_FARADAY is not set -# CONFIG_NET_VENDOR_INTEL is not set -# CONFIG_NET_VENDOR_MARVELL is not set -# CONFIG_NET_VENDOR_MICREL is not set -# CONFIG_NET_VENDOR_NATSEMI is not set -# CONFIG_ETHOC is not set -# CONFIG_NET_VENDOR_SMSC is not set -# CONFIG_NET_VENDOR_STMICRO is not set -CONFIG_AK_ETHERNET=y -# CONFIG_PHYLIB is not set -# CONFIG_MICREL_KS8995MA is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# USB Network Adapters -# -# CONFIG_USB_KAWETH is not set -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_USBNET is not set -# CONFIG_USB_IPHETH is not set -# CONFIG_WLAN is not set - -# -# Enable WiMAX (Networking options) to see the WiMAX drivers -# -# CONFIG_WAN is not set -# CONFIG_ISDN is not set - -# -# Input device support -# -CONFIG_INPUT=y -# CONFIG_INPUT_FF_MEMLESS is not set -# CONFIG_INPUT_POLLDEV is not set -# CONFIG_INPUT_SPARSEKMAP is not set - -# -# Userland interfaces -# -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_EVBUG is not set -# CONFIG_INPUT_KEYRESET is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -# CONFIG_KEYBOARD_ADP5588 is not set -# CONFIG_KEYBOARD_ADP5589 is not set -# CONFIG_KEYBOARD_ATKBD is not set -# CONFIG_KEYBOARD_QT1070 is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_GPIO is not set -# CONFIG_KEYBOARD_TCA6416 is not set -# CONFIG_KEYBOARD_TCA8418 is not set -# CONFIG_KEYBOARD_MATRIX is not set -# CONFIG_KEYBOARD_LM8323 is not set -# CONFIG_KEYBOARD_MAX7359 is not set -# CONFIG_KEYBOARD_MCS is not set -# CONFIG_KEYBOARD_MPR121 is not set -# CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_OPENCORES is not set -# CONFIG_KEYBOARD_SAMSUNG is not set -# CONFIG_KEYBOARD_STOWAWAY is not set -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_OMAP4 is not set -# CONFIG_KEYBOARD_XTKBD is not set -CONFIG_KEYBOARD_AKKEY=y -# CONFIG_KEYBOARD_AK_KEYPAD is not set -# CONFIG_KEYBOARD_ADKEY is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TABLET is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -# CONFIG_SERIO is not set -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -# CONFIG_VT is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_TRACE_SINK is not set -CONFIG_DEVMEM=y -# CONFIG_DEVKMEM is not set - -# -# Serial drivers -# -# CONFIG_SERIAL_8250 is not set - -# -# Non-8250 serial port support -# -# CONFIG_SERIAL_MAX3100 is not set -# CONFIG_SERIAL_MAX3107 is not set -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -# CONFIG_SERIAL_TIMBERDALE is not set -# CONFIG_SERIAL_ALTERA_JTAGUART is not set -# CONFIG_SERIAL_ALTERA_UART is not set -# CONFIG_SERIAL_XILINX_PS_UART is not set -CONFIG_SERIAL_AK39_UART=y -CONFIG_SERIAL_AK39_CONSOLE=y -# CONFIG_SERIAL_GPIO_UART is not set -CONFIG_TTY_PRINTK=y -# CONFIG_HVC_DCC is not set -# CONFIG_IPMI_HANDLER is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_R3964 is not set -# CONFIG_RAW_DRIVER is not set -# CONFIG_TCG_TPM is not set -# CONFIG_DCC_TTY is not set -# CONFIG_RAMOOPS is not set -CONFIG_I2C=y -CONFIG_I2C_BOARDINFO=y -CONFIG_I2C_COMPAT=y -# CONFIG_I2C_CHARDEV is not set -# CONFIG_I2C_HELPER_AUTO is not set -CONFIG_I2C_SMBUS=y - -# -# I2C Algorithms -# -CONFIG_I2C_ALGOBIT=y -# CONFIG_I2C_ALGOPCF is not set -# CONFIG_I2C_ALGOPCA is not set - -# -# I2C Hardware Bus support -# - -# -# I2C system bus drivers (mostly embedded / system-on-chip) -# -# CONFIG_I2C_DESIGNWARE_PLATFORM is not set -# CONFIG_I2C_GPIO is not set -# CONFIG_I2C_PCA_PLATFORM is not set -# CONFIG_I2C_PXA_PCI is not set -# CONFIG_I2C_SIMTEC is not set -CONFIG_I2C_ANYKA=y -CONFIG_I2C_AK39_HW=y -# CONFIG_I2C_GPIO_SOFT is not set - -# -# External I2C/SMBus adapter drivers -# -# CONFIG_I2C_DIOLAN_U2C is not set -# CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_TINY_USB is not set - -# -# Other I2C/SMBus bus drivers -# -# CONFIG_I2C_DEBUG_CORE is not set -# CONFIG_I2C_DEBUG_ALGO is not set -# CONFIG_I2C_DEBUG_BUS is not set -CONFIG_SPI=y -# CONFIG_SPI_DEBUG is not set -CONFIG_SPI_MASTER=y - -# -# SPI Master Controller Drivers -# -# CONFIG_SPI_ALTERA is not set -CONFIG_SPI_BITBANG=y -# CONFIG_SPI_GPIO is not set -# CONFIG_SPI_OC_TINY is not set -# CONFIG_SPI_PXA2XX_PCI is not set -CONFIG_SPI_ANYKA=y -# CONFIG_SPI_DESIGNWARE is not set - -# -# SPI Protocol Masters -# -# CONFIG_SPI_TLE62X0 is not set -# CONFIG_HSI is not set - -# -# PPS support -# - -# -# PPS generators support -# - -# -# PTP clock support -# - -# -# Enable Device Drivers -> PPS to see the PTP clock options. -# -CONFIG_ARCH_REQUIRE_GPIOLIB=y -CONFIG_GPIOLIB=y -# CONFIG_DEBUG_GPIO is not set - -# -# Memory mapped GPIO drivers: -# -# CONFIG_GPIO_GENERIC_PLATFORM is not set - -# -# I2C GPIO expanders: -# -# CONFIG_GPIO_MAX7300 is not set -# CONFIG_GPIO_MAX732X is not set -# CONFIG_GPIO_PCF857X is not set -# CONFIG_GPIO_SX150X is not set -# CONFIG_GPIO_ADP5588 is not set - -# -# PCI GPIO expanders: -# - -# -# SPI GPIO expanders: -# -# CONFIG_GPIO_MAX7301 is not set -# CONFIG_GPIO_MCP23S08 is not set -# CONFIG_GPIO_MC33880 is not set -# CONFIG_GPIO_74X164 is not set - -# -# AC97 GPIO expanders: -# - -# -# MODULbus GPIO expanders: -# -# CONFIG_W1 is not set -CONFIG_POWER_SUPPLY=y -# CONFIG_POWER_SUPPLY_DEBUG is not set -# CONFIG_PDA_POWER is not set -# CONFIG_TEST_POWER is not set -# CONFIG_BATTERY_DS2780 is not set -# CONFIG_BATTERY_DS2781 is not set -# CONFIG_BATTERY_DS2782 is not set -# CONFIG_BATTERY_SBS is not set -# CONFIG_BATTERY_BQ27x00 is not set -# CONFIG_BATTERY_MAX17040 is not set -# CONFIG_BATTERY_MAX17042 is not set -# CONFIG_BATTERY_ANDROID is not set -# CONFIG_CHARGER_MAX8903 is not set -# CONFIG_CHARGER_LP8727 is not set -# CONFIG_CHARGER_GPIO is not set -# CONFIG_CHARGER_SMB347 is not set -# CONFIG_BATTERY_AK is not set -# CONFIG_HWMON is not set -# CONFIG_THERMAL is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_CORE=y -# CONFIG_WATCHDOG_NOWAYOUT is not set - -# -# Watchdog Device Drivers -# -# CONFIG_SOFT_WATCHDOG is not set -# CONFIG_DW_WATCHDOG is not set -# CONFIG_MAX63XX_WATCHDOG is not set -CONFIG_AK39_WATCHDOG=y - -# -# USB-based Watchdog Cards -# -# CONFIG_USBPCWATCHDOG is not set -CONFIG_SSB_POSSIBLE=y - -# -# Sonics Silicon Backplane -# -# CONFIG_SSB is not set -CONFIG_BCMA_POSSIBLE=y - -# -# Broadcom specific AMBA -# -# CONFIG_BCMA is not set - -# -# Multifunction device drivers -# -# CONFIG_MFD_CORE is not set -# CONFIG_MFD_88PM860X is not set -# CONFIG_MFD_SM501 is not set -# CONFIG_MFD_ASIC3 is not set -# CONFIG_HTC_EGPIO is not set -# CONFIG_HTC_PASIC3 is not set -# CONFIG_HTC_I2CPLD is not set -# CONFIG_TPS6105X is not set -# CONFIG_TPS65010 is not set -# CONFIG_TPS6507X is not set -# CONFIG_MFD_TPS65217 is not set -# CONFIG_MFD_TPS6586X is not set -# CONFIG_MFD_TPS65910 is not set -# CONFIG_MFD_TPS65912_I2C is not set -# CONFIG_MFD_TPS65912_SPI is not set -# CONFIG_TWL4030_CORE is not set -# CONFIG_TWL6040_CORE is not set -# CONFIG_MFD_STMPE is not set -# CONFIG_MFD_TC3589X is not set -# CONFIG_MFD_TMIO is not set -# CONFIG_MFD_T7L66XB is not set -# CONFIG_MFD_TC6387XB is not set -# CONFIG_MFD_TC6393XB is not set -# CONFIG_PMIC_DA903X is not set -# CONFIG_MFD_DA9052_SPI is not set -# CONFIG_MFD_DA9052_I2C is not set -# CONFIG_PMIC_ADP5520 is not set -# CONFIG_MFD_MAX8925 is not set -# CONFIG_MFD_MAX8997 is not set -# CONFIG_MFD_MAX8998 is not set -# CONFIG_MFD_S5M_CORE is not set -# CONFIG_MFD_WM8400 is not set -# CONFIG_MFD_WM831X_I2C is not set -# CONFIG_MFD_WM831X_SPI is not set -# CONFIG_MFD_WM8350_I2C is not set -# CONFIG_MFD_WM8994 is not set -# CONFIG_MFD_PCF50633 is not set -# CONFIG_MFD_MC13XXX is not set -# CONFIG_ABX500_CORE is not set -# CONFIG_EZX_PCAP is not set -# CONFIG_MFD_WL1273_CORE is not set -# CONFIG_MFD_TPS65090 is not set -# CONFIG_MFD_AAT2870_CORE is not set -# CONFIG_MFD_RC5T583 is not set -# CONFIG_REGULATOR is not set -# CONFIG_MEDIA_SUPPORT is not set - -# -# Graphics support -# -# CONFIG_DRM is not set -CONFIG_ION=y -CONFIG_ION_AK=m -# CONFIG_VGASTATE is not set -# CONFIG_VIDEO_OUTPUT_CONTROL is not set -# CONFIG_FB is not set -# CONFIG_EXYNOS_VIDEO is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -# CONFIG_SOUND is not set -# CONFIG_HID_SUPPORT is not set -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB_ARCH_HAS_EHCI is not set -# CONFIG_USB_ARCH_HAS_XHCI is not set -CONFIG_USB_SUPPORT=y -CONFIG_USB_COMMON=y -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB=y -# CONFIG_USB_DEBUG is not set -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y - -# -# Miscellaneous USB options -# -# CONFIG_USB_DEVICEFS is not set -# CONFIG_USB_DEVICE_CLASS is not set -# CONFIG_USB_DYNAMIC_MINORS is not set -# CONFIG_USB_OTG_WHITELIST is not set -# CONFIG_USB_OTG_BLACKLIST_HUB is not set -# CONFIG_USB_DWC3 is not set -# CONFIG_USB_MON is not set -# CONFIG_USB_WUSB_CBAF is not set - -# -# USB Host Controller Drivers -# -# CONFIG_USB_C67X00_HCD is not set -# CONFIG_USB_OXU210HP_HCD is not set -# CONFIG_USB_ISP116X_HCD is not set -# CONFIG_USB_ISP1362_HCD is not set -# CONFIG_USB_SL811_HCD is not set -# CONFIG_USB_R8A66597_HCD is not set -CONFIG_USB_ANYKA_HCD=y -CONFIG_USB_AKOTG_HS_HCD=m -# CONFIG_USB_AKOTG_DMA is not set -# CONFIG_USB_MUSB_HDRC is not set -# CONFIG_USB_RENESAS_USBHS is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set -# CONFIG_USB_WDM is not set -# CONFIG_USB_TMC is not set - -# -# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -# - -# -# also be needed; see USB_STORAGE Help for more info -# -CONFIG_USB_STORAGE=y -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_REALTEK is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_USBAT is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_SDDR55 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_STORAGE_ALAUDA is not set -# CONFIG_USB_STORAGE_ONETOUCH is not set -# CONFIG_USB_STORAGE_KARMA is not set -# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set -# CONFIG_USB_STORAGE_ENE_UB6250 is not set -# CONFIG_USB_LIBUSUAL is not set - -# -# USB Imaging devices -# -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_MICROTEK is not set - -# -# USB port drivers -# -# 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_SEVSEG 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_IDMOUSE is not set -# CONFIG_USB_FTDI_ELAN is not set -# CONFIG_USB_APPLEDISPLAY is not set -# CONFIG_USB_LD is not set -# CONFIG_USB_TRANCEVIBRATOR is not set -# CONFIG_USB_IOWARRIOR is not set -# CONFIG_USB_TEST is not set -# CONFIG_USB_ISIGHTFW is not set -# CONFIG_USB_YUREX is not set -CONFIG_USB_GADGET=y -# CONFIG_USB_GADGET_DEBUG is not set -# CONFIG_USB_GADGET_DEBUG_FILES is not set -CONFIG_USB_GADGET_VBUS_DRAW=500 -CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -# CONFIG_USB_FUSB300 is not set -# CONFIG_USB_R8A66597 is not set -# CONFIG_USB_MV_UDC is not set -# CONFIG_USB_GADGET_AKUDC_PRODUCER is not set -CONFIG_USB_GADGET_AKUDC=y -CONFIG_USB_AKUDC=m -# CONFIG_USB_AKUDC_DEBUG_FS is not set -# CONFIG_USB_M66592 is not set -# CONFIG_USB_NET2272 is not set -# CONFIG_USB_DUMMY_HCD is not set -CONFIG_USB_GADGET_DUALSPEED=y -# CONFIG_USB_ZERO is not set -# CONFIG_USB_ETH is not set -# CONFIG_USB_G_NCM is not set -# CONFIG_USB_FILE_STORAGE is not set -CONFIG_USB_MASS_STORAGE=m -# CONFIG_USB_G_SERIAL is not set -# CONFIG_USB_G_PRINTER is not set -# CONFIG_USB_CDC_COMPOSITE is not set -# CONFIG_USB_G_ACM_MS is not set -# CONFIG_USB_G_MULTI is not set -# CONFIG_USB_G_HID is not set -# CONFIG_USB_G_DBGP is not set - -# -# OTG and related infrastructure -# -# CONFIG_USB_OTG_WAKELOCK is not set -# CONFIG_USB_GPIO_VBUS is not set -# CONFIG_USB_ULPI is not set -# CONFIG_NOP_USB_XCEIV is not set -CONFIG_MMC=y -# CONFIG_MMC_DEBUG is not set -# CONFIG_MMC_UNSAFE_RESUME is not set - -# -# MMC/SD/SDIO Card Drivers -# -CONFIG_MMC_BLOCK=y -CONFIG_MMC_BLOCK_MINORS=8 -# CONFIG_MMC_BLOCK_BOUNCE is not set -# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set -# CONFIG_SDIO_UART is not set -# CONFIG_MMC_TEST is not set -# CONFIG_SDIO_WIFI is not set - -# -# MMC/SD/SDIO Host Controller Drivers -# -# CONFIG_MMC_SDHCI is not set -# CONFIG_MMC_SDHCI_PXAV3 is not set -# CONFIG_MMC_SDHCI_PXAV2 is not set -# CONFIG_MMC_SPI is not set -# CONFIG_MMC_DW is not set -# CONFIG_MMC_VUB300 is not set -# CONFIG_MMC_USHC is not set -CONFIG_MMC_ANYKA=y -# CONFIG_MEMSTICK is not set -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y - -# -# LED drivers -# -# CONFIG_LEDS_LM3530 is not set -# CONFIG_LEDS_GPIO is not set -# CONFIG_LEDS_LP3944 is not set -# CONFIG_LEDS_LP5521 is not set -# CONFIG_LEDS_LP5523 is not set -# CONFIG_LEDS_PCA955X is not set -# CONFIG_LEDS_PCA9633 is not set -# CONFIG_LEDS_DAC124S085 is not set -# CONFIG_LEDS_BD2802 is not set -CONFIG_LEDS_AK39=y -# CONFIG_LEDS_LT3593 is not set -# CONFIG_LEDS_RENESAS_TPU is not set -# CONFIG_LEDS_TCA6507 is not set -# CONFIG_LEDS_OT200 is not set -CONFIG_LEDS_TRIGGERS=y - -# -# LED Triggers -# -CONFIG_LEDS_TRIGGER_TIMER=y -# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set -# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set -# CONFIG_LEDS_TRIGGER_GPIO is not set -# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set - -# -# iptables trigger is under Netfilter config (LED target) -# -# CONFIG_SWITCH is not set -# CONFIG_ACCESSIBILITY is not set -CONFIG_RTC_LIB=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS=y -CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -# CONFIG_RTC_DEBUG is not set - -# -# RTC interfaces -# -CONFIG_RTC_INTF_SYSFS=y -CONFIG_RTC_INTF_PROC=y -CONFIG_RTC_INTF_DEV=y -# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -# CONFIG_RTC_DRV_TEST is not set - -# -# I2C RTC drivers -# -# CONFIG_RTC_DRV_DS1307 is not set -# CONFIG_RTC_DRV_DS1374 is not set -# CONFIG_RTC_DRV_DS1672 is not set -# CONFIG_RTC_DRV_DS3232 is not set -# CONFIG_RTC_DRV_MAX6900 is not set -# CONFIG_RTC_DRV_RS5C372 is not set -# CONFIG_RTC_DRV_ISL1208 is not set -# CONFIG_RTC_DRV_ISL12022 is not set -# CONFIG_RTC_DRV_X1205 is not set -# CONFIG_RTC_DRV_PCF8563 is not set -# CONFIG_RTC_DRV_PCF8583 is not set -# CONFIG_RTC_DRV_M41T80 is not set -# CONFIG_RTC_DRV_BQ32K is not set -# CONFIG_RTC_DRV_S35390A is not set -# CONFIG_RTC_DRV_FM3130 is not set -# CONFIG_RTC_DRV_RX8581 is not set -# CONFIG_RTC_DRV_RX8025 is not set -# CONFIG_RTC_DRV_EM3027 is not set -# CONFIG_RTC_DRV_RV3029C2 is not set - -# -# SPI RTC drivers -# -# CONFIG_RTC_DRV_M41T93 is not set -# CONFIG_RTC_DRV_M41T94 is not set -# CONFIG_RTC_DRV_DS1305 is not set -# CONFIG_RTC_DRV_DS1390 is not set -# CONFIG_RTC_DRV_MAX6902 is not set -# CONFIG_RTC_DRV_R9701 is not set -# CONFIG_RTC_DRV_RS5C348 is not set -# CONFIG_RTC_DRV_DS3234 is not set -# CONFIG_RTC_DRV_PCF2123 is not set - -# -# Platform RTC drivers -# -# CONFIG_RTC_DRV_CMOS is not set -# CONFIG_RTC_DRV_DS1286 is not set -# CONFIG_RTC_DRV_DS1511 is not set -# CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_DS1742 is not set -# CONFIG_RTC_DRV_STK17TA8 is not set -# CONFIG_RTC_DRV_M48T86 is not set -# CONFIG_RTC_DRV_M48T35 is not set -# CONFIG_RTC_DRV_M48T59 is not set -# CONFIG_RTC_DRV_MSM6242 is not set -# CONFIG_RTC_DRV_BQ4802 is not set -# CONFIG_RTC_DRV_RP5C01 is not set -# CONFIG_RTC_DRV_V3020 is not set - -# -# on-CPU RTC drivers -# -CONFIG_RTC_DRV_AK=y -# CONFIG_DMADEVICES is not set -# CONFIG_AUXDISPLAY is not set -CONFIG_UIO=y -# CONFIG_UIO_PDRV is not set -# CONFIG_UIO_PDRV_GENIRQ is not set -CONFIG_UIO_VCODEC=y - -# -# Virtio drivers -# -# CONFIG_VIRTIO_BALLOON is not set - -# -# Microsoft Hyper-V guest support -# -# CONFIG_STAGING is not set -CONFIG_CLKDEV_LOOKUP=y - -# -# Hardware Spinlock drivers -# -# CONFIG_IOMMU_SUPPORT is not set - -# -# Remoteproc drivers (EXPERIMENTAL) -# - -# -# Rpmsg drivers (EXPERIMENTAL) -# -# CONFIG_VIRT_DRIVERS is not set -# CONFIG_PM_DEVFREQ is not set - -# -# File systems -# -# CONFIG_EXT2_FS is not set -# CONFIG_EXT3_FS is not set -# CONFIG_EXT4_FS is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_XFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set -CONFIG_FILE_LOCKING=y -CONFIG_FSNOTIFY=y -CONFIG_DNOTIFY=y -CONFIG_INOTIFY_USER=y -# CONFIG_FANOTIFY is not set -# CONFIG_QUOTA is not set -# CONFIG_QUOTACTL is not set -# CONFIG_AUTOFS4_FS is not set -# CONFIG_FUSE_FS is not set -CONFIG_OVERLAYFS_FS=y - -# -# Caches -# -# CONFIG_FSCACHE is not set - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=m -# CONFIG_MSDOS_FS is not set -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_PROC_PAGE_MONITOR=y -CONFIG_SYSFS=y -# CONFIG_HUGETLB_PAGE is not set -# CONFIG_CONFIGFS_FS is not set -CONFIG_MISC_FILESYSTEMS=y -# CONFIG_HFSPLUS_FS is not set -# CONFIG_YAFFS_FS is not set -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_WRITEBUFFER is not set -# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set -CONFIG_JFFS2_ZLIB=y -# CONFIG_JFFS2_LZO is not set -CONFIG_JFFS2_RTIME=y -# CONFIG_JFFS2_RUBIN is not set -# CONFIG_CRAMFS is not set -CONFIG_SQUASHFS=y -# CONFIG_SQUASHFS_XATTR is not set -# CONFIG_SQUASHFS_ZLIB is not set -# CONFIG_SQUASHFS_LZO is not set -CONFIG_SQUASHFS_XZ=y -# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set -# CONFIG_SQUASHFS_EMBEDDED is not set -CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 -# CONFIG_VXFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_OMFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_QNX6FS_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_PSTORE is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set -CONFIG_NETWORK_FILESYSTEMS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_NFS_V3_ACL is not set -# CONFIG_NFS_V4 is not set -CONFIG_ROOT_NFS=y -# CONFIG_NFSD is not set -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_SUNRPC_DEBUG is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -CONFIG_NLS_ISO8859_1=y -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -CONFIG_NLS_UTF8=y - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -CONFIG_DEFAULT_MESSAGE_LOGLEVEL=3 -CONFIG_ENABLE_WARN_DEPRECATED=y -CONFIG_ENABLE_MUST_CHECK=y -CONFIG_FRAME_WARN=1024 -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_STRIP_ASM_SYMS is not set -# CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set -# CONFIG_HEADERS_CHECK is not set -# CONFIG_DEBUG_SECTION_MISMATCH is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_SHIRQ is not set -# CONFIG_LOCKUP_DETECTOR is not set -# CONFIG_HARDLOCKUP_DETECTOR_NMI is not set -# CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU is not set -# CONFIG_HARDLOCKUP_DETECTOR is not set -# CONFIG_DETECT_HUNG_TASK is not set -# CONFIG_SCHED_DEBUG is not set -# CONFIG_SCHEDSTATS is not set -# CONFIG_TIMER_STATS is not set -# CONFIG_DEBUG_OBJECTS is not set -# CONFIG_SLUB_STATS is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_LOCK_ALLOC is not set -# CONFIG_PROVE_LOCKING is not set -# CONFIG_SPARSE_RCU_POINTER is not set -# CONFIG_LOCK_STAT is not set -# CONFIG_DEBUG_ATOMIC_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_STACKTRACE is not set -# CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_WRITECOUNT is not set -# CONFIG_DEBUG_MEMORY_INIT is not set -# CONFIG_DEBUG_LIST is not set -# CONFIG_TEST_LIST_SORT is not set -# CONFIG_DEBUG_SG is not set -# CONFIG_DEBUG_NOTIFIERS is not set -# CONFIG_DEBUG_CREDENTIALS is not set -CONFIG_FRAME_POINTER=y -# CONFIG_BOOT_PRINTK_DELAY is not set -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_RCU_TRACE is not set -# CONFIG_BACKTRACE_SELF_TEST is not set -# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -# CONFIG_FAULT_INJECTION is not set -# CONFIG_LATENCYTOP is not set -# CONFIG_DEBUG_PAGEALLOC is not set -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_TRACING_SUPPORT=y -# CONFIG_FTRACE is not set -# CONFIG_DMA_API_DEBUG is not set -# CONFIG_ATOMIC64_SELFTEST is not set -# CONFIG_SAMPLES is not set -CONFIG_HAVE_ARCH_KGDB=y -# CONFIG_TEST_KSTRTOX is not set -# CONFIG_STRICT_DEVMEM is not set -CONFIG_DEBUG_USER=y -# CONFIG_DEBUG_RODATA is not set -# CONFIG_DEBUG_LL is not set - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY_DMESG_RESTRICT is not set -# CONFIG_SECURITY is not set -# CONFIG_SECURITYFS is not set -CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_DEFAULT_SECURITY="" -CONFIG_CRYPTO=y - -# -# Crypto core or helper -# -CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_ALGAPI2=y -# CONFIG_CRYPTO_MANAGER is not set -# CONFIG_CRYPTO_MANAGER2 is not set -# CONFIG_CRYPTO_USER is not set -# CONFIG_CRYPTO_GF128MUL is not set -# CONFIG_CRYPTO_NULL is not set -# CONFIG_CRYPTO_CRYPTD is not set -# CONFIG_CRYPTO_AUTHENC is not set -# CONFIG_CRYPTO_TEST is not set - -# -# Authenticated Encryption with Associated Data -# -# CONFIG_CRYPTO_CCM is not set -# CONFIG_CRYPTO_GCM is not set -# CONFIG_CRYPTO_SEQIV is not set - -# -# Block modes -# -# CONFIG_CRYPTO_CBC is not set -# CONFIG_CRYPTO_CTR is not set -# CONFIG_CRYPTO_CTS is not set -# CONFIG_CRYPTO_ECB is not set -# CONFIG_CRYPTO_LRW is not set -# CONFIG_CRYPTO_PCBC is not set -# CONFIG_CRYPTO_XTS is not set - -# -# Hash modes -# -# CONFIG_CRYPTO_HMAC is not set - -# -# Digest -# -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_GHASH is not set -# CONFIG_CRYPTO_MD4 is not set -# CONFIG_CRYPTO_MD5 is not set -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_RMD128 is not set -# CONFIG_CRYPTO_RMD160 is not set -# CONFIG_CRYPTO_RMD256 is not set -# CONFIG_CRYPTO_RMD320 is not set -# CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_TGR192 is not set -# CONFIG_CRYPTO_WP512 is not set - -# -# Ciphers -# -CONFIG_CRYPTO_AES=y -# CONFIG_CRYPTO_ANUBIS is not set -CONFIG_CRYPTO_ARC4=y -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_CAMELLIA is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -# CONFIG_CRYPTO_DES is not set -# CONFIG_CRYPTO_FCRYPT is not set -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_SEED is not set -# CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_TEA is not set -# CONFIG_CRYPTO_TWOFISH is not set - -# -# Compression -# -# CONFIG_CRYPTO_DEFLATE is not set -# CONFIG_CRYPTO_ZLIB is not set -# CONFIG_CRYPTO_LZO is not set - -# -# Random Number Generation -# -# CONFIG_CRYPTO_ANSI_CPRNG is not set -# CONFIG_CRYPTO_USER_API_HASH is not set -# CONFIG_CRYPTO_USER_API_SKCIPHER is not set -# CONFIG_CRYPTO_HW is not set -# CONFIG_BINARY_PRINTF is not set - -# -# Library routines -# -CONFIG_BITREVERSE=y -CONFIG_GENERIC_PCI_IOMAP=y -CONFIG_GENERIC_IO=y -# CONFIG_CRC_CCITT is not set -CONFIG_CRC16=y -# CONFIG_CRC_T10DIF is not set -# CONFIG_CRC_ITU_T is not set -CONFIG_CRC32=y -# CONFIG_CRC32_SELFTEST is not set -CONFIG_CRC32_SLICEBY8=y -# CONFIG_CRC32_SLICEBY4 is not set -# CONFIG_CRC32_SARWATE is not set -# CONFIG_CRC32_BIT is not set -# CONFIG_CRC7 is not set -# CONFIG_LIBCRC32C is not set -# CONFIG_CRC8 is not set -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=y -CONFIG_XZ_DEC=y -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y -CONFIG_XZ_DEC_BCJ=y -# CONFIG_XZ_DEC_TEST is not set -CONFIG_DECOMPRESS_GZIP=y -CONFIG_GENERIC_ALLOCATOR=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAS_DMA=y -CONFIG_DQL=y -CONFIG_NLATTR=y -CONFIG_GENERIC_ATOMIC64=y -CONFIG_AVERAGE=y -# CONFIG_CORDIC is not set diff --git a/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libakaec.a b/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libakaec.a deleted file mode 100755 index b6fd2b07..00000000 Binary files a/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libakaec.a and /dev/null differ diff --git a/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libakaec2.a b/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libakaec2.a deleted file mode 100644 index b39cab3b..00000000 Binary files a/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libakaec2.a and /dev/null differ diff --git a/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libfha.a b/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libfha.a deleted file mode 100644 index 483af4c9..00000000 Binary files a/br-ext-chip-anyka/board/ak3918ev200/kernel/overlay/lib/libfha.a and /dev/null differ diff --git a/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/001-ak3918-kernel-3.4.35.patch b/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/001-ak3918-kernel-3.4.35.patch deleted file mode 100644 index dd8b6240..00000000 --- a/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/001-ak3918-kernel-3.4.35.patch +++ /dev/null @@ -1,214307 +0,0 @@ -diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power -index 840f7d64..45000f0d 100644 ---- a/Documentation/ABI/testing/sysfs-devices-power -+++ b/Documentation/ABI/testing/sysfs-devices-power -@@ -96,16 +96,26 @@ Description: - is read-only. If the device is not enabled to wake up the - system from sleep states, this attribute is not present. - --What: /sys/devices/.../power/wakeup_hit_count --Date: September 2010 -+What: /sys/devices/.../power/wakeup_abort_count -+Date: February 2012 - Contact: Rafael J. Wysocki <rjw@sisk.pl> - Description: -- The /sys/devices/.../wakeup_hit_count attribute contains the -+ The /sys/devices/.../wakeup_abort_count attribute contains the - number of times the processing of a wakeup event associated with -- the device might prevent the system from entering a sleep state. -- This attribute is read-only. If the device is not enabled to -- wake up the system from sleep states, this attribute is not -- present. -+ the device might have aborted system transition into a sleep -+ state in progress. This attribute is read-only. If the device -+ is not enabled to wake up the system from sleep states, this -+ attribute is not present. -+ -+What: /sys/devices/.../power/wakeup_expire_count -+Date: February 2012 -+Contact: Rafael J. Wysocki <rjw@sisk.pl> -+Description: -+ The /sys/devices/.../wakeup_expire_count attribute contains the -+ number of times a wakeup event associated with the device has -+ been reported with a timeout that expired. This attribute is -+ read-only. If the device is not enabled to wake up the system -+ from sleep states, this attribute is not present. - - What: /sys/devices/.../power/wakeup_active - Date: September 2010 -@@ -148,6 +158,17 @@ Description: - not enabled to wake up the system from sleep states, this - attribute is not present. - -+What: /sys/devices/.../power/wakeup_prevent_sleep_time_ms -+Date: February 2012 -+Contact: Rafael J. Wysocki <rjw@sisk.pl> -+Description: -+ The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute -+ contains the total time the device has been preventing -+ opportunistic transitions to sleep states from occuring. -+ This attribute is read-only. If the device is not enabled to -+ wake up the system from sleep states, this attribute is not -+ present. -+ - What: /sys/devices/.../power/autosuspend_delay_ms - Date: September 2010 - Contact: Alan Stern <stern@rowland.harvard.edu> -diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power -index b464d127..31725ffe 100644 ---- a/Documentation/ABI/testing/sysfs-power -+++ b/Documentation/ABI/testing/sysfs-power -@@ -172,3 +172,62 @@ Description: - - Reading from this file will display the current value, which is - set to 1 MB by default. -+ -+What: /sys/power/autosleep -+Date: April 2012 -+Contact: Rafael J. Wysocki <rjw@sisk.pl> -+Description: -+ The /sys/power/autosleep file can be written one of the strings -+ returned by reads from /sys/power/state. If that happens, a -+ work item attempting to trigger a transition of the system to -+ the sleep state represented by that string is queued up. This -+ attempt will only succeed if there are no active wakeup sources -+ in the system at that time. After every execution, regardless -+ of whether or not the attempt to put the system to sleep has -+ succeeded, the work item requeues itself until user space -+ writes "off" to /sys/power/autosleep. -+ -+ Reading from this file causes the last string successfully -+ written to it to be returned. -+ -+What: /sys/power/wake_lock -+Date: February 2012 -+Contact: Rafael J. Wysocki <rjw@sisk.pl> -+Description: -+ The /sys/power/wake_lock file allows user space to create -+ wakeup source objects and activate them on demand (if one of -+ those wakeup sources is active, reads from the -+ /sys/power/wakeup_count file block or return false). When a -+ string without white space is written to /sys/power/wake_lock, -+ it will be assumed to represent a wakeup source name. If there -+ is a wakeup source object with that name, it will be activated -+ (unless active already). Otherwise, a new wakeup source object -+ will be registered, assigned the given name and activated. -+ If a string written to /sys/power/wake_lock contains white -+ space, the part of the string preceding the white space will be -+ regarded as a wakeup source name and handled as descrived above. -+ The other part of the string will be regarded as a timeout (in -+ nanoseconds) such that the wakeup source will be automatically -+ deactivated after it has expired. The timeout, if present, is -+ set regardless of the current state of the wakeup source object -+ in question. -+ -+ Reads from this file return a string consisting of the names of -+ wakeup sources created with the help of it that are active at -+ the moment, separated with spaces. -+ -+ -+What: /sys/power/wake_unlock -+Date: February 2012 -+Contact: Rafael J. Wysocki <rjw@sisk.pl> -+Description: -+ The /sys/power/wake_unlock file allows user space to deactivate -+ wakeup sources created with the help of /sys/power/wake_lock. -+ When a string is written to /sys/power/wake_unlock, it will be -+ assumed to represent the name of a wakeup source to deactivate. -+ If a wakeup source object of that name exists and is active at -+ the moment, it will be deactivated. -+ -+ Reads from this file return a string consisting of the names of -+ wakeup sources created with the help of /sys/power/wake_lock -+ that are inactive at the moment, separated with spaces. -diff --git a/Documentation/android.txt b/Documentation/android.txt -new file mode 100644 -index 00000000..72a62afd ---- /dev/null -+++ b/Documentation/android.txt -@@ -0,0 +1,121 @@ -+ ============= -+ A N D R O I D -+ ============= -+ -+Copyright (C) 2009 Google, Inc. -+Written by Mike Chan <mike@android.com> -+ -+CONTENTS: -+--------- -+ -+1. Android -+ 1.1 Required enabled config options -+ 1.2 Required disabled config options -+ 1.3 Recommended enabled config options -+2. Contact -+ -+ -+1. Android -+========== -+ -+Android (www.android.com) is an open source operating system for mobile devices. -+This document describes configurations needed to run the Android framework on -+top of the Linux kernel. -+ -+To see a working defconfig look at msm_defconfig or goldfish_defconfig -+which can be found at http://android.git.kernel.org in kernel/common.git -+and kernel/msm.git -+ -+ -+1.1 Required enabled config options -+----------------------------------- -+After building a standard defconfig, ensure that these options are enabled in -+your .config or defconfig if they are not already. Based off the msm_defconfig. -+You should keep the rest of the default options enabled in the defconfig -+unless you know what you are doing. -+ -+ANDROID_PARANOID_NETWORK -+ASHMEM -+CONFIG_FB_MODE_HELPERS -+CONFIG_FONT_8x16 -+CONFIG_FONT_8x8 -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM -+DAB -+EARLYSUSPEND -+FB -+FB_CFB_COPYAREA -+FB_CFB_FILLRECT -+FB_CFB_IMAGEBLIT -+FB_DEFERRED_IO -+FB_TILEBLITTING -+HIGH_RES_TIMERS -+INOTIFY -+INOTIFY_USER -+INPUT_EVDEV -+INPUT_GPIO -+INPUT_MISC -+LEDS_CLASS -+LEDS_GPIO -+LOCK_KERNEL -+LkOGGER -+LOW_MEMORY_KILLER -+MISC_DEVICES -+NEW_LEDS -+NO_HZ -+POWER_SUPPLY -+PREEMPT -+RAMFS -+RTC_CLASS -+RTC_LIB -+SWITCH -+SWITCH_GPIO -+TMPFS -+UID_STAT -+UID16 -+USB_FUNCTION -+USB_FUNCTION_ADB -+USER_WAKELOCK -+VIDEO_OUTPUT_CONTROL -+WAKELOCK -+YAFFS_AUTO_YAFFS2 -+YAFFS_FS -+YAFFS_YAFFS1 -+YAFFS_YAFFS2 -+ -+ -+1.2 Required disabled config options -+------------------------------------ -+CONFIG_YAFFS_DISABLE_LAZY_LOAD -+DNOTIFY -+ -+ -+1.3 Recommended enabled config options -+------------------------------ -+ANDROID_PMEM -+ANDROID_RAM_CONSOLE -+ANDROID_RAM_CONSOLE_ERROR_CORRECTION -+SCHEDSTATS -+DEBUG_PREEMPT -+DEBUG_MUTEXES -+DEBUG_SPINLOCK_SLEEP -+DEBUG_INFO -+FRAME_POINTER -+CPU_FREQ -+CPU_FREQ_TABLE -+CPU_FREQ_DEFAULT_GOV_ONDEMAND -+CPU_FREQ_GOV_ONDEMAND -+CRC_CCITT -+EMBEDDED -+INPUT_TOUCHSCREEN -+I2C -+I2C_BOARDINFO -+LOG_BUF_SHIFT=17 -+SERIAL_CORE -+SERIAL_CORE_CONSOLE -+ -+ -+2. Contact -+========== -+website: http://android.git.kernel.org -+ -+mailing-lists: android-kernel@googlegroups.com -diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt -index 8e74980a..594ff17d 100644 ---- a/Documentation/cgroups/cgroups.txt -+++ b/Documentation/cgroups/cgroups.txt -@@ -592,6 +592,15 @@ there are not tasks in the cgroup. If pre_destroy() returns error code, - rmdir() will fail with it. From this behavior, pre_destroy() can be - called multiple times against a cgroup. - -+int allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) -+(cgroup_mutex held by caller) -+ -+Called prior to moving a task into a cgroup; if the subsystem -+returns an error, this will abort the attach operation. Used -+to extend the permission checks - if all subsystems in a cgroup -+return 0, the attach will be allowed to proceed, even if the -+default permission check (root or same user) fails. -+ - int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) - (cgroup_mutex held by caller) - -diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt -index c7a2eb84..b4ae5e68 100644 ---- a/Documentation/cpu-freq/governors.txt -+++ b/Documentation/cpu-freq/governors.txt -@@ -28,6 +28,7 @@ Contents: - 2.3 Userspace - 2.4 Ondemand - 2.5 Conservative -+2.6 Interactive - - 3. The Governor Interface in the CPUfreq Core - -@@ -191,6 +192,81 @@ governor but for the opposite direction. For example when set to its - default value of '20' it means that if the CPU usage needs to be below - 20% between samples to have the frequency decreased. - -+ -+2.6 Interactive -+--------------- -+ -+The CPUfreq governor "interactive" is designed for latency-sensitive, -+interactive workloads. This governor sets the CPU speed depending on -+usage, similar to "ondemand" and "conservative" governors, but with a -+different set of configurable behaviors. -+ -+The tuneable values for this governor are: -+ -+target_loads: CPU load values used to adjust speed to influence the -+current CPU load toward that value. In general, the lower the target -+load, the more often the governor will raise CPU speeds to bring load -+below the target. The format is a single target load, optionally -+followed by pairs of CPU speeds and CPU loads to target at or above -+those speeds. Colons can be used between the speeds and associated -+target loads for readability. For example: -+ -+ 85 1000000:90 1700000:99 -+ -+targets CPU load 85% below speed 1GHz, 90% at or above 1GHz, until -+1.7GHz and above, at which load 99% is targeted. If speeds are -+specified these must appear in ascending order. Higher target load -+values are typically specified for higher speeds, that is, target load -+values also usually appear in an ascending order. The default is -+target load 90% for all speeds. -+ -+min_sample_time: The minimum amount of time to spend at the current -+frequency before ramping down. Default is 80000 uS. -+ -+hispeed_freq: An intermediate "hi speed" at which to initially ramp -+when CPU load hits the value specified in go_hispeed_load. If load -+stays high for the amount of time specified in above_hispeed_delay, -+then speed may be bumped higher. Default is the maximum speed -+allowed by the policy at governor initialization time. -+ -+go_hispeed_load: The CPU load at which to ramp to hispeed_freq. -+Default is 99%. -+ -+above_hispeed_delay: When speed is at or above hispeed_freq, wait for -+this long before raising speed in response to continued high load. -+Default is 20000 uS. -+ -+timer_rate: Sample rate for reevaluating CPU load when the CPU is not -+idle. A deferrable timer is used, such that the CPU will not be woken -+from idle to service this timer until something else needs to run. -+(The maximum time to allow deferring this timer when not running at -+minimum speed is configurable via timer_slack.) Default is 20000 uS. -+ -+timer_slack: Maximum additional time to defer handling the governor -+sampling timer beyond timer_rate when running at speeds above the -+minimum. For platforms that consume additional power at idle when -+CPUs are running at speeds greater than minimum, this places an upper -+bound on how long the timer will be deferred prior to re-evaluating -+load and dropping speed. For example, if timer_rate is 20000uS and -+timer_slack is 10000uS then timers will be deferred for up to 30msec -+when not at lowest speed. A value of -1 means defer timers -+indefinitely at all speeds. Default is 80000 uS. -+ -+boost: If non-zero, immediately boost speed of all CPUs to at least -+hispeed_freq until zero is written to this attribute. If zero, allow -+CPU speeds to drop below hispeed_freq according to load as usual. -+Default is zero. -+ -+boostpulse: On each write, immediately boost speed of all CPUs to -+hispeed_freq for at least the period of time specified by -+boostpulse_duration, after which speeds are allowed to drop below -+hispeed_freq according to load as usual. -+ -+boostpulse_duration: Length of time to hold CPU speed at hispeed_freq -+on a write to boostpulse, before allowing speed to drop according to -+load as usual. Default is 80000 uS. -+ -+ - 3. The Governor Interface in the CPUfreq Core - ============================================= - -diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt -index 3bbd5c51..5ff4d2b8 100644 ---- a/Documentation/dma-buf-sharing.txt -+++ b/Documentation/dma-buf-sharing.txt -@@ -29,13 +29,6 @@ The buffer-user - in memory, mapped into its own address space, so it can access the same area - of memory. - --*IMPORTANT*: [see https://lkml.org/lkml/2011/12/20/211 for more details] --For this first version, A buffer shared using the dma_buf sharing API: --- *may* be exported to user space using "mmap" *ONLY* by exporter, outside of -- this framework. --- with this new iteration of the dma-buf api cpu access from the kernel has been -- enable, see below for the details. -- - dma-buf operations for device dma only - -------------------------------------- - -@@ -313,6 +306,83 @@ Access to a dma_buf from the kernel context involves three steps: - enum dma_data_direction dir); - - -+Direct Userspace Access/mmap Support -+------------------------------------ -+ -+Being able to mmap an export dma-buf buffer object has 2 main use-cases: -+- CPU fallback processing in a pipeline and -+- supporting existing mmap interfaces in importers. -+ -+1. CPU fallback processing in a pipeline -+ -+ In many processing pipelines it is sometimes required that the cpu can access -+ the data in a dma-buf (e.g. for thumbnail creation, snapshots, ...). To avoid -+ the need to handle this specially in userspace frameworks for buffer sharing -+ it's ideal if the dma_buf fd itself can be used to access the backing storage -+ from userspace using mmap. -+ -+ Furthermore Android's ION framework already supports this (and is otherwise -+ rather similar to dma-buf from a userspace consumer side with using fds as -+ handles, too). So it's beneficial to support this in a similar fashion on -+ dma-buf to have a good transition path for existing Android userspace. -+ -+ No special interfaces, userspace simply calls mmap on the dma-buf fd. -+ -+2. Supporting existing mmap interfaces in exporters -+ -+ Similar to the motivation for kernel cpu access it is again important that -+ the userspace code of a given importing subsystem can use the same interfaces -+ with a imported dma-buf buffer object as with a native buffer object. This is -+ especially important for drm where the userspace part of contemporary OpenGL, -+ X, and other drivers is huge, and reworking them to use a different way to -+ mmap a buffer rather invasive. -+ -+ The assumption in the current dma-buf interfaces is that redirecting the -+ initial mmap is all that's needed. A survey of some of the existing -+ subsystems shows that no driver seems to do any nefarious thing like syncing -+ up with outstanding asynchronous processing on the device or allocating -+ special resources at fault time. So hopefully this is good enough, since -+ adding interfaces to intercept pagefaults and allow pte shootdowns would -+ increase the complexity quite a bit. -+ -+ Interface: -+ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, -+ unsigned long); -+ -+ If the importing subsystem simply provides a special-purpose mmap call to set -+ up a mapping in userspace, calling do_mmap with dma_buf->file will equally -+ achieve that for a dma-buf object. -+ -+3. Implementation notes for exporters -+ -+ Because dma-buf buffers have invariant size over their lifetime, the dma-buf -+ core checks whether a vma is too large and rejects such mappings. The -+ exporter hence does not need to duplicate this check. -+ -+ Because existing importing subsystems might presume coherent mappings for -+ userspace, the exporter needs to set up a coherent mapping. If that's not -+ possible, it needs to fake coherency by manually shooting down ptes when -+ leaving the cpu domain and flushing caches at fault time. Note that all the -+ dma_buf files share the same anon inode, hence the exporter needs to replace -+ the dma_buf file stored in vma->vm_file with it's own if pte shootdown is -+ requred. This is because the kernel uses the underlying inode's address_space -+ for vma tracking (and hence pte tracking at shootdown time with -+ unmap_mapping_range). -+ -+ If the above shootdown dance turns out to be too expensive in certain -+ scenarios, we can extend dma-buf with a more explicit cache tracking scheme -+ for userspace mappings. But the current assumption is that using mmap is -+ always a slower path, so some inefficiencies should be acceptable. -+ -+ Exporters that shoot down mappings (for any reasons) shall not do any -+ synchronization at fault time with outstanding device operations. -+ Synchronization is an orthogonal issue to sharing the backing storage of a -+ buffer and hence should not be handled by dma-buf itself. This is explictly -+ mentioned here because many people seem to want something like this, but if -+ different exporters handle this differently, buffer sharing can fail in -+ interesting ways depending upong the exporter (if userspace starts depending -+ upon this implicit synchronization). -+ - Miscellaneous notes - ------------------- - -@@ -336,6 +406,20 @@ Miscellaneous notes - the exporting driver to create a dmabuf fd must provide a way to let - userspace control setting of O_CLOEXEC flag passed in to dma_buf_fd(). - -+- If an exporter needs to manually flush caches and hence needs to fake -+ coherency for mmap support, it needs to be able to zap all the ptes pointing -+ at the backing storage. Now linux mm needs a struct address_space associated -+ with the struct file stored in vma->vm_file to do that with the function -+ unmap_mapping_range. But the dma_buf framework only backs every dma_buf fd -+ with the anon_file struct file, i.e. all dma_bufs share the same file. -+ -+ Hence exporters need to setup their own file (and address_space) association -+ by setting vma->vm_file and adjusting vma->vm_pgoff in the dma_buf mmap -+ callback. In the specific case of a gem driver the exporter could use the -+ shmem file already provided by gem (and set vm_pgoff = 0). Exporters can then -+ zap ptes by unmapping the corresponding range of the struct address_space -+ associated with their own file. -+ - References: - [1] struct dma_buf_ops in include/linux/dma-buf.h - [2] All interfaces mentioned above defined in include/linux/dma-buf.h -diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt -new file mode 100644 -index 00000000..4627c424 ---- /dev/null -+++ b/Documentation/hid/uhid.txt -@@ -0,0 +1,169 @@ -+ UHID - User-space I/O driver support for HID subsystem -+ ======================================================== -+ -+The HID subsystem needs two kinds of drivers. In this document we call them: -+ -+ 1. The "HID I/O Driver" is the driver that performs raw data I/O to the -+ low-level device. Internally, they register an hid_ll_driver structure with -+ the HID core. They perform device setup, read raw data from the device and -+ push it into the HID subsystem and they provide a callback so the HID -+ subsystem can send data to the device. -+ -+ 2. The "HID Device Driver" is the driver that parses HID reports and reacts on -+ them. There are generic drivers like "generic-usb" and "generic-bluetooth" -+ which adhere to the HID specification and provide the standardizes features. -+ But there may be special drivers and quirks for each non-standard device out -+ there. Internally, they use the hid_driver structure. -+ -+Historically, the USB stack was the first subsystem to provide an HID I/O -+Driver. However, other standards like Bluetooth have adopted the HID specs and -+may provide HID I/O Drivers, too. The UHID driver allows to implement HID I/O -+Drivers in user-space and feed the data into the kernel HID-subsystem. -+ -+This allows user-space to operate on the same level as USB-HID, Bluetooth-HID -+and similar. It does not provide a way to write HID Device Drivers, though. Use -+hidraw for this purpose. -+ -+There is an example user-space application in ./samples/uhid/uhid-example.c -+ -+The UHID API -+------------ -+ -+UHID is accessed through a character misc-device. The minor-number is allocated -+dynamically so you need to rely on udev (or similar) to create the device node. -+This is /dev/uhid by default. -+ -+If a new device is detected by your HID I/O Driver and you want to register this -+device with the HID subsystem, then you need to open /dev/uhid once for each -+device you want to register. All further communication is done by read()'ing or -+write()'ing "struct uhid_event" objects. Non-blocking operations are supported -+by setting O_NONBLOCK. -+ -+struct uhid_event { -+ __u32 type; -+ union { -+ struct uhid_create_req create; -+ struct uhid_data_req data; -+ ... -+ } u; -+}; -+ -+The "type" field contains the ID of the event. Depending on the ID different -+payloads are sent. You must not split a single event across multiple read()'s or -+multiple write()'s. A single event must always be sent as a whole. Furthermore, -+only a single event can be sent per read() or write(). Pending data is ignored. -+If you want to handle multiple events in a single syscall, then use vectored -+I/O with readv()/writev(). -+ -+The first thing you should do is sending an UHID_CREATE event. This will -+register the device. UHID will respond with an UHID_START event. You can now -+start sending data to and reading data from UHID. However, unless UHID sends the -+UHID_OPEN event, the internally attached HID Device Driver has no user attached. -+That is, you might put your device asleep unless you receive the UHID_OPEN -+event. If you receive the UHID_OPEN event, you should start I/O. If the last -+user closes the HID device, you will receive an UHID_CLOSE event. This may be -+followed by an UHID_OPEN event again and so on. There is no need to perform -+reference-counting in user-space. That is, you will never receive multiple -+UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs -+ref-counting for you. -+You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even -+though the device may have no users. -+ -+If you want to send data to the HID subsystem, you send an HID_INPUT event with -+your raw data payload. If the kernel wants to send data to the device, you will -+read an UHID_OUTPUT or UHID_OUTPUT_EV event. -+ -+If your device disconnects, you should send an UHID_DESTROY event. This will -+unregister the device. You can now send UHID_CREATE again to register a new -+device. -+If you close() the fd, the device is automatically unregistered and destroyed -+internally. -+ -+write() -+------- -+write() allows you to modify the state of the device and feed input data into -+the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and -+UHID_INPUT. The kernel will parse the event immediately and if the event ID is -+not supported, it will return -EOPNOTSUPP. If the payload is invalid, then -+-EINVAL is returned, otherwise, the amount of data that was read is returned and -+the request was handled successfully. -+ -+ UHID_CREATE: -+ This creates the internal HID device. No I/O is possible until you send this -+ event to the kernel. The payload is of type struct uhid_create_req and -+ contains information about your device. You can start I/O now. -+ -+ UHID_DESTROY: -+ This destroys the internal HID device. No further I/O will be accepted. There -+ may still be pending messages that you can receive with read() but no further -+ UHID_INPUT events can be sent to the kernel. -+ You can create a new device by sending UHID_CREATE again. There is no need to -+ reopen the character device. -+ -+ UHID_INPUT: -+ You must send UHID_CREATE before sending input to the kernel! This event -+ contains a data-payload. This is the raw data that you read from your device. -+ The kernel will parse the HID reports and react on it. -+ -+ UHID_FEATURE_ANSWER: -+ If you receive a UHID_FEATURE request you must answer with this request. You -+ must copy the "id" field from the request into the answer. Set the "err" field -+ to 0 if no error occured or to EIO if an I/O error occurred. -+ If "err" is 0 then you should fill the buffer of the answer with the results -+ of the feature request and set "size" correspondingly. -+ -+read() -+------ -+read() will return a queued ouput report. These output reports can be of type -+UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No -+reaction is required to any of them but you should handle them according to your -+needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads. -+ -+ UHID_START: -+ This is sent when the HID device is started. Consider this as an answer to -+ UHID_CREATE. This is always the first event that is sent. -+ -+ UHID_STOP: -+ This is sent when the HID device is stopped. Consider this as an answer to -+ UHID_DESTROY. -+ If the kernel HID device driver closes the device manually (that is, you -+ didn't send UHID_DESTROY) then you should consider this device closed and send -+ an UHID_DESTROY event. You may want to reregister your device, though. This is -+ always the last message that is sent to you unless you reopen the device with -+ UHID_CREATE. -+ -+ UHID_OPEN: -+ This is sent when the HID device is opened. That is, the data that the HID -+ device provides is read by some other process. You may ignore this event but -+ it is useful for power-management. As long as you haven't received this event -+ there is actually no other process that reads your data so there is no need to -+ send UHID_INPUT events to the kernel. -+ -+ UHID_CLOSE: -+ This is sent when there are no more processes which read the HID data. It is -+ the counterpart of UHID_OPEN and you may as well ignore this event. -+ -+ UHID_OUTPUT: -+ This is sent if the HID device driver wants to send raw data to the I/O -+ device. You should read the payload and forward it to the device. The payload -+ is of type "struct uhid_data_req". -+ This may be received even though you haven't received UHID_OPEN, yet. -+ -+ UHID_OUTPUT_EV: -+ Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This -+ is called for force-feedback, LED or similar events which are received through -+ an input device by the HID subsystem. You should convert this into raw reports -+ and send them to your device similar to events of type UHID_OUTPUT. -+ -+ UHID_FEATURE: -+ This event is sent if the kernel driver wants to perform a feature request as -+ described in the HID specs. The report-type and report-number are available in -+ the payload. -+ The kernel serializes feature requests so there will never be two in parallel. -+ However, if you fail to respond with a UHID_FEATURE_ANSWER in a time-span of 5 -+ seconds, then the requests will be dropped and a new one might be sent. -+ Therefore, the payload also contains an "id" field that identifies every -+ request. -+ -+Document by: -+ David Herrmann <dh.herrmann@googlemail.com> -diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt -index 753d18ae..693037fb 100644 ---- a/Documentation/kernel-parameters.txt -+++ b/Documentation/kernel-parameters.txt -@@ -2377,6 +2377,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. - - resume= [SWSUSP] - Specify the partition device for software suspend -+ Format: -+ {/dev/<dev> | PARTUUID=<uuid> | <int>:<int> | <hex>} - - resume_offset= [SWSUSP] - Specify the offset from the beginning of the partition -diff --git a/Documentation/power/suspend-and-cpuhotplug.txt b/Documentation/power/suspend-and-cpuhotplug.txt -index f28f9a6f..e13dafc8 100644 ---- a/Documentation/power/suspend-and-cpuhotplug.txt -+++ b/Documentation/power/suspend-and-cpuhotplug.txt -@@ -29,7 +29,7 @@ More details follow: - - Write 'mem' to - /sys/power/state -- syfs file -+ sysfs file - | - v - Acquire pm_mutex lock -diff --git a/Documentation/sync.txt b/Documentation/sync.txt -new file mode 100644 -index 00000000..a2d05e7f ---- /dev/null -+++ b/Documentation/sync.txt -@@ -0,0 +1,75 @@ -+Motivation: -+ -+In complicated DMA pipelines such as graphics (multimedia, camera, gpu, display) -+a consumer of a buffer needs to know when the producer has finished producing -+it. Likewise the producer needs to know when the consumer is finished with the -+buffer so it can reuse it. A particular buffer may be consumed by multiple -+consumers which will retain the buffer for different amounts of time. In -+addition, a consumer may consume multiple buffers atomically. -+The sync framework adds an API which allows synchronization between the -+producers and consumers in a generic way while also allowing platforms which -+have shared hardware synchronization primitives to exploit them. -+ -+Goals: -+ * provide a generic API for expressing synchronization dependencies -+ * allow drivers to exploit hardware synchronization between hardware -+ blocks -+ * provide a userspace API that allows a compositor to manage -+ dependencies. -+ * provide rich telemetry data to allow debugging slowdowns and stalls of -+ the graphics pipeline. -+ -+Objects: -+ * sync_timeline -+ * sync_pt -+ * sync_fence -+ -+sync_timeline: -+ -+A sync_timeline is an abstract monotonically increasing counter. In general, -+each driver/hardware block context will have one of these. They can be backed -+by the appropriate hardware or rely on the generic sw_sync implementation. -+Timelines are only ever created through their specific implementations -+(i.e. sw_sync.) -+ -+sync_pt: -+ -+A sync_pt is an abstract value which marks a point on a sync_timeline. Sync_pts -+have a single timeline parent. They have 3 states: active, signaled, and error. -+They start in active state and transition, once, to either signaled (when the -+timeline counter advances beyond the sync_pt’s value) or error state. -+ -+sync_fence: -+ -+Sync_fences are the primary primitives used by drivers to coordinate -+synchronization of their buffers. They are a collection of sync_pts which may -+or may not have the same timeline parent. A sync_pt can only exist in one fence -+and the fence's list of sync_pts is immutable once created. Fences can be -+waited on synchronously or asynchronously. Two fences can also be merged to -+create a third fence containing a copy of the two fences’ sync_pts. Fences are -+backed by file descriptors to allow userspace to coordinate the display pipeline -+dependencies. -+ -+Use: -+ -+A driver implementing sync support should have a work submission function which: -+ * takes a fence argument specifying when to begin work -+ * asynchronously queues that work to kick off when the fence is signaled -+ * returns a fence to indicate when its work will be done. -+ * signals the returned fence once the work is completed. -+ -+Consider an imaginary display driver that has the following API: -+/* -+ * assumes buf is ready to be displayed. -+ * blocks until the buffer is on screen. -+ */ -+ void display_buffer(struct dma_buf *buf); -+ -+The new API will become: -+/* -+ * will display buf when fence is signaled. -+ * returns immediately with a fence that will signal when buf -+ * is no longer displayed. -+ */ -+struct sync_fence* display_buffer(struct dma_buf *buf, -+ struct sync_fence *fence); -diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt -index 6f51fed4..a5c45d7b 100644 ---- a/Documentation/trace/ftrace.txt -+++ b/Documentation/trace/ftrace.txt -@@ -1458,6 +1458,35 @@ will produce: - 1) 1.449 us | } - - -+You can disable the hierarchical function call formatting and instead print a -+flat list of function entry and return events. This uses the format described -+in the Output Formatting section and respects all the trace options that -+control that formatting. Hierarchical formatting is the default. -+ -+ hierachical: echo nofuncgraph-flat > trace_options -+ flat: echo funcgraph-flat > trace_options -+ -+ ie: -+ -+ # tracer: function_graph -+ # -+ # entries-in-buffer/entries-written: 68355/68355 #P:2 -+ # -+ # _-----=> irqs-off -+ # / _----=> need-resched -+ # | / _---=> hardirq/softirq -+ # || / _--=> preempt-depth -+ # ||| / delay -+ # TASK-PID CPU# |||| TIMESTAMP FUNCTION -+ # | | | |||| | | -+ sh-1806 [001] d... 198.843443: graph_ent: func=_raw_spin_lock -+ sh-1806 [001] d... 198.843445: graph_ent: func=__raw_spin_lock -+ sh-1806 [001] d..1 198.843447: graph_ret: func=__raw_spin_lock -+ sh-1806 [001] d..1 198.843449: graph_ret: func=_raw_spin_lock -+ sh-1806 [001] d..1 198.843451: graph_ent: func=_raw_spin_unlock_irqrestore -+ sh-1806 [001] d... 198.843453: graph_ret: func=_raw_spin_unlock_irqrestore -+ -+ - You might find other useful features for this tracer in the - following "dynamic ftrace" section such as tracing only specific - functions or tasks. -diff --git a/MAINTAINERS b/MAINTAINERS -index c744d9c6..c5b99af4 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -6855,6 +6855,13 @@ S: Maintained - F: Documentation/filesystems/ufs.txt - F: fs/ufs/ - -+UHID USERSPACE HID IO DRIVER: -+M: David Herrmann <dh.herrmann@googlemail.com> -+L: linux-input@vger.kernel.org -+S: Maintained -+F: drivers/hid/uhid.c -+F: include/linux/uhid.h -+ - ULTRA-WIDEBAND (UWB) SUBSYSTEM: - L: linux-usb@vger.kernel.org - S: Orphan -diff --git a/Makefile b/Makefile -index 282e8da3..fb92e2ab 100644 ---- a/Makefile -+++ b/Makefile -@@ -3,6 +3,7 @@ PATCHLEVEL = 4 - SUBLEVEL = 35 - EXTRAVERSION = - NAME = Saber-toothed Squirrel -+ANYKA_VERSION = 1.0.05 - - # *DOCUMENTATION* - # To see a list of typical targets execute "make help" -@@ -132,6 +133,20 @@ sub-make: FORCE - KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile \ - $(filter-out _all sub-make,$(MAKECMDGOALS)) - -+myPATH := $(KBUILD_OUTPUT)/lib -+myFILE := "libfha.a" -+myFILE_SOURCE := "lib/libfha.a" -+$(shell if [ ! -d $(myPATH) ]; then\ -+ mkdir -p $(myPATH); fi) -+$(shell cp -f $(myFILE_SOURCE) $(myPATH)) -+ -+aecPATH := $(KBUILD_OUTPUT)/lib -+aecFILE := "libakaec.a" -+aecFILE_SOURCE := "lib/libakaec.a" -+$(shell if [ ! -d $(aecPATH) ]; then\ -+ mkdir -p $(aecPATH); fi) -+$(shell cp -f $(aecFILE_SOURCE) $(aecPATH)) -+ - # Leave processing to above invocation of make - skip-makefile := 1 - endif # ifneq ($(KBUILD_OUTPUT),) -@@ -192,8 +207,11 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ - # Default value for CROSS_COMPILE is not to prefix executables - # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile - export KBUILD_BUILDHOST := $(SUBARCH) --ARCH ?= $(SUBARCH) --CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) -+# ARCH ?= $(SUBARCH) -+# CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) -+ -+ARCH ?= arm -+CROSS_COMPILE ?= arm-none-linux-gnueabi- - - # Architecture as present in compile.h - UTS_MACHINE := $(ARCH) -@@ -350,7 +368,7 @@ CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ - CFLAGS_MODULE = - AFLAGS_MODULE = - LDFLAGS_MODULE = --CFLAGS_KERNEL = -+CFLAGS_KERNEL = -DANYKA_VERSION=$(ANYKA_VERSION) - AFLAGS_KERNEL = - CFLAGS_GCOV = -fprofile-arcs -ftest-coverage - -@@ -725,7 +743,7 @@ drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) - net-y := $(patsubst %/, %/built-in.o, $(net-y)) - libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) - libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) --libs-y := $(libs-y1) $(libs-y2) -+libs-y := $(libs-y1) $(libs-y2) lib/libfha.a lib/libakaec.a - - # Build vmlinux - # --------------------------------------------------------------------------- -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 7fe19a38..1aad3ad0 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -1010,6 +1010,19 @@ config ARCH_ZYNQ - select USE_OF - help - Support for Xilinx Zynq ARM Cortex A9 Platform -+ -+config ARCH_AK39 -+ bool "ANYKA AK39XX" -+ select CPU_ARM926T -+ select GENERIC_GPIO -+ select ARCH_REQUIRE_GPIOLIB -+ select CLKDEV_LOOKUP -+# select WIRELESS_EXT -+ select ARCH_USES_GETTIMEOFFSET -+ select ARCH_HAS_CPUFREQ -+ help -+ Support for Anyka AK39xx series Chips platform. -+ - endchoice - - # -@@ -1128,6 +1141,9 @@ source "arch/arm/mach-vt8500/Kconfig" - - source "arch/arm/mach-w90x900/Kconfig" - -+source "arch/arm/mach-ak39/Kconfig" -+source "arch/arm/plat-anyka/Kconfig" -+ - # Definitions to make life easier - config ARCH_ACORN - bool -@@ -1896,6 +1912,15 @@ config DEPRECATED_PARAM_STRUCT - This was deprecated in 2001 and announced to live on for 5 years. - Some old boot loaders still use this way. - -+config ARM_FLUSH_CONSOLE_ON_RESTART -+ bool "Force flush the console on restart" -+ help -+ If the console is locked while the system is rebooted, the messages -+ in the temporary logbuffer would not have propogated to all the -+ console drivers. This option forces the console lock to be -+ released if it failed to be acquired, which will cause all the -+ pending messages to be flushed. -+ - endmenu - - menu "Boot options" -@@ -2113,6 +2138,22 @@ config AUTO_ZRELADDR - 0xf8000000. This assumes the zImage being placed in the first 128MB - from start of memory. - -+config RAM_BASE -+ hex "RAM physical starting address" -+ depends on ARCH_AK39 -+ default 0x80000000 -+ help -+ ANYKA RAM physical starting address (in hex), default addr is 0x80000000 for Anyka platform. -+ -+config VIDEO_RESERVED_MEM_SIZE -+ hex "Memory reserved for video decoding" -+ depends on ARCH_AK39 -+ default 0x1A00000 -+ help -+ ANYKA H.264 decoder requires continuous physical RAM which do NOT cross -+ 32MB boundary (Decoder IP requirement). So we have to reserve enough RAM -+ for H.264 decoding. Default size is 0x1A00000 (26MB) for AK39xx. -+ - endmenu - - menu "CPU Power Management" -diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index 85348a09..037bd5af 100644 ---- a/arch/arm/Kconfig.debug -+++ b/arch/arm/Kconfig.debug -@@ -63,6 +63,27 @@ config DEBUG_USER - 8 - SIGSEGV faults - 16 - SIGBUS faults - -+config DEBUG_RODATA -+ bool "Write protect kernel text section" -+ default n -+ depends on DEBUG_KERNEL && MMU -+ ---help--- -+ Mark the kernel text section as write-protected in the pagetables, -+ in order to catch accidental (and incorrect) writes to such const -+ data. This will cause the size of the kernel, plus up to 4MB, to -+ be mapped as pages instead of sections, which will increase TLB -+ pressure. -+ If in doubt, say "N". -+ -+config DEBUG_RODATA_TEST -+ bool "Testcase for the DEBUG_RODATA feature" -+ depends on DEBUG_RODATA -+ default n -+ ---help--- -+ This option enables a testcase for the DEBUG_RODATA -+ feature. -+ If in doubt, say "N" -+ - # These options are only for real kernel hackers who want to get their hands dirty. - config DEBUG_LL - bool "Kernel low-level debugging functions (read help!)" -diff --git a/arch/arm/Makefile b/arch/arm/Makefile -index 1d6402cb..54bf4034 100644 ---- a/arch/arm/Makefile -+++ b/arch/arm/Makefile -@@ -197,6 +197,7 @@ machine-$(CONFIG_MACH_SPEAR310) := spear3xx - machine-$(CONFIG_MACH_SPEAR320) := spear3xx - machine-$(CONFIG_MACH_SPEAR600) := spear6xx - machine-$(CONFIG_ARCH_ZYNQ) := zynq -+machine-$(CONFIG_ARCH_AK39) := ak39 - - # Platform directory name. This list is sorted alphanumerically - # by CONFIG_* macro name. -@@ -212,6 +213,7 @@ plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx samsung - plat-$(CONFIG_PLAT_S5P) := s5p samsung - plat-$(CONFIG_PLAT_SPEAR) := spear - plat-$(CONFIG_PLAT_VERSATILE) := versatile -+plat-$(CONFIG_PLAT_ANYKA) := anyka - - ifeq ($(CONFIG_ARCH_EBSA110),y) - # This is what happens if you forget the IOCS16 line. -diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S -index 87278fc8..9e631db1 100644 ---- a/arch/arm/boot/compressed/head.S -+++ b/arch/arm/boot/compressed/head.S -@@ -9,6 +9,7 @@ - * published by the Free Software Foundation. - */ - #include <linux/linkage.h> -+#include <asm/mach-types.h> - - /* - * Debugging stuff -@@ -132,7 +133,21 @@ start: - .word start @ absolute load/run zImage address - .word _edata @ zImage end address - THUMB( .thumb ) --1: mov r7, r1 @ save architecture ID -+1: -+/* -+ * Actually `machine type' MUST be provided in register r1 by boot/loader according -+ * to ARM Linux booting requirements (Documentation/arm/Booting). However, it seems -+ * that AK39xx nandboot or boot/loader-like program do NOT follow this standard, -+ * we have to give a fake one here. -+ * -+ * NOTE: The following code assumes that machine type is NOT greater than 0xFFFF, that could be true for a very long time, so just keep the code. -+ */ -+#ifdef CONFIG_ARCH_AK39 -+ mov r1, #(MACH_TYPE_AK39XX & 0xFF) -+ orr r1, r1, #(MACH_TYPE_AK39XX & 0xFF00) -+#endif -+ -+ mov r7, r1 @ save architecture ID - mov r8, r2 @ save atags pointer - - #ifndef __ARM_ARCH_2__ -@@ -767,6 +782,8 @@ proc_types: - @ b __arm6_mmu_cache_off - @ b __armv3_mmu_cache_flush - -+#if !defined(CONFIG_CPU_V7) -+ /* This collides with some V7 IDs, preventing correct detection */ - .word 0x00000000 @ old ARM ID - .word 0x0000f000 - mov pc, lr -@@ -775,6 +792,7 @@ proc_types: - THUMB( nop ) - mov pc, lr - THUMB( nop ) -+#endif - - .word 0x41007000 @ ARM7/710 - .word 0xfff8fe00 -diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c -index 8e2a8fca..b05ee262 100644 ---- a/arch/arm/boot/compressed/misc.c -+++ b/arch/arm/boot/compressed/misc.c -@@ -27,6 +27,9 @@ extern void error(char *x); - - #include <mach/uncompress.h> - -+#define _STR(x) #x -+#define STR(x) _STR(x) -+ - #ifdef CONFIG_DEBUG_ICEDCC - - #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7) -@@ -151,4 +154,6 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, - error("decompressor returned an error"); - else - putstr(" done, booting the kernel.\n"); -+ -+ putstr("Anyka Linux Kernel Version: "STR(ANYKA_VERSION)"\n"); - } -diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig -index 283fa1d8..271dd136 100644 ---- a/arch/arm/common/Kconfig -+++ b/arch/arm/common/Kconfig -@@ -40,3 +40,53 @@ config SHARP_PARAM - - config SHARP_SCOOP - bool -+ -+config FIQ_GLUE -+ bool -+ select FIQ -+ -+config FIQ_DEBUGGER -+ bool "FIQ Mode Serial Debugger" -+ select FIQ -+ select FIQ_GLUE -+ default n -+ help -+ The FIQ serial debugger can accept commands even when the -+ kernel is unresponsive due to being stuck with interrupts -+ disabled. -+ -+ -+config FIQ_DEBUGGER_NO_SLEEP -+ bool "Keep serial debugger active" -+ depends on FIQ_DEBUGGER -+ default n -+ help -+ Enables the serial debugger at boot. Passing -+ fiq_debugger.no_sleep on the kernel commandline will -+ override this config option. -+ -+config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON -+ bool "Don't disable wakeup IRQ when debugger is active" -+ depends on FIQ_DEBUGGER -+ default n -+ help -+ Don't disable the wakeup irq when enabling the uart clock. This will -+ cause extra interrupts, but it makes the serial debugger usable with -+ on some MSM radio builds that ignore the uart clock request in power -+ collapse. -+ -+config FIQ_DEBUGGER_CONSOLE -+ bool "Console on FIQ Serial Debugger port" -+ depends on FIQ_DEBUGGER -+ default n -+ help -+ Enables a console so that printk messages are displayed on -+ the debugger serial port as the occur. -+ -+config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE -+ bool "Put the FIQ debugger into console mode by default" -+ depends on FIQ_DEBUGGER_CONSOLE -+ default n -+ help -+ If enabled, this puts the fiq debugger into console mode by default. -+ Otherwise, the fiq debugger will start out in debug mode. -diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile -index 215816f1..11670f9d 100644 ---- a/arch/arm/common/Makefile -+++ b/arch/arm/common/Makefile -@@ -15,3 +15,5 @@ obj-$(CONFIG_ARCH_IXP2000) += uengine.o - obj-$(CONFIG_ARCH_IXP23XX) += uengine.o - obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o - obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o -+obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o -+obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o -diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c -new file mode 100644 -index 00000000..d0686388 ---- /dev/null -+++ b/arch/arm/common/fiq_debugger.c -@@ -0,0 +1,1388 @@ -+/* -+ * arch/arm/common/fiq_debugger.c -+ * -+ * Serial Debugger Interface accessed through an FIQ interrupt. -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#include <stdarg.h> -+#include <linux/module.h> -+#include <linux/io.h> -+#include <linux/console.h> -+#include <linux/interrupt.h> -+#include <linux/clk.h> -+#include <linux/platform_device.h> -+#include <linux/kernel_stat.h> -+#include <linux/irq.h> -+#include <linux/delay.h> -+#include <linux/reboot.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/smp.h> -+#include <linux/timer.h> -+#include <linux/tty.h> -+#include <linux/tty_flip.h> -+#include <linux/wakelock.h> -+ -+#include <asm/fiq_debugger.h> -+#include <asm/fiq_glue.h> -+#include <asm/stacktrace.h> -+ -+#include <linux/uaccess.h> -+ -+#include "fiq_debugger_ringbuf.h" -+ -+#define DEBUG_MAX 64 -+#define MAX_UNHANDLED_FIQ_COUNT 1000000 -+ -+#define MAX_FIQ_DEBUGGER_PORTS 4 -+ -+#define THREAD_INFO(sp) ((struct thread_info *) \ -+ ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) -+ -+struct fiq_debugger_state { -+ struct fiq_glue_handler handler; -+ -+ int fiq; -+ int uart_irq; -+ int signal_irq; -+ int wakeup_irq; -+ bool wakeup_irq_no_set_wake; -+ struct clk *clk; -+ struct fiq_debugger_pdata *pdata; -+ struct platform_device *pdev; -+ -+ char debug_cmd[DEBUG_MAX]; -+ int debug_busy; -+ int debug_abort; -+ -+ char debug_buf[DEBUG_MAX]; -+ int debug_count; -+ -+ bool no_sleep; -+ bool debug_enable; -+ bool ignore_next_wakeup_irq; -+ struct timer_list sleep_timer; -+ spinlock_t sleep_timer_lock; -+ bool uart_enabled; -+ struct wake_lock debugger_wake_lock; -+ bool console_enable; -+ int current_cpu; -+ atomic_t unhandled_fiq_count; -+ bool in_fiq; -+ -+ struct work_struct work; -+ spinlock_t work_lock; -+ char work_cmd[DEBUG_MAX]; -+ -+#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -+ spinlock_t console_lock; -+ struct console console; -+ struct tty_struct *tty; -+ int tty_open_count; -+ struct fiq_debugger_ringbuf *tty_rbuf; -+ bool syslog_dumping; -+#endif -+ -+ unsigned int last_irqs[NR_IRQS]; -+ unsigned int last_local_timer_irqs[NR_CPUS]; -+}; -+ -+#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -+struct tty_driver *fiq_tty_driver; -+#endif -+ -+#ifdef CONFIG_FIQ_DEBUGGER_NO_SLEEP -+static bool initial_no_sleep = true; -+#else -+static bool initial_no_sleep; -+#endif -+ -+#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE -+static bool initial_debug_enable = true; -+static bool initial_console_enable = true; -+#else -+static bool initial_debug_enable; -+static bool initial_console_enable; -+#endif -+ -+static bool fiq_kgdb_enable; -+ -+module_param_named(no_sleep, initial_no_sleep, bool, 0644); -+module_param_named(debug_enable, initial_debug_enable, bool, 0644); -+module_param_named(console_enable, initial_console_enable, bool, 0644); -+module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644); -+ -+#ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON -+static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {} -+static inline void disable_wakeup_irq(struct fiq_debugger_state *state) {} -+#else -+static inline void enable_wakeup_irq(struct fiq_debugger_state *state) -+{ -+ if (state->wakeup_irq < 0) -+ return; -+ enable_irq(state->wakeup_irq); -+ if (!state->wakeup_irq_no_set_wake) -+ enable_irq_wake(state->wakeup_irq); -+} -+static inline void disable_wakeup_irq(struct fiq_debugger_state *state) -+{ -+ if (state->wakeup_irq < 0) -+ return; -+ disable_irq_nosync(state->wakeup_irq); -+ if (!state->wakeup_irq_no_set_wake) -+ disable_irq_wake(state->wakeup_irq); -+} -+#endif -+ -+static bool inline debug_have_fiq(struct fiq_debugger_state *state) -+{ -+ return (state->fiq >= 0); -+} -+ -+static void debug_force_irq(struct fiq_debugger_state *state) -+{ -+ unsigned int irq = state->signal_irq; -+ -+ if (WARN_ON(!debug_have_fiq(state))) -+ return; -+ if (state->pdata->force_irq) { -+ state->pdata->force_irq(state->pdev, irq); -+ } else { -+ struct irq_chip *chip = irq_get_chip(irq); -+ if (chip && chip->irq_retrigger) -+ chip->irq_retrigger(irq_get_irq_data(irq)); -+ } -+} -+ -+static void debug_uart_enable(struct fiq_debugger_state *state) -+{ -+ if (state->clk) -+ clk_enable(state->clk); -+ if (state->pdata->uart_enable) -+ state->pdata->uart_enable(state->pdev); -+} -+ -+static void debug_uart_disable(struct fiq_debugger_state *state) -+{ -+ if (state->pdata->uart_disable) -+ state->pdata->uart_disable(state->pdev); -+ if (state->clk) -+ clk_disable(state->clk); -+} -+ -+static void debug_uart_flush(struct fiq_debugger_state *state) -+{ -+ if (state->pdata->uart_flush) -+ state->pdata->uart_flush(state->pdev); -+} -+ -+static void debug_putc(struct fiq_debugger_state *state, char c) -+{ -+ state->pdata->uart_putc(state->pdev, c); -+} -+ -+static void debug_puts(struct fiq_debugger_state *state, char *s) -+{ -+ unsigned c; -+ while ((c = *s++)) { -+ if (c == '\n') -+ debug_putc(state, '\r'); -+ debug_putc(state, c); -+ } -+} -+ -+static void debug_prompt(struct fiq_debugger_state *state) -+{ -+ debug_puts(state, "debug> "); -+} -+ -+int log_buf_copy(char *dest, int idx, int len); -+static void dump_kernel_log(struct fiq_debugger_state *state) -+{ -+ char buf[1024]; -+ int idx = 0; -+ int ret; -+ int saved_oip; -+ -+ /* setting oops_in_progress prevents log_buf_copy() -+ * from trying to take a spinlock which will make it -+ * very unhappy in some cases... -+ */ -+ saved_oip = oops_in_progress; -+ oops_in_progress = 1; -+ for (;;) { -+ ret = log_buf_copy(buf, idx, 1023); -+ if (ret <= 0) -+ break; -+ buf[ret] = 0; -+ debug_puts(state, buf); -+ idx += ret; -+ } -+ oops_in_progress = saved_oip; -+} -+ -+static char *mode_name(unsigned cpsr) -+{ -+ switch (cpsr & MODE_MASK) { -+ case USR_MODE: return "USR"; -+ case FIQ_MODE: return "FIQ"; -+ case IRQ_MODE: return "IRQ"; -+ case SVC_MODE: return "SVC"; -+ case ABT_MODE: return "ABT"; -+ case UND_MODE: return "UND"; -+ case SYSTEM_MODE: return "SYS"; -+ default: return "???"; -+ } -+} -+ -+static int debug_printf(void *cookie, const char *fmt, ...) -+{ -+ struct fiq_debugger_state *state = cookie; -+ char buf[256]; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ vsnprintf(buf, sizeof(buf), fmt, ap); -+ va_end(ap); -+ -+ debug_puts(state, buf); -+ return state->debug_abort; -+} -+ -+/* Safe outside fiq context */ -+static int debug_printf_nfiq(void *cookie, const char *fmt, ...) -+{ -+ struct fiq_debugger_state *state = cookie; -+ char buf[256]; -+ va_list ap; -+ unsigned long irq_flags; -+ -+ va_start(ap, fmt); -+ vsnprintf(buf, 128, fmt, ap); -+ va_end(ap); -+ -+ local_irq_save(irq_flags); -+ debug_puts(state, buf); -+ debug_uart_flush(state); -+ local_irq_restore(irq_flags); -+ return state->debug_abort; -+} -+ -+static void dump_regs(struct fiq_debugger_state *state, unsigned *regs) -+{ -+ debug_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", -+ regs[0], regs[1], regs[2], regs[3]); -+ debug_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", -+ regs[4], regs[5], regs[6], regs[7]); -+ debug_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", -+ regs[8], regs[9], regs[10], regs[11], -+ mode_name(regs[16])); -+ if ((regs[16] & MODE_MASK) == USR_MODE) -+ debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " -+ "cpsr %08x\n", regs[12], regs[13], regs[14], -+ regs[15], regs[16]); -+ else -+ debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " -+ "cpsr %08x spsr %08x\n", regs[12], regs[13], -+ regs[14], regs[15], regs[16], regs[17]); -+} -+ -+struct mode_regs { -+ unsigned long sp_svc; -+ unsigned long lr_svc; -+ unsigned long spsr_svc; -+ -+ unsigned long sp_abt; -+ unsigned long lr_abt; -+ unsigned long spsr_abt; -+ -+ unsigned long sp_und; -+ unsigned long lr_und; -+ unsigned long spsr_und; -+ -+ unsigned long sp_irq; -+ unsigned long lr_irq; -+ unsigned long spsr_irq; -+ -+ unsigned long r8_fiq; -+ unsigned long r9_fiq; -+ unsigned long r10_fiq; -+ unsigned long r11_fiq; -+ unsigned long r12_fiq; -+ unsigned long sp_fiq; -+ unsigned long lr_fiq; -+ unsigned long spsr_fiq; -+}; -+ -+void __naked get_mode_regs(struct mode_regs *regs) -+{ -+ asm volatile ( -+ "mrs r1, cpsr\n" -+ "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" -+ "stmia r0!, {r13 - r14}\n" -+ "mrs r2, spsr\n" -+ "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" -+ "stmia r0!, {r2, r13 - r14}\n" -+ "mrs r2, spsr\n" -+ "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" -+ "stmia r0!, {r2, r13 - r14}\n" -+ "mrs r2, spsr\n" -+ "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" -+ "stmia r0!, {r2, r13 - r14}\n" -+ "mrs r2, spsr\n" -+ "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" -+ "stmia r0!, {r2, r8 - r14}\n" -+ "mrs r2, spsr\n" -+ "stmia r0!, {r2}\n" -+ "msr cpsr_c, r1\n" -+ "bx lr\n"); -+} -+ -+ -+static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs) -+{ -+ struct mode_regs mode_regs; -+ dump_regs(state, regs); -+ get_mode_regs(&mode_regs); -+ debug_printf(state, " svc: sp %08x lr %08x spsr %08x\n", -+ mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); -+ debug_printf(state, " abt: sp %08x lr %08x spsr %08x\n", -+ mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); -+ debug_printf(state, " und: sp %08x lr %08x spsr %08x\n", -+ mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); -+ debug_printf(state, " irq: sp %08x lr %08x spsr %08x\n", -+ mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); -+ debug_printf(state, " fiq: r8 %08x r9 %08x r10 %08x r11 %08x " -+ "r12 %08x\n", -+ mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, -+ mode_regs.r11_fiq, mode_regs.r12_fiq); -+ debug_printf(state, " fiq: sp %08x lr %08x spsr %08x\n", -+ mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); -+} -+ -+static void dump_irqs(struct fiq_debugger_state *state) -+{ -+ int n; -+ -+ debug_printf(state, "irqnr total since-last status name\n"); -+ for (n = 0; n < NR_IRQS; n++) { -+ struct irqaction *act = irq_desc[n].action; -+ if (!act && !kstat_irqs(n)) -+ continue; -+ debug_printf(state, "%5d: %10u %11u %8x %s\n", n, -+ kstat_irqs(n), -+ kstat_irqs(n) - state->last_irqs[n], -+ irq_desc[n].status_use_accessors, -+ (act && act->name) ? act->name : "???"); -+ state->last_irqs[n] = kstat_irqs(n); -+ } -+} -+ -+struct stacktrace_state { -+ struct fiq_debugger_state *state; -+ unsigned int depth; -+}; -+ -+static int report_trace(struct stackframe *frame, void *d) -+{ -+ struct stacktrace_state *sts = d; -+ -+ if (sts->depth) { -+ debug_printf(sts->state, -+ " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", -+ frame->pc, frame->pc, frame->lr, frame->lr, -+ frame->sp, frame->fp); -+ sts->depth--; -+ return 0; -+ } -+ debug_printf(sts->state, " ...\n"); -+ -+ return sts->depth == 0; -+} -+ -+struct frame_tail { -+ struct frame_tail *fp; -+ unsigned long sp; -+ unsigned long lr; -+} __attribute__((packed)); -+ -+static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, -+ struct frame_tail *tail) -+{ -+ struct frame_tail buftail[2]; -+ -+ /* Also check accessibility of one struct frame_tail beyond */ -+ if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { -+ debug_printf(state, " invalid frame pointer %p\n", tail); -+ return NULL; -+ } -+ if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { -+ debug_printf(state, -+ " failed to copy frame pointer %p\n", tail); -+ return NULL; -+ } -+ -+ debug_printf(state, " %p\n", buftail[0].lr); -+ -+ /* frame pointers should strictly progress back up the stack -+ * (towards higher addresses) */ -+ if (tail >= buftail[0].fp) -+ return NULL; -+ -+ return buftail[0].fp-1; -+} -+ -+void dump_stacktrace(struct fiq_debugger_state *state, -+ struct pt_regs * const regs, unsigned int depth, void *ssp) -+{ -+ struct frame_tail *tail; -+ struct thread_info *real_thread_info = THREAD_INFO(ssp); -+ struct stacktrace_state sts; -+ -+ sts.depth = depth; -+ sts.state = state; -+ *current_thread_info() = *real_thread_info; -+ -+ if (!current) -+ debug_printf(state, "current NULL\n"); -+ else -+ debug_printf(state, "pid: %d comm: %s\n", -+ current->pid, current->comm); -+ dump_regs(state, (unsigned *)regs); -+ -+ if (!user_mode(regs)) { -+ struct stackframe frame; -+ frame.fp = regs->ARM_fp; -+ frame.sp = regs->ARM_sp; -+ frame.lr = regs->ARM_lr; -+ frame.pc = regs->ARM_pc; -+ debug_printf(state, -+ " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", -+ regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, -+ regs->ARM_sp, regs->ARM_fp); -+ walk_stackframe(&frame, report_trace, &sts); -+ return; -+ } -+ -+ tail = ((struct frame_tail *) regs->ARM_fp) - 1; -+ while (depth-- && tail && !((unsigned long) tail & 3)) -+ tail = user_backtrace(state, tail); -+} -+ -+static void do_ps(struct fiq_debugger_state *state) -+{ -+ struct task_struct *g; -+ struct task_struct *p; -+ unsigned task_state; -+ static const char stat_nam[] = "RSDTtZX"; -+ -+ debug_printf(state, "pid ppid prio task pc\n"); -+ read_lock(&tasklist_lock); -+ do_each_thread(g, p) { -+ task_state = p->state ? __ffs(p->state) + 1 : 0; -+ debug_printf(state, -+ "%5d %5d %4d ", p->pid, p->parent->pid, p->prio); -+ debug_printf(state, "%-13.13s %c", p->comm, -+ task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]); -+ if (task_state == TASK_RUNNING) -+ debug_printf(state, " running\n"); -+ else -+ debug_printf(state, " %08lx\n", thread_saved_pc(p)); -+ } while_each_thread(g, p); -+ read_unlock(&tasklist_lock); -+} -+ -+#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -+static void begin_syslog_dump(struct fiq_debugger_state *state) -+{ -+ state->syslog_dumping = true; -+} -+ -+static void end_syslog_dump(struct fiq_debugger_state *state) -+{ -+ state->syslog_dumping = false; -+} -+#else -+extern int do_syslog(int type, char __user *bug, int count); -+static void begin_syslog_dump(struct fiq_debugger_state *state) -+{ -+ do_syslog(5 /* clear */, NULL, 0); -+} -+ -+static void end_syslog_dump(struct fiq_debugger_state *state) -+{ -+ char buf[128]; -+ int ret; -+ int idx = 0; -+ -+ while (1) { -+ ret = log_buf_copy(buf, idx, sizeof(buf) - 1); -+ if (ret <= 0) -+ break; -+ buf[ret] = 0; -+ debug_printf(state, "%s", buf); -+ idx += ret; -+ } -+} -+#endif -+ -+static void do_sysrq(struct fiq_debugger_state *state, char rq) -+{ -+ if ((rq == 'g' || rq == 'G') && !fiq_kgdb_enable) { -+ debug_printf(state, "sysrq-g blocked\n"); -+ return; -+ } -+ begin_syslog_dump(state); -+ handle_sysrq(rq); -+ end_syslog_dump(state); -+} -+ -+#ifdef CONFIG_KGDB -+static void do_kgdb(struct fiq_debugger_state *state) -+{ -+ if (!fiq_kgdb_enable) { -+ debug_printf(state, "kgdb through fiq debugger not enabled\n"); -+ return; -+ } -+ -+ debug_printf(state, "enabling console and triggering kgdb\n"); -+ state->console_enable = true; -+ handle_sysrq('g'); -+} -+#endif -+ -+static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&state->work_lock, flags); -+ if (state->work_cmd[0] != '\0') { -+ debug_printf(state, "work command processor busy\n"); -+ spin_unlock_irqrestore(&state->work_lock, flags); -+ return; -+ } -+ -+ strlcpy(state->work_cmd, cmd, sizeof(state->work_cmd)); -+ spin_unlock_irqrestore(&state->work_lock, flags); -+ -+ schedule_work(&state->work); -+} -+ -+static void debug_work(struct work_struct *work) -+{ -+ struct fiq_debugger_state *state; -+ char work_cmd[DEBUG_MAX]; -+ char *cmd; -+ unsigned long flags; -+ -+ state = container_of(work, struct fiq_debugger_state, work); -+ -+ spin_lock_irqsave(&state->work_lock, flags); -+ -+ strlcpy(work_cmd, state->work_cmd, sizeof(work_cmd)); -+ state->work_cmd[0] = '\0'; -+ -+ spin_unlock_irqrestore(&state->work_lock, flags); -+ -+ cmd = work_cmd; -+ if (!strncmp(cmd, "reboot", 6)) { -+ cmd += 6; -+ while (*cmd == ' ') -+ cmd++; -+ if (cmd != '\0') -+ kernel_restart(cmd); -+ else -+ kernel_restart(NULL); -+ } else { -+ debug_printf(state, "unknown work command '%s'\n", work_cmd); -+ } -+} -+ -+/* This function CANNOT be called in FIQ context */ -+static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd) -+{ -+ if (!strcmp(cmd, "ps")) -+ do_ps(state); -+ if (!strcmp(cmd, "sysrq")) -+ do_sysrq(state, 'h'); -+ if (!strncmp(cmd, "sysrq ", 6)) -+ do_sysrq(state, cmd[6]); -+#ifdef CONFIG_KGDB -+ if (!strcmp(cmd, "kgdb")) -+ do_kgdb(state); -+#endif -+ if (!strncmp(cmd, "reboot", 6)) -+ debug_schedule_work(state, cmd); -+} -+ -+static void debug_help(struct fiq_debugger_state *state) -+{ -+ debug_printf(state, "FIQ Debugger commands:\n" -+ " pc PC status\n" -+ " regs Register dump\n" -+ " allregs Extended Register dump\n" -+ " bt Stack trace\n" -+ " reboot [<c>] Reboot with command <c>\n" -+ " reset [<c>] Hard reset with command <c>\n" -+ " irqs Interupt status\n" -+ " kmsg Kernel log\n" -+ " version Kernel version\n"); -+ debug_printf(state, " sleep Allow sleep while in FIQ\n" -+ " nosleep Disable sleep while in FIQ\n" -+ " console Switch terminal to console\n" -+ " cpu Current CPU\n" -+ " cpu <number> Switch to CPU<number>\n"); -+ debug_printf(state, " ps Process list\n" -+ " sysrq sysrq options\n" -+ " sysrq <param> Execute sysrq with <param>\n"); -+#ifdef CONFIG_KGDB -+ debug_printf(state, " kgdb Enter kernel debugger\n"); -+#endif -+} -+ -+static void take_affinity(void *info) -+{ -+ struct fiq_debugger_state *state = info; -+ struct cpumask cpumask; -+ -+ cpumask_clear(&cpumask); -+ cpumask_set_cpu(get_cpu(), &cpumask); -+ -+ irq_set_affinity(state->uart_irq, &cpumask); -+} -+ -+static void switch_cpu(struct fiq_debugger_state *state, int cpu) -+{ -+ if (!debug_have_fiq(state)) -+ smp_call_function_single(cpu, take_affinity, state, false); -+ state->current_cpu = cpu; -+} -+ -+static bool debug_fiq_exec(struct fiq_debugger_state *state, -+ const char *cmd, unsigned *regs, void *svc_sp) -+{ -+ bool signal_helper = false; -+ -+ if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { -+ debug_help(state); -+ } else if (!strcmp(cmd, "pc")) { -+ debug_printf(state, " pc %08x cpsr %08x mode %s\n", -+ regs[15], regs[16], mode_name(regs[16])); -+ } else if (!strcmp(cmd, "regs")) { -+ dump_regs(state, regs); -+ } else if (!strcmp(cmd, "allregs")) { -+ dump_allregs(state, regs); -+ } else if (!strcmp(cmd, "bt")) { -+ dump_stacktrace(state, (struct pt_regs *)regs, 100, svc_sp); -+ } else if (!strncmp(cmd, "reset", 5)) { -+ cmd += 5; -+ while (*cmd == ' ') -+ cmd++; -+ if (*cmd) { -+ char tmp_cmd[32]; -+ strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd)); -+ machine_restart(tmp_cmd); -+ } else { -+ machine_restart(NULL); -+ } -+ } else if (!strcmp(cmd, "irqs")) { -+ dump_irqs(state); -+ } else if (!strcmp(cmd, "kmsg")) { -+ dump_kernel_log(state); -+ } else if (!strcmp(cmd, "version")) { -+ debug_printf(state, "%s\n", linux_banner); -+ } else if (!strcmp(cmd, "sleep")) { -+ state->no_sleep = false; -+ debug_printf(state, "enabling sleep\n"); -+ } else if (!strcmp(cmd, "nosleep")) { -+ state->no_sleep = true; -+ debug_printf(state, "disabling sleep\n"); -+ } else if (!strcmp(cmd, "console")) { -+ debug_printf(state, "console mode\n"); -+ debug_uart_flush(state); -+ state->console_enable = true; -+ } else if (!strcmp(cmd, "cpu")) { -+ debug_printf(state, "cpu %d\n", state->current_cpu); -+ } else if (!strncmp(cmd, "cpu ", 4)) { -+ unsigned long cpu = 0; -+ if (strict_strtoul(cmd + 4, 10, &cpu) == 0) -+ switch_cpu(state, cpu); -+ else -+ debug_printf(state, "invalid cpu\n"); -+ debug_printf(state, "cpu %d\n", state->current_cpu); -+ } else { -+ if (state->debug_busy) { -+ debug_printf(state, -+ "command processor busy. trying to abort.\n"); -+ state->debug_abort = -1; -+ } else { -+ strcpy(state->debug_cmd, cmd); -+ state->debug_busy = 1; -+ } -+ -+ return true; -+ } -+ if (!state->console_enable) -+ debug_prompt(state); -+ -+ return signal_helper; -+} -+ -+static void sleep_timer_expired(unsigned long data) -+{ -+ struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&state->sleep_timer_lock, flags); -+ if (state->uart_enabled && !state->no_sleep) { -+ if (state->debug_enable && !state->console_enable) { -+ state->debug_enable = false; -+ debug_printf_nfiq(state, "suspending fiq debugger\n"); -+ } -+ state->ignore_next_wakeup_irq = true; -+ debug_uart_disable(state); -+ state->uart_enabled = false; -+ enable_wakeup_irq(state); -+ } -+ wake_unlock(&state->debugger_wake_lock); -+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags); -+} -+ -+static void handle_wakeup(struct fiq_debugger_state *state) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&state->sleep_timer_lock, flags); -+ if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) { -+ state->ignore_next_wakeup_irq = false; -+ } else if (!state->uart_enabled) { -+ wake_lock(&state->debugger_wake_lock); -+ debug_uart_enable(state); -+ state->uart_enabled = true; -+ disable_wakeup_irq(state); -+ mod_timer(&state->sleep_timer, jiffies + HZ / 2); -+ } -+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags); -+} -+ -+static irqreturn_t wakeup_irq_handler(int irq, void *dev) -+{ -+ struct fiq_debugger_state *state = dev; -+ -+ if (!state->no_sleep) -+ debug_puts(state, "WAKEUP\n"); -+ handle_wakeup(state); -+ -+ return IRQ_HANDLED; -+} -+ -+ -+static void debug_handle_irq_context(struct fiq_debugger_state *state) -+{ -+ if (!state->no_sleep) { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&state->sleep_timer_lock, flags); -+ wake_lock(&state->debugger_wake_lock); -+ mod_timer(&state->sleep_timer, jiffies + HZ * 5); -+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags); -+ } -+#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) -+ if (state->tty) { -+ int i; -+ int count = fiq_debugger_ringbuf_level(state->tty_rbuf); -+ for (i = 0; i < count; i++) { -+ int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0); -+ tty_insert_flip_char(state->tty, c, TTY_NORMAL); -+ if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1)) -+ pr_warn("fiq tty failed to consume byte\n"); -+ } -+ tty_flip_buffer_push(state->tty); -+ } -+#endif -+ if (state->debug_busy) { -+ debug_irq_exec(state, state->debug_cmd); -+ if (!state->console_enable) -+ debug_prompt(state); -+ state->debug_busy = 0; -+ } -+} -+ -+static int debug_getc(struct fiq_debugger_state *state) -+{ -+ return state->pdata->uart_getc(state->pdev); -+} -+ -+static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, -+ int this_cpu, void *regs, void *svc_sp) -+{ -+ int c; -+ static int last_c; -+ int count = 0; -+ bool signal_helper = false; -+ -+ if (this_cpu != state->current_cpu) { -+ if (state->in_fiq) -+ return false; -+ -+ if (atomic_inc_return(&state->unhandled_fiq_count) != -+ MAX_UNHANDLED_FIQ_COUNT) -+ return false; -+ -+ debug_printf(state, "fiq_debugger: cpu %d not responding, " -+ "reverting to cpu %d\n", state->current_cpu, -+ this_cpu); -+ -+ atomic_set(&state->unhandled_fiq_count, 0); -+ switch_cpu(state, this_cpu); -+ return false; -+ } -+ -+ state->in_fiq = true; -+ -+ while ((c = debug_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { -+ count++; -+ if (!state->debug_enable) { -+ if ((c == 13) || (c == 10)) { -+ state->debug_enable = true; -+ state->debug_count = 0; -+ debug_prompt(state); -+ } -+ } else if (c == FIQ_DEBUGGER_BREAK) { -+ state->console_enable = false; -+ debug_puts(state, "fiq debugger mode\n"); -+ state->debug_count = 0; -+ debug_prompt(state); -+#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -+ } else if (state->console_enable && state->tty_rbuf) { -+ fiq_debugger_ringbuf_push(state->tty_rbuf, c); -+ signal_helper = true; -+#endif -+ } else if ((c >= ' ') && (c < 127)) { -+ if (state->debug_count < (DEBUG_MAX - 1)) { -+ state->debug_buf[state->debug_count++] = c; -+ debug_putc(state, c); -+ } -+ } else if ((c == 8) || (c == 127)) { -+ if (state->debug_count > 0) { -+ state->debug_count--; -+ debug_putc(state, 8); -+ debug_putc(state, ' '); -+ debug_putc(state, 8); -+ } -+ } else if ((c == 13) || (c == 10)) { -+ if (c == '\r' || (c == '\n' && last_c != '\r')) { -+ debug_putc(state, '\r'); -+ debug_putc(state, '\n'); -+ } -+ if (state->debug_count) { -+ state->debug_buf[state->debug_count] = 0; -+ state->debug_count = 0; -+ signal_helper |= -+ debug_fiq_exec(state, state->debug_buf, -+ regs, svc_sp); -+ } else { -+ debug_prompt(state); -+ } -+ } -+ last_c = c; -+ } -+ if (!state->console_enable) -+ debug_uart_flush(state); -+ if (state->pdata->fiq_ack) -+ state->pdata->fiq_ack(state->pdev, state->fiq); -+ -+ /* poke sleep timer if necessary */ -+ if (state->debug_enable && !state->no_sleep) -+ signal_helper = true; -+ -+ atomic_set(&state->unhandled_fiq_count, 0); -+ state->in_fiq = false; -+ -+ return signal_helper; -+} -+ -+static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) -+{ -+ struct fiq_debugger_state *state = -+ container_of(h, struct fiq_debugger_state, handler); -+ unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; -+ bool need_irq; -+ -+ need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp); -+ if (need_irq) -+ debug_force_irq(state); -+} -+ -+/* -+ * When not using FIQs, we only use this single interrupt as an entry point. -+ * This just effectively takes over the UART interrupt and does all the work -+ * in this context. -+ */ -+static irqreturn_t debug_uart_irq(int irq, void *dev) -+{ -+ struct fiq_debugger_state *state = dev; -+ bool not_done; -+ -+ handle_wakeup(state); -+ -+ /* handle the debugger irq in regular context */ -+ not_done = debug_handle_uart_interrupt(state, smp_processor_id(), -+ get_irq_regs(), -+ current_thread_info()); -+ if (not_done) -+ debug_handle_irq_context(state); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * If FIQs are used, not everything can happen in fiq context. -+ * FIQ handler does what it can and then signals this interrupt to finish the -+ * job in irq context. -+ */ -+static irqreturn_t debug_signal_irq(int irq, void *dev) -+{ -+ struct fiq_debugger_state *state = dev; -+ -+ if (state->pdata->force_irq_ack) -+ state->pdata->force_irq_ack(state->pdev, state->signal_irq); -+ -+ debug_handle_irq_context(state); -+ -+ return IRQ_HANDLED; -+} -+ -+static void debug_resume(struct fiq_glue_handler *h) -+{ -+ struct fiq_debugger_state *state = -+ container_of(h, struct fiq_debugger_state, handler); -+ if (state->pdata->uart_resume) -+ state->pdata->uart_resume(state->pdev); -+} -+ -+#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) -+struct tty_driver *debug_console_device(struct console *co, int *index) -+{ -+ *index = co->index; -+ return fiq_tty_driver; -+} -+ -+static void debug_console_write(struct console *co, -+ const char *s, unsigned int count) -+{ -+ struct fiq_debugger_state *state; -+ unsigned long flags; -+ -+ state = container_of(co, struct fiq_debugger_state, console); -+ -+ if (!state->console_enable && !state->syslog_dumping) -+ return; -+ -+ debug_uart_enable(state); -+ spin_lock_irqsave(&state->console_lock, flags); -+ while (count--) { -+ if (*s == '\n') -+ debug_putc(state, '\r'); -+ debug_putc(state, *s++); -+ } -+ debug_uart_flush(state); -+ spin_unlock_irqrestore(&state->console_lock, flags); -+ debug_uart_disable(state); -+} -+ -+static struct console fiq_debugger_console = { -+ .name = "ttyFIQ", -+ .device = debug_console_device, -+ .write = debug_console_write, -+ .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, -+}; -+ -+int fiq_tty_open(struct tty_struct *tty, struct file *filp) -+{ -+ int line = tty->index; -+ struct fiq_debugger_state **states = tty->driver->driver_state; -+ struct fiq_debugger_state *state = states[line]; -+ if (state->tty_open_count++) -+ return 0; -+ -+ tty->driver_data = state; -+ state->tty = tty; -+ return 0; -+} -+ -+void fiq_tty_close(struct tty_struct *tty, struct file *filp) -+{ -+ struct fiq_debugger_state *state = tty->driver_data; -+ if (--state->tty_open_count) -+ return; -+ state->tty = NULL; -+} -+ -+int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) -+{ -+ int i; -+ struct fiq_debugger_state *state = tty->driver_data; -+ -+ if (!state->console_enable) -+ return count; -+ -+ debug_uart_enable(state); -+ spin_lock_irq(&state->console_lock); -+ for (i = 0; i < count; i++) -+ debug_putc(state, *buf++); -+ spin_unlock_irq(&state->console_lock); -+ debug_uart_disable(state); -+ -+ return count; -+} -+ -+int fiq_tty_write_room(struct tty_struct *tty) -+{ -+ return 16; -+} -+ -+#ifdef CONFIG_CONSOLE_POLL -+static int fiq_tty_poll_init(struct tty_driver *driver, int line, char *options) -+{ -+ return 0; -+} -+ -+static int fiq_tty_poll_get_char(struct tty_driver *driver, int line) -+{ -+ struct fiq_debugger_state *state = driver->ttys[line]->driver_data; -+ int c = NO_POLL_CHAR; -+ -+ debug_uart_enable(state); -+ if (debug_have_fiq(state)) { -+ int count = fiq_debugger_ringbuf_level(state->tty_rbuf); -+ if (count > 0) { -+ c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0); -+ fiq_debugger_ringbuf_consume(state->tty_rbuf, 1); -+ } -+ } else { -+ c = debug_getc(state); -+ if (c == FIQ_DEBUGGER_NO_CHAR) -+ c = NO_POLL_CHAR; -+ } -+ debug_uart_disable(state); -+ -+ return c; -+} -+ -+static void fiq_tty_poll_put_char(struct tty_driver *driver, int line, char ch) -+{ -+ struct fiq_debugger_state *state = driver->ttys[line]->driver_data; -+ debug_uart_enable(state); -+ debug_putc(state, ch); -+ debug_uart_disable(state); -+} -+#endif -+ -+static const struct tty_operations fiq_tty_driver_ops = { -+ .write = fiq_tty_write, -+ .write_room = fiq_tty_write_room, -+ .open = fiq_tty_open, -+ .close = fiq_tty_close, -+#ifdef CONFIG_CONSOLE_POLL -+ .poll_init = fiq_tty_poll_init, -+ .poll_get_char = fiq_tty_poll_get_char, -+ .poll_put_char = fiq_tty_poll_put_char, -+#endif -+}; -+ -+static int fiq_debugger_tty_init(void) -+{ -+ int ret; -+ struct fiq_debugger_state **states = NULL; -+ -+ states = kzalloc(sizeof(*states) * MAX_FIQ_DEBUGGER_PORTS, GFP_KERNEL); -+ if (!states) { -+ pr_err("Failed to allocate fiq debugger state structres\n"); -+ return -ENOMEM; -+ } -+ -+ fiq_tty_driver = alloc_tty_driver(MAX_FIQ_DEBUGGER_PORTS); -+ if (!fiq_tty_driver) { -+ pr_err("Failed to allocate fiq debugger tty\n"); -+ ret = -ENOMEM; -+ goto err_free_state; -+ } -+ -+ fiq_tty_driver->owner = THIS_MODULE; -+ fiq_tty_driver->driver_name = "fiq-debugger"; -+ fiq_tty_driver->name = "ttyFIQ"; -+ fiq_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; -+ fiq_tty_driver->subtype = SERIAL_TYPE_NORMAL; -+ fiq_tty_driver->init_termios = tty_std_termios; -+ fiq_tty_driver->flags = TTY_DRIVER_REAL_RAW | -+ TTY_DRIVER_DYNAMIC_DEV; -+ fiq_tty_driver->driver_state = states; -+ -+ fiq_tty_driver->init_termios.c_cflag = -+ B115200 | CS8 | CREAD | HUPCL | CLOCAL; -+ fiq_tty_driver->init_termios.c_ispeed = 115200; -+ fiq_tty_driver->init_termios.c_ospeed = 115200; -+ -+ tty_set_operations(fiq_tty_driver, &fiq_tty_driver_ops); -+ -+ ret = tty_register_driver(fiq_tty_driver); -+ if (ret) { -+ pr_err("Failed to register fiq tty: %d\n", ret); -+ goto err_free_tty; -+ } -+ -+ pr_info("Registered FIQ tty driver\n"); -+ return 0; -+ -+err_free_tty: -+ put_tty_driver(fiq_tty_driver); -+ fiq_tty_driver = NULL; -+err_free_state: -+ kfree(states); -+ return ret; -+} -+ -+static int fiq_debugger_tty_init_one(struct fiq_debugger_state *state) -+{ -+ int ret; -+ struct device *tty_dev; -+ struct fiq_debugger_state **states = fiq_tty_driver->driver_state; -+ -+ states[state->pdev->id] = state; -+ -+ state->tty_rbuf = fiq_debugger_ringbuf_alloc(1024); -+ if (!state->tty_rbuf) { -+ pr_err("Failed to allocate fiq debugger ringbuf\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ tty_dev = tty_register_device(fiq_tty_driver, state->pdev->id, -+ &state->pdev->dev); -+ if (IS_ERR(tty_dev)) { -+ pr_err("Failed to register fiq debugger tty device\n"); -+ ret = PTR_ERR(tty_dev); -+ goto err; -+ } -+ -+ device_set_wakeup_capable(tty_dev, 1); -+ -+ pr_info("Registered fiq debugger ttyFIQ%d\n", state->pdev->id); -+ -+ return 0; -+ -+err: -+ fiq_debugger_ringbuf_free(state->tty_rbuf); -+ state->tty_rbuf = NULL; -+ return ret; -+} -+#endif -+ -+static int fiq_debugger_dev_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct fiq_debugger_state *state = platform_get_drvdata(pdev); -+ -+ if (state->pdata->uart_dev_suspend) -+ return state->pdata->uart_dev_suspend(pdev); -+ return 0; -+} -+ -+static int fiq_debugger_dev_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct fiq_debugger_state *state = platform_get_drvdata(pdev); -+ -+ if (state->pdata->uart_dev_resume) -+ return state->pdata->uart_dev_resume(pdev); -+ return 0; -+} -+ -+static int fiq_debugger_probe(struct platform_device *pdev) -+{ -+ int ret; -+ struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev); -+ struct fiq_debugger_state *state; -+ int fiq; -+ int uart_irq; -+ -+ if (pdev->id >= MAX_FIQ_DEBUGGER_PORTS) -+ return -EINVAL; -+ -+ if (!pdata->uart_getc || !pdata->uart_putc) -+ return -EINVAL; -+ if ((pdata->uart_enable && !pdata->uart_disable) || -+ (!pdata->uart_enable && pdata->uart_disable)) -+ return -EINVAL; -+ -+ fiq = platform_get_irq_byname(pdev, "fiq"); -+ uart_irq = platform_get_irq_byname(pdev, "uart_irq"); -+ -+ /* uart_irq mode and fiq mode are mutually exclusive, but one of them -+ * is required */ -+ if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0)) -+ return -EINVAL; -+ if (fiq >= 0 && !pdata->fiq_enable) -+ return -EINVAL; -+ -+ state = kzalloc(sizeof(*state), GFP_KERNEL); -+ setup_timer(&state->sleep_timer, sleep_timer_expired, -+ (unsigned long)state); -+ state->pdata = pdata; -+ state->pdev = pdev; -+ state->no_sleep = initial_no_sleep; -+ state->debug_enable = initial_debug_enable; -+ state->console_enable = initial_console_enable; -+ -+ state->fiq = fiq; -+ state->uart_irq = uart_irq; -+ state->signal_irq = platform_get_irq_byname(pdev, "signal"); -+ state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); -+ -+ INIT_WORK(&state->work, debug_work); -+ spin_lock_init(&state->work_lock); -+ -+ platform_set_drvdata(pdev, state); -+ -+ spin_lock_init(&state->sleep_timer_lock); -+ -+ if (state->wakeup_irq < 0 && debug_have_fiq(state)) -+ state->no_sleep = true; -+ state->ignore_next_wakeup_irq = !state->no_sleep; -+ -+ wake_lock_init(&state->debugger_wake_lock, -+ WAKE_LOCK_SUSPEND, "serial-debug"); -+ -+ state->clk = clk_get(&pdev->dev, NULL); -+ if (IS_ERR(state->clk)) -+ state->clk = NULL; -+ -+ /* do not call pdata->uart_enable here since uart_init may still -+ * need to do some initialization before uart_enable can work. -+ * So, only try to manage the clock during init. -+ */ -+ if (state->clk) -+ clk_enable(state->clk); -+ -+ if (pdata->uart_init) { -+ ret = pdata->uart_init(pdev); -+ if (ret) -+ goto err_uart_init; -+ } -+ -+ debug_printf_nfiq(state, "<hit enter %sto activate fiq debugger>\n", -+ state->no_sleep ? "" : "twice "); -+ -+ if (debug_have_fiq(state)) { -+ state->handler.fiq = debug_fiq; -+ state->handler.resume = debug_resume; -+ ret = fiq_glue_register_handler(&state->handler); -+ if (ret) { -+ pr_err("%s: could not install fiq handler\n", __func__); -+ goto err_register_fiq; -+ } -+ -+ pdata->fiq_enable(pdev, state->fiq, 1); -+ } else { -+ ret = request_irq(state->uart_irq, debug_uart_irq, -+ IRQF_NO_SUSPEND, "debug", state); -+ if (ret) { -+ pr_err("%s: could not install irq handler\n", __func__); -+ goto err_register_irq; -+ } -+ -+ /* for irq-only mode, we want this irq to wake us up, if it -+ * can. -+ */ -+ enable_irq_wake(state->uart_irq); -+ } -+ -+ if (state->clk) -+ clk_disable(state->clk); -+ -+ if (state->signal_irq >= 0) { -+ ret = request_irq(state->signal_irq, debug_signal_irq, -+ IRQF_TRIGGER_RISING, "debug-signal", state); -+ if (ret) -+ pr_err("serial_debugger: could not install signal_irq"); -+ } -+ -+ if (state->wakeup_irq >= 0) { -+ ret = request_irq(state->wakeup_irq, wakeup_irq_handler, -+ IRQF_TRIGGER_FALLING | IRQF_DISABLED, -+ "debug-wakeup", state); -+ if (ret) { -+ pr_err("serial_debugger: " -+ "could not install wakeup irq\n"); -+ state->wakeup_irq = -1; -+ } else { -+ ret = enable_irq_wake(state->wakeup_irq); -+ if (ret) { -+ pr_err("serial_debugger: " -+ "could not enable wakeup\n"); -+ state->wakeup_irq_no_set_wake = true; -+ } -+ } -+ } -+ if (state->no_sleep) -+ handle_wakeup(state); -+ -+#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) -+ spin_lock_init(&state->console_lock); -+ state->console = fiq_debugger_console; -+ state->console.index = pdev->id; -+ if (!console_set_on_cmdline) -+ add_preferred_console(state->console.name, -+ state->console.index, NULL); -+ register_console(&state->console); -+ fiq_debugger_tty_init_one(state); -+#endif -+ return 0; -+ -+err_register_irq: -+err_register_fiq: -+ if (pdata->uart_free) -+ pdata->uart_free(pdev); -+err_uart_init: -+ if (state->clk) -+ clk_disable(state->clk); -+ if (state->clk) -+ clk_put(state->clk); -+ wake_lock_destroy(&state->debugger_wake_lock); -+ platform_set_drvdata(pdev, NULL); -+ kfree(state); -+ return ret; -+} -+ -+static const struct dev_pm_ops fiq_debugger_dev_pm_ops = { -+ .suspend = fiq_debugger_dev_suspend, -+ .resume = fiq_debugger_dev_resume, -+}; -+ -+static struct platform_driver fiq_debugger_driver = { -+ .probe = fiq_debugger_probe, -+ .driver = { -+ .name = "fiq_debugger", -+ .pm = &fiq_debugger_dev_pm_ops, -+ }, -+}; -+ -+static int __init fiq_debugger_init(void) -+{ -+ fiq_debugger_tty_init(); -+ return platform_driver_register(&fiq_debugger_driver); -+} -+ -+postcore_initcall(fiq_debugger_init); -diff --git a/arch/arm/common/fiq_debugger_ringbuf.h b/arch/arm/common/fiq_debugger_ringbuf.h -new file mode 100644 -index 00000000..2649b558 ---- /dev/null -+++ b/arch/arm/common/fiq_debugger_ringbuf.h -@@ -0,0 +1,94 @@ -+/* -+ * arch/arm/common/fiq_debugger_ringbuf.c -+ * -+ * simple lockless ringbuffer -+ * -+ * Copyright (C) 2010 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+ -+struct fiq_debugger_ringbuf { -+ int len; -+ int head; -+ int tail; -+ u8 buf[]; -+}; -+ -+ -+static inline struct fiq_debugger_ringbuf *fiq_debugger_ringbuf_alloc(int len) -+{ -+ struct fiq_debugger_ringbuf *rbuf; -+ -+ rbuf = kzalloc(sizeof(*rbuf) + len, GFP_KERNEL); -+ if (rbuf == NULL) -+ return NULL; -+ -+ rbuf->len = len; -+ rbuf->head = 0; -+ rbuf->tail = 0; -+ smp_mb(); -+ -+ return rbuf; -+} -+ -+static inline void fiq_debugger_ringbuf_free(struct fiq_debugger_ringbuf *rbuf) -+{ -+ kfree(rbuf); -+} -+ -+static inline int fiq_debugger_ringbuf_level(struct fiq_debugger_ringbuf *rbuf) -+{ -+ int level = rbuf->head - rbuf->tail; -+ -+ if (level < 0) -+ level = rbuf->len + level; -+ -+ return level; -+} -+ -+static inline int fiq_debugger_ringbuf_room(struct fiq_debugger_ringbuf *rbuf) -+{ -+ return rbuf->len - fiq_debugger_ringbuf_level(rbuf) - 1; -+} -+ -+static inline u8 -+fiq_debugger_ringbuf_peek(struct fiq_debugger_ringbuf *rbuf, int i) -+{ -+ return rbuf->buf[(rbuf->tail + i) % rbuf->len]; -+} -+ -+static inline int -+fiq_debugger_ringbuf_consume(struct fiq_debugger_ringbuf *rbuf, int count) -+{ -+ count = min(count, fiq_debugger_ringbuf_level(rbuf)); -+ -+ rbuf->tail = (rbuf->tail + count) % rbuf->len; -+ smp_mb(); -+ -+ return count; -+} -+ -+static inline int -+fiq_debugger_ringbuf_push(struct fiq_debugger_ringbuf *rbuf, u8 datum) -+{ -+ if (fiq_debugger_ringbuf_room(rbuf) == 0) -+ return 0; -+ -+ rbuf->buf[rbuf->head] = datum; -+ smp_mb(); -+ rbuf->head = (rbuf->head + 1) % rbuf->len; -+ smp_mb(); -+ -+ return 1; -+} -diff --git a/arch/arm/common/fiq_glue.S b/arch/arm/common/fiq_glue.S -new file mode 100644 -index 00000000..9e3455a0 ---- /dev/null -+++ b/arch/arm/common/fiq_glue.S -@@ -0,0 +1,111 @@ -+/* -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/linkage.h> -+#include <asm/assembler.h> -+ -+ .text -+ -+ .global fiq_glue_end -+ -+ /* fiq stack: r0-r15,cpsr,spsr of interrupted mode */ -+ -+ENTRY(fiq_glue) -+ /* store pc, cpsr from previous mode */ -+ mrs r12, spsr -+ sub r11, lr, #4 -+ subs r10, #1 -+ bne nested_fiq -+ -+ stmfd sp!, {r11-r12, lr} -+ -+ /* store r8-r14 from previous mode */ -+ sub sp, sp, #(7 * 4) -+ stmia sp, {r8-r14}^ -+ nop -+ -+ /* store r0-r7 from previous mode */ -+ stmfd sp!, {r0-r7} -+ -+ /* setup func(data,regs) arguments */ -+ mov r0, r9 -+ mov r1, sp -+ mov r3, r8 -+ -+ mov r7, sp -+ -+ /* Get sp and lr from non-user modes */ -+ and r4, r12, #MODE_MASK -+ cmp r4, #USR_MODE -+ beq fiq_from_usr_mode -+ -+ mov r7, sp -+ orr r4, r4, #(PSR_I_BIT | PSR_F_BIT) -+ msr cpsr_c, r4 -+ str sp, [r7, #(4 * 13)] -+ str lr, [r7, #(4 * 14)] -+ mrs r5, spsr -+ str r5, [r7, #(4 * 17)] -+ -+ cmp r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) -+ /* use fiq stack if we reenter this mode */ -+ subne sp, r7, #(4 * 3) -+ -+fiq_from_usr_mode: -+ msr cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) -+ mov r2, sp -+ sub sp, r7, #12 -+ stmfd sp!, {r2, ip, lr} -+ /* call func(data,regs) */ -+ blx r3 -+ ldmfd sp, {r2, ip, lr} -+ mov sp, r2 -+ -+ /* restore/discard saved state */ -+ cmp r4, #USR_MODE -+ beq fiq_from_usr_mode_exit -+ -+ msr cpsr_c, r4 -+ ldr sp, [r7, #(4 * 13)] -+ ldr lr, [r7, #(4 * 14)] -+ msr spsr_cxsf, r5 -+ -+fiq_from_usr_mode_exit: -+ msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) -+ -+ ldmfd sp!, {r0-r7} -+ add sp, sp, #(7 * 4) -+ ldmfd sp!, {r11-r12, lr} -+exit_fiq: -+ msr spsr_cxsf, r12 -+ add r10, #1 -+ movs pc, r11 -+ -+nested_fiq: -+ orr r12, r12, #(PSR_F_BIT) -+ b exit_fiq -+ -+fiq_glue_end: -+ -+ENTRY(fiq_glue_setup) /* func, data, sp */ -+ mrs r3, cpsr -+ msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) -+ movs r8, r0 -+ mov r9, r1 -+ mov sp, r2 -+ moveq r10, #0 -+ movne r10, #1 -+ msr cpsr_c, r3 -+ bx lr -+ -diff --git a/arch/arm/common/fiq_glue_setup.c b/arch/arm/common/fiq_glue_setup.c -new file mode 100644 -index 00000000..4044c7db ---- /dev/null -+++ b/arch/arm/common/fiq_glue_setup.c -@@ -0,0 +1,100 @@ -+/* -+ * Copyright (C) 2010 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/percpu.h> -+#include <linux/slab.h> -+#include <asm/fiq.h> -+#include <asm/fiq_glue.h> -+ -+extern unsigned char fiq_glue, fiq_glue_end; -+extern void fiq_glue_setup(void *func, void *data, void *sp); -+ -+static struct fiq_handler fiq_debbuger_fiq_handler = { -+ .name = "fiq_glue", -+}; -+DEFINE_PER_CPU(void *, fiq_stack); -+static struct fiq_glue_handler *current_handler; -+static DEFINE_MUTEX(fiq_glue_lock); -+ -+static void fiq_glue_setup_helper(void *info) -+{ -+ struct fiq_glue_handler *handler = info; -+ fiq_glue_setup(handler->fiq, handler, -+ __get_cpu_var(fiq_stack) + THREAD_START_SP); -+} -+ -+int fiq_glue_register_handler(struct fiq_glue_handler *handler) -+{ -+ int ret; -+ int cpu; -+ -+ if (!handler || !handler->fiq) -+ return -EINVAL; -+ -+ mutex_lock(&fiq_glue_lock); -+ if (fiq_stack) { -+ ret = -EBUSY; -+ goto err_busy; -+ } -+ -+ for_each_possible_cpu(cpu) { -+ void *stack; -+ stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); -+ if (WARN_ON(!stack)) { -+ ret = -ENOMEM; -+ goto err_alloc_fiq_stack; -+ } -+ per_cpu(fiq_stack, cpu) = stack; -+ } -+ -+ ret = claim_fiq(&fiq_debbuger_fiq_handler); -+ if (WARN_ON(ret)) -+ goto err_claim_fiq; -+ -+ current_handler = handler; -+ on_each_cpu(fiq_glue_setup_helper, handler, true); -+ set_fiq_handler(&fiq_glue, &fiq_glue_end - &fiq_glue); -+ -+ mutex_unlock(&fiq_glue_lock); -+ return 0; -+ -+err_claim_fiq: -+err_alloc_fiq_stack: -+ for_each_possible_cpu(cpu) { -+ __free_pages(per_cpu(fiq_stack, cpu), THREAD_SIZE_ORDER); -+ per_cpu(fiq_stack, cpu) = NULL; -+ } -+err_busy: -+ mutex_unlock(&fiq_glue_lock); -+ return ret; -+} -+ -+/** -+ * fiq_glue_resume - Restore fiqs after suspend or low power idle states -+ * -+ * This must be called before calling local_fiq_enable after returning from a -+ * power state where the fiq mode registers were lost. If a driver provided -+ * a resume hook when it registered the handler it will be called. -+ */ -+ -+void fiq_glue_resume(void) -+{ -+ if (!current_handler) -+ return; -+ fiq_glue_setup(current_handler->fiq, current_handler, -+ __get_cpu_var(fiq_stack) + THREAD_START_SP); -+ if (current_handler->resume) -+ current_handler->resume(current_handler); -+} -+ -diff --git a/arch/arm/configs/aimer39_ak3916_defconfig b/arch/arm/configs/aimer39_ak3916_defconfig -new file mode 100644 -index 00000000..294c522a ---- /dev/null -+++ b/arch/arm/configs/aimer39_ak3916_defconfig -@@ -0,0 +1,1962 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# Linux/arm 3.4.35 Kernel Configuration -+# -+CONFIG_ARM=y -+CONFIG_SYS_SUPPORTS_APM_EMULATION=y -+CONFIG_GENERIC_GPIO=y -+CONFIG_ARCH_USES_GETTIMEOFFSET=y -+CONFIG_KTIME_SCALAR=y -+CONFIG_HAVE_PROC_CPU=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_HAVE_LATENCYTOP_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+CONFIG_HARDIRQS_SW_RESEND=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+CONFIG_ARCH_HAS_CPUFREQ=y -+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_NEED_DMA_MAP_STATE=y -+CONFIG_VECTORS_BASE=0xffff0000 -+# CONFIG_ARM_PATCH_PHYS_VIRT is not set -+CONFIG_PHYS_OFFSET=0x81000000 -+CONFIG_GENERIC_BUG=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+CONFIG_HAVE_IRQ_WORK=y -+ -+# -+# General setup -+# -+# CONFIG_EXPERIMENTAL is not set -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_CROSS_COMPILE="" -+CONFIG_LOCALVERSION="" -+# CONFIG_LOCALVERSION_AUTO is not set -+CONFIG_HAVE_KERNEL_GZIP=y -+CONFIG_HAVE_KERNEL_LZMA=y -+CONFIG_HAVE_KERNEL_XZ=y -+CONFIG_HAVE_KERNEL_LZO=y -+# CONFIG_KERNEL_GZIP is not set -+# CONFIG_KERNEL_LZMA is not set -+# CONFIG_KERNEL_XZ is not set -+CONFIG_KERNEL_LZO=y -+CONFIG_DEFAULT_HOSTNAME="(none)" -+# CONFIG_SWAP is not set -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_FHANDLE is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_AUDIT is not set -+CONFIG_HAVE_GENERIC_HARDIRQS=y -+ -+# -+# IRQ subsystem -+# -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_SHOW=y -+ -+# -+# RCU Subsystem -+# -+CONFIG_TINY_RCU=y -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=16 -+# CONFIG_CGROUPS is not set -+# CONFIG_CHECKPOINT_RESTORE is not set -+# CONFIG_NAMESPACES is not set -+# CONFIG_SCHED_AUTOGROUP is not set -+# CONFIG_SYSFS_DEPRECATED is not set -+# CONFIG_RELAY is not set -+# CONFIG_BLK_DEV_INITRD is not set -+CONFIG_CC_OPTIMIZE_FOR_SIZE=y -+CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y -+CONFIG_PANIC_TIMEOUT=0 -+CONFIG_EXPERT=y -+CONFIG_UID16=y -+# CONFIG_SYSCTL_SYSCALL is not set -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_ALL 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_SIGNALFD=y -+CONFIG_TIMERFD=y -+CONFIG_EVENTFD=y -+# CONFIG_SHMEM is not set -+CONFIG_AIO=y -+CONFIG_EMBEDDED=y -+CONFIG_HAVE_PERF_EVENTS=y -+CONFIG_PERF_USE_VMALLOC=y -+ -+# -+# Kernel Performance Events And Counters -+# -+# CONFIG_PERF_EVENTS is not set -+# CONFIG_PERF_COUNTERS is not set -+# CONFIG_VM_EVENT_COUNTERS is not set -+# CONFIG_SLUB_DEBUG is not set -+CONFIG_COMPAT_BRK=y -+# CONFIG_SLAB is not set -+CONFIG_SLUB=y -+# CONFIG_SLOB is not set -+# CONFIG_PROFILING is not set -+CONFIG_HAVE_OPROFILE=y -+# CONFIG_KPROBES is not set -+CONFIG_JUMP_LABEL=y -+CONFIG_HAVE_KPROBES=y -+CONFIG_HAVE_KRETPROBES=y -+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -+CONFIG_HAVE_CLK=y -+CONFIG_HAVE_DMA_API_DEBUG=y -+CONFIG_HAVE_ARCH_JUMP_LABEL=y -+ -+# -+# GCOV-based kernel profiling -+# -+CONFIG_HAVE_GENERIC_DMA_COHERENT=y -+CONFIG_RT_MUTEXES=y -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_FORCE_LOAD=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODVERSIONS is not set -+# CONFIG_MODULE_SRCVERSION_ALL is not set -+CONFIG_BLOCK=y -+# CONFIG_LBDAF is not set -+# CONFIG_BLK_DEV_BSG is not set -+# CONFIG_BLK_DEV_BSGLIB is not set -+# CONFIG_BLK_DEV_INTEGRITY is not set -+ -+# -+# Partition Types -+# -+# CONFIG_PARTITION_ADVANCED is not set -+CONFIG_MSDOS_PARTITION=y -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+# CONFIG_IOSCHED_DEADLINE is not set -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_CFQ=y -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="cfq" -+# CONFIG_INLINE_SPIN_TRYLOCK is not set -+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK is not set -+# CONFIG_INLINE_SPIN_LOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_READ_TRYLOCK is not set -+# CONFIG_INLINE_READ_LOCK is not set -+# CONFIG_INLINE_READ_LOCK_BH is not set -+# CONFIG_INLINE_READ_LOCK_IRQ is not set -+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -+CONFIG_INLINE_READ_UNLOCK=y -+# CONFIG_INLINE_READ_UNLOCK_BH is not set -+CONFIG_INLINE_READ_UNLOCK_IRQ=y -+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_WRITE_TRYLOCK is not set -+# CONFIG_INLINE_WRITE_LOCK is not set -+# CONFIG_INLINE_WRITE_LOCK_BH is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -+CONFIG_INLINE_WRITE_UNLOCK=y -+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -+# CONFIG_MUTEX_SPIN_ON_OWNER is not set -+CONFIG_FREEZER=y -+ -+# -+# System Type -+# -+CONFIG_MMU=y -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_REALVIEW is not set -+# CONFIG_ARCH_VERSATILE is not set -+# CONFIG_ARCH_VEXPRESS is not set -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_BCMRING is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_CLPS711X is not set -+# CONFIG_ARCH_CNS3XXX is not set -+# CONFIG_ARCH_GEMINI is not set -+# CONFIG_ARCH_PRIMA2 is not set -+# CONFIG_ARCH_EBSA110 is not set -+# CONFIG_ARCH_EP93XX is not set -+# CONFIG_ARCH_FOOTBRIDGE is not set -+# CONFIG_ARCH_MXC is not set -+# CONFIG_ARCH_MXS is not set -+# CONFIG_ARCH_NETX is not set -+# CONFIG_ARCH_H720X is not set -+# CONFIG_ARCH_IOP13XX is not set -+# CONFIG_ARCH_IOP32X is not set -+# CONFIG_ARCH_IOP33X is not set -+# CONFIG_ARCH_IXP23XX is not set -+# CONFIG_ARCH_IXP2000 is not set -+# CONFIG_ARCH_IXP4XX is not set -+# CONFIG_ARCH_DOVE is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_MV78XX0 is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_ARCH_MMP is not set -+# CONFIG_ARCH_KS8695 is not set -+# CONFIG_ARCH_W90X900 is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_PICOXCELL is not set -+# CONFIG_ARCH_PNX4008 is not set -+# CONFIG_ARCH_PXA is not set -+# CONFIG_ARCH_MSM is not set -+# CONFIG_ARCH_SHMOBILE is not set -+# CONFIG_ARCH_RPC is not set -+# CONFIG_ARCH_SA1100 is not set -+# CONFIG_ARCH_S3C24XX is not set -+# CONFIG_ARCH_S3C64XX is not set -+# CONFIG_ARCH_S5P64X0 is not set -+# CONFIG_ARCH_S5PC100 is not set -+# CONFIG_ARCH_S5PV210 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_SHARK is not set -+# CONFIG_ARCH_U300 is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_NOMADIK is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_OMAP is not set -+# CONFIG_PLAT_SPEAR is not set -+# CONFIG_ARCH_VT8500 is not set -+# CONFIG_ARCH_ZYNQ is not set -+CONFIG_ARCH_AK39=y -+# CONFIG_GPIO_PCA953X is not set -+# CONFIG_KEYBOARD_GPIO_POLLED is not set -+ -+# -+# System MMU -+# -+CONFIG_CPU_AK3916=y -+# CONFIG_ARCH_SDK3910 is not set -+CONFIG_ARCH_AIMER39_AK3916=y -+# CONFIG_ARCH_AIMER39_AK3918 is not set -+CONFIG_ASIC_FREQ_VALUE=90000000 -+ -+# -+# Power management -+# -+# CONFIG_AK39_PM is not set -+# CONFIG_AK39_PWM_TIMER is not set -+CONFIG_PLAT_ANYKA=y -+ -+# -+# Processor Type -+# -+CONFIG_CPU_ARM926T=y -+CONFIG_CPU_32v5=y -+CONFIG_CPU_ABRT_EV5TJ=y -+CONFIG_CPU_PABRT_LEGACY=y -+CONFIG_CPU_CACHE_VIVT=y -+CONFIG_CPU_COPY_V4WB=y -+CONFIG_CPU_TLB_V4WBI=y -+CONFIG_CPU_CP15=y -+CONFIG_CPU_CP15_MMU=y -+CONFIG_CPU_USE_DOMAINS=y -+ -+# -+# Processor Features -+# -+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -+# CONFIG_ARM_THUMB is not set -+# CONFIG_CPU_ICACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set -+# CONFIG_CACHE_L2X0 is not set -+CONFIG_ARM_L1_CACHE_SHIFT=5 -+CONFIG_ARM_NR_BANKS=8 -+# CONFIG_FIQ_DEBUGGER is not set -+ -+# -+# Bus support -+# -+# CONFIG_PCI_SYSCALL is not set -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_PCCARD=y -+CONFIG_PCMCIA=y -+ -+# -+# PC-card bridges -+# -+ -+# -+# Kernel Features -+# -+CONFIG_VMSPLIT_3G=y -+# CONFIG_VMSPLIT_2G is not set -+# CONFIG_VMSPLIT_1G is not set -+CONFIG_PAGE_OFFSET=0xC0000000 -+CONFIG_ARCH_NR_GPIO=0 -+CONFIG_PREEMPT_NONE=y -+# CONFIG_PREEMPT_VOLUNTARY is not set -+# CONFIG_PREEMPT is not set -+CONFIG_HZ=100 -+CONFIG_AEABI=y -+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -+CONFIG_HAVE_ARCH_PFN_VALID=y -+# CONFIG_HIGHMEM is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+CONFIG_HAVE_MEMBLOCK=y -+CONFIG_PAGEFLAGS_EXTENDED=y -+CONFIG_SPLIT_PTLOCK_CPUS=999999 -+# CONFIG_COMPACTION is not set -+# CONFIG_PHYS_ADDR_T_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_KSM is not set -+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -+CONFIG_NEED_PER_CPU_KM=y -+# CONFIG_CLEANCACHE is not set -+CONFIG_FORCE_MAX_ZONEORDER=11 -+CONFIG_ALIGNMENT_TRAP=y -+# CONFIG_SECCOMP is not set -+# CONFIG_DEPRECATED_PARAM_STRUCT is not set -+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -+ -+# -+# Boot options -+# -+# CONFIG_USE_OF is not set -+CONFIG_ZBOOT_ROM_TEXT=0 -+CONFIG_ZBOOT_ROM_BSS=0 -+CONFIG_CMDLINE="root=/dev/mtdblock1 ro init=/sbin/init mem=64M console=ttySAK0,115200" -+CONFIG_CMDLINE_FROM_BOOTLOADER=y -+# CONFIG_CMDLINE_EXTEND is not set -+# CONFIG_CMDLINE_FORCE is not set -+# CONFIG_XIP_KERNEL is not set -+# CONFIG_AUTO_ZRELADDR is not set -+CONFIG_RAM_BASE=0x80000000 -+CONFIG_VIDEO_RESERVED_MEM_SIZE=0x1000000 -+ -+# -+# CPU Power Management -+# -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ is not set -+# CONFIG_CPU_IDLE is not set -+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set -+ -+# -+# Floating point emulation -+# -+ -+# -+# At least one emulation must be selected -+# -+# CONFIG_VFP is not set -+ -+# -+# Userspace binary formats -+# -+CONFIG_BINFMT_ELF=y -+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -+CONFIG_HAVE_AOUT=y -+# CONFIG_BINFMT_AOUT is not set -+# CONFIG_BINFMT_MISC is not set -+ -+# -+# Power management options -+# -+CONFIG_SUSPEND=y -+CONFIG_SUSPEND_FREEZER=y -+CONFIG_HAS_WAKELOCK=y -+CONFIG_WAKELOCK=y -+CONFIG_PM_SLEEP=y -+# CONFIG_PM_AUTOSLEEP is not set -+# CONFIG_PM_WAKELOCKS is not set -+# CONFIG_PM_RUNTIME is not set -+CONFIG_PM=y -+# CONFIG_PM_DEBUG is not set -+# CONFIG_APM_EMULATION is not set -+CONFIG_PM_CLK=y -+CONFIG_CPU_PM=y -+# CONFIG_SUSPEND_TIME is not set -+CONFIG_ARCH_SUSPEND_POSSIBLE=y -+CONFIG_ARM_CPU_SUSPEND=y -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+CONFIG_UNIX=y -+CONFIG_UNIX_DIAG=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+CONFIG_IP_MULTICAST=y -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+CONFIG_IP_PNP_RARP=y -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE_DEMUX is not set -+# CONFIG_IP_MROUTE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+CONFIG_INET_LRO=y -+CONFIG_INET_DIAG=y -+CONFIG_INET_TCP_DIAG=y -+CONFIG_INET_UDP_DIAG=y -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_IPV6 is not set -+CONFIG_ANDROID_PARANOID_NETWORK=y -+CONFIG_NET_ACTIVITY_STATS=y -+# CONFIG_NETWORK_SECMARK is not set -+CONFIG_NETFILTER=y -+# CONFIG_NETFILTER_DEBUG is not set -+CONFIG_NETFILTER_ADVANCED=y -+ -+# -+# Core Netfilter Configuration -+# -+# CONFIG_NETFILTER_NETLINK_ACCT is not set -+# CONFIG_NETFILTER_NETLINK_QUEUE is not set -+# CONFIG_NETFILTER_NETLINK_LOG is not set -+# CONFIG_NF_CONNTRACK is not set -+# CONFIG_NETFILTER_XTABLES is not set -+# CONFIG_IP_VS is not set -+ -+# -+# IP: Netfilter Configuration -+# -+# CONFIG_NF_DEFRAG_IPV4 is not set -+# CONFIG_IP_NF_QUEUE is not set -+# CONFIG_IP_NF_IPTABLES is not set -+# CONFIG_IP_NF_ARPTABLES is not set -+# CONFIG_ATM is not set -+# CONFIG_L2TP 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_PHONET is not set -+# CONFIG_NET_SCHED is not set -+# CONFIG_DCB is not set -+# CONFIG_BATMAN_ADV is not set -+# CONFIG_OPENVSWITCH is not set -+CONFIG_BQL=y -+CONFIG_HAVE_BPF_JIT=y -+# CONFIG_BPF_JIT is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_CAN is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+CONFIG_WIRELESS=y -+CONFIG_WIRELESS_EXT=y -+CONFIG_WEXT_CORE=y -+CONFIG_WEXT_PROC=y -+CONFIG_WEXT_SPY=y -+CONFIG_WEXT_PRIV=y -+CONFIG_CFG80211=y -+# CONFIG_NL80211_TESTMODE is not set -+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -+# CONFIG_CFG80211_REG_DEBUG is not set -+CONFIG_CFG80211_DEFAULT_PS=y -+# CONFIG_CFG80211_INTERNAL_REGDB is not set -+CONFIG_CFG80211_WEXT=y -+CONFIG_WIRELESS_EXT_SYSFS=y -+CONFIG_LIB80211=y -+# CONFIG_LIB80211_DEBUG is not set -+CONFIG_CFG80211_ALLOW_RECONNECT=y -+CONFIG_MAC80211=y -+CONFIG_MAC80211_HAS_RC=y -+# CONFIG_MAC80211_RC_PID is not set -+CONFIG_MAC80211_RC_MINSTREL=y -+CONFIG_MAC80211_RC_MINSTREL_HT=y -+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -+# CONFIG_MAC80211_LEDS is not set -+# CONFIG_MAC80211_DEBUG_MENU is not set -+# CONFIG_WIMAX is not set -+CONFIG_RFKILL=y -+CONFIG_RFKILL_PM=y -+CONFIG_RFKILL_LEDS=y -+# CONFIG_RFKILL_INPUT is not set -+# CONFIG_RFKILL_GPIO is not set -+# CONFIG_NET_9P is not set -+# CONFIG_CAIF is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_DEVTMPFS=y -+CONFIG_DEVTMPFS_MOUNT=y -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+CONFIG_FW_LOADER=y -+CONFIG_FIRMWARE_IN_KERNEL=y -+CONFIG_EXTRA_FIRMWARE="" -+# CONFIG_DEBUG_DRIVER is not set -+# CONFIG_DEBUG_DEVRES is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_GENERIC_CPU_DEVICES is not set -+CONFIG_DMA_SHARED_BUFFER=y -+# CONFIG_SYNC is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_TESTS is not set -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+# CONFIG_MTD_AFS_PARTS is not set -+# CONFIG_MTD_AR7_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SST25L 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_DOCG3 is not set -+CONFIG_MTD_AK_SPIFLASH=y -+# CONFIG_MTD_NAND_IDS is not set -+# CONFIG_MTD_NAND is not set -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# LPDDR flash memory drivers -+# -+# CONFIG_MTD_LPDDR is not set -+# CONFIG_MTD_UBI is not set -+# CONFIG_PARPORT is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+ -+# -+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected -+# -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+# CONFIG_BLK_DEV_XIP is not set -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+# CONFIG_MG_DISK is not set -+ -+# -+# Misc devices -+# -+# CONFIG_SENSORS_LIS3LV02D is not set -+# CONFIG_AD525X_DPOT is not set -+# CONFIG_ATMEL_PWM is not set -+# CONFIG_ENCLOSURE_SERVICES is not set -+# CONFIG_APDS9802ALS is not set -+# CONFIG_ISL29003 is not set -+# CONFIG_ISL29020 is not set -+# CONFIG_SENSORS_TSL2550 is not set -+# CONFIG_SENSORS_BH1780 is not set -+# CONFIG_SENSORS_BH1770 is not set -+# CONFIG_SENSORS_APDS990X is not set -+# CONFIG_HMC6352 is not set -+# CONFIG_SENSORS_AK8975 is not set -+# CONFIG_TI_DAC7512 is not set -+# CONFIG_UID_STAT is not set -+# CONFIG_BMP085 is not set -+# CONFIG_USB_SWITCH_FSA9480 is not set -+# CONFIG_WL127X_RFKILL is not set -+CONFIG_AK_SERIAL_NUMBER=y -+# CONFIG_AK_MOTOR is not set -+ -+# -+# user space generic gpio controller -+# -+# CONFIG_GPIOS_AKCUSTOM is not set -+ -+# -+# EEPROM support -+# -+# CONFIG_EEPROM_AT24 is not set -+# CONFIG_EEPROM_AT25 is not set -+# CONFIG_EEPROM_LEGACY is not set -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_EEPROM_93XX46 is not set -+ -+# -+# Texas Instruments shared transport line discipline -+# -+# CONFIG_TI_ST is not set -+# CONFIG_SENSORS_LIS3_SPI is not set -+# CONFIG_SENSORS_LIS3_I2C is not set -+ -+# -+# Altera FPGA firmware download module -+# -+# CONFIG_ALTERA_STAPL is not set -+CONFIG_HAVE_IDE=y -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+CONFIG_SCSI_MOD=y -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_SCSI_PROC_FS is not set -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+# CONFIG_SCSI_WAIT_SCAN is not set -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+# CONFIG_SCSI_LOWLEVEL is not set -+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set -+# CONFIG_SCSI_DH is not set -+# CONFIG_SCSI_OSD_INITIATOR is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_TARGET_CORE is not set -+CONFIG_NETDEVICES=y -+CONFIG_NET_CORE=y -+# CONFIG_BONDING is not set -+# CONFIG_DUMMY is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_MII is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+# CONFIG_ARCNET is not set -+ -+# -+# CAIF transport drivers -+# -+CONFIG_ETHERNET=y -+# CONFIG_NET_VENDOR_3COM is not set -+# CONFIG_NET_VENDOR_AMD is not set -+# CONFIG_NET_VENDOR_BROADCOM is not set -+# CONFIG_NET_CALXEDA_XGMAC is not set -+# CONFIG_NET_VENDOR_CHELSIO is not set -+# CONFIG_NET_VENDOR_CIRRUS is not set -+# CONFIG_DM9000 is not set -+# CONFIG_DNET is not set -+# CONFIG_NET_VENDOR_FARADAY is not set -+# CONFIG_NET_VENDOR_FUJITSU is not set -+# CONFIG_NET_VENDOR_INTEL is not set -+# CONFIG_NET_VENDOR_MARVELL is not set -+# CONFIG_NET_VENDOR_MICREL is not set -+# CONFIG_NET_VENDOR_NATSEMI is not set -+# CONFIG_ETHOC is not set -+# CONFIG_NET_VENDOR_SMSC is not set -+# CONFIG_NET_VENDOR_STMICRO is not set -+# CONFIG_NET_VENDOR_XIRCOM is not set -+CONFIG_AK_ETHERNET=y -+# CONFIG_PHYLIB is not set -+# CONFIG_MICREL_KS8995MA is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_TR is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_USB_HSO is not set -+# CONFIG_USB_IPHETH is not set -+CONFIG_WLAN=y -+CONFIG_PCMCIA_RAYCS=y -+# CONFIG_LIBERTAS_THINFIRM is not set -+# CONFIG_ATMEL is not set -+# CONFIG_AT76C50X_USB is not set -+# CONFIG_AIRO_CS is not set -+# CONFIG_USB_ZD1201 is not set -+# CONFIG_RTL8187 is not set -+# CONFIG_MAC80211_HWSIM is not set -+# CONFIG_WIFI_CONTROL_FUNC is not set -+# CONFIG_ATH_COMMON is not set -+# CONFIG_B43 is not set -+# CONFIG_B43LEGACY is not set -+# CONFIG_BCMDHD is not set -+# CONFIG_BRCMFMAC is not set -+# CONFIG_HOSTAP is not set -+# CONFIG_LIBERTAS is not set -+# CONFIG_HERMES is not set -+# CONFIG_RT2X00 is not set -+# CONFIG_MWIFIEX is not set -+ -+# -+# Enable WiMAX (Networking options) to see the WiMAX drivers -+# -+# CONFIG_WAN is not set -+# CONFIG_ISDN is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+# CONFIG_INPUT_SPARSEKMAP is not set -+ -+# -+# Userland interfaces -+# -+# CONFIG_INPUT_MOUSEDEV is not set -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+# CONFIG_INPUT_KEYRESET is not set -+ -+# -+# Input Device Drivers -+# -+CONFIG_INPUT_KEYBOARD=y -+# CONFIG_KEYBOARD_ADP5588 is not set -+# CONFIG_KEYBOARD_ADP5589 is not set -+# CONFIG_KEYBOARD_ATKBD is not set -+# CONFIG_KEYBOARD_QT1070 is not set -+# CONFIG_KEYBOARD_LKKBD is not set -+# CONFIG_KEYBOARD_GPIO is not set -+# CONFIG_KEYBOARD_TCA6416 is not set -+# CONFIG_KEYBOARD_TCA8418 is not set -+# CONFIG_KEYBOARD_MATRIX is not set -+# CONFIG_KEYBOARD_LM8323 is not set -+# CONFIG_KEYBOARD_MAX7359 is not set -+# CONFIG_KEYBOARD_MCS is not set -+# CONFIG_KEYBOARD_MPR121 is not set -+# CONFIG_KEYBOARD_NEWTON is not set -+# CONFIG_KEYBOARD_OPENCORES is not set -+# CONFIG_KEYBOARD_SAMSUNG is not set -+# CONFIG_KEYBOARD_STOWAWAY is not set -+# CONFIG_KEYBOARD_SUNKBD is not set -+# CONFIG_KEYBOARD_OMAP4 is not set -+# CONFIG_KEYBOARD_XTKBD is not set -+CONFIG_KEYBOARD_AKKEY=y -+# CONFIG_KEYBOARD_AK_KEYPAD is not set -+CONFIG_KEYBOARD_ADKEY=y -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+# CONFIG_SERIO is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+# CONFIG_VT is not set -+# CONFIG_UNIX98_PTYS is not set -+# CONFIG_LEGACY_PTYS is not set -+# CONFIG_SERIAL_NONSTANDARD is not set -+# CONFIG_TRACE_SINK is not set -+CONFIG_DEVMEM=y -+# CONFIG_DEVKMEM is not set -+ -+# -+# Serial drivers -+# -+# CONFIG_SERIAL_8250 is not set -+ -+# -+# Non-8250 serial port support -+# -+# CONFIG_SERIAL_MAX3100 is not set -+# CONFIG_SERIAL_MAX3107 is not set -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_SERIAL_TIMBERDALE is not set -+# CONFIG_SERIAL_ALTERA_JTAGUART is not set -+# CONFIG_SERIAL_ALTERA_UART is not set -+# CONFIG_SERIAL_XILINX_PS_UART is not set -+CONFIG_SERIAL_AK39_UART=y -+CONFIG_SERIAL_AK39_CONSOLE=y -+# CONFIG_SERIAL_GPIO_UART is not set -+CONFIG_TTY_PRINTK=y -+# CONFIG_HVC_DCC is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_R3964 is not set -+ -+# -+# PCMCIA character devices -+# -+# CONFIG_SYNCLINK_CS is not set -+# CONFIG_CARDMAN_4000 is not set -+# CONFIG_CARDMAN_4040 is not set -+# CONFIG_IPWIRELESS is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+# CONFIG_DCC_TTY is not set -+# CONFIG_RAMOOPS is not set -+CONFIG_I2C=y -+CONFIG_I2C_BOARDINFO=y -+CONFIG_I2C_COMPAT=y -+# CONFIG_I2C_CHARDEV is not set -+# CONFIG_I2C_HELPER_AUTO is not set -+CONFIG_I2C_SMBUS=y -+ -+# -+# I2C Algorithms -+# -+CONFIG_I2C_ALGOBIT=y -+# CONFIG_I2C_ALGOPCF is not set -+# CONFIG_I2C_ALGOPCA is not set -+ -+# -+# I2C Hardware Bus support -+# -+ -+# -+# I2C system bus drivers (mostly embedded / system-on-chip) -+# -+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set -+# CONFIG_I2C_GPIO is not set -+# CONFIG_I2C_PCA_PLATFORM is not set -+# CONFIG_I2C_PXA_PCI is not set -+# CONFIG_I2C_SIMTEC is not set -+CONFIG_I2C_ANYKA=y -+CONFIG_I2C_AK39_HW=y -+# CONFIG_I2C_GPIO_SOFT is not set -+ -+# -+# External I2C/SMBus adapter drivers -+# -+# CONFIG_I2C_DIOLAN_U2C is not set -+# CONFIG_I2C_PARPORT_LIGHT is not set -+# CONFIG_I2C_TINY_USB is not set -+ -+# -+# Other I2C/SMBus bus drivers -+# -+# CONFIG_I2C_DEBUG_CORE is not set -+# CONFIG_I2C_DEBUG_ALGO is not set -+# CONFIG_I2C_DEBUG_BUS is not set -+CONFIG_SPI=y -+# CONFIG_SPI_DEBUG is not set -+CONFIG_SPI_MASTER=y -+ -+# -+# SPI Master Controller Drivers -+# -+# CONFIG_SPI_ALTERA is not set -+CONFIG_SPI_BITBANG=y -+# CONFIG_SPI_GPIO is not set -+# CONFIG_SPI_OC_TINY is not set -+# CONFIG_SPI_PXA2XX_PCI is not set -+CONFIG_SPI_ANYKA=y -+# CONFIG_SPI_DESIGNWARE is not set -+ -+# -+# SPI Protocol Masters -+# -+# CONFIG_SPI_TLE62X0 is not set -+# CONFIG_HSI is not set -+ -+# -+# PPS support -+# -+ -+# -+# PPS generators support -+# -+ -+# -+# PTP clock support -+# -+ -+# -+# Enable Device Drivers -> PPS to see the PTP clock options. -+# -+CONFIG_ARCH_REQUIRE_GPIOLIB=y -+CONFIG_GPIOLIB=y -+# CONFIG_DEBUG_GPIO is not set -+ -+# -+# Memory mapped GPIO drivers: -+# -+# CONFIG_GPIO_GENERIC_PLATFORM is not set -+ -+# -+# I2C GPIO expanders: -+# -+# CONFIG_GPIO_MAX7300 is not set -+# CONFIG_GPIO_MAX732X is not set -+# CONFIG_GPIO_PCF857X is not set -+# CONFIG_GPIO_SX150X is not set -+# CONFIG_GPIO_ADP5588 is not set -+ -+# -+# PCI GPIO expanders: -+# -+ -+# -+# SPI GPIO expanders: -+# -+# CONFIG_GPIO_MAX7301 is not set -+# CONFIG_GPIO_MCP23S08 is not set -+# CONFIG_GPIO_MC33880 is not set -+# CONFIG_GPIO_74X164 is not set -+ -+# -+# AC97 GPIO expanders: -+# -+ -+# -+# MODULbus GPIO expanders: -+# -+# CONFIG_W1 is not set -+CONFIG_POWER_SUPPLY=y -+# CONFIG_POWER_SUPPLY_DEBUG is not set -+# CONFIG_PDA_POWER is not set -+# CONFIG_TEST_POWER is not set -+# CONFIG_BATTERY_DS2780 is not set -+# CONFIG_BATTERY_DS2781 is not set -+# CONFIG_BATTERY_DS2782 is not set -+# CONFIG_BATTERY_SBS is not set -+# CONFIG_BATTERY_BQ27x00 is not set -+# CONFIG_BATTERY_MAX17040 is not set -+# CONFIG_BATTERY_MAX17042 is not set -+# CONFIG_BATTERY_ANDROID is not set -+# CONFIG_CHARGER_MAX8903 is not set -+# CONFIG_CHARGER_LP8727 is not set -+# CONFIG_CHARGER_GPIO is not set -+# CONFIG_CHARGER_SMB347 is not set -+CONFIG_BATTERY_AK=y -+# CONFIG_HWMON is not set -+# CONFIG_THERMAL is not set -+CONFIG_WATCHDOG=y -+CONFIG_WATCHDOG_CORE=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+# CONFIG_SOFT_WATCHDOG is not set -+# CONFIG_DW_WATCHDOG is not set -+# CONFIG_MAX63XX_WATCHDOG is not set -+CONFIG_AK39_WATCHDOG=y -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+CONFIG_SSB_POSSIBLE=y -+ -+# -+# Sonics Silicon Backplane -+# -+# CONFIG_SSB is not set -+CONFIG_BCMA_POSSIBLE=y -+ -+# -+# Broadcom specific AMBA -+# -+# CONFIG_BCMA is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_CORE is not set -+# CONFIG_MFD_88PM860X is not set -+# CONFIG_MFD_SM501 is not set -+# CONFIG_MFD_ASIC3 is not set -+# CONFIG_HTC_EGPIO is not set -+# CONFIG_HTC_PASIC3 is not set -+# CONFIG_HTC_I2CPLD is not set -+# CONFIG_TPS6105X is not set -+# CONFIG_TPS65010 is not set -+# CONFIG_TPS6507X is not set -+# CONFIG_MFD_TPS65217 is not set -+# CONFIG_MFD_TPS6586X is not set -+# CONFIG_MFD_TPS65910 is not set -+# CONFIG_MFD_TPS65912_I2C is not set -+# CONFIG_MFD_TPS65912_SPI is not set -+# CONFIG_TWL4030_CORE is not set -+# CONFIG_TWL6040_CORE is not set -+# CONFIG_MFD_STMPE is not set -+# CONFIG_MFD_TC3589X is not set -+# CONFIG_MFD_TMIO is not set -+# CONFIG_MFD_T7L66XB is not set -+# CONFIG_MFD_TC6387XB is not set -+# CONFIG_MFD_TC6393XB is not set -+# CONFIG_PMIC_DA903X is not set -+# CONFIG_MFD_DA9052_SPI is not set -+# CONFIG_MFD_DA9052_I2C is not set -+# CONFIG_PMIC_ADP5520 is not set -+# CONFIG_MFD_MAX8925 is not set -+# CONFIG_MFD_MAX8997 is not set -+# CONFIG_MFD_MAX8998 is not set -+# CONFIG_MFD_S5M_CORE is not set -+# CONFIG_MFD_WM8400 is not set -+# CONFIG_MFD_WM831X_I2C is not set -+# CONFIG_MFD_WM831X_SPI is not set -+# CONFIG_MFD_WM8350_I2C is not set -+# CONFIG_MFD_WM8994 is not set -+# CONFIG_MFD_PCF50633 is not set -+# CONFIG_MFD_MC13XXX is not set -+# CONFIG_ABX500_CORE is not set -+# CONFIG_EZX_PCAP is not set -+# CONFIG_MFD_WL1273_CORE is not set -+# CONFIG_MFD_TPS65090 is not set -+# CONFIG_MFD_AAT2870_CORE is not set -+# CONFIG_MFD_RC5T583 is not set -+# CONFIG_REGULATOR is not set -+CONFIG_MEDIA_SUPPORT=y -+ -+# -+# Multimedia core support -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L2_COMMON=y -+# CONFIG_DVB_CORE is not set -+CONFIG_VIDEO_MEDIA=y -+ -+# -+# Multimedia drivers -+# -+# CONFIG_RC_CORE is not set -+# CONFIG_MEDIA_ATTACH is not set -+CONFIG_MEDIA_TUNER=y -+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set -+CONFIG_MEDIA_TUNER_SIMPLE=y -+CONFIG_MEDIA_TUNER_TDA8290=y -+CONFIG_MEDIA_TUNER_TDA827X=y -+CONFIG_MEDIA_TUNER_TDA18271=y -+CONFIG_MEDIA_TUNER_TDA9887=y -+CONFIG_MEDIA_TUNER_TEA5767=y -+CONFIG_MEDIA_TUNER_MT20XX=y -+CONFIG_MEDIA_TUNER_XC2028=y -+CONFIG_MEDIA_TUNER_XC5000=y -+CONFIG_MEDIA_TUNER_XC4000=y -+CONFIG_MEDIA_TUNER_MC44S803=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEOBUF_GEN=y -+CONFIG_VIDEOBUF_DMA_CONTIG=y -+CONFIG_VIDEOBUF2_CORE=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set -+ -+# -+# Encoders, decoders, sensors and other helper chips -+# -+ -+# -+# Audio decoders, processors and mixers -+# -+# CONFIG_VIDEO_TVAUDIO is not set -+# CONFIG_VIDEO_TDA7432 is not set -+# CONFIG_VIDEO_TDA9840 is not set -+# CONFIG_VIDEO_TEA6415C is not set -+# CONFIG_VIDEO_TEA6420 is not set -+# CONFIG_VIDEO_MSP3400 is not set -+# CONFIG_VIDEO_CS5345 is not set -+# CONFIG_VIDEO_CS53L32A is not set -+# CONFIG_VIDEO_WM8775 is not set -+# CONFIG_VIDEO_WM8739 is not set -+# CONFIG_VIDEO_VP27SMPX is not set -+ -+# -+# RDS decoders -+# -+# CONFIG_VIDEO_SAA6588 is not set -+ -+# -+# Video decoders -+# -+# CONFIG_VIDEO_ADV7180 is not set -+# CONFIG_VIDEO_ADV7183 is not set -+# CONFIG_VIDEO_BT819 is not set -+# CONFIG_VIDEO_BT856 is not set -+# CONFIG_VIDEO_BT866 is not set -+# CONFIG_VIDEO_KS0127 is not set -+# CONFIG_VIDEO_SAA7110 is not set -+# CONFIG_VIDEO_SAA711X is not set -+# CONFIG_VIDEO_SAA7191 is not set -+# CONFIG_VIDEO_TVP514X is not set -+# CONFIG_VIDEO_TVP5150 is not set -+# CONFIG_VIDEO_TVP7002 is not set -+# CONFIG_VIDEO_VPX3220 is not set -+ -+# -+# Video and audio decoders -+# -+# CONFIG_VIDEO_SAA717X is not set -+# CONFIG_VIDEO_CX25840 is not set -+ -+# -+# MPEG video encoders -+# -+# CONFIG_VIDEO_CX2341X is not set -+ -+# -+# Video encoders -+# -+# CONFIG_VIDEO_SAA7127 is not set -+# CONFIG_VIDEO_SAA7185 is not set -+# CONFIG_VIDEO_ADV7170 is not set -+# CONFIG_VIDEO_ADV7175 is not set -+# CONFIG_VIDEO_ADV7343 is not set -+# CONFIG_VIDEO_AK881X is not set -+ -+# -+# Camera sensor devices -+# -+# CONFIG_VIDEO_OV7670 is not set -+# CONFIG_VIDEO_VS6624 is not set -+# CONFIG_VIDEO_MT9V011 is not set -+# CONFIG_VIDEO_TCM825X is not set -+# CONFIG_VIDEO_SR030PC30 is not set -+ -+# -+# Flash devices -+# -+ -+# -+# Video improvement chips -+# -+# CONFIG_VIDEO_UPD64031A is not set -+# CONFIG_VIDEO_UPD64083 is not set -+ -+# -+# Miscelaneous helper chips -+# -+# CONFIG_VIDEO_THS7303 is not set -+# CONFIG_VIDEO_M52790 is not set -+# CONFIG_V4L_USB_DRIVERS is not set -+CONFIG_V4L_PLATFORM_DRIVERS=y -+CONFIG_SOC_CAMERA=y -+# CONFIG_SOC_CAMERA_IMX074 is not set -+# CONFIG_SOC_CAMERA_MT9M001 is not set -+# CONFIG_SOC_CAMERA_MT9M111 is not set -+# CONFIG_SOC_CAMERA_MT9T031 is not set -+# CONFIG_SOC_CAMERA_MT9T112 is not set -+# CONFIG_SOC_CAMERA_MT9V022 is not set -+# CONFIG_SOC_CAMERA_RJ54N1 is not set -+# CONFIG_SOC_CAMERA_TW9910 is not set -+# CONFIG_SOC_CAMERA_PLATFORM is not set -+# CONFIG_SOC_CAMERA_OV2640 is not set -+# CONFIG_SOC_CAMERA_OV5642 is not set -+# CONFIG_SOC_CAMERA_OV6650 is not set -+# CONFIG_SOC_CAMERA_OV772X is not set -+# CONFIG_SOC_CAMERA_OV9640 is not set -+# CONFIG_SOC_CAMERA_OV9740 is not set -+CONFIG_LINUX_AKSENSOR=y -+CONFIG_SENSOR_GC0308=y -+CONFIG_SENSOR_OV2643=y -+CONFIG_SENSOR_OV7725=y -+CONFIG_SENSOR_HM1375=y -+CONFIG_SENSOR_OV9712=y -+CONFIG_SENSOR_OV2710=y -+# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set -+# CONFIG_VIDEO_SH_MOBILE_CEU is not set -+CONFIG_VIDEO_AK=y -+# CONFIG_V4L_MEM2MEM_DRIVERS is not set -+# CONFIG_RADIO_ADAPTERS is not set -+ -+# -+# Graphics support -+# -+# CONFIG_DRM is not set -+CONFIG_ION=y -+CONFIG_ION_AK=y -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_EXYNOS_VIDEO is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+CONFIG_SOUND=y -+# CONFIG_SOUND_OSS_CORE is not set -+CONFIG_SND=y -+CONFIG_SND_TIMER=y -+CONFIG_SND_PCM=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 -+# CONFIG_SND_RAWMIDI_SEQ is not set -+# CONFIG_SND_OPL3_LIB_SEQ is not set -+# CONFIG_SND_OPL4_LIB_SEQ is not set -+# CONFIG_SND_SBAWE_SEQ is not set -+# CONFIG_SND_EMU10K1_SEQ is not set -+# CONFIG_SND_DRIVERS is not set -+CONFIG_SND_ARM=y -+CONFIG_SND_AK_PCM=y -+CONFIG_CODEC_AK39=y -+CONFIG_SPKHP_SWITCH_AUTO=y -+# CONFIG_SPKHP_SWITCH_MIXER is not set -+# CONFIG_SPKHP_SWITCH_UEVENT is not set -+CONFIG_SUPPORT_AEC=y -+# CONFIG_SND_SPI is not set -+# CONFIG_SND_USB is not set -+CONFIG_SND_PCMCIA=y -+# CONFIG_SND_VXPOCKET is not set -+# CONFIG_SND_PDAUDIOCF is not set -+# CONFIG_SND_SOC is not set -+# CONFIG_SOUND_PRIME is not set -+# CONFIG_HID_SUPPORT is not set -+# CONFIG_USB_ARCH_HAS_OHCI is not set -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB_ARCH_HAS_XHCI is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_COMMON=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+# CONFIG_USB_DEVICE_CLASS is not set -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_OTG_WHITELIST is not set -+# CONFIG_USB_OTG_BLACKLIST_HUB is not set -+# CONFIG_USB_DWC3 is not set -+# CONFIG_USB_MON is not set -+# CONFIG_USB_WUSB_CBAF is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_C67X00_HCD is not set -+# CONFIG_USB_OXU210HP_HCD is not set -+# CONFIG_USB_ISP116X_HCD is not set -+# CONFIG_USB_ISP1362_HCD is not set -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+CONFIG_USB_ANYKA_HCD=y -+CONFIG_USB_AKOTG_HS_HCD=m -+# CONFIG_USB_AKOTG_DMA is not set -+# CONFIG_USB_MUSB_HDRC is not set -+# CONFIG_USB_RENESAS_USBHS is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+# CONFIG_USB_WDM is not set -+# CONFIG_USB_TMC is not set -+ -+# -+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -+# -+ -+# -+# also be needed; see USB_STORAGE Help for more info -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_REALTEK is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_ONETOUCH is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set -+# CONFIG_USB_STORAGE_ENE_UB6250 is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+ -+# -+# USB port drivers -+# -+# 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_SEVSEG 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_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+# CONFIG_USB_TEST is not set -+# CONFIG_USB_ISIGHTFW is not set -+# CONFIG_USB_YUREX is not set -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_VBUS_DRAW=500 -+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -+# CONFIG_USB_FUSB300 is not set -+# CONFIG_USB_R8A66597 is not set -+# CONFIG_USB_MV_UDC is not set -+# CONFIG_USB_GADGET_AKUDC_PRODUCER is not set -+CONFIG_USB_GADGET_AKUDC=y -+CONFIG_USB_AKUDC=m -+# CONFIG_USB_AKUDC_DEBUG_FS is not set -+# CONFIG_USB_M66592 is not set -+# CONFIG_USB_NET2272 is not set -+# CONFIG_USB_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_AUDIO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_G_NCM is not set -+# CONFIG_USB_FILE_STORAGE is not set -+CONFIG_USB_MASS_STORAGE=m -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_G_PRINTER is not set -+# CONFIG_USB_CDC_COMPOSITE is not set -+# CONFIG_USB_G_ACM_MS is not set -+# CONFIG_USB_G_MULTI is not set -+# CONFIG_USB_G_HID is not set -+# CONFIG_USB_G_DBGP is not set -+# CONFIG_USB_G_WEBCAM is not set -+ -+# -+# OTG and related infrastructure -+# -+# CONFIG_USB_OTG_WAKELOCK is not set -+# CONFIG_USB_GPIO_VBUS is not set -+# CONFIG_USB_ULPI is not set -+# CONFIG_NOP_USB_XCEIV is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD/SDIO Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_MINORS=8 -+# CONFIG_MMC_BLOCK_BOUNCE is not set -+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set -+# CONFIG_SDIO_UART is not set -+# CONFIG_MMC_TEST is not set -+# CONFIG_SDIO_WIFI is not set -+ -+# -+# MMC/SD/SDIO Host Controller Drivers -+# -+# CONFIG_MMC_SDHCI is not set -+# CONFIG_MMC_SDHCI_PXAV3 is not set -+# CONFIG_MMC_SDHCI_PXAV2 is not set -+# CONFIG_MMC_SPI is not set -+# CONFIG_MMC_DW is not set -+# CONFIG_MMC_VUB300 is not set -+# CONFIG_MMC_USHC is not set -+CONFIG_MMC_ANYKA=y -+# CONFIG_MEMSTICK is not set -+CONFIG_NEW_LEDS=y -+CONFIG_LEDS_CLASS=y -+ -+# -+# LED drivers -+# -+# CONFIG_LEDS_LM3530 is not set -+# CONFIG_LEDS_GPIO is not set -+# CONFIG_LEDS_LP3944 is not set -+# CONFIG_LEDS_LP5521 is not set -+# CONFIG_LEDS_LP5523 is not set -+# CONFIG_LEDS_PCA955X is not set -+# CONFIG_LEDS_PCA9633 is not set -+# CONFIG_LEDS_DAC124S085 is not set -+# CONFIG_LEDS_BD2802 is not set -+CONFIG_LEDS_AK39=y -+# CONFIG_LEDS_LT3593 is not set -+# CONFIG_LEDS_RENESAS_TPU is not set -+# CONFIG_LEDS_TCA6507 is not set -+# CONFIG_LEDS_OT200 is not set -+CONFIG_LEDS_TRIGGERS=y -+ -+# -+# LED Triggers -+# -+CONFIG_LEDS_TRIGGER_TIMER=y -+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set -+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set -+# CONFIG_LEDS_TRIGGER_GPIO is not set -+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set -+ -+# -+# iptables trigger is under Netfilter config (LED target) -+# -+# CONFIG_SWITCH is not set -+# CONFIG_ACCESSIBILITY is not set -+CONFIG_RTC_LIB=y -+CONFIG_RTC_CLASS=y -+CONFIG_RTC_HCTOSYS=y -+CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -+# CONFIG_RTC_DEBUG is not set -+ -+# -+# RTC interfaces -+# -+CONFIG_RTC_INTF_SYSFS=y -+CONFIG_RTC_INTF_PROC=y -+CONFIG_RTC_INTF_DEV=y -+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -+# CONFIG_RTC_DRV_TEST is not set -+ -+# -+# I2C RTC drivers -+# -+# CONFIG_RTC_DRV_DS1307 is not set -+# CONFIG_RTC_DRV_DS1374 is not set -+# CONFIG_RTC_DRV_DS1672 is not set -+# CONFIG_RTC_DRV_DS3232 is not set -+# CONFIG_RTC_DRV_MAX6900 is not set -+# CONFIG_RTC_DRV_RS5C372 is not set -+# CONFIG_RTC_DRV_ISL1208 is not set -+# CONFIG_RTC_DRV_ISL12022 is not set -+# CONFIG_RTC_DRV_X1205 is not set -+# CONFIG_RTC_DRV_PCF8563 is not set -+# CONFIG_RTC_DRV_PCF8583 is not set -+# CONFIG_RTC_DRV_M41T80 is not set -+# CONFIG_RTC_DRV_BQ32K is not set -+# CONFIG_RTC_DRV_S35390A is not set -+# CONFIG_RTC_DRV_FM3130 is not set -+# CONFIG_RTC_DRV_RX8581 is not set -+# CONFIG_RTC_DRV_RX8025 is not set -+# CONFIG_RTC_DRV_EM3027 is not set -+# CONFIG_RTC_DRV_RV3029C2 is not set -+ -+# -+# SPI RTC drivers -+# -+# CONFIG_RTC_DRV_M41T93 is not set -+# CONFIG_RTC_DRV_M41T94 is not set -+# CONFIG_RTC_DRV_DS1305 is not set -+# CONFIG_RTC_DRV_DS1390 is not set -+# CONFIG_RTC_DRV_MAX6902 is not set -+# CONFIG_RTC_DRV_R9701 is not set -+# CONFIG_RTC_DRV_RS5C348 is not set -+# CONFIG_RTC_DRV_DS3234 is not set -+# CONFIG_RTC_DRV_PCF2123 is not set -+ -+# -+# Platform RTC drivers -+# -+# CONFIG_RTC_DRV_CMOS is not set -+# CONFIG_RTC_DRV_DS1286 is not set -+# CONFIG_RTC_DRV_DS1511 is not set -+# CONFIG_RTC_DRV_DS1553 is not set -+# CONFIG_RTC_DRV_DS1742 is not set -+# CONFIG_RTC_DRV_STK17TA8 is not set -+# CONFIG_RTC_DRV_M48T86 is not set -+# CONFIG_RTC_DRV_M48T35 is not set -+# CONFIG_RTC_DRV_M48T59 is not set -+# CONFIG_RTC_DRV_MSM6242 is not set -+# CONFIG_RTC_DRV_BQ4802 is not set -+# CONFIG_RTC_DRV_RP5C01 is not set -+# CONFIG_RTC_DRV_V3020 is not set -+ -+# -+# on-CPU RTC drivers -+# -+CONFIG_RTC_DRV_AK=y -+# CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set -+CONFIG_UIO=y -+# CONFIG_UIO_PDRV is not set -+# CONFIG_UIO_PDRV_GENIRQ is not set -+CONFIG_UIO_VCODEC=y -+ -+# -+# Virtio drivers -+# -+# CONFIG_VIRTIO_BALLOON is not set -+ -+# -+# Microsoft Hyper-V guest support -+# -+# CONFIG_STAGING is not set -+CONFIG_CLKDEV_LOOKUP=y -+ -+# -+# Hardware Spinlock drivers -+# -+# CONFIG_IOMMU_SUPPORT is not set -+ -+# -+# Remoteproc drivers (EXPERIMENTAL) -+# -+ -+# -+# Rpmsg drivers (EXPERIMENTAL) -+# -+# CONFIG_VIRT_DRIVERS is not set -+# CONFIG_PM_DEVFREQ is not set -+ -+# -+# File systems -+# -+# CONFIG_EXT2_FS is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4_FS is not set -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_FS_POSIX_ACL is not set -+CONFIG_FILE_LOCKING=y -+CONFIG_FSNOTIFY=y -+CONFIG_DNOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_FANOTIFY is not set -+# CONFIG_QUOTA is not set -+# CONFIG_QUOTACTL is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_PROC_PAGE_MONITOR=y -+CONFIG_SYSFS=y -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+CONFIG_MISC_FILESYSTEMS=y -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_YAFFS_FS is not set -+CONFIG_JFFS2_FS=y -+CONFIG_JFFS2_FS_DEBUG=0 -+# CONFIG_JFFS2_FS_WRITEBUFFER is not set -+CONFIG_JFFS2_COMPRESSION_OPTIONS=y -+# CONFIG_JFFS2_ZLIB is not set -+# CONFIG_JFFS2_LZO is not set -+# CONFIG_JFFS2_RTIME is not set -+# CONFIG_JFFS2_RUBIN is not set -+CONFIG_JFFS2_CMODE_NONE=y -+# CONFIG_JFFS2_CMODE_PRIORITY is not set -+# CONFIG_JFFS2_CMODE_SIZE is not set -+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set -+# CONFIG_CRAMFS is not set -+CONFIG_SQUASHFS=y -+# CONFIG_SQUASHFS_XATTR is not set -+CONFIG_SQUASHFS_ZLIB=y -+# CONFIG_SQUASHFS_LZO is not set -+# CONFIG_SQUASHFS_XZ is not set -+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set -+# CONFIG_SQUASHFS_EMBEDDED is not set -+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 -+# CONFIG_VXFS_FS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_OMFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_QNX6FS_FS is not set -+# CONFIG_ROMFS_FS is not set -+# CONFIG_PSTORE is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+# CONFIG_NETWORK_FILESYSTEMS is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+# CONFIG_NLS_CODEPAGE_936 is not set -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+# CONFIG_NLS_ASCII is not set -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+ -+# -+# Kernel hacking -+# -+# CONFIG_PRINTK_TIME is not set -+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_FRAME_WARN=1024 -+# CONFIG_MAGIC_SYSRQ is not set -+# CONFIG_STRIP_ASM_SYMS is not set -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_SECTION_MISMATCH is not set -+CONFIG_DEBUG_KERNEL=y -+# CONFIG_DEBUG_SHIRQ is not set -+# CONFIG_LOCKUP_DETECTOR is not set -+# CONFIG_HARDLOCKUP_DETECTOR_NMI is not set -+# CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU is not set -+# CONFIG_HARDLOCKUP_DETECTOR is not set -+# CONFIG_DETECT_HUNG_TASK is not set -+# CONFIG_SCHED_DEBUG is not set -+# CONFIG_SCHEDSTATS is not set -+# CONFIG_TIMER_STATS is not set -+# CONFIG_DEBUG_OBJECTS is not set -+# CONFIG_SLUB_STATS is not set -+# CONFIG_DEBUG_RT_MUTEXES is not set -+# CONFIG_RT_MUTEX_TESTER is not set -+# CONFIG_DEBUG_SPINLOCK is not set -+# CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_SPARSE_RCU_POINTER is not set -+# CONFIG_LOCK_STAT is not set -+# CONFIG_DEBUG_ATOMIC_SLEEP is not set -+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -+# CONFIG_STACKTRACE is not set -+# CONFIG_DEBUG_STACK_USAGE is not set -+# CONFIG_DEBUG_KOBJECT is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_DEBUG_INFO is not set -+# CONFIG_DEBUG_VM is not set -+# CONFIG_DEBUG_WRITECOUNT is not set -+# CONFIG_DEBUG_MEMORY_INIT is not set -+# CONFIG_DEBUG_LIST is not set -+# CONFIG_TEST_LIST_SORT is not set -+# CONFIG_DEBUG_SG is not set -+# CONFIG_DEBUG_NOTIFIERS is not set -+# CONFIG_DEBUG_CREDENTIALS is not set -+CONFIG_FRAME_POINTER=y -+# CONFIG_BOOT_PRINTK_DELAY is not set -+# CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_RCU_TRACE is not set -+# CONFIG_BACKTRACE_SELF_TEST is not set -+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -+# CONFIG_FAULT_INJECTION is not set -+# CONFIG_LATENCYTOP is not set -+# CONFIG_DEBUG_PAGEALLOC is not set -+CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -+CONFIG_HAVE_DYNAMIC_FTRACE=y -+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_HAVE_C_RECORDMCOUNT=y -+CONFIG_TRACING_SUPPORT=y -+# CONFIG_FTRACE is not set -+# CONFIG_DMA_API_DEBUG is not set -+# CONFIG_ATOMIC64_SELFTEST is not set -+# CONFIG_SAMPLES is not set -+CONFIG_HAVE_ARCH_KGDB=y -+# CONFIG_TEST_KSTRTOX is not set -+# CONFIG_STRICT_DEVMEM is not set -+CONFIG_DEBUG_USER=y -+# CONFIG_DEBUG_RODATA is not set -+# CONFIG_DEBUG_LL is not set -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY_DMESG_RESTRICT is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITYFS is not set -+CONFIG_DEFAULT_SECURITY_DAC=y -+CONFIG_DEFAULT_SECURITY="" -+CONFIG_CRYPTO=y -+ -+# -+# Crypto core or helper -+# -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_ALGAPI2=y -+# CONFIG_CRYPTO_MANAGER is not set -+# CONFIG_CRYPTO_MANAGER2 is not set -+# CONFIG_CRYPTO_USER is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_TEST is not set -+ -+# -+# Authenticated Encryption with Associated Data -+# -+# CONFIG_CRYPTO_CCM is not set -+# CONFIG_CRYPTO_GCM is not set -+# CONFIG_CRYPTO_SEQIV is not set -+ -+# -+# Block modes -+# -+# CONFIG_CRYPTO_CBC is not set -+# CONFIG_CRYPTO_CTR is not set -+# CONFIG_CRYPTO_CTS is not set -+# CONFIG_CRYPTO_ECB is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_XTS is not set -+ -+# -+# Hash modes -+# -+# CONFIG_CRYPTO_HMAC is not set -+ -+# -+# Digest -+# -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_GHASH is not set -+# CONFIG_CRYPTO_MD4 is not set -+# CONFIG_CRYPTO_MD5 is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_RMD128 is not set -+# CONFIG_CRYPTO_RMD160 is not set -+# CONFIG_CRYPTO_RMD256 is not set -+# CONFIG_CRYPTO_RMD320 is not set -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_WP512 is not set -+ -+# -+# Ciphers -+# -+CONFIG_CRYPTO_AES=y -+# CONFIG_CRYPTO_ANUBIS is not set -+CONFIG_CRYPTO_ARC4=y -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_DES is not set -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+ -+# -+# Compression -+# -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_ZLIB is not set -+# CONFIG_CRYPTO_LZO is not set -+ -+# -+# Random Number Generation -+# -+# CONFIG_CRYPTO_ANSI_CPRNG is not set -+# CONFIG_CRYPTO_USER_API_HASH is not set -+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set -+# CONFIG_CRYPTO_HW is not set -+# CONFIG_BINARY_PRINTF is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+CONFIG_GENERIC_PCI_IOMAP=y -+CONFIG_GENERIC_IO=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=y -+# CONFIG_CRC_T10DIF is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC32_SELFTEST is not set -+CONFIG_CRC32_SLICEBY8=y -+# CONFIG_CRC32_SLICEBY4 is not set -+# CONFIG_CRC32_SARWATE is not set -+# CONFIG_CRC32_BIT is not set -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+# CONFIG_CRC8 is not set -+CONFIG_ZLIB_INFLATE=y -+# CONFIG_XZ_DEC is not set -+# CONFIG_XZ_DEC_BCJ is not set -+CONFIG_GENERIC_ALLOCATOR=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -+CONFIG_DQL=y -+CONFIG_NLATTR=y -+CONFIG_GENERIC_ATOMIC64=y -+CONFIG_AVERAGE=y -+# CONFIG_CORDIC is not set -diff --git a/arch/arm/configs/aimer39_ak3916_ram_defconfig b/arch/arm/configs/aimer39_ak3916_ram_defconfig -new file mode 100644 -index 00000000..dc6af2ad ---- /dev/null -+++ b/arch/arm/configs/aimer39_ak3916_ram_defconfig -@@ -0,0 +1,1966 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# Linux/arm 3.4.35 Kernel Configuration -+# -+CONFIG_ARM=y -+CONFIG_SYS_SUPPORTS_APM_EMULATION=y -+CONFIG_GENERIC_GPIO=y -+CONFIG_ARCH_USES_GETTIMEOFFSET=y -+CONFIG_KTIME_SCALAR=y -+CONFIG_HAVE_PROC_CPU=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_HAVE_LATENCYTOP_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+CONFIG_HARDIRQS_SW_RESEND=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+CONFIG_ARCH_HAS_CPUFREQ=y -+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_NEED_DMA_MAP_STATE=y -+CONFIG_VECTORS_BASE=0xffff0000 -+# CONFIG_ARM_PATCH_PHYS_VIRT is not set -+CONFIG_PHYS_OFFSET=0x81000000 -+CONFIG_GENERIC_BUG=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+CONFIG_HAVE_IRQ_WORK=y -+ -+# -+# General setup -+# -+# CONFIG_EXPERIMENTAL is not set -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_CROSS_COMPILE="" -+CONFIG_LOCALVERSION="" -+# CONFIG_LOCALVERSION_AUTO is not set -+CONFIG_HAVE_KERNEL_GZIP=y -+CONFIG_HAVE_KERNEL_LZMA=y -+CONFIG_HAVE_KERNEL_XZ=y -+CONFIG_HAVE_KERNEL_LZO=y -+CONFIG_KERNEL_GZIP=y -+# CONFIG_KERNEL_LZMA is not set -+# CONFIG_KERNEL_XZ is not set -+# CONFIG_KERNEL_LZO is not set -+CONFIG_DEFAULT_HOSTNAME="(none)" -+# CONFIG_SWAP is not set -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_FHANDLE is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_AUDIT is not set -+CONFIG_HAVE_GENERIC_HARDIRQS=y -+ -+# -+# IRQ subsystem -+# -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_SHOW=y -+ -+# -+# RCU Subsystem -+# -+CONFIG_TINY_RCU=y -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=16 -+# CONFIG_CGROUPS is not set -+# CONFIG_CHECKPOINT_RESTORE is not set -+# CONFIG_NAMESPACES is not set -+# CONFIG_SCHED_AUTOGROUP is not set -+# CONFIG_SYSFS_DEPRECATED is not set -+# CONFIG_RELAY is not set -+CONFIG_BLK_DEV_INITRD=y -+CONFIG_INITRAMFS_SOURCE="../ipcamera/rootfs/rootfs.initramfs" -+CONFIG_INITRAMFS_ROOT_UID=0 -+CONFIG_INITRAMFS_ROOT_GID=0 -+CONFIG_RD_GZIP=y -+# CONFIG_RD_BZIP2 is not set -+# CONFIG_RD_LZMA is not set -+# CONFIG_RD_XZ is not set -+# CONFIG_RD_LZO is not set -+CONFIG_INITRAMFS_COMPRESSION_NONE=y -+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set -+CONFIG_CC_OPTIMIZE_FOR_SIZE=y -+CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y -+CONFIG_PANIC_TIMEOUT=0 -+CONFIG_EXPERT=y -+CONFIG_UID16=y -+# CONFIG_SYSCTL_SYSCALL is not set -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_ALL 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_SIGNALFD=y -+CONFIG_TIMERFD=y -+CONFIG_EVENTFD=y -+# CONFIG_SHMEM is not set -+CONFIG_AIO=y -+CONFIG_EMBEDDED=y -+CONFIG_HAVE_PERF_EVENTS=y -+CONFIG_PERF_USE_VMALLOC=y -+ -+# -+# Kernel Performance Events And Counters -+# -+# CONFIG_PERF_EVENTS is not set -+# CONFIG_PERF_COUNTERS is not set -+# CONFIG_VM_EVENT_COUNTERS is not set -+# CONFIG_SLUB_DEBUG is not set -+CONFIG_COMPAT_BRK=y -+# CONFIG_SLAB is not set -+CONFIG_SLUB=y -+# CONFIG_SLOB is not set -+# CONFIG_PROFILING is not set -+CONFIG_HAVE_OPROFILE=y -+# CONFIG_KPROBES is not set -+CONFIG_JUMP_LABEL=y -+CONFIG_HAVE_KPROBES=y -+CONFIG_HAVE_KRETPROBES=y -+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -+CONFIG_HAVE_CLK=y -+CONFIG_HAVE_DMA_API_DEBUG=y -+CONFIG_HAVE_ARCH_JUMP_LABEL=y -+ -+# -+# GCOV-based kernel profiling -+# -+CONFIG_HAVE_GENERIC_DMA_COHERENT=y -+CONFIG_RT_MUTEXES=y -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_FORCE_LOAD=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODVERSIONS is not set -+# CONFIG_MODULE_SRCVERSION_ALL is not set -+CONFIG_BLOCK=y -+# CONFIG_LBDAF is not set -+# CONFIG_BLK_DEV_BSG is not set -+# CONFIG_BLK_DEV_BSGLIB is not set -+# CONFIG_BLK_DEV_INTEGRITY is not set -+ -+# -+# Partition Types -+# -+# CONFIG_PARTITION_ADVANCED is not set -+CONFIG_MSDOS_PARTITION=y -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+# CONFIG_IOSCHED_DEADLINE is not set -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_CFQ=y -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="cfq" -+# CONFIG_INLINE_SPIN_TRYLOCK is not set -+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK is not set -+# CONFIG_INLINE_SPIN_LOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_READ_TRYLOCK is not set -+# CONFIG_INLINE_READ_LOCK is not set -+# CONFIG_INLINE_READ_LOCK_BH is not set -+# CONFIG_INLINE_READ_LOCK_IRQ is not set -+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -+CONFIG_INLINE_READ_UNLOCK=y -+# CONFIG_INLINE_READ_UNLOCK_BH is not set -+CONFIG_INLINE_READ_UNLOCK_IRQ=y -+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_WRITE_TRYLOCK is not set -+# CONFIG_INLINE_WRITE_LOCK is not set -+# CONFIG_INLINE_WRITE_LOCK_BH is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -+CONFIG_INLINE_WRITE_UNLOCK=y -+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -+# CONFIG_MUTEX_SPIN_ON_OWNER is not set -+CONFIG_FREEZER=y -+ -+# -+# System Type -+# -+CONFIG_MMU=y -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_REALVIEW is not set -+# CONFIG_ARCH_VERSATILE is not set -+# CONFIG_ARCH_VEXPRESS is not set -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_BCMRING is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_CLPS711X is not set -+# CONFIG_ARCH_CNS3XXX is not set -+# CONFIG_ARCH_GEMINI is not set -+# CONFIG_ARCH_PRIMA2 is not set -+# CONFIG_ARCH_EBSA110 is not set -+# CONFIG_ARCH_EP93XX is not set -+# CONFIG_ARCH_FOOTBRIDGE is not set -+# CONFIG_ARCH_MXC is not set -+# CONFIG_ARCH_MXS is not set -+# CONFIG_ARCH_NETX is not set -+# CONFIG_ARCH_H720X is not set -+# CONFIG_ARCH_IOP13XX is not set -+# CONFIG_ARCH_IOP32X is not set -+# CONFIG_ARCH_IOP33X is not set -+# CONFIG_ARCH_IXP23XX is not set -+# CONFIG_ARCH_IXP2000 is not set -+# CONFIG_ARCH_IXP4XX is not set -+# CONFIG_ARCH_DOVE is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_MV78XX0 is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_ARCH_MMP is not set -+# CONFIG_ARCH_KS8695 is not set -+# CONFIG_ARCH_W90X900 is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_PICOXCELL is not set -+# CONFIG_ARCH_PNX4008 is not set -+# CONFIG_ARCH_PXA is not set -+# CONFIG_ARCH_MSM is not set -+# CONFIG_ARCH_SHMOBILE is not set -+# CONFIG_ARCH_RPC is not set -+# CONFIG_ARCH_SA1100 is not set -+# CONFIG_ARCH_S3C24XX is not set -+# CONFIG_ARCH_S3C64XX is not set -+# CONFIG_ARCH_S5P64X0 is not set -+# CONFIG_ARCH_S5PC100 is not set -+# CONFIG_ARCH_S5PV210 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_SHARK is not set -+# CONFIG_ARCH_U300 is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_NOMADIK is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_OMAP is not set -+# CONFIG_PLAT_SPEAR is not set -+# CONFIG_ARCH_VT8500 is not set -+# CONFIG_ARCH_ZYNQ is not set -+CONFIG_ARCH_AK39=y -+# CONFIG_GPIO_PCA953X is not set -+# CONFIG_KEYBOARD_GPIO_POLLED is not set -+ -+# -+# System MMU -+# -+CONFIG_CPU_AK3916=y -+# CONFIG_ARCH_SDK3910 is not set -+CONFIG_ARCH_AIMER39_AK3916=y -+# CONFIG_ARCH_AIMER39_AK3918 is not set -+CONFIG_ASIC_FREQ_VALUE=90000000 -+ -+# -+# Power management -+# -+# CONFIG_AK39_PM is not set -+# CONFIG_AK39_PWM_TIMER is not set -+CONFIG_PLAT_ANYKA=y -+ -+# -+# Processor Type -+# -+CONFIG_CPU_ARM926T=y -+CONFIG_CPU_32v5=y -+CONFIG_CPU_ABRT_EV5TJ=y -+CONFIG_CPU_PABRT_LEGACY=y -+CONFIG_CPU_CACHE_VIVT=y -+CONFIG_CPU_COPY_V4WB=y -+CONFIG_CPU_TLB_V4WBI=y -+CONFIG_CPU_CP15=y -+CONFIG_CPU_CP15_MMU=y -+CONFIG_CPU_USE_DOMAINS=y -+ -+# -+# Processor Features -+# -+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -+# CONFIG_ARM_THUMB is not set -+# CONFIG_CPU_ICACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set -+# CONFIG_CACHE_L2X0 is not set -+CONFIG_ARM_L1_CACHE_SHIFT=5 -+CONFIG_ARM_NR_BANKS=8 -+# CONFIG_FIQ_DEBUGGER is not set -+ -+# -+# Bus support -+# -+# CONFIG_PCI_SYSCALL is not set -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_PCCARD=y -+CONFIG_PCMCIA=y -+ -+# -+# PC-card bridges -+# -+ -+# -+# Kernel Features -+# -+CONFIG_VMSPLIT_3G=y -+# CONFIG_VMSPLIT_2G is not set -+# CONFIG_VMSPLIT_1G is not set -+CONFIG_PAGE_OFFSET=0xC0000000 -+CONFIG_ARCH_NR_GPIO=0 -+CONFIG_PREEMPT_NONE=y -+# CONFIG_PREEMPT_VOLUNTARY is not set -+# CONFIG_PREEMPT is not set -+CONFIG_HZ=100 -+CONFIG_AEABI=y -+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -+CONFIG_HAVE_ARCH_PFN_VALID=y -+# CONFIG_HIGHMEM is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+CONFIG_HAVE_MEMBLOCK=y -+CONFIG_PAGEFLAGS_EXTENDED=y -+CONFIG_SPLIT_PTLOCK_CPUS=999999 -+# CONFIG_COMPACTION is not set -+# CONFIG_PHYS_ADDR_T_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_KSM is not set -+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -+CONFIG_NEED_PER_CPU_KM=y -+# CONFIG_CLEANCACHE is not set -+CONFIG_FORCE_MAX_ZONEORDER=11 -+CONFIG_ALIGNMENT_TRAP=y -+# CONFIG_SECCOMP is not set -+# CONFIG_DEPRECATED_PARAM_STRUCT is not set -+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -+ -+# -+# Boot options -+# -+# CONFIG_USE_OF is not set -+CONFIG_ZBOOT_ROM_TEXT=0 -+CONFIG_ZBOOT_ROM_BSS=0 -+CONFIG_CMDLINE="mem=64M console=ttySAK0,115200" -+CONFIG_CMDLINE_FROM_BOOTLOADER=y -+# CONFIG_CMDLINE_EXTEND is not set -+# CONFIG_CMDLINE_FORCE is not set -+# CONFIG_XIP_KERNEL is not set -+# CONFIG_AUTO_ZRELADDR is not set -+CONFIG_RAM_BASE=0x80000000 -+CONFIG_VIDEO_RESERVED_MEM_SIZE=0x1000000 -+ -+# -+# CPU Power Management -+# -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ is not set -+# CONFIG_CPU_IDLE is not set -+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set -+ -+# -+# Floating point emulation -+# -+ -+# -+# At least one emulation must be selected -+# -+# CONFIG_VFP is not set -+ -+# -+# Userspace binary formats -+# -+CONFIG_BINFMT_ELF=y -+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -+CONFIG_HAVE_AOUT=y -+# CONFIG_BINFMT_AOUT is not set -+# CONFIG_BINFMT_MISC is not set -+ -+# -+# Power management options -+# -+CONFIG_SUSPEND=y -+CONFIG_SUSPEND_FREEZER=y -+CONFIG_HAS_WAKELOCK=y -+CONFIG_WAKELOCK=y -+CONFIG_PM_SLEEP=y -+# CONFIG_PM_AUTOSLEEP is not set -+# CONFIG_PM_WAKELOCKS is not set -+# CONFIG_PM_RUNTIME is not set -+CONFIG_PM=y -+# CONFIG_PM_DEBUG is not set -+# CONFIG_APM_EMULATION is not set -+CONFIG_PM_CLK=y -+CONFIG_CPU_PM=y -+# CONFIG_SUSPEND_TIME is not set -+CONFIG_ARCH_SUSPEND_POSSIBLE=y -+CONFIG_ARM_CPU_SUSPEND=y -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+CONFIG_UNIX=y -+CONFIG_UNIX_DIAG=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+CONFIG_IP_MULTICAST=y -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+CONFIG_IP_PNP_RARP=y -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE_DEMUX is not set -+# CONFIG_IP_MROUTE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+CONFIG_INET_LRO=y -+CONFIG_INET_DIAG=y -+CONFIG_INET_TCP_DIAG=y -+CONFIG_INET_UDP_DIAG=y -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_IPV6 is not set -+CONFIG_ANDROID_PARANOID_NETWORK=y -+CONFIG_NET_ACTIVITY_STATS=y -+# CONFIG_NETWORK_SECMARK is not set -+CONFIG_NETFILTER=y -+# CONFIG_NETFILTER_DEBUG is not set -+CONFIG_NETFILTER_ADVANCED=y -+ -+# -+# Core Netfilter Configuration -+# -+# CONFIG_NETFILTER_NETLINK_ACCT is not set -+# CONFIG_NETFILTER_NETLINK_QUEUE is not set -+# CONFIG_NETFILTER_NETLINK_LOG is not set -+# CONFIG_NF_CONNTRACK is not set -+# CONFIG_NETFILTER_XTABLES is not set -+# CONFIG_IP_VS is not set -+ -+# -+# IP: Netfilter Configuration -+# -+# CONFIG_NF_DEFRAG_IPV4 is not set -+# CONFIG_IP_NF_QUEUE is not set -+# CONFIG_IP_NF_IPTABLES is not set -+# CONFIG_IP_NF_ARPTABLES is not set -+# CONFIG_ATM is not set -+# CONFIG_L2TP 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_PHONET is not set -+# CONFIG_NET_SCHED is not set -+# CONFIG_DCB is not set -+# CONFIG_BATMAN_ADV is not set -+# CONFIG_OPENVSWITCH is not set -+CONFIG_BQL=y -+CONFIG_HAVE_BPF_JIT=y -+# CONFIG_BPF_JIT is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_CAN is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+CONFIG_WIRELESS=y -+CONFIG_WIRELESS_EXT=y -+CONFIG_WEXT_CORE=y -+CONFIG_WEXT_PROC=y -+CONFIG_WEXT_SPY=y -+CONFIG_WEXT_PRIV=y -+CONFIG_CFG80211=y -+# CONFIG_NL80211_TESTMODE is not set -+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -+# CONFIG_CFG80211_REG_DEBUG is not set -+CONFIG_CFG80211_DEFAULT_PS=y -+# CONFIG_CFG80211_INTERNAL_REGDB is not set -+CONFIG_CFG80211_WEXT=y -+CONFIG_WIRELESS_EXT_SYSFS=y -+CONFIG_LIB80211=y -+# CONFIG_LIB80211_DEBUG is not set -+CONFIG_CFG80211_ALLOW_RECONNECT=y -+CONFIG_MAC80211=y -+CONFIG_MAC80211_HAS_RC=y -+# CONFIG_MAC80211_RC_PID is not set -+CONFIG_MAC80211_RC_MINSTREL=y -+CONFIG_MAC80211_RC_MINSTREL_HT=y -+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -+# CONFIG_MAC80211_LEDS is not set -+# CONFIG_MAC80211_DEBUG_MENU is not set -+# CONFIG_WIMAX is not set -+CONFIG_RFKILL=y -+CONFIG_RFKILL_PM=y -+CONFIG_RFKILL_LEDS=y -+# CONFIG_RFKILL_INPUT is not set -+# CONFIG_RFKILL_GPIO is not set -+# CONFIG_NET_9P is not set -+# CONFIG_CAIF is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_DEVTMPFS=y -+CONFIG_DEVTMPFS_MOUNT=y -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+CONFIG_FW_LOADER=y -+CONFIG_FIRMWARE_IN_KERNEL=y -+CONFIG_EXTRA_FIRMWARE="" -+# CONFIG_DEBUG_DRIVER is not set -+# CONFIG_DEBUG_DEVRES is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_GENERIC_CPU_DEVICES is not set -+CONFIG_DMA_SHARED_BUFFER=y -+# CONFIG_SYNC is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_TESTS is not set -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+# CONFIG_MTD_AFS_PARTS is not set -+# CONFIG_MTD_AR7_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SST25L 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_DOCG3 is not set -+CONFIG_MTD_AK_SPIFLASH=y -+# CONFIG_MTD_NAND_IDS is not set -+# CONFIG_MTD_NAND is not set -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# LPDDR flash memory drivers -+# -+# CONFIG_MTD_LPDDR is not set -+# CONFIG_MTD_UBI is not set -+# CONFIG_PARPORT is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+ -+# -+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected -+# -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+# CONFIG_BLK_DEV_XIP is not set -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+# CONFIG_MG_DISK is not set -+ -+# -+# Misc devices -+# -+# CONFIG_SENSORS_LIS3LV02D is not set -+# CONFIG_AD525X_DPOT is not set -+# CONFIG_ATMEL_PWM is not set -+# CONFIG_ENCLOSURE_SERVICES is not set -+# CONFIG_APDS9802ALS is not set -+# CONFIG_ISL29003 is not set -+# CONFIG_ISL29020 is not set -+# CONFIG_SENSORS_TSL2550 is not set -+# CONFIG_SENSORS_BH1780 is not set -+# CONFIG_SENSORS_BH1770 is not set -+# CONFIG_SENSORS_APDS990X is not set -+# CONFIG_HMC6352 is not set -+# CONFIG_SENSORS_AK8975 is not set -+# CONFIG_TI_DAC7512 is not set -+# CONFIG_UID_STAT is not set -+# CONFIG_BMP085 is not set -+# CONFIG_USB_SWITCH_FSA9480 is not set -+# CONFIG_WL127X_RFKILL is not set -+CONFIG_AK_SERIAL_NUMBER=y -+# CONFIG_AK_MOTOR is not set -+ -+# -+# user space generic gpio controller -+# -+# CONFIG_GPIOS_AKCUSTOM is not set -+ -+# -+# EEPROM support -+# -+# CONFIG_EEPROM_AT24 is not set -+# CONFIG_EEPROM_AT25 is not set -+# CONFIG_EEPROM_LEGACY is not set -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_EEPROM_93XX46 is not set -+ -+# -+# Texas Instruments shared transport line discipline -+# -+# CONFIG_TI_ST is not set -+# CONFIG_SENSORS_LIS3_SPI is not set -+# CONFIG_SENSORS_LIS3_I2C is not set -+ -+# -+# Altera FPGA firmware download module -+# -+# CONFIG_ALTERA_STAPL is not set -+CONFIG_HAVE_IDE=y -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+CONFIG_SCSI_MOD=y -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_SCSI_PROC_FS is not set -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+# CONFIG_SCSI_WAIT_SCAN is not set -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+# CONFIG_SCSI_LOWLEVEL is not set -+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set -+# CONFIG_SCSI_DH is not set -+# CONFIG_SCSI_OSD_INITIATOR is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_TARGET_CORE is not set -+CONFIG_NETDEVICES=y -+CONFIG_NET_CORE=y -+# CONFIG_BONDING is not set -+# CONFIG_DUMMY is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_MII is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+# CONFIG_ARCNET is not set -+ -+# -+# CAIF transport drivers -+# -+CONFIG_ETHERNET=y -+# CONFIG_NET_VENDOR_3COM is not set -+# CONFIG_NET_VENDOR_AMD is not set -+# CONFIG_NET_VENDOR_BROADCOM is not set -+# CONFIG_NET_CALXEDA_XGMAC is not set -+# CONFIG_NET_VENDOR_CHELSIO is not set -+# CONFIG_NET_VENDOR_CIRRUS is not set -+# CONFIG_DM9000 is not set -+# CONFIG_DNET is not set -+# CONFIG_NET_VENDOR_FARADAY is not set -+# CONFIG_NET_VENDOR_FUJITSU is not set -+# CONFIG_NET_VENDOR_INTEL is not set -+# CONFIG_NET_VENDOR_MARVELL is not set -+# CONFIG_NET_VENDOR_MICREL is not set -+# CONFIG_NET_VENDOR_NATSEMI is not set -+# CONFIG_ETHOC is not set -+# CONFIG_NET_VENDOR_SMSC is not set -+# CONFIG_NET_VENDOR_STMICRO is not set -+# CONFIG_NET_VENDOR_XIRCOM is not set -+CONFIG_AK_ETHERNET=y -+# CONFIG_PHYLIB is not set -+# CONFIG_MICREL_KS8995MA is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_TR is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_USB_HSO is not set -+# CONFIG_USB_IPHETH is not set -+CONFIG_WLAN=y -+CONFIG_PCMCIA_RAYCS=y -+# CONFIG_LIBERTAS_THINFIRM is not set -+# CONFIG_ATMEL is not set -+# CONFIG_AT76C50X_USB is not set -+# CONFIG_AIRO_CS is not set -+# CONFIG_USB_ZD1201 is not set -+# CONFIG_RTL8187 is not set -+# CONFIG_MAC80211_HWSIM is not set -+# CONFIG_WIFI_CONTROL_FUNC is not set -+# CONFIG_ATH_COMMON is not set -+# CONFIG_B43 is not set -+# CONFIG_B43LEGACY is not set -+# CONFIG_BCMDHD is not set -+# CONFIG_BRCMFMAC is not set -+# CONFIG_HOSTAP is not set -+# CONFIG_LIBERTAS is not set -+# CONFIG_HERMES is not set -+# CONFIG_RT2X00 is not set -+# CONFIG_MWIFIEX is not set -+ -+# -+# Enable WiMAX (Networking options) to see the WiMAX drivers -+# -+# CONFIG_WAN is not set -+# CONFIG_ISDN is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+# CONFIG_INPUT_SPARSEKMAP is not set -+ -+# -+# Userland interfaces -+# -+# CONFIG_INPUT_MOUSEDEV is not set -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+# CONFIG_INPUT_KEYRESET is not set -+ -+# -+# Input Device Drivers -+# -+CONFIG_INPUT_KEYBOARD=y -+# CONFIG_KEYBOARD_ADP5588 is not set -+# CONFIG_KEYBOARD_ADP5589 is not set -+# CONFIG_KEYBOARD_ATKBD is not set -+# CONFIG_KEYBOARD_QT1070 is not set -+# CONFIG_KEYBOARD_LKKBD is not set -+# CONFIG_KEYBOARD_GPIO is not set -+# CONFIG_KEYBOARD_TCA6416 is not set -+# CONFIG_KEYBOARD_TCA8418 is not set -+# CONFIG_KEYBOARD_MATRIX is not set -+# CONFIG_KEYBOARD_LM8323 is not set -+# CONFIG_KEYBOARD_MAX7359 is not set -+# CONFIG_KEYBOARD_MCS is not set -+# CONFIG_KEYBOARD_MPR121 is not set -+# CONFIG_KEYBOARD_NEWTON is not set -+# CONFIG_KEYBOARD_OPENCORES is not set -+# CONFIG_KEYBOARD_SAMSUNG is not set -+# CONFIG_KEYBOARD_STOWAWAY is not set -+# CONFIG_KEYBOARD_SUNKBD is not set -+# CONFIG_KEYBOARD_OMAP4 is not set -+# CONFIG_KEYBOARD_XTKBD is not set -+CONFIG_KEYBOARD_AKKEY=y -+# CONFIG_KEYBOARD_AK_KEYPAD is not set -+CONFIG_KEYBOARD_ADKEY=y -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+# CONFIG_SERIO is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+# CONFIG_VT is not set -+# CONFIG_UNIX98_PTYS is not set -+# CONFIG_LEGACY_PTYS is not set -+# CONFIG_SERIAL_NONSTANDARD is not set -+# CONFIG_TRACE_SINK is not set -+CONFIG_DEVMEM=y -+# CONFIG_DEVKMEM is not set -+ -+# -+# Serial drivers -+# -+# CONFIG_SERIAL_8250 is not set -+ -+# -+# Non-8250 serial port support -+# -+# CONFIG_SERIAL_MAX3100 is not set -+# CONFIG_SERIAL_MAX3107 is not set -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_SERIAL_TIMBERDALE is not set -+# CONFIG_SERIAL_ALTERA_JTAGUART is not set -+# CONFIG_SERIAL_ALTERA_UART is not set -+# CONFIG_SERIAL_XILINX_PS_UART is not set -+CONFIG_SERIAL_AK39_UART=y -+CONFIG_SERIAL_AK39_CONSOLE=y -+# CONFIG_SERIAL_GPIO_UART is not set -+CONFIG_TTY_PRINTK=y -+# CONFIG_HVC_DCC is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_R3964 is not set -+ -+# -+# PCMCIA character devices -+# -+# CONFIG_SYNCLINK_CS is not set -+# CONFIG_CARDMAN_4000 is not set -+# CONFIG_CARDMAN_4040 is not set -+# CONFIG_IPWIRELESS is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+# CONFIG_DCC_TTY is not set -+# CONFIG_RAMOOPS is not set -+CONFIG_I2C=y -+CONFIG_I2C_BOARDINFO=y -+CONFIG_I2C_COMPAT=y -+# CONFIG_I2C_CHARDEV is not set -+# CONFIG_I2C_HELPER_AUTO is not set -+CONFIG_I2C_SMBUS=y -+ -+# -+# I2C Algorithms -+# -+CONFIG_I2C_ALGOBIT=y -+# CONFIG_I2C_ALGOPCF is not set -+# CONFIG_I2C_ALGOPCA is not set -+ -+# -+# I2C Hardware Bus support -+# -+ -+# -+# I2C system bus drivers (mostly embedded / system-on-chip) -+# -+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set -+# CONFIG_I2C_GPIO is not set -+# CONFIG_I2C_PCA_PLATFORM is not set -+# CONFIG_I2C_PXA_PCI is not set -+# CONFIG_I2C_SIMTEC is not set -+CONFIG_I2C_ANYKA=y -+CONFIG_I2C_AK39_HW=y -+# CONFIG_I2C_GPIO_SOFT is not set -+ -+# -+# External I2C/SMBus adapter drivers -+# -+# CONFIG_I2C_DIOLAN_U2C is not set -+# CONFIG_I2C_PARPORT_LIGHT is not set -+# CONFIG_I2C_TINY_USB is not set -+ -+# -+# Other I2C/SMBus bus drivers -+# -+# CONFIG_I2C_DEBUG_CORE is not set -+# CONFIG_I2C_DEBUG_ALGO is not set -+# CONFIG_I2C_DEBUG_BUS is not set -+CONFIG_SPI=y -+# CONFIG_SPI_DEBUG is not set -+CONFIG_SPI_MASTER=y -+ -+# -+# SPI Master Controller Drivers -+# -+# CONFIG_SPI_ALTERA is not set -+CONFIG_SPI_BITBANG=y -+# CONFIG_SPI_GPIO is not set -+# CONFIG_SPI_OC_TINY is not set -+# CONFIG_SPI_PXA2XX_PCI is not set -+CONFIG_SPI_ANYKA=y -+# CONFIG_SPI_DESIGNWARE is not set -+ -+# -+# SPI Protocol Masters -+# -+# CONFIG_SPI_TLE62X0 is not set -+# CONFIG_HSI is not set -+ -+# -+# PPS support -+# -+ -+# -+# PPS generators support -+# -+ -+# -+# PTP clock support -+# -+ -+# -+# Enable Device Drivers -> PPS to see the PTP clock options. -+# -+CONFIG_ARCH_REQUIRE_GPIOLIB=y -+CONFIG_GPIOLIB=y -+# CONFIG_DEBUG_GPIO is not set -+ -+# -+# Memory mapped GPIO drivers: -+# -+# CONFIG_GPIO_GENERIC_PLATFORM is not set -+ -+# -+# I2C GPIO expanders: -+# -+# CONFIG_GPIO_MAX7300 is not set -+# CONFIG_GPIO_MAX732X is not set -+# CONFIG_GPIO_PCF857X is not set -+# CONFIG_GPIO_SX150X is not set -+# CONFIG_GPIO_ADP5588 is not set -+ -+# -+# PCI GPIO expanders: -+# -+ -+# -+# SPI GPIO expanders: -+# -+# CONFIG_GPIO_MAX7301 is not set -+# CONFIG_GPIO_MCP23S08 is not set -+# CONFIG_GPIO_MC33880 is not set -+# CONFIG_GPIO_74X164 is not set -+ -+# -+# AC97 GPIO expanders: -+# -+ -+# -+# MODULbus GPIO expanders: -+# -+# CONFIG_W1 is not set -+CONFIG_POWER_SUPPLY=y -+# CONFIG_POWER_SUPPLY_DEBUG is not set -+# CONFIG_PDA_POWER is not set -+# CONFIG_TEST_POWER is not set -+# CONFIG_BATTERY_DS2780 is not set -+# CONFIG_BATTERY_DS2781 is not set -+# CONFIG_BATTERY_DS2782 is not set -+# CONFIG_BATTERY_SBS is not set -+# CONFIG_BATTERY_BQ27x00 is not set -+# CONFIG_BATTERY_MAX17040 is not set -+# CONFIG_BATTERY_MAX17042 is not set -+# CONFIG_BATTERY_ANDROID is not set -+# CONFIG_CHARGER_MAX8903 is not set -+# CONFIG_CHARGER_LP8727 is not set -+# CONFIG_CHARGER_GPIO is not set -+# CONFIG_CHARGER_SMB347 is not set -+CONFIG_BATTERY_AK=y -+# CONFIG_HWMON is not set -+# CONFIG_THERMAL is not set -+CONFIG_WATCHDOG=y -+CONFIG_WATCHDOG_CORE=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+# CONFIG_SOFT_WATCHDOG is not set -+# CONFIG_DW_WATCHDOG is not set -+# CONFIG_MAX63XX_WATCHDOG is not set -+CONFIG_AK39_WATCHDOG=y -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+CONFIG_SSB_POSSIBLE=y -+ -+# -+# Sonics Silicon Backplane -+# -+# CONFIG_SSB is not set -+CONFIG_BCMA_POSSIBLE=y -+ -+# -+# Broadcom specific AMBA -+# -+# CONFIG_BCMA is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_CORE is not set -+# CONFIG_MFD_88PM860X is not set -+# CONFIG_MFD_SM501 is not set -+# CONFIG_MFD_ASIC3 is not set -+# CONFIG_HTC_EGPIO is not set -+# CONFIG_HTC_PASIC3 is not set -+# CONFIG_HTC_I2CPLD is not set -+# CONFIG_TPS6105X is not set -+# CONFIG_TPS65010 is not set -+# CONFIG_TPS6507X is not set -+# CONFIG_MFD_TPS65217 is not set -+# CONFIG_MFD_TPS6586X is not set -+# CONFIG_MFD_TPS65910 is not set -+# CONFIG_MFD_TPS65912_I2C is not set -+# CONFIG_MFD_TPS65912_SPI is not set -+# CONFIG_TWL4030_CORE is not set -+# CONFIG_TWL6040_CORE is not set -+# CONFIG_MFD_STMPE is not set -+# CONFIG_MFD_TC3589X is not set -+# CONFIG_MFD_TMIO is not set -+# CONFIG_MFD_T7L66XB is not set -+# CONFIG_MFD_TC6387XB is not set -+# CONFIG_MFD_TC6393XB is not set -+# CONFIG_PMIC_DA903X is not set -+# CONFIG_MFD_DA9052_SPI is not set -+# CONFIG_MFD_DA9052_I2C is not set -+# CONFIG_PMIC_ADP5520 is not set -+# CONFIG_MFD_MAX8925 is not set -+# CONFIG_MFD_MAX8997 is not set -+# CONFIG_MFD_MAX8998 is not set -+# CONFIG_MFD_S5M_CORE is not set -+# CONFIG_MFD_WM8400 is not set -+# CONFIG_MFD_WM831X_I2C is not set -+# CONFIG_MFD_WM831X_SPI is not set -+# CONFIG_MFD_WM8350_I2C is not set -+# CONFIG_MFD_WM8994 is not set -+# CONFIG_MFD_PCF50633 is not set -+# CONFIG_MFD_MC13XXX is not set -+# CONFIG_ABX500_CORE is not set -+# CONFIG_EZX_PCAP is not set -+# CONFIG_MFD_WL1273_CORE is not set -+# CONFIG_MFD_TPS65090 is not set -+# CONFIG_MFD_AAT2870_CORE is not set -+# CONFIG_MFD_RC5T583 is not set -+# CONFIG_REGULATOR is not set -+CONFIG_MEDIA_SUPPORT=y -+ -+# -+# Multimedia core support -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L2_COMMON=y -+# CONFIG_DVB_CORE is not set -+CONFIG_VIDEO_MEDIA=y -+ -+# -+# Multimedia drivers -+# -+# CONFIG_RC_CORE is not set -+# CONFIG_MEDIA_ATTACH is not set -+CONFIG_MEDIA_TUNER=y -+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set -+CONFIG_MEDIA_TUNER_SIMPLE=y -+CONFIG_MEDIA_TUNER_TDA8290=y -+CONFIG_MEDIA_TUNER_TDA827X=y -+CONFIG_MEDIA_TUNER_TDA18271=y -+CONFIG_MEDIA_TUNER_TDA9887=y -+CONFIG_MEDIA_TUNER_TEA5767=y -+CONFIG_MEDIA_TUNER_MT20XX=y -+CONFIG_MEDIA_TUNER_XC2028=y -+CONFIG_MEDIA_TUNER_XC5000=y -+CONFIG_MEDIA_TUNER_XC4000=y -+CONFIG_MEDIA_TUNER_MC44S803=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEOBUF_GEN=y -+CONFIG_VIDEOBUF_DMA_CONTIG=y -+CONFIG_VIDEOBUF2_CORE=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set -+ -+# -+# Encoders, decoders, sensors and other helper chips -+# -+ -+# -+# Audio decoders, processors and mixers -+# -+# CONFIG_VIDEO_TVAUDIO is not set -+# CONFIG_VIDEO_TDA7432 is not set -+# CONFIG_VIDEO_TDA9840 is not set -+# CONFIG_VIDEO_TEA6415C is not set -+# CONFIG_VIDEO_TEA6420 is not set -+# CONFIG_VIDEO_MSP3400 is not set -+# CONFIG_VIDEO_CS5345 is not set -+# CONFIG_VIDEO_CS53L32A is not set -+# CONFIG_VIDEO_WM8775 is not set -+# CONFIG_VIDEO_WM8739 is not set -+# CONFIG_VIDEO_VP27SMPX is not set -+ -+# -+# RDS decoders -+# -+# CONFIG_VIDEO_SAA6588 is not set -+ -+# -+# Video decoders -+# -+# CONFIG_VIDEO_ADV7180 is not set -+# CONFIG_VIDEO_ADV7183 is not set -+# CONFIG_VIDEO_BT819 is not set -+# CONFIG_VIDEO_BT856 is not set -+# CONFIG_VIDEO_BT866 is not set -+# CONFIG_VIDEO_KS0127 is not set -+# CONFIG_VIDEO_SAA7110 is not set -+# CONFIG_VIDEO_SAA711X is not set -+# CONFIG_VIDEO_SAA7191 is not set -+# CONFIG_VIDEO_TVP514X is not set -+# CONFIG_VIDEO_TVP5150 is not set -+# CONFIG_VIDEO_TVP7002 is not set -+# CONFIG_VIDEO_VPX3220 is not set -+ -+# -+# Video and audio decoders -+# -+# CONFIG_VIDEO_SAA717X is not set -+# CONFIG_VIDEO_CX25840 is not set -+ -+# -+# MPEG video encoders -+# -+# CONFIG_VIDEO_CX2341X is not set -+ -+# -+# Video encoders -+# -+# CONFIG_VIDEO_SAA7127 is not set -+# CONFIG_VIDEO_SAA7185 is not set -+# CONFIG_VIDEO_ADV7170 is not set -+# CONFIG_VIDEO_ADV7175 is not set -+# CONFIG_VIDEO_ADV7343 is not set -+# CONFIG_VIDEO_AK881X is not set -+ -+# -+# Camera sensor devices -+# -+# CONFIG_VIDEO_OV7670 is not set -+# CONFIG_VIDEO_VS6624 is not set -+# CONFIG_VIDEO_MT9V011 is not set -+# CONFIG_VIDEO_TCM825X is not set -+# CONFIG_VIDEO_SR030PC30 is not set -+ -+# -+# Flash devices -+# -+ -+# -+# Video improvement chips -+# -+# CONFIG_VIDEO_UPD64031A is not set -+# CONFIG_VIDEO_UPD64083 is not set -+ -+# -+# Miscelaneous helper chips -+# -+# CONFIG_VIDEO_THS7303 is not set -+# CONFIG_VIDEO_M52790 is not set -+# CONFIG_V4L_USB_DRIVERS is not set -+CONFIG_V4L_PLATFORM_DRIVERS=y -+CONFIG_SOC_CAMERA=y -+# CONFIG_SOC_CAMERA_IMX074 is not set -+# CONFIG_SOC_CAMERA_MT9M001 is not set -+# CONFIG_SOC_CAMERA_MT9M111 is not set -+# CONFIG_SOC_CAMERA_MT9T031 is not set -+# CONFIG_SOC_CAMERA_MT9T112 is not set -+# CONFIG_SOC_CAMERA_MT9V022 is not set -+# CONFIG_SOC_CAMERA_RJ54N1 is not set -+# CONFIG_SOC_CAMERA_TW9910 is not set -+# CONFIG_SOC_CAMERA_PLATFORM is not set -+# CONFIG_SOC_CAMERA_OV2640 is not set -+# CONFIG_SOC_CAMERA_OV5642 is not set -+# CONFIG_SOC_CAMERA_OV6650 is not set -+# CONFIG_SOC_CAMERA_OV772X is not set -+# CONFIG_SOC_CAMERA_OV9640 is not set -+# CONFIG_SOC_CAMERA_OV9740 is not set -+CONFIG_LINUX_AKSENSOR=y -+CONFIG_SENSOR_GC0308=y -+CONFIG_SENSOR_OV2643=y -+CONFIG_SENSOR_OV7725=y -+CONFIG_SENSOR_HM1375=y -+CONFIG_SENSOR_OV9712=y -+CONFIG_SENSOR_OV2710=y -+# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set -+# CONFIG_VIDEO_SH_MOBILE_CEU is not set -+CONFIG_VIDEO_AK=y -+# CONFIG_V4L_MEM2MEM_DRIVERS is not set -+# CONFIG_RADIO_ADAPTERS is not set -+ -+# -+# Graphics support -+# -+# CONFIG_DRM is not set -+CONFIG_ION=y -+CONFIG_ION_AK=y -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_EXYNOS_VIDEO is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+CONFIG_SOUND=y -+# CONFIG_SOUND_OSS_CORE is not set -+CONFIG_SND=y -+CONFIG_SND_TIMER=y -+CONFIG_SND_PCM=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 -+# CONFIG_SND_RAWMIDI_SEQ is not set -+# CONFIG_SND_OPL3_LIB_SEQ is not set -+# CONFIG_SND_OPL4_LIB_SEQ is not set -+# CONFIG_SND_SBAWE_SEQ is not set -+# CONFIG_SND_EMU10K1_SEQ is not set -+# CONFIG_SND_DRIVERS is not set -+CONFIG_SND_ARM=y -+CONFIG_SND_AK_PCM=y -+CONFIG_CODEC_AK39=y -+CONFIG_SPKHP_SWITCH_AUTO=y -+# CONFIG_SPKHP_SWITCH_MIXER is not set -+# CONFIG_SPKHP_SWITCH_UEVENT is not set -+# CONFIG_SUPPORT_AEC is not set -+# CONFIG_SND_SPI is not set -+# CONFIG_SND_USB is not set -+CONFIG_SND_PCMCIA=y -+# CONFIG_SND_VXPOCKET is not set -+# CONFIG_SND_PDAUDIOCF is not set -+# CONFIG_SND_SOC is not set -+# CONFIG_SOUND_PRIME is not set -+# CONFIG_HID_SUPPORT is not set -+# CONFIG_USB_ARCH_HAS_OHCI is not set -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB_ARCH_HAS_XHCI is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_COMMON=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+# CONFIG_USB_DEVICE_CLASS is not set -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_OTG_WHITELIST is not set -+# CONFIG_USB_OTG_BLACKLIST_HUB is not set -+# CONFIG_USB_DWC3 is not set -+# CONFIG_USB_MON is not set -+# CONFIG_USB_WUSB_CBAF is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_C67X00_HCD is not set -+# CONFIG_USB_OXU210HP_HCD is not set -+# CONFIG_USB_ISP116X_HCD is not set -+# CONFIG_USB_ISP1362_HCD is not set -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+CONFIG_USB_ANYKA_HCD=y -+CONFIG_USB_AKOTG_HS_HCD=m -+# CONFIG_USB_AKOTG_DMA is not set -+# CONFIG_USB_MUSB_HDRC is not set -+# CONFIG_USB_RENESAS_USBHS is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+# CONFIG_USB_WDM is not set -+# CONFIG_USB_TMC is not set -+ -+# -+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -+# -+ -+# -+# also be needed; see USB_STORAGE Help for more info -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_REALTEK is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_ONETOUCH is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set -+# CONFIG_USB_STORAGE_ENE_UB6250 is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+ -+# -+# USB port drivers -+# -+# 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_SEVSEG 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_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+# CONFIG_USB_TEST is not set -+# CONFIG_USB_ISIGHTFW is not set -+# CONFIG_USB_YUREX is not set -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_VBUS_DRAW=500 -+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -+# CONFIG_USB_FUSB300 is not set -+# CONFIG_USB_R8A66597 is not set -+# CONFIG_USB_MV_UDC is not set -+# CONFIG_USB_GADGET_AKUDC_PRODUCER is not set -+CONFIG_USB_GADGET_AKUDC=y -+CONFIG_USB_AKUDC=m -+# CONFIG_USB_AKUDC_DEBUG_FS is not set -+# CONFIG_USB_M66592 is not set -+# CONFIG_USB_NET2272 is not set -+# CONFIG_USB_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_AUDIO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_G_NCM is not set -+# CONFIG_USB_FILE_STORAGE is not set -+CONFIG_USB_MASS_STORAGE=m -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_G_PRINTER is not set -+# CONFIG_USB_CDC_COMPOSITE is not set -+# CONFIG_USB_G_ACM_MS is not set -+# CONFIG_USB_G_MULTI is not set -+# CONFIG_USB_G_HID is not set -+# CONFIG_USB_G_DBGP is not set -+# CONFIG_USB_G_WEBCAM is not set -+ -+# -+# OTG and related infrastructure -+# -+# CONFIG_USB_OTG_WAKELOCK is not set -+# CONFIG_USB_GPIO_VBUS is not set -+# CONFIG_USB_ULPI is not set -+# CONFIG_NOP_USB_XCEIV is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD/SDIO Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_MINORS=8 -+# CONFIG_MMC_BLOCK_BOUNCE is not set -+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set -+# CONFIG_SDIO_UART is not set -+# CONFIG_MMC_TEST is not set -+# CONFIG_SDIO_WIFI is not set -+ -+# -+# MMC/SD/SDIO Host Controller Drivers -+# -+# CONFIG_MMC_SDHCI is not set -+# CONFIG_MMC_SDHCI_PXAV3 is not set -+# CONFIG_MMC_SDHCI_PXAV2 is not set -+# CONFIG_MMC_SPI is not set -+# CONFIG_MMC_DW is not set -+# CONFIG_MMC_VUB300 is not set -+# CONFIG_MMC_USHC is not set -+CONFIG_MMC_ANYKA=y -+# CONFIG_MEMSTICK is not set -+CONFIG_NEW_LEDS=y -+CONFIG_LEDS_CLASS=y -+ -+# -+# LED drivers -+# -+# CONFIG_LEDS_LM3530 is not set -+# CONFIG_LEDS_GPIO is not set -+# CONFIG_LEDS_LP3944 is not set -+# CONFIG_LEDS_LP5521 is not set -+# CONFIG_LEDS_LP5523 is not set -+# CONFIG_LEDS_PCA955X is not set -+# CONFIG_LEDS_PCA9633 is not set -+# CONFIG_LEDS_DAC124S085 is not set -+# CONFIG_LEDS_BD2802 is not set -+CONFIG_LEDS_AK39=y -+# CONFIG_LEDS_LT3593 is not set -+# CONFIG_LEDS_RENESAS_TPU is not set -+# CONFIG_LEDS_TCA6507 is not set -+# CONFIG_LEDS_OT200 is not set -+CONFIG_LEDS_TRIGGERS=y -+ -+# -+# LED Triggers -+# -+CONFIG_LEDS_TRIGGER_TIMER=y -+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set -+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set -+# CONFIG_LEDS_TRIGGER_GPIO is not set -+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set -+ -+# -+# iptables trigger is under Netfilter config (LED target) -+# -+# CONFIG_SWITCH is not set -+# CONFIG_ACCESSIBILITY is not set -+CONFIG_RTC_LIB=y -+CONFIG_RTC_CLASS=y -+CONFIG_RTC_HCTOSYS=y -+CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -+# CONFIG_RTC_DEBUG is not set -+ -+# -+# RTC interfaces -+# -+CONFIG_RTC_INTF_SYSFS=y -+CONFIG_RTC_INTF_PROC=y -+CONFIG_RTC_INTF_DEV=y -+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -+# CONFIG_RTC_DRV_TEST is not set -+ -+# -+# I2C RTC drivers -+# -+# CONFIG_RTC_DRV_DS1307 is not set -+# CONFIG_RTC_DRV_DS1374 is not set -+# CONFIG_RTC_DRV_DS1672 is not set -+# CONFIG_RTC_DRV_DS3232 is not set -+# CONFIG_RTC_DRV_MAX6900 is not set -+# CONFIG_RTC_DRV_RS5C372 is not set -+# CONFIG_RTC_DRV_ISL1208 is not set -+# CONFIG_RTC_DRV_ISL12022 is not set -+# CONFIG_RTC_DRV_X1205 is not set -+# CONFIG_RTC_DRV_PCF8563 is not set -+# CONFIG_RTC_DRV_PCF8583 is not set -+# CONFIG_RTC_DRV_M41T80 is not set -+# CONFIG_RTC_DRV_BQ32K is not set -+# CONFIG_RTC_DRV_S35390A is not set -+# CONFIG_RTC_DRV_FM3130 is not set -+# CONFIG_RTC_DRV_RX8581 is not set -+# CONFIG_RTC_DRV_RX8025 is not set -+# CONFIG_RTC_DRV_EM3027 is not set -+# CONFIG_RTC_DRV_RV3029C2 is not set -+ -+# -+# SPI RTC drivers -+# -+# CONFIG_RTC_DRV_M41T93 is not set -+# CONFIG_RTC_DRV_M41T94 is not set -+# CONFIG_RTC_DRV_DS1305 is not set -+# CONFIG_RTC_DRV_DS1390 is not set -+# CONFIG_RTC_DRV_MAX6902 is not set -+# CONFIG_RTC_DRV_R9701 is not set -+# CONFIG_RTC_DRV_RS5C348 is not set -+# CONFIG_RTC_DRV_DS3234 is not set -+# CONFIG_RTC_DRV_PCF2123 is not set -+ -+# -+# Platform RTC drivers -+# -+# CONFIG_RTC_DRV_CMOS is not set -+# CONFIG_RTC_DRV_DS1286 is not set -+# CONFIG_RTC_DRV_DS1511 is not set -+# CONFIG_RTC_DRV_DS1553 is not set -+# CONFIG_RTC_DRV_DS1742 is not set -+# CONFIG_RTC_DRV_STK17TA8 is not set -+# CONFIG_RTC_DRV_M48T86 is not set -+# CONFIG_RTC_DRV_M48T35 is not set -+# CONFIG_RTC_DRV_M48T59 is not set -+# CONFIG_RTC_DRV_MSM6242 is not set -+# CONFIG_RTC_DRV_BQ4802 is not set -+# CONFIG_RTC_DRV_RP5C01 is not set -+# CONFIG_RTC_DRV_V3020 is not set -+ -+# -+# on-CPU RTC drivers -+# -+CONFIG_RTC_DRV_AK=y -+# CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set -+CONFIG_UIO=y -+# CONFIG_UIO_PDRV is not set -+# CONFIG_UIO_PDRV_GENIRQ is not set -+CONFIG_UIO_VCODEC=y -+ -+# -+# Virtio drivers -+# -+# CONFIG_VIRTIO_BALLOON is not set -+ -+# -+# Microsoft Hyper-V guest support -+# -+# CONFIG_STAGING is not set -+CONFIG_CLKDEV_LOOKUP=y -+ -+# -+# Hardware Spinlock drivers -+# -+# CONFIG_IOMMU_SUPPORT is not set -+ -+# -+# Remoteproc drivers (EXPERIMENTAL) -+# -+ -+# -+# Rpmsg drivers (EXPERIMENTAL) -+# -+# CONFIG_VIRT_DRIVERS is not set -+# CONFIG_PM_DEVFREQ is not set -+ -+# -+# File systems -+# -+# CONFIG_EXT2_FS is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4_FS is not set -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_FS_POSIX_ACL is not set -+CONFIG_FILE_LOCKING=y -+CONFIG_FSNOTIFY=y -+CONFIG_DNOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_FANOTIFY is not set -+# CONFIG_QUOTA is not set -+# CONFIG_QUOTACTL is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_PROC_PAGE_MONITOR=y -+CONFIG_SYSFS=y -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+CONFIG_MISC_FILESYSTEMS=y -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_YAFFS_FS is not set -+CONFIG_JFFS2_FS=y -+CONFIG_JFFS2_FS_DEBUG=0 -+# CONFIG_JFFS2_FS_WRITEBUFFER is not set -+CONFIG_JFFS2_COMPRESSION_OPTIONS=y -+# CONFIG_JFFS2_ZLIB is not set -+# CONFIG_JFFS2_LZO is not set -+# CONFIG_JFFS2_RTIME is not set -+# CONFIG_JFFS2_RUBIN is not set -+CONFIG_JFFS2_CMODE_NONE=y -+# CONFIG_JFFS2_CMODE_PRIORITY is not set -+# CONFIG_JFFS2_CMODE_SIZE is not set -+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_SQUASHFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_OMFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_QNX6FS_FS is not set -+# CONFIG_ROMFS_FS is not set -+# CONFIG_PSTORE is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+# CONFIG_NETWORK_FILESYSTEMS is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+# CONFIG_NLS_CODEPAGE_936 is not set -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+# CONFIG_NLS_ASCII is not set -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+ -+# -+# Kernel hacking -+# -+# CONFIG_PRINTK_TIME is not set -+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_FRAME_WARN=1024 -+# CONFIG_MAGIC_SYSRQ is not set -+# CONFIG_STRIP_ASM_SYMS is not set -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_SECTION_MISMATCH is not set -+CONFIG_DEBUG_KERNEL=y -+# CONFIG_DEBUG_SHIRQ is not set -+# CONFIG_LOCKUP_DETECTOR is not set -+# CONFIG_HARDLOCKUP_DETECTOR_NMI is not set -+# CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU is not set -+# CONFIG_HARDLOCKUP_DETECTOR is not set -+# CONFIG_DETECT_HUNG_TASK is not set -+# CONFIG_SCHED_DEBUG is not set -+# CONFIG_SCHEDSTATS is not set -+# CONFIG_TIMER_STATS is not set -+# CONFIG_DEBUG_OBJECTS is not set -+# CONFIG_SLUB_STATS is not set -+# CONFIG_DEBUG_RT_MUTEXES is not set -+# CONFIG_RT_MUTEX_TESTER is not set -+# CONFIG_DEBUG_SPINLOCK is not set -+# CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_SPARSE_RCU_POINTER is not set -+# CONFIG_LOCK_STAT is not set -+# CONFIG_DEBUG_ATOMIC_SLEEP is not set -+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -+# CONFIG_STACKTRACE is not set -+# CONFIG_DEBUG_STACK_USAGE is not set -+# CONFIG_DEBUG_KOBJECT is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_DEBUG_INFO is not set -+# CONFIG_DEBUG_VM is not set -+# CONFIG_DEBUG_WRITECOUNT is not set -+# CONFIG_DEBUG_MEMORY_INIT is not set -+# CONFIG_DEBUG_LIST is not set -+# CONFIG_TEST_LIST_SORT is not set -+# CONFIG_DEBUG_SG is not set -+# CONFIG_DEBUG_NOTIFIERS is not set -+# CONFIG_DEBUG_CREDENTIALS is not set -+CONFIG_FRAME_POINTER=y -+# CONFIG_BOOT_PRINTK_DELAY is not set -+# CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_RCU_TRACE is not set -+# CONFIG_BACKTRACE_SELF_TEST is not set -+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -+# CONFIG_FAULT_INJECTION is not set -+# CONFIG_LATENCYTOP is not set -+# CONFIG_DEBUG_PAGEALLOC is not set -+CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -+CONFIG_HAVE_DYNAMIC_FTRACE=y -+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_HAVE_C_RECORDMCOUNT=y -+CONFIG_TRACING_SUPPORT=y -+# CONFIG_FTRACE is not set -+# CONFIG_DMA_API_DEBUG is not set -+# CONFIG_ATOMIC64_SELFTEST is not set -+# CONFIG_SAMPLES is not set -+CONFIG_HAVE_ARCH_KGDB=y -+# CONFIG_TEST_KSTRTOX is not set -+# CONFIG_STRICT_DEVMEM is not set -+CONFIG_DEBUG_USER=y -+# CONFIG_DEBUG_RODATA is not set -+# CONFIG_DEBUG_LL is not set -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY_DMESG_RESTRICT is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITYFS is not set -+CONFIG_DEFAULT_SECURITY_DAC=y -+CONFIG_DEFAULT_SECURITY="" -+CONFIG_CRYPTO=y -+ -+# -+# Crypto core or helper -+# -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_ALGAPI2=y -+# CONFIG_CRYPTO_MANAGER is not set -+# CONFIG_CRYPTO_MANAGER2 is not set -+# CONFIG_CRYPTO_USER is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_TEST is not set -+ -+# -+# Authenticated Encryption with Associated Data -+# -+# CONFIG_CRYPTO_CCM is not set -+# CONFIG_CRYPTO_GCM is not set -+# CONFIG_CRYPTO_SEQIV is not set -+ -+# -+# Block modes -+# -+# CONFIG_CRYPTO_CBC is not set -+# CONFIG_CRYPTO_CTR is not set -+# CONFIG_CRYPTO_CTS is not set -+# CONFIG_CRYPTO_ECB is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_XTS is not set -+ -+# -+# Hash modes -+# -+# CONFIG_CRYPTO_HMAC is not set -+ -+# -+# Digest -+# -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_GHASH is not set -+# CONFIG_CRYPTO_MD4 is not set -+# CONFIG_CRYPTO_MD5 is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_RMD128 is not set -+# CONFIG_CRYPTO_RMD160 is not set -+# CONFIG_CRYPTO_RMD256 is not set -+# CONFIG_CRYPTO_RMD320 is not set -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_WP512 is not set -+ -+# -+# Ciphers -+# -+CONFIG_CRYPTO_AES=y -+# CONFIG_CRYPTO_ANUBIS is not set -+CONFIG_CRYPTO_ARC4=y -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_DES is not set -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+ -+# -+# Compression -+# -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_ZLIB is not set -+# CONFIG_CRYPTO_LZO is not set -+ -+# -+# Random Number Generation -+# -+# CONFIG_CRYPTO_ANSI_CPRNG is not set -+# CONFIG_CRYPTO_USER_API_HASH is not set -+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set -+# CONFIG_CRYPTO_HW is not set -+# CONFIG_BINARY_PRINTF is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+CONFIG_GENERIC_PCI_IOMAP=y -+CONFIG_GENERIC_IO=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=y -+# CONFIG_CRC_T10DIF is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC32_SELFTEST is not set -+CONFIG_CRC32_SLICEBY8=y -+# CONFIG_CRC32_SLICEBY4 is not set -+# CONFIG_CRC32_SARWATE is not set -+# CONFIG_CRC32_BIT is not set -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+# CONFIG_CRC8 is not set -+CONFIG_ZLIB_INFLATE=y -+# CONFIG_XZ_DEC is not set -+# CONFIG_XZ_DEC_BCJ is not set -+CONFIG_DECOMPRESS_GZIP=y -+CONFIG_GENERIC_ALLOCATOR=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -+CONFIG_DQL=y -+CONFIG_NLATTR=y -+CONFIG_GENERIC_ATOMIC64=y -+CONFIG_AVERAGE=y -+# CONFIG_CORDIC is not set -diff --git a/arch/arm/configs/aimer39_ak3918_defconfig b/arch/arm/configs/aimer39_ak3918_defconfig -new file mode 100644 -index 00000000..c767162a ---- /dev/null -+++ b/arch/arm/configs/aimer39_ak3918_defconfig -@@ -0,0 +1,1962 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# Linux/arm 3.4.35 Kernel Configuration -+# -+CONFIG_ARM=y -+CONFIG_SYS_SUPPORTS_APM_EMULATION=y -+CONFIG_GENERIC_GPIO=y -+CONFIG_ARCH_USES_GETTIMEOFFSET=y -+CONFIG_KTIME_SCALAR=y -+CONFIG_HAVE_PROC_CPU=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_HAVE_LATENCYTOP_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+CONFIG_HARDIRQS_SW_RESEND=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+CONFIG_ARCH_HAS_CPUFREQ=y -+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_NEED_DMA_MAP_STATE=y -+CONFIG_VECTORS_BASE=0xffff0000 -+# CONFIG_ARM_PATCH_PHYS_VIRT is not set -+CONFIG_PHYS_OFFSET=0x81000000 -+CONFIG_GENERIC_BUG=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+CONFIG_HAVE_IRQ_WORK=y -+ -+# -+# General setup -+# -+# CONFIG_EXPERIMENTAL is not set -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_CROSS_COMPILE="" -+CONFIG_LOCALVERSION="" -+# CONFIG_LOCALVERSION_AUTO is not set -+CONFIG_HAVE_KERNEL_GZIP=y -+CONFIG_HAVE_KERNEL_LZMA=y -+CONFIG_HAVE_KERNEL_XZ=y -+CONFIG_HAVE_KERNEL_LZO=y -+# CONFIG_KERNEL_GZIP is not set -+# CONFIG_KERNEL_LZMA is not set -+# CONFIG_KERNEL_XZ is not set -+CONFIG_KERNEL_LZO=y -+CONFIG_DEFAULT_HOSTNAME="(none)" -+# CONFIG_SWAP is not set -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_FHANDLE is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_AUDIT is not set -+CONFIG_HAVE_GENERIC_HARDIRQS=y -+ -+# -+# IRQ subsystem -+# -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_SHOW=y -+ -+# -+# RCU Subsystem -+# -+CONFIG_TINY_RCU=y -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=16 -+# CONFIG_CGROUPS is not set -+# CONFIG_CHECKPOINT_RESTORE is not set -+# CONFIG_NAMESPACES is not set -+# CONFIG_SCHED_AUTOGROUP is not set -+# CONFIG_SYSFS_DEPRECATED is not set -+# CONFIG_RELAY is not set -+# CONFIG_BLK_DEV_INITRD is not set -+CONFIG_CC_OPTIMIZE_FOR_SIZE=y -+CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y -+CONFIG_PANIC_TIMEOUT=0 -+CONFIG_EXPERT=y -+CONFIG_UID16=y -+# CONFIG_SYSCTL_SYSCALL is not set -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_ALL 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_SIGNALFD=y -+CONFIG_TIMERFD=y -+CONFIG_EVENTFD=y -+# CONFIG_SHMEM is not set -+CONFIG_AIO=y -+CONFIG_EMBEDDED=y -+CONFIG_HAVE_PERF_EVENTS=y -+CONFIG_PERF_USE_VMALLOC=y -+ -+# -+# Kernel Performance Events And Counters -+# -+# CONFIG_PERF_EVENTS is not set -+# CONFIG_PERF_COUNTERS is not set -+# CONFIG_VM_EVENT_COUNTERS is not set -+# CONFIG_SLUB_DEBUG is not set -+CONFIG_COMPAT_BRK=y -+# CONFIG_SLAB is not set -+CONFIG_SLUB=y -+# CONFIG_SLOB is not set -+# CONFIG_PROFILING is not set -+CONFIG_HAVE_OPROFILE=y -+# CONFIG_KPROBES is not set -+CONFIG_JUMP_LABEL=y -+CONFIG_HAVE_KPROBES=y -+CONFIG_HAVE_KRETPROBES=y -+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -+CONFIG_HAVE_CLK=y -+CONFIG_HAVE_DMA_API_DEBUG=y -+CONFIG_HAVE_ARCH_JUMP_LABEL=y -+ -+# -+# GCOV-based kernel profiling -+# -+CONFIG_HAVE_GENERIC_DMA_COHERENT=y -+CONFIG_RT_MUTEXES=y -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_FORCE_LOAD=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODVERSIONS is not set -+# CONFIG_MODULE_SRCVERSION_ALL is not set -+CONFIG_BLOCK=y -+# CONFIG_LBDAF is not set -+# CONFIG_BLK_DEV_BSG is not set -+# CONFIG_BLK_DEV_BSGLIB is not set -+# CONFIG_BLK_DEV_INTEGRITY is not set -+ -+# -+# Partition Types -+# -+# CONFIG_PARTITION_ADVANCED is not set -+CONFIG_MSDOS_PARTITION=y -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+# CONFIG_IOSCHED_DEADLINE is not set -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_CFQ=y -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="cfq" -+# CONFIG_INLINE_SPIN_TRYLOCK is not set -+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK is not set -+# CONFIG_INLINE_SPIN_LOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_READ_TRYLOCK is not set -+# CONFIG_INLINE_READ_LOCK is not set -+# CONFIG_INLINE_READ_LOCK_BH is not set -+# CONFIG_INLINE_READ_LOCK_IRQ is not set -+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -+CONFIG_INLINE_READ_UNLOCK=y -+# CONFIG_INLINE_READ_UNLOCK_BH is not set -+CONFIG_INLINE_READ_UNLOCK_IRQ=y -+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_WRITE_TRYLOCK is not set -+# CONFIG_INLINE_WRITE_LOCK is not set -+# CONFIG_INLINE_WRITE_LOCK_BH is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -+CONFIG_INLINE_WRITE_UNLOCK=y -+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -+# CONFIG_MUTEX_SPIN_ON_OWNER is not set -+CONFIG_FREEZER=y -+ -+# -+# System Type -+# -+CONFIG_MMU=y -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_REALVIEW is not set -+# CONFIG_ARCH_VERSATILE is not set -+# CONFIG_ARCH_VEXPRESS is not set -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_BCMRING is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_CLPS711X is not set -+# CONFIG_ARCH_CNS3XXX is not set -+# CONFIG_ARCH_GEMINI is not set -+# CONFIG_ARCH_PRIMA2 is not set -+# CONFIG_ARCH_EBSA110 is not set -+# CONFIG_ARCH_EP93XX is not set -+# CONFIG_ARCH_FOOTBRIDGE is not set -+# CONFIG_ARCH_MXC is not set -+# CONFIG_ARCH_MXS is not set -+# CONFIG_ARCH_NETX is not set -+# CONFIG_ARCH_H720X is not set -+# CONFIG_ARCH_IOP13XX is not set -+# CONFIG_ARCH_IOP32X is not set -+# CONFIG_ARCH_IOP33X is not set -+# CONFIG_ARCH_IXP23XX is not set -+# CONFIG_ARCH_IXP2000 is not set -+# CONFIG_ARCH_IXP4XX is not set -+# CONFIG_ARCH_DOVE is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_MV78XX0 is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_ARCH_MMP is not set -+# CONFIG_ARCH_KS8695 is not set -+# CONFIG_ARCH_W90X900 is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_PICOXCELL is not set -+# CONFIG_ARCH_PNX4008 is not set -+# CONFIG_ARCH_PXA is not set -+# CONFIG_ARCH_MSM is not set -+# CONFIG_ARCH_SHMOBILE is not set -+# CONFIG_ARCH_RPC is not set -+# CONFIG_ARCH_SA1100 is not set -+# CONFIG_ARCH_S3C24XX is not set -+# CONFIG_ARCH_S3C64XX is not set -+# CONFIG_ARCH_S5P64X0 is not set -+# CONFIG_ARCH_S5PC100 is not set -+# CONFIG_ARCH_S5PV210 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_SHARK is not set -+# CONFIG_ARCH_U300 is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_NOMADIK is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_OMAP is not set -+# CONFIG_PLAT_SPEAR is not set -+# CONFIG_ARCH_VT8500 is not set -+# CONFIG_ARCH_ZYNQ is not set -+CONFIG_ARCH_AK39=y -+# CONFIG_GPIO_PCA953X is not set -+# CONFIG_KEYBOARD_GPIO_POLLED is not set -+ -+# -+# System MMU -+# -+CONFIG_CPU_AK3918=y -+# CONFIG_ARCH_SDK3910 is not set -+# CONFIG_ARCH_AIMER39_AK3916 is not set -+CONFIG_ARCH_AIMER39_AK3918=y -+CONFIG_ASIC_FREQ_VALUE=90000000 -+ -+# -+# Power management -+# -+# CONFIG_AK39_PM is not set -+# CONFIG_AK39_PWM_TIMER is not set -+CONFIG_PLAT_ANYKA=y -+ -+# -+# Processor Type -+# -+CONFIG_CPU_ARM926T=y -+CONFIG_CPU_32v5=y -+CONFIG_CPU_ABRT_EV5TJ=y -+CONFIG_CPU_PABRT_LEGACY=y -+CONFIG_CPU_CACHE_VIVT=y -+CONFIG_CPU_COPY_V4WB=y -+CONFIG_CPU_TLB_V4WBI=y -+CONFIG_CPU_CP15=y -+CONFIG_CPU_CP15_MMU=y -+CONFIG_CPU_USE_DOMAINS=y -+ -+# -+# Processor Features -+# -+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -+# CONFIG_ARM_THUMB is not set -+# CONFIG_CPU_ICACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set -+# CONFIG_CACHE_L2X0 is not set -+CONFIG_ARM_L1_CACHE_SHIFT=5 -+CONFIG_ARM_NR_BANKS=8 -+# CONFIG_FIQ_DEBUGGER is not set -+ -+# -+# Bus support -+# -+# CONFIG_PCI_SYSCALL is not set -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_PCCARD=y -+CONFIG_PCMCIA=y -+ -+# -+# PC-card bridges -+# -+ -+# -+# Kernel Features -+# -+CONFIG_VMSPLIT_3G=y -+# CONFIG_VMSPLIT_2G is not set -+# CONFIG_VMSPLIT_1G is not set -+CONFIG_PAGE_OFFSET=0xC0000000 -+CONFIG_ARCH_NR_GPIO=0 -+CONFIG_PREEMPT_NONE=y -+# CONFIG_PREEMPT_VOLUNTARY is not set -+# CONFIG_PREEMPT is not set -+CONFIG_HZ=100 -+CONFIG_AEABI=y -+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -+CONFIG_HAVE_ARCH_PFN_VALID=y -+# CONFIG_HIGHMEM is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+CONFIG_HAVE_MEMBLOCK=y -+CONFIG_PAGEFLAGS_EXTENDED=y -+CONFIG_SPLIT_PTLOCK_CPUS=999999 -+# CONFIG_COMPACTION is not set -+# CONFIG_PHYS_ADDR_T_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_KSM is not set -+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -+CONFIG_NEED_PER_CPU_KM=y -+# CONFIG_CLEANCACHE is not set -+CONFIG_FORCE_MAX_ZONEORDER=11 -+CONFIG_ALIGNMENT_TRAP=y -+# CONFIG_SECCOMP is not set -+# CONFIG_DEPRECATED_PARAM_STRUCT is not set -+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -+ -+# -+# Boot options -+# -+# CONFIG_USE_OF is not set -+CONFIG_ZBOOT_ROM_TEXT=0 -+CONFIG_ZBOOT_ROM_BSS=0 -+CONFIG_CMDLINE="root=/dev/mtdblock1 ro init=/sbin/init mem=64M console=ttySAK0,115200" -+CONFIG_CMDLINE_FROM_BOOTLOADER=y -+# CONFIG_CMDLINE_EXTEND is not set -+# CONFIG_CMDLINE_FORCE is not set -+# CONFIG_XIP_KERNEL is not set -+# CONFIG_AUTO_ZRELADDR is not set -+CONFIG_RAM_BASE=0x80000000 -+CONFIG_VIDEO_RESERVED_MEM_SIZE=0x1000000 -+ -+# -+# CPU Power Management -+# -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ is not set -+# CONFIG_CPU_IDLE is not set -+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set -+ -+# -+# Floating point emulation -+# -+ -+# -+# At least one emulation must be selected -+# -+# CONFIG_VFP is not set -+ -+# -+# Userspace binary formats -+# -+CONFIG_BINFMT_ELF=y -+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -+CONFIG_HAVE_AOUT=y -+# CONFIG_BINFMT_AOUT is not set -+# CONFIG_BINFMT_MISC is not set -+ -+# -+# Power management options -+# -+CONFIG_SUSPEND=y -+CONFIG_SUSPEND_FREEZER=y -+CONFIG_HAS_WAKELOCK=y -+CONFIG_WAKELOCK=y -+CONFIG_PM_SLEEP=y -+# CONFIG_PM_AUTOSLEEP is not set -+# CONFIG_PM_WAKELOCKS is not set -+# CONFIG_PM_RUNTIME is not set -+CONFIG_PM=y -+# CONFIG_PM_DEBUG is not set -+# CONFIG_APM_EMULATION is not set -+CONFIG_PM_CLK=y -+CONFIG_CPU_PM=y -+# CONFIG_SUSPEND_TIME is not set -+CONFIG_ARCH_SUSPEND_POSSIBLE=y -+CONFIG_ARM_CPU_SUSPEND=y -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+CONFIG_UNIX=y -+CONFIG_UNIX_DIAG=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+CONFIG_IP_MULTICAST=y -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+CONFIG_IP_PNP_RARP=y -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE_DEMUX is not set -+# CONFIG_IP_MROUTE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+CONFIG_INET_LRO=y -+CONFIG_INET_DIAG=y -+CONFIG_INET_TCP_DIAG=y -+CONFIG_INET_UDP_DIAG=y -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_IPV6 is not set -+CONFIG_ANDROID_PARANOID_NETWORK=y -+CONFIG_NET_ACTIVITY_STATS=y -+# CONFIG_NETWORK_SECMARK is not set -+CONFIG_NETFILTER=y -+# CONFIG_NETFILTER_DEBUG is not set -+CONFIG_NETFILTER_ADVANCED=y -+ -+# -+# Core Netfilter Configuration -+# -+# CONFIG_NETFILTER_NETLINK_ACCT is not set -+# CONFIG_NETFILTER_NETLINK_QUEUE is not set -+# CONFIG_NETFILTER_NETLINK_LOG is not set -+# CONFIG_NF_CONNTRACK is not set -+# CONFIG_NETFILTER_XTABLES is not set -+# CONFIG_IP_VS is not set -+ -+# -+# IP: Netfilter Configuration -+# -+# CONFIG_NF_DEFRAG_IPV4 is not set -+# CONFIG_IP_NF_QUEUE is not set -+# CONFIG_IP_NF_IPTABLES is not set -+# CONFIG_IP_NF_ARPTABLES is not set -+# CONFIG_ATM is not set -+# CONFIG_L2TP 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_PHONET is not set -+# CONFIG_NET_SCHED is not set -+# CONFIG_DCB is not set -+# CONFIG_BATMAN_ADV is not set -+# CONFIG_OPENVSWITCH is not set -+CONFIG_BQL=y -+CONFIG_HAVE_BPF_JIT=y -+# CONFIG_BPF_JIT is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_CAN is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+CONFIG_WIRELESS=y -+CONFIG_WIRELESS_EXT=y -+CONFIG_WEXT_CORE=y -+CONFIG_WEXT_PROC=y -+CONFIG_WEXT_SPY=y -+CONFIG_WEXT_PRIV=y -+CONFIG_CFG80211=y -+# CONFIG_NL80211_TESTMODE is not set -+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -+# CONFIG_CFG80211_REG_DEBUG is not set -+CONFIG_CFG80211_DEFAULT_PS=y -+# CONFIG_CFG80211_INTERNAL_REGDB is not set -+CONFIG_CFG80211_WEXT=y -+CONFIG_WIRELESS_EXT_SYSFS=y -+CONFIG_LIB80211=y -+# CONFIG_LIB80211_DEBUG is not set -+CONFIG_CFG80211_ALLOW_RECONNECT=y -+CONFIG_MAC80211=y -+CONFIG_MAC80211_HAS_RC=y -+# CONFIG_MAC80211_RC_PID is not set -+CONFIG_MAC80211_RC_MINSTREL=y -+CONFIG_MAC80211_RC_MINSTREL_HT=y -+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -+# CONFIG_MAC80211_LEDS is not set -+# CONFIG_MAC80211_DEBUG_MENU is not set -+# CONFIG_WIMAX is not set -+CONFIG_RFKILL=y -+CONFIG_RFKILL_PM=y -+CONFIG_RFKILL_LEDS=y -+# CONFIG_RFKILL_INPUT is not set -+# CONFIG_RFKILL_GPIO is not set -+# CONFIG_NET_9P is not set -+# CONFIG_CAIF is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_DEVTMPFS=y -+CONFIG_DEVTMPFS_MOUNT=y -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+CONFIG_FW_LOADER=y -+CONFIG_FIRMWARE_IN_KERNEL=y -+CONFIG_EXTRA_FIRMWARE="" -+# CONFIG_DEBUG_DRIVER is not set -+# CONFIG_DEBUG_DEVRES is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_GENERIC_CPU_DEVICES is not set -+CONFIG_DMA_SHARED_BUFFER=y -+# CONFIG_SYNC is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_TESTS is not set -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+# CONFIG_MTD_AFS_PARTS is not set -+# CONFIG_MTD_AR7_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SST25L 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_DOCG3 is not set -+CONFIG_MTD_AK_SPIFLASH=y -+# CONFIG_MTD_NAND_IDS is not set -+# CONFIG_MTD_NAND is not set -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# LPDDR flash memory drivers -+# -+# CONFIG_MTD_LPDDR is not set -+# CONFIG_MTD_UBI is not set -+# CONFIG_PARPORT is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+ -+# -+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected -+# -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+# CONFIG_BLK_DEV_XIP is not set -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+# CONFIG_MG_DISK is not set -+ -+# -+# Misc devices -+# -+# CONFIG_SENSORS_LIS3LV02D is not set -+# CONFIG_AD525X_DPOT is not set -+# CONFIG_ATMEL_PWM is not set -+# CONFIG_ENCLOSURE_SERVICES is not set -+# CONFIG_APDS9802ALS is not set -+# CONFIG_ISL29003 is not set -+# CONFIG_ISL29020 is not set -+# CONFIG_SENSORS_TSL2550 is not set -+# CONFIG_SENSORS_BH1780 is not set -+# CONFIG_SENSORS_BH1770 is not set -+# CONFIG_SENSORS_APDS990X is not set -+# CONFIG_HMC6352 is not set -+# CONFIG_SENSORS_AK8975 is not set -+# CONFIG_TI_DAC7512 is not set -+# CONFIG_UID_STAT is not set -+# CONFIG_BMP085 is not set -+# CONFIG_USB_SWITCH_FSA9480 is not set -+# CONFIG_WL127X_RFKILL is not set -+CONFIG_AK_SERIAL_NUMBER=y -+CONFIG_AK_MOTOR=y -+ -+# -+# user space generic gpio controller -+# -+CONFIG_GPIOS_AKCUSTOM=y -+ -+# -+# EEPROM support -+# -+# CONFIG_EEPROM_AT24 is not set -+# CONFIG_EEPROM_AT25 is not set -+# CONFIG_EEPROM_LEGACY is not set -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_EEPROM_93XX46 is not set -+ -+# -+# Texas Instruments shared transport line discipline -+# -+# CONFIG_TI_ST is not set -+# CONFIG_SENSORS_LIS3_SPI is not set -+# CONFIG_SENSORS_LIS3_I2C is not set -+ -+# -+# Altera FPGA firmware download module -+# -+# CONFIG_ALTERA_STAPL is not set -+CONFIG_HAVE_IDE=y -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+CONFIG_SCSI_MOD=y -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_SCSI_PROC_FS is not set -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+# CONFIG_SCSI_WAIT_SCAN is not set -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+# CONFIG_SCSI_LOWLEVEL is not set -+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set -+# CONFIG_SCSI_DH is not set -+# CONFIG_SCSI_OSD_INITIATOR is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_TARGET_CORE is not set -+CONFIG_NETDEVICES=y -+CONFIG_NET_CORE=y -+# CONFIG_BONDING is not set -+# CONFIG_DUMMY is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_MII is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+# CONFIG_ARCNET is not set -+ -+# -+# CAIF transport drivers -+# -+CONFIG_ETHERNET=y -+# CONFIG_NET_VENDOR_3COM is not set -+# CONFIG_NET_VENDOR_AMD is not set -+# CONFIG_NET_VENDOR_BROADCOM is not set -+# CONFIG_NET_CALXEDA_XGMAC is not set -+# CONFIG_NET_VENDOR_CHELSIO is not set -+# CONFIG_NET_VENDOR_CIRRUS is not set -+# CONFIG_DM9000 is not set -+# CONFIG_DNET is not set -+# CONFIG_NET_VENDOR_FARADAY is not set -+# CONFIG_NET_VENDOR_FUJITSU is not set -+# CONFIG_NET_VENDOR_INTEL is not set -+# CONFIG_NET_VENDOR_MARVELL is not set -+# CONFIG_NET_VENDOR_MICREL is not set -+# CONFIG_NET_VENDOR_NATSEMI is not set -+# CONFIG_ETHOC is not set -+# CONFIG_NET_VENDOR_SMSC is not set -+# CONFIG_NET_VENDOR_STMICRO is not set -+# CONFIG_NET_VENDOR_XIRCOM is not set -+CONFIG_AK_ETHERNET=y -+# CONFIG_PHYLIB is not set -+# CONFIG_MICREL_KS8995MA is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_TR is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_USB_HSO is not set -+# CONFIG_USB_IPHETH is not set -+CONFIG_WLAN=y -+CONFIG_PCMCIA_RAYCS=y -+# CONFIG_LIBERTAS_THINFIRM is not set -+# CONFIG_ATMEL is not set -+# CONFIG_AT76C50X_USB is not set -+# CONFIG_AIRO_CS is not set -+# CONFIG_USB_ZD1201 is not set -+# CONFIG_RTL8187 is not set -+# CONFIG_MAC80211_HWSIM is not set -+# CONFIG_WIFI_CONTROL_FUNC is not set -+# CONFIG_ATH_COMMON is not set -+# CONFIG_B43 is not set -+# CONFIG_B43LEGACY is not set -+# CONFIG_BCMDHD is not set -+# CONFIG_BRCMFMAC is not set -+# CONFIG_HOSTAP is not set -+# CONFIG_LIBERTAS is not set -+# CONFIG_HERMES is not set -+# CONFIG_RT2X00 is not set -+# CONFIG_MWIFIEX is not set -+ -+# -+# Enable WiMAX (Networking options) to see the WiMAX drivers -+# -+# CONFIG_WAN is not set -+# CONFIG_ISDN is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+# CONFIG_INPUT_SPARSEKMAP is not set -+ -+# -+# Userland interfaces -+# -+# CONFIG_INPUT_MOUSEDEV is not set -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+# CONFIG_INPUT_KEYRESET is not set -+ -+# -+# Input Device Drivers -+# -+CONFIG_INPUT_KEYBOARD=y -+# CONFIG_KEYBOARD_ADP5588 is not set -+# CONFIG_KEYBOARD_ADP5589 is not set -+# CONFIG_KEYBOARD_ATKBD is not set -+# CONFIG_KEYBOARD_QT1070 is not set -+# CONFIG_KEYBOARD_LKKBD is not set -+# CONFIG_KEYBOARD_GPIO is not set -+# CONFIG_KEYBOARD_TCA6416 is not set -+# CONFIG_KEYBOARD_TCA8418 is not set -+# CONFIG_KEYBOARD_MATRIX is not set -+# CONFIG_KEYBOARD_LM8323 is not set -+# CONFIG_KEYBOARD_MAX7359 is not set -+# CONFIG_KEYBOARD_MCS is not set -+# CONFIG_KEYBOARD_MPR121 is not set -+# CONFIG_KEYBOARD_NEWTON is not set -+# CONFIG_KEYBOARD_OPENCORES is not set -+# CONFIG_KEYBOARD_SAMSUNG is not set -+# CONFIG_KEYBOARD_STOWAWAY is not set -+# CONFIG_KEYBOARD_SUNKBD is not set -+# CONFIG_KEYBOARD_OMAP4 is not set -+# CONFIG_KEYBOARD_XTKBD is not set -+CONFIG_KEYBOARD_AKKEY=y -+# CONFIG_KEYBOARD_AK_KEYPAD is not set -+# CONFIG_KEYBOARD_ADKEY is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+# CONFIG_SERIO is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+# CONFIG_VT is not set -+# CONFIG_UNIX98_PTYS is not set -+# CONFIG_LEGACY_PTYS is not set -+# CONFIG_SERIAL_NONSTANDARD is not set -+# CONFIG_TRACE_SINK is not set -+CONFIG_DEVMEM=y -+# CONFIG_DEVKMEM is not set -+ -+# -+# Serial drivers -+# -+# CONFIG_SERIAL_8250 is not set -+ -+# -+# Non-8250 serial port support -+# -+# CONFIG_SERIAL_MAX3100 is not set -+# CONFIG_SERIAL_MAX3107 is not set -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_SERIAL_TIMBERDALE is not set -+# CONFIG_SERIAL_ALTERA_JTAGUART is not set -+# CONFIG_SERIAL_ALTERA_UART is not set -+# CONFIG_SERIAL_XILINX_PS_UART is not set -+CONFIG_SERIAL_AK39_UART=y -+CONFIG_SERIAL_AK39_CONSOLE=y -+# CONFIG_SERIAL_GPIO_UART is not set -+CONFIG_TTY_PRINTK=y -+# CONFIG_HVC_DCC is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_R3964 is not set -+ -+# -+# PCMCIA character devices -+# -+# CONFIG_SYNCLINK_CS is not set -+# CONFIG_CARDMAN_4000 is not set -+# CONFIG_CARDMAN_4040 is not set -+# CONFIG_IPWIRELESS is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+# CONFIG_DCC_TTY is not set -+# CONFIG_RAMOOPS is not set -+CONFIG_I2C=y -+CONFIG_I2C_BOARDINFO=y -+CONFIG_I2C_COMPAT=y -+# CONFIG_I2C_CHARDEV is not set -+# CONFIG_I2C_HELPER_AUTO is not set -+CONFIG_I2C_SMBUS=y -+ -+# -+# I2C Algorithms -+# -+CONFIG_I2C_ALGOBIT=y -+# CONFIG_I2C_ALGOPCF is not set -+# CONFIG_I2C_ALGOPCA is not set -+ -+# -+# I2C Hardware Bus support -+# -+ -+# -+# I2C system bus drivers (mostly embedded / system-on-chip) -+# -+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set -+# CONFIG_I2C_GPIO is not set -+# CONFIG_I2C_PCA_PLATFORM is not set -+# CONFIG_I2C_PXA_PCI is not set -+# CONFIG_I2C_SIMTEC is not set -+CONFIG_I2C_ANYKA=y -+CONFIG_I2C_AK39_HW=y -+# CONFIG_I2C_GPIO_SOFT is not set -+ -+# -+# External I2C/SMBus adapter drivers -+# -+# CONFIG_I2C_DIOLAN_U2C is not set -+# CONFIG_I2C_PARPORT_LIGHT is not set -+# CONFIG_I2C_TINY_USB is not set -+ -+# -+# Other I2C/SMBus bus drivers -+# -+# CONFIG_I2C_DEBUG_CORE is not set -+# CONFIG_I2C_DEBUG_ALGO is not set -+# CONFIG_I2C_DEBUG_BUS is not set -+CONFIG_SPI=y -+# CONFIG_SPI_DEBUG is not set -+CONFIG_SPI_MASTER=y -+ -+# -+# SPI Master Controller Drivers -+# -+# CONFIG_SPI_ALTERA is not set -+CONFIG_SPI_BITBANG=y -+# CONFIG_SPI_GPIO is not set -+# CONFIG_SPI_OC_TINY is not set -+# CONFIG_SPI_PXA2XX_PCI is not set -+CONFIG_SPI_ANYKA=y -+# CONFIG_SPI_DESIGNWARE is not set -+ -+# -+# SPI Protocol Masters -+# -+# CONFIG_SPI_TLE62X0 is not set -+# CONFIG_HSI is not set -+ -+# -+# PPS support -+# -+ -+# -+# PPS generators support -+# -+ -+# -+# PTP clock support -+# -+ -+# -+# Enable Device Drivers -> PPS to see the PTP clock options. -+# -+CONFIG_ARCH_REQUIRE_GPIOLIB=y -+CONFIG_GPIOLIB=y -+# CONFIG_DEBUG_GPIO is not set -+ -+# -+# Memory mapped GPIO drivers: -+# -+# CONFIG_GPIO_GENERIC_PLATFORM is not set -+ -+# -+# I2C GPIO expanders: -+# -+# CONFIG_GPIO_MAX7300 is not set -+# CONFIG_GPIO_MAX732X is not set -+# CONFIG_GPIO_PCF857X is not set -+# CONFIG_GPIO_SX150X is not set -+# CONFIG_GPIO_ADP5588 is not set -+ -+# -+# PCI GPIO expanders: -+# -+ -+# -+# SPI GPIO expanders: -+# -+# CONFIG_GPIO_MAX7301 is not set -+# CONFIG_GPIO_MCP23S08 is not set -+# CONFIG_GPIO_MC33880 is not set -+# CONFIG_GPIO_74X164 is not set -+ -+# -+# AC97 GPIO expanders: -+# -+ -+# -+# MODULbus GPIO expanders: -+# -+# CONFIG_W1 is not set -+CONFIG_POWER_SUPPLY=y -+# CONFIG_POWER_SUPPLY_DEBUG is not set -+# CONFIG_PDA_POWER is not set -+# CONFIG_TEST_POWER is not set -+# CONFIG_BATTERY_DS2780 is not set -+# CONFIG_BATTERY_DS2781 is not set -+# CONFIG_BATTERY_DS2782 is not set -+# CONFIG_BATTERY_SBS is not set -+# CONFIG_BATTERY_BQ27x00 is not set -+# CONFIG_BATTERY_MAX17040 is not set -+# CONFIG_BATTERY_MAX17042 is not set -+# CONFIG_BATTERY_ANDROID is not set -+# CONFIG_CHARGER_MAX8903 is not set -+# CONFIG_CHARGER_LP8727 is not set -+# CONFIG_CHARGER_GPIO is not set -+# CONFIG_CHARGER_SMB347 is not set -+# CONFIG_BATTERY_AK is not set -+# CONFIG_HWMON is not set -+# CONFIG_THERMAL is not set -+CONFIG_WATCHDOG=y -+CONFIG_WATCHDOG_CORE=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+# CONFIG_SOFT_WATCHDOG is not set -+# CONFIG_DW_WATCHDOG is not set -+# CONFIG_MAX63XX_WATCHDOG is not set -+CONFIG_AK39_WATCHDOG=y -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+CONFIG_SSB_POSSIBLE=y -+ -+# -+# Sonics Silicon Backplane -+# -+# CONFIG_SSB is not set -+CONFIG_BCMA_POSSIBLE=y -+ -+# -+# Broadcom specific AMBA -+# -+# CONFIG_BCMA is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_CORE is not set -+# CONFIG_MFD_88PM860X is not set -+# CONFIG_MFD_SM501 is not set -+# CONFIG_MFD_ASIC3 is not set -+# CONFIG_HTC_EGPIO is not set -+# CONFIG_HTC_PASIC3 is not set -+# CONFIG_HTC_I2CPLD is not set -+# CONFIG_TPS6105X is not set -+# CONFIG_TPS65010 is not set -+# CONFIG_TPS6507X is not set -+# CONFIG_MFD_TPS65217 is not set -+# CONFIG_MFD_TPS6586X is not set -+# CONFIG_MFD_TPS65910 is not set -+# CONFIG_MFD_TPS65912_I2C is not set -+# CONFIG_MFD_TPS65912_SPI is not set -+# CONFIG_TWL4030_CORE is not set -+# CONFIG_TWL6040_CORE is not set -+# CONFIG_MFD_STMPE is not set -+# CONFIG_MFD_TC3589X is not set -+# CONFIG_MFD_TMIO is not set -+# CONFIG_MFD_T7L66XB is not set -+# CONFIG_MFD_TC6387XB is not set -+# CONFIG_MFD_TC6393XB is not set -+# CONFIG_PMIC_DA903X is not set -+# CONFIG_MFD_DA9052_SPI is not set -+# CONFIG_MFD_DA9052_I2C is not set -+# CONFIG_PMIC_ADP5520 is not set -+# CONFIG_MFD_MAX8925 is not set -+# CONFIG_MFD_MAX8997 is not set -+# CONFIG_MFD_MAX8998 is not set -+# CONFIG_MFD_S5M_CORE is not set -+# CONFIG_MFD_WM8400 is not set -+# CONFIG_MFD_WM831X_I2C is not set -+# CONFIG_MFD_WM831X_SPI is not set -+# CONFIG_MFD_WM8350_I2C is not set -+# CONFIG_MFD_WM8994 is not set -+# CONFIG_MFD_PCF50633 is not set -+# CONFIG_MFD_MC13XXX is not set -+# CONFIG_ABX500_CORE is not set -+# CONFIG_EZX_PCAP is not set -+# CONFIG_MFD_WL1273_CORE is not set -+# CONFIG_MFD_TPS65090 is not set -+# CONFIG_MFD_AAT2870_CORE is not set -+# CONFIG_MFD_RC5T583 is not set -+# CONFIG_REGULATOR is not set -+CONFIG_MEDIA_SUPPORT=y -+ -+# -+# Multimedia core support -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L2_COMMON=y -+# CONFIG_DVB_CORE is not set -+CONFIG_VIDEO_MEDIA=y -+ -+# -+# Multimedia drivers -+# -+# CONFIG_RC_CORE is not set -+# CONFIG_MEDIA_ATTACH is not set -+CONFIG_MEDIA_TUNER=y -+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set -+CONFIG_MEDIA_TUNER_SIMPLE=y -+CONFIG_MEDIA_TUNER_TDA8290=y -+CONFIG_MEDIA_TUNER_TDA827X=y -+CONFIG_MEDIA_TUNER_TDA18271=y -+CONFIG_MEDIA_TUNER_TDA9887=y -+CONFIG_MEDIA_TUNER_TEA5767=y -+CONFIG_MEDIA_TUNER_MT20XX=y -+CONFIG_MEDIA_TUNER_XC2028=y -+CONFIG_MEDIA_TUNER_XC5000=y -+CONFIG_MEDIA_TUNER_XC4000=y -+CONFIG_MEDIA_TUNER_MC44S803=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEOBUF_GEN=y -+CONFIG_VIDEOBUF_DMA_CONTIG=y -+CONFIG_VIDEOBUF2_CORE=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set -+ -+# -+# Encoders, decoders, sensors and other helper chips -+# -+ -+# -+# Audio decoders, processors and mixers -+# -+# CONFIG_VIDEO_TVAUDIO is not set -+# CONFIG_VIDEO_TDA7432 is not set -+# CONFIG_VIDEO_TDA9840 is not set -+# CONFIG_VIDEO_TEA6415C is not set -+# CONFIG_VIDEO_TEA6420 is not set -+# CONFIG_VIDEO_MSP3400 is not set -+# CONFIG_VIDEO_CS5345 is not set -+# CONFIG_VIDEO_CS53L32A is not set -+# CONFIG_VIDEO_WM8775 is not set -+# CONFIG_VIDEO_WM8739 is not set -+# CONFIG_VIDEO_VP27SMPX is not set -+ -+# -+# RDS decoders -+# -+# CONFIG_VIDEO_SAA6588 is not set -+ -+# -+# Video decoders -+# -+# CONFIG_VIDEO_ADV7180 is not set -+# CONFIG_VIDEO_ADV7183 is not set -+# CONFIG_VIDEO_BT819 is not set -+# CONFIG_VIDEO_BT856 is not set -+# CONFIG_VIDEO_BT866 is not set -+# CONFIG_VIDEO_KS0127 is not set -+# CONFIG_VIDEO_SAA7110 is not set -+# CONFIG_VIDEO_SAA711X is not set -+# CONFIG_VIDEO_SAA7191 is not set -+# CONFIG_VIDEO_TVP514X is not set -+# CONFIG_VIDEO_TVP5150 is not set -+# CONFIG_VIDEO_TVP7002 is not set -+# CONFIG_VIDEO_VPX3220 is not set -+ -+# -+# Video and audio decoders -+# -+# CONFIG_VIDEO_SAA717X is not set -+# CONFIG_VIDEO_CX25840 is not set -+ -+# -+# MPEG video encoders -+# -+# CONFIG_VIDEO_CX2341X is not set -+ -+# -+# Video encoders -+# -+# CONFIG_VIDEO_SAA7127 is not set -+# CONFIG_VIDEO_SAA7185 is not set -+# CONFIG_VIDEO_ADV7170 is not set -+# CONFIG_VIDEO_ADV7175 is not set -+# CONFIG_VIDEO_ADV7343 is not set -+# CONFIG_VIDEO_AK881X is not set -+ -+# -+# Camera sensor devices -+# -+# CONFIG_VIDEO_OV7670 is not set -+# CONFIG_VIDEO_VS6624 is not set -+# CONFIG_VIDEO_MT9V011 is not set -+# CONFIG_VIDEO_TCM825X is not set -+# CONFIG_VIDEO_SR030PC30 is not set -+ -+# -+# Flash devices -+# -+ -+# -+# Video improvement chips -+# -+# CONFIG_VIDEO_UPD64031A is not set -+# CONFIG_VIDEO_UPD64083 is not set -+ -+# -+# Miscelaneous helper chips -+# -+# CONFIG_VIDEO_THS7303 is not set -+# CONFIG_VIDEO_M52790 is not set -+# CONFIG_V4L_USB_DRIVERS is not set -+CONFIG_V4L_PLATFORM_DRIVERS=y -+CONFIG_SOC_CAMERA=y -+# CONFIG_SOC_CAMERA_IMX074 is not set -+# CONFIG_SOC_CAMERA_MT9M001 is not set -+# CONFIG_SOC_CAMERA_MT9M111 is not set -+# CONFIG_SOC_CAMERA_MT9T031 is not set -+# CONFIG_SOC_CAMERA_MT9T112 is not set -+# CONFIG_SOC_CAMERA_MT9V022 is not set -+# CONFIG_SOC_CAMERA_RJ54N1 is not set -+# CONFIG_SOC_CAMERA_TW9910 is not set -+# CONFIG_SOC_CAMERA_PLATFORM is not set -+# CONFIG_SOC_CAMERA_OV2640 is not set -+# CONFIG_SOC_CAMERA_OV5642 is not set -+# CONFIG_SOC_CAMERA_OV6650 is not set -+# CONFIG_SOC_CAMERA_OV772X is not set -+# CONFIG_SOC_CAMERA_OV9640 is not set -+# CONFIG_SOC_CAMERA_OV9740 is not set -+CONFIG_LINUX_AKSENSOR=y -+CONFIG_SENSOR_GC0308=y -+CONFIG_SENSOR_OV2643=y -+CONFIG_SENSOR_OV7725=y -+CONFIG_SENSOR_HM1375=y -+CONFIG_SENSOR_OV9712=y -+CONFIG_SENSOR_OV2710=y -+# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set -+# CONFIG_VIDEO_SH_MOBILE_CEU is not set -+CONFIG_VIDEO_AK=y -+# CONFIG_V4L_MEM2MEM_DRIVERS is not set -+# CONFIG_RADIO_ADAPTERS is not set -+ -+# -+# Graphics support -+# -+# CONFIG_DRM is not set -+CONFIG_ION=y -+CONFIG_ION_AK=y -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_EXYNOS_VIDEO is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+CONFIG_SOUND=y -+# CONFIG_SOUND_OSS_CORE is not set -+CONFIG_SND=y -+CONFIG_SND_TIMER=y -+CONFIG_SND_PCM=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 -+# CONFIG_SND_RAWMIDI_SEQ is not set -+# CONFIG_SND_OPL3_LIB_SEQ is not set -+# CONFIG_SND_OPL4_LIB_SEQ is not set -+# CONFIG_SND_SBAWE_SEQ is not set -+# CONFIG_SND_EMU10K1_SEQ is not set -+# CONFIG_SND_DRIVERS is not set -+CONFIG_SND_ARM=y -+CONFIG_SND_AK_PCM=y -+CONFIG_CODEC_AK39=y -+CONFIG_SPKHP_SWITCH_AUTO=y -+# CONFIG_SPKHP_SWITCH_MIXER is not set -+# CONFIG_SPKHP_SWITCH_UEVENT is not set -+CONFIG_SUPPORT_AEC=y -+# CONFIG_SND_SPI is not set -+# CONFIG_SND_USB is not set -+CONFIG_SND_PCMCIA=y -+# CONFIG_SND_VXPOCKET is not set -+# CONFIG_SND_PDAUDIOCF is not set -+# CONFIG_SND_SOC is not set -+# CONFIG_SOUND_PRIME is not set -+# CONFIG_HID_SUPPORT is not set -+# CONFIG_USB_ARCH_HAS_OHCI is not set -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB_ARCH_HAS_XHCI is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_COMMON=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+# CONFIG_USB_DEVICE_CLASS is not set -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_OTG_WHITELIST is not set -+# CONFIG_USB_OTG_BLACKLIST_HUB is not set -+# CONFIG_USB_DWC3 is not set -+# CONFIG_USB_MON is not set -+# CONFIG_USB_WUSB_CBAF is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_C67X00_HCD is not set -+# CONFIG_USB_OXU210HP_HCD is not set -+# CONFIG_USB_ISP116X_HCD is not set -+# CONFIG_USB_ISP1362_HCD is not set -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+CONFIG_USB_ANYKA_HCD=y -+CONFIG_USB_AKOTG_HS_HCD=m -+# CONFIG_USB_AKOTG_DMA is not set -+# CONFIG_USB_MUSB_HDRC is not set -+# CONFIG_USB_RENESAS_USBHS is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+# CONFIG_USB_WDM is not set -+# CONFIG_USB_TMC is not set -+ -+# -+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -+# -+ -+# -+# also be needed; see USB_STORAGE Help for more info -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_REALTEK is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_ONETOUCH is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set -+# CONFIG_USB_STORAGE_ENE_UB6250 is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+ -+# -+# USB port drivers -+# -+# 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_SEVSEG 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_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+# CONFIG_USB_TEST is not set -+# CONFIG_USB_ISIGHTFW is not set -+# CONFIG_USB_YUREX is not set -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_VBUS_DRAW=500 -+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -+# CONFIG_USB_FUSB300 is not set -+# CONFIG_USB_R8A66597 is not set -+# CONFIG_USB_MV_UDC is not set -+# CONFIG_USB_GADGET_AKUDC_PRODUCER is not set -+CONFIG_USB_GADGET_AKUDC=y -+CONFIG_USB_AKUDC=m -+# CONFIG_USB_AKUDC_DEBUG_FS is not set -+# CONFIG_USB_M66592 is not set -+# CONFIG_USB_NET2272 is not set -+# CONFIG_USB_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_AUDIO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_G_NCM is not set -+# CONFIG_USB_FILE_STORAGE is not set -+CONFIG_USB_MASS_STORAGE=m -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_G_PRINTER is not set -+# CONFIG_USB_CDC_COMPOSITE is not set -+# CONFIG_USB_G_ACM_MS is not set -+# CONFIG_USB_G_MULTI is not set -+# CONFIG_USB_G_HID is not set -+# CONFIG_USB_G_DBGP is not set -+# CONFIG_USB_G_WEBCAM is not set -+ -+# -+# OTG and related infrastructure -+# -+# CONFIG_USB_OTG_WAKELOCK is not set -+# CONFIG_USB_GPIO_VBUS is not set -+# CONFIG_USB_ULPI is not set -+# CONFIG_NOP_USB_XCEIV is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD/SDIO Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_MINORS=8 -+# CONFIG_MMC_BLOCK_BOUNCE is not set -+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set -+# CONFIG_SDIO_UART is not set -+# CONFIG_MMC_TEST is not set -+# CONFIG_SDIO_WIFI is not set -+ -+# -+# MMC/SD/SDIO Host Controller Drivers -+# -+# CONFIG_MMC_SDHCI is not set -+# CONFIG_MMC_SDHCI_PXAV3 is not set -+# CONFIG_MMC_SDHCI_PXAV2 is not set -+# CONFIG_MMC_SPI is not set -+# CONFIG_MMC_DW is not set -+# CONFIG_MMC_VUB300 is not set -+# CONFIG_MMC_USHC is not set -+CONFIG_MMC_ANYKA=y -+# CONFIG_MEMSTICK is not set -+CONFIG_NEW_LEDS=y -+CONFIG_LEDS_CLASS=y -+ -+# -+# LED drivers -+# -+# CONFIG_LEDS_LM3530 is not set -+# CONFIG_LEDS_GPIO is not set -+# CONFIG_LEDS_LP3944 is not set -+# CONFIG_LEDS_LP5521 is not set -+# CONFIG_LEDS_LP5523 is not set -+# CONFIG_LEDS_PCA955X is not set -+# CONFIG_LEDS_PCA9633 is not set -+# CONFIG_LEDS_DAC124S085 is not set -+# CONFIG_LEDS_BD2802 is not set -+CONFIG_LEDS_AK39=y -+# CONFIG_LEDS_LT3593 is not set -+# CONFIG_LEDS_RENESAS_TPU is not set -+# CONFIG_LEDS_TCA6507 is not set -+# CONFIG_LEDS_OT200 is not set -+CONFIG_LEDS_TRIGGERS=y -+ -+# -+# LED Triggers -+# -+CONFIG_LEDS_TRIGGER_TIMER=y -+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set -+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set -+# CONFIG_LEDS_TRIGGER_GPIO is not set -+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set -+ -+# -+# iptables trigger is under Netfilter config (LED target) -+# -+# CONFIG_SWITCH is not set -+# CONFIG_ACCESSIBILITY is not set -+CONFIG_RTC_LIB=y -+CONFIG_RTC_CLASS=y -+CONFIG_RTC_HCTOSYS=y -+CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -+# CONFIG_RTC_DEBUG is not set -+ -+# -+# RTC interfaces -+# -+CONFIG_RTC_INTF_SYSFS=y -+CONFIG_RTC_INTF_PROC=y -+CONFIG_RTC_INTF_DEV=y -+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -+# CONFIG_RTC_DRV_TEST is not set -+ -+# -+# I2C RTC drivers -+# -+# CONFIG_RTC_DRV_DS1307 is not set -+# CONFIG_RTC_DRV_DS1374 is not set -+# CONFIG_RTC_DRV_DS1672 is not set -+# CONFIG_RTC_DRV_DS3232 is not set -+# CONFIG_RTC_DRV_MAX6900 is not set -+# CONFIG_RTC_DRV_RS5C372 is not set -+# CONFIG_RTC_DRV_ISL1208 is not set -+# CONFIG_RTC_DRV_ISL12022 is not set -+# CONFIG_RTC_DRV_X1205 is not set -+# CONFIG_RTC_DRV_PCF8563 is not set -+# CONFIG_RTC_DRV_PCF8583 is not set -+# CONFIG_RTC_DRV_M41T80 is not set -+# CONFIG_RTC_DRV_BQ32K is not set -+# CONFIG_RTC_DRV_S35390A is not set -+# CONFIG_RTC_DRV_FM3130 is not set -+# CONFIG_RTC_DRV_RX8581 is not set -+# CONFIG_RTC_DRV_RX8025 is not set -+# CONFIG_RTC_DRV_EM3027 is not set -+# CONFIG_RTC_DRV_RV3029C2 is not set -+ -+# -+# SPI RTC drivers -+# -+# CONFIG_RTC_DRV_M41T93 is not set -+# CONFIG_RTC_DRV_M41T94 is not set -+# CONFIG_RTC_DRV_DS1305 is not set -+# CONFIG_RTC_DRV_DS1390 is not set -+# CONFIG_RTC_DRV_MAX6902 is not set -+# CONFIG_RTC_DRV_R9701 is not set -+# CONFIG_RTC_DRV_RS5C348 is not set -+# CONFIG_RTC_DRV_DS3234 is not set -+# CONFIG_RTC_DRV_PCF2123 is not set -+ -+# -+# Platform RTC drivers -+# -+# CONFIG_RTC_DRV_CMOS is not set -+# CONFIG_RTC_DRV_DS1286 is not set -+# CONFIG_RTC_DRV_DS1511 is not set -+# CONFIG_RTC_DRV_DS1553 is not set -+# CONFIG_RTC_DRV_DS1742 is not set -+# CONFIG_RTC_DRV_STK17TA8 is not set -+# CONFIG_RTC_DRV_M48T86 is not set -+# CONFIG_RTC_DRV_M48T35 is not set -+# CONFIG_RTC_DRV_M48T59 is not set -+# CONFIG_RTC_DRV_MSM6242 is not set -+# CONFIG_RTC_DRV_BQ4802 is not set -+# CONFIG_RTC_DRV_RP5C01 is not set -+# CONFIG_RTC_DRV_V3020 is not set -+ -+# -+# on-CPU RTC drivers -+# -+CONFIG_RTC_DRV_AK=y -+# CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set -+CONFIG_UIO=y -+# CONFIG_UIO_PDRV is not set -+# CONFIG_UIO_PDRV_GENIRQ is not set -+CONFIG_UIO_VCODEC=y -+ -+# -+# Virtio drivers -+# -+# CONFIG_VIRTIO_BALLOON is not set -+ -+# -+# Microsoft Hyper-V guest support -+# -+# CONFIG_STAGING is not set -+CONFIG_CLKDEV_LOOKUP=y -+ -+# -+# Hardware Spinlock drivers -+# -+# CONFIG_IOMMU_SUPPORT is not set -+ -+# -+# Remoteproc drivers (EXPERIMENTAL) -+# -+ -+# -+# Rpmsg drivers (EXPERIMENTAL) -+# -+# CONFIG_VIRT_DRIVERS is not set -+# CONFIG_PM_DEVFREQ is not set -+ -+# -+# File systems -+# -+# CONFIG_EXT2_FS is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4_FS is not set -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_FS_POSIX_ACL is not set -+CONFIG_FILE_LOCKING=y -+CONFIG_FSNOTIFY=y -+CONFIG_DNOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_FANOTIFY is not set -+# CONFIG_QUOTA is not set -+# CONFIG_QUOTACTL is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_PROC_PAGE_MONITOR=y -+CONFIG_SYSFS=y -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+CONFIG_MISC_FILESYSTEMS=y -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_YAFFS_FS is not set -+CONFIG_JFFS2_FS=y -+CONFIG_JFFS2_FS_DEBUG=0 -+# CONFIG_JFFS2_FS_WRITEBUFFER is not set -+CONFIG_JFFS2_COMPRESSION_OPTIONS=y -+# CONFIG_JFFS2_ZLIB is not set -+# CONFIG_JFFS2_LZO is not set -+# CONFIG_JFFS2_RTIME is not set -+# CONFIG_JFFS2_RUBIN is not set -+CONFIG_JFFS2_CMODE_NONE=y -+# CONFIG_JFFS2_CMODE_PRIORITY is not set -+# CONFIG_JFFS2_CMODE_SIZE is not set -+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set -+# CONFIG_CRAMFS is not set -+CONFIG_SQUASHFS=y -+# CONFIG_SQUASHFS_XATTR is not set -+CONFIG_SQUASHFS_ZLIB=y -+# CONFIG_SQUASHFS_LZO is not set -+# CONFIG_SQUASHFS_XZ is not set -+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set -+# CONFIG_SQUASHFS_EMBEDDED is not set -+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 -+# CONFIG_VXFS_FS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_OMFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_QNX6FS_FS is not set -+# CONFIG_ROMFS_FS is not set -+# CONFIG_PSTORE is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+# CONFIG_NETWORK_FILESYSTEMS is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+# CONFIG_NLS_CODEPAGE_936 is not set -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+# CONFIG_NLS_ASCII is not set -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+ -+# -+# Kernel hacking -+# -+# CONFIG_PRINTK_TIME is not set -+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_FRAME_WARN=1024 -+# CONFIG_MAGIC_SYSRQ is not set -+# CONFIG_STRIP_ASM_SYMS is not set -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_SECTION_MISMATCH is not set -+CONFIG_DEBUG_KERNEL=y -+# CONFIG_DEBUG_SHIRQ is not set -+# CONFIG_LOCKUP_DETECTOR is not set -+# CONFIG_HARDLOCKUP_DETECTOR_NMI is not set -+# CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU is not set -+# CONFIG_HARDLOCKUP_DETECTOR is not set -+# CONFIG_DETECT_HUNG_TASK is not set -+# CONFIG_SCHED_DEBUG is not set -+# CONFIG_SCHEDSTATS is not set -+# CONFIG_TIMER_STATS is not set -+# CONFIG_DEBUG_OBJECTS is not set -+# CONFIG_SLUB_STATS is not set -+# CONFIG_DEBUG_RT_MUTEXES is not set -+# CONFIG_RT_MUTEX_TESTER is not set -+# CONFIG_DEBUG_SPINLOCK is not set -+# CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_SPARSE_RCU_POINTER is not set -+# CONFIG_LOCK_STAT is not set -+# CONFIG_DEBUG_ATOMIC_SLEEP is not set -+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -+# CONFIG_STACKTRACE is not set -+# CONFIG_DEBUG_STACK_USAGE is not set -+# CONFIG_DEBUG_KOBJECT is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_DEBUG_INFO is not set -+# CONFIG_DEBUG_VM is not set -+# CONFIG_DEBUG_WRITECOUNT is not set -+# CONFIG_DEBUG_MEMORY_INIT is not set -+# CONFIG_DEBUG_LIST is not set -+# CONFIG_TEST_LIST_SORT is not set -+# CONFIG_DEBUG_SG is not set -+# CONFIG_DEBUG_NOTIFIERS is not set -+# CONFIG_DEBUG_CREDENTIALS is not set -+CONFIG_FRAME_POINTER=y -+# CONFIG_BOOT_PRINTK_DELAY is not set -+# CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_RCU_TRACE is not set -+# CONFIG_BACKTRACE_SELF_TEST is not set -+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -+# CONFIG_FAULT_INJECTION is not set -+# CONFIG_LATENCYTOP is not set -+# CONFIG_DEBUG_PAGEALLOC is not set -+CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -+CONFIG_HAVE_DYNAMIC_FTRACE=y -+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_HAVE_C_RECORDMCOUNT=y -+CONFIG_TRACING_SUPPORT=y -+# CONFIG_FTRACE is not set -+# CONFIG_DMA_API_DEBUG is not set -+# CONFIG_ATOMIC64_SELFTEST is not set -+# CONFIG_SAMPLES is not set -+CONFIG_HAVE_ARCH_KGDB=y -+# CONFIG_TEST_KSTRTOX is not set -+# CONFIG_STRICT_DEVMEM is not set -+CONFIG_DEBUG_USER=y -+# CONFIG_DEBUG_RODATA is not set -+# CONFIG_DEBUG_LL is not set -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY_DMESG_RESTRICT is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITYFS is not set -+CONFIG_DEFAULT_SECURITY_DAC=y -+CONFIG_DEFAULT_SECURITY="" -+CONFIG_CRYPTO=y -+ -+# -+# Crypto core or helper -+# -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_ALGAPI2=y -+# CONFIG_CRYPTO_MANAGER is not set -+# CONFIG_CRYPTO_MANAGER2 is not set -+# CONFIG_CRYPTO_USER is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_TEST is not set -+ -+# -+# Authenticated Encryption with Associated Data -+# -+# CONFIG_CRYPTO_CCM is not set -+# CONFIG_CRYPTO_GCM is not set -+# CONFIG_CRYPTO_SEQIV is not set -+ -+# -+# Block modes -+# -+# CONFIG_CRYPTO_CBC is not set -+# CONFIG_CRYPTO_CTR is not set -+# CONFIG_CRYPTO_CTS is not set -+# CONFIG_CRYPTO_ECB is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_XTS is not set -+ -+# -+# Hash modes -+# -+# CONFIG_CRYPTO_HMAC is not set -+ -+# -+# Digest -+# -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_GHASH is not set -+# CONFIG_CRYPTO_MD4 is not set -+# CONFIG_CRYPTO_MD5 is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_RMD128 is not set -+# CONFIG_CRYPTO_RMD160 is not set -+# CONFIG_CRYPTO_RMD256 is not set -+# CONFIG_CRYPTO_RMD320 is not set -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_WP512 is not set -+ -+# -+# Ciphers -+# -+CONFIG_CRYPTO_AES=y -+# CONFIG_CRYPTO_ANUBIS is not set -+CONFIG_CRYPTO_ARC4=y -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_DES is not set -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+ -+# -+# Compression -+# -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_ZLIB is not set -+# CONFIG_CRYPTO_LZO is not set -+ -+# -+# Random Number Generation -+# -+# CONFIG_CRYPTO_ANSI_CPRNG is not set -+# CONFIG_CRYPTO_USER_API_HASH is not set -+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set -+# CONFIG_CRYPTO_HW is not set -+# CONFIG_BINARY_PRINTF is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+CONFIG_GENERIC_PCI_IOMAP=y -+CONFIG_GENERIC_IO=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=y -+# CONFIG_CRC_T10DIF is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC32_SELFTEST is not set -+CONFIG_CRC32_SLICEBY8=y -+# CONFIG_CRC32_SLICEBY4 is not set -+# CONFIG_CRC32_SARWATE is not set -+# CONFIG_CRC32_BIT is not set -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+# CONFIG_CRC8 is not set -+CONFIG_ZLIB_INFLATE=y -+# CONFIG_XZ_DEC is not set -+# CONFIG_XZ_DEC_BCJ is not set -+CONFIG_GENERIC_ALLOCATOR=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -+CONFIG_DQL=y -+CONFIG_NLATTR=y -+CONFIG_GENERIC_ATOMIC64=y -+CONFIG_AVERAGE=y -+# CONFIG_CORDIC is not set -diff --git a/arch/arm/configs/ak39_micro_defconfig b/arch/arm/configs/ak39_micro_defconfig -new file mode 100644 -index 00000000..aab60f4b ---- /dev/null -+++ b/arch/arm/configs/ak39_micro_defconfig -@@ -0,0 +1,1272 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# Linux/arm 3.4.35 Kernel Configuration -+# -+CONFIG_ARM=y -+CONFIG_SYS_SUPPORTS_APM_EMULATION=y -+CONFIG_GENERIC_GPIO=y -+CONFIG_ARCH_USES_GETTIMEOFFSET=y -+CONFIG_KTIME_SCALAR=y -+CONFIG_HAVE_PROC_CPU=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_HAVE_LATENCYTOP_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+CONFIG_HARDIRQS_SW_RESEND=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+CONFIG_ARCH_HAS_CPUFREQ=y -+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_NEED_DMA_MAP_STATE=y -+CONFIG_VECTORS_BASE=0xffff0000 -+# CONFIG_ARM_PATCH_PHYS_VIRT is not set -+CONFIG_PHYS_OFFSET=0x80000000 -+CONFIG_GENERIC_BUG=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+CONFIG_HAVE_IRQ_WORK=y -+CONFIG_IRQ_WORK=y -+ -+# -+# General setup -+# -+# CONFIG_EXPERIMENTAL is not set -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_CROSS_COMPILE="" -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_HAVE_KERNEL_GZIP=y -+CONFIG_HAVE_KERNEL_LZMA=y -+CONFIG_HAVE_KERNEL_XZ=y -+CONFIG_HAVE_KERNEL_LZO=y -+CONFIG_KERNEL_GZIP=y -+# CONFIG_KERNEL_LZMA is not set -+# CONFIG_KERNEL_XZ is not set -+# CONFIG_KERNEL_LZO is not set -+CONFIG_DEFAULT_HOSTNAME="(none)" -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+CONFIG_BSD_PROCESS_ACCT=y -+CONFIG_BSD_PROCESS_ACCT_V3=y -+CONFIG_FHANDLE=y -+# CONFIG_TASKSTATS is not set -+# CONFIG_AUDIT is not set -+CONFIG_HAVE_GENERIC_HARDIRQS=y -+ -+# -+# IRQ subsystem -+# -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_SHOW=y -+ -+# -+# RCU Subsystem -+# -+CONFIG_TINY_RCU=y -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=16 -+# CONFIG_CGROUPS is not set -+# CONFIG_CHECKPOINT_RESTORE is not set -+CONFIG_NAMESPACES=y -+CONFIG_UTS_NS=y -+CONFIG_IPC_NS=y -+CONFIG_PID_NS=y -+CONFIG_NET_NS=y -+# CONFIG_SCHED_AUTOGROUP is not set -+# CONFIG_SYSFS_DEPRECATED is not set -+# CONFIG_RELAY is not set -+CONFIG_BLK_DEV_INITRD=y -+CONFIG_INITRAMFS_SOURCE="../targetfs/rootfs/rootfs.initramfs" -+CONFIG_INITRAMFS_ROOT_UID=0 -+CONFIG_INITRAMFS_ROOT_GID=0 -+CONFIG_RD_GZIP=y -+# CONFIG_RD_BZIP2 is not set -+# CONFIG_RD_LZMA is not set -+# CONFIG_RD_XZ is not set -+# CONFIG_RD_LZO is not set -+CONFIG_INITRAMFS_COMPRESSION_NONE=y -+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y -+CONFIG_PANIC_TIMEOUT=0 -+CONFIG_EXPERT=y -+CONFIG_UID16=y -+# CONFIG_SYSCTL_SYSCALL is not set -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_ALL 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_SIGNALFD=y -+CONFIG_TIMERFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_AIO=y -+CONFIG_EMBEDDED=y -+CONFIG_HAVE_PERF_EVENTS=y -+CONFIG_PERF_USE_VMALLOC=y -+ -+# -+# Kernel Performance Events And Counters -+# -+CONFIG_PERF_EVENTS=y -+# CONFIG_PERF_COUNTERS is not set -+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLUB_DEBUG=y -+CONFIG_COMPAT_BRK=y -+# CONFIG_SLAB is not set -+CONFIG_SLUB=y -+# CONFIG_SLOB is not set -+# CONFIG_PROFILING is not set -+CONFIG_HAVE_OPROFILE=y -+# CONFIG_KPROBES is not set -+CONFIG_JUMP_LABEL=y -+CONFIG_HAVE_KPROBES=y -+CONFIG_HAVE_KRETPROBES=y -+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -+CONFIG_HAVE_CLK=y -+CONFIG_HAVE_DMA_API_DEBUG=y -+CONFIG_HAVE_ARCH_JUMP_LABEL=y -+ -+# -+# GCOV-based kernel profiling -+# -+# CONFIG_GCOV_KERNEL is not set -+CONFIG_HAVE_GENERIC_DMA_COHERENT=y -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_FORCE_LOAD=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODVERSIONS is not set -+# CONFIG_MODULE_SRCVERSION_ALL is not set -+CONFIG_BLOCK=y -+CONFIG_LBDAF=y -+CONFIG_BLK_DEV_BSG=y -+CONFIG_BLK_DEV_BSGLIB=y -+CONFIG_BLK_DEV_INTEGRITY=y -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+# CONFIG_DEFAULT_DEADLINE is not set -+CONFIG_DEFAULT_CFQ=y -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="cfq" -+# CONFIG_INLINE_SPIN_TRYLOCK is not set -+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK is not set -+# CONFIG_INLINE_SPIN_LOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_READ_TRYLOCK is not set -+# CONFIG_INLINE_READ_LOCK is not set -+# CONFIG_INLINE_READ_LOCK_BH is not set -+# CONFIG_INLINE_READ_LOCK_IRQ is not set -+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -+CONFIG_INLINE_READ_UNLOCK=y -+# CONFIG_INLINE_READ_UNLOCK_BH is not set -+CONFIG_INLINE_READ_UNLOCK_IRQ=y -+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_WRITE_TRYLOCK is not set -+# CONFIG_INLINE_WRITE_LOCK is not set -+# CONFIG_INLINE_WRITE_LOCK_BH is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -+CONFIG_INLINE_WRITE_UNLOCK=y -+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -+# CONFIG_MUTEX_SPIN_ON_OWNER is not set -+CONFIG_FREEZER=y -+ -+# -+# System Type -+# -+CONFIG_MMU=y -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_REALVIEW is not set -+# CONFIG_ARCH_VERSATILE is not set -+# CONFIG_ARCH_VEXPRESS is not set -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_BCMRING is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_CLPS711X is not set -+# CONFIG_ARCH_CNS3XXX is not set -+# CONFIG_ARCH_GEMINI is not set -+# CONFIG_ARCH_PRIMA2 is not set -+# CONFIG_ARCH_EBSA110 is not set -+# CONFIG_ARCH_EP93XX is not set -+# CONFIG_ARCH_FOOTBRIDGE is not set -+# CONFIG_ARCH_MXC is not set -+# CONFIG_ARCH_MXS is not set -+# CONFIG_ARCH_NETX is not set -+# CONFIG_ARCH_H720X is not set -+# CONFIG_ARCH_IOP13XX is not set -+# CONFIG_ARCH_IOP32X is not set -+# CONFIG_ARCH_IOP33X is not set -+# CONFIG_ARCH_IXP23XX is not set -+# CONFIG_ARCH_IXP2000 is not set -+# CONFIG_ARCH_IXP4XX is not set -+# CONFIG_ARCH_DOVE is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_MV78XX0 is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_ARCH_MMP is not set -+# CONFIG_ARCH_KS8695 is not set -+# CONFIG_ARCH_W90X900 is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_PICOXCELL is not set -+# CONFIG_ARCH_PNX4008 is not set -+# CONFIG_ARCH_PXA is not set -+# CONFIG_ARCH_MSM is not set -+# CONFIG_ARCH_SHMOBILE is not set -+# CONFIG_ARCH_RPC is not set -+# CONFIG_ARCH_SA1100 is not set -+# CONFIG_ARCH_S3C24XX is not set -+# CONFIG_ARCH_S3C64XX is not set -+# CONFIG_ARCH_S5P64X0 is not set -+# CONFIG_ARCH_S5PC100 is not set -+# CONFIG_ARCH_S5PV210 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_SHARK is not set -+# CONFIG_ARCH_U300 is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_NOMADIK is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_OMAP is not set -+# CONFIG_PLAT_SPEAR is not set -+# CONFIG_ARCH_VT8500 is not set -+# CONFIG_ARCH_ZYNQ is not set -+CONFIG_ARCH_AK39=y -+ -+# -+# System MMU -+# -+CONFIG_CPU_AK3910=y -+CONFIG_ARCH_SDK3910=y -+ -+# -+# Power management -+# -+CONFIG_PLAT_ANYKA=y -+ -+# -+# Processor Type -+# -+CONFIG_CPU_ARM926T=y -+CONFIG_CPU_32v5=y -+CONFIG_CPU_ABRT_EV5TJ=y -+CONFIG_CPU_PABRT_LEGACY=y -+CONFIG_CPU_CACHE_VIVT=y -+CONFIG_CPU_COPY_V4WB=y -+CONFIG_CPU_TLB_V4WBI=y -+CONFIG_CPU_CP15=y -+CONFIG_CPU_CP15_MMU=y -+CONFIG_CPU_USE_DOMAINS=y -+ -+# -+# Processor Features -+# -+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -+CONFIG_ARM_THUMB=y -+# CONFIG_CPU_ICACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set -+# CONFIG_CACHE_L2X0 is not set -+CONFIG_ARM_L1_CACHE_SHIFT=5 -+CONFIG_ARM_NR_BANKS=8 -+# CONFIG_FIQ_DEBUGGER is not set -+ -+# -+# Bus support -+# -+# CONFIG_PCI_SYSCALL is not set -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_PCCARD=y -+CONFIG_PCMCIA=y -+ -+# -+# PC-card bridges -+# -+ -+# -+# Kernel Features -+# -+CONFIG_VMSPLIT_3G=y -+# CONFIG_VMSPLIT_2G is not set -+# CONFIG_VMSPLIT_1G is not set -+CONFIG_PAGE_OFFSET=0xC0000000 -+CONFIG_ARCH_NR_GPIO=0 -+CONFIG_PREEMPT_NONE=y -+# CONFIG_PREEMPT_VOLUNTARY is not set -+# CONFIG_PREEMPT is not set -+CONFIG_HZ=100 -+CONFIG_AEABI=y -+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -+CONFIG_HAVE_ARCH_PFN_VALID=y -+# CONFIG_HIGHMEM is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+CONFIG_HAVE_MEMBLOCK=y -+CONFIG_PAGEFLAGS_EXTENDED=y -+CONFIG_SPLIT_PTLOCK_CPUS=999999 -+# CONFIG_COMPACTION is not set -+# CONFIG_PHYS_ADDR_T_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_KSM is not set -+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -+CONFIG_NEED_PER_CPU_KM=y -+# CONFIG_CLEANCACHE is not set -+CONFIG_FORCE_MAX_ZONEORDER=11 -+CONFIG_ALIGNMENT_TRAP=y -+# CONFIG_SECCOMP is not set -+# CONFIG_DEPRECATED_PARAM_STRUCT is not set -+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -+ -+# -+# Boot options -+# -+# CONFIG_USE_OF is not set -+CONFIG_ZBOOT_ROM_TEXT=0 -+CONFIG_ZBOOT_ROM_BSS=0 -+CONFIG_CMDLINE="mem=256M console=ttySAK0,115200" -+CONFIG_CMDLINE_FROM_BOOTLOADER=y -+# CONFIG_CMDLINE_EXTEND is not set -+# CONFIG_CMDLINE_FORCE is not set -+# CONFIG_XIP_KERNEL is not set -+# CONFIG_AUTO_ZRELADDR is not set -+CONFIG_RAM_BASE=0x80000000 -+CONFIG_VIDEO_RESERVED_MEM_SIZE=0x0 -+ -+# -+# CPU Power Management -+# -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ is not set -+CONFIG_CPU_IDLE=y -+CONFIG_CPU_IDLE_GOV_LADDER=y -+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set -+ -+# -+# Floating point emulation -+# -+ -+# -+# At least one emulation must be selected -+# -+CONFIG_VFP=y -+ -+# -+# Userspace binary formats -+# -+CONFIG_BINFMT_ELF=y -+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -+CONFIG_HAVE_AOUT=y -+# CONFIG_BINFMT_AOUT is not set -+# CONFIG_BINFMT_MISC is not set -+ -+# -+# Power management options -+# -+CONFIG_SUSPEND=y -+CONFIG_SUSPEND_FREEZER=y -+CONFIG_HAS_WAKELOCK=y -+CONFIG_WAKELOCK=y -+CONFIG_PM_SLEEP=y -+# CONFIG_PM_AUTOSLEEP is not set -+# CONFIG_PM_WAKELOCKS is not set -+# CONFIG_PM_RUNTIME is not set -+CONFIG_PM=y -+# CONFIG_PM_DEBUG is not set -+# CONFIG_APM_EMULATION is not set -+CONFIG_PM_CLK=y -+CONFIG_CPU_PM=y -+# CONFIG_SUSPEND_TIME is not set -+CONFIG_ARCH_SUSPEND_POSSIBLE=y -+CONFIG_ARM_CPU_SUSPEND=y -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+CONFIG_UNIX=y -+CONFIG_UNIX_DIAG=y -+CONFIG_XFRM=y -+# CONFIG_XFRM_USER is not set -+CONFIG_NET_KEY=y -+CONFIG_INET=y -+CONFIG_IP_MULTICAST=y -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+CONFIG_IP_PNP_RARP=y -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE_DEMUX is not set -+# CONFIG_IP_MROUTE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+CONFIG_INET_XFRM_MODE_TRANSPORT=y -+CONFIG_INET_XFRM_MODE_TUNNEL=y -+CONFIG_INET_XFRM_MODE_BEET=y -+CONFIG_INET_LRO=y -+CONFIG_INET_DIAG=y -+CONFIG_INET_TCP_DIAG=y -+CONFIG_INET_UDP_DIAG=y -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_IPV6 is not set -+CONFIG_ANDROID_PARANOID_NETWORK=y -+CONFIG_NET_ACTIVITY_STATS=y -+# CONFIG_NETWORK_SECMARK is not set -+CONFIG_NETFILTER=y -+# CONFIG_NETFILTER_DEBUG is not set -+CONFIG_NETFILTER_ADVANCED=y -+ -+# -+# Core Netfilter Configuration -+# -+# CONFIG_NETFILTER_NETLINK_ACCT is not set -+# CONFIG_NETFILTER_NETLINK_QUEUE is not set -+# CONFIG_NETFILTER_NETLINK_LOG is not set -+# CONFIG_NF_CONNTRACK is not set -+# CONFIG_NETFILTER_XTABLES is not set -+# CONFIG_IP_VS is not set -+ -+# -+# IP: Netfilter Configuration -+# -+# CONFIG_NF_DEFRAG_IPV4 is not set -+# CONFIG_IP_NF_QUEUE is not set -+# CONFIG_IP_NF_IPTABLES is not set -+# CONFIG_IP_NF_ARPTABLES is not set -+# CONFIG_ATM is not set -+# CONFIG_L2TP 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_PHONET is not set -+# CONFIG_NET_SCHED is not set -+# CONFIG_DCB is not set -+# CONFIG_BATMAN_ADV is not set -+# CONFIG_OPENVSWITCH is not set -+CONFIG_BQL=y -+CONFIG_HAVE_BPF_JIT=y -+# CONFIG_BPF_JIT is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_CAN is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+CONFIG_WIRELESS=y -+CONFIG_WEXT_CORE=y -+CONFIG_WEXT_PROC=y -+CONFIG_CFG80211=y -+# CONFIG_NL80211_TESTMODE is not set -+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -+# CONFIG_CFG80211_REG_DEBUG is not set -+CONFIG_CFG80211_DEFAULT_PS=y -+# CONFIG_CFG80211_DEBUGFS is not set -+# CONFIG_CFG80211_INTERNAL_REGDB is not set -+CONFIG_CFG80211_WEXT=y -+CONFIG_WIRELESS_EXT_SYSFS=y -+CONFIG_LIB80211=y -+# CONFIG_LIB80211_DEBUG is not set -+CONFIG_CFG80211_ALLOW_RECONNECT=y -+CONFIG_MAC80211=y -+CONFIG_MAC80211_HAS_RC=y -+# CONFIG_MAC80211_RC_PID is not set -+CONFIG_MAC80211_RC_MINSTREL=y -+CONFIG_MAC80211_RC_MINSTREL_HT=y -+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -+# CONFIG_MAC80211_DEBUGFS is not set -+# CONFIG_MAC80211_DEBUG_MENU is not set -+# CONFIG_WIMAX is not set -+CONFIG_RFKILL=y -+CONFIG_RFKILL_PM=y -+# CONFIG_RFKILL_INPUT is not set -+# CONFIG_RFKILL_GPIO is not set -+# CONFIG_NET_9P is not set -+# CONFIG_CAIF is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_DEVTMPFS=y -+CONFIG_DEVTMPFS_MOUNT=y -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+CONFIG_FW_LOADER=y -+CONFIG_FIRMWARE_IN_KERNEL=y -+CONFIG_EXTRA_FIRMWARE="" -+# CONFIG_DEBUG_DRIVER is not set -+# CONFIG_DEBUG_DEVRES is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_GENERIC_CPU_DEVICES is not set -+CONFIG_SYNC=y -+CONFIG_SW_SYNC=y -+# CONFIG_SW_SYNC_USER is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_TESTS is not set -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+# CONFIG_MTD_AFS_PARTS is not set -+# CONFIG_MTD_AR7_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+# CONFIG_MTD_CHAR is not set -+# CONFIG_MTD_BLKDEVS is not set -+# CONFIG_MTD_BLOCK is not set -+# CONFIG_MTD_BLOCK_RO is not set -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+# CONFIG_MTD_SWAP is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOCG3 is not set -+# CONFIG_MTD_NAND_IDS is not set -+# CONFIG_MTD_NAND is not set -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# LPDDR flash memory drivers -+# -+# CONFIG_MTD_LPDDR is not set -+# CONFIG_MTD_UBI is not set -+# CONFIG_PARPORT is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+ -+# -+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected -+# -+# CONFIG_BLK_DEV_NBD is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+# CONFIG_BLK_DEV_XIP is not set -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+# CONFIG_MG_DISK is not set -+ -+# -+# Misc devices -+# -+# CONFIG_SENSORS_LIS3LV02D is not set -+# CONFIG_ATMEL_PWM is not set -+# CONFIG_ENCLOSURE_SERVICES is not set -+# CONFIG_UID_STAT is not set -+# CONFIG_WL127X_RFKILL is not set -+ -+# -+# EEPROM support -+# -+# CONFIG_EEPROM_93CX6 is not set -+ -+# -+# Texas Instruments shared transport line discipline -+# -+# CONFIG_TI_ST is not set -+ -+# -+# Altera FPGA firmware download module -+# -+CONFIG_HAVE_IDE=y -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+CONFIG_SCSI_MOD=y -+# CONFIG_RAID_ATTRS is not set -+# CONFIG_SCSI is not set -+# CONFIG_SCSI_DMA is not set -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_NETDEVICES is not set -+# CONFIG_ISDN is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+# CONFIG_INPUT_SPARSEKMAP is not set -+ -+# -+# Userland interfaces -+# -+# CONFIG_INPUT_MOUSEDEV is not set -+# CONFIG_INPUT_JOYDEV is not set -+# CONFIG_INPUT_EVDEV is not set -+# CONFIG_INPUT_EVBUG is not set -+# CONFIG_INPUT_KEYRESET is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+# CONFIG_SERIO is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_CONSOLE_TRANSLATIONS=y -+CONFIG_VT_CONSOLE=y -+CONFIG_VT_CONSOLE_SLEEP=y -+CONFIG_HW_CONSOLE=y -+# CONFIG_VT_HW_CONSOLE_BINDING is not set -+CONFIG_UNIX98_PTYS=y -+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set -+# CONFIG_LEGACY_PTYS is not set -+# CONFIG_SERIAL_NONSTANDARD is not set -+# CONFIG_TRACE_SINK is not set -+CONFIG_DEVMEM=y -+CONFIG_DEVKMEM=y -+ -+# -+# Serial drivers -+# -+# CONFIG_SERIAL_8250 is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_SERIAL_TIMBERDALE is not set -+# CONFIG_SERIAL_ALTERA_JTAGUART is not set -+# CONFIG_SERIAL_ALTERA_UART is not set -+# CONFIG_SERIAL_XILINX_PS_UART is not set -+CONFIG_SERIAL_AK39_UART=y -+CONFIG_SERIAL_AK39_CONSOLE=y -+CONFIG_TTY_PRINTK=y -+# CONFIG_HVC_DCC is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_R3964 is not set -+ -+# -+# PCMCIA character devices -+# -+# CONFIG_SYNCLINK_CS is not set -+# CONFIG_CARDMAN_4000 is not set -+# CONFIG_CARDMAN_4040 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+# CONFIG_DCC_TTY is not set -+# CONFIG_RAMOOPS is not set -+# CONFIG_I2C is not set -+# CONFIG_SPI is not set -+# CONFIG_HSI is not set -+ -+# -+# PPS support -+# -+ -+# -+# PPS generators support -+# -+ -+# -+# PTP clock support -+# -+ -+# -+# Enable Device Drivers -> PPS to see the PTP clock options. -+# -+CONFIG_ARCH_REQUIRE_GPIOLIB=y -+CONFIG_GPIOLIB=y -+# CONFIG_DEBUG_GPIO is not set -+ -+# -+# Memory mapped GPIO drivers: -+# -+# CONFIG_GPIO_GENERIC_PLATFORM is not set -+ -+# -+# I2C GPIO expanders: -+# -+ -+# -+# PCI GPIO expanders: -+# -+ -+# -+# SPI GPIO expanders: -+# -+ -+# -+# AC97 GPIO expanders: -+# -+ -+# -+# MODULbus GPIO expanders: -+# -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+# CONFIG_THERMAL is not set -+# CONFIG_WATCHDOG is not set -+CONFIG_SSB_POSSIBLE=y -+ -+# -+# Sonics Silicon Backplane -+# -+# CONFIG_SSB is not set -+CONFIG_BCMA_POSSIBLE=y -+ -+# -+# Broadcom specific AMBA -+# -+# CONFIG_BCMA is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_CORE is not set -+# CONFIG_MFD_SM501 is not set -+# CONFIG_MFD_ASIC3 is not set -+# CONFIG_HTC_EGPIO is not set -+# CONFIG_HTC_PASIC3 is not set -+# CONFIG_MFD_TMIO is not set -+# CONFIG_MFD_T7L66XB is not set -+# CONFIG_MFD_TC6387XB is not set -+# CONFIG_MFD_TC6393XB is not set -+# CONFIG_ABX500_CORE is not set -+# CONFIG_REGULATOR is not set -+# CONFIG_MEDIA_SUPPORT is not set -+ -+# -+# Graphics support -+# -+# CONFIG_DRM is not set -+# CONFIG_ION is not set -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_EXYNOS_VIDEO is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+CONFIG_DUMMY_CONSOLE=y -+# CONFIG_SOUND is not set -+# CONFIG_HID_SUPPORT is not set -+# CONFIG_USB_ARCH_HAS_OHCI is not set -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB_ARCH_HAS_XHCI is not set -+# CONFIG_USB_SUPPORT is not set -+# CONFIG_MMC is not set -+# CONFIG_MEMSTICK is not set -+# CONFIG_NEW_LEDS is not set -+# CONFIG_SWITCH is not set -+# CONFIG_ACCESSIBILITY is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+# CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set -+# CONFIG_UIO is not set -+ -+# -+# Virtio drivers -+# -+# CONFIG_VIRTIO_BALLOON is not set -+ -+# -+# Microsoft Hyper-V guest support -+# -+# CONFIG_STAGING is not set -+CONFIG_CLKDEV_LOOKUP=y -+ -+# -+# Hardware Spinlock drivers -+# -+# CONFIG_IOMMU_SUPPORT is not set -+ -+# -+# Remoteproc drivers (EXPERIMENTAL) -+# -+ -+# -+# Rpmsg drivers (EXPERIMENTAL) -+# -+# CONFIG_VIRT_DRIVERS is not set -+# CONFIG_PM_DEVFREQ is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+CONFIG_EXT2_FS_POSIX_ACL=y -+CONFIG_EXT2_FS_SECURITY=y -+CONFIG_EXT2_FS_XIP=y -+CONFIG_EXT3_FS=y -+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y -+CONFIG_EXT3_FS_XATTR=y -+CONFIG_EXT3_FS_POSIX_ACL=y -+CONFIG_EXT3_FS_SECURITY=y -+CONFIG_EXT4_FS=y -+CONFIG_EXT4_FS_XATTR=y -+CONFIG_EXT4_FS_POSIX_ACL=y -+CONFIG_EXT4_FS_SECURITY=y -+# CONFIG_EXT4_DEBUG is not set -+CONFIG_FS_XIP=y -+CONFIG_JBD=y -+# CONFIG_JBD_DEBUG is not set -+CONFIG_JBD2=y -+# CONFIG_JBD2_DEBUG is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+CONFIG_FS_POSIX_ACL=y -+CONFIG_EXPORTFS=y -+CONFIG_FILE_LOCKING=y -+CONFIG_FSNOTIFY=y -+CONFIG_DNOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_FANOTIFY is not set -+# CONFIG_QUOTA is not set -+# CONFIG_QUOTACTL is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+CONFIG_GENERIC_ACL=y -+ -+# -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_PROC_PAGE_MONITOR=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+CONFIG_TMPFS_POSIX_ACL=y -+CONFIG_TMPFS_XATTR=y -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+CONFIG_MISC_FILESYSTEMS=y -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_JFFS2_FS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_SQUASHFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_OMFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_QNX6FS_FS is not set -+# CONFIG_ROMFS_FS is not set -+# CONFIG_PSTORE is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+# CONFIG_NETWORK_FILESYSTEMS is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+CONFIG_NLS_UTF8=y -+ -+# -+# Kernel hacking -+# -+# CONFIG_PRINTK_TIME is not set -+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_FRAME_WARN=1024 -+# CONFIG_MAGIC_SYSRQ is not set -+# CONFIG_STRIP_ASM_SYMS is not set -+# CONFIG_UNUSED_SYMBOLS is not set -+CONFIG_DEBUG_FS=y -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_SECTION_MISMATCH is not set -+CONFIG_DEBUG_KERNEL=y -+# CONFIG_DEBUG_SHIRQ is not set -+# CONFIG_LOCKUP_DETECTOR is not set -+# CONFIG_HARDLOCKUP_DETECTOR_NMI is not set -+# CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU is not set -+# CONFIG_HARDLOCKUP_DETECTOR is not set -+# CONFIG_DETECT_HUNG_TASK is not set -+# CONFIG_SCHED_DEBUG is not set -+# CONFIG_SCHEDSTATS is not set -+# CONFIG_TIMER_STATS is not set -+# CONFIG_DEBUG_OBJECTS is not set -+# CONFIG_SLUB_DEBUG_ON is not set -+# CONFIG_SLUB_STATS is not set -+# CONFIG_DEBUG_RT_MUTEXES is not set -+# CONFIG_RT_MUTEX_TESTER is not set -+# CONFIG_DEBUG_SPINLOCK is not set -+# CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_SPARSE_RCU_POINTER is not set -+# CONFIG_LOCK_STAT is not set -+# CONFIG_DEBUG_ATOMIC_SLEEP is not set -+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -+CONFIG_STACKTRACE=y -+# CONFIG_DEBUG_STACK_USAGE is not set -+# CONFIG_DEBUG_KOBJECT is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_DEBUG_INFO is not set -+# CONFIG_DEBUG_VM is not set -+# CONFIG_DEBUG_WRITECOUNT is not set -+# CONFIG_DEBUG_MEMORY_INIT is not set -+# CONFIG_DEBUG_LIST is not set -+# CONFIG_TEST_LIST_SORT is not set -+# CONFIG_DEBUG_SG is not set -+# CONFIG_DEBUG_NOTIFIERS is not set -+# CONFIG_DEBUG_CREDENTIALS is not set -+CONFIG_FRAME_POINTER=y -+# CONFIG_BOOT_PRINTK_DELAY is not set -+# CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_RCU_TRACE is not set -+# CONFIG_BACKTRACE_SELF_TEST is not set -+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -+# CONFIG_LKDTM is not set -+# CONFIG_FAULT_INJECTION is not set -+# CONFIG_LATENCYTOP is not set -+# CONFIG_DEBUG_PAGEALLOC is not set -+CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -+CONFIG_HAVE_DYNAMIC_FTRACE=y -+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_HAVE_C_RECORDMCOUNT=y -+CONFIG_TRACING_SUPPORT=y -+# CONFIG_FTRACE is not set -+# CONFIG_DYNAMIC_DEBUG is not set -+# CONFIG_DMA_API_DEBUG is not set -+# CONFIG_ATOMIC64_SELFTEST is not set -+# CONFIG_SAMPLES is not set -+CONFIG_HAVE_ARCH_KGDB=y -+# CONFIG_TEST_KSTRTOX is not set -+# CONFIG_STRICT_DEVMEM is not set -+CONFIG_DEBUG_USER=y -+# CONFIG_DEBUG_RODATA is not set -+# CONFIG_DEBUG_LL is not set -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY_DMESG_RESTRICT is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITYFS is not set -+CONFIG_DEFAULT_SECURITY_DAC=y -+CONFIG_DEFAULT_SECURITY="" -+CONFIG_CRYPTO=y -+ -+# -+# Crypto core or helper -+# -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_ALGAPI2=y -+# CONFIG_CRYPTO_MANAGER is not set -+# CONFIG_CRYPTO_MANAGER2 is not set -+# CONFIG_CRYPTO_USER is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_TEST is not set -+ -+# -+# Authenticated Encryption with Associated Data -+# -+# CONFIG_CRYPTO_CCM is not set -+# CONFIG_CRYPTO_GCM is not set -+# CONFIG_CRYPTO_SEQIV is not set -+ -+# -+# Block modes -+# -+# CONFIG_CRYPTO_CBC is not set -+# CONFIG_CRYPTO_CTR is not set -+# CONFIG_CRYPTO_CTS is not set -+# CONFIG_CRYPTO_ECB is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_XTS is not set -+ -+# -+# Hash modes -+# -+# CONFIG_CRYPTO_HMAC is not set -+ -+# -+# Digest -+# -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_GHASH is not set -+# CONFIG_CRYPTO_MD4 is not set -+# CONFIG_CRYPTO_MD5 is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_RMD128 is not set -+# CONFIG_CRYPTO_RMD160 is not set -+# CONFIG_CRYPTO_RMD256 is not set -+# CONFIG_CRYPTO_RMD320 is not set -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_WP512 is not set -+ -+# -+# Ciphers -+# -+CONFIG_CRYPTO_AES=y -+# CONFIG_CRYPTO_ANUBIS is not set -+CONFIG_CRYPTO_ARC4=y -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_DES is not set -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+ -+# -+# Compression -+# -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_ZLIB is not set -+# CONFIG_CRYPTO_LZO is not set -+ -+# -+# Random Number Generation -+# -+# CONFIG_CRYPTO_ANSI_CPRNG is not set -+# CONFIG_CRYPTO_USER_API_HASH is not set -+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set -+CONFIG_CRYPTO_HW=y -+# CONFIG_BINARY_PRINTF is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+CONFIG_GENERIC_PCI_IOMAP=y -+CONFIG_GENERIC_IO=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=y -+CONFIG_CRC_T10DIF=y -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC32_SELFTEST is not set -+CONFIG_CRC32_SLICEBY8=y -+# CONFIG_CRC32_SLICEBY4 is not set -+# CONFIG_CRC32_SARWATE is not set -+# CONFIG_CRC32_BIT is not set -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+# CONFIG_CRC8 is not set -+CONFIG_ZLIB_INFLATE=y -+CONFIG_XZ_DEC=y -+CONFIG_XZ_DEC_X86=y -+CONFIG_XZ_DEC_POWERPC=y -+CONFIG_XZ_DEC_IA64=y -+CONFIG_XZ_DEC_ARM=y -+CONFIG_XZ_DEC_ARMTHUMB=y -+CONFIG_XZ_DEC_SPARC=y -+CONFIG_XZ_DEC_BCJ=y -+# CONFIG_XZ_DEC_TEST is not set -+CONFIG_DECOMPRESS_GZIP=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -+CONFIG_DQL=y -+CONFIG_NLATTR=y -+CONFIG_GENERIC_ATOMIC64=y -+CONFIG_AVERAGE=y -+# CONFIG_CORDIC is not set -diff --git a/arch/arm/configs/ak39_producer_defconfig b/arch/arm/configs/ak39_producer_defconfig -new file mode 100644 -index 00000000..fa47ebd7 ---- /dev/null -+++ b/arch/arm/configs/ak39_producer_defconfig -@@ -0,0 +1,1028 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# Linux/arm 3.4.35 Kernel Configuration -+# -+CONFIG_ARM=y -+CONFIG_SYS_SUPPORTS_APM_EMULATION=y -+CONFIG_GENERIC_GPIO=y -+CONFIG_ARCH_USES_GETTIMEOFFSET=y -+CONFIG_KTIME_SCALAR=y -+CONFIG_HAVE_PROC_CPU=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_HAVE_LATENCYTOP_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+CONFIG_HARDIRQS_SW_RESEND=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+CONFIG_ARCH_HAS_CPUFREQ=y -+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_NEED_DMA_MAP_STATE=y -+CONFIG_VECTORS_BASE=0xffff0000 -+# CONFIG_ARM_PATCH_PHYS_VIRT is not set -+CONFIG_PHYS_OFFSET=0x81a00000 -+CONFIG_GENERIC_BUG=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+CONFIG_HAVE_IRQ_WORK=y -+ -+# -+# General setup -+# -+# CONFIG_EXPERIMENTAL is not set -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_CROSS_COMPILE="" -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_HAVE_KERNEL_GZIP=y -+CONFIG_HAVE_KERNEL_LZMA=y -+CONFIG_HAVE_KERNEL_XZ=y -+CONFIG_HAVE_KERNEL_LZO=y -+CONFIG_KERNEL_GZIP=y -+# CONFIG_KERNEL_LZMA is not set -+# CONFIG_KERNEL_XZ is not set -+# CONFIG_KERNEL_LZO is not set -+CONFIG_DEFAULT_HOSTNAME="(none)" -+# CONFIG_SWAP is not set -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_FHANDLE is not set -+CONFIG_HAVE_GENERIC_HARDIRQS=y -+ -+# -+# IRQ subsystem -+# -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_SHOW=y -+ -+# -+# RCU Subsystem -+# -+CONFIG_TINY_RCU=y -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=16 -+# CONFIG_CHECKPOINT_RESTORE is not set -+# CONFIG_NAMESPACES is not set -+# CONFIG_SCHED_AUTOGROUP is not set -+# CONFIG_SYSFS_DEPRECATED is not set -+# CONFIG_RELAY is not set -+CONFIG_BLK_DEV_INITRD=y -+CONFIG_INITRAMFS_SOURCE="../../librootfs/rootfs" -+CONFIG_INITRAMFS_ROOT_UID=0 -+CONFIG_INITRAMFS_ROOT_GID=0 -+CONFIG_RD_GZIP=y -+# CONFIG_RD_BZIP2 is not set -+# CONFIG_RD_LZMA is not set -+# CONFIG_RD_XZ is not set -+# CONFIG_RD_LZO is not set -+# CONFIG_INITRAMFS_COMPRESSION_NONE is not set -+CONFIG_INITRAMFS_COMPRESSION_GZIP=y -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y -+CONFIG_PANIC_TIMEOUT=0 -+CONFIG_EXPERT=y -+CONFIG_UID16=y -+# CONFIG_SYSCTL_SYSCALL is not set -+# CONFIG_KALLSYMS 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 is not set -+# CONFIG_SIGNALFD is not set -+# CONFIG_TIMERFD is not set -+# CONFIG_EVENTFD is not set -+# CONFIG_SHMEM is not set -+# CONFIG_AIO is not set -+CONFIG_EMBEDDED=y -+CONFIG_HAVE_PERF_EVENTS=y -+CONFIG_PERF_USE_VMALLOC=y -+ -+# -+# Kernel Performance Events And Counters -+# -+# CONFIG_PERF_EVENTS is not set -+# CONFIG_PERF_COUNTERS is not set -+# CONFIG_VM_EVENT_COUNTERS is not set -+# CONFIG_SLUB_DEBUG is not set -+# CONFIG_COMPAT_BRK is not set -+# CONFIG_SLAB is not set -+CONFIG_SLUB=y -+# CONFIG_SLOB is not set -+# CONFIG_PROFILING is not set -+CONFIG_HAVE_OPROFILE=y -+# CONFIG_KPROBES is not set -+CONFIG_JUMP_LABEL=y -+CONFIG_HAVE_KPROBES=y -+CONFIG_HAVE_KRETPROBES=y -+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -+CONFIG_HAVE_CLK=y -+CONFIG_HAVE_DMA_API_DEBUG=y -+CONFIG_HAVE_ARCH_JUMP_LABEL=y -+ -+# -+# GCOV-based kernel profiling -+# -+CONFIG_HAVE_GENERIC_DMA_COHERENT=y -+CONFIG_RT_MUTEXES=y -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_FORCE_LOAD=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODVERSIONS is not set -+# CONFIG_MODULE_SRCVERSION_ALL is not set -+CONFIG_BLOCK=y -+# CONFIG_LBDAF is not set -+# CONFIG_BLK_DEV_BSG is not set -+# CONFIG_BLK_DEV_BSGLIB is not set -+# CONFIG_BLK_DEV_INTEGRITY is not set -+ -+# -+# Partition Types -+# -+# CONFIG_PARTITION_ADVANCED is not set -+CONFIG_MSDOS_PARTITION=y -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+# CONFIG_IOSCHED_DEADLINE is not set -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_CFQ=y -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="cfq" -+# CONFIG_INLINE_SPIN_TRYLOCK is not set -+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK is not set -+# CONFIG_INLINE_SPIN_LOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_READ_TRYLOCK is not set -+# CONFIG_INLINE_READ_LOCK is not set -+# CONFIG_INLINE_READ_LOCK_BH is not set -+# CONFIG_INLINE_READ_LOCK_IRQ is not set -+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -+CONFIG_INLINE_READ_UNLOCK=y -+# CONFIG_INLINE_READ_UNLOCK_BH is not set -+CONFIG_INLINE_READ_UNLOCK_IRQ=y -+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_WRITE_TRYLOCK is not set -+# CONFIG_INLINE_WRITE_LOCK is not set -+# CONFIG_INLINE_WRITE_LOCK_BH is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -+CONFIG_INLINE_WRITE_UNLOCK=y -+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -+# CONFIG_MUTEX_SPIN_ON_OWNER is not set -+CONFIG_FREEZER=y -+ -+# -+# System Type -+# -+CONFIG_MMU=y -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_REALVIEW is not set -+# CONFIG_ARCH_VERSATILE is not set -+# CONFIG_ARCH_VEXPRESS is not set -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_BCMRING is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_CLPS711X is not set -+# CONFIG_ARCH_CNS3XXX is not set -+# CONFIG_ARCH_GEMINI is not set -+# CONFIG_ARCH_PRIMA2 is not set -+# CONFIG_ARCH_EBSA110 is not set -+# CONFIG_ARCH_EP93XX is not set -+# CONFIG_ARCH_FOOTBRIDGE is not set -+# CONFIG_ARCH_MXC is not set -+# CONFIG_ARCH_MXS is not set -+# CONFIG_ARCH_NETX is not set -+# CONFIG_ARCH_H720X is not set -+# CONFIG_ARCH_IOP13XX is not set -+# CONFIG_ARCH_IOP32X is not set -+# CONFIG_ARCH_IOP33X is not set -+# CONFIG_ARCH_IXP23XX is not set -+# CONFIG_ARCH_IXP2000 is not set -+# CONFIG_ARCH_IXP4XX is not set -+# CONFIG_ARCH_DOVE is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_MV78XX0 is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_ARCH_MMP is not set -+# CONFIG_ARCH_KS8695 is not set -+# CONFIG_ARCH_W90X900 is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_PICOXCELL is not set -+# CONFIG_ARCH_PNX4008 is not set -+# CONFIG_ARCH_PXA is not set -+# CONFIG_ARCH_MSM is not set -+# CONFIG_ARCH_SHMOBILE is not set -+# CONFIG_ARCH_RPC is not set -+# CONFIG_ARCH_SA1100 is not set -+# CONFIG_ARCH_S3C24XX is not set -+# CONFIG_ARCH_S3C64XX is not set -+# CONFIG_ARCH_S5P64X0 is not set -+# CONFIG_ARCH_S5PC100 is not set -+# CONFIG_ARCH_S5PV210 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_SHARK is not set -+# CONFIG_ARCH_U300 is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_NOMADIK is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_OMAP is not set -+# CONFIG_PLAT_SPEAR is not set -+# CONFIG_ARCH_VT8500 is not set -+# CONFIG_ARCH_ZYNQ is not set -+CONFIG_ARCH_AK39=y -+ -+# -+# System MMU -+# -+CONFIG_CPU_AK3910=y -+CONFIG_ARCH_SDK3910=y -+# CONFIG_ARCH_AIMER39_AK3916 is not set -+CONFIG_ASIC_FREQ_VALUE=90000000 -+ -+# -+# Power management -+# -+# CONFIG_AK39_PM is not set -+# CONFIG_AK39_PWM is not set -+CONFIG_PLAT_ANYKA=y -+ -+# -+# Processor Type -+# -+CONFIG_CPU_ARM926T=y -+CONFIG_CPU_32v5=y -+CONFIG_CPU_ABRT_EV5TJ=y -+CONFIG_CPU_PABRT_LEGACY=y -+CONFIG_CPU_CACHE_VIVT=y -+CONFIG_CPU_COPY_V4WB=y -+CONFIG_CPU_TLB_V4WBI=y -+CONFIG_CPU_CP15=y -+CONFIG_CPU_CP15_MMU=y -+CONFIG_CPU_USE_DOMAINS=y -+ -+# -+# Processor Features -+# -+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -+# CONFIG_ARM_THUMB is not set -+# CONFIG_CPU_ICACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set -+# CONFIG_CACHE_L2X0 is not set -+CONFIG_ARM_L1_CACHE_SHIFT=5 -+CONFIG_ARM_NR_BANKS=8 -+# CONFIG_FIQ_DEBUGGER is not set -+ -+# -+# Bus support -+# -+# CONFIG_PCI_SYSCALL is not set -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+# CONFIG_PCCARD is not set -+ -+# -+# Kernel Features -+# -+CONFIG_VMSPLIT_3G=y -+# CONFIG_VMSPLIT_2G is not set -+# CONFIG_VMSPLIT_1G is not set -+CONFIG_PAGE_OFFSET=0xC0000000 -+CONFIG_ARCH_NR_GPIO=0 -+CONFIG_PREEMPT_NONE=y -+# CONFIG_PREEMPT_VOLUNTARY is not set -+# CONFIG_PREEMPT is not set -+CONFIG_HZ=100 -+CONFIG_AEABI=y -+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -+CONFIG_HAVE_ARCH_PFN_VALID=y -+# CONFIG_HIGHMEM is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+CONFIG_HAVE_MEMBLOCK=y -+CONFIG_PAGEFLAGS_EXTENDED=y -+CONFIG_SPLIT_PTLOCK_CPUS=999999 -+# CONFIG_COMPACTION is not set -+# CONFIG_PHYS_ADDR_T_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_KSM is not set -+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -+CONFIG_NEED_PER_CPU_KM=y -+# CONFIG_CLEANCACHE is not set -+CONFIG_FORCE_MAX_ZONEORDER=11 -+CONFIG_ALIGNMENT_TRAP=y -+# CONFIG_SECCOMP is not set -+# CONFIG_DEPRECATED_PARAM_STRUCT is not set -+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -+ -+# -+# Boot options -+# -+# CONFIG_USE_OF is not set -+CONFIG_ZBOOT_ROM_TEXT=0 -+CONFIG_ZBOOT_ROM_BSS=0 -+CONFIG_CMDLINE="mem=64M console=ttySAK0,115200 download=1" -+CONFIG_CMDLINE_FROM_BOOTLOADER=y -+# CONFIG_CMDLINE_EXTEND is not set -+# CONFIG_CMDLINE_FORCE is not set -+# CONFIG_XIP_KERNEL is not set -+# CONFIG_AUTO_ZRELADDR is not set -+CONFIG_RAM_BASE=0x80000000 -+CONFIG_VIDEO_RESERVED_MEM_SIZE=0x1a00000 -+ -+# -+# CPU Power Management -+# -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ is not set -+# CONFIG_CPU_IDLE is not set -+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set -+ -+# -+# Floating point emulation -+# -+ -+# -+# At least one emulation must be selected -+# -+# CONFIG_VFP is not set -+ -+# -+# Userspace binary formats -+# -+CONFIG_BINFMT_ELF=y -+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -+CONFIG_HAVE_AOUT=y -+# CONFIG_BINFMT_AOUT is not set -+# CONFIG_BINFMT_MISC is not set -+ -+# -+# Power management options -+# -+CONFIG_SUSPEND=y -+CONFIG_SUSPEND_FREEZER=y -+CONFIG_HAS_WAKELOCK=y -+CONFIG_WAKELOCK=y -+CONFIG_PM_SLEEP=y -+# CONFIG_PM_AUTOSLEEP is not set -+# CONFIG_PM_WAKELOCKS is not set -+# CONFIG_PM_RUNTIME is not set -+CONFIG_PM=y -+# CONFIG_PM_DEBUG is not set -+# CONFIG_APM_EMULATION is not set -+CONFIG_PM_CLK=y -+CONFIG_CPU_PM=y -+# CONFIG_SUSPEND_TIME is not set -+CONFIG_ARCH_SUSPEND_POSSIBLE=y -+CONFIG_ARM_CPU_SUSPEND=y -+# CONFIG_NET is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_DEVTMPFS=y -+CONFIG_DEVTMPFS_MOUNT=y -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+CONFIG_FW_LOADER=y -+CONFIG_FIRMWARE_IN_KERNEL=y -+CONFIG_EXTRA_FIRMWARE="" -+# CONFIG_DEBUG_DRIVER is not set -+# CONFIG_DEBUG_DEVRES is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_GENERIC_CPU_DEVICES is not set -+CONFIG_SYNC=y -+CONFIG_SW_SYNC=y -+# CONFIG_SW_SYNC_USER is not set -+CONFIG_MTD=y -+# CONFIG_MTD_TESTS is not set -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+# CONFIG_MTD_AFS_PARTS is not set -+# CONFIG_MTD_AR7_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SST25L 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_DOCG3 is not set -+CONFIG_MTD_AK_SPIFLASH=y -+# CONFIG_MTD_NAND_IDS is not set -+# CONFIG_MTD_NAND is not set -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# LPDDR flash memory drivers -+# -+# CONFIG_MTD_LPDDR is not set -+# CONFIG_MTD_UBI is not set -+# CONFIG_PARPORT is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+# CONFIG_BLK_DEV_LOOP is not set -+ -+# -+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected -+# -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+# CONFIG_BLK_DEV_XIP is not set -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_MG_DISK is not set -+ -+# -+# Misc devices -+# -+# CONFIG_AD525X_DPOT is not set -+# CONFIG_ATMEL_PWM is not set -+# CONFIG_ENCLOSURE_SERVICES is not set -+# CONFIG_TI_DAC7512 is not set -+# CONFIG_UID_STAT is not set -+ -+# -+# EEPROM support -+# -+# CONFIG_EEPROM_AT25 is not set -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_EEPROM_93XX46 is not set -+ -+# -+# Texas Instruments shared transport line discipline -+# -+ -+# -+# Altera FPGA firmware download module -+# -+ -+# -+# SCSI device support -+# -+CONFIG_SCSI_MOD=y -+# CONFIG_RAID_ATTRS is not set -+# CONFIG_SCSI is not set -+# CONFIG_SCSI_DMA is not set -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+ -+# -+# Input device support -+# -+# CONFIG_INPUT is not set -+ -+# -+# Hardware I/O ports -+# -+# CONFIG_SERIO is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+# CONFIG_VT is not set -+# CONFIG_UNIX98_PTYS is not set -+# CONFIG_LEGACY_PTYS is not set -+# CONFIG_SERIAL_NONSTANDARD is not set -+# CONFIG_TRACE_SINK is not set -+CONFIG_DEVMEM=y -+CONFIG_DEVKMEM=y -+ -+# -+# Serial drivers -+# -+# CONFIG_SERIAL_8250 is not set -+ -+# -+# Non-8250 serial port support -+# -+# CONFIG_SERIAL_MAX3100 is not set -+# CONFIG_SERIAL_MAX3107 is not set -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_SERIAL_TIMBERDALE is not set -+# CONFIG_SERIAL_ALTERA_JTAGUART is not set -+# CONFIG_SERIAL_ALTERA_UART is not set -+# CONFIG_SERIAL_XILINX_PS_UART is not set -+CONFIG_SERIAL_AK39_UART=y -+CONFIG_SERIAL_AK39_CONSOLE=y -+# CONFIG_TTY_PRINTK is not set -+# CONFIG_HVC_DCC is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+# CONFIG_DCC_TTY is not set -+# CONFIG_RAMOOPS is not set -+# CONFIG_I2C is not set -+CONFIG_SPI=y -+# CONFIG_SPI_DEBUG is not set -+CONFIG_SPI_MASTER=y -+ -+# -+# SPI Master Controller Drivers -+# -+# CONFIG_SPI_ALTERA is not set -+CONFIG_SPI_BITBANG=y -+# CONFIG_SPI_GPIO is not set -+# CONFIG_SPI_OC_TINY is not set -+# CONFIG_SPI_PXA2XX_PCI is not set -+CONFIG_SPI_ANYKA=y -+# CONFIG_SPI_DESIGNWARE is not set -+ -+# -+# SPI Protocol Masters -+# -+# CONFIG_SPI_TLE62X0 is not set -+# CONFIG_HSI is not set -+ -+# -+# PPS support -+# -+ -+# -+# PPS generators support -+# -+ -+# -+# PTP clock support -+# -+ -+# -+# Enable Device Drivers -> PPS to see the PTP clock options. -+# -+CONFIG_ARCH_REQUIRE_GPIOLIB=y -+CONFIG_GPIOLIB=y -+# CONFIG_DEBUG_GPIO is not set -+ -+# -+# Memory mapped GPIO drivers: -+# -+# CONFIG_GPIO_GENERIC_PLATFORM is not set -+ -+# -+# I2C GPIO expanders: -+# -+ -+# -+# PCI GPIO expanders: -+# -+ -+# -+# SPI GPIO expanders: -+# -+# CONFIG_GPIO_MAX7301 is not set -+# CONFIG_GPIO_MCP23S08 is not set -+# CONFIG_GPIO_MC33880 is not set -+# CONFIG_GPIO_74X164 is not set -+ -+# -+# AC97 GPIO expanders: -+# -+ -+# -+# MODULbus GPIO expanders: -+# -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+# CONFIG_THERMAL is not set -+# CONFIG_WATCHDOG is not set -+CONFIG_SSB_POSSIBLE=y -+ -+# -+# Sonics Silicon Backplane -+# -+# CONFIG_SSB is not set -+CONFIG_BCMA_POSSIBLE=y -+ -+# -+# Broadcom specific AMBA -+# -+# CONFIG_BCMA is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_CORE is not set -+# CONFIG_MFD_SM501 is not set -+# CONFIG_MFD_ASIC3 is not set -+# CONFIG_HTC_EGPIO is not set -+# CONFIG_HTC_PASIC3 is not set -+# CONFIG_MFD_TPS65912_SPI is not set -+# CONFIG_MFD_STMPE is not set -+# CONFIG_MFD_TMIO is not set -+# CONFIG_MFD_T7L66XB is not set -+# CONFIG_MFD_TC6387XB is not set -+# CONFIG_MFD_TC6393XB is not set -+# CONFIG_MFD_DA9052_SPI is not set -+# CONFIG_MFD_WM831X_SPI is not set -+# CONFIG_MFD_MC13XXX is not set -+# CONFIG_ABX500_CORE is not set -+# CONFIG_EZX_PCAP is not set -+# CONFIG_REGULATOR is not set -+# CONFIG_MEDIA_SUPPORT is not set -+ -+# -+# Graphics support -+# -+# CONFIG_DRM is not set -+# CONFIG_ION is not set -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_EXYNOS_VIDEO is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+# CONFIG_SOUND is not set -+# CONFIG_USB_ARCH_HAS_OHCI is not set -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB_ARCH_HAS_XHCI is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_COMMON=y -+CONFIG_USB_ARCH_HAS_HCD=y -+# CONFIG_USB is not set -+# CONFIG_USB_OTG_WHITELIST is not set -+# CONFIG_USB_OTG_BLACKLIST_HUB is not set -+ -+# -+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -+# -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_VBUS_DRAW=2 -+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -+# CONFIG_USB_FUSB300 is not set -+# CONFIG_USB_R8A66597 is not set -+# CONFIG_USB_MV_UDC is not set -+CONFIG_USB_GADGET_AKUDC_PRODUCER=y -+CONFIG_USB_AKUDC_PRODUCER=y -+# CONFIG_USB_GADGET_AKUDC is not set -+# CONFIG_USB_M66592 is not set -+# CONFIG_USB_NET2272 is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+# CONFIG_USB_MASS_STORAGE is not set -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_G_PRINTER is not set -+# CONFIG_USB_G_ACM_MS is not set -+# CONFIG_USB_G_HID is not set -+# CONFIG_USB_G_DBGP is not set -+ -+# -+# OTG and related infrastructure -+# -+# CONFIG_USB_OTG_WAKELOCK is not set -+# CONFIG_USB_GPIO_VBUS is not set -+# CONFIG_USB_ULPI is not set -+# CONFIG_NOP_USB_XCEIV is not set -+# CONFIG_MMC is not set -+# CONFIG_MEMSTICK is not set -+# CONFIG_NEW_LEDS is not set -+# CONFIG_SWITCH is not set -+# CONFIG_ACCESSIBILITY is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+# CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set -+# CONFIG_UIO is not set -+ -+# -+# Virtio drivers -+# -+# CONFIG_VIRTIO_BALLOON is not set -+ -+# -+# Microsoft Hyper-V guest support -+# -+# CONFIG_STAGING is not set -+CONFIG_CLKDEV_LOOKUP=y -+ -+# -+# Hardware Spinlock drivers -+# -+# CONFIG_IOMMU_SUPPORT is not set -+ -+# -+# Remoteproc drivers (EXPERIMENTAL) -+# -+ -+# -+# Rpmsg drivers (EXPERIMENTAL) -+# -+# CONFIG_VIRT_DRIVERS is not set -+# CONFIG_PM_DEVFREQ is not set -+ -+# -+# File systems -+# -+# CONFIG_EXT2_FS is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4_FS is not set -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_FS_POSIX_ACL is not set -+# CONFIG_FILE_LOCKING is not set -+# CONFIG_FSNOTIFY is not set -+# CONFIG_DNOTIFY is not set -+# CONFIG_INOTIFY_USER is not set -+# CONFIG_FANOTIFY is not set -+# CONFIG_QUOTA is not set -+# CONFIG_QUOTACTL is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+# CONFIG_MSDOS_FS is not set -+# CONFIG_VFAT_FS is not set -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_PROC_PAGE_MONITOR=y -+CONFIG_SYSFS=y -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+CONFIG_MISC_FILESYSTEMS=y -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_YAFFS_FS is not set -+CONFIG_JFFS2_FS=y -+CONFIG_JFFS2_FS_DEBUG=0 -+CONFIG_JFFS2_FS_WRITEBUFFER=y -+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set -+CONFIG_JFFS2_COMPRESSION_OPTIONS=y -+# CONFIG_JFFS2_ZLIB is not set -+# CONFIG_JFFS2_LZO is not set -+# CONFIG_JFFS2_RTIME is not set -+# CONFIG_JFFS2_RUBIN is not set -+CONFIG_JFFS2_CMODE_NONE=y -+# CONFIG_JFFS2_CMODE_PRIORITY is not set -+# CONFIG_JFFS2_CMODE_SIZE is not set -+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_SQUASHFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_OMFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_QNX6FS_FS is not set -+# CONFIG_ROMFS_FS is not set -+# CONFIG_PSTORE is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="utf8" -+# CONFIG_NLS_CODEPAGE_437 is not set -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+# CONFIG_NLS_CODEPAGE_936 is not set -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+# CONFIG_NLS_ISO8859_1 is not set -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+CONFIG_NLS_UTF8=y -+ -+# -+# Kernel hacking -+# -+# CONFIG_PRINTK_TIME is not set -+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_FRAME_WARN=1024 -+# CONFIG_MAGIC_SYSRQ is not set -+# CONFIG_STRIP_ASM_SYMS is not set -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_SECTION_MISMATCH is not set -+CONFIG_DEBUG_KERNEL=y -+# CONFIG_DEBUG_SHIRQ is not set -+# CONFIG_LOCKUP_DETECTOR is not set -+# CONFIG_HARDLOCKUP_DETECTOR_NMI is not set -+# CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU is not set -+# CONFIG_HARDLOCKUP_DETECTOR is not set -+# CONFIG_DETECT_HUNG_TASK is not set -+# CONFIG_SCHED_DEBUG is not set -+# CONFIG_SCHEDSTATS is not set -+# CONFIG_TIMER_STATS is not set -+# CONFIG_DEBUG_OBJECTS is not set -+# CONFIG_SLUB_STATS is not set -+# CONFIG_DEBUG_RT_MUTEXES is not set -+# CONFIG_RT_MUTEX_TESTER is not set -+# CONFIG_DEBUG_SPINLOCK is not set -+# CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_SPARSE_RCU_POINTER is not set -+# CONFIG_LOCK_STAT is not set -+# CONFIG_DEBUG_ATOMIC_SLEEP is not set -+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -+# CONFIG_STACKTRACE is not set -+# CONFIG_DEBUG_STACK_USAGE is not set -+# CONFIG_DEBUG_KOBJECT is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_DEBUG_INFO is not set -+# CONFIG_DEBUG_VM is not set -+# CONFIG_DEBUG_WRITECOUNT is not set -+# CONFIG_DEBUG_MEMORY_INIT is not set -+# CONFIG_DEBUG_LIST is not set -+# CONFIG_TEST_LIST_SORT is not set -+# CONFIG_DEBUG_SG is not set -+# CONFIG_DEBUG_NOTIFIERS is not set -+# CONFIG_DEBUG_CREDENTIALS is not set -+CONFIG_FRAME_POINTER=y -+# CONFIG_BOOT_PRINTK_DELAY is not set -+# CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_RCU_TRACE is not set -+# CONFIG_BACKTRACE_SELF_TEST is not set -+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -+# CONFIG_FAULT_INJECTION is not set -+# CONFIG_LATENCYTOP is not set -+# CONFIG_DEBUG_PAGEALLOC is not set -+CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -+CONFIG_HAVE_DYNAMIC_FTRACE=y -+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_HAVE_C_RECORDMCOUNT=y -+CONFIG_TRACING_SUPPORT=y -+# CONFIG_FTRACE is not set -+# CONFIG_DMA_API_DEBUG is not set -+# CONFIG_ATOMIC64_SELFTEST is not set -+# CONFIG_SAMPLES is not set -+CONFIG_HAVE_ARCH_KGDB=y -+# CONFIG_TEST_KSTRTOX is not set -+# CONFIG_STRICT_DEVMEM is not set -+# CONFIG_DEBUG_USER is not set -+# CONFIG_DEBUG_RODATA is not set -+# CONFIG_DEBUG_LL is not set -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY_DMESG_RESTRICT is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITYFS is not set -+CONFIG_DEFAULT_SECURITY_DAC=y -+CONFIG_DEFAULT_SECURITY="" -+# CONFIG_CRYPTO is not set -+# CONFIG_BINARY_PRINTF is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+CONFIG_GENERIC_PCI_IOMAP=y -+CONFIG_GENERIC_IO=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=y -+CONFIG_CRC_T10DIF=y -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC32_SELFTEST is not set -+CONFIG_CRC32_SLICEBY8=y -+# CONFIG_CRC32_SLICEBY4 is not set -+# CONFIG_CRC32_SARWATE is not set -+# CONFIG_CRC32_BIT is not set -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+# CONFIG_CRC8 is not set -+CONFIG_ZLIB_INFLATE=y -+# CONFIG_XZ_DEC is not set -+# CONFIG_XZ_DEC_BCJ is not set -+CONFIG_DECOMPRESS_GZIP=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -+CONFIG_GENERIC_ATOMIC64=y -+# CONFIG_AVERAGE is not set -+# CONFIG_CORDIC is not set -diff --git a/arch/arm/configs/ak39_sdk3910_defconfig b/arch/arm/configs/ak39_sdk3910_defconfig -new file mode 100644 -index 00000000..2c051bc0 ---- /dev/null -+++ b/arch/arm/configs/ak39_sdk3910_defconfig -@@ -0,0 +1,1920 @@ -+# -+# Automatically generated file; DO NOT EDIT. -+# Linux/arm 3.4.35 Kernel Configuration -+# -+CONFIG_ARM=y -+CONFIG_SYS_SUPPORTS_APM_EMULATION=y -+CONFIG_GENERIC_GPIO=y -+CONFIG_ARCH_USES_GETTIMEOFFSET=y -+CONFIG_KTIME_SCALAR=y -+CONFIG_HAVE_PROC_CPU=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_HAVE_LATENCYTOP_SUPPORT=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+CONFIG_HARDIRQS_SW_RESEND=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+CONFIG_ARCH_HAS_CPUFREQ=y -+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_NEED_DMA_MAP_STATE=y -+CONFIG_VECTORS_BASE=0xffff0000 -+# CONFIG_ARM_PATCH_PHYS_VIRT is not set -+CONFIG_PHYS_OFFSET=0x81000000 -+CONFIG_GENERIC_BUG=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+CONFIG_HAVE_IRQ_WORK=y -+CONFIG_IRQ_WORK=y -+ -+# -+# General setup -+# -+# CONFIG_EXPERIMENTAL is not set -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_CROSS_COMPILE="" -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_HAVE_KERNEL_GZIP=y -+CONFIG_HAVE_KERNEL_LZMA=y -+CONFIG_HAVE_KERNEL_XZ=y -+CONFIG_HAVE_KERNEL_LZO=y -+CONFIG_KERNEL_GZIP=y -+# CONFIG_KERNEL_LZMA is not set -+# CONFIG_KERNEL_XZ is not set -+# CONFIG_KERNEL_LZO is not set -+CONFIG_DEFAULT_HOSTNAME="(none)" -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+CONFIG_BSD_PROCESS_ACCT=y -+CONFIG_BSD_PROCESS_ACCT_V3=y -+CONFIG_FHANDLE=y -+# CONFIG_TASKSTATS is not set -+# CONFIG_AUDIT is not set -+CONFIG_HAVE_GENERIC_HARDIRQS=y -+ -+# -+# IRQ subsystem -+# -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_SHOW=y -+ -+# -+# RCU Subsystem -+# -+CONFIG_TINY_RCU=y -+# CONFIG_PREEMPT_RCU is not set -+# CONFIG_TREE_RCU_TRACE is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=16 -+# CONFIG_CGROUPS is not set -+# CONFIG_CHECKPOINT_RESTORE is not set -+CONFIG_NAMESPACES=y -+CONFIG_UTS_NS=y -+CONFIG_IPC_NS=y -+CONFIG_PID_NS=y -+CONFIG_NET_NS=y -+# CONFIG_SCHED_AUTOGROUP is not set -+# CONFIG_SYSFS_DEPRECATED is not set -+# CONFIG_RELAY is not set -+CONFIG_BLK_DEV_INITRD=y -+CONFIG_INITRAMFS_SOURCE="../targetfs/rootfs/rootfs.initramfs" -+CONFIG_INITRAMFS_ROOT_UID=0 -+CONFIG_INITRAMFS_ROOT_GID=0 -+CONFIG_RD_GZIP=y -+# CONFIG_RD_BZIP2 is not set -+# CONFIG_RD_LZMA is not set -+# CONFIG_RD_XZ is not set -+# CONFIG_RD_LZO is not set -+CONFIG_INITRAMFS_COMPRESSION_NONE=y -+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_ANON_INODES=y -+CONFIG_PANIC_TIMEOUT=0 -+CONFIG_EXPERT=y -+CONFIG_UID16=y -+# CONFIG_SYSCTL_SYSCALL is not set -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_ALL 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_SIGNALFD=y -+CONFIG_TIMERFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_AIO=y -+CONFIG_EMBEDDED=y -+CONFIG_HAVE_PERF_EVENTS=y -+CONFIG_PERF_USE_VMALLOC=y -+ -+# -+# Kernel Performance Events And Counters -+# -+CONFIG_PERF_EVENTS=y -+# CONFIG_PERF_COUNTERS is not set -+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLUB_DEBUG=y -+CONFIG_COMPAT_BRK=y -+# CONFIG_SLAB is not set -+CONFIG_SLUB=y -+# CONFIG_SLOB is not set -+# CONFIG_PROFILING is not set -+CONFIG_HAVE_OPROFILE=y -+# CONFIG_KPROBES is not set -+CONFIG_JUMP_LABEL=y -+CONFIG_HAVE_KPROBES=y -+CONFIG_HAVE_KRETPROBES=y -+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -+CONFIG_HAVE_CLK=y -+CONFIG_HAVE_DMA_API_DEBUG=y -+CONFIG_HAVE_ARCH_JUMP_LABEL=y -+ -+# -+# GCOV-based kernel profiling -+# -+# CONFIG_GCOV_KERNEL is not set -+CONFIG_HAVE_GENERIC_DMA_COHERENT=y -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_FORCE_LOAD=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODVERSIONS is not set -+# CONFIG_MODULE_SRCVERSION_ALL is not set -+CONFIG_BLOCK=y -+CONFIG_LBDAF=y -+CONFIG_BLK_DEV_BSG=y -+CONFIG_BLK_DEV_BSGLIB=y -+CONFIG_BLK_DEV_INTEGRITY=y -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+# CONFIG_DEFAULT_DEADLINE is not set -+CONFIG_DEFAULT_CFQ=y -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="cfq" -+# CONFIG_INLINE_SPIN_TRYLOCK is not set -+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK is not set -+# CONFIG_INLINE_SPIN_LOCK_BH is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set -+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set -+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_READ_TRYLOCK is not set -+# CONFIG_INLINE_READ_LOCK is not set -+# CONFIG_INLINE_READ_LOCK_BH is not set -+# CONFIG_INLINE_READ_LOCK_IRQ is not set -+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -+CONFIG_INLINE_READ_UNLOCK=y -+# CONFIG_INLINE_READ_UNLOCK_BH is not set -+CONFIG_INLINE_READ_UNLOCK_IRQ=y -+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set -+# CONFIG_INLINE_WRITE_TRYLOCK is not set -+# CONFIG_INLINE_WRITE_LOCK is not set -+# CONFIG_INLINE_WRITE_LOCK_BH is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set -+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -+CONFIG_INLINE_WRITE_UNLOCK=y -+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set -+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -+# CONFIG_MUTEX_SPIN_ON_OWNER is not set -+CONFIG_FREEZER=y -+ -+# -+# System Type -+# -+CONFIG_MMU=y -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_REALVIEW is not set -+# CONFIG_ARCH_VERSATILE is not set -+# CONFIG_ARCH_VEXPRESS is not set -+# CONFIG_ARCH_AT91 is not set -+# CONFIG_ARCH_BCMRING is not set -+# CONFIG_ARCH_HIGHBANK is not set -+# CONFIG_ARCH_CLPS711X is not set -+# CONFIG_ARCH_CNS3XXX is not set -+# CONFIG_ARCH_GEMINI is not set -+# CONFIG_ARCH_PRIMA2 is not set -+# CONFIG_ARCH_EBSA110 is not set -+# CONFIG_ARCH_EP93XX is not set -+# CONFIG_ARCH_FOOTBRIDGE is not set -+# CONFIG_ARCH_MXC is not set -+# CONFIG_ARCH_MXS is not set -+# CONFIG_ARCH_NETX is not set -+# CONFIG_ARCH_H720X is not set -+# CONFIG_ARCH_IOP13XX is not set -+# CONFIG_ARCH_IOP32X is not set -+# CONFIG_ARCH_IOP33X is not set -+# CONFIG_ARCH_IXP23XX is not set -+# CONFIG_ARCH_IXP2000 is not set -+# CONFIG_ARCH_IXP4XX is not set -+# CONFIG_ARCH_DOVE is not set -+# CONFIG_ARCH_KIRKWOOD is not set -+# CONFIG_ARCH_LPC32XX is not set -+# CONFIG_ARCH_MV78XX0 is not set -+# CONFIG_ARCH_ORION5X is not set -+# CONFIG_ARCH_MMP is not set -+# CONFIG_ARCH_KS8695 is not set -+# CONFIG_ARCH_W90X900 is not set -+# CONFIG_ARCH_TEGRA is not set -+# CONFIG_ARCH_PICOXCELL is not set -+# CONFIG_ARCH_PNX4008 is not set -+# CONFIG_ARCH_PXA is not set -+# CONFIG_ARCH_MSM is not set -+# CONFIG_ARCH_SHMOBILE is not set -+# CONFIG_ARCH_RPC is not set -+# CONFIG_ARCH_SA1100 is not set -+# CONFIG_ARCH_S3C24XX is not set -+# CONFIG_ARCH_S3C64XX is not set -+# CONFIG_ARCH_S5P64X0 is not set -+# CONFIG_ARCH_S5PC100 is not set -+# CONFIG_ARCH_S5PV210 is not set -+# CONFIG_ARCH_EXYNOS is not set -+# CONFIG_ARCH_SHARK is not set -+# CONFIG_ARCH_U300 is not set -+# CONFIG_ARCH_U8500 is not set -+# CONFIG_ARCH_NOMADIK is not set -+# CONFIG_ARCH_DAVINCI is not set -+# CONFIG_ARCH_OMAP is not set -+# CONFIG_PLAT_SPEAR is not set -+# CONFIG_ARCH_VT8500 is not set -+# CONFIG_ARCH_ZYNQ is not set -+CONFIG_ARCH_AK39=y -+# CONFIG_GPIO_PCA953X is not set -+ -+# -+# System MMU -+# -+CONFIG_CPU_AK3910=y -+CONFIG_ARCH_SDK3910=y -+# CONFIG_ARCH_AIMER39_AK3916 is not set -+CONFIG_ASIC_FREQ_VALUE=90000000 -+ -+# -+# Power management -+# -+# CONFIG_AK39_PM is not set -+# CONFIG_AK39_PWM is not set -+CONFIG_PLAT_ANYKA=y -+ -+# -+# Processor Type -+# -+CONFIG_CPU_ARM926T=y -+CONFIG_CPU_32v5=y -+CONFIG_CPU_ABRT_EV5TJ=y -+CONFIG_CPU_PABRT_LEGACY=y -+CONFIG_CPU_CACHE_VIVT=y -+CONFIG_CPU_COPY_V4WB=y -+CONFIG_CPU_TLB_V4WBI=y -+CONFIG_CPU_CP15=y -+CONFIG_CPU_CP15_MMU=y -+CONFIG_CPU_USE_DOMAINS=y -+ -+# -+# Processor Features -+# -+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set -+CONFIG_ARM_THUMB=y -+# CONFIG_CPU_ICACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set -+# CONFIG_CACHE_L2X0 is not set -+CONFIG_ARM_L1_CACHE_SHIFT=5 -+CONFIG_ARM_NR_BANKS=8 -+# CONFIG_FIQ_DEBUGGER is not set -+ -+# -+# Bus support -+# -+# CONFIG_PCI_SYSCALL is not set -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_PCCARD=y -+CONFIG_PCMCIA=y -+ -+# -+# PC-card bridges -+# -+ -+# -+# Kernel Features -+# -+CONFIG_VMSPLIT_3G=y -+# CONFIG_VMSPLIT_2G is not set -+# CONFIG_VMSPLIT_1G is not set -+CONFIG_PAGE_OFFSET=0xC0000000 -+CONFIG_ARCH_NR_GPIO=0 -+CONFIG_PREEMPT_NONE=y -+# CONFIG_PREEMPT_VOLUNTARY is not set -+# CONFIG_PREEMPT is not set -+CONFIG_HZ=100 -+CONFIG_AEABI=y -+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set -+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set -+CONFIG_HAVE_ARCH_PFN_VALID=y -+# CONFIG_HIGHMEM is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+CONFIG_HAVE_MEMBLOCK=y -+CONFIG_PAGEFLAGS_EXTENDED=y -+CONFIG_SPLIT_PTLOCK_CPUS=999999 -+# CONFIG_COMPACTION is not set -+# CONFIG_PHYS_ADDR_T_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_KSM is not set -+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -+CONFIG_NEED_PER_CPU_KM=y -+# CONFIG_CLEANCACHE is not set -+CONFIG_FORCE_MAX_ZONEORDER=11 -+CONFIG_ALIGNMENT_TRAP=y -+# CONFIG_SECCOMP is not set -+# CONFIG_DEPRECATED_PARAM_STRUCT is not set -+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -+ -+# -+# Boot options -+# -+# CONFIG_USE_OF is not set -+CONFIG_ZBOOT_ROM_TEXT=0 -+CONFIG_ZBOOT_ROM_BSS=0 -+CONFIG_CMDLINE="mem=64M console=ttySAK0,115200" -+CONFIG_CMDLINE_FROM_BOOTLOADER=y -+# CONFIG_CMDLINE_EXTEND is not set -+# CONFIG_CMDLINE_FORCE is not set -+# CONFIG_XIP_KERNEL is not set -+# CONFIG_AUTO_ZRELADDR is not set -+CONFIG_RAM_BASE=0x80000000 -+CONFIG_VIDEO_RESERVED_MEM_SIZE=0x1000000 -+ -+# -+# CPU Power Management -+# -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ is not set -+CONFIG_CPU_IDLE=y -+CONFIG_CPU_IDLE_GOV_LADDER=y -+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set -+ -+# -+# Floating point emulation -+# -+ -+# -+# At least one emulation must be selected -+# -+CONFIG_VFP=y -+ -+# -+# Userspace binary formats -+# -+CONFIG_BINFMT_ELF=y -+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y -+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -+CONFIG_HAVE_AOUT=y -+# CONFIG_BINFMT_AOUT is not set -+# CONFIG_BINFMT_MISC is not set -+ -+# -+# Power management options -+# -+CONFIG_SUSPEND=y -+CONFIG_SUSPEND_FREEZER=y -+CONFIG_HAS_WAKELOCK=y -+CONFIG_WAKELOCK=y -+CONFIG_PM_SLEEP=y -+# CONFIG_PM_AUTOSLEEP is not set -+# CONFIG_PM_WAKELOCKS is not set -+# CONFIG_PM_RUNTIME is not set -+CONFIG_PM=y -+# CONFIG_PM_DEBUG is not set -+# CONFIG_APM_EMULATION is not set -+CONFIG_PM_CLK=y -+CONFIG_CPU_PM=y -+# CONFIG_SUSPEND_TIME is not set -+CONFIG_ARCH_SUSPEND_POSSIBLE=y -+CONFIG_ARM_CPU_SUSPEND=y -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+CONFIG_UNIX=y -+CONFIG_UNIX_DIAG=y -+CONFIG_XFRM=y -+# CONFIG_XFRM_USER is not set -+CONFIG_NET_KEY=y -+CONFIG_INET=y -+CONFIG_IP_MULTICAST=y -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+CONFIG_IP_PNP_RARP=y -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE_DEMUX is not set -+# CONFIG_IP_MROUTE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+CONFIG_INET_XFRM_MODE_TRANSPORT=y -+CONFIG_INET_XFRM_MODE_TUNNEL=y -+CONFIG_INET_XFRM_MODE_BEET=y -+CONFIG_INET_LRO=y -+CONFIG_INET_DIAG=y -+CONFIG_INET_TCP_DIAG=y -+CONFIG_INET_UDP_DIAG=y -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_IPV6 is not set -+CONFIG_ANDROID_PARANOID_NETWORK=y -+CONFIG_NET_ACTIVITY_STATS=y -+# CONFIG_NETWORK_SECMARK is not set -+CONFIG_NETFILTER=y -+# CONFIG_NETFILTER_DEBUG is not set -+CONFIG_NETFILTER_ADVANCED=y -+ -+# -+# Core Netfilter Configuration -+# -+# CONFIG_NETFILTER_NETLINK_ACCT is not set -+# CONFIG_NETFILTER_NETLINK_QUEUE is not set -+# CONFIG_NETFILTER_NETLINK_LOG is not set -+# CONFIG_NF_CONNTRACK is not set -+# CONFIG_NETFILTER_XTABLES is not set -+# CONFIG_IP_VS is not set -+ -+# -+# IP: Netfilter Configuration -+# -+# CONFIG_NF_DEFRAG_IPV4 is not set -+# CONFIG_IP_NF_QUEUE is not set -+# CONFIG_IP_NF_IPTABLES is not set -+# CONFIG_IP_NF_ARPTABLES is not set -+# CONFIG_ATM is not set -+# CONFIG_L2TP 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_PHONET is not set -+# CONFIG_NET_SCHED is not set -+# CONFIG_DCB is not set -+# CONFIG_BATMAN_ADV is not set -+# CONFIG_OPENVSWITCH is not set -+CONFIG_BQL=y -+CONFIG_HAVE_BPF_JIT=y -+# CONFIG_BPF_JIT is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_CAN is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+CONFIG_WIRELESS=y -+CONFIG_WIRELESS_EXT=y -+CONFIG_WEXT_CORE=y -+CONFIG_WEXT_PROC=y -+CONFIG_WEXT_SPY=y -+CONFIG_WEXT_PRIV=y -+CONFIG_CFG80211=y -+# CONFIG_NL80211_TESTMODE is not set -+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -+# CONFIG_CFG80211_REG_DEBUG is not set -+CONFIG_CFG80211_DEFAULT_PS=y -+# CONFIG_CFG80211_DEBUGFS is not set -+# CONFIG_CFG80211_INTERNAL_REGDB is not set -+CONFIG_CFG80211_WEXT=y -+CONFIG_WIRELESS_EXT_SYSFS=y -+CONFIG_LIB80211=y -+# CONFIG_LIB80211_DEBUG is not set -+CONFIG_CFG80211_ALLOW_RECONNECT=y -+CONFIG_MAC80211=y -+CONFIG_MAC80211_HAS_RC=y -+# CONFIG_MAC80211_RC_PID is not set -+CONFIG_MAC80211_RC_MINSTREL=y -+CONFIG_MAC80211_RC_MINSTREL_HT=y -+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -+# CONFIG_MAC80211_LEDS is not set -+# CONFIG_MAC80211_DEBUGFS is not set -+# CONFIG_MAC80211_DEBUG_MENU is not set -+# CONFIG_WIMAX is not set -+CONFIG_RFKILL=y -+CONFIG_RFKILL_PM=y -+CONFIG_RFKILL_LEDS=y -+# CONFIG_RFKILL_INPUT is not set -+# CONFIG_RFKILL_GPIO is not set -+# CONFIG_NET_9P is not set -+# CONFIG_CAIF is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_DEVTMPFS=y -+CONFIG_DEVTMPFS_MOUNT=y -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+CONFIG_FW_LOADER=y -+CONFIG_FIRMWARE_IN_KERNEL=y -+CONFIG_EXTRA_FIRMWARE="" -+# CONFIG_DEBUG_DRIVER is not set -+# CONFIG_DEBUG_DEVRES is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_GENERIC_CPU_DEVICES is not set -+CONFIG_DMA_SHARED_BUFFER=y -+CONFIG_SYNC=y -+CONFIG_SW_SYNC=y -+# CONFIG_SW_SYNC_USER is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_TESTS is not set -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+# CONFIG_MTD_AFS_PARTS is not set -+# CONFIG_MTD_AR7_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+# CONFIG_MTD_SWAP is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SST25L 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_DOCG3 is not set -+CONFIG_MTD_AK_SPIFLASH=y -+# CONFIG_MTD_NAND_IDS is not set -+# CONFIG_MTD_NAND is not set -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# LPDDR flash memory drivers -+# -+# CONFIG_MTD_LPDDR is not set -+# CONFIG_MTD_UBI is not set -+# CONFIG_PARPORT is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+ -+# -+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected -+# -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+# CONFIG_BLK_DEV_XIP is not set -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+# CONFIG_MG_DISK is not set -+ -+# -+# Misc devices -+# -+# CONFIG_SENSORS_LIS3LV02D is not set -+# CONFIG_AD525X_DPOT is not set -+# CONFIG_ATMEL_PWM is not set -+# CONFIG_ENCLOSURE_SERVICES is not set -+# CONFIG_APDS9802ALS is not set -+# CONFIG_ISL29003 is not set -+# CONFIG_ISL29020 is not set -+# CONFIG_SENSORS_TSL2550 is not set -+# CONFIG_SENSORS_BH1780 is not set -+# CONFIG_SENSORS_BH1770 is not set -+# CONFIG_SENSORS_APDS990X is not set -+# CONFIG_HMC6352 is not set -+# CONFIG_SENSORS_AK8975 is not set -+# CONFIG_TI_DAC7512 is not set -+# CONFIG_UID_STAT is not set -+# CONFIG_BMP085 is not set -+# CONFIG_USB_SWITCH_FSA9480 is not set -+# CONFIG_WL127X_RFKILL is not set -+ -+# -+# EEPROM support -+# -+# CONFIG_EEPROM_AT24 is not set -+# CONFIG_EEPROM_AT25 is not set -+# CONFIG_EEPROM_LEGACY is not set -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_EEPROM_93XX46 is not set -+ -+# -+# Texas Instruments shared transport line discipline -+# -+# CONFIG_TI_ST is not set -+# CONFIG_SENSORS_LIS3_SPI is not set -+# CONFIG_SENSORS_LIS3_I2C is not set -+ -+# -+# Altera FPGA firmware download module -+# -+# CONFIG_ALTERA_STAPL is not set -+CONFIG_HAVE_IDE=y -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+CONFIG_SCSI_MOD=y -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_SCSI_PROC_FS is not set -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+# CONFIG_SCSI_LOWLEVEL is not set -+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set -+# CONFIG_SCSI_DH is not set -+# CONFIG_SCSI_OSD_INITIATOR is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_TARGET_CORE is not set -+CONFIG_NETDEVICES=y -+CONFIG_NET_CORE=y -+# CONFIG_BONDING is not set -+# CONFIG_DUMMY is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_MII is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+# CONFIG_ARCNET is not set -+ -+# -+# CAIF transport drivers -+# -+CONFIG_ETHERNET=y -+# CONFIG_NET_VENDOR_3COM is not set -+# CONFIG_NET_VENDOR_AMD is not set -+# CONFIG_NET_VENDOR_BROADCOM is not set -+# CONFIG_NET_CALXEDA_XGMAC is not set -+# CONFIG_NET_VENDOR_CHELSIO is not set -+# CONFIG_NET_VENDOR_CIRRUS is not set -+# CONFIG_DM9000 is not set -+# CONFIG_DNET is not set -+# CONFIG_NET_VENDOR_FARADAY is not set -+# CONFIG_NET_VENDOR_FUJITSU is not set -+# CONFIG_NET_VENDOR_INTEL is not set -+# CONFIG_NET_VENDOR_MARVELL is not set -+# CONFIG_NET_VENDOR_MICREL is not set -+# CONFIG_NET_VENDOR_NATSEMI is not set -+# CONFIG_ETHOC is not set -+# CONFIG_NET_VENDOR_SMSC is not set -+# CONFIG_NET_VENDOR_STMICRO is not set -+# CONFIG_NET_VENDOR_XIRCOM is not set -+CONFIG_AK_ETHERNET=y -+# CONFIG_PHYLIB is not set -+# CONFIG_MICREL_KS8995MA is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_TR is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_USB_HSO is not set -+# CONFIG_USB_IPHETH is not set -+CONFIG_WLAN=y -+CONFIG_PCMCIA_RAYCS=y -+# CONFIG_LIBERTAS_THINFIRM is not set -+# CONFIG_ATMEL is not set -+# CONFIG_AT76C50X_USB is not set -+# CONFIG_AIRO_CS is not set -+# CONFIG_USB_ZD1201 is not set -+# CONFIG_RTL8187 is not set -+# CONFIG_MAC80211_HWSIM is not set -+# CONFIG_WIFI_CONTROL_FUNC is not set -+# CONFIG_ATH_COMMON is not set -+# CONFIG_B43 is not set -+# CONFIG_B43LEGACY is not set -+# CONFIG_BCMDHD is not set -+# CONFIG_BRCMFMAC is not set -+# CONFIG_HOSTAP is not set -+# CONFIG_LIBERTAS is not set -+# CONFIG_HERMES is not set -+# CONFIG_RT2X00 is not set -+# CONFIG_MWIFIEX is not set -+ -+# -+# Enable WiMAX (Networking options) to see the WiMAX drivers -+# -+CONFIG_WAN=y -+# CONFIG_HDLC is not set -+# CONFIG_DLCI is not set -+# CONFIG_ISDN is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+# CONFIG_INPUT_SPARSEKMAP is not set -+ -+# -+# Userland interfaces -+# -+# CONFIG_INPUT_MOUSEDEV is not set -+# CONFIG_INPUT_JOYDEV is not set -+# CONFIG_INPUT_EVDEV is not set -+# CONFIG_INPUT_EVBUG is not set -+# CONFIG_INPUT_KEYRESET is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+# CONFIG_SERIO is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_CONSOLE_TRANSLATIONS=y -+CONFIG_VT_CONSOLE=y -+CONFIG_VT_CONSOLE_SLEEP=y -+CONFIG_HW_CONSOLE=y -+# CONFIG_VT_HW_CONSOLE_BINDING is not set -+CONFIG_UNIX98_PTYS=y -+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set -+# CONFIG_LEGACY_PTYS is not set -+# CONFIG_SERIAL_NONSTANDARD is not set -+# CONFIG_TRACE_SINK is not set -+CONFIG_DEVMEM=y -+CONFIG_DEVKMEM=y -+ -+# -+# Serial drivers -+# -+# CONFIG_SERIAL_8250 is not set -+ -+# -+# Non-8250 serial port support -+# -+# CONFIG_SERIAL_MAX3100 is not set -+# CONFIG_SERIAL_MAX3107 is not set -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_SERIAL_TIMBERDALE is not set -+# CONFIG_SERIAL_ALTERA_JTAGUART is not set -+# CONFIG_SERIAL_ALTERA_UART is not set -+# CONFIG_SERIAL_XILINX_PS_UART is not set -+CONFIG_SERIAL_AK39_UART=y -+CONFIG_SERIAL_AK39_CONSOLE=y -+CONFIG_TTY_PRINTK=y -+# CONFIG_HVC_DCC is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_R3964 is not set -+ -+# -+# PCMCIA character devices -+# -+# CONFIG_SYNCLINK_CS is not set -+# CONFIG_CARDMAN_4000 is not set -+# CONFIG_CARDMAN_4040 is not set -+# CONFIG_IPWIRELESS is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+# CONFIG_DCC_TTY is not set -+# CONFIG_RAMOOPS is not set -+CONFIG_I2C=y -+CONFIG_I2C_BOARDINFO=y -+CONFIG_I2C_COMPAT=y -+# CONFIG_I2C_CHARDEV is not set -+# CONFIG_I2C_HELPER_AUTO is not set -+CONFIG_I2C_SMBUS=y -+ -+# -+# I2C Algorithms -+# -+CONFIG_I2C_ALGOBIT=y -+# CONFIG_I2C_ALGOPCF is not set -+# CONFIG_I2C_ALGOPCA is not set -+ -+# -+# I2C Hardware Bus support -+# -+ -+# -+# I2C system bus drivers (mostly embedded / system-on-chip) -+# -+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set -+# CONFIG_I2C_GPIO is not set -+# CONFIG_I2C_PCA_PLATFORM is not set -+# CONFIG_I2C_PXA_PCI is not set -+# CONFIG_I2C_SIMTEC is not set -+CONFIG_I2C_ANYKA=y -+CONFIG_I2C_AK39_HW=y -+# CONFIG_I2C_GPIO_SOFT is not set -+ -+# -+# External I2C/SMBus adapter drivers -+# -+# CONFIG_I2C_DIOLAN_U2C is not set -+# CONFIG_I2C_PARPORT_LIGHT is not set -+# CONFIG_I2C_TINY_USB is not set -+ -+# -+# Other I2C/SMBus bus drivers -+# -+# CONFIG_I2C_DEBUG_CORE is not set -+# CONFIG_I2C_DEBUG_ALGO is not set -+# CONFIG_I2C_DEBUG_BUS is not set -+CONFIG_SPI=y -+# CONFIG_SPI_DEBUG is not set -+CONFIG_SPI_MASTER=y -+ -+# -+# SPI Master Controller Drivers -+# -+# CONFIG_SPI_ALTERA is not set -+CONFIG_SPI_BITBANG=y -+# CONFIG_SPI_GPIO is not set -+# CONFIG_SPI_OC_TINY is not set -+# CONFIG_SPI_PXA2XX_PCI is not set -+CONFIG_SPI_ANYKA=y -+# CONFIG_SPI_DESIGNWARE is not set -+ -+# -+# SPI Protocol Masters -+# -+# CONFIG_SPI_TLE62X0 is not set -+# CONFIG_HSI is not set -+ -+# -+# PPS support -+# -+ -+# -+# PPS generators support -+# -+ -+# -+# PTP clock support -+# -+ -+# -+# Enable Device Drivers -> PPS to see the PTP clock options. -+# -+CONFIG_ARCH_REQUIRE_GPIOLIB=y -+CONFIG_GPIOLIB=y -+# CONFIG_DEBUG_GPIO is not set -+ -+# -+# Memory mapped GPIO drivers: -+# -+# CONFIG_GPIO_GENERIC_PLATFORM is not set -+ -+# -+# I2C GPIO expanders: -+# -+# CONFIG_GPIO_MAX7300 is not set -+# CONFIG_GPIO_MAX732X is not set -+# CONFIG_GPIO_PCF857X is not set -+# CONFIG_GPIO_SX150X is not set -+# CONFIG_GPIO_ADP5588 is not set -+ -+# -+# PCI GPIO expanders: -+# -+ -+# -+# SPI GPIO expanders: -+# -+# CONFIG_GPIO_MAX7301 is not set -+# CONFIG_GPIO_MCP23S08 is not set -+# CONFIG_GPIO_MC33880 is not set -+# CONFIG_GPIO_74X164 is not set -+ -+# -+# AC97 GPIO expanders: -+# -+ -+# -+# MODULbus GPIO expanders: -+# -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+# CONFIG_THERMAL is not set -+# CONFIG_WATCHDOG is not set -+CONFIG_SSB_POSSIBLE=y -+ -+# -+# Sonics Silicon Backplane -+# -+# CONFIG_SSB is not set -+CONFIG_BCMA_POSSIBLE=y -+ -+# -+# Broadcom specific AMBA -+# -+# CONFIG_BCMA is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_CORE is not set -+# CONFIG_MFD_88PM860X is not set -+# CONFIG_MFD_SM501 is not set -+# CONFIG_MFD_ASIC3 is not set -+# CONFIG_HTC_EGPIO is not set -+# CONFIG_HTC_PASIC3 is not set -+# CONFIG_HTC_I2CPLD is not set -+# CONFIG_TPS6105X is not set -+# CONFIG_TPS65010 is not set -+# CONFIG_TPS6507X is not set -+# CONFIG_MFD_TPS65217 is not set -+# CONFIG_MFD_TPS6586X is not set -+# CONFIG_MFD_TPS65910 is not set -+# CONFIG_MFD_TPS65912_I2C is not set -+# CONFIG_MFD_TPS65912_SPI is not set -+# CONFIG_TWL4030_CORE is not set -+# CONFIG_TWL6040_CORE is not set -+# CONFIG_MFD_STMPE is not set -+# CONFIG_MFD_TC3589X is not set -+# CONFIG_MFD_TMIO is not set -+# CONFIG_MFD_T7L66XB is not set -+# CONFIG_MFD_TC6387XB is not set -+# CONFIG_MFD_TC6393XB is not set -+# CONFIG_PMIC_DA903X is not set -+# CONFIG_MFD_DA9052_SPI is not set -+# CONFIG_MFD_DA9052_I2C is not set -+# CONFIG_PMIC_ADP5520 is not set -+# CONFIG_MFD_MAX8925 is not set -+# CONFIG_MFD_MAX8997 is not set -+# CONFIG_MFD_MAX8998 is not set -+# CONFIG_MFD_S5M_CORE is not set -+# CONFIG_MFD_WM8400 is not set -+# CONFIG_MFD_WM831X_I2C is not set -+# CONFIG_MFD_WM831X_SPI is not set -+# CONFIG_MFD_WM8350_I2C is not set -+# CONFIG_MFD_WM8994 is not set -+# CONFIG_MFD_PCF50633 is not set -+# CONFIG_MFD_MC13XXX is not set -+# CONFIG_ABX500_CORE is not set -+# CONFIG_EZX_PCAP is not set -+# CONFIG_MFD_WL1273_CORE is not set -+# CONFIG_MFD_TPS65090 is not set -+# CONFIG_MFD_AAT2870_CORE is not set -+# CONFIG_MFD_RC5T583 is not set -+# CONFIG_REGULATOR is not set -+CONFIG_MEDIA_SUPPORT=y -+ -+# -+# Multimedia core support -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L2_COMMON=y -+# CONFIG_DVB_CORE is not set -+CONFIG_VIDEO_MEDIA=y -+ -+# -+# Multimedia drivers -+# -+# CONFIG_RC_CORE is not set -+# CONFIG_MEDIA_ATTACH is not set -+CONFIG_MEDIA_TUNER=y -+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set -+CONFIG_MEDIA_TUNER_SIMPLE=y -+CONFIG_MEDIA_TUNER_TDA8290=y -+CONFIG_MEDIA_TUNER_TDA827X=y -+CONFIG_MEDIA_TUNER_TDA18271=y -+CONFIG_MEDIA_TUNER_TDA9887=y -+CONFIG_MEDIA_TUNER_TEA5767=y -+CONFIG_MEDIA_TUNER_MT20XX=y -+CONFIG_MEDIA_TUNER_XC2028=y -+CONFIG_MEDIA_TUNER_XC5000=y -+CONFIG_MEDIA_TUNER_XC4000=y -+CONFIG_MEDIA_TUNER_MC44S803=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEOBUF_GEN=y -+CONFIG_VIDEOBUF_DMA_CONTIG=y -+CONFIG_VIDEOBUF2_CORE=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set -+ -+# -+# Encoders, decoders, sensors and other helper chips -+# -+ -+# -+# Audio decoders, processors and mixers -+# -+# CONFIG_VIDEO_TVAUDIO is not set -+# CONFIG_VIDEO_TDA7432 is not set -+# CONFIG_VIDEO_TDA9840 is not set -+# CONFIG_VIDEO_TEA6415C is not set -+# CONFIG_VIDEO_TEA6420 is not set -+# CONFIG_VIDEO_MSP3400 is not set -+# CONFIG_VIDEO_CS5345 is not set -+# CONFIG_VIDEO_CS53L32A is not set -+# CONFIG_VIDEO_WM8775 is not set -+# CONFIG_VIDEO_WM8739 is not set -+# CONFIG_VIDEO_VP27SMPX is not set -+ -+# -+# RDS decoders -+# -+# CONFIG_VIDEO_SAA6588 is not set -+ -+# -+# Video decoders -+# -+# CONFIG_VIDEO_ADV7180 is not set -+# CONFIG_VIDEO_ADV7183 is not set -+# CONFIG_VIDEO_BT819 is not set -+# CONFIG_VIDEO_BT856 is not set -+# CONFIG_VIDEO_BT866 is not set -+# CONFIG_VIDEO_KS0127 is not set -+# CONFIG_VIDEO_SAA7110 is not set -+# CONFIG_VIDEO_SAA711X is not set -+# CONFIG_VIDEO_SAA7191 is not set -+# CONFIG_VIDEO_TVP514X is not set -+# CONFIG_VIDEO_TVP5150 is not set -+# CONFIG_VIDEO_TVP7002 is not set -+# CONFIG_VIDEO_VPX3220 is not set -+ -+# -+# Video and audio decoders -+# -+# CONFIG_VIDEO_SAA717X is not set -+# CONFIG_VIDEO_CX25840 is not set -+ -+# -+# MPEG video encoders -+# -+# CONFIG_VIDEO_CX2341X is not set -+ -+# -+# Video encoders -+# -+# CONFIG_VIDEO_SAA7127 is not set -+# CONFIG_VIDEO_SAA7185 is not set -+# CONFIG_VIDEO_ADV7170 is not set -+# CONFIG_VIDEO_ADV7175 is not set -+# CONFIG_VIDEO_ADV7343 is not set -+# CONFIG_VIDEO_AK881X is not set -+ -+# -+# Camera sensor devices -+# -+# CONFIG_VIDEO_OV7670 is not set -+# CONFIG_VIDEO_VS6624 is not set -+# CONFIG_VIDEO_MT9V011 is not set -+# CONFIG_VIDEO_TCM825X is not set -+# CONFIG_VIDEO_SR030PC30 is not set -+ -+# -+# Flash devices -+# -+ -+# -+# Video improvement chips -+# -+# CONFIG_VIDEO_UPD64031A is not set -+# CONFIG_VIDEO_UPD64083 is not set -+ -+# -+# Miscelaneous helper chips -+# -+# CONFIG_VIDEO_THS7303 is not set -+# CONFIG_VIDEO_M52790 is not set -+# CONFIG_V4L_USB_DRIVERS is not set -+CONFIG_V4L_PLATFORM_DRIVERS=y -+CONFIG_SOC_CAMERA=y -+# CONFIG_SOC_CAMERA_IMX074 is not set -+# CONFIG_SOC_CAMERA_MT9M001 is not set -+# CONFIG_SOC_CAMERA_MT9M111 is not set -+# CONFIG_SOC_CAMERA_MT9T031 is not set -+# CONFIG_SOC_CAMERA_MT9T112 is not set -+# CONFIG_SOC_CAMERA_MT9V022 is not set -+# CONFIG_SOC_CAMERA_RJ54N1 is not set -+# CONFIG_SOC_CAMERA_TW9910 is not set -+# CONFIG_SOC_CAMERA_PLATFORM is not set -+# CONFIG_SOC_CAMERA_OV2640 is not set -+# CONFIG_SOC_CAMERA_OV5642 is not set -+# CONFIG_SOC_CAMERA_OV6650 is not set -+# CONFIG_SOC_CAMERA_OV772X is not set -+# CONFIG_SOC_CAMERA_OV9640 is not set -+# CONFIG_SOC_CAMERA_OV9740 is not set -+CONFIG_LINUX_AKSENSOR=y -+CONFIG_SENSOR_GC0308=y -+CONFIG_SENSOR_OV2643=y -+# CONFIG_SENSOR_OV7725 is not set -+# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set -+# CONFIG_VIDEO_SH_MOBILE_CEU is not set -+CONFIG_VIDEO_AK=y -+# CONFIG_V4L_MEM2MEM_DRIVERS is not set -+# CONFIG_RADIO_ADAPTERS is not set -+ -+# -+# Graphics support -+# -+# CONFIG_DRM is not set -+CONFIG_ION=y -+CONFIG_ION_AK=y -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_EXYNOS_VIDEO is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_SOUND=y -+# CONFIG_SOUND_OSS_CORE is not set -+CONFIG_SND=y -+CONFIG_SND_TIMER=y -+CONFIG_SND_PCM=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=y -+CONFIG_SND_VERBOSE_PROCFS=y -+# CONFIG_SND_VERBOSE_PRINTK is not set -+# CONFIG_SND_DEBUG is not set -+# CONFIG_SND_RAWMIDI_SEQ is not set -+# CONFIG_SND_OPL3_LIB_SEQ is not set -+# CONFIG_SND_OPL4_LIB_SEQ is not set -+# CONFIG_SND_SBAWE_SEQ is not set -+# CONFIG_SND_EMU10K1_SEQ is not set -+CONFIG_SND_DRIVERS=y -+# CONFIG_SND_DUMMY is not set -+# CONFIG_SND_ALOOP is not set -+# CONFIG_SND_MTPAV is not set -+# CONFIG_SND_SERIAL_U16550 is not set -+# CONFIG_SND_MPU401 is not set -+CONFIG_SND_ARM=y -+CONFIG_SND_AK_PCM=y -+CONFIG_CODEC_AK39=y -+CONFIG_SPKHP_SWITCH_AUTO=y -+# CONFIG_SPKHP_SWITCH_MIXER is not set -+# CONFIG_SPKHP_SWITCH_UEVENT is not set -+CONFIG_SND_SPI=y -+CONFIG_SND_USB=y -+# CONFIG_SND_USB_AUDIO is not set -+# CONFIG_SND_USB_UA101 is not set -+# CONFIG_SND_USB_CAIAQ is not set -+# CONFIG_SND_USB_6FIRE is not set -+CONFIG_SND_PCMCIA=y -+# CONFIG_SND_VXPOCKET is not set -+# CONFIG_SND_PDAUDIOCF is not set -+# CONFIG_SND_SOC is not set -+# CONFIG_SOUND_PRIME is not set -+# CONFIG_HID_SUPPORT is not set -+# CONFIG_USB_ARCH_HAS_OHCI is not set -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB_ARCH_HAS_XHCI is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_COMMON=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+# CONFIG_USB_DEVICE_CLASS is not set -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_OTG_WHITELIST is not set -+# CONFIG_USB_OTG_BLACKLIST_HUB is not set -+# CONFIG_USB_DWC3 is not set -+# CONFIG_USB_MON is not set -+# CONFIG_USB_WUSB_CBAF is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_C67X00_HCD is not set -+# CONFIG_USB_OXU210HP_HCD is not set -+# CONFIG_USB_ISP116X_HCD is not set -+# CONFIG_USB_ISP1362_HCD is not set -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+CONFIG_USB_ANYKA_HCD=y -+CONFIG_USB_AKOTG_HS_HCD=m -+# CONFIG_USB_AKOTG_DMA is not set -+# CONFIG_USB_MUSB_HDRC is not set -+# CONFIG_USB_RENESAS_USBHS is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+# CONFIG_USB_WDM is not set -+# CONFIG_USB_TMC is not set -+ -+# -+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -+# -+ -+# -+# also be needed; see USB_STORAGE Help for more info -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_REALTEK is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_ONETOUCH is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set -+# CONFIG_USB_STORAGE_ENE_UB6250 is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+ -+# -+# USB port drivers -+# -+# 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_SEVSEG 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_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+# CONFIG_USB_TEST is not set -+# CONFIG_USB_ISIGHTFW is not set -+# CONFIG_USB_YUREX is not set -+CONFIG_USB_GADGET=y -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_VBUS_DRAW=2 -+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -+# CONFIG_USB_FUSB300 is not set -+# CONFIG_USB_R8A66597 is not set -+# CONFIG_USB_MV_UDC is not set -+# CONFIG_USB_GADGET_AKUDC_PRODUCER is not set -+CONFIG_USB_GADGET_AKUDC=y -+CONFIG_USB_AKUDC=m -+# CONFIG_USB_AKUDC_DEBUG_FS is not set -+# CONFIG_USB_M66592 is not set -+# CONFIG_USB_NET2272 is not set -+# CONFIG_USB_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_AUDIO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_G_NCM is not set -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+CONFIG_USB_MASS_STORAGE=m -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_G_PRINTER is not set -+# CONFIG_USB_CDC_COMPOSITE is not set -+# CONFIG_USB_G_ACM_MS is not set -+# CONFIG_USB_G_MULTI is not set -+# CONFIG_USB_G_HID is not set -+# CONFIG_USB_G_DBGP is not set -+# CONFIG_USB_G_WEBCAM is not set -+ -+# -+# OTG and related infrastructure -+# -+# CONFIG_USB_OTG_WAKELOCK is not set -+# CONFIG_USB_GPIO_VBUS is not set -+# CONFIG_USB_ULPI is not set -+# CONFIG_NOP_USB_XCEIV is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD/SDIO Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_MINORS=8 -+# CONFIG_MMC_BLOCK_BOUNCE is not set -+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set -+# CONFIG_SDIO_UART is not set -+# CONFIG_MMC_TEST is not set -+ -+# -+# MMC/SD/SDIO Host Controller Drivers -+# -+# CONFIG_MMC_SDHCI is not set -+# CONFIG_MMC_SDHCI_PXAV3 is not set -+# CONFIG_MMC_SDHCI_PXAV2 is not set -+# CONFIG_MMC_SPI is not set -+# CONFIG_MMC_DW is not set -+# CONFIG_MMC_VUB300 is not set -+# CONFIG_MMC_USHC is not set -+CONFIG_MMC_ANYKA=y -+# CONFIG_MEMSTICK is not set -+CONFIG_NEW_LEDS=y -+CONFIG_LEDS_CLASS=y -+ -+# -+# LED drivers -+# -+# CONFIG_LEDS_LM3530 is not set -+# CONFIG_LEDS_GPIO is not set -+# CONFIG_LEDS_LP3944 is not set -+# CONFIG_LEDS_LP5521 is not set -+# CONFIG_LEDS_LP5523 is not set -+# CONFIG_LEDS_PCA955X is not set -+# CONFIG_LEDS_PCA9633 is not set -+# CONFIG_LEDS_DAC124S085 is not set -+# CONFIG_LEDS_BD2802 is not set -+CONFIG_LEDS_AK39=y -+# CONFIG_LEDS_LT3593 is not set -+# CONFIG_LEDS_RENESAS_TPU is not set -+# CONFIG_LEDS_TCA6507 is not set -+# CONFIG_LEDS_OT200 is not set -+CONFIG_LEDS_TRIGGERS=y -+ -+# -+# LED Triggers -+# -+CONFIG_LEDS_TRIGGER_TIMER=y -+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set -+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set -+# CONFIG_LEDS_TRIGGER_GPIO is not set -+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set -+ -+# -+# iptables trigger is under Netfilter config (LED target) -+# -+# CONFIG_SWITCH is not set -+# CONFIG_ACCESSIBILITY is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+# CONFIG_DMADEVICES is not set -+# CONFIG_AUXDISPLAY is not set -+CONFIG_UIO=y -+# CONFIG_UIO_PDRV is not set -+# CONFIG_UIO_PDRV_GENIRQ is not set -+CONFIG_UIO_VCODEC=y -+ -+# -+# Virtio drivers -+# -+# CONFIG_VIRTIO_BALLOON is not set -+ -+# -+# Microsoft Hyper-V guest support -+# -+# CONFIG_STAGING is not set -+CONFIG_CLKDEV_LOOKUP=y -+ -+# -+# Hardware Spinlock drivers -+# -+# CONFIG_IOMMU_SUPPORT is not set -+ -+# -+# Remoteproc drivers (EXPERIMENTAL) -+# -+ -+# -+# Rpmsg drivers (EXPERIMENTAL) -+# -+# CONFIG_VIRT_DRIVERS is not set -+# CONFIG_PM_DEVFREQ is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+CONFIG_EXT2_FS_POSIX_ACL=y -+CONFIG_EXT2_FS_SECURITY=y -+CONFIG_EXT2_FS_XIP=y -+CONFIG_EXT3_FS=y -+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y -+CONFIG_EXT3_FS_XATTR=y -+CONFIG_EXT3_FS_POSIX_ACL=y -+CONFIG_EXT3_FS_SECURITY=y -+CONFIG_EXT4_FS=y -+CONFIG_EXT4_FS_XATTR=y -+CONFIG_EXT4_FS_POSIX_ACL=y -+CONFIG_EXT4_FS_SECURITY=y -+# CONFIG_EXT4_DEBUG is not set -+CONFIG_FS_XIP=y -+CONFIG_JBD=y -+# CONFIG_JBD_DEBUG is not set -+CONFIG_JBD2=y -+# CONFIG_JBD2_DEBUG is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+CONFIG_FS_POSIX_ACL=y -+CONFIG_EXPORTFS=y -+CONFIG_FILE_LOCKING=y -+CONFIG_FSNOTIFY=y -+CONFIG_DNOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_FANOTIFY is not set -+# CONFIG_QUOTA is not set -+# CONFIG_QUOTACTL is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+CONFIG_GENERIC_ACL=y -+ -+# -+# Caches -+# -+# CONFIG_FSCACHE is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_PROC_PAGE_MONITOR=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+CONFIG_TMPFS_POSIX_ACL=y -+CONFIG_TMPFS_XATTR=y -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+CONFIG_MISC_FILESYSTEMS=y -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_YAFFS_FS is not set -+CONFIG_JFFS2_FS=y -+CONFIG_JFFS2_FS_DEBUG=0 -+CONFIG_JFFS2_FS_WRITEBUFFER=y -+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set -+CONFIG_JFFS2_COMPRESSION_OPTIONS=y -+# CONFIG_JFFS2_ZLIB is not set -+# CONFIG_JFFS2_LZO is not set -+# CONFIG_JFFS2_RTIME is not set -+# CONFIG_JFFS2_RUBIN is not set -+CONFIG_JFFS2_CMODE_NONE=y -+# CONFIG_JFFS2_CMODE_PRIORITY is not set -+# CONFIG_JFFS2_CMODE_SIZE is not set -+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_SQUASHFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_OMFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_QNX6FS_FS is not set -+# CONFIG_ROMFS_FS is not set -+# CONFIG_PSTORE is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+# CONFIG_NETWORK_FILESYSTEMS is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+CONFIG_NLS_UTF8=y -+ -+# -+# Kernel hacking -+# -+# CONFIG_PRINTK_TIME is not set -+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_FRAME_WARN=1024 -+# CONFIG_MAGIC_SYSRQ is not set -+# CONFIG_STRIP_ASM_SYMS is not set -+# CONFIG_UNUSED_SYMBOLS is not set -+CONFIG_DEBUG_FS=y -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_SECTION_MISMATCH is not set -+CONFIG_DEBUG_KERNEL=y -+# CONFIG_DEBUG_SHIRQ is not set -+# CONFIG_LOCKUP_DETECTOR is not set -+# CONFIG_HARDLOCKUP_DETECTOR_NMI is not set -+# CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU is not set -+# CONFIG_HARDLOCKUP_DETECTOR is not set -+# CONFIG_DETECT_HUNG_TASK is not set -+# CONFIG_SCHED_DEBUG is not set -+# CONFIG_SCHEDSTATS is not set -+# CONFIG_TIMER_STATS is not set -+# CONFIG_DEBUG_OBJECTS is not set -+# CONFIG_SLUB_DEBUG_ON is not set -+# CONFIG_SLUB_STATS is not set -+# CONFIG_DEBUG_RT_MUTEXES is not set -+# CONFIG_RT_MUTEX_TESTER is not set -+# CONFIG_DEBUG_SPINLOCK is not set -+# CONFIG_DEBUG_MUTEXES is not set -+# CONFIG_DEBUG_LOCK_ALLOC is not set -+# CONFIG_PROVE_LOCKING is not set -+# CONFIG_SPARSE_RCU_POINTER is not set -+# CONFIG_LOCK_STAT is not set -+# CONFIG_DEBUG_ATOMIC_SLEEP is not set -+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -+CONFIG_STACKTRACE=y -+# CONFIG_DEBUG_STACK_USAGE is not set -+# CONFIG_DEBUG_KOBJECT is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_DEBUG_INFO is not set -+# CONFIG_DEBUG_VM is not set -+# CONFIG_DEBUG_WRITECOUNT is not set -+# CONFIG_DEBUG_MEMORY_INIT is not set -+# CONFIG_DEBUG_LIST is not set -+# CONFIG_TEST_LIST_SORT is not set -+# CONFIG_DEBUG_SG is not set -+# CONFIG_DEBUG_NOTIFIERS is not set -+# CONFIG_DEBUG_CREDENTIALS is not set -+CONFIG_FRAME_POINTER=y -+# CONFIG_BOOT_PRINTK_DELAY is not set -+# CONFIG_RCU_TORTURE_TEST is not set -+# CONFIG_RCU_TRACE is not set -+# CONFIG_BACKTRACE_SELF_TEST is not set -+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set -+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -+# CONFIG_LKDTM is not set -+# CONFIG_FAULT_INJECTION is not set -+# CONFIG_LATENCYTOP is not set -+# CONFIG_DEBUG_PAGEALLOC is not set -+CONFIG_HAVE_FUNCTION_TRACER=y -+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -+CONFIG_HAVE_DYNAMIC_FTRACE=y -+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -+CONFIG_HAVE_C_RECORDMCOUNT=y -+CONFIG_TRACING_SUPPORT=y -+# CONFIG_FTRACE is not set -+# CONFIG_DYNAMIC_DEBUG is not set -+# CONFIG_DMA_API_DEBUG is not set -+# CONFIG_ATOMIC64_SELFTEST is not set -+# CONFIG_SAMPLES is not set -+CONFIG_HAVE_ARCH_KGDB=y -+# CONFIG_TEST_KSTRTOX is not set -+# CONFIG_STRICT_DEVMEM is not set -+CONFIG_DEBUG_USER=y -+# CONFIG_DEBUG_RODATA is not set -+# CONFIG_DEBUG_LL is not set -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY_DMESG_RESTRICT is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITYFS is not set -+CONFIG_DEFAULT_SECURITY_DAC=y -+CONFIG_DEFAULT_SECURITY="" -+CONFIG_CRYPTO=y -+ -+# -+# Crypto core or helper -+# -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_ALGAPI2=y -+# CONFIG_CRYPTO_MANAGER is not set -+# CONFIG_CRYPTO_MANAGER2 is not set -+# CONFIG_CRYPTO_USER is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_TEST is not set -+ -+# -+# Authenticated Encryption with Associated Data -+# -+# CONFIG_CRYPTO_CCM is not set -+# CONFIG_CRYPTO_GCM is not set -+# CONFIG_CRYPTO_SEQIV is not set -+ -+# -+# Block modes -+# -+# CONFIG_CRYPTO_CBC is not set -+# CONFIG_CRYPTO_CTR is not set -+# CONFIG_CRYPTO_CTS is not set -+# CONFIG_CRYPTO_ECB is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_XTS is not set -+ -+# -+# Hash modes -+# -+# CONFIG_CRYPTO_HMAC is not set -+ -+# -+# Digest -+# -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_GHASH is not set -+# CONFIG_CRYPTO_MD4 is not set -+# CONFIG_CRYPTO_MD5 is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_RMD128 is not set -+# CONFIG_CRYPTO_RMD160 is not set -+# CONFIG_CRYPTO_RMD256 is not set -+# CONFIG_CRYPTO_RMD320 is not set -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_WP512 is not set -+ -+# -+# Ciphers -+# -+CONFIG_CRYPTO_AES=y -+# CONFIG_CRYPTO_ANUBIS is not set -+CONFIG_CRYPTO_ARC4=y -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_DES is not set -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+ -+# -+# Compression -+# -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_ZLIB is not set -+# CONFIG_CRYPTO_LZO is not set -+ -+# -+# Random Number Generation -+# -+# CONFIG_CRYPTO_ANSI_CPRNG is not set -+# CONFIG_CRYPTO_USER_API_HASH is not set -+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set -+CONFIG_CRYPTO_HW=y -+# CONFIG_BINARY_PRINTF is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+CONFIG_GENERIC_PCI_IOMAP=y -+CONFIG_GENERIC_IO=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=y -+CONFIG_CRC_T10DIF=y -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC32_SELFTEST is not set -+CONFIG_CRC32_SLICEBY8=y -+# CONFIG_CRC32_SLICEBY4 is not set -+# CONFIG_CRC32_SARWATE is not set -+# CONFIG_CRC32_BIT is not set -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+# CONFIG_CRC8 is not set -+CONFIG_ZLIB_INFLATE=y -+CONFIG_XZ_DEC=y -+CONFIG_XZ_DEC_X86=y -+CONFIG_XZ_DEC_POWERPC=y -+CONFIG_XZ_DEC_IA64=y -+CONFIG_XZ_DEC_ARM=y -+CONFIG_XZ_DEC_ARMTHUMB=y -+CONFIG_XZ_DEC_SPARC=y -+CONFIG_XZ_DEC_BCJ=y -+# CONFIG_XZ_DEC_TEST is not set -+CONFIG_DECOMPRESS_GZIP=y -+CONFIG_GENERIC_ALLOCATOR=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -+CONFIG_DQL=y -+CONFIG_NLATTR=y -+CONFIG_GENERIC_ATOMIC64=y -+CONFIG_AVERAGE=y -+# CONFIG_CORDIC is not set -diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h -index 42dec04f..d0366c1e 100644 ---- a/arch/arm/include/asm/cacheflush.h -+++ b/arch/arm/include/asm/cacheflush.h -@@ -16,6 +16,7 @@ - #include <asm/shmparam.h> - #include <asm/cachetype.h> - #include <asm/outercache.h> -+#include <asm/rodata.h> - - #define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) - -diff --git a/arch/arm/include/asm/fiq_debugger.h b/arch/arm/include/asm/fiq_debugger.h -new file mode 100644 -index 00000000..4d274883 ---- /dev/null -+++ b/arch/arm/include/asm/fiq_debugger.h -@@ -0,0 +1,64 @@ -+/* -+ * arch/arm/include/asm/fiq_debugger.h -+ * -+ * Copyright (C) 2010 Google, Inc. -+ * Author: Colin Cross <ccross@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_ -+#define _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_ -+ -+#include <linux/serial_core.h> -+ -+#define FIQ_DEBUGGER_NO_CHAR NO_POLL_CHAR -+#define FIQ_DEBUGGER_BREAK 0x00ff0100 -+ -+#define FIQ_DEBUGGER_FIQ_IRQ_NAME "fiq" -+#define FIQ_DEBUGGER_SIGNAL_IRQ_NAME "signal" -+#define FIQ_DEBUGGER_WAKEUP_IRQ_NAME "wakeup" -+ -+/** -+ * struct fiq_debugger_pdata - fiq debugger platform data -+ * @uart_resume: used to restore uart state right before enabling -+ * the fiq. -+ * @uart_enable: Do the work necessary to communicate with the uart -+ * hw (enable clocks, etc.). This must be ref-counted. -+ * @uart_disable: Do the work necessary to disable the uart hw -+ * (disable clocks, etc.). This must be ref-counted. -+ * @uart_dev_suspend: called during PM suspend, generally not needed -+ * for real fiq mode debugger. -+ * @uart_dev_resume: called during PM resume, generally not needed -+ * for real fiq mode debugger. -+ */ -+struct fiq_debugger_pdata { -+ int (*uart_init)(struct platform_device *pdev); -+ void (*uart_free)(struct platform_device *pdev); -+ int (*uart_resume)(struct platform_device *pdev); -+ int (*uart_getc)(struct platform_device *pdev); -+ void (*uart_putc)(struct platform_device *pdev, unsigned int c); -+ void (*uart_flush)(struct platform_device *pdev); -+ void (*uart_enable)(struct platform_device *pdev); -+ void (*uart_disable)(struct platform_device *pdev); -+ -+ int (*uart_dev_suspend)(struct platform_device *pdev); -+ int (*uart_dev_resume)(struct platform_device *pdev); -+ -+ void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq, -+ bool enable); -+ void (*fiq_ack)(struct platform_device *pdev, unsigned int fiq); -+ -+ void (*force_irq)(struct platform_device *pdev, unsigned int irq); -+ void (*force_irq_ack)(struct platform_device *pdev, unsigned int irq); -+}; -+ -+#endif -diff --git a/arch/arm/include/asm/fiq_glue.h b/arch/arm/include/asm/fiq_glue.h -new file mode 100644 -index 00000000..d54c29db ---- /dev/null -+++ b/arch/arm/include/asm/fiq_glue.h -@@ -0,0 +1,30 @@ -+/* -+ * Copyright (C) 2010 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#ifndef __ASM_FIQ_GLUE_H -+#define __ASM_FIQ_GLUE_H -+ -+struct fiq_glue_handler { -+ void (*fiq)(struct fiq_glue_handler *h, void *regs, void *svc_sp); -+ void (*resume)(struct fiq_glue_handler *h); -+}; -+ -+int fiq_glue_register_handler(struct fiq_glue_handler *handler); -+ -+#ifdef CONFIG_FIQ_GLUE -+void fiq_glue_resume(void); -+#else -+static inline void fiq_glue_resume(void) {} -+#endif -+ -+#endif -diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h -index 436e60b2..2740c2a2 100644 ---- a/arch/arm/include/asm/hardirq.h -+++ b/arch/arm/include/asm/hardirq.h -@@ -5,7 +5,7 @@ - #include <linux/threads.h> - #include <asm/irq.h> - --#define NR_IPI 5 -+#define NR_IPI 6 - - typedef struct { - unsigned int __softirq_pending; -diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h -index c4c87bc1..bd2c6a53 100644 ---- a/arch/arm/include/asm/hardware/cache-l2x0.h -+++ b/arch/arm/include/asm/hardware/cache-l2x0.h -@@ -66,6 +66,7 @@ - #define L2X0_STNDBY_MODE_EN (1 << 0) - - /* Registers shifts and masks */ -+#define L2X0_CACHE_ID_REV_MASK (0x3f) - #define L2X0_CACHE_ID_PART_MASK (0xf << 6) - #define L2X0_CACHE_ID_PART_L210 (1 << 6) - #define L2X0_CACHE_ID_PART_L310 (3 << 6) -@@ -102,6 +103,8 @@ - - #define L2X0_ADDR_FILTER_EN 1 - -+#define REV_PL310_R2P0 4 -+ - #ifndef __ASSEMBLY__ - extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask); - #if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF) -diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h -index 7ecd793b..dcf74d71 100644 ---- a/arch/arm/include/asm/hardware/coresight.h -+++ b/arch/arm/include/asm/hardware/coresight.h -@@ -17,15 +17,23 @@ - #define TRACER_ACCESSED_BIT 0 - #define TRACER_RUNNING_BIT 1 - #define TRACER_CYCLE_ACC_BIT 2 -+#define TRACER_TRACE_DATA_BIT 3 -+#define TRACER_TIMESTAMP_BIT 4 -+#define TRACER_BRANCHOUTPUT_BIT 5 -+#define TRACER_RETURN_STACK_BIT 6 - #define TRACER_ACCESSED BIT(TRACER_ACCESSED_BIT) - #define TRACER_RUNNING BIT(TRACER_RUNNING_BIT) - #define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT) -+#define TRACER_TRACE_DATA BIT(TRACER_TRACE_DATA_BIT) -+#define TRACER_TIMESTAMP BIT(TRACER_TIMESTAMP_BIT) -+#define TRACER_BRANCHOUTPUT BIT(TRACER_BRANCHOUTPUT_BIT) -+#define TRACER_RETURN_STACK BIT(TRACER_RETURN_STACK_BIT) - - #define TRACER_TIMEOUT 10000 - --#define etm_writel(t, v, x) \ -- (__raw_writel((v), (t)->etm_regs + (x))) --#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x))) -+#define etm_writel(t, id, v, x) \ -+ (__raw_writel((v), (t)->etm_regs[(id)] + (x))) -+#define etm_readl(t, id, x) (__raw_readl((t)->etm_regs[(id)] + (x))) - - /* CoreSight Management Registers */ - #define CSMR_LOCKACCESS 0xfb0 -@@ -43,7 +51,7 @@ - #define ETMCTRL_POWERDOWN 1 - #define ETMCTRL_PROGRAM (1 << 10) - #define ETMCTRL_PORTSEL (1 << 11) --#define ETMCTRL_DO_CONTEXTID (3 << 14) -+#define ETMCTRL_CONTEXTIDSIZE(x) (((x) & 3) << 14) - #define ETMCTRL_PORTMASK1 (7 << 4) - #define ETMCTRL_PORTMASK2 (1 << 21) - #define ETMCTRL_PORTMASK (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2) -@@ -55,9 +63,12 @@ - #define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR) - #define ETMCTRL_BRANCH_OUTPUT (1 << 8) - #define ETMCTRL_CYCLEACCURATE (1 << 12) -+#define ETMCTRL_TIMESTAMP_EN (1 << 28) -+#define ETMCTRL_RETURN_STACK_EN (1 << 29) - - /* ETM configuration code register */ - #define ETMR_CONFCODE (0x04) -+#define ETMCCR_ETMIDR_PRESENT BIT(31) - - /* ETM trace start/stop resource control register */ - #define ETMR_TRACESSCTRL (0x18) -@@ -113,10 +124,25 @@ - #define ETMR_TRACEENCTRL 0x24 - #define ETMTE_INCLEXCL BIT(24) - #define ETMR_TRACEENEVT 0x20 --#define ETMCTRL_OPTS (ETMCTRL_DO_CPRT | \ -- ETMCTRL_DATA_DO_ADDR | \ -- ETMCTRL_BRANCH_OUTPUT | \ -- ETMCTRL_DO_CONTEXTID) -+ -+#define ETMR_VIEWDATAEVT 0x30 -+#define ETMR_VIEWDATACTRL1 0x34 -+#define ETMR_VIEWDATACTRL2 0x38 -+#define ETMR_VIEWDATACTRL3 0x3c -+#define ETMVDC3_EXCLONLY BIT(16) -+ -+#define ETMCTRL_OPTS (ETMCTRL_DO_CPRT) -+ -+#define ETMR_ID 0x1e4 -+#define ETMIDR_VERSION(x) (((x) >> 4) & 0xff) -+#define ETMIDR_VERSION_3_1 0x21 -+#define ETMIDR_VERSION_PFT_1_0 0x30 -+ -+#define ETMR_CCE 0x1e8 -+#define ETMCCER_RETURN_STACK_IMPLEMENTED BIT(23) -+#define ETMCCER_TIMESTAMPING_IMPLEMENTED BIT(22) -+ -+#define ETMR_TRACEIDR 0x200 - - /* ETM management registers, "ETM Architecture", 3.5.24 */ - #define ETMMR_OSLAR 0x300 -@@ -140,14 +166,16 @@ - #define ETBFF_TRIGIN BIT(8) - #define ETBFF_TRIGEVT BIT(9) - #define ETBFF_TRIGFL BIT(10) -+#define ETBFF_STOPFL BIT(12) - - #define etb_writel(t, v, x) \ - (__raw_writel((v), (t)->etb_regs + (x))) - #define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x))) - --#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0) --#define etm_unlock(t) \ -- do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0) -+#define etm_lock(t, id) \ -+ do { etm_writel((t), (id), 0, CSMR_LOCKACCESS); } while (0) -+#define etm_unlock(t, id) \ -+ do { etm_writel((t), (id), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0) - - #define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0) - #define etb_unlock(t) \ -diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h -index 35c21c37..3e0857a6 100644 ---- a/arch/arm/include/asm/irq.h -+++ b/arch/arm/include/asm/irq.h -@@ -30,6 +30,9 @@ extern void asm_do_IRQ(unsigned int, struct pt_regs *); - void handle_IRQ(unsigned int, struct pt_regs *); - void init_IRQ(void); - -+void arch_trigger_all_cpu_backtrace(void); -+#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace -+ - #endif - - #endif -diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h -new file mode 100644 -index 00000000..bca864ac ---- /dev/null -+++ b/arch/arm/include/asm/mach/mmc.h -@@ -0,0 +1,28 @@ -+/* -+ * arch/arm/include/asm/mach/mmc.h -+ */ -+#ifndef ASMARM_MACH_MMC_H -+#define ASMARM_MACH_MMC_H -+ -+#include <linux/mmc/host.h> -+#include <linux/mmc/card.h> -+#include <linux/mmc/sdio_func.h> -+ -+struct embedded_sdio_data { -+ struct sdio_cis cis; -+ struct sdio_cccr cccr; -+ struct sdio_embedded_func *funcs; -+ int num_funcs; -+}; -+ -+struct mmc_platform_data { -+ unsigned int ocr_mask; /* available voltages */ -+ int built_in; /* built-in device flag */ -+ int card_present; /* card detect state */ -+ u32 (*translate_vdd)(struct device *, unsigned int); -+ unsigned int (*status)(struct device *); -+ struct embedded_sdio_data *embedded_sdio; -+ int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); -+}; -+ -+#endif -diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h -index b8e580a2..14965658 100644 ---- a/arch/arm/include/asm/mmu.h -+++ b/arch/arm/include/asm/mmu.h -@@ -34,11 +34,4 @@ typedef struct { - - #endif - --/* -- * switch_mm() may do a full cache flush over the context switch, -- * so enable interrupts over the context switch to avoid high -- * latency. -- */ --#define __ARCH_WANT_INTERRUPTS_ON_CTXSW -- - #endif -diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h -index a0b3cac0..0306bc64 100644 ---- a/arch/arm/include/asm/mmu_context.h -+++ b/arch/arm/include/asm/mmu_context.h -@@ -43,45 +43,104 @@ void __check_kvm_seq(struct mm_struct *mm); - #define ASID_FIRST_VERSION (1 << ASID_BITS) - - extern unsigned int cpu_last_asid; --#ifdef CONFIG_SMP --DECLARE_PER_CPU(struct mm_struct *, current_mm); --#endif - - void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); - void __new_context(struct mm_struct *mm); -+void cpu_set_reserved_ttbr0(void); - --static inline void check_context(struct mm_struct *mm) -+static inline void switch_new_context(struct mm_struct *mm) - { -- /* -- * This code is executed with interrupts enabled. Therefore, -- * mm->context.id cannot be updated to the latest ASID version -- * on a different CPU (and condition below not triggered) -- * without first getting an IPI to reset the context. The -- * alternative is to take a read_lock on mm->context.id_lock -- * (after changing its type to rwlock_t). -- */ -- if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) -- __new_context(mm); -+ unsigned long flags; -+ -+ __new_context(mm); -+ -+ local_irq_save(flags); -+ cpu_switch_mm(mm->pgd, mm); -+ local_irq_restore(flags); -+} - -+static inline void check_and_switch_context(struct mm_struct *mm, -+ struct task_struct *tsk) -+{ - if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) - __check_kvm_seq(mm); -+ -+ /* -+ * Required during context switch to avoid speculative page table -+ * walking with the wrong TTBR. -+ */ -+ cpu_set_reserved_ttbr0(); -+ -+ if (!((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) -+ /* -+ * The ASID is from the current generation, just switch to the -+ * new pgd. This condition is only true for calls from -+ * context_switch() and interrupts are already disabled. -+ */ -+ cpu_switch_mm(mm->pgd, mm); -+ else if (irqs_disabled()) -+ /* -+ * Defer the new ASID allocation until after the context -+ * switch critical region since __new_context() cannot be -+ * called with interrupts disabled (it sends IPIs). -+ */ -+ set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); -+ else -+ /* -+ * That is a direct call to switch_mm() or activate_mm() with -+ * interrupts enabled and a new context. -+ */ -+ switch_new_context(mm); - } - - #define init_new_context(tsk,mm) (__init_new_context(tsk,mm),0) - --#else -- --static inline void check_context(struct mm_struct *mm) -+#define finish_arch_post_lock_switch \ -+ finish_arch_post_lock_switch -+static inline void finish_arch_post_lock_switch(void) - { -+ if (test_and_clear_thread_flag(TIF_SWITCH_MM)) -+ switch_new_context(current->mm); -+} -+ -+#else /* !CONFIG_CPU_HAS_ASID */ -+ - #ifdef CONFIG_MMU -+ -+static inline void check_and_switch_context(struct mm_struct *mm, -+ struct task_struct *tsk) -+{ - if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) - __check_kvm_seq(mm); --#endif -+ -+ if (irqs_disabled()) -+ /* -+ * cpu_switch_mm() needs to flush the VIVT caches. To avoid -+ * high interrupt latencies, defer the call and continue -+ * running with the old mm. Since we only support UP systems -+ * on non-ASID CPUs, the old mm will remain valid until the -+ * finish_arch_post_lock_switch() call. -+ */ -+ set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); -+ else -+ cpu_switch_mm(mm->pgd, mm); - } - -+#define finish_arch_post_lock_switch \ -+ finish_arch_post_lock_switch -+static inline void finish_arch_post_lock_switch(void) -+{ -+ if (test_and_clear_thread_flag(TIF_SWITCH_MM)) { -+ struct mm_struct *mm = current->mm; -+ cpu_switch_mm(mm->pgd, mm); -+ } -+} -+ -+#endif /* CONFIG_MMU */ -+ - #define init_new_context(tsk,mm) 0 - --#endif -+#endif /* CONFIG_CPU_HAS_ASID */ - - #define destroy_context(mm) do { } while(0) - -@@ -119,12 +178,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, - __flush_icache_all(); - #endif - if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) { --#ifdef CONFIG_SMP -- struct mm_struct **crt_mm = &per_cpu(current_mm, cpu); -- *crt_mm = next; --#endif -- check_context(next); -- cpu_switch_mm(next->pgd, next); -+ check_and_switch_context(next, tsk); - if (cache_is_vivt()) - cpumask_clear_cpu(cpu, mm_cpumask(prev)); - } -diff --git a/arch/arm/include/asm/rodata.h b/arch/arm/include/asm/rodata.h -new file mode 100644 -index 00000000..8c8add87 ---- /dev/null -+++ b/arch/arm/include/asm/rodata.h -@@ -0,0 +1,32 @@ -+/* -+ * arch/arm/include/asm/rodata.h -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * Author: Colin Cross <ccross@android.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. -+ */ -+#ifndef _ASMARM_RODATA_H -+#define _ASMARM_RODATA_H -+ -+#ifndef __ASSEMBLY__ -+ -+#ifdef CONFIG_DEBUG_RODATA -+ -+int set_memory_rw(unsigned long virt, int numpages); -+int set_memory_ro(unsigned long virt, int numpages); -+ -+void mark_rodata_ro(void); -+void set_kernel_text_rw(void); -+void set_kernel_text_ro(void); -+#else -+static inline void set_kernel_text_rw(void) { } -+static inline void set_kernel_text_ro(void) { } -+#endif -+ -+#endif -+ -+#endif -diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h -index e3f75726..05b8e82e 100644 ---- a/arch/arm/include/asm/sched_clock.h -+++ b/arch/arm/include/asm/sched_clock.h -@@ -10,5 +10,7 @@ - - extern void sched_clock_postinit(void); - extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate); -+extern void setup_sched_clock_needs_suspend(u32 (*read)(void), int bits, -+ unsigned long rate); - - #endif -diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h -index ae292932..7f74b59f 100644 ---- a/arch/arm/include/asm/smp.h -+++ b/arch/arm/include/asm/smp.h -@@ -93,4 +93,6 @@ extern void platform_cpu_enable(unsigned int cpu); - extern void arch_send_call_function_single_ipi(int cpu); - extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); - -+extern void smp_send_all_cpu_backtrace(void); -+ - #endif /* ifndef __ASM_ARM_SMP_H */ -diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h -index 0f04d845..68388eb4 100644 ---- a/arch/arm/include/asm/thread_info.h -+++ b/arch/arm/include/asm/thread_info.h -@@ -153,6 +153,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, - #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ - #define TIF_RESTORE_SIGMASK 20 - #define TIF_SECCOMP 21 -+#define TIF_SWITCH_MM 22 /* deferred switch_mm */ - - #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) - #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c -index 36d20bd5..c5fb6c9f 100644 ---- a/arch/arm/kernel/etm.c -+++ b/arch/arm/kernel/etm.c -@@ -15,6 +15,7 @@ - #include <linux/init.h> - #include <linux/types.h> - #include <linux/io.h> -+#include <linux/slab.h> - #include <linux/sysrq.h> - #include <linux/device.h> - #include <linux/clk.h> -@@ -37,26 +38,37 @@ MODULE_AUTHOR("Alexander Shishkin"); - struct tracectx { - unsigned int etb_bufsz; - void __iomem *etb_regs; -- void __iomem *etm_regs; -+ void __iomem **etm_regs; -+ int etm_regs_count; - unsigned long flags; - int ncmppairs; - int etm_portsz; -+ int etm_contextid_size; -+ u32 etb_fc; -+ unsigned long range_start; -+ unsigned long range_end; -+ unsigned long data_range_start; -+ unsigned long data_range_end; -+ bool dump_initial_etb; - struct device *dev; - struct clk *emu_clk; - struct mutex mutex; - }; - --static struct tracectx tracer; -+static struct tracectx tracer = { -+ .range_start = (unsigned long)_stext, -+ .range_end = (unsigned long)_etext, -+}; - - static inline bool trace_isrunning(struct tracectx *t) - { - return !!(t->flags & TRACER_RUNNING); - } - --static int etm_setup_address_range(struct tracectx *t, int n, -+static int etm_setup_address_range(struct tracectx *t, int id, int n, - unsigned long start, unsigned long end, int exclude, int data) - { -- u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \ -+ u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY | - ETMAAT_NOVALCMP; - - if (n < 1 || n > t->ncmppairs) -@@ -72,95 +84,185 @@ static int etm_setup_address_range(struct tracectx *t, int n, - flags |= ETMAAT_IEXEC; - - /* first comparator for the range */ -- etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2)); -- etm_writel(t, start, ETMR_COMP_VAL(n * 2)); -+ etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2)); -+ etm_writel(t, id, start, ETMR_COMP_VAL(n * 2)); - - /* second comparator is right next to it */ -- etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1)); -- etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1)); -- -- flags = exclude ? ETMTE_INCLEXCL : 0; -- etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL); -+ etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1)); -+ etm_writel(t, id, end, ETMR_COMP_VAL(n * 2 + 1)); -+ -+ if (data) { -+ flags = exclude ? ETMVDC3_EXCLONLY : 0; -+ if (exclude) -+ n += 8; -+ etm_writel(t, id, flags | BIT(n), ETMR_VIEWDATACTRL3); -+ } else { -+ flags = exclude ? ETMTE_INCLEXCL : 0; -+ etm_writel(t, id, flags | (1 << n), ETMR_TRACEENCTRL); -+ } - - return 0; - } - --static int trace_start(struct tracectx *t) -+static int trace_start_etm(struct tracectx *t, int id) - { - u32 v; - unsigned long timeout = TRACER_TIMEOUT; - -- etb_unlock(t); -- -- etb_writel(t, 0, ETBR_FORMATTERCTRL); -- etb_writel(t, 1, ETBR_CTRL); -- -- etb_lock(t); -- -- /* configure etm */ - v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz); -+ v |= ETMCTRL_CONTEXTIDSIZE(t->etm_contextid_size); - - if (t->flags & TRACER_CYCLE_ACC) - v |= ETMCTRL_CYCLEACCURATE; - -- etm_unlock(t); -+ if (t->flags & TRACER_BRANCHOUTPUT) -+ v |= ETMCTRL_BRANCH_OUTPUT; -+ -+ if (t->flags & TRACER_TRACE_DATA) -+ v |= ETMCTRL_DATA_DO_ADDR; -+ -+ if (t->flags & TRACER_TIMESTAMP) -+ v |= ETMCTRL_TIMESTAMP_EN; -+ -+ if (t->flags & TRACER_RETURN_STACK) -+ v |= ETMCTRL_RETURN_STACK_EN; - -- etm_writel(t, v, ETMR_CTRL); -+ etm_unlock(t, id); - -- while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) -+ etm_writel(t, id, v, ETMR_CTRL); -+ -+ while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) - ; - if (!timeout) { - dev_dbg(t->dev, "Waiting for progbit to assert timed out\n"); -- etm_lock(t); -+ etm_lock(t, id); - return -EFAULT; - } - -- etm_setup_address_range(t, 1, (unsigned long)_stext, -- (unsigned long)_etext, 0, 0); -- etm_writel(t, 0, ETMR_TRACEENCTRL2); -- etm_writel(t, 0, ETMR_TRACESSCTRL); -- etm_writel(t, 0x6f, ETMR_TRACEENEVT); -+ if (t->range_start || t->range_end) -+ etm_setup_address_range(t, id, 1, -+ t->range_start, t->range_end, 0, 0); -+ else -+ etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL); -+ -+ etm_writel(t, id, 0, ETMR_TRACEENCTRL2); -+ etm_writel(t, id, 0, ETMR_TRACESSCTRL); -+ etm_writel(t, id, 0x6f, ETMR_TRACEENEVT); -+ -+ etm_writel(t, id, 0, ETMR_VIEWDATACTRL1); -+ etm_writel(t, id, 0, ETMR_VIEWDATACTRL2); -+ -+ if (t->data_range_start || t->data_range_end) -+ etm_setup_address_range(t, id, 2, t->data_range_start, -+ t->data_range_end, 0, 1); -+ else -+ etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3); -+ -+ etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT); - - v &= ~ETMCTRL_PROGRAM; - v |= ETMCTRL_PORTSEL; - -- etm_writel(t, v, ETMR_CTRL); -+ etm_writel(t, id, v, ETMR_CTRL); - - timeout = TRACER_TIMEOUT; -- while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout) -+ while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout) - ; - if (!timeout) { - dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n"); -- etm_lock(t); -+ etm_lock(t, id); - return -EFAULT; - } - -- etm_lock(t); -+ etm_lock(t, id); -+ return 0; -+} -+ -+static int trace_start(struct tracectx *t) -+{ -+ int ret; -+ int id; -+ u32 etb_fc = t->etb_fc; -+ -+ etb_unlock(t); -+ -+ t->dump_initial_etb = false; -+ etb_writel(t, 0, ETBR_WRITEADDR); -+ etb_writel(t, etb_fc, ETBR_FORMATTERCTRL); -+ etb_writel(t, 1, ETBR_CTRL); -+ -+ etb_lock(t); -+ -+ /* configure etm(s) */ -+ for (id = 0; id < t->etm_regs_count; id++) { -+ ret = trace_start_etm(t, id); -+ if (ret) -+ return ret; -+ } - - t->flags |= TRACER_RUNNING; - - return 0; - } - --static int trace_stop(struct tracectx *t) -+static int trace_stop_etm(struct tracectx *t, int id) - { - unsigned long timeout = TRACER_TIMEOUT; - -- etm_unlock(t); -+ etm_unlock(t, id); - -- etm_writel(t, 0x440, ETMR_CTRL); -- while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) -+ etm_writel(t, id, 0x440, ETMR_CTRL); -+ while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) - ; - if (!timeout) { -- dev_dbg(t->dev, "Waiting for progbit to assert timed out\n"); -- etm_lock(t); -+ dev_err(t->dev, -+ "etm%d: Waiting for progbit to assert timed out\n", -+ id); -+ etm_lock(t, id); - return -EFAULT; - } - -- etm_lock(t); -+ etm_lock(t, id); -+ return 0; -+} -+ -+static int trace_power_down_etm(struct tracectx *t, int id) -+{ -+ unsigned long timeout = TRACER_TIMEOUT; -+ etm_unlock(t, id); -+ while (!(etm_readl(t, id, ETMR_STATUS) & ETMST_PROGBIT) && --timeout) -+ ; -+ if (!timeout) { -+ dev_err(t->dev, "etm%d: Waiting for status progbit to assert timed out\n", -+ id); -+ etm_lock(t, id); -+ return -EFAULT; -+ } -+ -+ etm_writel(t, id, 0x441, ETMR_CTRL); -+ -+ etm_lock(t, id); -+ return 0; -+} -+ -+static int trace_stop(struct tracectx *t) -+{ -+ int id; -+ unsigned long timeout = TRACER_TIMEOUT; -+ u32 etb_fc = t->etb_fc; -+ -+ for (id = 0; id < t->etm_regs_count; id++) -+ trace_stop_etm(t, id); -+ -+ for (id = 0; id < t->etm_regs_count; id++) -+ trace_power_down_etm(t, id); - - etb_unlock(t); -- etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL); -+ if (etb_fc) { -+ etb_fc |= ETBFF_STOPFL; -+ etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL); -+ } -+ etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL); - - timeout = TRACER_TIMEOUT; - while (etb_readl(t, ETBR_FORMATTERCTRL) & -@@ -185,24 +287,15 @@ static int trace_stop(struct tracectx *t) - static int etb_getdatalen(struct tracectx *t) - { - u32 v; -- int rp, wp; -+ int wp; - - v = etb_readl(t, ETBR_STATUS); - - if (v & 1) - return t->etb_bufsz; - -- rp = etb_readl(t, ETBR_READADDR); - wp = etb_readl(t, ETBR_WRITEADDR); -- -- if (rp > wp) { -- etb_writel(t, 0, ETBR_READADDR); -- etb_writel(t, 0, ETBR_WRITEADDR); -- -- return 0; -- } -- -- return wp - rp; -+ return wp; - } - - /* sysrq+v will always stop the running trace and leave it at that */ -@@ -235,21 +328,18 @@ static void etm_dump(void) - printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM))); - printk(KERN_INFO "\n--- ETB buffer end ---\n"); - -- /* deassert the overflow bit */ -- etb_writel(t, 1, ETBR_CTRL); -- etb_writel(t, 0, ETBR_CTRL); -- -- etb_writel(t, 0, ETBR_TRIGGERCOUNT); -- etb_writel(t, 0, ETBR_READADDR); -- etb_writel(t, 0, ETBR_WRITEADDR); -- - etb_lock(t); - } - - static void sysrq_etm_dump(int key) - { -+ if (!mutex_trylock(&tracer.mutex)) { -+ printk(KERN_INFO "Tracing hardware busy\n"); -+ return; -+ } - dev_dbg(tracer.dev, "Dumping ETB buffer\n"); - etm_dump(); -+ mutex_unlock(&tracer.mutex); - } - - static struct sysrq_key_op sysrq_etm_op = { -@@ -276,6 +366,10 @@ static ssize_t etb_read(struct file *file, char __user *data, - struct tracectx *t = file->private_data; - u32 first = 0; - u32 *buf; -+ int wpos; -+ int skip; -+ long wlength; -+ loff_t pos = *ppos; - - mutex_lock(&t->mutex); - -@@ -287,31 +381,39 @@ static ssize_t etb_read(struct file *file, char __user *data, - etb_unlock(t); - - total = etb_getdatalen(t); -+ if (total == 0 && t->dump_initial_etb) -+ total = t->etb_bufsz; - if (total == t->etb_bufsz) - first = etb_readl(t, ETBR_WRITEADDR); - -+ if (pos > total * 4) { -+ skip = 0; -+ wpos = total; -+ } else { -+ skip = (int)pos % 4; -+ wpos = (int)pos / 4; -+ } -+ total -= wpos; -+ first = (first + wpos) % t->etb_bufsz; -+ - etb_writel(t, first, ETBR_READADDR); - -- length = min(total * 4, (int)len); -- buf = vmalloc(length); -+ wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4)); -+ length = min(total * 4 - skip, (int)len); -+ buf = vmalloc(wlength * 4); - -- dev_dbg(t->dev, "ETB buffer length: %d\n", total); -+ dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n", -+ length, pos, wlength, first); -+ dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos); - dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS)); -- for (i = 0; i < length / 4; i++) -+ for (i = 0; i < wlength; i++) - buf[i] = etb_readl(t, ETBR_READMEM); - -- /* the only way to deassert overflow bit in ETB status is this */ -- etb_writel(t, 1, ETBR_CTRL); -- etb_writel(t, 0, ETBR_CTRL); -- -- etb_writel(t, 0, ETBR_WRITEADDR); -- etb_writel(t, 0, ETBR_READADDR); -- etb_writel(t, 0, ETBR_TRIGGERCOUNT); -- - etb_lock(t); - -- length -= copy_to_user(data, buf, length); -+ length -= copy_to_user(data, (u8 *)buf + skip, length); - vfree(buf); -+ *ppos = pos + length; - - out: - mutex_unlock(&t->mutex); -@@ -348,28 +450,17 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id - if (ret) - goto out; - -+ mutex_lock(&t->mutex); - t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res)); - if (!t->etb_regs) { - ret = -ENOMEM; - goto out_release; - } - -+ t->dev = &dev->dev; -+ t->dump_initial_etb = true; - amba_set_drvdata(dev, t); - -- etb_miscdev.parent = &dev->dev; -- -- ret = misc_register(&etb_miscdev); -- if (ret) -- goto out_unmap; -- -- t->emu_clk = clk_get(&dev->dev, "emu_src_ck"); -- if (IS_ERR(t->emu_clk)) { -- dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n"); -- return -EFAULT; -- } -- -- clk_enable(t->emu_clk); -- - etb_unlock(t); - t->etb_bufsz = etb_readl(t, ETBR_DEPTH); - dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz); -@@ -378,6 +469,20 @@ static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id - etb_writel(t, 0, ETBR_CTRL); - etb_writel(t, 0x1000, ETBR_FORMATTERCTRL); - etb_lock(t); -+ mutex_unlock(&t->mutex); -+ -+ etb_miscdev.parent = &dev->dev; -+ -+ ret = misc_register(&etb_miscdev); -+ if (ret) -+ goto out_unmap; -+ -+ /* Get optional clock. Currently used to select clock source on omap3 */ -+ t->emu_clk = clk_get(&dev->dev, "emu_src_ck"); -+ if (IS_ERR(t->emu_clk)) -+ dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n"); -+ else -+ clk_enable(t->emu_clk); - - dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n"); - -@@ -385,10 +490,13 @@ out: - return ret; - - out_unmap: -+ mutex_lock(&t->mutex); - amba_set_drvdata(dev, NULL); - iounmap(t->etb_regs); -+ t->etb_regs = NULL; - - out_release: -+ mutex_unlock(&t->mutex); - amba_release_regions(dev); - - return ret; -@@ -403,8 +511,10 @@ static int etb_remove(struct amba_device *dev) - iounmap(t->etb_regs); - t->etb_regs = NULL; - -- clk_disable(t->emu_clk); -- clk_put(t->emu_clk); -+ if (!IS_ERR(t->emu_clk)) { -+ clk_disable(t->emu_clk); -+ clk_put(t->emu_clk); -+ } - - amba_release_regions(dev); - -@@ -448,7 +558,10 @@ static ssize_t trace_running_store(struct kobject *kobj, - return -EINVAL; - - mutex_lock(&tracer.mutex); -- ret = value ? trace_start(&tracer) : trace_stop(&tracer); -+ if (!tracer.etb_regs) -+ ret = -ENODEV; -+ else -+ ret = value ? trace_start(&tracer) : trace_stop(&tracer); - mutex_unlock(&tracer.mutex); - - return ret ? : n; -@@ -463,36 +576,50 @@ static ssize_t trace_info_show(struct kobject *kobj, - { - u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st; - int datalen; -+ int id; -+ int ret; - -- etb_unlock(&tracer); -- datalen = etb_getdatalen(&tracer); -- etb_wa = etb_readl(&tracer, ETBR_WRITEADDR); -- etb_ra = etb_readl(&tracer, ETBR_READADDR); -- etb_st = etb_readl(&tracer, ETBR_STATUS); -- etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL); -- etb_lock(&tracer); -- -- etm_unlock(&tracer); -- etm_ctrl = etm_readl(&tracer, ETMR_CTRL); -- etm_st = etm_readl(&tracer, ETMR_STATUS); -- etm_lock(&tracer); -+ mutex_lock(&tracer.mutex); -+ if (tracer.etb_regs) { -+ etb_unlock(&tracer); -+ datalen = etb_getdatalen(&tracer); -+ etb_wa = etb_readl(&tracer, ETBR_WRITEADDR); -+ etb_ra = etb_readl(&tracer, ETBR_READADDR); -+ etb_st = etb_readl(&tracer, ETBR_STATUS); -+ etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL); -+ etb_lock(&tracer); -+ } else { -+ etb_wa = etb_ra = etb_st = etb_fc = ~0; -+ datalen = -1; -+ } - -- return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n" -+ ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n" - "ETBR_WRITEADDR:\t%08x\n" - "ETBR_READADDR:\t%08x\n" - "ETBR_STATUS:\t%08x\n" -- "ETBR_FORMATTERCTRL:\t%08x\n" -- "ETMR_CTRL:\t%08x\n" -- "ETMR_STATUS:\t%08x\n", -+ "ETBR_FORMATTERCTRL:\t%08x\n", - datalen, - tracer.ncmppairs, - etb_wa, - etb_ra, - etb_st, -- etb_fc, -+ etb_fc -+ ); -+ -+ for (id = 0; id < tracer.etm_regs_count; id++) { -+ etm_unlock(&tracer, id); -+ etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL); -+ etm_st = etm_readl(&tracer, id, ETMR_STATUS); -+ etm_lock(&tracer, id); -+ ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n" -+ "ETMR_STATUS:\t%08x\n", - etm_ctrl, - etm_st - ); -+ } -+ mutex_unlock(&tracer.mutex); -+ -+ return ret; - } - - static struct kobj_attribute trace_info_attr = -@@ -531,42 +658,260 @@ static ssize_t trace_mode_store(struct kobject *kobj, - static struct kobj_attribute trace_mode_attr = - __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store); - -+static ssize_t trace_contextid_size_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ /* 0: No context id tracing, 1: One byte, 2: Two bytes, 3: Four bytes */ -+ return sprintf(buf, "%d\n", (1 << tracer.etm_contextid_size) >> 1); -+} -+ -+static ssize_t trace_contextid_size_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ unsigned int contextid_size; -+ -+ if (sscanf(buf, "%u", &contextid_size) != 1) -+ return -EINVAL; -+ -+ if (contextid_size == 3 || contextid_size > 4) -+ return -EINVAL; -+ -+ mutex_lock(&tracer.mutex); -+ tracer.etm_contextid_size = fls(contextid_size); -+ mutex_unlock(&tracer.mutex); -+ -+ return n; -+} -+ -+static struct kobj_attribute trace_contextid_size_attr = -+ __ATTR(trace_contextid_size, 0644, -+ trace_contextid_size_show, trace_contextid_size_store); -+ -+static ssize_t trace_branch_output_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_BRANCHOUTPUT)); -+} -+ -+static ssize_t trace_branch_output_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ unsigned int branch_output; -+ -+ if (sscanf(buf, "%u", &branch_output) != 1) -+ return -EINVAL; -+ -+ mutex_lock(&tracer.mutex); -+ if (branch_output) { -+ tracer.flags |= TRACER_BRANCHOUTPUT; -+ /* Branch broadcasting is incompatible with the return stack */ -+ tracer.flags &= ~TRACER_RETURN_STACK; -+ } else { -+ tracer.flags &= ~TRACER_BRANCHOUTPUT; -+ } -+ mutex_unlock(&tracer.mutex); -+ -+ return n; -+} -+ -+static struct kobj_attribute trace_branch_output_attr = -+ __ATTR(trace_branch_output, 0644, -+ trace_branch_output_show, trace_branch_output_store); -+ -+static ssize_t trace_return_stack_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_RETURN_STACK)); -+} -+ -+static ssize_t trace_return_stack_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ unsigned int return_stack; -+ -+ if (sscanf(buf, "%u", &return_stack) != 1) -+ return -EINVAL; -+ -+ mutex_lock(&tracer.mutex); -+ if (return_stack) { -+ tracer.flags |= TRACER_RETURN_STACK; -+ /* Return stack is incompatible with branch broadcasting */ -+ tracer.flags &= ~TRACER_BRANCHOUTPUT; -+ } else { -+ tracer.flags &= ~TRACER_RETURN_STACK; -+ } -+ mutex_unlock(&tracer.mutex); -+ -+ return n; -+} -+ -+static struct kobj_attribute trace_return_stack_attr = -+ __ATTR(trace_return_stack, 0644, -+ trace_return_stack_show, trace_return_stack_store); -+ -+static ssize_t trace_timestamp_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_TIMESTAMP)); -+} -+ -+static ssize_t trace_timestamp_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ unsigned int timestamp; -+ -+ if (sscanf(buf, "%u", ×tamp) != 1) -+ return -EINVAL; -+ -+ mutex_lock(&tracer.mutex); -+ if (timestamp) -+ tracer.flags |= TRACER_TIMESTAMP; -+ else -+ tracer.flags &= ~TRACER_TIMESTAMP; -+ mutex_unlock(&tracer.mutex); -+ -+ return n; -+} -+ -+static struct kobj_attribute trace_timestamp_attr = -+ __ATTR(trace_timestamp, 0644, -+ trace_timestamp_show, trace_timestamp_store); -+ -+static ssize_t trace_range_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%08lx %08lx\n", -+ tracer.range_start, tracer.range_end); -+} -+ -+static ssize_t trace_range_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ unsigned long range_start, range_end; -+ -+ if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2) -+ return -EINVAL; -+ -+ mutex_lock(&tracer.mutex); -+ tracer.range_start = range_start; -+ tracer.range_end = range_end; -+ mutex_unlock(&tracer.mutex); -+ -+ return n; -+} -+ -+ -+static struct kobj_attribute trace_range_attr = -+ __ATTR(trace_range, 0644, trace_range_show, trace_range_store); -+ -+static ssize_t trace_data_range_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ unsigned long range_start; -+ u64 range_end; -+ mutex_lock(&tracer.mutex); -+ range_start = tracer.data_range_start; -+ range_end = tracer.data_range_end; -+ if (!range_end && (tracer.flags & TRACER_TRACE_DATA)) -+ range_end = 0x100000000ULL; -+ mutex_unlock(&tracer.mutex); -+ return sprintf(buf, "%08lx %08llx\n", range_start, range_end); -+} -+ -+static ssize_t trace_data_range_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ unsigned long range_start; -+ u64 range_end; -+ -+ if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2) -+ return -EINVAL; -+ -+ mutex_lock(&tracer.mutex); -+ tracer.data_range_start = range_start; -+ tracer.data_range_end = (unsigned long)range_end; -+ if (range_end) -+ tracer.flags |= TRACER_TRACE_DATA; -+ else -+ tracer.flags &= ~TRACER_TRACE_DATA; -+ mutex_unlock(&tracer.mutex); -+ -+ return n; -+} -+ -+ -+static struct kobj_attribute trace_data_range_attr = -+ __ATTR(trace_data_range, 0644, -+ trace_data_range_show, trace_data_range_store); -+ - static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id) - { - struct tracectx *t = &tracer; - int ret = 0; -+ void __iomem **new_regs; -+ int new_count; -+ u32 etmccr; -+ u32 etmidr; -+ u32 etmccer = 0; -+ u8 etm_version = 0; -+ -+ mutex_lock(&t->mutex); -+ new_count = t->etm_regs_count + 1; -+ new_regs = krealloc(t->etm_regs, -+ sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL); - -- if (t->etm_regs) { -- dev_dbg(&dev->dev, "ETM already initialized\n"); -- ret = -EBUSY; -+ if (!new_regs) { -+ dev_dbg(&dev->dev, "Failed to allocate ETM register array\n"); -+ ret = -ENOMEM; - goto out; - } -+ t->etm_regs = new_regs; - - ret = amba_request_regions(dev, NULL); - if (ret) - goto out; - -- t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res)); -- if (!t->etm_regs) { -+ t->etm_regs[t->etm_regs_count] = -+ ioremap_nocache(dev->res.start, resource_size(&dev->res)); -+ if (!t->etm_regs[t->etm_regs_count]) { - ret = -ENOMEM; - goto out_release; - } - -- amba_set_drvdata(dev, t); -+ amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]); - -- mutex_init(&t->mutex); -- t->dev = &dev->dev; -- t->flags = TRACER_CYCLE_ACC; -+ t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA | TRACER_BRANCHOUTPUT; - t->etm_portsz = 1; -+ t->etm_contextid_size = 3; - -- etm_unlock(t); -- (void)etm_readl(t, ETMMR_PDSR); -+ etm_unlock(t, t->etm_regs_count); -+ (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR); - /* dummy first read */ -- (void)etm_readl(&tracer, ETMMR_OSSRR); -- -- t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf; -- etm_writel(t, 0x440, ETMR_CTRL); -- etm_lock(t); -+ (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR); -+ -+ etmccr = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE); -+ t->ncmppairs = etmccr & 0xf; -+ if (etmccr & ETMCCR_ETMIDR_PRESENT) { -+ etmidr = etm_readl(t, t->etm_regs_count, ETMR_ID); -+ etm_version = ETMIDR_VERSION(etmidr); -+ if (etm_version >= ETMIDR_VERSION_3_1) -+ etmccer = etm_readl(t, t->etm_regs_count, ETMR_CCE); -+ } -+ etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL); -+ etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR); -+ etm_lock(t, t->etm_regs_count); - - ret = sysfs_create_file(&dev->dev.kobj, - &trace_running_attr.attr); -@@ -582,36 +927,101 @@ static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id - if (ret) - dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n"); - -- dev_dbg(t->dev, "ETM AMBA driver initialized.\n"); -+ ret = sysfs_create_file(&dev->dev.kobj, -+ &trace_contextid_size_attr.attr); -+ if (ret) -+ dev_dbg(&dev->dev, -+ "Failed to create trace_contextid_size in sysfs\n"); -+ -+ ret = sysfs_create_file(&dev->dev.kobj, -+ &trace_branch_output_attr.attr); -+ if (ret) -+ dev_dbg(&dev->dev, -+ "Failed to create trace_branch_output in sysfs\n"); -+ -+ if (etmccer & ETMCCER_RETURN_STACK_IMPLEMENTED) { -+ ret = sysfs_create_file(&dev->dev.kobj, -+ &trace_return_stack_attr.attr); -+ if (ret) -+ dev_dbg(&dev->dev, -+ "Failed to create trace_return_stack in sysfs\n"); -+ } -+ -+ if (etmccer & ETMCCER_TIMESTAMPING_IMPLEMENTED) { -+ ret = sysfs_create_file(&dev->dev.kobj, -+ &trace_timestamp_attr.attr); -+ if (ret) -+ dev_dbg(&dev->dev, -+ "Failed to create trace_timestamp in sysfs\n"); -+ } -+ -+ ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr); -+ if (ret) -+ dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n"); -+ -+ if (etm_version < ETMIDR_VERSION_PFT_1_0) { -+ ret = sysfs_create_file(&dev->dev.kobj, -+ &trace_data_range_attr.attr); -+ if (ret) -+ dev_dbg(&dev->dev, -+ "Failed to create trace_data_range in sysfs\n"); -+ } else { -+ tracer.flags &= ~TRACER_TRACE_DATA; -+ } -+ -+ dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n"); -+ -+ /* Enable formatter if there are multiple trace sources */ -+ if (new_count > 1) -+ t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC; -+ -+ t->etm_regs_count = new_count; - - out: -+ mutex_unlock(&t->mutex); - return ret; - - out_unmap: - amba_set_drvdata(dev, NULL); -- iounmap(t->etm_regs); -+ iounmap(t->etm_regs[t->etm_regs_count]); - - out_release: - amba_release_regions(dev); - -+ mutex_unlock(&t->mutex); - return ret; - } - - static int etm_remove(struct amba_device *dev) - { -- struct tracectx *t = amba_get_drvdata(dev); -+ int i; -+ struct tracectx *t = &tracer; -+ void __iomem *etm_regs = amba_get_drvdata(dev); -+ -+ sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr); -+ sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr); -+ sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr); -+ sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr); -+ sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr); - - amba_set_drvdata(dev, NULL); - -- iounmap(t->etm_regs); -- t->etm_regs = NULL; -+ mutex_lock(&t->mutex); -+ for (i = 0; i < t->etm_regs_count; i++) -+ if (t->etm_regs[i] == etm_regs) -+ break; -+ for (; i < t->etm_regs_count - 1; i++) -+ t->etm_regs[i] = t->etm_regs[i + 1]; -+ t->etm_regs_count--; -+ if (!t->etm_regs_count) { -+ kfree(t->etm_regs); -+ t->etm_regs = NULL; -+ } -+ mutex_unlock(&t->mutex); - -+ iounmap(etm_regs); - amba_release_regions(dev); - -- sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr); -- sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr); -- sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr); -- - return 0; - } - -@@ -620,6 +1030,10 @@ static struct amba_id etm_ids[] = { - .id = 0x0003b921, - .mask = 0x0007ffff, - }, -+ { -+ .id = 0x0003b950, -+ .mask = 0x0007ffff, -+ }, - { 0, 0 }, - }; - -@@ -637,6 +1051,8 @@ static int __init etm_init(void) - { - int retval; - -+ mutex_init(&tracer.mutex); -+ - retval = amba_driver_register(&etb_driver); - if (retval) { - printk(KERN_ERR "Failed to register etb\n"); -diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c -index df0bf0c8..6a740a93 100644 ---- a/arch/arm/kernel/ftrace.c -+++ b/arch/arm/kernel/ftrace.c -@@ -13,6 +13,7 @@ - */ - - #include <linux/ftrace.h> -+#include <linux/module.h> - #include <linux/uaccess.h> - - #include <asm/cacheflush.h> -@@ -63,6 +64,20 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) - } - #endif - -+int ftrace_arch_code_modify_prepare(void) -+{ -+ set_kernel_text_rw(); -+ set_all_modules_text_rw(); -+ return 0; -+} -+ -+int ftrace_arch_code_modify_post_process(void) -+{ -+ set_all_modules_text_ro(); -+ set_kernel_text_ro(); -+ return 0; -+} -+ - static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) - { - return arm_gen_branch_link(pc, addr); -@@ -179,19 +194,20 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, - old = *parent; - *parent = return_hooker; - -- err = ftrace_push_return_trace(old, self_addr, &trace.depth, -- frame_pointer); -- if (err == -EBUSY) { -- *parent = old; -- return; -- } -- - trace.func = self_addr; -+ trace.depth = current->curr_ret_stack + 1; - - /* Only trace if the calling function expects to */ - if (!ftrace_graph_entry(&trace)) { -- current->curr_ret_stack--; - *parent = old; -+ return; -+ } -+ -+ err = ftrace_push_return_trace(old, self_addr, &trace.depth, -+ frame_pointer); -+ if (err == -EBUSY) { -+ *parent = old; -+ return; - } - } - -diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c -index 1911dae1..2050399e 100644 ---- a/arch/arm/kernel/leds.c -+++ b/arch/arm/kernel/leds.c -@@ -10,6 +10,8 @@ - #include <linux/export.h> - #include <linux/init.h> - #include <linux/device.h> -+#include <linux/notifier.h> -+#include <linux/cpu.h> - #include <linux/syscore_ops.h> - #include <linux/string.h> - -@@ -103,6 +105,25 @@ static struct syscore_ops leds_syscore_ops = { - .resume = leds_resume, - }; - -+static int leds_idle_notifier(struct notifier_block *nb, unsigned long val, -+ void *data) -+{ -+ switch (val) { -+ case IDLE_START: -+ leds_event(led_idle_start); -+ break; -+ case IDLE_END: -+ leds_event(led_idle_end); -+ break; -+ } -+ -+ return 0; -+} -+ -+static struct notifier_block leds_idle_nb = { -+ .notifier_call = leds_idle_notifier, -+}; -+ - static int __init leds_init(void) - { - int ret; -@@ -111,8 +132,11 @@ static int __init leds_init(void) - ret = device_register(&leds_device); - if (ret == 0) - ret = device_create_file(&leds_device, &dev_attr_event); -- if (ret == 0) -+ if (ret == 0) { - register_syscore_ops(&leds_syscore_ops); -+ idle_notifier_register(&leds_idle_nb); -+ } -+ - return ret; - } - -diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c -index 48f36246..ff6c55df 100644 ---- a/arch/arm/kernel/process.c -+++ b/arch/arm/kernel/process.c -@@ -31,9 +31,9 @@ - #include <linux/random.h> - #include <linux/hw_breakpoint.h> - #include <linux/cpuidle.h> -+#include <linux/console.h> - - #include <asm/cacheflush.h> --#include <asm/leds.h> - #include <asm/processor.h> - #include <asm/thread_notify.h> - #include <asm/stacktrace.h> -@@ -60,6 +60,18 @@ extern void setup_mm_for_reboot(void); - - static volatile int hlt_counter; - -+#ifdef CONFIG_SMP -+void arch_trigger_all_cpu_backtrace(void) -+{ -+ smp_send_all_cpu_backtrace(); -+} -+#else -+void arch_trigger_all_cpu_backtrace(void) -+{ -+ dump_stack(); -+} -+#endif -+ - void disable_hlt(void) - { - hlt_counter++; -@@ -92,6 +104,31 @@ __setup("hlt", hlt_setup); - extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); - typedef void (*phys_reset_t)(unsigned long); - -+#ifdef CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART -+void arm_machine_flush_console(void) -+{ -+ printk("\n"); -+ pr_emerg("Restarting %s\n", linux_banner); -+ if (console_trylock()) { -+ console_unlock(); -+ return; -+ } -+ -+ mdelay(50); -+ -+ local_irq_disable(); -+ if (!console_trylock()) -+ pr_emerg("arm_restart: Console was locked! Busting\n"); -+ else -+ pr_emerg("arm_restart: Console was locked!\n"); -+ console_unlock(); -+} -+#else -+void arm_machine_flush_console(void) -+{ -+} -+#endif -+ - /* - * A temporary stack to use for CPU reset. This is static so that we - * don't clobber it with the identity mapping. When running with this -@@ -207,9 +244,9 @@ void cpu_idle(void) - - /* endless idle loop with no priority at all */ - while (1) { -+ idle_notifier_call_chain(IDLE_START); - tick_nohz_idle_enter(); - rcu_idle_enter(); -- leds_event(led_idle_start); - while (!need_resched()) { - #ifdef CONFIG_HOTPLUG_CPU - if (cpu_is_offline(smp_processor_id())) -@@ -240,9 +277,9 @@ void cpu_idle(void) - } else - local_irq_enable(); - } -- leds_event(led_idle_end); - rcu_idle_exit(); - tick_nohz_idle_exit(); -+ idle_notifier_call_chain(IDLE_END); - schedule_preempt_disabled(); - } - } -@@ -260,6 +297,15 @@ __setup("reboot=", reboot_setup); - void machine_shutdown(void) - { - #ifdef CONFIG_SMP -+ /* -+ * Disable preemption so we're guaranteed to -+ * run to power off or reboot and prevent -+ * the possibility of switching to another -+ * thread that might wind up blocking on -+ * one of the stopped CPUs. -+ */ -+ preempt_disable(); -+ - smp_send_stop(); - #endif - } -@@ -282,6 +328,10 @@ void machine_restart(char *cmd) - { - machine_shutdown(); - -+ /* Flush the console to make sure all the relevant messages make it -+ * out to the console drivers */ -+ arm_machine_flush_console(); -+ - arm_pm_restart(reboot_mode, cmd); - - /* Give a grace period for failure to restart of 1s */ -@@ -293,6 +343,77 @@ void machine_restart(char *cmd) - while (1); - } - -+/* -+ * dump a block of kernel memory from around the given address -+ */ -+static void show_data(unsigned long addr, int nbytes, const char *name) -+{ -+ int i, j; -+ int nlines; -+ u32 *p; -+ -+ /* -+ * don't attempt to dump non-kernel addresses or -+ * values that are probably just small negative numbers -+ */ -+ if (addr < PAGE_OFFSET || addr > -256UL) -+ return; -+ -+ printk("\n%s: %#lx:\n", name, addr); -+ -+ /* -+ * round address down to a 32 bit boundary -+ * and always dump a multiple of 32 bytes -+ */ -+ p = (u32 *)(addr & ~(sizeof(u32) - 1)); -+ nbytes += (addr & (sizeof(u32) - 1)); -+ nlines = (nbytes + 31) / 32; -+ -+ -+ for (i = 0; i < nlines; i++) { -+ /* -+ * just display low 16 bits of address to keep -+ * each line of the dump < 80 characters -+ */ -+ printk("%04lx ", (unsigned long)p & 0xffff); -+ for (j = 0; j < 8; j++) { -+ u32 data; -+ if (probe_kernel_address(p, data)) { -+ printk(" ********"); -+ } else { -+ printk(" %08x", data); -+ } -+ ++p; -+ } -+ printk("\n"); -+ } -+} -+ -+static void show_extra_register_data(struct pt_regs *regs, int nbytes) -+{ -+ mm_segment_t fs; -+ -+ fs = get_fs(); -+ set_fs(KERNEL_DS); -+ show_data(regs->ARM_pc - nbytes, nbytes * 2, "PC"); -+ show_data(regs->ARM_lr - nbytes, nbytes * 2, "LR"); -+ show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP"); -+ show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP"); -+ show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP"); -+ show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0"); -+ show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1"); -+ show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2"); -+ show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3"); -+ show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4"); -+ show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5"); -+ show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6"); -+ show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7"); -+ show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8"); -+ show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9"); -+ show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10"); -+ set_fs(fs); -+} -+ - void __show_regs(struct pt_regs *regs) - { - unsigned long flags; -@@ -352,6 +473,8 @@ void __show_regs(struct pt_regs *regs) - printk("Control: %08x%s\n", ctrl, buf); - } - #endif -+ -+ show_extra_register_data(regs, 128); - } - - void show_regs(struct pt_regs * regs) -diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c -index 6bbf936b..63bc22c8 100644 ---- a/arch/arm/kernel/sched_clock.c -+++ b/arch/arm/kernel/sched_clock.c -@@ -21,6 +21,8 @@ struct clock_data { - u32 epoch_cyc_copy; - u32 mult; - u32 shift; -+ bool suspended; -+ bool needs_suspend; - }; - - static void sched_clock_poll(unsigned long wrap_ticks); -@@ -49,6 +51,9 @@ static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask) - u64 epoch_ns; - u32 epoch_cyc; - -+ if (cd.suspended) -+ return cd.epoch_ns; -+ - /* - * Load the epoch_cyc and epoch_ns atomically. We do this by - * ensuring that we always write epoch_cyc, epoch_ns and -@@ -98,6 +103,13 @@ static void sched_clock_poll(unsigned long wrap_ticks) - update_sched_clock(); - } - -+void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits, -+ unsigned long rate) -+{ -+ setup_sched_clock(read, bits, rate); -+ cd.needs_suspend = true; -+} -+ - void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) - { - unsigned long r, w; -@@ -169,11 +181,23 @@ void __init sched_clock_postinit(void) - static int sched_clock_suspend(void) - { - sched_clock_poll(sched_clock_timer.data); -+ if (cd.needs_suspend) -+ cd.suspended = true; - return 0; - } - -+static void sched_clock_resume(void) -+{ -+ if (cd.needs_suspend) { -+ cd.epoch_cyc = read_sched_clock(); -+ cd.epoch_cyc_copy = cd.epoch_cyc; -+ cd.suspended = false; -+ } -+} -+ - static struct syscore_ops sched_clock_ops = { - .suspend = sched_clock_suspend, -+ .resume = sched_clock_resume, - }; - - static int __init sched_clock_syscore_init(void) -diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c -index ebfac782..5df79774 100644 ---- a/arch/arm/kernel/setup.c -+++ b/arch/arm/kernel/setup.c -@@ -575,6 +575,21 @@ static int __init early_mem(char *p) - size = memparse(p, &endp); - if (*endp == '@') - start = memparse(endp + 1, NULL); -+ -+#ifdef CONFIG_VIDEO_RESERVED_MEM_SIZE -+ /* -+ * Workaround for AK39xx H.264 decoder limitation which requires continous -+ * physical RAM which do NOT cross 32MB boundary (Decoder IP requirement). -+ * -+ * To avoid confusing developers, developer still pass something like -+ * mem=REAL_RAM_SIZE in command line. But we must skip memory reserved for -+ * H.264 decoder since they are NOT handled by normal kernel VM. They are -+ * manipulated by pmem-like drivers. -+ */ -+ if (meminfo.nr_banks == 0) { -+ size -= CONFIG_VIDEO_RESERVED_MEM_SIZE; -+ } -+#endif - - arm_add_memory(start, size); - -diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c -index d68d1b69..eb3a2912 100644 ---- a/arch/arm/kernel/signal.c -+++ b/arch/arm/kernel/signal.c -@@ -642,7 +642,7 @@ static void do_signal(struct pt_regs *regs, int syscall) - } - } - -- if (try_to_freeze()) -+ if (try_to_freeze_nowarn()) - goto no_signal; - - /* -diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c -index 8f14a1b8..22ad00ad 100644 ---- a/arch/arm/kernel/smp.c -+++ b/arch/arm/kernel/smp.c -@@ -56,6 +56,7 @@ enum ipi_msg_type { - IPI_CALL_FUNC, - IPI_CALL_FUNC_SINGLE, - IPI_CPU_STOP, -+ IPI_CPU_BACKTRACE, - }; - - static DECLARE_COMPLETION(cpu_running); -@@ -389,6 +390,7 @@ static const char *ipi_types[NR_IPI] = { - S(IPI_CALL_FUNC, "Function call interrupts"), - S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), - S(IPI_CPU_STOP, "CPU stop interrupts"), -+ S(IPI_CPU_BACKTRACE, "CPU backtrace"), - }; - - void show_ipi_list(struct seq_file *p, int prec) -@@ -520,6 +522,58 @@ static void ipi_cpu_stop(unsigned int cpu) - cpu_relax(); - } - -+static cpumask_t backtrace_mask; -+static DEFINE_RAW_SPINLOCK(backtrace_lock); -+ -+/* "in progress" flag of arch_trigger_all_cpu_backtrace */ -+static unsigned long backtrace_flag; -+ -+void smp_send_all_cpu_backtrace(void) -+{ -+ unsigned int this_cpu = smp_processor_id(); -+ int i; -+ -+ if (test_and_set_bit(0, &backtrace_flag)) -+ /* -+ * If there is already a trigger_all_cpu_backtrace() in progress -+ * (backtrace_flag == 1), don't output double cpu dump infos. -+ */ -+ return; -+ -+ cpumask_copy(&backtrace_mask, cpu_online_mask); -+ cpu_clear(this_cpu, backtrace_mask); -+ -+ pr_info("Backtrace for cpu %d (current):\n", this_cpu); -+ dump_stack(); -+ -+ pr_info("\nsending IPI to all other CPUs:\n"); -+ smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE); -+ -+ /* Wait for up to 10 seconds for all other CPUs to do the backtrace */ -+ for (i = 0; i < 10 * 1000; i++) { -+ if (cpumask_empty(&backtrace_mask)) -+ break; -+ mdelay(1); -+ } -+ -+ clear_bit(0, &backtrace_flag); -+ smp_mb__after_clear_bit(); -+} -+ -+/* -+ * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace() -+ */ -+static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs) -+{ -+ if (cpu_isset(cpu, backtrace_mask)) { -+ raw_spin_lock(&backtrace_lock); -+ pr_warning("IPI backtrace for cpu %d\n", cpu); -+ show_regs(regs); -+ raw_spin_unlock(&backtrace_lock); -+ cpu_clear(cpu, backtrace_mask); -+ } -+} -+ - /* - * Main handler for inter-processor interrupts - */ -@@ -565,6 +619,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs) - irq_exit(); - break; - -+ case IPI_CPU_BACKTRACE: -+ ipi_cpu_backtrace(cpu, regs); -+ break; -+ - default: - printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", - cpu, ipinr); -diff --git a/arch/arm/mach-ak39/Kconfig b/arch/arm/mach-ak39/Kconfig -new file mode 100644 -index 00000000..79decd10 ---- /dev/null -+++ b/arch/arm/mach-ak39/Kconfig -@@ -0,0 +1,73 @@ -+# linux/arch/arm/mach-ak39/Kconfig -+# -+# Copyright 2013 Anaka Microelectronics -+# -+# Licensed under GPLv2 -+ -+# define CPU TYPE FLAGS -+config CPU_AK3910 -+ bool -+config CPU_AK3916 -+ bool -+config CPU_AK3918 -+ bool -+ -+# Machine support -+choice -+ prompt "ANYKA AK39xx boards" -+ default ARCH_SDK3910 -+ depends on ARCH_AK39 -+ -+config ARCH_SDK3910 -+ bool "SDK3910" -+ depends on ARCH_AK39 -+ select CPU_AK3910 -+ help -+ Say Y here if you are using the SDK3910(Athena v2 borad) on chip AK3910 -+ -+config ARCH_AIMER39_AK3916 -+ bool "Aimer39 AK3916 board" -+ depends on ARCH_AK39 -+ select CPU_AK3916 -+ help -+ Say Y here if you are using the Aimer39_AK3916_MB_v1.0.0 board on chip AK3916 -+ -+config ARCH_AIMER39_AK3918 -+ bool "Aimer39 AK3918 board" -+ depends on ARCH_AK39 -+ select CPU_AK3918 -+ help -+ Say Y here if you are using the Aimer39_AK3918_MB_v1.0.0 board on chip AK3918 -+ -+endchoice -+ -+# aisc cpufreq set -+config ASIC_FREQ_VALUE -+ int "Config asic frequency(if asic>100MHz asic=vclk; else asic=vclk/2)" -+ range 45000000 120000000 -+ default 90000000 -+ depends on ARCH_AK39 -+ help -+ config ak39xx asic frequency when the kernel uncompress. -+ note: vclk be equal to even asic. -+ -+# power managerment -+comment "Power management" -+config AK39_PM -+ bool "ak39 Power Management support" -+ depends on PM && ARCH_AK39 -+ help -+ Say Y here if you want support power management for AK39. -+ -+config AK39_CPUFREQ -+ bool "ak39 Frequency scaling support" -+ depends on CPU_FREQ && ARCH_AK39 -+ help -+ Say Y here, CPU Frequency scaling support for AK39 SoC CPUs. -+ -+# chip extra controller lib -+config AK39_PWM_TIMER -+ bool "ak39 PWM/Timer Control support" -+ depends on ARCH_AK39 -+ help -+ Say Y here if you want support pwm control. -diff --git a/arch/arm/mach-ak39/Makefile b/arch/arm/mach-ak39/Makefile -new file mode 100644 -index 00000000..91413177 ---- /dev/null -+++ b/arch/arm/mach-ak39/Makefile -@@ -0,0 +1,29 @@ -+#linux/arch/arm/mach-ak39/Makefile -+# -+# Copyright 2013 Anyka Microelectronics -+# -+# Licensed under GPLv2 -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+# Core support for all Anyka SoCs -+obj-y += cpu.o time.o irq.o clock.o \ -+ l2cache.o devices.o \ -+ ak39-gpio.o gpio.o \ -+ adc.o \ -+ reset.o reboot.o \ -+ -+ -+# chip extra interface -+obj-$(CONFIG_AK39_PWM_TIMER) += pwm_timer.o -+ -+# Power Management support -+obj-$(CONFIG_AK39_PM) += pm.o -+ -+# Machin support -+obj-$(CONFIG_ARCH_SDK3910) += mach-sdk3910.o -+obj-$(CONFIG_ARCH_AIMER39_AK3916) += mach-aimer39_ak3916.o -+obj-$(CONFIG_ARCH_AIMER39_AK3918) += mach-aimer39_ak3918.o -diff --git a/arch/arm/mach-ak39/Makefile.boot b/arch/arm/mach-ak39/Makefile.boot -new file mode 100644 -index 00000000..f2e0fa5e ---- /dev/null -+++ b/arch/arm/mach-ak39/Makefile.boot -@@ -0,0 +1,11 @@ -+ifdef CONFIG_VIDEO_RESERVED_MEM_SIZE -+ __ZRELADDR := $(shell /bin/bash -c 'printf "0x%08x" \ -+ $$[$(CONFIG_RAM_BASE) + $(CONFIG_VIDEO_RESERVED_MEM_SIZE) + 0x8000]') -+__PARAMS_PHYS := $(shell /bin/bash -c 'printf "0x%08x" \ -+ $$[$(CONFIG_RAM_BASE) + $(CONFIG_VIDEO_RESERVED_MEM_SIZE) + 0x100]') -+ zreladdr-y := $(__ZRELADDR) -+params_phys-y := $(__PARAMS_PHYS) -+else -+ zreladdr-y := 0x80008000 -+params_phys-y := 0x80000100 -+endif -diff --git a/arch/arm/mach-ak39/adc.c b/arch/arm/mach-ak39/adc.c -new file mode 100644 -index 00000000..aa778fd9 ---- /dev/null -+++ b/arch/arm/mach-ak39/adc.c -@@ -0,0 +1,186 @@ -+/* -+ * ak_adc.c - ak ADC1 operation API -+ * -+ * 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/delay.h> -+#include <linux/spinlock.h> -+#include <mach/adc.h> -+#include <mach/gpio.h> -+ -+static spinlock_t adc1_lock; -+ -+/** -+ * @BRIEF config saradc clk -+ * @AUTHOR Gao Wangsheng -+ * @DATE 2013-4-24 -+ * @PARAM div SARADC CLK = 12Mhz/(div+1); -+ * @PARAM div value always 2 -+ * @RETURN -+ * @NOTE: -+ */ -+static void adc1_clk_cfg(unsigned long div) -+{ -+ unsigned long saradc_chief_driven; -+ unsigned long saradc_module_driven; -+ -+ //reserve the driven value -+ saradc_chief_driven = ((REG32(SAR_IF_CFG_REG)) & (0x1<<0)); -+ saradc_module_driven = ((REG32(SAR_IF_CFG_REG)) & (0x7<<5)); -+ -+ //disable module chief driven by sar adc clk -+ REG32(SAR_IF_CFG_REG) &= (~(1<<0)); -+ -+ //disable Ain0_sampling Ain1_sampling Bat_sampling -+ REG32(SAR_IF_CFG_REG) &= (~(0x7<<5)); -+ -+ //close sar adc clk -+ REG32(AD_DA_CLK1_REG) &= (~(0x1<<3)); -+ -+ //cofig div -+ REG32(AD_DA_CLK1_REG) &= (~0x7); -+ REG32(AD_DA_CLK1_REG) |= (div & 0x7); -+ -+ //open sar adc clk -+ REG32(AD_DA_CLK1_REG) |= (0x1<<3); -+ -+ //get back the driven cfg -+ REG32(SAR_IF_CFG_REG) |= (saradc_chief_driven | saradc_module_driven); -+} -+ -+static void power_on_adc1(void) -+{ -+ REG32(AD_DA_CLK1_REG) &= (~(1 << 31)); -+} -+ -+static void power_off_adc1(void) -+{ -+ REG32(AD_DA_CLK1_REG) |= (1 << 31); -+} -+ -+static void enable_adc1_channel(int channel) -+{ -+ REG32(SAR_IF_CFG_REG) &= ~(1 << 0); -+ REG32(SAR_IF_CFG_REG) |= (1 << (channel + 5)); -+ REG32(SAR_IF_CFG_REG) |= (1 << 0); -+} -+ -+static void disable_adc1_channel(int channel) -+{ -+ REG32(SAR_IF_CFG_REG) &= ~(1 << 0); -+ REG32(SAR_IF_CFG_REG) &= ~(1 << (channel + 5)); -+ REG32(SAR_IF_CFG_REG) |= (1 << 0); -+} -+ -+/** -+ * @brief: Read AD0/AD1/BAT voltage -+ * @author: Zhongjunchao -+ * @data: 2011-7-20 -+ * -+ * @Warning: Please don`t use this function in IRQ handle routine! -+ */ -+unsigned long adc1_read_channel(int channel) -+{ -+ int count; -+ unsigned long val = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&adc1_lock, flags); -+ -+ power_on_adc1(); -+ enable_adc1_channel(channel); -+ mdelay(1); -+ -+ val = ((REG32(SAR_IF_SMP_DAT_REG) >> (channel * 10)) & 0x3ff); -+ if (channel == AK_ADC1_BAT) { -+ for(count = 0; count < 4; count++) { -+ mdelay(1); -+ val += ((REG32(SAR_IF_SMP_DAT_REG) >> (channel * 10)) & 0x3ff); -+ } -+ val /= 5; -+ } -+ val = (val * AK_AVCC) >> 10; -+ -+ disable_adc1_channel(channel); -+ power_off_adc1(); -+ -+ spin_unlock_irqrestore(&adc1_lock, flags); -+ -+ return val; -+} -+ -+/** -+ * @brief: ADC1 initialization -+ * @author: Zhongjunchao -+ * @data: 2011-7-20 -+ * @modify: 2013-4-27 -+ * -+ * @note: This function will init ADC1 clock and sample rate, and then enable -+ * ADC1 but not power on. Any device use ADC1 please use the read value API. -+ * We use some default value, if ADC1 can`t work make be will change it. -+ * Please use this function in machine init. -+ */ -+int adc1_init(void) -+{ -+ unsigned long samplerate; -+ unsigned long adc1_clk, clkdiv; -+ unsigned long spl_cycle, spl_hold, spl_wait; -+ -+ spin_lock_init(&adc1_lock); -+ -+ /* reset adc1 */ -+ REG32(RESET_CTRL_REG) &= (~(1<<30)); -+ -+ /* config adc1 clk, default 1.5MHz(BAT use only in 1.5MHz) */ -+ clkdiv = ADC1_MAIN_CLK/ADC1_DEFAULT_CLK - 1; -+ clkdiv &= 0x7; -+ adc1_clk_cfg(clkdiv); -+ -+ /* release reset */ -+ REG32(RESET_CTRL_REG) |= (1<<30); -+ -+ /* disable all sample */ -+ REG32(SAR_IF_CFG_REG) &= ( ~( (1<<0) | (0x7<<5) ) ); -+ -+ /* clear all adc1 interrupt state */ -+ REG32(SAR_IF_INT_STATUS_REG) = 0x0; -+ -+ /* mask all adc1 interrupt */ -+ REG32(SAR_IF_CFG_REG) &= (~ (0xf<<1)); -+ -+ /* power on adc1 */ -+ power_on_adc1(); -+ -+ //select AVCC -+ REG32(SAR_ADC_CFG_REG) &= (~((1<<16)|(1<<22))); -+ -+ /* one channel one time, default samplerate is 5000 */ -+ adc1_clk = ADC1_MAIN_CLK / (clkdiv + 1); -+ samplerate = DEFAULT_SAMPLE; -+ spl_cycle = adc1_clk / samplerate; -+ spl_wait = 1; -+ spl_hold = spl_wait + 16 + 1; -+ -+ REG32(SAR_IF_CFG_REG) &= (~(0xff << 14)); -+ REG32(SAR_IF_CFG_REG) |= (spl_wait << 14); -+ -+ REG32(SAR_TIMING_CFG_REG) = 0; -+ REG32(SAR_TIMING_CFG_REG) = spl_cycle | (spl_hold << 16) ; -+ -+ /* spl_cnt config, what is it ? */ -+ REG32(SAR_IF_CFG_REG) &= (~(0x7 << 8)); -+ REG32(SAR_IF_CFG_REG) |= (1 << 8); -+ -+ /* disable the bat div radio */ -+ REG32(SAR_ADC_CFG_REG) &= ~(1 << 1) ; -+ -+ /* we don`t know who will use ADC1, so we close it */ -+ power_off_adc1(); -+ -+ return 0; -+} -diff --git a/arch/arm/mach-ak39/ak39-gpio.c b/arch/arm/mach-ak39/ak39-gpio.c -new file mode 100755 -index 00000000..401235b0 ---- /dev/null -+++ b/arch/arm/mach-ak39/ak39-gpio.c -@@ -0,0 +1,839 @@ -+/* -+ * arch/arm/mach-ak39/gpio.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+#include <linux/module.h> -+#include <asm/irq.h> -+#include <mach/gpio.h> -+ -+//share pin config fore module in AK39xx -+struct gpio_sharepin_cfg share_cfg_module[] = { -+ {ePIN_AS_OPCLK, SHARE_CFG1, (0x3<<2), (1<<2), 0, 0, 0, 0}, -+ {ePIN_AS_JTAG, SHARE_CFG1, (0x3f<<16)|(1<<1), (0x15<<16)|(1<<1), 0, 0, 0, 0}, -+ {ePIN_AS_RTCK, SHARE_CFG1, (0x3<<22), (1<<22), 0, 0, 0, 0}, -+ {ePIN_AS_I2S, SHARE_CFG13, ((0xf<<8)|(1<<13)), ((0xf<<8)|(1<<13)), 0, 0, (0x3<<4), (0x3<<4)}, -+ {ePIN_AS_PWM1, SHARE_CFG1, ((0x3<<16)|(1<<4)), ((0x3<<16)|(1<<4)), 0, 0, 0, 0}, -+ {ePIN_AS_PWM2, SHARE_CFG1, (0x3<<18), (0x3<<18), 0, 0, 0, 0}, -+ {ePIN_AS_PWM3, SHARE_CFG1, ((0x3<<20)|(1<<6)), ((0x3<<20)|(1<<6)), 0, 0, 0, 0}, -+ {ePIN_AS_PWM4, SHARE_CFG1, ((0x3<<22)|(1<<7)), ((0x3<<22)|(1<<7)), 0, 0, 0, 0}, -+#if defined(CONFIG_CPU_AK3910) -+ {ePIN_AS_PWM5, SHARE_CFG13, (0x3<<2), (0x3<<2), 0, 0, (0x3<<4), (0x1<<4)}, -+ {ePIN_AS_SPI1, SHARE_CFG3, 0, 0, 0, 0, ((0x3<<23)|(1<<21)|(1<<19)|(0x3)),((0x1<<23)|(1<<21)|(1<<19)|(0x3))}, -+ {ePIN_AS_SPI2, SHARE_CFG3, 0, 0, 0, 0, ((0x3<<23)|(1<<21)|(1<<19)|(0xf<<2)),((0x3<<23)|(1<<21)|(1<<19)|(0xa<<2))}, -+#elif defined(CONFIG_CPU_AK3916) || defined(CONFIG_CPU_AK3918) -+ {ePIN_AS_PWM5, SHARE_CFG13, ((1<<12)|(0x3<<2)), ((1<<12)|(0x3<<2)), 0, 0, (0x3<<4), (0x1<<4)}, -+ {ePIN_AS_SPI1, SHARE_CFG3, 0, 0, 0, 0, ((0x3<<23)|(1<<21)|(1<<19)|(0x3)),((0x1<<23)|(1<<21)|(1<<19)|(0x3))}, -+ {ePIN_AS_SPI2, SHARE_CFG3, 0, 0, 0, 0, ((0x3<<23)|(1<<21)|(1<<19)|(0xf<<2)),((0x3<<23)|(1<<21)|(1<<19)|(0xa<<2))}, -+#endif -+ {ePIN_AS_UART1, SHARE_CFG1, (0x3<<14), (0x3<<14), 0, 0, 0, 0}, -+ {ePIN_AS_UART2, SHARE_CFG1, (0xff<<16), (0xaa<<16), 0, 0, 0, 0}, -+ {ePIN_AS_CAMERA, SHARE_CFG2, 0, 0, (0xf), (0x0), 0, 0}, -+ {ePIN_AS_SDIO, SHARE_CFG3, 0, 0, 0, 0, (0xff<<16), (0x57<<16)}, -+ {ePIN_AS_MCI, SHARE_CFG3, 0, 0, 0, 0, (0xf<<6), (0xf<<6)}, -+ {ePIN_AS_MCI_8LINE, SHARE_CFG3, 0, 0, 0, 0, (0x3ff<<6), (0x15f<<6)}, -+ {ePIN_AS_MAC, SHARE_CFG12, (0x3<<2), (1<<2), (0x1fff<<4), (0x1fff<<4), 0, 0}, -+ {ePIN_AS_I2C, SHARE_CFG3, 0, 0, 0, 0, (0x3<<25), (0x3<<25)}, -+ {ePIN_AS_IRDA, SHARE_CFG3, 0, 0, 0, 0, (0x3<<2), (0x1<<2)}, -+ {ePIN_AS_DUMMY, EXIT_CFG, 0, 0, 0, 0, 0, 0} -+}; -+ -+struct gpio_pupd_cfg pupd_cfg_info[] = { -+ //pin, index, register, up/down -+ {AK_GPIO_0, 0, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_1, 19, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_2, 20, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_3, 1, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_4, 21, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_5, 22, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_6, 23, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_7, 24, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_8, 4, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_9, 5, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_10, 7, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_11, 8, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_12, 10, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_13, 11, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_14, 14, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_15, 15, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_16, 16, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_17, 17, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_18, 18, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_19, 20, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_20, 21, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_21, 22, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_22, 23, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_23, 25, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_24, 26, PUPD_CFG2, PULLDOWN}, -+ {AK_GPIO_25, 0, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_26, 1, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_27, 20, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_28, 21, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_29, 2, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_30, 3, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_31, 4, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_32, 5, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_33, 6, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_34, 7, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_35, 8, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_36, 9, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_37, 10, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_38, 11, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_39, 12, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_40, 13, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_41, 14, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_42, 15, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_43, 16, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_44, 17, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_45, 18, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_46, 19, PUPD_CFG3, PULLUP}, -+ {AK_GPIO_47, 2, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_48, 3, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_50, 5, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_51, 6, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_52, 7, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_53, 8, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_54, 9, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_55, 10, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_56, 11, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_57, 12, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_58, 13, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_59, 14, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_60, 15, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_61, 16, PUPD_CFG1, PULLDOWN}, -+ {AK_GPIO_62, 17, PUPD_CFG1, PULLUP}, -+ {AK_GPIO_63, 18, PUPD_CFG1, PULLUP}, -+}; -+ -+//this used to clr in gpio chare pin cfg1 -+struct sharepin_as_gpio sharepin_cfg_gpio1[] = { -+ {0, 0, 0, AS_GPIO_CFG_BIT1}, -+ {3, 3, 1, AS_GPIO_CFG_BIT1}, -+ {47, 47, 2, AS_GPIO_CFG_BIT2}, -+ {48, 48, 4, AS_GPIO_CFG_BIT1}, -+ {50, 50, 6, AS_GPIO_CFG_BIT1}, -+ {51, 51, 7, AS_GPIO_CFG_BIT1}, -+ {52, 52, 8, AS_GPIO_CFG_BIT1}, -+ {53, 53, 9, AS_GPIO_CFG_BIT1}, -+ {54, 54, 10, AS_GPIO_CFG_BIT1}, -+ {55, 55, 11, AS_GPIO_CFG_BIT1}, -+ {56, 56, 12, AS_GPIO_CFG_BIT1}, -+ {57, 57, 13, AS_GPIO_CFG_BIT1}, -+ {1, 1, 14, AS_GPIO_CFG_BIT1}, -+ {2, 2, 15, AS_GPIO_CFG_BIT1}, -+ {4, 4, 16, AS_GPIO_CFG_BIT2}, -+ {5, 5, 18, AS_GPIO_CFG_BIT2}, -+ {6, 6, 20, AS_GPIO_CFG_BIT2}, -+ {7, 7, 22, AS_GPIO_CFG_BIT2}, -+}; -+ -+//this used to clr in gpio chare pin cfg2 -+struct sharepin_as_gpio sharepin_cfg_gpio3[] = { -+ {25, 25, 0, AS_GPIO_CFG_BIT1}, -+ {26, 26, 1, AS_GPIO_CFG_BIT1}, -+ {29, 29, 2, AS_GPIO_CFG_BIT2}, -+ {30, 30, 4, AS_GPIO_CFG_BIT2}, -+ {31, 31, 6, AS_GPIO_CFG_BIT1}, -+ {32, 32, 7, AS_GPIO_CFG_BIT1}, -+ {33, 33, 8, AS_GPIO_CFG_BIT1}, -+ {34, 36, 9, AS_GPIO_CFG_BIT1}, -+ {37, 38, 10, AS_GPIO_CFG_BIT2}, -+ {39, 39, 12, AS_GPIO_CFG_BIT2}, -+ {40, 40, 14, AS_GPIO_CFG_BIT2}, -+ {41, 41, 16, AS_GPIO_CFG_BIT1}, -+ {42, 42, 17, AS_GPIO_CFG_BIT1}, -+ {43, 43, 18, AS_GPIO_CFG_BIT2}, -+ {44, 44, 20, AS_GPIO_CFG_BIT2}, -+ {45, 46, 22, AS_GPIO_CFG_BIT2}, -+ {27, 27, 25, AS_GPIO_CFG_BIT1}, -+ {28, 28, 26, AS_GPIO_CFG_BIT1}, -+}; -+ -+#define INVALID_WK_BIT 0xff -+struct t_gpio_wakeup_cfg gpio_wakeup_cfg[] = { -+ //gpio_start gpio_end start_bit -+ {AK_GPIO_0, AK_GPIO_7, 0}, -+ {AK_GPIO_12, AK_GPIO_14, 8}, -+ {AK_GPIO_22, AK_GPIO_30, 11}, -+ {AK_GPIO_39, AK_GPIO_44, 16}, -+ {AK_GPIO_47, AK_GPIO_55, 22}, -+ {AK_GPIO_57, AK_GPIO_57, 31}, -+}; -+ -+ -+unsigned int ak3910_invalid_gpio[] = { -+ AK_GPIO_37, AK_GPIO_38, AK_GPIO_39, AK_GPIO_40, AK_GPIO_56, -+ AK_GPIO_58, AK_GPIO_59, AK_GPIO_60, AK_GPIO_61, AK_GPIO_62, -+ AK_GPIO_63, -+}; -+ -+unsigned int ak3916_invalid_gpio[] = { -+}; -+ -+static unsigned char get_bit_by_pin_wk(unsigned char pin) -+{ -+ int i, n; -+ n = ARRAY_SIZE(gpio_wakeup_cfg); -+ -+ for (i=0; i<n; i++) { -+ if (pin >= gpio_wakeup_cfg[i].gpio_start && pin <= gpio_wakeup_cfg[i].gpio_end) -+ return gpio_wakeup_cfg[i].start_bit + (pin - gpio_wakeup_cfg[i].gpio_start); -+ } -+ -+ return INVALID_WK_BIT; -+} -+ -+/* when the specific bit is set to 0, the wake-up GPIO is rising triggered -+ * when the specific bit is set to 1, the wake-up GPIO is falling triggered -+ */ -+void ak_gpio_wakeup_pol(unsigned int pin, unsigned char pol) -+{ -+ unsigned char bit = get_bit_by_pin_wk(pin); -+ unsigned int val; -+ -+ if (bit == INVALID_WK_BIT) { -+ panic("this pin %u doesn't support wakeup function\n", pin); -+ return; -+ } -+ -+ val = REG32(AK_WGPIO_POLARITY); -+ val &= ~(1 << bit); -+ val |= (pol << bit); -+ REG32(AK_WGPIO_POLARITY) = val; -+} -+EXPORT_SYMBOL(ak_gpio_wakeup_pol); -+ -+int ak_gpio_wakeup(unsigned int pin, unsigned char enable) -+{ -+ unsigned char bit = get_bit_by_pin_wk(pin); -+ unsigned int val; -+ -+ if (bit == INVALID_WK_BIT) { -+ panic("this pin %d doesn't support wakeup function\n", pin); -+ return -1; -+ } -+ //clear wake gpio status -+ val = REG32(AK_WGPIO_CLEAR); -+ val |= (1 << bit); -+ REG32(AK_WGPIO_CLEAR) = val; -+ val &= ~(1 << bit); -+ REG32(AK_WGPIO_CLEAR) = val; -+ -+ val = REG32(AK_WGPIO_ENABLE); -+ if (enable == AK_WAKEUP_ENABLE) { -+ val |= (1 << bit); -+ } else if (enable == AK_WAKEUP_DISABLE) { -+ val &= ~(1 << bit); -+ } else -+ panic("wrong enable value in ak_gpio_wakeup\n"); -+ REG32(AK_WGPIO_ENABLE) = val; -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_wakeup); -+ -+/* -+ * @brief set gpio pin group as specified module used -+ * @param[in] PinCfg enum data. the specified module -+ */ -+void ak_group_config(T_GPIO_SHAREPIN_CFG mod_name) -+{ -+ unsigned long i, flags, val = 0; -+ -+ if(ePIN_AS_GPIO == mod_name) { -+ //set all pin as gpio except uart0 -+ local_irq_save(flags); -+ __raw_writel(0xc000, AK_SHAREPIN_CON1); -+ __raw_writel(0xf, AK_SHAREPIN_CON2); -+ __raw_writel(0x0, AK_SHAREPIN_CON3); -+ local_irq_restore(flags); -+ return; -+ } -+ -+ for(i = 0; ; i++) { -+ if(ePIN_AS_DUMMY == share_cfg_module[i].func_module) -+ break; -+ -+ if(mod_name == share_cfg_module[i].func_module) { -+ //set pull attribute for module -+ g_ak39_setgroup_attribute(mod_name); -+ -+ local_irq_save(flags); -+ switch(share_cfg_module[i].share_config) { -+ case SHARE_CFG1: //set share pin cfg reg1 -+ val = __raw_readl(AK_SHAREPIN_CON1); -+ val &= ~(share_cfg_module[i].reg1_bit_mask); -+ val |= (share_cfg_module[i].reg1_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON1); -+ break; -+ -+ case SHARE_CFG2: //set share pin cfg reg2 -+ val = __raw_readl(AK_SHAREPIN_CON2); -+ val &= ~(share_cfg_module[i].reg2_bit_mask); -+ val |= (share_cfg_module[i].reg2_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON2); -+ break; -+ -+ case SHARE_CFG3: //set share pin cfg reg3 -+ val = __raw_readl(AK_SHAREPIN_CON3); -+ val &= ~(share_cfg_module[i].reg3_bit_mask); -+ val |= (share_cfg_module[i].reg3_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON3); -+ break; -+ -+ case SHARE_CFG12: -+ val = __raw_readl(AK_SHAREPIN_CON1); -+ val &= ~(share_cfg_module[i].reg1_bit_mask); -+ val |= (share_cfg_module[i].reg1_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON1); -+ -+ val = __raw_readl(AK_SHAREPIN_CON2); -+ val &= ~(share_cfg_module[i].reg2_bit_mask); -+ val |= (share_cfg_module[i].reg2_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON2); -+ break; -+ case SHARE_CFG13: -+ val = __raw_readl(AK_SHAREPIN_CON1); -+ val &= ~(share_cfg_module[i].reg1_bit_mask); -+ val |= (share_cfg_module[i].reg1_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON1); -+ -+ val = __raw_readl(AK_SHAREPIN_CON3); -+ val &= ~(share_cfg_module[i].reg3_bit_mask); -+ val |= (share_cfg_module[i].reg3_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON3); -+ break; -+ -+ case SHARE_CFG23: -+ val = __raw_readl(AK_SHAREPIN_CON2); -+ val &= ~(share_cfg_module[i].reg2_bit_mask); -+ val |= (share_cfg_module[i].reg2_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON2); -+ -+ val = __raw_readl(AK_SHAREPIN_CON3); -+ val &= ~(share_cfg_module[i].reg3_bit_mask); -+ val |= (share_cfg_module[i].reg3_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON3); -+ break; -+ -+ case SHARE_CFG123: -+ val = __raw_readl(AK_SHAREPIN_CON1); -+ val &= ~(share_cfg_module[i].reg1_bit_mask); -+ val |= (share_cfg_module[i].reg1_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON1); -+ -+ val = __raw_readl(AK_SHAREPIN_CON2); -+ val &= ~(share_cfg_module[i].reg2_bit_mask); -+ val |= (share_cfg_module[i].reg2_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON2); -+ -+ val = __raw_readl(AK_SHAREPIN_CON3); -+ val &= ~(share_cfg_module[i].reg3_bit_mask); -+ val |= (share_cfg_module[i].reg3_bit_value); -+ __raw_writel(val, AK_SHAREPIN_CON3); -+ break; -+ -+ default: -+ break; -+ } -+ local_irq_restore(flags); -+ return ; -+ } -+ } -+ return ; -+} -+EXPORT_SYMBOL(ak_group_config); -+ -+static unsigned char gpio_assert_legal(unsigned long pin) -+{ -+ int i, len; -+ unsigned int *gpio_legal; -+ -+ if ((pin < 0) || (pin > GPIO_UPLIMIT)) { -+ return AK_FALSE; -+ } -+ -+#if defined(CONFIG_CPU_AK3910) -+ len = ARRAY_SIZE(ak3910_invalid_gpio); -+ gpio_legal = ak3910_invalid_gpio; -+#elif defined(CONFIG_CPU_AK3916) || defined(CONFIG_CPU_AK3918) -+ len = ARRAY_SIZE(ak3916_invalid_gpio); -+ gpio_legal = ak3916_invalid_gpio; -+#endif -+ -+ for(i = 0; i < len; i++) { -+ if(gpio_legal[i] == pin) -+ return AK_FALSE; -+ } -+ return AK_TRUE; -+} -+ -+ -+/** -+ * @brief set gpio share pin as gpio -+ * @param pin [in] gpio pin ID -+ */ -+int g_ak39_setpin_as_gpio(unsigned int pin) -+{ -+ int i, bit = 0; -+ unsigned long flags; -+ -+ //check param -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, Invalid gpio %u configuration!\n", pin); -+ return -1; -+ } -+ -+ /* reserved uart0 confige, but provide the error info */ -+ if(AK_GPIO_1 == pin || AK_GPIO_2 == pin) { -+ REG32(AK_SHAREPIN_CON1) |= (0x3 << 14); -+ return -1; -+ } -+ -+ //loop to find the correct bits to clr in share ping cfg1 -+ for(i = 0; i < ARRAY_SIZE(sharepin_cfg_gpio1); i++){ -+ if((pin >= sharepin_cfg_gpio1[i].gpio_start) -+ && (pin <= sharepin_cfg_gpio1[i].gpio_end)) -+ { -+ local_irq_save(flags); -+ -+ bit = sharepin_cfg_gpio1[i].index; -+ if (sharepin_cfg_gpio1[i].flag == AS_GPIO_CFG_BIT1) -+ REG32(AK_SHAREPIN_CON1) &= ~(1 << bit); -+ else if (sharepin_cfg_gpio1[i].flag == AS_GPIO_CFG_BIT2) -+ REG32(AK_SHAREPIN_CON1) &= ~(0x3 << bit); -+ -+ local_irq_restore(flags); -+ return 0; -+ } -+ } -+ -+ //find the correct bits to clr in share ping cfg2 -+ if ((pin >= AK_GPIO_8) && (pin <= AK_GPIO_24)) { -+ local_irq_save(flags); -+ if (pin <= AK_GPIO_11) -+ REG32(AK_SHAREPIN_CON2) |= (1<<(pin-8)); -+ else -+ REG32(AK_SHAREPIN_CON2) &= ~(1<<(pin-8)); -+ local_irq_restore(flags); -+ return 0; -+ } -+ -+ //loop to find the correct bits to set in share ping cfg3 -+ for(i = 0; i < ARRAY_SIZE(sharepin_cfg_gpio3); i++){ -+ if((pin >= sharepin_cfg_gpio3[i].gpio_start) -+ && (pin <= sharepin_cfg_gpio3[i].gpio_end)) -+ { -+ local_irq_save(flags); -+ -+ bit = sharepin_cfg_gpio3[i].index; -+ if (sharepin_cfg_gpio3[i].flag == AS_GPIO_CFG_BIT1) -+ REG32(AK_SHAREPIN_CON3) &= ~(1 << bit); -+ else if (sharepin_cfg_gpio3[i].flag == AS_GPIO_CFG_BIT2) -+ REG32(AK_SHAREPIN_CON3) &= ~(0x3 << bit); -+ -+ local_irq_restore(flags); -+ return 0; -+ } -+ } -+ return 0; -+} -+ -+/* -+ enable: 1:enable pullup 0:disable pullup function -+ if the pin is attached pullup and pulldown resistor, then writing 1 to enable -+ pullup, 0 to enable pulldown, if you want to disable pullup/pulldown, then -+ disable the PE parameter -+*/ -+int g_ak39_gpio_pullup(unsigned int pin, unsigned char enable) -+{ -+ void __iomem *base = AK_PPU_PPD_BASE(pin); -+ unsigned long flags; -+ int i; -+ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, Invalid gpio %u configuration!\n", pin); -+ return -1; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(pupd_cfg_info); i++) { -+ if (pin == pupd_cfg_info[i].pin) { -+ -+ if (pupd_cfg_info[i].pupd_type == PULLDOWN) -+ panic("Invalid GPIO[%d] pullup config.\n", pin); -+ -+ switch(pupd_cfg_info[i].pupd_cfg) { -+ case PUPD_CFG1: -+ base = AK_PPU_PPD1; -+ break; -+ case PUPD_CFG2: -+ base = AK_PPU_PPD2; -+ break; -+ case PUPD_CFG3: -+ base = AK_PPU_PPD3; -+ break; -+ } -+ -+ local_irq_save(flags); -+ if (enable == AK_PULLUP_ENABLE) -+ REG32(base) &= ~(1 << pupd_cfg_info[i].index); -+ else if (enable == AK_PULLUP_DISABLE) -+ REG32(base) |= (1 << pupd_cfg_info[i].index); -+ local_irq_restore(flags); -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+//1.enable pulldown 0.disable pulldown -+ int g_ak39_gpio_pulldown(unsigned int pin, unsigned char enable) -+{ -+ void __iomem *base = AK_PPU_PPD_BASE(pin); -+ unsigned long flags; -+ int i; -+ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, Invalid gpio %u configuration!\n", pin); -+ return -1; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(pupd_cfg_info); i++) { -+ if (pin == pupd_cfg_info[i].pin) { -+ -+ if (pupd_cfg_info[i].pupd_type == PULLUP) -+ panic("Invalid GPIO[%d] pulldown config.\n", pin); -+ -+ switch(pupd_cfg_info[i].pupd_cfg) { -+ case PUPD_CFG1: -+ base = AK_PPU_PPD1; -+ break; -+ case PUPD_CFG2: -+ base = AK_PPU_PPD2; -+ break; -+ case PUPD_CFG3: -+ base = AK_PPU_PPD3; -+ break; -+ } -+ -+ local_irq_save(flags); -+ if (enable == AK_PULLDOWN_ENABLE) -+ REG32(base) &= ~(1 << pupd_cfg_info[i].index); -+ else if (enable == AK_PULLDOWN_DISABLE) -+ REG32(base) |= (1 << pupd_cfg_info[i].index); -+ local_irq_restore(flags); -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+void g_ak39_setgroup_attribute(T_GPIO_SHAREPIN_CFG mod_name) -+{ -+ unsigned long pin, start_pin = 0, end_pin = 0; -+ -+ switch (mod_name) { -+ case ePIN_AS_MCI: -+ start_pin = 31, end_pin = 36; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ break; -+ -+ case ePIN_AS_MCI_8LINE: -+ start_pin = 31, end_pin = 40; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ break; -+ -+ case ePIN_AS_SDIO: -+ start_pin = 41, end_pin = 46; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ break; -+ -+ case ePIN_AS_SPI1: -+ /* spi_clk #spi_cs */ -+ start_pin = 25, end_pin = 26; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ -+ start_pin = 43, end_pin = 46; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ -+ break; -+ -+ case ePIN_AS_SPI2: -+ /* spi_clk #spi_cs */ -+ start_pin = 29, end_pin = 30; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ -+ start_pin = 43, end_pin = 46; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ break; -+ -+ case ePIN_AS_I2S: -+ start_pin = 52, end_pin = 53; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_FALSE); -+ } -+ g_ak39_gpio_pullup(AK_GPIO_57, AK_FALSE); -+ g_ak39_gpio_pulldown(AK_GPIO_55, AK_FALSE); -+ g_ak39_gpio_pullup(AK_GPIO_55, AK_FALSE); -+ break; -+ -+ case ePIN_AS_UART1: -+ start_pin = 1, end_pin = 2; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ break; -+ -+ case ePIN_AS_UART2: -+ start_pin = 4, end_pin = 7; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_TRUE); -+ } -+ break; -+ -+ case ePIN_AS_I2C: -+ start_pin = 27, end_pin = 28; -+ for (pin = start_pin; pin <= end_pin; pin++) -+ { -+ g_ak39_gpio_pullup(pin, AK_FALSE); -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+/* -+ * configuration gpio pin -+ * 0: corresponding port is input mode -+ * 1: corresponding port is output mode -+ */ -+int g_ak39_gpio_cfgpin(unsigned int pin, unsigned int to) -+{ -+ void __iomem *base = AK_GPIO_DIR_BASE(pin); -+ unsigned int offset = ((pin) & 31); -+ unsigned long flags; -+ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, Invalid gpio %d configuration!\n", pin); -+ return -1; -+ } -+ -+ /* gpio[49] can't set output mode for ak39xx*/ -+ if ((to == AK_GPIO_DIR_OUTPUT)&&(pin == AK_GPIO_49)) { -+ panic("Error, gpio %d isn't config output mode\n", pin); -+ return -1; -+ } -+ -+ local_irq_save(flags); -+ if (AK_GPIO_DIR_INPUT == to) -+ REG32(base) &= ~(1 << offset); -+ else if (AK_GPIO_DIR_OUTPUT == to) -+ REG32(base) |= (1 << offset); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+/* hold the real-time output value from GPIO[x] */ -+int g_ak39_gpio_setpin(unsigned int pin, unsigned int to) -+{ -+ void __iomem *base = AK_GPIO_OUT_BASE(pin); -+ unsigned int offset = ((pin) & 31); -+ unsigned long flags; -+ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, Invalid gpio %d configuration!\n", pin); -+ return -1; -+ } -+ -+ /* gpio[49] can't set output level for ak39xx*/ -+ if (pin == AK_GPIO_49) { -+ panic("Error, gpio %d isn't config outpu level\n", pin); -+ return -1; -+ } -+ -+ local_irq_save(flags); -+ if (AK_GPIO_OUT_LOW == to) -+ REG32(base) &= ~(1 << offset); -+ else if (AK_GPIO_OUT_HIGH == to) -+ REG32(base) |= (1 << offset); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+ -+/* hold the real-time input value of GPIO[x] */ -+ int g_ak39_gpio_getpin(unsigned int pin) -+{ -+ void __iomem *base = AK_GPIO_IN_BASE(pin); -+ unsigned int offset = ((pin) & 31); -+ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, read invalid gpio %d status!\n", pin); -+ return -1; -+ } -+ return ((__raw_readl(base) & (1 << offset)) == (1 << offset)); -+} -+ -+ -+/* -+ * enalbe/disable the interrupt function of GPIO[X] -+ * 1: interrupt function of corresponding port is enable -+ * 0: interrupt function of corresponding port is disable -+ */ -+int g_ak39_gpio_inten(unsigned int pin, unsigned int enable) -+{ -+ void __iomem *base = AK_GPIO_INTEN_BASE(pin); -+ unsigned int offset = ((pin) & 31); -+ unsigned long flags; -+ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, invalid gpio %d!\n", pin); -+ return -1; -+ } -+ -+ local_irq_save(flags); -+ if (AK_GPIO_INT_ENABLE == enable) -+ REG32(base) |= (1 << offset); -+ else if (AK_GPIO_INT_DISABLE == enable) -+ REG32(base) &= ~(1 << offset); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+ -+/* -+ * interrupt polarity selection -+ * 0: the input interrupt polarity of GPIO[X] is active high -+ * 1: the input interrupt polarity of GPIO[X] is active low -+ */ -+int g_ak39_gpio_intpol(unsigned int pin, unsigned int level) -+{ -+ void __iomem *base = AK_GPIO_INTPOL_BASE(pin); -+ unsigned int offset = ((pin) & 31); -+ unsigned long flags; -+ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, invalid gpio %d!\n", pin); -+ return -1; -+ } -+ -+ local_irq_save(flags); -+ if (AK_GPIO_INT_HIGHLEVEL == level) -+ REG32(base) &= ~(1 << offset); -+ else if (AK_GPIO_INT_LOWLEVEL == level) -+ REG32(base) |= (1 << offset); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+int reg_set_mutli_bit(void __iomem *reg, unsigned int value, int bit, int index) -+{ -+ unsigned long con, flags; -+ -+ if (bit <= 0) -+ return -1; -+ -+ local_irq_save(flags); -+ -+ con = __raw_readl(reg); -+ con &= ~(((1 << bit) - 1) << index); -+ con |= (value << index); -+ __raw_writel(con, reg); -+ -+ local_irq_restore(flags); -+ return 0; -+} -+EXPORT_SYMBOL(reg_set_mutli_bit); -+ -+int g_ak39_gpio_to_irq(unsigned int pin) -+{ -+ if(!gpio_assert_legal(pin)) { -+ panic("Error, invalid gpio %d!\n", pin); -+ return -1; -+ } -+ return (IRQ_GPIO_0 + (pin - AK_GPIO_0)); -+} -+ -+int g_ak39_irq_to_gpio(unsigned int irq) -+{ -+ return (AK_GPIO_0 + (irq - IRQ_GPIO_0)); -+} -+ -+ -+#if 0 -+static const char *ak39_gpio_list[AK_GPIO_MAX]; -+ -+int ak_gpio_request(unsigned long gpio, const char *label) -+{ -+ if (gpio > GPIO_UPLIMIT) -+ return -EINVAL; -+ -+ if (ak39_gpio_list[gpio]) -+ return -EBUSY; -+ -+ if (label) -+ ak39_gpio_list[gpio] = label; -+ else -+ ak39_gpio_list[gpio] = "busy"; -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_request); -+ -+void ak_gpio_free(unsigned long gpio) -+{ -+ BUG_ON(!ak39_gpio_list[gpio]); -+ -+ ak39_gpio_list[gpio] = NULL; -+} -+EXPORT_SYMBOL(ak_gpio_free); -+ -+#else -+ -+int ak_gpio_request(unsigned long gpio, const char *label) -+{ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_request); -+ -+void ak_gpio_free(unsigned long gpio) -+{ -+} -+EXPORT_SYMBOL(ak_gpio_free); -+ -+#endif -+ -diff --git a/arch/arm/mach-ak39/clock.c b/arch/arm/mach-ak39/clock.c -new file mode 100755 -index 00000000..6fbb4215 ---- /dev/null -+++ b/arch/arm/mach-ak39/clock.c -@@ -0,0 +1,932 @@ -+/* -+ * linux/arch/arm/mach-ak39/clock.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/module.h> -+#include <linux/err.h> -+ -+#include <mach/gpio.h> -+#include <mach/clock.h> -+#include <linux/delay.h> -+#include <plat-anyka/anyka_types.h> -+ -+ -+/* clock information */ -+ -+static LIST_HEAD(clocks); -+ -+/* We originally used an mutex here, but some contexts (see resume) -+ * are calling functions such as clk_set_parent() with IRQs disabled -+ * causing an BUG to be triggered. -+ */ -+DEFINE_SPINLOCK(clocks_lock); -+ -+/* enable and disable calls for use with the clk struct */ -+ -+static int clk_null_enable(struct clk *clk, int enable) -+{ -+ return 0; -+} -+ -+int clk_enable(struct clk *clk) -+{ -+ unsigned long flags; -+ -+ if (IS_ERR(clk) || clk == NULL) -+ return -EINVAL; -+ -+ clk_enable(clk->parent); -+ -+ spin_lock_irqsave(&clocks_lock, flags); -+ -+ if ((clk->usage++) == 0) -+ (clk->enable)(clk, 1); -+ -+ spin_unlock_irqrestore(&clocks_lock, flags); -+ return 0; -+} -+ -+void clk_disable(struct clk *clk) -+{ -+ unsigned long flags; -+ -+ if (IS_ERR(clk) || clk == NULL) -+ return; -+ -+ spin_lock_irqsave(&clocks_lock, flags); -+ -+ if ((--clk->usage) == 0) -+ (clk->enable)(clk, 0); -+ -+ spin_unlock_irqrestore(&clocks_lock, flags); -+ clk_disable(clk->parent); -+} -+ -+ -+unsigned long clk_get_rate(struct clk *clk) -+{ -+ if (IS_ERR(clk)) -+ return 0; -+ -+ if (clk->rate != 0) -+ return clk->rate; -+ -+ if (clk->ops != NULL && clk->ops->get_rate != NULL) -+ return (clk->ops->get_rate)(clk); -+ -+ if (clk->parent != NULL) -+ return clk_get_rate(clk->parent); -+ -+ return clk->rate; -+} -+ -+long clk_round_rate(struct clk *clk, unsigned long rate) -+{ -+ if (!IS_ERR(clk) && clk->ops && clk->ops->round_rate) -+ return (clk->ops->round_rate)(clk, rate); -+ -+ return rate; -+} -+ -+int clk_set_rate(struct clk *clk, unsigned long rate) -+{ -+ int ret; -+ -+ if (IS_ERR(clk)) -+ return -EINVAL; -+ -+ /* We do not default just do a clk->rate = rate as -+ * the clock may have been made this way by choice. -+ */ -+ -+ WARN_ON(clk->ops == NULL); -+ WARN_ON(clk->ops && clk->ops->set_rate == NULL); -+ -+ if (clk->ops == NULL || clk->ops->set_rate == NULL) -+ return -EINVAL; -+ -+ spin_lock(&clocks_lock); -+ ret = (clk->ops->set_rate)(clk, rate); -+ spin_unlock(&clocks_lock); -+ -+ return ret; -+} -+ -+struct clk *clk_get_parent(struct clk *clk) -+{ -+ return clk->parent; -+} -+ -+int clk_set_parent(struct clk *clk, struct clk *parent) -+{ -+ int ret = 0; -+ -+ if (IS_ERR(clk)) -+ return -EINVAL; -+ -+ spin_lock(&clocks_lock); -+ -+ if (clk->ops && clk->ops->set_parent) -+ ret = (clk->ops->set_parent)(clk, parent); -+ -+ spin_unlock(&clocks_lock); -+ -+ return ret; -+} -+ -+EXPORT_SYMBOL(clk_enable); -+EXPORT_SYMBOL(clk_disable); -+EXPORT_SYMBOL(clk_get_rate); -+EXPORT_SYMBOL(clk_round_rate); -+EXPORT_SYMBOL(clk_set_rate); -+EXPORT_SYMBOL(clk_get_parent); -+EXPORT_SYMBOL(clk_set_parent); -+/* base clocks */ -+ -+#if 0 -+static u32 __power2(u32 x) -+{ -+ u32 s = 1; -+ -+ while (x--) -+ s <<= 1; -+ -+ return s; -+} -+#endif -+ -+static int clk_default_setrate(struct clk *clk, unsigned long rate) -+{ -+ clk->rate = rate; -+ return 0; -+} -+ -+static int inline ak39xx_gate(void __iomem *reg, -+ struct clk *clk, int enable) -+{ -+ unsigned int ctrlbit = clk->ctrlbit; -+ u32 con; -+ -+ con = __raw_readl(reg); -+ -+ if (enable) -+ con &= ~ctrlbit; -+ else -+ con |= ctrlbit; -+ -+ __raw_writel(con, reg); -+ return 0; -+} -+ -+static int ak39xx_12M_enable(struct clk *clk, int enable) -+{ -+ return ak39xx_gate(CLOCK_PERI_PLL_CTRL1, clk, enable); -+} -+ -+static int ak39xx_25M_enable(struct clk *clk, int enable) -+{ -+ unsigned int ctrlbit = clk->ctrlbit; -+ u32 con; -+ -+ con = __raw_readl(CLOCK_PERI_PLL_CTRL1); -+ -+ if (enable) -+ con |= (ctrlbit|AK_CLKCON_CLK_25M_IN); -+ else -+ con &= ~(ctrlbit|AK_CLKCON_CLK_25M_IN); -+ -+ __raw_writel(con, CLOCK_PERI_PLL_CTRL1); -+ return 0; -+} -+ -+struct clk clk_xtal_12M = { -+ .name = "xtal_12M", -+ .usage = 0, -+ .rate = 12 * MHz, -+ .parent = NULL, -+ .enable = ak39xx_12M_enable, -+ .ctrlbit = AK_CLKCON_CLK_12M, -+}; -+ -+struct clk clk_xtal_25M = { -+ .name = "xtal_25M", -+ .rate = 25 * MHz, -+ .parent = NULL, -+ .enable = ak39xx_25M_enable, -+ .ctrlbit = AK_CLKCON_CLK_25M, -+}; -+ -+struct clk clk_xtal_32K = { -+ .name = "xtal_32K", -+ .id = -1, -+ .rate = 32768, -+ .parent = NULL, -+}; -+ -+ -+struct clk clk_cpu_pll = { -+ .name = "cpu_pll", -+ .usage = 0, -+ .rate = 0, -+ .parent = NULL, -+}; -+ -+struct clk clk_asic_pll = { -+ .name = "asic_pll", -+ .usage = 0, -+ .rate = 0, -+ .parent = NULL, -+}; -+ -+struct clk clk_peri_pll = { -+ .name = "peri_pll", -+ .usage = 0, -+ .rate = 0, -+ .parent = NULL, -+}; -+ -+struct clk clk_cpu = { -+ .name = "cpu_pll", -+ .usage = 0, -+ .rate = 0, -+ .parent = &clk_cpu_pll, -+}; -+ -+/* AHB clock maybe from cpu pll, also maybe vclk[0] */ -+struct clk clk_ahb = { -+ .name = "ahb_clk", -+ .usage = 0, -+ .rate = 0, -+ .parent = &clk_cpu_pll, -+}; -+ -+struct clk clk_mem = { -+ .name = "mem_clk", -+ .usage = 0, -+ .rate = 0, -+ .parent = &clk_cpu_pll, -+}; -+ -+ -+struct clk clk_vclk = { -+ .name = "vclk", -+ .usage = 0, -+ .rate = 0, -+ .parent = &clk_asic_pll, -+}; -+ -+struct clk clk_asic = { -+ .name = "asic_clk", -+ .usage = 0, -+ .rate = 0, -+ .parent = &clk_vclk, -+}; -+ -+ -+static int ak39xx_opclk_ctrl(struct clk *clk, int enable) -+{ -+ return ak39xx_gate(CLOCK_PERI_PLL_CTRL2, clk, enable); -+} -+ -+struct clk clk_opclk = { -+ .name = "clk_opclk", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_opclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_MAC, -+}; -+ -+static int ak39xx_mclk_ctrl(struct clk *clk, int enable) -+{ -+ return ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+} -+ -+static int ak39xx_video_ctrl(struct clk *clk, int enable) -+{ -+ return ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+} -+ -+static int ak39xx_camera_ctrl(struct clk *clk, int enable) -+{ -+ return ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+} -+ -+static int ak39xx_asicclk_ctrl(struct clk *clk, int enable) -+{ -+ return ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+} -+ -+static int ak39xx_clk_dac(struct clk *clk, int enable) -+{ -+ u32 con; -+ -+ ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+ -+ con = __raw_readl(CLOCK_ADC2_DAC_CTRL); -+ -+ if (enable) -+ con |= AK_CLKCON_CLK_DAC; -+ else -+ con &= ~AK_CLKCON_CLK_DAC; -+ -+ __raw_writel(con, CLOCK_ADC2_DAC_CTRL); -+ return 0; -+} -+ -+static int ak39xx_hclk_dac(struct clk *clk, int enable) -+{ -+ u32 con; -+ -+ ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+ -+ con = __raw_readl(CLOCK_ADC2_DAC_HS_CTRL); -+ -+ if (enable) -+ con |= AK_CLKCON_HCLK_DAC; -+ else -+ con &= ~AK_CLKCON_HCLK_DAC; -+ -+ __raw_writel(con, CLOCK_ADC2_DAC_HS_CTRL); -+ return 0; -+} -+ -+static int ak39xx_clk_adc1(struct clk *clk, int enable) -+{ -+ u32 con; -+ -+ ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+ -+ con = __raw_readl(CLOCK_ADC2_DAC_CTRL); -+ -+ if (enable) -+ con |= AK_CLKCON_CLK_ADC1; -+ else -+ con &= ~AK_CLKCON_CLK_ADC1; -+ -+ __raw_writel(con, CLOCK_ADC2_DAC_CTRL); -+ return 0; -+} -+ -+static int ak39xx_clk_adc2(struct clk *clk, int enable) -+{ -+ u32 con; -+ -+ ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+ -+ con = __raw_readl(CLOCK_ADC2_DAC_HS_CTRL); -+ -+ if (enable) -+ con |= AK_CLKCON_CLK_ADC2; -+ else -+ con &= ~AK_CLKCON_CLK_ADC2; -+ -+ __raw_writel(con, CLOCK_ADC2_DAC_HS_CTRL); -+ return 0; -+} -+ -+static int ak39xx_hclk_adc2(struct clk *clk, int enable) -+{ -+ u32 con; -+ -+ ak39xx_gate(CLOCK_GATE_CTRL1, clk, enable); -+ -+ con = __raw_readl(CLOCK_ADC2_DAC_HS_CTRL); -+ -+ if (enable) -+ con |= AK_CLKCON_HCLK_ADC2; -+ else -+ con &= ~AK_CLKCON_HCLK_ADC2; -+ -+ __raw_writel(con, CLOCK_ADC2_DAC_HS_CTRL); -+ return 0; -+} -+ -+static int ak39xx_sensor_ctrl(struct clk *clk, int enable) -+{ -+ unsigned int ctrlbit = clk->ctrlbit; -+ u32 con; -+ -+ con = __raw_readl(CLOCK_PERI_PLL_CTRL2); -+ -+ if (enable) -+ con |= ctrlbit; -+ else -+ con &= ~ctrlbit; -+ -+ __raw_writel(con, CLOCK_PERI_PLL_CTRL2); -+ return 0; -+} -+ -+static struct clk init_clocks[] = { -+ { -+ .name = "dram", -+ .usage = 0, -+ .parent = &clk_cpu, -+ .enable = ak39xx_mclk_ctrl, -+ .ctrlbit = AK_CLKCON_MCLK_DRAM, -+ }, { -+ .name = "video", -+ .usage = 0, -+ .parent = &clk_vclk, -+ .enable = ak39xx_video_ctrl, -+ .ctrlbit = AK_CLKCON_VCLK2_VIDEO, -+ }, { -+ .name = "camera", -+ .usage = 0, -+ .parent = &clk_vclk, -+ .enable = ak39xx_camera_ctrl, -+ .ctrlbit = AK_CLKCON_VCLK1_CAMERA, -+ }, { -+ .name = "usb-host", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_USB, -+ }, { -+ .name = "usb-slave", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_USB, -+ }, { -+ .name = "encryption", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_ENCRY, -+ }, { -+ .name = "mac", -+ .usage = 0, -+ .parent = &clk_opclk, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_MAC, -+ }, { -+ .name = "gpio", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_GPIO, -+ }, { -+ .name = "IrDA", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_IRDA, -+ }, { -+ .name = "i2c", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_I2C, -+ }, { -+ .name = "l2mem", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_L2MEM, -+ }, { -+ .name = "uart1", -+ .devname = "ak39xx-uart.1", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_UART2, -+ }, { -+ .name = "uart0", -+ .devname = "ak39xx-uart.0", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_UART1, -+ }, { -+ .name = "spi2", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_SPI2, -+ }, { -+ .name = "spi1", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_SPI1, -+ }, { -+ .name = "dac_clk", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_clk_dac, -+ .ctrlbit = AK_CLKCON_ASICCLK_DAC, -+ }, { -+ .name = "dac_hclk", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_hclk_dac, -+ .ctrlbit = AK_CLKCON_ASICCLK_DAC, -+ }, { -+ .name = "adc1_clk", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_clk_adc1, -+ .ctrlbit = AK_CLKCON_ASICCLK_ADC, -+ }, { -+ .name = "adc2_clk", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_clk_adc2, -+ .ctrlbit = AK_CLKCON_ASICCLK_ADC, -+ }, { -+ .name = "adc2_hclk", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_hclk_adc2, -+ .ctrlbit = AK_CLKCON_ASICCLK_ADC, -+ -+ }, { -+ .name = "sdio", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_SDIO, -+ }, { -+ .name = "mci", -+ .usage = 0, -+ .parent = &clk_asic, -+ .enable = ak39xx_asicclk_ctrl, -+ .ctrlbit = AK_CLKCON_ASICCLK_MCI, -+ }, { -+ .name = "sensor", -+ .usage = 0, -+ .parent = &clk_peri_pll, -+ .enable = ak39xx_sensor_ctrl, -+ .ctrlbit = AK_CLKCON_SCLK_CIS, -+ }, -+}; -+ -+ -+/** -+ * ak39xx_register_clock() - register a clock -+ * @clk: The clock to register -+ * -+ * Add the specified clock to the list of clocks known by the system. -+ */ -+int ak39xx_register_clock(struct clk *clk) -+{ -+ if (clk->enable == NULL) -+ clk->enable = clk_null_enable; -+ -+ /* fill up the clk_lookup structure and register it*/ -+ clk->lookup.dev_id = clk->devname; -+ clk->lookup.con_id = clk->name; -+ clk->lookup.clk = clk; -+ clkdev_add(&clk->lookup); -+ -+ return 0; -+} -+ -+#if 0 -+/** -+ * ak39xx_register_clocks() - register an array of clock pointers -+ * @clks: Pointer to an array of struct clk pointers -+ * @nr_clks: The number of clocks in the @clks array. -+ * -+ * Call ak39xx_register_clock() for all the clock pointers contained -+ * in the @clks list. Returns the number of failures. -+ */ -+int ak39xx_register_clocks(struct clk **clks, int nr_clks) -+{ -+ int fails = 0; -+ -+ for (; nr_clks > 0; nr_clks--, clks++) { -+ if (ak39xx_register_clock(*clks) < 0) { -+ struct clk *clk = *clks; -+ printk(KERN_ERR "%s: failed to register %p: %s\n", -+ __func__, clk, clk->name); -+ fails++; -+ } -+ } -+ -+ return fails; -+} -+#endif -+ -+/** -+ * s3c_register_clocks() - register an array of clocks -+ * @clkp: Pointer to the first clock in the array. -+ * @nr_clks: Number of clocks to register. -+ * -+ * Call s3c24xx_register_clock() on the @clkp array given, printing an -+ * error if it fails to register the clock (unlikely). -+ */ -+void __init ak39xx_register_clocks(struct clk *clkp, int nr_clks) -+{ -+ int ret; -+ -+ for (; nr_clks > 0; nr_clks--, clkp++) { -+ ret = ak39xx_register_clock(clkp); -+ if (ret < 0) { -+ printk(KERN_ERR "Failed to register clock %s (%d)\n", -+ clkp->name, ret); -+ } -+ } -+} -+ -+ -+/* initialise the clock system */ -+ -+T_cpu_mode ak_get_cpu_mode(void) -+{ -+ unsigned long regval = __raw_readl(CLOCK_CPU_PLL_CTRL); -+ -+ if ((regval & AK39_CLK_CPU3X_MODE) && (~(regval & AK39_CLK_CPU2X_MODE))) -+ return CPU_MODE_CPU3X; -+ else if ((~(regval & AK39_CLK_CPU3X_MODE)) && (regval & AK39_CLK_CPU2X_MODE)) -+ return CPU_MODE_CPU2X; -+ else if ((~(regval & AK39_CLK_CPU3X_MODE)) && (~(regval & AK39_CLK_CPU2X_MODE))) -+ return CPU_MODE_NORMAL; -+} -+EXPORT_SYMBOL(ak_get_cpu_mode); -+ -+bool ak_cpu_is_normal_mode(void) -+{ -+ return ak_get_cpu_mode() == CPU_MODE_NORMAL; -+} -+EXPORT_SYMBOL(ak_cpu_is_normal_mode); -+ -+bool ak_cpu_is_2x_mode(void) -+{ -+ return ak_get_cpu_mode() == CPU_MODE_CPU2X; -+} -+EXPORT_SYMBOL(ak_cpu_is_2x_mode); -+ -+bool ak_cpu_is_3x_mode(void) -+{ -+ return ak_get_cpu_mode() == CPU_MODE_CPU3X; -+} -+EXPORT_SYMBOL(ak_cpu_is_3x_mode); -+ -+unsigned long ak_get_cpu_pll_clk(void) -+{ -+ unsigned long pll_m, pll_n, pll_od; -+ unsigned long cpu_pll_clk; -+ unsigned long regval; -+ -+ regval = __raw_readl(CLOCK_CPU_PLL_CTRL); -+ pll_od = (regval & (0x3 << 12)) >> 12; -+ pll_n = (regval & (0xf << 8)) >> 8; -+ pll_m = regval & 0xff; -+ -+ //cpu_pll_clk = 12 * pll_m /(pll_n * __power2(pll_od)); // clk unit: MHz -+ cpu_pll_clk = 12 * pll_m /(pll_n * (1 << pll_od)); // clk unit: MHz -+ if ((pll_od >= 1) && ((pll_n >= 2) && (pll_n <= 6)) -+ && ((pll_m >= 84) && (pll_m <= 254))) -+ -+ return cpu_pll_clk * MHz; -+ -+ panic("cpu pll clk: %ld(Mhz) is unusable\n", cpu_pll_clk); -+} -+EXPORT_SYMBOL(ak_get_cpu_pll_clk); -+ -+unsigned long ak_get_asic_pll_clk(void) -+{ -+ unsigned long pll_m, pll_n, pll_od; -+ unsigned long asic_pll_clk; -+ unsigned long regval; -+ -+ regval = __raw_readl(CLOCK_ASIC_PLL_CTRL); -+ pll_od = (regval & (0x3 << 12)) >> 12; -+ pll_n = (regval & (0xf << 8)) >> 8; -+ pll_m = regval & 0xff; -+ -+ asic_pll_clk = (12 * pll_m)/(pll_n * (1 << pll_od)); // clk unit: MHz -+ -+ if ((pll_od >= 1) && ((pll_n >= 2) && (pll_n <= 6)) -+ && ((pll_m >= 84) && (pll_m <= 254))) -+ -+ return asic_pll_clk * MHz; -+ -+ panic("asic pll clk: %ld(Mhz) is unusable\n", asic_pll_clk); -+} -+EXPORT_SYMBOL(ak_get_asic_pll_clk); -+ -+ -+unsigned long ak_get_peri_pll_clk(void) -+{ -+ unsigned long pll_m, pll_n, pll_od; -+ unsigned long peri_pll_clk; -+ unsigned long regval; -+ -+ regval = __raw_readl(CLOCK_PERI_PLL_CTRL1); -+ pll_od = (regval & (0x3 << 12)) >> 12; -+ pll_n = (regval & (0xf << 8)) >> 8; -+ pll_m = regval & 0xff; -+ -+ peri_pll_clk = (12 * pll_m)/(pll_n * (1 << pll_od)); // clk unit: MHz -+ if ((pll_od >= 1) && ((pll_n >= 2) && (pll_n <= 6)) -+ && ((pll_m >= 84) && (pll_m <= 254))) -+ -+ return peri_pll_clk * MHz; -+ -+ panic("peri pll clk: %ld(Mhz) is unusable\n", peri_pll_clk); -+} -+EXPORT_SYMBOL(ak_get_peri_pll_clk); -+ -+ -+static unsigned long ak_get_cpu_hclk(void) -+{ -+ unsigned long regval; -+ unsigned long div; -+ -+ regval = __raw_readl(CLOCK_CPU_PLL_CTRL); -+ div = (regval & (0x7 << 17)) >> 17; -+ -+ if (div == 0) -+ return ak_get_cpu_pll_clk() >> 1; -+ -+ return ak_get_cpu_pll_clk() >> div; -+} -+ -+static unsigned long ak_get_cpu_dclk(void) -+{ -+ unsigned long regval; -+ unsigned long div; -+ -+ regval = __raw_readl(CLOCK_CPU_PLL_CTRL); -+ div = (regval & (0x7 << 20)) >> 20; -+ -+ if (div == 0) -+ return ak_get_cpu_pll_clk() >> 1; -+ -+ return ak_get_cpu_pll_clk() >> div; -+} -+ -+unsigned long ak_get_cpu_clk(void) -+{ -+ if (ak_cpu_is_normal_mode()) -+ return ak_get_cpu_hclk(); -+ -+ return ak_get_cpu_pll_clk(); -+} -+EXPORT_SYMBOL(ak_get_cpu_clk); -+ -+unsigned long ak_get_ahb_clk(void) -+{ -+ if (ak_cpu_is_3x_mode()) -+ return ak_get_cpu_pll_clk()/3; -+ -+ return ak_get_cpu_hclk(); -+} -+EXPORT_SYMBOL(ak_get_ahb_clk); -+ -+unsigned long ak_get_mem_clk(void) -+{ -+ if (ak_cpu_is_3x_mode()) -+ return ak_get_cpu_pll_clk()/3; -+ -+ return ak_get_cpu_dclk(); -+} -+EXPORT_SYMBOL(ak_get_mem_clk); -+ -+unsigned long ak_get_vclk(void) -+{ -+ unsigned long regval; -+ unsigned long div; -+ -+ regval = __raw_readl(CLOCK_ASIC_PLL_CTRL); -+ div = (regval & (0x7 << 17)) >> 17; -+ if (div == 0) -+ return ak_get_asic_pll_clk() >> 1; -+ -+ return ak_get_asic_pll_clk() >> div; -+} -+EXPORT_SYMBOL(ak_get_vclk); -+ -+unsigned long ak_get_asic_clk(void) -+{ -+ unsigned long regval; -+ unsigned long div; -+ -+ regval = __raw_readl(CLOCK_ASIC_PLL_CTRL); -+ div = regval & (1 << 24); -+ if (div == 0) -+ return ak_get_vclk(); -+ -+ return ak_get_vclk() >> 1; -+} -+EXPORT_SYMBOL(ak_get_asic_clk); -+ -+void aisc_freq_set(void) -+{ -+ unsigned long asicclk, asicclk_pll; -+ unsigned long div_od, div_n, div_m; -+ unsigned long uartdiv; -+ -+ asicclk = CONFIG_ASIC_FREQ_VALUE; -+ div_od = 2; -+ div_n = 2; -+ if ((div_n < 2) || (div_n > 6) -+ || (div_od < 1) || (div_od > 3)) -+ panic("Asic frequency parameter Error"); -+ -+ if (asicclk > 100*MHz) { -+ /* asic_pll = 2vclk = 2asic */ -+ asicclk_pll = (asicclk/MHz) << 1; -+ div_m = (asicclk_pll*(div_n * (1 << div_od)))/12; -+ uartdiv = asicclk/115200-1; -+ /* set asic frequency */ -+ REG32(AK_VA_SYSCTRL + 0x08) = ((1 << 23)|(1 <<17)|(div_od << 12)|(div_n << 8)|(div_m)); -+ } else { -+ /* asic_pll = 2vclk = 4asic */ -+ asicclk_pll = (asicclk/MHz) << 2; -+ div_m = (asicclk_pll*(div_n * (1 << div_od)))/12; -+ uartdiv = asicclk/115200-1; -+ /* set asic frequency */ -+ REG32(AK_VA_SYSCTRL + 0x08) = ((1 << 24)|(1 << 23)|(1 <<17)|(div_od << 12)|(div_n << 8)|(div_m)); -+ } -+ -+ /* enable asic freq change valid */ -+ REG32(AK_VA_SYSCTRL + 0x04) |= (1 << 28); -+ /* set uart baudrate */ -+ REG32(AK_VA_UART + 0x0) = ((3<<28)|(3<<21)|(uartdiv)); -+} -+EXPORT_SYMBOL(aisc_freq_set); -+ -+/***** end extern call for comm drivers compatible *****/ -+ -+/* initalise all the clocks */ -+static int __init ak39xx_init_clocks(void) -+{ -+ clk_default_setrate(&clk_cpu_pll, ak_get_cpu_pll_clk()); -+ clk_default_setrate(&clk_asic_pll, ak_get_asic_pll_clk()); -+ clk_default_setrate(&clk_peri_pll, ak_get_peri_pll_clk()); -+ -+ clk_default_setrate(&clk_cpu, ak_get_cpu_clk()); -+ clk_default_setrate(&clk_ahb, ak_get_ahb_clk()); -+ clk_default_setrate(&clk_mem, ak_get_mem_clk()); -+ clk_default_setrate(&clk_vclk, ak_get_vclk()); -+ clk_default_setrate(&clk_asic, ak_get_asic_clk()); -+ -+ printk("AK39 clocks: CPU %ldMHz, MEM %ldMHz, ASIC %ldMHz\n", -+ clk_cpu.rate/MHz, clk_mem.rate/MHz, clk_asic.rate/MHz); -+ -+ /* register clocks */ -+ if (ak39xx_register_clock(&clk_xtal_12M) < 0) -+ printk(KERN_ERR "failed to register 12M xtal\n"); -+ -+ if (ak39xx_register_clock(&clk_xtal_25M) < 0) -+ printk(KERN_ERR "failed to register 25M xtal\n"); -+ -+ if (ak39xx_register_clock(&clk_xtal_32K) < 0) -+ printk(KERN_ERR "failed to register 32K xtal\n"); -+ -+ if (ak39xx_register_clock(&clk_cpu_pll) < 0) -+ printk(KERN_ERR "failed to register cpu pll clk\n"); -+ -+ if (ak39xx_register_clock(&clk_asic_pll) < 0) -+ printk(KERN_ERR "failed to register asic pll clk\n"); -+ -+ if (ak39xx_register_clock(&clk_peri_pll) < 0) -+ printk(KERN_ERR "failed to register peri pll clk\n"); -+ -+ if (ak39xx_register_clock(&clk_cpu) < 0) -+ printk(KERN_ERR "failed to register cpu clk\n"); -+ -+ if (ak39xx_register_clock(&clk_ahb) < 0) -+ printk(KERN_ERR "failed to register AHB clk\n"); -+ -+ if (ak39xx_register_clock(&clk_mem) < 0) -+ printk(KERN_ERR "failed to register memory clk\n"); -+ -+ if (ak39xx_register_clock(&clk_vclk) < 0) -+ printk(KERN_ERR "failed to register vclk\n"); -+ -+ if (ak39xx_register_clock(&clk_asic) < 0) -+ printk(KERN_ERR "failed to register asic clk\n"); -+ -+ if (ak39xx_register_clock(&clk_opclk) < 0) -+ printk(KERN_ERR "failed to register opclk\n"); -+ -+ ak39xx_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); -+ -+#if 0 -+ printk("ak39xx_init_clocks: clk gate reg=0x%p\n", REG32(CLOCK_GATE_CTRL1)); -+ /* -+ * Enable L2buf clock by default, Disable all other clocks. -+ * uart0 clock has been open in uncompreess.h -+ */ -+ int i; -+ for (i = 0; i < ARRAY_SIZE(init_clocks); i++) { -+ if (strcmp(init_clocks[i].name, "uart0") == 0) { -+ clk_enable(&init_clocks[i]); -+ } -+ } -+#endif -+ -+ return 0; -+} -+ -+arch_initcall(ak39xx_init_clocks); -+ -diff --git a/arch/arm/mach-ak39/cpu.c b/arch/arm/mach-ak39/cpu.c -new file mode 100755 -index 00000000..57d0a109 ---- /dev/null -+++ b/arch/arm/mach-ak39/cpu.c -@@ -0,0 +1,67 @@ -+/* -+ * init cpu freq, clock -+ * -+ * report cpu id -+ */ -+#include <asm/mach/irq.h> -+#include <asm/mach/arch.h> -+#include <asm/mach/map.h> -+#include <asm/io.h> -+ -+#include <asm/sizes.h> -+#include <mach/map.h> -+#include <mach/clock.h> -+ -+#define AK_CPU_ID (AK_VA_SYSCTRL + 0x00) -+ -+#if defined(CONFIG_CPU_AK3910) -+#define AKCPU_VALUE 0x20120100 -+#define AKCPU_TYPE "AK3910" -+#elif defined(CONFIG_CPU_AK3916) -+#define AKCPU_VALUE 0x20120100 -+#define AKCPU_TYPE "AK3916" -+#elif defined(CONFIG_CPU_AK3918) -+#define AKCPU_VALUE 0x20120100 -+#define AKCPU_TYPE "AK3918" -+#else -+#error AK39xx Board NOT supported -+#endif -+ -+ -+#define IODESC_ENT(x) \ -+{ \ -+ .virtual = (unsigned long)AK_VA_##x, \ -+ .pfn = __phys_to_pfn(AK_PA_##x), \ -+ .length = AK_SZ_##x, \ -+ .type = MT_DEVICE \ -+} -+ -+static struct map_desc ak39_iodesc[] __initdata = { -+ IODESC_ENT(SYSCTRL), -+ IODESC_ENT(CAMERA), -+ IODESC_ENT(VENCODE), -+ IODESC_ENT(SUBCTRL), -+ IODESC_ENT(MAC), -+ IODESC_ENT(REGRAM), -+ IODESC_ENT(L2MEM), -+}; -+ -+void __init ak39_map_io(void) -+{ -+ unsigned long regval = 0x0; -+ -+ /* initialise the io descriptors we need for initialisation */ -+ iotable_init(ak39_iodesc, ARRAY_SIZE(ak39_iodesc)); -+ -+ regval = __raw_readl(AK_CPU_ID); -+ if (regval == AKCPU_VALUE) -+ printk("ANYKA CPU %s (ID 0x%lx)\n", AKCPU_TYPE, regval); -+ else -+ panic("Unknown ANYKA CPU ID: 0x%lx\n", regval); -+ -+ /* need to change asic freq is here, Because higher asic freq was affected usb function, -+ * I don't know essential reason of the problem -+ */ -+ aisc_freq_set(); -+} -+ -diff --git a/arch/arm/mach-ak39/cpu.h b/arch/arm/mach-ak39/cpu.h -new file mode 100644 -index 00000000..1968ab0f ---- /dev/null -+++ b/arch/arm/mach-ak39/cpu.h -@@ -0,0 +1,4 @@ -+ -+extern struct sys_timer ak39_timer; -+ -+void __init ak39_map_io(void); -diff --git a/arch/arm/mach-ak39/cpufreq.c b/arch/arm/mach-ak39/cpufreq.c -new file mode 100755 -index 00000000..95849dc5 ---- /dev/null -+++ b/arch/arm/mach-ak39/cpufreq.c -@@ -0,0 +1,773 @@ -+/* arch/arm/mach-ak39/cpufreq.c -+ * -+ * AK98 CPUfreq Support -+ * -+ * 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/kernel.h> -+#include <linux/suspend.h> -+#include <linux/errno.h> -+#include <linux/time.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/delay.h> -+#include <linux/anyka_cpufreq.h> -+#include <linux/dma-mapping.h> -+#include <linux/freezer.h> -+#include <linux/syscalls.h> -+ -+#if 0 -+#include <mach/cpufreq.h> -+#include <mach/clock.h> -+ -+#define SIZE_1K 0x00000400 /* 1K */ -+extern atomic_t suspend_flags; -+ -+static struct cpufreq_freqs freqs; -+static T_OPERATION_MODE current_mode; -+static int previous_mode_flag; -+static int cpufreq_in_ddr2 = 1; -+static unsigned int clkdiv = 1000000; -+ -+typedef enum { -+ CPU_LOW_MODE = 0, -+ CPU_NORMAL_MODE, -+ CPU_NORMAL_2XMODE, -+} T_cpufreq_mode; -+ -+#if 1 -+struct cpufreq_mode_clkdiv cpufreq_divs[] = { -+ //mode_name pll_sel clk168_div cpu_div mem_div asic_div low_clock is_3x (cpu,mem,asic[MHz]) -+ {LOW_MODE_CLOCK_0, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ {LOW_MODE_CLOCK_1, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ {LOW_MODE_CLOCK_2, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ {LOW_MODE_CLOCK_3, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ {LOW_MODE_CLOCK_4, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ {LOW_MODE_CLOCK_5, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ {LOW_MODE_CLOCK_6, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ {LOW_MODE_CLOCK_7, 0x2d, 0, 0, 2, 4, 1, 0}, /* (90,180,90) */ -+ -+ {NORMAL_MODE_CLOCK_0, 0x2d, 0, 0, 2, 4, 0, 0}, /* (180,180,90) */ -+ {NORMAL_MODE_CLOCK_1, 0x2d, 0, 0, 2, 4, 0, 0}, /* (180,180,90) */ -+ {NORMAL_MODE_CLOCK_2, 0x2d, 0, 0, 2, 4, 0, 0}, /* (180,180,90) */ -+ {NORMAL_MODE_CLOCK_3, 0x2d, 0, 0, 2, 4, 0, 0}, /* (180,180,90) */ -+ {NORMAL_MODE_CLOCK_4, 0x2d, 0, 0, 2, 4, 0, 0}, /* (180,180,90) */ -+ {NORMAL_MODE_CLOCK_5, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {NORMAL_MODE_CLOCK_6, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {NORMAL_MODE_CLOCK_7, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ -+ {VIDEO_MODE_CLOCK_0, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {VIDEO_MODE_CLOCK_1, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {VIDEO_MODE_CLOCK_2, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {VIDEO_MODE_CLOCK_3, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {VIDEO_MODE_CLOCK_4, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {VIDEO_MODE_CLOCK_5, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {VIDEO_MODE_CLOCK_6, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {VIDEO_MODE_CLOCK_7, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ {LOWBATTERY_MODE_CLOCK, 0x2d, 0, 0, 2, 4, 0, 0}, /* (180,180,90) */ -+ {USBPLUG_MODE_CLOCK, 0x2d, 0, 1, 2, 4, 0, 0}, /* (360,180,90) */ -+ -+}; -+#else -+struct cpufreq_mode_clkdiv cpufreq_divs[] = { -+ //mode_name pll_sel clk168_div cpu_div mem_div asic_div low_clock is_3x (cpu,mem,asic[MHz]) -+ {LOW_MODE_CLOCK_0, 0x14, 0, 0, 2, 4, 1, 0}, /* (65,130,65) */ -+ {LOW_MODE_CLOCK_1, 0x14, 0, 0, 2, 4, 0, 0}, /* (65,130,65) */ -+ {LOW_MODE_CLOCK_2, 0x14, 0, 1, 2, 4, 0, 0}, /* (130,130,65) */ -+ {LOW_MODE_CLOCK_3, 0x14, 0, 0, 2, 2, 0, 0}, /* (130,130,65) */ -+ {LOW_MODE_CLOCK_4, 0x28, 0, 0, 2, 4, 0, 0}, /* (170,170,85) */ -+ {LOW_MODE_CLOCK_5, 0x2D, 0, 0, 2, 4, 0, 0}, /* (180,180,90) */ -+ {LOW_MODE_CLOCK_6, 0x37, 0, 0, 2, 4, 0, 0}, /* (200,200,100) */ -+ {LOW_MODE_CLOCK_7, 0x37, 0, 1, 2, 4, 0, 0}, /* (400,200,100) */ -+ -+ {NORMAL_MODE_CLOCK_0, 0x37, 0, 0, 2, 4, 0, 0}, /* (200,200,100) */ -+ {NORMAL_MODE_CLOCK_1, 0x37, 0, 0, 2, 4, 0, 0}, /* (200,200,100) */ -+ {NORMAL_MODE_CLOCK_2, 0x37, 0, 0, 2, 4, 0, 0}, /* (200,200,100) */ -+ {NORMAL_MODE_CLOCK_3, 0x37, 0, 0, 2, 4, 0, 0}, /* (200,200,100) */ -+ {NORMAL_MODE_CLOCK_4, 0x37, 0, 0, 2, 4, 0, 0}, /* (200,200,100) */ -+ {NORMAL_MODE_CLOCK_5, 0x37, 0, 1, 2, 4, 0, 0}, /* (400,200,100) */ -+ {NORMAL_MODE_CLOCK_6, 0x37, 0, 1, 2, 4, 0, 0}, /* (400,200,100) */ -+ {NORMAL_MODE_CLOCK_7, 0x37, 0, 1, 2, 4, 0, 0}, /* (400,200,100) */ -+ -+ {VIDEO_MODE_CLOCK_0, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+ {VIDEO_MODE_CLOCK_1, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+ {VIDEO_MODE_CLOCK_2, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+ {VIDEO_MODE_CLOCK_3, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+ {VIDEO_MODE_CLOCK_4, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+ {VIDEO_MODE_CLOCK_5, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+ {VIDEO_MODE_CLOCK_6, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+ {VIDEO_MODE_CLOCK_7, 0x36, 0, 1, 0, 0, 0, 1}, /* (396,132,132) */ -+}; -+#endif -+ -+static T_OPERATION_MODE prev_suspend_mode; -+#define SUSPEND_NORMAL_MODE NORMAL_MODE_CLOCK_2 -+ -+static int get_cpufreq_mode_clkdiv(T_OPERATION_MODE mode, struct cpufreq_mode_clkdiv *clkdiv) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(cpufreq_divs); i++) { -+ if (cpufreq_divs[i].mode_name == mode) { -+ *clkdiv = cpufreq_divs[i]; -+ return 0; -+ } -+ } -+ return -1; -+} -+ -+static unsigned int calcue_power(unsigned int num) -+{ -+ unsigned int i; -+ -+ if(num < 0) -+ return -1; -+ if((num == 2)||(num == 0)) -+ return 0; -+ -+ for(i = 0; num % 2 == 0; i++){ -+ num /= 2; -+ } -+ if(num > 2) -+ return -1; -+ -+ return i; -+} -+ -+static int current_is_lowmode(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ if (freqs.old_cpufreq.low_clock == 1) -+ return 1; -+ else -+ return 0; -+} -+ -+static int new_is_lowmode(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ if ((cpufreq->low_clock == 1)) -+ return 1; -+ else -+ return 0; -+} -+ -+static int new_is_2x_mode(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ if ((cpufreq->cpu_div == 1)) -+ return 1; -+ else -+ return 0; -+} -+ -+static void config_asicclk_parameter(struct cpufreq_mode_clkdiv *cpufreq, -+ unsigned long *ratio) -+{ -+ unsigned long clk_ratio = *ratio; -+ unsigned int asicdiv; -+ -+ asicdiv = calcue_power(cpufreq->asic_div); -+ if( asicdiv < 0) -+ printk("Error, calcue asic_div."); -+ -+ clk_ratio &= ~(0x7 << 6); -+ clk_ratio |= ((asicdiv << 6) | CLOCK_ASIC_MEM_ENA); -+ -+ *ratio = clk_ratio; -+} -+ -+static void config_clock_parameter(struct cpufreq_mode_clkdiv *cpufreq, -+ unsigned long *ratio) -+{ -+ unsigned long clk_ratio = *ratio; -+ unsigned int memdiv, asicdiv; -+ -+ memdiv = calcue_power(cpufreq->mem_div); -+ if( memdiv < 0) -+ printk("Error, calcue mem_div."); -+ asicdiv = calcue_power(cpufreq->asic_div); -+ if( asicdiv < 0) -+ printk("Error, calcue asic_div."); -+ -+ clk_ratio &= ~((1 << 28)|(1 << 22)|(0xF << 17)|(1 << 15)|(0x7 << 9)|(0x7 << 6)|(0x3F << 0)); -+ -+ clk_ratio |= (cpufreq->is_3x << 28); //is 3x ? -+ clk_ratio |= (cpufreq->clk168_div << 17); //clk168 div -+ clk_ratio |= (cpufreq->cpu_div << 15); //cpu clk = mem clk or cpu clk = asic clk -+ clk_ratio |= (cpufreq->low_clock << 22); //cpu clk = asic clk -+ clk_ratio |= (memdiv << 9)|(asicdiv << 6); //mem div and asic div -+ clk_ratio |= (cpufreq->pll_sel << 0); //pll_sel -+ clk_ratio |= PLL_CHANGE_ENA; -+ -+ *ratio = clk_ratio; -+} -+ -+/* -+ * *function: enter L2 modify register parameters of clock for change sys clcok -+ * */ -+void L2_LINK(freqchange) L2FUNC_NAME(freqchange)(unsigned long param1, -+ unsigned long param2,unsigned long param3,unsigned long param4) -+{ -+ DISABLE_CACHE_MMU(); -+ -+ // check this bit and unitil both are empty -+ while(!((REG32(PHY_RAM_CFG_REG4) & (FIFO_R_EMPTY | FIFO_CMD_EMPTY)) == (FIFO_R_EMPTY | FIFO_CMD_EMPTY))) -+ ; -+ -+ // setup periodic of refresh interval and disable auto-refresh -+ REG32(PHY_RAM_CFG_REG4) = REFRESH_PERIOD_INTERVAL; -+ -+ DDR2_ENTER_POWERDOWN(); -+ // after send enter self - refresh, delay stable clock at least more than 2 tck -+ PM_DELAY(0x4); -+ -+ //disable ram clock -+ REG32(PHY_CLOCK_CTRL_REG) |= (1<<10); -+ -+ // other mode change to normal mode -+ //cpu clock from other mode to normal -+ REG32(PHY_CLOCK_DIV_REG) &= ~((1 << 28)|(1 << 22)); -+ PM_DELAY(0x100); -+ -+ //set clock div and check pll[12] -+ REG32(PHY_CLOCK_DIV_REG) = param1; -+ while (REG32(PHY_CLOCK_DIV_REG) & PLL_CHANGE_ENA); -+ PM_DELAY(0x10); -+ -+ //enable ram clock -+ REG32(PHY_CLOCK_CTRL_REG) &= ~(1<<10); -+ // new clock stable at least more than 1tck,here is ignore because follow has few instruction. -+ -+ // softreset ddr2 memory controller -+ REG32(0x0800000c) |= (0x1 << 26); -+ PM_DELAY(0x10); -+ REG32(0x0800000c) &= ~(0x1 << 26); -+ -+ // re-init ram controller -+ REG32(0x2000e05c) = 0x00000200; // bypass DCC -+ REG32(0x2000e078) = 0x43020100; // initial sstl = 00(12ma), tsel = 10(150ohm) -+ REG32(0x2000e000) = 0x00004e90; // 32 bit bus width -+ -+ // exit precharge power-down mode before delay at least 1 tck -+ PM_DELAY(10); -+ DDR2_EXIT_POWERDOWN(); -+ -+ // load mr, reset dll and delay for 200 tck, and set odt high -+ REG32(PHY_RAM_CPU_CMD) = 0x02800532; -+ // send nop, delay for 200 tck for dll reset, -+ PM_DELAY(0x10); -+ -+ // load mr, clean reset dll and remain odt low in ddr2 memory -+ REG32(PHY_RAM_CPU_CMD) = 0x1a800432; -+ -+ //enable dll and wate for dll stable in ram controller -+ REG32(0x2000e020) = 0x00000003; -+ while (!(REG32(0x2000e020) & (1 << 2))); -+ -+ // open auto-referesh -+ // default as mclk = 120mhz for calc tck=8.3ns, trefi=7.7us -+ REG32(0x2000e00c) = (0x39f<<1)|0x1; -+ -+ //calibration sart and wait for finish -+ REG32(0x2000e024) = ((param2>>0x7)<<10)|0x1; -+ while (!(REG32(0x2000e024) & (1 << 1))); -+ -+ ENABLE_CACHE_MMU(); -+} -+ -+/* -+ *function: change pll clock, include mem clock,asic clock and cpu clock. -+ */ -+static void cpufreq_change_clocks(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ unsigned long ratio; -+ void *addr; -+ unsigned long phy_addr; -+ -+ addr = kzalloc(512, GFP_KERNEL | GFP_ATOMIC); -+ if (addr == NULL) -+ return ; -+ phy_addr = virt_to_phys(addr); -+ -+ ratio = REG32(CLOCK_DIV_REG); -+ config_clock_parameter(cpufreq, &ratio); -+ -+ SPECIFIC_L2BUF_EXEC(freqchange, ratio, phy_addr,0,0); -+ -+ kfree(addr); -+} -+ -+/* -+ *function: according to needed new clocks and determine branch of cpufreq -+ * @cpufreq: structure include mode name and clock div -+ * note: the mode enter L2 cpufreq -+ */ -+static int l2_cpu_freq_change(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ int error; -+ -+ error = usermodehelper_disable(); -+ if (error) -+ goto Finish; -+ -+ // freeze process and kernel task. -+ error = cpufreq_freeze_processes(); -+ if (error) -+ goto freeze; -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ cpufreq_change_clocks(cpufreq); -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+ -+ thaw_processes(); -+ usermodehelper_enable(); -+ -+ return 0; -+ -+freeze: -+ thaw_processes(); -+Finish: -+ usermodehelper_enable(); -+ return error; -+} -+ -+static void ddr2_transfrom_clock_mode(T_cpufreq_mode state) -+{ -+ unsigned long ratio; -+ -+ ratio = REG32(CLOCK_DIV_REG); -+ ratio &= ~(1 << 22); -+ switch (state) { -+ case CPU_LOW_MODE: -+ ratio |= (1 << 22); //|(1 << 14); -+ ratio &= ~(1 << 15); -+ break; -+ case CPU_NORMAL_MODE: -+ ratio &= ~(1 << 15); -+ break; -+ case CPU_NORMAL_2XMODE: -+ ratio |= (1 << 15); -+ break; -+ default: -+ printk("CPUFREQ: need mode is error.\n"); -+ break; -+ } -+ REG32(CLOCK_DIV_REG) = ratio; -+} -+ -+/* -+ *function: according to needed new clocks and determine branch of cpufreq -+ * @cpufreq: structure include mode name and clock div -+ * note: the mode cpufreq in ddr2 -+ */ -+static int ddr2_cpu_freq_change(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ unsigned long ratio, flags; -+ unsigned long cpuid = 0; -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ local_irq_save(flags); -+ -+ // check if cpu clock from other mode to normal and cutover to normal -+ if (current_is_lowmode(cpufreq)) { -+ ddr2_transfrom_clock_mode(CPU_NORMAL_MODE); -+ //cpuid = REG32(CPU_CHIP_ID); // used as delay -+ udelay(10); -+ } -+ -+ // change asic clock -+ if (freqs.old_cpufreq.asic_clk != freqs.new_cpufreq.asic_clk) { -+ ratio = REG32(CLOCK_DIV_REG); -+ config_asicclk_parameter(cpufreq, &ratio); -+ -+ REG32(CLOCK_DIV_REG) = ratio; -+ while (REG32(CLOCK_DIV_REG) & CLOCK_ASIC_MEM_ENA); -+ } -+ -+ // change cpu clock -+ if (freqs.old_cpufreq.cpu_clk != freqs.new_cpufreq.cpu_clk) { -+ if (new_is_2x_mode(cpufreq)) -+ ddr2_transfrom_clock_mode(CPU_NORMAL_2XMODE); -+ else if (!new_is_2x_mode(cpufreq)) { -+ if (new_is_lowmode(cpufreq)) -+ ddr2_transfrom_clock_mode(CPU_LOW_MODE); -+ else if (!current_is_lowmode(cpufreq)) -+ ddr2_transfrom_clock_mode(CPU_NORMAL_MODE); -+ } -+ udelay(10); -+ } -+ -+ local_irq_restore(flags); -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+ -+ return 0; -+} -+ -+static int cpu_freq_change(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ int error; -+ static int l2_cpufreq_flag = 0; -+ -+ if (freqs.old_cpufreq.pll_sel == freqs.new_cpufreq.pll_sel) { -+ if (current_is_lowmode(cpufreq) && l2_cpufreq_flag) { -+ error = l2_cpu_freq_change(cpufreq); -+ if (error) -+ goto exit_cpufreq; -+ -+ cpufreq_in_ddr2 = 0; -+ } else { -+ error = ddr2_cpu_freq_change(cpufreq); -+ if (error < 0) -+ goto exit_cpufreq; -+ -+ cpufreq_in_ddr2 = 1; -+ l2_cpufreq_flag = 0; -+ } -+ } else { -+ error = l2_cpu_freq_change(cpufreq); -+ if (error) -+ goto exit_cpufreq; -+ -+ cpufreq_in_ddr2 = 0; -+ l2_cpufreq_flag = 1; -+ } -+ -+ return 0; -+ -+exit_cpufreq: -+ return error; -+} -+ -+/* -+ * change from low mode to normal mode for suspend (low mode --> normal mode) -+ */ -+void cpu_freq_suspend_check(void) -+{ -+ struct cpufreq_mode_clkdiv cpufreq; -+ unsigned long ratio; -+ -+ // change to normal mode -+ if (freqs.old_cpufreq.low_clock == 1) { -+ if (cpufreq_in_ddr2) { -+ ddr2_transfrom_clock_mode(CPU_NORMAL_MODE); -+ udelay(10); -+ } else { -+ // save low mode before suspend change normal -+ prev_suspend_mode = current_mode; -+ -+ if(!get_cpufreq_mode_clkdiv(SUSPEND_NORMAL_MODE, &cpufreq)){ -+ cpufreq_change_clocks(&cpufreq); -+ } -+ } -+ } -+} -+EXPORT_SYMBOL(cpu_freq_suspend_check); -+ -+/* -+ * restore low mode after resume (normal mode --> low mode) -+ */ -+void cpu_freq_resume_check(void) -+{ -+ struct cpufreq_mode_clkdiv cpufreq; -+ unsigned long ratio; -+ -+ // chang to low mode -+ if (freqs.old_cpufreq.low_clock == 1) { -+ if (cpufreq_in_ddr2) { -+ ddr2_transfrom_clock_mode(CPU_LOW_MODE); -+ udelay(10); -+ } else { -+ if(!get_cpufreq_mode_clkdiv(prev_suspend_mode, &cpufreq)){ -+ cpufreq_change_clocks(&cpufreq); -+ } -+ } -+ } -+} -+EXPORT_SYMBOL(cpu_freq_resume_check); -+ -+static void info_clock_value(void) -+{ -+ printk("Cpufreq: system clocks(unit:MHz)[cpu,mem,asic] from (%d,%d,%d) to (%d,%d,%d)\n", -+ freqs.old_cpufreq.cpu_clk/clkdiv, freqs.old_cpufreq.mem_clk/clkdiv, -+ freqs.old_cpufreq.asic_clk/clkdiv, ak98_get_cpu_clk()/clkdiv, -+ ak98_get_mem_clk()/clkdiv, ak98_get_asic_clk()/clkdiv); -+} -+ -+static int clock_need_changing(void) -+{ -+ if((freqs.new_cpufreq.cpu_clk == freqs.old_cpufreq.cpu_clk)&& -+ (freqs.new_cpufreq.mem_clk == freqs.old_cpufreq.mem_clk)&& -+ (freqs.new_cpufreq.asic_clk == freqs.old_cpufreq.asic_clk)) -+ return 0; -+ else -+ return 1; -+} -+ -+static unsigned int get_asic_clk(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ unsigned int asicclk; -+ -+ if(cpufreq->is_3x) -+ asicclk = ((PLL_CLK_MIN+(cpufreq->pll_sel*4))/(cpufreq->clk168_div+1))/3; -+ else -+ asicclk = ((PLL_CLK_MIN+(cpufreq->pll_sel*4))/(cpufreq->clk168_div+1))/cpufreq->asic_div; -+ -+ return asicclk; -+} -+ -+static unsigned int get_mem_clk(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ unsigned int memclk; -+ -+ if(cpufreq->is_3x) -+ memclk = ((PLL_CLK_MIN+(cpufreq->pll_sel*4))/(cpufreq->clk168_div+1))/3; -+ else -+ memclk = ((PLL_CLK_MIN+(cpufreq->pll_sel*4))/(cpufreq->clk168_div+1))/cpufreq->mem_div; -+ -+ return memclk; -+} -+ -+static unsigned int get_cpu_clk(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ unsigned int cpuclk; -+ -+ if(cpufreq->is_3x) { -+ cpuclk = (PLL_CLK_MIN+(cpufreq->pll_sel*4))/(cpufreq->clk168_div+1); -+ } else { -+ if(cpufreq->cpu_div) { -+ cpuclk = (PLL_CLK_MIN+(cpufreq->pll_sel*4))/(cpufreq->clk168_div+1); -+ } else { -+ if(cpufreq->low_clock) -+ cpuclk = get_asic_clk(cpufreq); -+ else -+ cpuclk = get_mem_clk(cpufreq); -+ } -+ } -+ -+ return cpuclk; -+} -+ -+static void update_current_clock(void) -+{ -+ freqs.old_cpufreq.cpu_clk = freqs.new_cpufreq.cpu_clk; -+ freqs.old_cpufreq.mem_clk = freqs.new_cpufreq.mem_clk; -+ freqs.old_cpufreq.asic_clk = freqs.new_cpufreq.asic_clk; -+ freqs.old = freqs.new; -+ freqs.old_cpufreq.pll_sel = freqs.new_cpufreq.pll_sel; -+ freqs.old_cpufreq.low_clock = freqs.new_cpufreq.low_clock; -+} -+ -+static void get_newmode_clock(struct cpufreq_mode_clkdiv *cpufreq) -+{ -+ freqs.new_cpufreq.cpu_clk = get_cpu_clk(cpufreq)*clkdiv; -+ freqs.new_cpufreq.mem_clk = get_mem_clk(cpufreq)*clkdiv; -+ freqs.new_cpufreq.asic_clk = get_asic_clk(cpufreq)*clkdiv; -+ freqs.new = freqs.new_cpufreq.cpu_clk; -+ freqs.new_cpufreq.pll_sel = cpufreq->pll_sel; -+ freqs.new_cpufreq.low_clock = cpufreq->low_clock; -+} -+ -+void update_pre_mode(void) -+{ -+ // assign to save old mode -+ previous_mode_flag = freqs.old_cpufreq.low_clock; -+} -+ -+unsigned int get_pll_sel(T_OPERATION_MODE state) -+{ -+ int i, len; -+ -+ len = ARRAY_SIZE(cpufreq_divs); -+ for (i = 0; i < len; i++) { -+ if (state == cpufreq_divs[i].mode_name) -+ break; -+ } -+ if (likely(i < len)) -+ return cpufreq_divs[i].pll_sel; -+ -+ return -1; -+} -+EXPORT_SYMBOL(get_pll_sel); -+ -+int current_mode_is_low_mode(void) -+{ -+ return freqs.old_cpufreq.low_clock; -+} -+EXPORT_SYMBOL(current_mode_is_low_mode); -+ -+/* -+ *function: get system boot's mode -+ */ -+T_OPERATION_MODE get_current_mode(void) -+{ -+ return current_mode; -+} -+EXPORT_SYMBOL(get_current_mode); -+ -+/* function: enter change cpufreq -+ * @state: requested mode name -+ * return: -+ * -1: if system init mode is not surpport. -+ * 0: if cpufreq change successful. -+ */ -+int request_cpufreq_enter(T_OPERATION_MODE state) -+{ -+ int i, len; -+ int error; -+ -+ // check if request suspending, prevent cpufreq when suspending -+ if (atomic_read(&suspend_flags)) -+ return 0; -+ -+ if (state == current_mode) { -+ //printk("requset new mode equal to current mode.\n"); -+ return 0; -+ } -+ -+ len = ARRAY_SIZE(cpufreq_divs); -+ for (i = 0; i < len; i++) { -+ if (state == cpufreq_divs[i].mode_name) -+ break; -+ } -+ if (likely(i < len)) { -+ get_newmode_clock(&cpufreq_divs[i]); -+ update_pre_mode(); -+ -+ if (!clock_need_changing()) { -+ //printk("Cpufreq: new mode clocks equal to old mode clocks, exit changing.\n"); -+ return 0; -+ } -+ -+ error = cpu_freq_change(&cpufreq_divs[i]); -+ if (error) { -+ printk("CPUFREQ: request new mode changed fail. working mode is current mode.\n\n"); -+ goto cpufreq_err; -+ } -+ } else { -+ printk("CPUFREQ: requset new mode is not surpport.\n"); -+ goto cpufreq_err; -+ } -+ -+ info_clock_value(); -+ update_current_clock(); -+ current_mode = state; -+ -+ return 0; -+ -+cpufreq_err: -+ return -1; -+} -+EXPORT_SYMBOL(request_cpufreq_enter); -+ -+/* -+ * function: get system boot's mode -+ */ -+static int get_init_mode(void) -+{ -+ int i; -+ unsigned int pllclk, clk168, cpuclk, memclk, asicclk; -+ unsigned int pllsel, clk168div, cpudiv, memdiv, asicdiv, lowclock; -+ -+ pllclk = ak98_get_pll_clk()/clkdiv; -+ clk168 = ak98_get_clk168m_clk()/clkdiv; -+ cpuclk = freqs.old_cpufreq.cpu_clk/clkdiv; -+ memclk = freqs.old_cpufreq.mem_clk/clkdiv; -+ asicclk = freqs.old_cpufreq.asic_clk/clkdiv; -+ pllsel = ((pllclk - PLL_CLK_MIN)/4) & 0x3f; -+ -+ if(pllclk == clk168) -+ clk168div = 0; -+ else -+ clk168div = pllclk/clk168; -+ -+ //system is 3x mode -+ if((cpuclk / memclk == 3)&&(cpuclk / asicclk == 3)&& -+ (cpuclk % memclk == 0)&&(cpuclk % asicclk == 0)) { -+ for(i = 0; i < ARRAY_SIZE(cpufreq_divs); i++) { -+ if((cpufreq_divs[i].is_3x == 1) && -+ (cpufreq_divs[i].clk168_div == clk168div) && -+ (cpufreq_divs[i].pll_sel == pllsel)){ -+ -+ current_mode = cpufreq_divs[i].mode_name; -+ freqs.old_cpufreq.low_clock = cpufreq_divs[i].low_clock; -+ return 0; -+ } -+ } -+ return -1; -+ } -+ -+ //system is normal mode -+ if(cpuclk == clk168) { -+ lowclock = 0; -+ cpudiv = 1; -+ } else if(cpuclk == memclk) { -+ lowclock = 0; -+ cpudiv = 0; -+ } else if(cpuclk == asicclk) { -+ lowclock = 1; -+ cpudiv = 0; -+ } -+ memdiv = clk168/memclk; -+ asicdiv = clk168/asicclk; -+ -+ for(i = 0; i < ARRAY_SIZE(cpufreq_divs); i++){ -+ if((cpufreq_divs[i].cpu_div == cpudiv) && -+ (cpufreq_divs[i].low_clock == lowclock)&& -+ (cpufreq_divs[i].mem_div == memdiv) && -+ (cpufreq_divs[i].asic_div == asicdiv) && -+ (cpufreq_divs[i].pll_sel == pllsel) && -+ (cpufreq_divs[i].clk168_div == clk168div)){ -+ -+ current_mode = cpufreq_divs[i].mode_name; -+ freqs.old_cpufreq.low_clock = cpufreq_divs[i].low_clock; -+ return 0; -+ } -+ } -+ return -1; -+} -+ -+static void cpufreq_operation_init(void) -+{ -+ int i, error; -+ unsigned int tmp; -+ -+ freqs.old_cpufreq.cpu_clk = ak98_get_cpu_clk(); -+ freqs.old_cpufreq.mem_clk = ak98_get_mem_clk(); -+ freqs.old_cpufreq.asic_clk = ak98_get_asic_clk(); -+ freqs.old = freqs.old_cpufreq.cpu_clk; -+ -+ freqs.flags = 0; -+ -+ tmp = cpufreq_divs[0].pll_sel; -+ for(i = 1; i < ARRAY_SIZE(cpufreq_divs); i++){ -+ if(cpufreq_divs[i].pll_sel > tmp) -+ tmp = cpufreq_divs[i].pll_sel; -+ } -+ freqs.old_cpufreq.pll_sel = tmp; -+ -+ error = get_init_mode(); -+ if(error < 0) -+ current_mode = error; -+ -+ return; -+} -+ -+/* ak98_cpufreq_init -+ * -+ * Attach the cpu frequence scaling functions. This should be called -+ * from the board specific initialisation if the board supports -+ * it. -+*/ -+int __init ak98_cpufreq_init(void) -+{ -+ printk("AK98 cpu frequence change support, (c) 2011 ANYAK\n"); -+ cpufreq_operation_init(); -+ -+ return 0; -+} -+module_init(ak98_cpufreq_init); -+ -+#endif -+ -diff --git a/arch/arm/mach-ak39/devices.c b/arch/arm/mach-ak39/devices.c -new file mode 100755 -index 00000000..4469bf97 ---- /dev/null -+++ b/arch/arm/mach-ak39/devices.c -@@ -0,0 +1,405 @@ -+/* linux/arch/arm/mach-ak39/devices.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/dma-mapping.h> -+#include <plat-anyka/ak_camera.h> -+ -+#include <asm/irq.h> -+#include <asm/gpio.h> -+#include <mach/i2c.h> -+#include <linux/ion.h> -+#include <linux/uio_driver.h> -+#include <linux/akuio_driver.h> -+ -+struct platform_device ak39_uart0_device = { -+ .name = "ak39-uart", -+ .id = 0, -+}; -+EXPORT_SYMBOL(ak39_uart0_device); -+ -+struct platform_device ak39_uart1_device = { -+ .name = "ak39-uart", -+ .id = 1, -+}; -+EXPORT_SYMBOL(ak39_uart1_device); -+ -+struct platform_device ak39_gpio_uart_device = { -+ .name = "gpio-uart", -+ .id = 0, -+}; -+EXPORT_SYMBOL(ak39_gpio_uart_device); -+ -+ -+/* MCI platform data */ -+static struct resource ak39_mmc_resource[] = { -+ [0] = { -+ .start = 0x20100000, -+ .end = 0x20100000 + 0x43, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_MCI, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+struct platform_device ak39_mmc_device = { -+ .name = "ak_mci", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(ak39_mmc_resource), -+ .resource = ak39_mmc_resource, -+}; -+EXPORT_SYMBOL(ak39_mmc_device); -+ -+/* SDIO platform data */ -+static struct resource ak39_sdio_resource[] = { -+ [0] = { -+ .start = 0x20108000, -+ .end = 0x20108000 + 0x43, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_SDIO, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+struct platform_device ak39_sdio_device = { -+ .name = "ak_sdio", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(ak39_sdio_resource), -+ .resource = ak39_sdio_resource, -+}; -+EXPORT_SYMBOL(ak39_sdio_device); -+ -+/* I2C */ -+#if defined(CONFIG_I2C_AK39_HW) -+struct gpio_info i2c_gpios[] = { -+ { -+ .pin = AK_GPIO_27, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .value = AK_GPIO_OUT_HIGH, -+ .int_pol = -1, -+ }, -+ { -+ .pin = AK_GPIO_28, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .value = AK_GPIO_OUT_HIGH, -+ .int_pol = -1, -+ -+ }, -+}; -+ -+static struct ak39_platform_i2c ak39_default_i2c_data = { -+ .flags = 0, -+ .bus_num = 0, -+ .slave_addr = 0x10, -+ .frequency = 100*1000, -+ .sda_delay = 100, -+ .gpios = i2c_gpios, -+ .npins = ARRAY_SIZE(i2c_gpios), -+}; -+ -+static struct resource ak39_i2c_resource[] = { -+ [0] = { -+ .start = 0x20150000, -+ .end = 0x20150000+SZ_256, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_I2C, -+ .end = IRQ_I2C, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+struct platform_device ak39_i2c_device = { -+ .name = "i2c-ak39", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak39_default_i2c_data, -+ }, -+ .num_resources = ARRAY_SIZE(ak39_i2c_resource), -+ .resource = ak39_i2c_resource, -+}; -+EXPORT_SYMBOL(ak39_i2c_device); -+ -+#elif defined(CONFIG_I2C_GPIO_SOFT) -+struct i2c_gpio_platform_data ak39_i2c_data={ -+ .sda_pin = INVALID_GPIO, -+ .scl_pin = INVALID_GPIO, -+ .udelay = 10, -+ .timeout = 200 -+}; -+ -+struct platform_device ak39_i2c_device = { -+ .name = "i2c-gpio", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak39_i2c_data, -+ }, -+}; -+EXPORT_SYMBOL(ak39_i2c_device); -+#else -+struct platform_device ak39_i2c_device = { -+ .name = "i2c", -+ .id = -1, -+}; -+EXPORT_SYMBOL(ak39_i2c_device); -+#endif -+ -+ -+/* USB udc device data */ -+static struct resource usb_otg_udc_resource[] = { -+ [0] = { -+ .start = 0x20200000, -+ .end = 0x202003ff, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .name = "usb mcu irq", -+ .start = IRQ_USBOTG_MCU, -+ .flags = IORESOURCE_IRQ, -+ }, -+ [2] = { -+ .name = "usb dma irq", -+ .start = IRQ_USBOTG_DMA, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+struct platform_device ak39_usb_udc_device = { -+ .name = "ak-hsudc", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(usb_otg_udc_resource), -+ .resource = usb_otg_udc_resource, -+}; -+EXPORT_SYMBOL(ak39_usb_udc_device); -+ -+/* USB otg host data */ -+static struct resource usb_otg_hcd_resource[] = { -+ [0] = { -+ .start = 0x20200000, -+ .end = 0x202003ff, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .name = "usb mcu irq", -+ .start = IRQ_USBOTG_MCU, -+ .flags = IORESOURCE_IRQ, -+ }, -+ [2] = { -+ .name = "usb dma irq", -+ .start = IRQ_USBOTG_DMA, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+struct platform_device ak39_usb_otg_hcd_device = { -+ .name = "usb-host", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(usb_otg_hcd_resource), -+ .resource = usb_otg_hcd_resource, -+}; -+EXPORT_SYMBOL(ak39_usb_otg_hcd_device); -+ -+/* MAC */ -+static struct resource ak39_mac_resource[] = { -+ [0] = { -+ .start = 0x20300000, -+ .end = 0x20301fff, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .name = "mac irq", -+ .start = IRQ_MAC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+struct platform_device ak39_mac_device = { -+ .name = "ak_ethernet", -+ .id = 0, -+ .num_resources = ARRAY_SIZE(ak39_mac_resource), -+ .resource = ak39_mac_resource, -+}; -+EXPORT_SYMBOL(ak39_mac_device); -+ -+/* AK39 SPI device platform data */ -+static struct resource ak39_spi1_resource[] = { -+ [0] = { -+ .start = 0x20120000, -+ .end = 0x20120027, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_SPI1, -+ .end = IRQ_SPI1, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+struct platform_device ak39_spi1_device = { -+ .name = "ak-spi", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(ak39_spi1_resource), -+ .resource = ak39_spi1_resource, -+}; -+EXPORT_SYMBOL(ak39_spi1_device); -+ -+ -+/* Camera interface resource */ -+static struct resource ak39_camera_resource[] = { -+ [0] = { -+ .start = 0x20000000, -+ .end = 0x20000030, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .name = "camera if irq", -+ .start = IRQ_CAMERA, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static struct ak_camera_pdata ak39_camera_info = { -+ .mclk = 24, -+}; -+ -+/* camera interface */ -+struct platform_device ak39_camera_interface = { -+ .name = "ak_camera", -+ .id = 39, -+ .num_resources = ARRAY_SIZE(ak39_camera_resource), -+ .resource = ak39_camera_resource, -+ .dev = { -+ .platform_data = &ak39_camera_info, -+ } -+}; -+ -+EXPORT_SYMBOL(ak39_camera_interface); -+ -+static u64 snd_dma_mask = DMA_BIT_MASK(32); -+ -+struct platform_device ak39_pcm_device = { -+ .name = "snd_akpcm", -+ .id = 0, -+ .dev = { -+ .dma_mask = &snd_dma_mask, -+ .coherent_dma_mask = DMA_BIT_MASK(32), -+ }, -+}; -+EXPORT_SYMBOL(ak39_pcm_device); -+ -+ -+static struct ion_platform_data ak39_ion_pdata = { -+ .nr = 1, -+ .heaps = { -+ { -+ .type = ION_HEAP_TYPE_CARVEOUT, -+ .id = 1, -+ .name = "Reserved phys Memory", -+ .base = CONFIG_RAM_BASE, -+ .size = CONFIG_VIDEO_RESERVED_MEM_SIZE, /* the first reserved size */ -+ .align = PAGE_SIZE, -+ }, -+ } -+}; -+ -+struct platform_device ak39_ion_device = { -+ .name = "ion-ak", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak39_ion_pdata, -+ }, -+}; -+EXPORT_SYMBOL(ak39_ion_device); -+ -+struct platform_device ak39_led_pdev = { -+ .name = "ak_led", -+ .id = -1, -+}; -+EXPORT_SYMBOL(ak39_led_pdev); -+ -+struct platform_device akfha_char_device = { -+ .name = "ak-fhachar", -+ .id = -1, -+ .dev = { -+ .platform_data = NULL, -+ }, -+}; -+EXPORT_SYMBOL(akfha_char_device); -+ -+struct platform_device ak39_gpio_keys_device = { -+ .name = "akgpio-keys", -+ .id = -1, -+}; -+EXPORT_SYMBOL(ak39_gpio_keys_device); -+ -+/* battery_power supply */ -+struct platform_device ak39_battery_power = { -+ .name = "battery", -+ .id = -1, -+}; -+EXPORT_SYMBOL(ak39_battery_power); -+ -+static struct resource ak39mmx_resources[] = { -+ { -+ .name = "video-base", -+ .start = 0x20020000, -+ .end = 0x2002042f, -+ .flags = IORESOURCE_MEM, -+ }, -+}; -+ -+static struct uio_info akmmx_uioinfo = { -+ .name = "video_codec", -+ .version = "0.1.0", -+#ifdef CONFIG_UIODMA -+ .use_dma = true, -+#endif -+ .irq = UIO_IRQ_CUSTOM, -+}; -+ -+struct platform_device ak39_mmx_device = { -+ .name = "uio_vcodec", -+ .id = 0, -+ .dev = { -+ .platform_data = &akmmx_uioinfo, -+ }, -+ .num_resources = ARRAY_SIZE(ak39mmx_resources), -+ .resource = ak39mmx_resources, -+}; -+EXPORT_SYMBOL(ak39_mmx_device); -+ -+struct platform_device ak39_rtc_device = { -+ .name = "ak-rtc", -+ .id = -1, -+}; -+EXPORT_SYMBOL(ak39_rtc_device); -+ -+struct platform_device ak39_motor0_device = { -+ .name = "ak-motor", -+ .id = 0, -+}; -+EXPORT_SYMBOL(ak39_motor0_device); -+ -+struct platform_device ak39_motor1_device = { -+ .name = "ak-motor", -+ .id = 1, -+}; -+EXPORT_SYMBOL(ak39_motor1_device); -+ -+ -+ -diff --git a/arch/arm/mach-ak39/gpio.c b/arch/arm/mach-ak39/gpio.c -new file mode 100755 -index 00000000..ab11fa53 ---- /dev/null -+++ b/arch/arm/mach-ak39/gpio.c -@@ -0,0 +1,314 @@ -+/** -+* @file arch/arm/mach-ak39/gpio.c -+* @brief dispatch the call of GPIO API -+* Copyright C 2011 Anyka CO.,LTD -+* 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. -+* @author zhou wenyong -+* @date 2011-08-11 -+* @note 2010-10-21 created by caolianming -+* @note 2011-06-14 move this file of old version to the ak39-gpio.c -+* -- unify the GPIO API -+* @note 2010-08-11 add more comments and change some identifiers' name -+*/ -+#include <linux/module.h> -+#include <mach/irqs.h> -+#include <mach/gpio.h> -+ -+/* -+ Look up table in which we look up the implementation function of GPIO API by -+ gpio pin -+*/ -+static struct gpio_api_lut ak39_gpio_api_lut[] = -+{ -+ { -+ .pin_start = AK_GPIO_MIN, -+ .pin_end = AK_GPIO_MAX, -+ .setpin_as_gpio = g_ak39_setpin_as_gpio, -+ .gpio_pullup = g_ak39_gpio_pullup, -+ .gpio_pulldown = g_ak39_gpio_pulldown, -+ .gpio_dircfg = g_ak39_gpio_cfgpin, -+ .gpio_intcfg = g_ak39_gpio_inten, -+ .gpio_set_intpol= g_ak39_gpio_intpol, -+ .gpio_setpin = g_ak39_gpio_setpin, -+ .gpio_getpin = g_ak39_gpio_getpin, -+ .gpio_to_irq = g_ak39_gpio_to_irq, -+ .irq_to_gpio = g_ak39_irq_to_gpio, -+ }, -+}; -+ -+#define GPIO_API_LUT ak39_gpio_api_lut -+/* -+ Look up the table to get the implementation function of corresponding -+ GPIO API -+*/ -+#define GET_GPIO_FUNC(pfun, pin, name)\ -+ do{\ -+ int _i_name;\ -+ pfun=NULL;\ -+ for (_i_name=0; _i_name<ARRAY_SIZE(GPIO_API_LUT); _i_name++)\ -+ if (pin>= GPIO_API_LUT[_i_name].pin_start && pin <= GPIO_API_LUT[_i_name].pin_end)\ -+ { pfun = GPIO_API_LUT[_i_name].name; break;}\ -+ }while(0); -+ -+ -+ -+/** -+* @brief set pin as GPIO port -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @return int -+*/ -+int ak_setpin_as_gpio(unsigned int pin) -+{ -+ int (*pfunc)(unsigned int); -+ GET_GPIO_FUNC(pfunc, pin, setpin_as_gpio); -+ if (pfunc) -+ return pfunc(pin); -+ return 0; -+} -+EXPORT_SYMBOL(ak_setpin_as_gpio); -+ -+ -+/** -+* @brief configure GPIO PULLUP function -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] enable -+* @return int -+*/ -+int ak_gpio_pullup(unsigned int pin, unsigned char enable) -+{ -+ int (*pfunc)(unsigned int, unsigned char); -+ GET_GPIO_FUNC(pfunc, pin, gpio_pullup); -+ if (pfunc) -+ return pfunc(pin, enable); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_pullup); -+ -+/** -+* @brief configure GPIO PULLDOWN function -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] enable -+* @return int -+*/ -+int ak_gpio_pulldown(unsigned int pin, unsigned char enable) -+{ -+ int (*pfunc)(unsigned int, unsigned char); -+ GET_GPIO_FUNC(pfunc, pin, gpio_pulldown); -+ if (pfunc) -+ return pfunc(pin, enable); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_pulldown); -+ -+ -+/** -+* @brief configure GPIO direction -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] direction -+* @return int -+*/ -+int ak_gpio_dircfg(unsigned int pin, unsigned int direction) -+{ -+ int (*pfunc)(unsigned int, unsigned int); -+ GET_GPIO_FUNC(pfunc, pin, gpio_dircfg); -+ if (pfunc) -+ return pfunc(pin, direction); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_dircfg); -+/** -+* @brief old version of ak_gpio_dircfg -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] to -+* @return int -+*/ -+int ak_gpio_cfgpin(unsigned int pin, unsigned int to) -+{ -+ return ak_gpio_dircfg(pin, to); -+} -+EXPORT_SYMBOL(ak_gpio_cfgpin); -+ -+ -+/** -+* @brief enable/disable GPIO interrupt -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] enable -+* @return int -+*/ -+int ak_gpio_intcfg(unsigned int pin, unsigned int enable) -+{ -+ int (*pfunc)(unsigned int, unsigned int); -+ GET_GPIO_FUNC(pfunc, pin, gpio_intcfg); -+ if (pfunc) -+ return pfunc(pin, enable); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_intcfg); -+/** -+* @brief old version of ak_gpio_intcfg -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] enable -+* @return int -+*/ -+int ak_gpio_inten(unsigned int pin, unsigned int enable) -+{ -+ return ak_gpio_intcfg(pin, enable); -+} -+EXPORT_SYMBOL(ak_gpio_inten); -+ -+ -+/** -+* @brief configure GPIO interrupt polarity -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] level -+* @return int -+*/ -+int ak_gpio_set_intpol(unsigned int pin, unsigned int level) -+{ -+ int (*pfunc)(unsigned int, unsigned int); -+ GET_GPIO_FUNC(pfunc, pin, gpio_set_intpol); -+ if (pfunc) -+ return pfunc(pin, level); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_set_intpol); -+/** -+* @brief old version of ak_gpio_set_intpol -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] level -+* @return int -+*/ -+int ak_gpio_intpol(unsigned int pin, unsigned int level) -+{ -+ return ak_gpio_set_intpol(pin, level); -+} -+EXPORT_SYMBOL(ak_gpio_intpol); -+ -+ -+/** -+* @brief configure GPIO output state -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @param[in] to -+* @return int -+*/ -+int ak_gpio_setpin(unsigned int pin, unsigned int to) -+{ -+ int (*pfunc)(unsigned int, unsigned int); -+ GET_GPIO_FUNC(pfunc, pin, gpio_setpin); -+ if (pfunc) -+ return pfunc(pin, to); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_setpin); -+ -+/** -+* @brief read GPIO input state -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @return int -+*/ -+ int ak_gpio_getpin(unsigned int pin) -+{ -+ int (*pfunc)(unsigned int); -+ GET_GPIO_FUNC(pfunc, pin, gpio_getpin); -+ if (pfunc) -+ return pfunc(pin); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_getpin); -+ -+ -+/** -+* @brief get corresponding irq by pin -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] pin -+* @return int -+*/ -+ int ak_gpio_to_irq(unsigned int pin) -+{ -+ int (*pfunc)(unsigned int); -+ GET_GPIO_FUNC(pfunc, pin, gpio_to_irq); -+ if (pfunc) -+ return pfunc(pin); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_gpio_to_irq); -+ -+/** -+* @brief get corresponding gpio pin by irq -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[in] irq -+* @return int -+*/ -+ int ak_irq_to_gpio(unsigned int irq) -+{ -+ if ( irq >= IRQ_GPIO_0 && irq<= NR_IRQS - 1) -+ return AK_GPIO_0 + (irq-IRQ_GPIO_0); -+ else -+ panic("wrong irq number %u passed to ak_irq_to_gpio.\n", irq); -+ -+ return -1; -+} -+EXPORT_SYMBOL(ak_irq_to_gpio); -+ -+ -+/** -+* @brief configure GPIO followed properties specified in info -+* @author zhou wenyong -+* @date 2011-08-11 -+* @param[out] *info -+* @return void -+*/ -+void ak_gpio_set(const struct gpio_info *info) -+{ -+ if ( ! (info->pin >= AK_GPIO_MIN && info->pin <= AK_GPIO_MAX )) -+ return ; -+ -+ ak_setpin_as_gpio(info->pin); -+ if (info->dir == AK_GPIO_DIR_OUTPUT || info->dir == AK_GPIO_DIR_INPUT) -+ ak_gpio_dircfg(info->pin, info->dir); -+ if (info->pullup == AK_PULLUP_ENABLE || info->pullup == AK_PULLUP_DISABLE) -+ ak_gpio_pullup(info->pin, info->pullup); -+ if (info->pulldown == AK_PULLDOWN_ENABLE || info->pulldown == AK_PULLDOWN_DISABLE) -+ ak_gpio_pulldown(info->pin, info->pulldown); -+ if (info->value == AK_GPIO_OUT_HIGH || info->value == AK_GPIO_OUT_LOW) -+ ak_gpio_setpin(info->pin, info->value); -+ if (info->int_pol == AK_GPIO_INT_LOWLEVEL || info->int_pol == AK_GPIO_INT_HIGHLEVEL) -+ ak_gpio_set_intpol(info->pin, info->int_pol); -+} -+EXPORT_SYMBOL(ak_gpio_set); -+ -diff --git a/arch/arm/mach-ak39/include/mach/adc.h b/arch/arm/mach-ak39/include/mach/adc.h -new file mode 100755 -index 00000000..7549d81e ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/adc.h -@@ -0,0 +1,40 @@ -+/* -+ * ak_adc.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef __AK_ADC_H_ -+#define __AK_ADC_H_ -+ -+#include <mach/map.h> -+ -+#define RESET_CTRL_REG (AK_VA_SYSCTRL + 0x20) -+#define AD_DA_CLK1_REG (AK_VA_SYSCTRL + 0x0C) -+#define SAR_ADC_CFG_REG (AK_VA_SYSCTRL + 0x98) -+#define SAR_IF_CFG_REG (AK_VA_SYSCTRL + 0x5C) -+#define SAR_TIMING_CFG_REG (AK_VA_SYSCTRL + 0x60) -+#define SAR_THRESHOLD_REG (AK_VA_SYSCTRL + 0x64) -+#define SAR_IF_SMP_DAT_REG (AK_VA_SYSCTRL + 0x68) -+#define SAR_IF_INT_STATUS_REG (AK_VA_SYSCTRL + 0x6C) -+ -+ -+#define ADC1_MAIN_CLK (12000000) -+#define ADC1_DEFAULT_CLK (1500000) /* FIXME: bat work in 1.5MHz */ -+#define DEFAULT_SAMPLE (1000) /* FIXME: somebody need change it */ -+#define AK_AVCC (3300) /* AVCC always 3.3V ? */ -+ -+#define AK_ADC1_AD0 (0) /* FIXME: AD0=AIN0=BAT ? AD1=AIM1 ? AD2=AIN2 ? */ -+#define AK_ADC1_AD1 (1) -+#define AK_ADC1_BAT (2) -+ -+int adc1_init(void); -+unsigned long adc1_read_channel(int channel); -+ -+#define adc1_read_bat() adc1_read_channel(AK_ADC1_AD0) -+#define adc1_read_ad5() adc1_read_channel(AK_ADC1_AD1) /* is it right ? */ -+ -+#endif -diff --git a/arch/arm/mach-ak39/include/mach/ak_codec.h b/arch/arm/mach-ak39/include/mach/ak_codec.h -new file mode 100644 -index 00000000..21ba20b6 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/ak_codec.h -@@ -0,0 +1,164 @@ -+#ifndef AK39_CODEC_H -+#define AK39_CODEC_H -+ -+#include <mach/gpio.h> -+#include <linux/delay.h> -+#include <sound/asound.h> -+ -+ -+//pAddress0800 0x08000000-0x080000FF -+#define CPUPLLCHN_CLOCK_CTRL_REG 0x0004 -+ -+#define CLOCK_CTRL_REG 0x000C -+#define HIGHSPEED_CLOCK_CTRL_REG 0x0010 -+#define CLOCK_GATE_CTRL_REG 0x001c -+#define SOFT_RST_CTRL_REG 0x0020 -+#define MULTIPLE_FUN_CTRL_REG1 0x0058 -+#define FADEOUT_CTRL_REG 0x0070 -+ -+#define ADC1_CONF_REG1 0x0098 -+ -+#define ANALOG_CTRL_REG1 0x009c -+#define ANALOG_CTRL_REG2 0x00A0 -+#define ANALOG_CTRL_REG3 0x00A4 -+ -+//pAddress2011 0x2011000-0x20118008 -+#define DAC_CONFIG_REG 0x0000 -+#define I2S_CONFIG_REG 0x0004 -+#define CPU_DATA_REG 0x0008 -+ -+#define ADC2_CONFIG_REG 0x8000 -+#define ADC2_DATA_REG 0x8004 -+ -+//ADC2_CONFIG_REG(0x20118000) -+#define WORD_LENGTH_MASK (0XF << 8) -+#define I2S_EN (1 << 4) -+#define CH_POLARITY_SEL (1 << 3) -+#define HOST_RD_INT_EN (1 << 2) -+#define ADC2MODE_L2_EN (1 << 1) -+#define ADC2_CTRL_EN (1 <<0) -+ -+//CLOCK_CTRL_REG(0x08000004) -+#define ASIC_FREQ_ADJ (1 << 28) -+ -+//CLOCK_CTRL_REG(0x0800000C) -+#define DAC_DIV_VLD (1 << 29) -+#define DAC_CLK_EN (1 << 28) -+#define MASK_DAC_DIV_FRAC (0xFFF << 12) -+#define DAC_DIV_FRAC(val) (((val)&0xFFF) << 12) -+#define MASK_DAC_DIV_INT (0xFF << 4) -+#define DAC_DIV_INT(val) (((val)&0xFF) << 4) -+ -+//HIGHSPEED_CLOCK_CTRL_REG(0x0800 0010) -+#define ADC2_HSDIV_VLD (1 << 29) -+#define ADC2_HCLK_EN (1 << 28) -+#define MASK_ADC2_HCLK_DIV (0x3F << 20) -+#define ADC2_HCLK_DIV(val) (((val)&0x3F)<<20) -+#define DAC_HSDIV_VLD (1 << 19) -+#define DAC_HCLK_EN (1 << 18) -+#define MASK_DAC_HCLK_DIV (0xFF << 10) -+#define DAC_HCLK_DIV(val) (((val)&0xFF)<<10) -+#define ADC2_DIV_VLD (1 << 9) -+#define ADC2_CLK_EN (1 << 8) -+#define MASK_ADC2_DIV (0x3F << 0) -+#define ADC2_DIV(val) ((val)&0x3F) -+ -+ -+//SOFT_RST_CTRL_REG(0x08000020) -+#define DAC_SOFT_RST ((1 << 26)|(1 << 28)) -+#define ADC2_SOFT_RST ((1 << 27)|(1 << 29)) -+ -+ -+//MULTIPLE_FUN_CTRL_REG1(0x08000058) -+#define IN_DAAD_EN (1 << 25) //ENABLE INTERNAL DAC ADC via i2s -+ -+//FADEOUT_CTRL_REG(0x0080 0070) -+#define OSR_MASK (0x7 << 0) -+#define OSR(value) (((value)&0x7) << 0) -+#define ADC2_OSR_BIT 31 -+#define DAC_FILTER_EN (1<<3) -+ -+//ADC_CONF_REG1(0x0080 0098) -+#define SEL_VREF (1<< 23) -+ -+//ANALOG_CTRL_REG1(0x0080 009c) -+#define PD2_HP (1 << 24) -+#define VCM3_SEL (1 << 23) -+#define MASK_HP_GAIN (0x1F << 18) -+#define HP_GAIN(val) (((val)&0x1F)<<18) -+#define PRE_EN1 (1 << 17) -+#define PRE_EN2 (1 << 16) -+#define PD1_HP (1 << 15) -+#define RST_DAC (1 << 11) -+#define PD_OP (1 << 10) -+#define PD_CK (1 << 9) -+#define PD_VCM3 (1 << 3) -+#define PL_VCM2 (1 << 2) //pull down to ground. -+#define PD_VCM2 (1 << 1) // power off -+#define PD_REF (1 << 0) -+ -+//ANALOG_CTRL_REG2(0x0080 00A0) -+#define VDD_MIC_SEL (1 << 25) -+#define PD_S2D (1 << 22) -+#define ADC_LIM (1 << 21) -+#define PD_MICP (1 << 23) -+#define PD_MICN (1 << 24) -+#define PD_ADC2 (1 << 1) -+#define PL_VCM3 (1 << 0) -+ -+//ANALOG_CTRL_REG3(0x0080 00A4) -+ -+//DAC_CONFIG_REG(0x2011000) -+#define ARM_INT (1 << 3) //ARM interrupt enable -+#define MUTE (1 << 2) // repeat to sent the Last data to DAC -+#define FORMAT (1 << 4) // 1 is used memeory saving format. -+#define L2_EN (1 << 1) -+#define DAC_CTRL_EN (1 << 0) -+ -+//I2S_CONFIG_REG(0x20110004) -+#define LR_CLK (1 << 6) -+#define POLARITY_SEL (1 << 5) -+#define I2S_CONFIG_WORDLENGTH_MASK (0x1F << 0) -+ -+/////////////HP_IN ADC23_IN -+#define SOURCE_DAC (0b001) -+#define SOURCE_LINEIN (0b010) -+#define SOURCE_MIC (0b100) -+#define SIGNAL_SRC_MUTE 0 -+#define SIGNAL_SRC_MAX (SOURCE_DAC|SOURCE_LINEIN|SOURCE_MIC) -+ -+#define SOURCE_DAC_MASK (0b001) -+#define SOURCE_LINEIN_MASK (0b010) -+#define SOURCE_MIC_MASK (0b100) -+#define SOURCE_MIXED_ALL_MASK (SOURCE_DAC_MASK|SOURCE_LINEIN_MASK|SOURCE_MIC_MASK) -+ -+ -+#define HEADPHONE_GAIN_MIN 0 -+#define HEADPHONE_GAIN_MAX 5 -+#define LINEIN_GAIN_MIN 0 -+#define LINEIN_GAIN_MAX 15 -+#define MIC_GAIN_MIN 0 -+#define MIC_GAIN_MAX 7 -+ -+ -+#define PLAYMODE_AUTO_SWITCH (0) /*hp & sp switch*/ -+#define PLAYMODE_HP (1) -+#define PLAYMODE_SPEAKER (2) -+ -+/** -+ * platform data of the ak39 pcm driver -+ */ -+struct ak39_codec_platform_data -+{ -+ struct gpio_info hpdet_gpio; /* gpio for headphone detecting */ -+ struct gpio_info spk_down_gpio; /* gpio for shutdown speaker */ -+ struct gpio_info hpmute_gpio; /* gpio for headphone de-pipa */ -+ int hp_on_value; /* the gpio value when headphone is pulg */ -+ int hpdet_irq; /* the irq of heaphone detecting */ -+ int bIsHPmuteUsed; /* does this board has headphone de-pipa hardware or not */ -+ int hp_mute_enable_value; /* the gpio value when enable headphone de-pipa hardware */ -+ int bIsMetalfixed; /* the ak37 SoC is metal fixed version or not */ -+ int boutput_only; /* use only 0: hp & sp, 1: hp only, 2:sp only*/ -+}; -+ -+#endif -diff --git a/arch/arm/mach-ak39/include/mach/clock.h b/arch/arm/mach-ak39/include/mach/clock.h -new file mode 100755 -index 00000000..7ecd310c ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/clock.h -@@ -0,0 +1,154 @@ -+/* -+ * arch/arm/mach-ak39/include/mach/clock.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ -+ -+#ifndef _ANYKA_CLK_H_ -+#define _ANYKA_CLK_H_ -+ -+#include <linux/clkdev.h> -+ -+#define CLOCK_CPU_PLL_CTRL (AK_VA_SYSCTRL + 0x04) -+#define CLOCK_ASIC_PLL_CTRL (AK_VA_SYSCTRL + 0x08) -+#define CLOCK_ADC2_DAC_CTRL (AK_VA_SYSCTRL + 0x0C) -+#define CLOCK_ADC2_DAC_HS_CTRL (AK_VA_SYSCTRL + 0x10) -+#define CLOCK_PERI_PLL_CTRL1 (AK_VA_SYSCTRL + 0x14) -+#define CLOCK_PERI_PLL_CTRL2 (AK_VA_SYSCTRL + 0x18) -+#define CLOCK_GATE_CTRL1 (AK_VA_SYSCTRL + 0x1C) -+#define CLOCK_SOFT_RESET (AK_VA_SYSCTRL + 0x20) -+ -+/* clock gate control register bit */ -+#define AK_CLKCON_MCLK_DRAM (1 << 24) -+#define AK_CLKCON_VCLK2_VIDEO (1 << 20) -+#define AK_CLKCON_VCLK1_CAMERA (1 << 19) -+#define AK_CLKCON_ASICCLK_USB (1 << 15) -+#define AK_CLKCON_ASICCLK_ENCRY (1 << 14) -+#define AK_CLKCON_ASICCLK_MAC (1 << 13) -+#define AK_CLKCON_ASICCLK_GPIO (1 << 12) -+#define AK_CLKCON_ASICCLK_IRDA (1 << 11) -+#define AK_CLKCON_ASICCLK_I2C (1 << 10) -+#define AK_CLKCON_ASICCLK_L2MEM (1 << 9) -+#define AK_CLKCON_ASICCLK_UART2 (1 << 8) -+#define AK_CLKCON_ASICCLK_UART1 (1 << 7) -+#define AK_CLKCON_ASICCLK_SPI2 (1 << 6) -+#define AK_CLKCON_ASICCLK_SPI1 (1 << 5) -+#define AK_CLKCON_ASICCLK_DAC (1 << 4) -+#define AK_CLKCON_ASICCLK_ADC (1 << 3) -+#define AK_CLKCON_ASICCLK_SDIO (1 << 2) -+#define AK_CLKCON_ASICCLK_MCI (1 << 1) -+ -+/* ADC2/DAC clock control register */ -+#define AK_CLKCON_CLK_DAC (1 << 28) -+#define AK_CLKCON_CLK_ADC1 (1 << 3) -+ -+/* ADC2/DAC high speed clock control register */ -+#define AK_CLKCON_HCLK_ADC2 (1 << 28) -+#define AK_CLKCON_HCLK_DAC (1 << 18) -+#define AK_CLKCON_CLK_ADC2 (1 << 8) -+ -+ -+/* PERI PLL channel clock control register1 */ -+//1: peri pll 0: external 12MHz -+#define AK_CLKCON_CLK_PHY_SEL (1 << 19) -+//1: peri pll 0: external 25MHz -+#define AK_CLKCON_CLK_MAC_SEL (1 << 18) -+#define AK_CLKCON_CLK_12M (1 << 17) -+#define AK_CLKCON_CLK_25M (1 << 16) -+#define AK_CLKCON_CLK_25M_IN (1 << 14) -+ -+ -+/* PERI PLL channel clock control register2 */ -+/* 1: positive clk 0: negative clk */ -+#define AK_CLKCON_PCLK_CIS (1 << 20) //camera -+#define AK_CLKCON_SCLK_CIS (1 << 18) //sensor -+#define AK_CLKCON_CLK_OPCLK (1 << 8) //MAC -+ -+ -+/** -+ * struct clk_ops - standard clock operations -+ * @set_rate: set the clock rate, see clk_set_rate(). -+ * @get_rate: get the clock rate, see clk_get_rate(). -+ * @round_rate: round a given clock rate, see clk_round_rate(). -+ * @set_parent: set the clock's parent, see clk_set_parent(). -+ * -+ * Group the common clock implementations together so that we -+ * don't have to keep setting the same fields again. We leave -+ * enable in struct clk. -+ * -+ * Adding an extra layer of indirection into the process should -+ * not be a problem as it is unlikely these operations are going -+ * to need to be called quickly. -+ */ -+struct clk_ops { -+ int (*set_rate)(struct clk *c, unsigned long rate); -+ unsigned long (*get_rate)(struct clk *c); -+ unsigned long (*round_rate)(struct clk *c, unsigned long rate); -+ int (*set_parent)(struct clk *c, struct clk *parent); -+}; -+ -+struct clk { -+ struct list_head list; -+ struct module *owner; -+ struct clk *parent; -+ const char *name; -+ const char *devname; -+ int id; -+ int usage; -+ unsigned long rate; -+ unsigned long ctrlbit; -+ -+ struct clk_lookup lookup; -+ struct clk_ops *ops; -+ int (*enable)(struct clk *, int enable); -+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) -+ struct dentry *dent; /* For visible tree hierarchy */ -+#endif -+}; -+ -+ -+/* core clock support */ -+extern struct clk clk_xtal_12M; -+extern struct clk clk_xtal_25M; -+extern struct clk clk_xtal_32K; -+extern struct clk clk_pll; -+extern struct clk clk_cpu; -+extern struct clk clk_ahb; -+extern struct clk clk_mem; -+extern struct clk clk_vclk; -+extern struct clk clk_asic; -+ -+ -+/* other clocks which may be registered by board support */ -+ -+typedef enum { -+ CPU_MODE_NORMAL, -+ CPU_MODE_CPU2X, -+ CPU_MODE_CPU3X, -+} T_cpu_mode; -+ -+#define AK39_CLK_CPU3X_MODE (1 << 26) -+#define AK39_CLK_CPU2X_MODE (1 << 24) -+ -+ -+#define MHz 1000000UL -+ -+T_cpu_mode ak_get_cpu_mode(void); -+bool ak_cpu_is_3x_mode(void); -+bool ak_cpu_is_2x_mode(void); -+bool ak_cpu_is_normal_mode(void); -+ -+unsigned long ak_get_cpu_pll_clk(void); -+unsigned long ak_get_asic_pll_clk(void); -+unsigned long ak_get_peri_pll_clk(void); -+unsigned long ak_get_pll_clk(void); -+unsigned long ak_get_cpu_clk(void); -+unsigned long ak_get_ahb_clk(void); -+unsigned long ak_get_mem_clk(void); -+unsigned long ak_get_vclk(void); -+unsigned long ak_get_asic_clk(void); -+void aisc_freq_set(void); -+ -+#endif -diff --git a/arch/arm/mach-ak39/include/mach/cpufreq.h b/arch/arm/mach-ak39/include/mach/cpufreq.h -new file mode 100755 -index 00000000..e1a6ccc4 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/cpufreq.h -@@ -0,0 +1,33 @@ -+#ifndef __CPUFREQ_H__ -+#define __CPUFREQ_H__ -+ -+#if 0 -+#include <linux/cpufreq.h> -+#include <plat/l2_exebuf.h> -+ -+#define MEM_CLK_DIV 0x7 -+#define ASIC_CLK_DIV 0x7 -+ -+#define PLL_CLK_MIN 180 -+#define PLL_CLK_MAX (PLL_CLK_MIN + 4*(0x3F)) -+ -+//#define CPUFREQ_DEBUG -+ -+/* clock divider register */ -+#define PLL_CHANGE_ENA (1 << 12) -+#define CLOCK_ASIC_MEM_ENA (1 << 14) -+ -+struct cpufreq_mode_clkdiv { -+ T_OPERATION_MODE mode_name; -+ unsigned int pll_sel; -+ unsigned int clk168_div; -+ unsigned int cpu_div; -+ unsigned int mem_div; -+ unsigned int asic_div; -+ unsigned int low_clock; -+ unsigned int is_3x; -+}; -+ -+#endif -+ -+#endif /* end __CPUFREQ_H__ */ -diff --git a/arch/arm/mach-ak39/include/mach/devices.h b/arch/arm/mach-ak39/include/mach/devices.h -new file mode 100755 -index 00000000..c892c714 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/devices.h -@@ -0,0 +1,35 @@ -+#ifndef _MACH_DEVICES_H -+#define _MACH_DEVICES_H -+ -+ -+extern struct platform_device ak39_uart0_device; -+extern struct platform_device ak39_uart1_device; -+extern struct platform_device ak39_gpio_uart_device; -+ -+extern struct platform_device ak39_mmc_device; -+extern struct platform_device ak39_sdio_device; -+ -+extern struct platform_device ak39_i2c_device; -+ -+extern struct platform_device ak39_usb_udc_device; -+extern struct platform_device ak39_usb_otg_hcd_device; -+extern struct platform_device ak39_mac_device; -+ -+extern struct platform_device ak39_spi1_device; -+extern struct platform_device ak39_camera_interface; -+extern struct platform_device ak39_pcm_device; -+extern struct platform_device ak39_mmx_device; -+ -+extern struct platform_device ak39_ion_device; -+extern struct platform_device ak39_led_pdev; -+extern struct platform_device ak39_gpio_keys_device; -+extern struct platform_device ak39_battery_power; -+extern struct platform_device ak39_rtc_device; -+ -+extern struct platform_device akfha_char_device; -+ -+extern struct platform_device ak39_motor0_device; -+extern struct platform_device ak39_motor1_device; -+ -+#endif /* endif _MACH_DEVICES_H */ -+ -diff --git a/arch/arm/mach-ak39/include/mach/entry-macro.S b/arch/arm/mach-ak39/include/mach/entry-macro.S -new file mode 100755 -index 00000000..279c7aab ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/entry-macro.S -@@ -0,0 +1,144 @@ -+/* -+ * include/asm-arm/arch-ak39/entry-macro.S -+ * -+ * Low-level IRQ helper macros for AK39-based platforms -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+*/ -+ -+#include <mach/hardware.h> -+#include <asm/irq.h> -+ -+#define AK39_IRQ_INTMASK (AK_VA_SYSCTRL + 0x24) -+#define AK39_FIQ_INTMASK (AK_VA_SYSCTRL + 0x28) -+#define AK39_INT_STATUS (AK_VA_SYSCTRL + 0x4C) -+ -+ .macro get_irqnr_preamble, base, tmp -+ .endm -+ -+ .macro arch_ret_to_user, tmp1, tmp2 -+ .endm -+ -+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp -+ -+ ldr \base, =AK39_INT_STATUS -+ ldr \irqstat, [\base] @ get interrupts status -+ teq \irqstat, #0x0 -+ beq 1002f -+ -+ ldr \base, =AK39_IRQ_INTMASK @ get interrupts mask -+ ldr \base, [\base] -+ and \irqstat, \irqstat, \base -+ -+ tst \irqstat, #(1<<IRQ_MEM) -+ bicne \irqstat, \irqstat, #(1<<IRQ_MEM) -+ movne \irqnr, #IRQ_MEM -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_CAMERA) -+ bicne \irqstat, \irqstat, #(1<<IRQ_CAMERA) -+ movne \irqnr, #IRQ_CAMERA -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_VIDEO_ENCODER) -+ bicne \irqstat, \irqstat, #(1<<IRQ_VIDEO_ENCODER) -+ movne \irqnr, #IRQ_VIDEO_ENCODER -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_SYSCTRL) -+ bicne \irqstat, \irqstat, #(1<<IRQ_SYSCTRL) -+ movne \irqnr, #IRQ_SYSCTRL -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_MCI) -+ bicne \irqstat, \irqstat, #(1<<IRQ_MCI) -+ movne \irqnr, #IRQ_MCI -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_SDIO) -+ bicne \irqstat, \irqstat, #(1<<IRQ_SDIO) -+ movne \irqnr, #IRQ_SDIO -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_ADC2) -+ bicne \irqstat, \irqstat, #(1<<IRQ_ADC2) -+ movne \irqnr, #IRQ_ADC2 -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_DAC) -+ bicne \irqstat, \irqstat, #(1<<IRQ_DAC) -+ movne \irqnr, #IRQ_DAC -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_SPI1) -+ bicne \irqstat, \irqstat, #(1<<IRQ_SPI1) -+ movne \irqnr, #IRQ_SPI1 -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_SPI2) -+ bicne \irqstat, \irqstat, #(1<<IRQ_SPI2) -+ movne \irqnr, #IRQ_SPI2 -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_UART0) -+ bicne \irqstat, \irqstat, #(1<<IRQ_UART0) -+ movne \irqnr, #IRQ_UART0 -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_UART1) -+ bicne \irqstat, \irqstat, #(1<<IRQ_UART1) -+ movne \irqnr, #IRQ_UART1 -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_L2MEM) -+ bicne \irqstat, \irqstat, #(1<<IRQ_L2MEM) -+ movne \irqnr, #IRQ_L2MEM -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_I2C) -+ bicne \irqstat, \irqstat, #(1<<IRQ_I2C) -+ movne \irqnr, #IRQ_I2C -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_IRDA) -+ bicne \irqstat, \irqstat, #(1<<IRQ_IRDA) -+ movne \irqnr, #IRQ_IRDA -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_GPIO) -+ bicne \irqstat, \irqstat, #(1<<IRQ_GPIO) -+ movne \irqnr, #IRQ_GPIO -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_MAC) -+ bicne \irqstat, \irqstat, #(1<<IRQ_MAC) -+ movne \irqnr, #IRQ_MAC -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_ENCRYTION) -+ bicne \irqstat, \irqstat, #(1<<IRQ_ENCRYTION) -+ movne \irqnr, #IRQ_ENCRYTION -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_USBOTG_MCU) -+ bicne \irqstat, \irqstat, #(1<<IRQ_USBOTG_MCU) -+ movne \irqnr, #IRQ_USBOTG_MCU -+ bne 1001f -+ -+ tst \irqstat, #(1<<IRQ_USBOTG_DMA) -+ bicne \irqstat, \irqstat, #(1<<IRQ_USBOTG_DMA) -+ movne \irqnr, #IRQ_USBOTG_DMA -+ bne 1001f -+ -+ 1001: -+ @ got irqnr -+ 1002: -+ @ exit here -+ .endm -+ -+ /* currently don't need an disable_fiq macro */ -+ .macro disable_fiq -+ .endm -+ -diff --git a/arch/arm/mach-ak39/include/mach/gpio.h b/arch/arm/mach-ak39/include/mach/gpio.h -new file mode 100755 -index 00000000..788514df ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/gpio.h -@@ -0,0 +1,365 @@ -+/************************************************************************* -+* Filename: arch/arm/mach-ak39/include/mach/gpio.h -+* -+* This program is free software; you can redistribute it and/or modify -+* it under the terms of the GNU General Public License as published by -+* the Free Software Foundation; either version 2 of the License, or -+* (at your option) any later version. -+**************************************************************************/ -+ -+#ifndef __GPIO_H__ -+#define __GPIO_H__ -+ -+#include <linux/gpio.h> -+#include <asm/io.h> -+#include "map.h" -+ -+ -+#define AK_WAKEUP_ENABLE 1 -+#define AK_WAKEUP_DISABLE 0 -+#define AK_FALLING_TRIGGERED 1 -+#define AK_RISING_TRIGGERED 0 -+ -+#define AK_GPIO_DIR_OUTPUT 1 -+#define AK_GPIO_DIR_INPUT 0 -+#define AK_GPIO_INT_DISABLE 0 -+#define AK_GPIO_INT_ENABLE 1 -+#define AK_GPIO_INT_LOWLEVEL 0 -+#define AK_GPIO_INT_HIGHLEVEL 1 -+ -+#define AK_GPIO_OUT_LOW 0 -+#define AK_GPIO_OUT_HIGH 1 -+ -+#define AK_PULLUP_DISABLE 0 -+#define AK_PULLUP_ENABLE 1 -+#define AK_PULLDOWN_DISABLE 0 -+#define AK_PULLDOWN_ENABLE 1 -+ -+#define GPIO_PIN_MODE_GPIO 0 -+#define GPIO_PIN_MODE_INT 1 -+ -+#define ATTR_FIXED_1 1 -+#define ATTR_FIXED_0 0 -+#define PIN_ATTE_LINE 6 -+ -+#undef END_FLAG -+#define END_FLAG 0xff -+#define INVALID_GPIO (-1) -+ -+ -+#define AK_FALSE 0 -+#define AK_TRUE 1 -+#undef AK_NULL -+#define AK_NULL ((void *)(0)) -+ -+ -+/**************** gpio offsets ************************/ -+#define AK_GPIO_GROUP1 (32*0) -+#define AK_GPIO_GROUP2 (32*1) -+ -+#define AK_GPIO_GROUP1_NO(offset) ( AK_GPIO_GROUP1 + (offset)) -+#define AK_GPIO_GROUP2_NO(offset) ( AK_GPIO_GROUP2 + (offset)) -+ -+#define AK_GPIO_0 AK_GPIO_GROUP1_NO(0) -+#define AK_GPIO_1 AK_GPIO_GROUP1_NO(1) -+#define AK_GPIO_2 AK_GPIO_GROUP1_NO(2) -+#define AK_GPIO_3 AK_GPIO_GROUP1_NO(3) -+#define AK_GPIO_4 AK_GPIO_GROUP1_NO(4) -+#define AK_GPIO_5 AK_GPIO_GROUP1_NO(5) -+#define AK_GPIO_6 AK_GPIO_GROUP1_NO(6) -+#define AK_GPIO_7 AK_GPIO_GROUP1_NO(7) -+#define AK_GPIO_8 AK_GPIO_GROUP1_NO(8) -+#define AK_GPIO_9 AK_GPIO_GROUP1_NO(9) -+#define AK_GPIO_10 AK_GPIO_GROUP1_NO(10) -+#define AK_GPIO_11 AK_GPIO_GROUP1_NO(11) -+#define AK_GPIO_12 AK_GPIO_GROUP1_NO(12) -+#define AK_GPIO_13 AK_GPIO_GROUP1_NO(13) -+#define AK_GPIO_14 AK_GPIO_GROUP1_NO(14) -+#define AK_GPIO_15 AK_GPIO_GROUP1_NO(15) -+#define AK_GPIO_16 AK_GPIO_GROUP1_NO(16) -+#define AK_GPIO_17 AK_GPIO_GROUP1_NO(17) -+#define AK_GPIO_18 AK_GPIO_GROUP1_NO(18) -+#define AK_GPIO_19 AK_GPIO_GROUP1_NO(19) -+#define AK_GPIO_20 AK_GPIO_GROUP1_NO(20) -+#define AK_GPIO_21 AK_GPIO_GROUP1_NO(21) -+#define AK_GPIO_22 AK_GPIO_GROUP1_NO(22) -+#define AK_GPIO_23 AK_GPIO_GROUP1_NO(23) -+#define AK_GPIO_24 AK_GPIO_GROUP1_NO(24) -+#define AK_GPIO_25 AK_GPIO_GROUP1_NO(25) -+#define AK_GPIO_26 AK_GPIO_GROUP1_NO(26) -+#define AK_GPIO_27 AK_GPIO_GROUP1_NO(27) -+#define AK_GPIO_28 AK_GPIO_GROUP1_NO(28) -+#define AK_GPIO_29 AK_GPIO_GROUP1_NO(29) -+#define AK_GPIO_30 AK_GPIO_GROUP1_NO(30) -+#define AK_GPIO_31 AK_GPIO_GROUP1_NO(31) -+ -+#define AK_GPIO_32 AK_GPIO_GROUP2_NO(0) -+#define AK_GPIO_33 AK_GPIO_GROUP2_NO(1) -+#define AK_GPIO_34 AK_GPIO_GROUP2_NO(2) -+#define AK_GPIO_35 AK_GPIO_GROUP2_NO(3) -+#define AK_GPIO_36 AK_GPIO_GROUP2_NO(4) -+#define AK_GPIO_37 AK_GPIO_GROUP2_NO(5) -+#define AK_GPIO_38 AK_GPIO_GROUP2_NO(6) -+#define AK_GPIO_39 AK_GPIO_GROUP2_NO(7) -+#define AK_GPIO_40 AK_GPIO_GROUP2_NO(8) -+#define AK_GPIO_41 AK_GPIO_GROUP2_NO(9) -+#define AK_GPIO_42 AK_GPIO_GROUP2_NO(10) -+#define AK_GPIO_43 AK_GPIO_GROUP2_NO(11) -+#define AK_GPIO_44 AK_GPIO_GROUP2_NO(12) -+#define AK_GPIO_45 AK_GPIO_GROUP2_NO(13) -+#define AK_GPIO_46 AK_GPIO_GROUP2_NO(14) -+#define AK_GPIO_47 AK_GPIO_GROUP2_NO(15) -+#define AK_GPIO_48 AK_GPIO_GROUP2_NO(16) -+#define AK_GPIO_49 AK_GPIO_GROUP2_NO(17) -+#define AK_GPIO_50 AK_GPIO_GROUP2_NO(18) -+#define AK_GPIO_51 AK_GPIO_GROUP2_NO(19) -+#define AK_GPIO_52 AK_GPIO_GROUP2_NO(20) -+#define AK_GPIO_53 AK_GPIO_GROUP2_NO(21) -+#define AK_GPIO_54 AK_GPIO_GROUP2_NO(22) -+#define AK_GPIO_55 AK_GPIO_GROUP2_NO(23) -+#define AK_GPIO_56 AK_GPIO_GROUP2_NO(24) -+#define AK_GPIO_57 AK_GPIO_GROUP2_NO(25) -+#define AK_GPIO_58 AK_GPIO_GROUP2_NO(26) -+#define AK_GPIO_59 AK_GPIO_GROUP2_NO(27) -+#define AK_GPIO_60 AK_GPIO_GROUP2_NO(28) -+#define AK_GPIO_61 AK_GPIO_GROUP2_NO(29) -+#define AK_GPIO_62 AK_GPIO_GROUP2_NO(30) -+#define AK_GPIO_63 AK_GPIO_GROUP2_NO(31) -+ -+ -+#define AK_GPIO_MIN AK_GPIO_0 -+#define AK_GPIO_MAX AK_GPIO_63 -+#define GPIO_UPLIMIT AK_GPIO_MAX -+ -+/****************** access gpio register addr **********************/ -+#define AK_GPIO_DIR1 (AK_VA_GPIO + 0x00) -+#define AK_GPIO_DIR2 (AK_VA_GPIO + 0x04) -+ -+#define AK_GPIO_OUT1 (AK_VA_GPIO + 0x08) -+#define AK_GPIO_OUT2 (AK_VA_GPIO + 0x0C) -+ -+#define AK_GPIO_INPUT1 (AK_VA_GPIO + 0x10) -+#define AK_GPIO_INPUT2 (AK_VA_GPIO + 0x14) -+ -+#define AK_GPIO_INT_MASK1 (AK_VA_GPIO + 0x18) -+#define AK_GPIO_INT_MASK2 (AK_VA_GPIO + 0x1C) -+ -+#define AK_GPIO_INT_MODE1 (AK_VA_GPIO + 0x20) -+#define AK_GPIO_INT_MODE2 (AK_VA_GPIO + 0x24) -+ -+#define AK_GPIO_INTP1 (AK_VA_GPIO + 0x28) -+#define AK_GPIO_INTP2 (AK_VA_GPIO + 0x2C) -+ -+#define AK_GPIO_EDGE_STATUS1 (AK_VA_GPIO + 0x30) -+#define AK_GPIO_EDGE_STATUS2 (AK_VA_GPIO + 0x34) -+ -+#define AK_PPU_PPD1 (AK_VA_SYSCTRL + 0x80) -+#define AK_PPU_PPD2 (AK_VA_SYSCTRL + 0x84) -+#define AK_PPU_PPD3 (AK_VA_SYSCTRL + 0x88) -+ -+#define AK_SHAREPIN_CON1 (AK_VA_SYSCTRL + 0x74) -+#define AK_SHAREPIN_CON2 (AK_VA_SYSCTRL + 0x78) -+#define AK_SHAREPIN_CON3 (AK_VA_SYSCTRL + 0x7C) -+ -+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+#define AK_GPIO_DIR_BASE(pin) (((pin)>>5)*4 + AK_GPIO_DIR1) -+#define AK_GPIO_OUT_BASE(pin) (((pin)>>5)*4 + AK_GPIO_OUT1) -+ -+#define AK_GPIO_IN_BASE(pin) (((pin)>>5)*4 + AK_GPIO_INPUT1) -+#define AK_GPIO_INTEN_BASE(pin) (((pin)>>5)*4 + AK_GPIO_INT_MASK1) -+#define AK_GPIO_INTPOL_BASE(pin) (((pin)>>5)*4 + AK_GPIO_INTP1) -+#define AK_PPU_PPD_BASE(pin) (((pin)>>5)*4 + AK_PPU_PPD1) -+ -+/****************** end access gpio register addr **********************/ -+ -+#define AK_WGPIO_POLARITY (AK_VA_SYSCTRL + 0x3C) -+#define AK_WGPIO_CLEAR (AK_VA_SYSCTRL + 0x40) -+#define AK_WGPIO_ENABLE (AK_VA_SYSCTRL + 0x44) -+#define AK_WGPIO_STATUS (AK_VA_SYSCTRL + 0x48) -+ -+#define AK_PA_WGPIO_POLARITY (AK_PA_SYSCTRL + 0x3C) -+#define AK_PA_WGPIO_CLEAR (AK_PA_SYSCTRL + 0x40) -+#define AK_PA_WGPIO_ENABLE (AK_PA_SYSCTRL + 0x44) -+#define AK_PA_WGPIO_STATUS (AK_PA_SYSCTRL + 0x48) -+ -+#undef REG32 -+#define REG32(_reg) (*(volatile unsigned long *)(_reg)) -+#undef REG16 -+#define REG16(_reg) (*(volatile unsigned short *)(_reg)) -+ -+#define AK_GPIO_UART1_FLOW(x) REG32(AK_VA_SYSCTRL + 0x74) &= ~(0xa << 20) -+ -+/****************** enum defined **********************/ -+typedef enum { -+ ePIN_AS_GPIO = 0, // All pin as gpio -+ ePIN_AS_OPCLK, -+ ePIN_AS_JTAG, // share pin as JTAG -+ ePIN_AS_RTCK, // share pin as watch dog -+ ePIN_AS_I2S, // share pin as I2S -+ ePIN_AS_PWM1, // share pin as PWM1 -+ ePIN_AS_PWM2, // share pin as PWM2 -+ ePIN_AS_PWM3, // share pin as PWM3 -+ ePIN_AS_PWM4, // share pin as PWM4 -+ ePIN_AS_PWM5, // share pin as PWM5 -+ ePIN_AS_UART1, // share pin as UART1 -+ ePIN_AS_UART2, // share pin as UART2 -+ ePIN_AS_CAMERA, // share pin as CAMERA -+ ePIN_AS_MCI, // share pin as MDAT1, 4 lines -+ ePIN_AS_MCI_8LINE, // share pin as MDAT1, 8 lines -+ ePIN_AS_SDIO, // share pin as SDIO -+ ePIN_AS_SPI1, // share pin as SPI1 -+ ePIN_AS_SPI2, // share pin as SPI2 -+ ePIN_AS_MAC, // share pin as Ethernet MAC -+ ePIN_AS_I2C, // share pin as I2C -+ ePIN_AS_IRDA, // share png as IrDA -+ ePIN_AS_RAM, // share pin as RAM Controller -+ -+ ePIN_AS_DUMMY -+ } T_GPIO_SHAREPIN_CFG ; -+ -+typedef enum { -+ SHARE_CONFG1 = 0, -+ SHARE_CONFG2 -+} T_SHARE_CONFG; -+ -+typedef enum { -+ SHARE_CFG1 = 0, // share cfg1 -+ SHARE_CFG2, // share cfg2 -+ SHARE_CFG3, // share cfg2 -+ SHARE_CFG12, // share cfg1 and share cfg2 as used -+ SHARE_CFG13, // share cfg1 and share cfg3 as used -+ SHARE_CFG23, // share cfg2 and share cfg2 as used -+ SHARE_CFG123, // share cfg1, share config2 and cfg3 as used -+ EXIT_CFG -+}T_SHARE_CFG; -+ -+struct gpio_sharepin_cfg { -+ T_GPIO_SHAREPIN_CFG func_module; -+ T_SHARE_CFG share_config; -+ unsigned long reg1_bit_mask; -+ unsigned long reg1_bit_value; -+ unsigned long reg2_bit_mask; -+ unsigned long reg2_bit_value; -+ unsigned long reg3_bit_mask; -+ unsigned long reg3_bit_value; -+}; -+ -+typedef enum { -+ PULLUP = 0, -+ PULLDOWN, -+ PULLUPDOWN, -+ UNDEFINED -+ } T_PUPD_TYPE ; -+ -+typedef enum { -+ PUPD_CFG1 = 0, // share cfg1 -+ PUPD_CFG2, // share cfg2 -+ PUPD_CFG3, // share cfg2 -+}T_PUPD_CFG; -+ -+typedef enum { -+ AS_GPIO_CFG_BIT1 = 0, // share cfg1 -+ AS_GPIO_CFG_BIT2, // share cfg2 -+}T_AS_GPIO_CFG; -+ -+struct gpio_pupd_cfg { -+ int pin; -+ int index; -+ T_PUPD_CFG pupd_cfg; -+ T_PUPD_TYPE pupd_type; -+}; -+ -+struct sharepin_as_gpio { -+ unsigned char gpio_start; -+ unsigned char gpio_end; -+ int index; -+ T_AS_GPIO_CFG flag; -+}; -+ -+struct t_gpio_wakeup_cfg { -+ unsigned char gpio_start; -+ unsigned char gpio_end; -+ unsigned char start_bit; -+}; -+ -+struct gpio_info { -+ int pin; -+ char pulldown; -+ char pullup; -+ char value; -+ char dir; -+ char int_pol; -+}; -+ -+struct gpio_api_lut { -+ unsigned int pin_start; -+ unsigned int pin_end; -+ -+ int (*setpin_as_gpio) (unsigned int pin); -+ int (*gpio_pullup)(unsigned int pin, unsigned char enable); -+ int (*gpio_pulldown)(unsigned int pin, unsigned char enable); -+ -+ int (*gpio_dircfg)(unsigned int pin, unsigned int to); -+ -+ int (*gpio_intcfg)(unsigned int pin, unsigned int enable); -+ int (*gpio_set_intpol)(unsigned int pin, unsigned int level); -+ -+ int (*gpio_setpin)(unsigned int pin, unsigned int to); -+ int (*gpio_getpin)(unsigned int pin); -+ -+ int (*gpio_to_irq)(unsigned int pin); -+ int (*irq_to_gpio)(unsigned int irq); -+}; -+ -+void ak_group_config(T_GPIO_SHAREPIN_CFG mod_name); -+ -+/* set gpio's wake up polarity*/ -+void ak_gpio_wakeup_pol(unsigned int pin, unsigned char pol); -+/* enable/disable gpio wake up function*/ -+int ak_gpio_wakeup(unsigned int pin, unsigned char enable); -+ -+int ak_setpin_as_gpio (unsigned int pin); -+int ak_gpio_setpin(unsigned int pin, unsigned int to); -+int ak_gpio_getpin(unsigned int pin); -+int ak_gpio_pullup(unsigned int pin, unsigned char enable); -+int ak_gpio_pulldown(unsigned int pin, unsigned char enable); -+/* new version of ak_gpio_cfgpin */ -+int ak_gpio_dircfg(unsigned int pin, unsigned int to); -+/* new version of ak_gpio_inten*/ -+int ak_gpio_intcfg(unsigned int pin, unsigned int enable); -+/* new version of ak_gpio_intpol*/ -+int ak_gpio_set_intpol(unsigned int pin, unsigned int level); -+ -+/* to support backward compatibility*/ -+int ak_gpio_cfgpin(unsigned int pin, unsigned int to); -+int ak_gpio_inten(unsigned int pin, unsigned int enable); -+int ak_gpio_intpol(unsigned int pin, unsigned int level); -+int reg_set_mutli_bit(void __iomem *reg, unsigned int value, int bit, int index); -+ -+int ak_gpio_to_irq(unsigned int pin); -+int ak_irq_to_gpio(unsigned int irq); -+ -+extern int ak_gpio_request(unsigned long gpio, const char *label); -+extern void ak_gpio_free(unsigned long gpio); -+ -+ -+/*************** wrap gpio interface again ****************/ -+void ak_gpio_set(const struct gpio_info *info); -+ -+int g_ak39_setpin_as_gpio(unsigned int pin); -+void g_ak39_setgroup_attribute(T_GPIO_SHAREPIN_CFG mod_name); -+int g_ak39_gpio_pullup(unsigned int pin, unsigned char enable); -+int g_ak39_gpio_pulldown(unsigned int pin, unsigned char enable); -+int g_ak39_gpio_cfgpin(unsigned int pin, unsigned int to); -+int g_ak39_gpio_setpin(unsigned int pin, unsigned int to); -+int g_ak39_gpio_getpin(unsigned int pin); -+int g_ak39_gpio_inten(unsigned int pin, unsigned int enable); -+int g_ak39_gpio_intpol(unsigned int pin, unsigned int level); -+ -+int g_ak39_gpio_to_irq(unsigned int pin); -+int g_ak39_irq_to_gpio(unsigned int irq); -+ -+/*************** end wrap gpio interface again ****************/ -+ -+#endif /* __GPIO_H__ */ -+ -diff --git a/arch/arm/mach-ak39/include/mach/hardware.h b/arch/arm/mach-ak39/include/mach/hardware.h -new file mode 100644 -index 00000000..66488e52 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/hardware.h -@@ -0,0 +1,24 @@ -+/* arch/arm/mach-s3c2410/include/mach/hardware.h -+ * -+ * Copyright (c) 2003 Simtec Electronics -+ * Ben Dooks <ben@simtec.co.uk> -+ * -+ * S3C2410 - hardware -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ -+ -+#ifndef __ASM_ARCH_HARDWARE_H -+#define __ASM_ARCH_HARDWARE_H -+ -+#ifndef __ASSEMBLY__ -+#endif /* __ASSEMBLY__ */ -+ -+#include <asm/sizes.h> -+#include <mach/map.h> -+ -+/* machine specific hardware definitions should go after this */ -+ -+#endif /* __ASM_ARCH_HARDWARE_H */ -diff --git a/arch/arm/mach-ak39/include/mach/i2c.h b/arch/arm/mach-ak39/include/mach/i2c.h -new file mode 100755 -index 00000000..f89434f2 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/i2c.h -@@ -0,0 +1,57 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ -+ -+#ifndef __AK39_IIC_H -+#define __AK39_IIC_H __FILE__ -+ -+#include <asm/gpio.h> -+ -+#define I2C_CLKPIN (27) -+#define I2C_DATPIN (28) -+#define I2C_INTPIN (24) -+ -+#define AK39_I2C_NACKEN (1 << 17) -+#define AK39_I2C_NOSTOP (1 << 16) -+#define AK39_I2C_ACKEN (1 << 15) -+#define AK39_I2C_START (1 << 14) -+#define AK39_I2C_TXRXSEL (1 << 13) -+#define AK39_I2C_TRX_BYTE (9) -+#define AK39_I2C_CLR_DELAY (0x3 << 7) -+#define AK39_I2C_SDA_DELAY (0x2 << 7) -+#define AK39_I2C_TXDIV_512 (1 << 6) -+#define AK39_I2C_INTEN (1 << 5) -+ -+#define INT_PEND_FLAG (1 << 4) -+#define AK39_TX_CLK_DIV (0xf) -+ -+#define AK39_I2C_CMD_EN (1 << 18) -+#define AK39_I2C_START_BIT (1 << 17) -+ -+#define AK39_I2C_READ 1 -+#define AK39_I2C_WRITE 0 -+ -+#define AK39_I2C_CTRL REG_VA_ADDR(AK_VA_I2C, 0x00) -+#define AK39_I2C_CMD1 REG_VA_ADDR(AK_VA_I2C, 0x10) -+#define AK39_I2C_CMD2 REG_VA_ADDR(AK_VA_I2C, 0x14) -+#define AK39_I2C_CMD3 REG_VA_ADDR(AK_VA_I2C, 0x18) -+#define AK39_I2C_CMD4 REG_VA_ADDR(AK_VA_I2C, 0x1C) -+#define AK39_I2C_DATA0 REG_VA_ADDR(AK_VA_I2C, 0x20) -+#define AK39_I2C_DATA1 REG_VA_ADDR(AK_VA_I2C, 0x24) -+#define AK39_I2C_DATA2 REG_VA_ADDR(AK_VA_I2C, 0x28) -+#define AK39_I2C_DATA3 REG_VA_ADDR(AK_VA_I2C, 0x2C) -+ -+ -+struct ak39_platform_i2c { -+ int bus_num; -+ unsigned int flags; -+ unsigned int slave_addr; -+ unsigned long frequency; -+ unsigned int sda_delay; -+ struct gpio_info *gpios; -+ int npins; -+}; -+ -+#endif /* __AK39_IIC_H */ -diff --git a/arch/arm/mach-ak39/include/mach/irqs.h b/arch/arm/mach-ak39/include/mach/irqs.h -new file mode 100755 -index 00000000..84822914 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/irqs.h -@@ -0,0 +1,132 @@ -+/* linux/arch/arm/mach-ak39/include/mach/irqs.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ -+ -+#ifndef __ASM_ARCH_IRQS_H_ -+#define __ASM_ARCH_IRQS_H_ -+ -+#define AK39_IRQ(x) (x) -+ -+/* -+ * Main CPU Interrupts -+ */ -+#define IRQ_MEM AK39_IRQ(0) -+#define IRQ_CAMERA AK39_IRQ(1) -+#define IRQ_VIDEO_ENCODER AK39_IRQ(2) -+#define IRQ_SYSCTRL AK39_IRQ(3) -+#define IRQ_MCI AK39_IRQ(4) -+#define IRQ_SDIO AK39_IRQ(5) -+#define IRQ_ADC2 AK39_IRQ(6) -+#define IRQ_DAC AK39_IRQ(7) -+#define IRQ_SPI1 AK39_IRQ(8) -+#define IRQ_SPI2 AK39_IRQ(9) -+#define IRQ_UART0 AK39_IRQ(10) -+#define IRQ_UART1 AK39_IRQ(11) -+#define IRQ_L2MEM AK39_IRQ(12) -+#define IRQ_I2C AK39_IRQ(13) -+#define IRQ_IRDA AK39_IRQ(14) -+#define IRQ_GPIO AK39_IRQ(15) -+#define IRQ_MAC AK39_IRQ(16) -+#define IRQ_ENCRYTION AK39_IRQ(17) -+#define IRQ_USBOTG_MCU AK39_IRQ(18) -+#define IRQ_USBOTG_DMA AK39_IRQ(19) -+ -+/* -+ * System Control Module Sub-IRQs -+ */ -+#define IRQ_SYSCTRL_START (IRQ_USBOTG_DMA + 1) -+#define AK39_SYSCTRL_IRQ(x) (IRQ_SYSCTRL_START + (x)) -+ -+#define IRQ_SARADC AK39_SYSCTRL_IRQ(0) -+#define IRQ_TIMER5 AK39_SYSCTRL_IRQ(1) -+#define IRQ_TIMER4 AK39_SYSCTRL_IRQ(2) -+#define IRQ_TIMER3 AK39_SYSCTRL_IRQ(3) -+#define IRQ_TIMER2 AK39_SYSCTRL_IRQ(4) -+#define IRQ_TIMER1 AK39_SYSCTRL_IRQ(5) -+#define IRQ_WGPIO AK39_SYSCTRL_IRQ(6) -+#define IRQ_RTC_RDY AK39_SYSCTRL_IRQ(7) -+#define IRQ_RTC_ALARM AK39_SYSCTRL_IRQ(8) -+#define IRQ_RTC_TIMER AK39_SYSCTRL_IRQ(9) -+#define IRQ_RTC_WATCHDOG AK39_SYSCTRL_IRQ(10) -+ -+/* -+ * GPIO IRQs -+ */ -+#define IRQ_GPIO_START (IRQ_RTC_WATCHDOG + 1) -+#define AK39_GPIO_IRQ(x) (IRQ_GPIO_START + (x)) -+ -+#define IRQ_GPIO_0 AK39_GPIO_IRQ(0) -+#define IRQ_GPIO_1 AK39_GPIO_IRQ(1) -+#define IRQ_GPIO_2 AK39_GPIO_IRQ(2) -+#define IRQ_GPIO_3 AK39_GPIO_IRQ(3) -+#define IRQ_GPIO_4 AK39_GPIO_IRQ(4) -+#define IRQ_GPIO_5 AK39_GPIO_IRQ(5) -+#define IRQ_GPIO_6 AK39_GPIO_IRQ(6) -+#define IRQ_GPIO_7 AK39_GPIO_IRQ(7) -+#define IRQ_GPIO_8 AK39_GPIO_IRQ(8) -+#define IRQ_GPIO_9 AK39_GPIO_IRQ(9) -+#define IRQ_GPIO_10 AK39_GPIO_IRQ(10) -+#define IRQ_GPIO_11 AK39_GPIO_IRQ(11) -+#define IRQ_GPIO_12 AK39_GPIO_IRQ(12) -+#define IRQ_GPIO_13 AK39_GPIO_IRQ(13) -+#define IRQ_GPIO_14 AK39_GPIO_IRQ(14) -+#define IRQ_GPIO_15 AK39_GPIO_IRQ(15) -+#define IRQ_GPIO_16 AK39_GPIO_IRQ(16) -+#define IRQ_GPIO_17 AK39_GPIO_IRQ(17) -+#define IRQ_GPIO_18 AK39_GPIO_IRQ(18) -+#define IRQ_GPIO_19 AK39_GPIO_IRQ(19) -+#define IRQ_GPIO_20 AK39_GPIO_IRQ(20) -+#define IRQ_GPIO_21 AK39_GPIO_IRQ(21) -+#define IRQ_GPIO_22 AK39_GPIO_IRQ(22) -+#define IRQ_GPIO_23 AK39_GPIO_IRQ(23) -+#define IRQ_GPIO_24 AK39_GPIO_IRQ(24) -+#define IRQ_GPIO_25 AK39_GPIO_IRQ(25) -+#define IRQ_GPIO_26 AK39_GPIO_IRQ(26) -+#define IRQ_GPIO_27 AK39_GPIO_IRQ(27) -+#define IRQ_GPIO_28 AK39_GPIO_IRQ(28) -+#define IRQ_GPIO_29 AK39_GPIO_IRQ(29) -+#define IRQ_GPIO_30 AK39_GPIO_IRQ(30) -+#define IRQ_GPIO_31 AK39_GPIO_IRQ(31) -+ -+#define IRQ_GPIO_32 AK39_GPIO_IRQ(32) -+#define IRQ_GPIO_33 AK39_GPIO_IRQ(33) -+#define IRQ_GPIO_34 AK39_GPIO_IRQ(34) -+#define IRQ_GPIO_35 AK39_GPIO_IRQ(35) -+#define IRQ_GPIO_36 AK39_GPIO_IRQ(36) -+#define IRQ_GPIO_37 AK39_GPIO_IRQ(37) -+#define IRQ_GPIO_38 AK39_GPIO_IRQ(38) -+#define IRQ_GPIO_39 AK39_GPIO_IRQ(39) -+#define IRQ_GPIO_40 AK39_GPIO_IRQ(40) -+#define IRQ_GPIO_41 AK39_GPIO_IRQ(41) -+#define IRQ_GPIO_42 AK39_GPIO_IRQ(42) -+#define IRQ_GPIO_43 AK39_GPIO_IRQ(43) -+#define IRQ_GPIO_44 AK39_GPIO_IRQ(44) -+#define IRQ_GPIO_45 AK39_GPIO_IRQ(45) -+#define IRQ_GPIO_46 AK39_GPIO_IRQ(46) -+#define IRQ_GPIO_47 AK39_GPIO_IRQ(47) -+#define IRQ_GPIO_48 AK39_GPIO_IRQ(48) -+#define IRQ_GPIO_49 AK39_GPIO_IRQ(49) -+#define IRQ_GPIO_50 AK39_GPIO_IRQ(50) -+#define IRQ_GPIO_51 AK39_GPIO_IRQ(51) -+#define IRQ_GPIO_52 AK39_GPIO_IRQ(52) -+#define IRQ_GPIO_53 AK39_GPIO_IRQ(53) -+#define IRQ_GPIO_54 AK39_GPIO_IRQ(54) -+#define IRQ_GPIO_55 AK39_GPIO_IRQ(55) -+#define IRQ_GPIO_56 AK39_GPIO_IRQ(56) -+#define IRQ_GPIO_57 AK39_GPIO_IRQ(57) -+#define IRQ_GPIO_58 AK39_GPIO_IRQ(58) -+#define IRQ_GPIO_59 AK39_GPIO_IRQ(59) -+#define IRQ_GPIO_60 AK39_GPIO_IRQ(60) -+#define IRQ_GPIO_61 AK39_GPIO_IRQ(61) -+#define IRQ_GPIO_62 AK39_GPIO_IRQ(62) -+#define IRQ_GPIO_63 AK39_GPIO_IRQ(63) -+ -+ -+/* total irq number */ -+#define NR_IRQS (IRQ_GPIO_63 + 1) -+ -+#endif /* __ASM_ARCH_IRQS_H_ */ -+ -diff --git a/arch/arm/mach-ak39/include/mach/l2cache.h b/arch/arm/mach-ak39/include/mach/l2cache.h -new file mode 100644 -index 00000000..9b4084c2 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/l2cache.h -@@ -0,0 +1,17 @@ -+/* -+ * linux/arch/arm/mach-ak39/include/l2cache.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef __ASM_ARCH_L2CACHE_H -+#define __ASM_ARCH_L2CACHE_H -+ -+void l2cache_init(void); -+void l2cache_clean_finish(void); -+void l2cache_invalidate(void); -+ -+#endif /* __ASM_ARCH_L2CACHE_H */ -diff --git a/arch/arm/mach-ak39/include/mach/leds-gpio.h b/arch/arm/mach-ak39/include/mach/leds-gpio.h -new file mode 100755 -index 00000000..e2201287 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/leds-gpio.h -@@ -0,0 +1,29 @@ -+/* arch/arm/mach-ak98/include/mach/leds-gpio.h -+ * -+ * Copyright (c) Anyka -+ * -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ -+ -+#ifndef __ASM_ARCH_LEDSGPIO_H -+#define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h" -+ -+#define AK_LEDF_ACTLOW (1<<0) /* LED is on when GPIO low */ -+#define AK_LEDF_ACTHIGH (1<<1) /* LED is on when GPIO hight */ -+#define AK_LEDF_TRISTATE (1<<2) /* tristate to turn off */ -+ -+struct ak_led_data { -+ char *name; -+ char *def_trigger; -+ struct gpio_info gpio; -+}; -+ -+struct ak_led_pdata { -+ struct ak_led_data *leds; -+ int nr_led; -+}; -+ -+#endif /* __ASM_ARCH_LEDSGPIO_H */ -diff --git a/arch/arm/mach-ak39/include/mach/map.h b/arch/arm/mach-ak39/include/mach/map.h -new file mode 100755 -index 00000000..c1189cc7 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/map.h -@@ -0,0 +1,114 @@ -+/* arch/arm/arch-ak39/include/mach/map.h -+ * -+ * AK39 - Memory map definitions -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ -+ -+#ifndef __ASM_ARCH_MAP_H -+#define __ASM_ARCH_MAP_H -+ -+#ifndef __ASSEMBLY__ -+#define AK39_ADDR(x) ((void __iomem *)0xF0000000 + (x)) -+#else -+#define AK39_ADDR(x) (0xF0000000 + (x)) -+#endif -+ -+#define AK_VA_OCROM AK39_ADDR(0x00000000) -+#define AK_PA_OCROM 0x00000000 -+#define AK_SZ_OCROM SZ_32K /* 32KB */ -+ -+#define AK_VA_SYSCTRL AK39_ADDR(0x00008000) -+#define AK_PA_SYSCTRL (0x08000000) -+#define AK_SZ_SYSCTRL SZ_32K /* 32KB */ -+ -+#define AK_VA_CAMERA AK39_ADDR(0x00010000) -+#define AK_PA_CAMERA (0x20000000) -+#define AK_SZ_CAMERA SZ_64K /* 64KB */ -+ -+#define AK_VA_VENCODE AK39_ADDR(0x00020000) -+#define AK_PA_VENCODE (0x20020000) -+#define AK_SZ_VENCODE SZ_64K /* 64KB */ -+ -+/* some sub system control register */ -+#define AK_VA_SUBCTRL AK39_ADDR(0x00030000) -+#define AK_PA_SUBCTRL (0x20100000) -+#define AK_SZ_SUBCTRL SZ_2M /* 2MB */ -+ -+#define AK_VA_MAC AK39_ADDR(0x00230000) -+#define AK_PA_MAC (0x20300000) -+#define AK_SZ_MAC SZ_8K /* 8KB */ -+ -+#define AK_VA_REGRAM AK39_ADDR(0x00232000) -+#define AK_PA_REGRAM (0x21000000) -+#define AK_SZ_REGRAM SZ_8K /* 8KB */ -+ -+#define AK_VA_L2MEM AK39_ADDR(0x00234000) -+#define AK_PA_L2MEM (0x4800C000) -+#define AK_SZ_L2MEM SZ_8K /* 8KB */ -+ -+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -+#define AK_VA_MCI (AK_VA_SUBCTRL + 0x0000) -+#define AK_PA_MCI (AK_PA_SUBCTRL + 0x0000) -+ -+#define AK_VA_SDIO (AK_VA_SUBCTRL + 0x8000) -+#define AK_PA_SDIO (AK_PA_SUBCTRL + 0x8000) -+ -+#define AK_VA_DAC (AK_VA_SUBCTRL + 0x10000) -+#define AK_PA_DAC (AK_PA_SUBCTRL + 0x10000) -+ -+#define AK_VA_ADC (AK_VA_SUBCTRL + 0x18000) -+#define AK_PA_ADC (AK_PA_SUBCTRL + 0x18000) -+ -+#define AK_VA_SPI1 (AK_VA_SUBCTRL + 0x20000) -+#define AK_PA_SPI1 (AK_PA_SUBCTRL + 0x20000) -+ -+#define AK_VA_SPI2 (AK_VA_SUBCTRL + 0x28000) -+#define AK_PA_SPI2 (AK_PA_SUBCTRL + 0x28000) -+ -+#define AK_VA_UART (AK_VA_SUBCTRL + 0x30000) -+#define AK_PA_UART (AK_PA_SUBCTRL + 0x30000) -+ -+#define AK_VA_L2CTRL (AK_VA_SUBCTRL + 0x40000) -+#define AK_PA_L2CTRL (AK_PA_SUBCTRL + 0x40000) -+ -+#define AK_VA_I2C (AK_VA_SUBCTRL + 0x50000) -+#define AK_PA_I2C (AK_VA_SUBCTRL + 0x50000) -+ -+#define AK_VA_IRDA (AK_VA_SUBCTRL + 0x60000) -+#define AK_PA_IRDA (AK_PA_SUBCTRL + 0x60000) -+ -+#define AK_VA_GPIO (AK_VA_SUBCTRL + 0x70000) -+#define AK_PA_GPIO (AK_PA_SUBCTRL + 0x70000) -+ -+/* encryption register */ -+#define AK_VA_ENCRY (AK_VA_SUBCTRL + 0x80000) -+#define AK_PA_ENCRY (AK_PA_SUBCTRL + 0x80000) -+ -+/* usb register */ -+#define AK_VA_USB (AK_VA_SUBCTRL + 0x100000) -+#define AK_PA_USB (AK_PA_SUBCTRL + 0x100000) -+ -+ -+#define write_ramb(v, p) (*(volatile unsigned char *)(p) = (v)) -+#define write_ramw(v, p) (*(volatile unsigned short *)(p) = (v)) -+#define write_raml(v, p) (*(volatile unsigned long *)(p) = (v)) -+ -+#define read_ramb(p) (*(volatile unsigned char *)(p)) -+#define read_ramw(p) (*(volatile unsigned short *)(p)) -+#define read_raml(p) (*(volatile unsigned long *)(p)) -+ -+#define write_buf(v, p) (*(volatile unsigned long *)(p) = (v)) -+#define read_buf(p) (*(volatile unsigned long *)(p)) -+ -+#define REG_VA_VAL(base_addr, offset) (*(volatile unsigned long *)((base_addr) + (offset))) -+#define REG_VA_ADDR(base_addr, offset) ((base_addr) + (offset)) -+ -+#define REG_PA_VAL(base_addr, offset) (*(volatile unsigned long *)((base_addr) + (offset))) -+#define REG_PA_ADDR(base_addr, offset) ((base_addr) + (offset)) -+ -+ -+#endif /* __ASM_ARCH_MAP_H */ -+ -diff --git a/arch/arm/mach-ak39/include/mach/pm.h b/arch/arm/mach-ak39/include/mach/pm.h -new file mode 100644 -index 00000000..90b21e8e ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/pm.h -@@ -0,0 +1,24 @@ -+#ifndef __PM_H -+#define __PM_H -+ -+#include <plat/l2_exebuf.h> -+ -+ -+/* ak39_pm_init -+ * -+ * called from board at initialisation time to setup the power -+ * management -+*/ -+ -+#ifdef CONFIG_PM -+extern int __init ak39_pm_init(void); -+#else -+static inline int ak39_pm_init(void) -+{ -+ return 0; -+} -+#endif -+ -+#endif /* __PM_H */ -+ -+ -diff --git a/arch/arm/mach-ak39/include/mach/pwm_timer.h b/arch/arm/mach-ak39/include/mach/pwm_timer.h -new file mode 100644 -index 00000000..f1d4f7e6 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/pwm_timer.h -@@ -0,0 +1,129 @@ -+#ifndef __PWM_TIMER_H__ -+#define __PWM_TIMER_H__ -+ -+ -+#define timer_cnt pt_u.timer.cnt -+#define timer_irq pt_u.timer.irq -+#define timer_cb pt_u.timer.callback -+#define timer_reload pt_u.timer.auto_reload -+#define timer_priv pt_u.timer.priv_data -+ -+#define pwm_hlimit pt_u.pwm.high_limit -+#define pwm_llimit pt_u.pwm.low_limit -+#define pwm_pin pt_u.pwm.pin -+ -+/*pwm/timer object*/ -+struct ak_pwm_timer -+{ -+ int id; -+ u8 mode; -+ u8 pre_div; -+ u8 __iomem *base; -+ bool status; -+ -+ union { -+ struct { -+ u32 cnt; -+ bool auto_reload; -+ void *priv_data; -+ int irq; -+ int (*callback)(void*); -+ }timer; /*timer private element*/ -+ struct { -+ u16 high_limit; -+ u16 low_limit; -+ int pin; -+ }pwm; /*pwm private element*/ -+ }pt_u; -+}; -+ -+ -+struct ak_platform_pwm_bl_data { -+ int pwm_id; -+ unsigned int max_brightness; -+ unsigned int dft_brightness; -+ unsigned int high_limit; -+ unsigned int low_limit; -+ unsigned int pwm_clk; -+ int (*init)(struct ak_pwm_timer *dev); -+ int (*notify)(int brightness); -+ void (*exit)(struct ak_pwm_timer *dev); -+}; -+ -+ -+ -+#define AK_PWM1_CTRL (AK_VA_SYSCTRL+0xB4) -+#define AK_PWM2_CTRL (AK_VA_SYSCTRL+0xBC) -+#define AK_PWM3_CTRL (AK_VA_SYSCTRL+0xC4) -+#define AK_PWM4_CTRL (AK_VA_SYSCTRL+0xCC) -+#define AK_PWM5_CTRL (AK_VA_SYSCTRL+0xD4) -+ -+ -+#define AK_PWM_TIMER_CTRL1 (0x00) -+#define AK_PWM_TIMER_CTRL2 (0x04) -+ -+#define AK_PWM_HIGH_LEVEL(x) ((x) << 16) -+#define AK_PWM_LOW_LEVEL(x) (x) -+ -+#define AK_TIMER_TIMEOUT_CLR (1<<30) -+#define AK_TIMER_FEED_TIMER (1<<29) -+#define AK_PWM_TIMER_EN (1<<28) -+#define AK_TIMER_TIMEOUT_STA (1<<27) -+#define AK_TIMER_READ_SEL (1<<26) -+ -+#define AK_TIMER_WORK_MODE(x) ((x)<<24) -+#define AK_PWM_TIMER_PRE_DIV(x) ((x) << 16) -+#define AK_PWM_TIMER_PRE_DIV_MASK ((0xff) << 16) -+ -+ -+#define REAL_CRYSTAL_FREQ (12*1000*1000) -+#define PWM_MAX_FREQ (6*1000*1000) -+#define PWM_MIN_FREQ (92*1000) -+ -+#define AK_PWM_TIMER_CNT (5) -+ -+/*the pwm/timer number.*/ -+enum ak_pwm_timer_nr { -+ AK_PWM_TIMER1, -+ AK_PWM_TIMER2, -+ AK_PWM_TIMER3, -+ AK_PWM_TIMER4, -+ AK_PWM_TIMER5, -+ AK_PWM_TIMER_NR, -+}; -+ -+ -+enum ak_pwm_timer_status { -+ PWM_TIMER_UNUSED, -+ PWM_TIMER_BUSY, -+ PWM_TIMER_RESERVED, -+}; -+ -+ -+enum ak_pwm_timer_mode -+{ -+ AK_PT_MODE_TIMER_AUTO_LOAD = 0, -+ AK_PT_MODE_TIMER_ONE_SHOT, -+ AK_PT_MODE_PWM, -+}; -+ -+ -+int ak_pwm_get_duty_cycle(struct ak_pwm_timer *pwm, unsigned short *high, unsigned short *low); -+int ak_pwm_config(struct ak_pwm_timer *pwm, unsigned short high, unsigned short low, unsigned int freq); -+ -+int ak_pwm_enable(struct ak_pwm_timer *pwm); -+void ak_pwm_disable(struct ak_pwm_timer *pwm); -+int ak_timer_enable(struct ak_pwm_timer *timer); -+int ak_timer_enable_sync(struct ak_pwm_timer *timer); -+void ak_timer_disable(struct ak_pwm_timer *timer); -+ -+struct ak_pwm_timer *ak_pwm_request(int pwm_id); -+struct ak_pwm_timer *ak_timer_request(int timer_id, bool auto_reload, int (*cb)(void* data)); -+ -+void ak_pwm_release(struct ak_pwm_timer *pwm); -+void ak_timer_release(struct ak_pwm_timer *timer); -+ -+int ak_timer_config(struct ak_pwm_timer *timer, u32 cnt, u8 pre_div); -+ -+#endif -+ -diff --git a/arch/arm/mach-ak39/include/mach/reboot.h b/arch/arm/mach-ak39/include/mach/reboot.h -new file mode 100644 -index 00000000..292f6507 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/reboot.h -@@ -0,0 +1,7 @@ -+#ifndef __AK39_REBOOT_H -+#define __AK39_REBOOT_H -+ -+void ak39_reboot_sys_by_soft(void); -+void ak39_jump_to_rom(unsigned long addr); -+ -+#endif -diff --git a/arch/arm/mach-ak39/include/mach/reset.h b/arch/arm/mach-ak39/include/mach/reset.h -new file mode 100644 -index 00000000..73718d18 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/reset.h -@@ -0,0 +1,58 @@ -+/* -+ * mach/reset.h -+ */ -+#ifndef _AK39_RESET_H_ -+#define _AK39_RESET_H_ __FILE__ -+ -+#include <linux/types.h> -+ -+extern void (*ak39_arch_reset) (void); -+ -+#define MODULE_RESET_CON1 (AK_VA_SYSCTRL + 0x20) -+ -+#define AK39_SRESET_MMCSD (1) -+#define AK39_SRESET_SDIO (2) -+#define AK39_SRESET_ADC (3) -+#define AK39_SRESET_DAC (4) -+#define AK39_SRESET_SPI1 (5) -+#define AK39_SRESET_SPI2 (6) -+#define AK39_SRESET_UART1 (7) -+#define AK39_SRESET_UART2 (8) -+#define AK39_SRESET_L2MEM (9) -+#define AK39_SRESET_I2C (10) -+#define AK39_SRESET_IRDA (11) -+#define AK39_SRESET_GPIO (12) -+#define AK39_SRESET_MAC (13) -+#define AK39_SRESET_ENCRY (14) -+#define AK39_SRESET_USBHS (15) -+#define AK39_SRESET_CAMERA (19) -+#define AK39_SRESET_VIDEO (20) -+#define AK39_SRESET_DRAM (24) -+ -+int ak39_soft_reset(u32 module); -+ -+/***** extern call for comm drivers compatible *****/ -+#define AK_SRESET_MMCSD AK39_SRESET_MMCSD -+#define AK_SRESET_SDIO AK39_SRESET_SDIO -+#define AK_SRESET_ADC AK39_SRESET_ADC -+#define AK_SRESET_DAC AK39_SRESET_DAC -+#define AK_SRESET_SPI1 AK39_SRESET_SPI1 -+#define AK_SRESET_SPI2 AK39_SRESET_SPI2 -+#define AK_SRESET_UART1 AK39_SRESET_UART1 -+#define AK_SRESET_UART2 AK39_SRESET_UART2 -+#define AK_SRESET_L2MEM AK39_SRESET_L2MEM -+#define AK_SRESET_I2C AK39_SRESET_I2C -+#define AK_SRESET_IRDA AK39_SRESET_IRDA -+#define AK_SRESET_GPIO AK39_SRESET_GPIO -+#define AK_SRESET_MAC AK39_SRESET_MAC -+#define AK_SRESET_ENCRY AK39_SRESET_ENCRY -+#define AK_SRESET_USBHS AK39_SRESET_USBHS -+#define AK_SRESET_CAMERA AK39_SRESET_CAMERA -+#define AK_SRESET_VIDEO AK39_SRESET_VIDEO -+#define AK_SRESET_DRAM AK39_SRESET_DRAM -+ -+ -+int ak_soft_reset(u32 module); -+/*** end extern call for comm drivers compatible ***/ -+ -+#endif -diff --git a/arch/arm/mach-ak39/include/mach/spi.h b/arch/arm/mach-ak39/include/mach/spi.h -new file mode 100644 -index 00000000..86072ff2 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/spi.h -@@ -0,0 +1,93 @@ -+/* -+ * include/asm-arm/arch-ak37/spi.h -+ */ -+ -+#ifndef __SPI_H__ -+#define __SPI_H__ -+ -+struct ak_spi_info { -+ unsigned long* pin_cs; -+ unsigned short num_cs; -+ unsigned long board_size; -+ unsigned short bus_num; -+ unsigned short mode_bits; -+ char clk_name[20]; -+ int xfer_mode; /*use for dma or cpu*/ -+}; -+ -+enum akspi_cs_num { -+ AKSPI_ONCHIP_CS = 0, /*on chip control cs index*/ -+ /*AKSPI_CS1,*/ -+ /*AKSPI_CS2,*/ -+ AKSPI_CS_NUM, -+}; -+ -+enum akspi_bus_num { -+ AKSPI_BUS_NUM1, -+ AKSPI_BUS_NUM2, -+ AKSPI_MAX_BUS_NUM, -+}; -+ -+ -+#define AKSPI_1DATAWIRE (0b00<<16) -+#define AKSPI_2DATAWIRE (0b01<<16) -+#define AKSPI_4DATAWIRE (0b10<<16) -+ -+#define AKSPI_XFER_MODE_DMA (1) -+#define AKSPI_XFER_MODE_CPU (2) -+ -+ -+#define AK_SPICON (0x00) -+#define AK_SPICON_WIRE (0x3<<16) -+#define AK_SPICON_CLKDIV (0x7F<<8) -+#define AK_SPICON_EN (1<<6) -+#define AK_SPICON_CS (1<<5) -+#define AK_SPICON_MS (1<<4) -+#define AK_SPICON_CPHA (1<<3) -+#define AK_SPICON_CPOL (1<<2) -+#define AK_SPICON_ARRM (1<<1) -+#define AK_SPICON_TGDM (1<<0) -+ -+#define AK_SPISTA (0x04) -+#define AK_SPISTA_TIMEOUT (1<<10) -+#define AK_SPISTA_MPROC (1<<9) -+#define AK_SPISTA_TRANSF (1<<8) -+#define AK_SPISTA_RXOVER (1<<7) -+#define AK_SPISTA_RXHFULL (1<<6) -+#define AK_SPISTA_RXFULL (1<<5) -+#define AK_SPISTA_RXEMP (1<<4) -+#define AK_SPISTA_TXUNDER (1<<3) -+#define AK_SPISTA_TXHEMP (1<<2) -+#define AK_SPISTA_TXFULL (1<<1) -+#define AK_SPISTA_TXEMP (1<<0) -+ -+#define AK_SPIINT (0x08) -+#define AK_SPIINT_TIMEOUT (1<<10) -+#define AK_SPIINT_MPROC (1<<9) -+#define AK_SPIINT_TRANSF (1<<8) -+#define AK_SPIINT_RXOVER (1<<7) -+#define AK_SPIINT_RXHFULL (1<<6) -+#define AK_SPIINT_RXFULL (1<<5) -+#define AK_SPIINT_RXEMP (1<<4) -+#define AK_SPIINT_TXUNDER (1<<3) -+#define AK_SPIINT_TXHEMP (1<<2) -+#define AK_SPIINT_TXFULL (1<<1) -+#define AK_SPIINT_TXEMP (1<<0) -+ -+#define AK_SPICNT (0x0C) -+ -+#define AK_SPIEXTX (0x10) -+#define AK_SPIEXTX_BUFEN (1<<0) -+#define AK_SPIEXTX_DMAEN (1<<16) -+ -+ -+#define AK_SPIEXRX (0x14) -+#define AK_SPIEXRX_BUFEN (1<<0) -+#define AK_SPIEXRX_DMAEN (1<<16) -+ -+#define AK_SPIOUT (0x18) -+ -+#define AK_SPIIN (0x1C) -+ -+#endif -+ -diff --git a/arch/arm/mach-ak39/include/mach/timex.h b/arch/arm/mach-ak39/include/mach/timex.h -new file mode 100644 -index 00000000..da916374 ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/timex.h -@@ -0,0 +1,24 @@ -+/* arch/arm/mach-ak39/include/mach/timex.h -+ * -+ * Copyright (c) 2003-2005 Simtec Electronics -+ * Ben Dooks <ben@simtec.co.uk> -+ * -+ * AK39XX - time parameters -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ -+ -+#ifndef __ASM_ARCH_TIMEX_H -+#define __ASM_ARCH_TIMEX_H -+ -+/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it -+ * a variable is useless. It seems as long as we make our timers an -+ * exact multiple of HZ, any value that makes a 1->1 correspondence -+ * for the time conversion functions to/from jiffies is acceptable. -+*/ -+ -+#define CLOCK_TICK_RATE 12000000 -+ -+#endif /* end __ASM_ARCH_TIMEX_H */ -diff --git a/arch/arm/mach-ak39/include/mach/uncompress.h b/arch/arm/mach-ak39/include/mach/uncompress.h -new file mode 100755 -index 00000000..aed3953a ---- /dev/null -+++ b/arch/arm/mach-ak39/include/mach/uncompress.h -@@ -0,0 +1,237 @@ -+/* -+ * linux/arch/arm/mach-ak39/include/mach/uncompress.h -+ * -+ */ -+#ifndef __UNCOMPRESS_H_ -+#define __UNCOMPRESS_H_ -+ -+#include <asm/sizes.h> -+#include <mach/map.h> -+ -+#if defined(CONFIG_CPU_AK3910) || defined(CONFIG_CPU_AK3916) || defined(CONFIG_CPU_AK3918) -+#define CONFIG_UART0_INIT -+#endif -+ -+#define BAUD_RATE 115200 -+#define ENDDING_OFFSET 60 -+ -+#undef REG32 -+#define REG32(_reg) (*(volatile unsigned long *)(_reg)) -+ -+#define CLK_ASIC_PLL_CTRL (AK_PA_SYSCTRL + 0x08) -+ -+/* L2 buffer address */ -+#define UART0_TXBUF_ADDR REG_PA_ADDR(0x48000000, 0x1000) //0x48001000 -+#define UART0_RXBUF_ADDR REG_PA_ADDR(0x48000000, 0x1080) -+#define UART1_TXBUF_ADDR REG_PA_ADDR(0x48000000, 0x1100) -+#define UART1_RXBUF_ADDR REG_PA_ADDR(0x48000000, 0x1180) -+ -+/* L2 buffer control register */ -+#define L2BUF_CONF2_REG REG_PA_VAL(0x20140000, 0x008C) //0x2014008c -+#define UART0_TXBUF_CLR_BIT 16 -+#define UART0_RXBUF_CLR_BIT 17 -+#define UART1_TXBUF_CLR_BIT 18 -+#define UART1_RXBUF_CLR_BIT 19 -+ -+/* pullup/pulldown configure registers */ -+#define PPU_PPD1_REG REG_PA_VAL(AK_PA_SYSCTRL, 0x80) //0x08000080 -+#define RTS1_PU_BIT 24 -+#define CTS1_PU_BIT 23 -+#define TXD1_PU_BIT 22 -+#define RXD1_PU_BIT 21 -+#define TXD0_PU_BIT 20 -+#define RXD0_PU_BIT 19 -+ -+/* Clock control register */ -+#define CLK_CTRL_REG1 REG_PA_VAL(AK_PA_SYSCTRL, 0x1C) //0x0800000C -+#define UART0_CLKEN_BIT 7 -+#define UART1_CLKEN_BIT 8 -+ -+/*********** Shared pin control reigsters ********/ -+#define SRDPIN_CTRL1_REG REG_PA_VAL(AK_PA_SYSCTRL, 0x74) //0x08000074 -+#define UART0_RXD 14 -+#define UART0_TXD 15 -+#define UART1_RXD 16 -+#define UART1_TXD 18 -+#define UART1_CTS 20 -+#define UART1_RTS 22 -+ -+/** ************ UART registers *****************************/ -+#define UART0_CONF1_REG REG_PA_VAL(0x20130000, 0x00) //0x20130000 -+#define UART0_CONF2_REG REG_PA_VAL(0x20130000, 0x04) -+#define UART0_DATA_CONF_REG REG_PA_VAL(0x20130000, 0x08) -+#define UART0_BUF_THRE_REG REG_PA_VAL(0x20130000, 0x0C) -+#define UART0_BUF_RX_REG REG_PA_VAL(0x20130000, 0x10) -+#define UART0_BUF_RX_BACKUP_REG REG_PA_VAL(0x20130000, 0x14) -+#define UART0_BUF_STOPBIT_REG REG_PA_VAL(0x20130000, 0x18) -+ -+#define UART1_CONF1_REG REG_PA_VAL(0x20138000, 0x00) //0x20138000 -+#define UART1_CONF2_REG REG_PA_VAL(0x20138000, 0x04) -+#define UART1_DATA_CONF_REG REG_PA_VAL(0x20138000, 0x08) -+#define UART1_BUF_THRE_REG REG_PA_VAL(0x20138000, 0x0C) -+#define UART1_BUF_RX_REG REG_PA_VAL(0x20138000, 0x10) -+#define UART1_BUF_RX_BACKUP_REG REG_PA_VAL(0x20138000, 0x14) -+#define UART1_BUF_STOPBIT_REG REG_PA_VAL(0x20138000, 0x18) -+ -+/* bit define of UARTx_CONF1_REG */ -+#define CTS_SEL_BIT 18 -+#define RTS_SEL_BIT 19 -+#define PORT_ENABLE_BIT 21 //0: disable, 1:enable -+#define TX_STATUS_CLR_BIT 28 -+#define RX_STATUS_CLR_BIT 29 -+ -+/* bit define of UARTx_CONF2_REG */ -+#define TX_COUNT_BIT 4 -+#define TX_COUNT_VALID_BIT 16 -+#define TX_END_BIT 19 -+#define TX_END_MASK (1 << TX_END_BIT) -+ -+#if defined CONFIG_UART0_INIT -+#define UART_TXBUF_CLR_BIT UART0_TXBUF_CLR_BIT -+#define SRDPIN_UART_RXTX_BIT ((1 << UART0_RXD)|(1 << UART0_RXD)) -+#define RXD_PU_BIT RXD0_PU_BIT -+#define TXD_PU_BIT TXD0_PU_BIT -+#define UART_CLKEN_BIT UART0_CLKEN_BIT -+#define UART_TXBUF_ADDR UART0_TXBUF_ADDR -+#define UART_CONF1_REG UART0_CONF1_REG -+#define UART_CONF2_REG UART0_CONF2_REG -+#define UART_DATA_CONF_REG UART0_DATA_CONF_REG -+#define UART_BUF_STOPBIT_REG UART0_BUF_STOPBIT_REG -+#elif defined CONFIG_UART1_INIT -+#define UART_TXBUF_CLR_BIT UART1_TXBUF_CLR_BIT -+#define SRDPIN_UART_RXTX_BIT ((0x2 << UART1_RXD)|(0x2 << UART1_RXD)) -+#define RXD_PU_BIT RXD1_PU_BIT -+#define TXD_PU_BIT TXD1_PU_BIT -+#define UART_CLKEN_BIT UART1_CLKEN_BIT -+#define UART_TXBUF_ADDR UART1_TXBUF_ADDR -+#define UART_CONF1_REG UART1_CONF1_REG -+#define UART_CONF2_REG UART1_CONF2_REG -+#define UART_DATA_CONF_REG UART1_DATA_CONF_REG -+#define UART_BUF_STOPBIT_REG UART1_BUF_STOPBIT_REG -+ -+#else -+#error One of UART0 ~ UART1 Must be defined -+#endif -+ -+static unsigned int __uidiv(unsigned int num, unsigned int den) -+{ -+ unsigned int i; -+ -+ if (den == 1) -+ return num; -+ -+ i = 1; -+ while (den * i < num) -+ i++; -+ -+ return i-1; -+} -+ -+static unsigned long __get_asic_pll_clk(void) -+{ -+ unsigned long pll_m, pll_n, pll_od; -+ unsigned long asic_pll_clk; -+ unsigned long regval; -+ -+ regval = REG32(CLK_ASIC_PLL_CTRL); -+ pll_od = (regval & (0x3 << 12)) >> 12; -+ pll_n = (regval & (0xf << 8)) >> 8; -+ pll_m = regval & 0xff; -+ -+ asic_pll_clk = (12 * pll_m)/(pll_n * (1 << pll_od)); // clk unit: MHz -+ -+ if ((pll_od >= 1) && ((pll_n >= 2) && (pll_n <= 6)) -+ && ((pll_m >= 84) && (pll_m <= 254))) -+ return asic_pll_clk; -+ return 0; -+} -+ -+static unsigned long __get_vclk(void) -+{ -+ unsigned long regval; -+ unsigned long div; -+ -+ regval = REG32(CLK_ASIC_PLL_CTRL); -+ div = (regval & (0x7 << 17)) >> 17; -+ if (div == 0) -+ return __get_asic_pll_clk() >> 1; -+ -+ return __get_asic_pll_clk() >> div; -+} -+ -+unsigned long __get_asic_clk(void) -+{ -+ unsigned long regval; -+ unsigned long div; -+ -+ regval = REG32(CLK_ASIC_PLL_CTRL); -+ div = regval & (1 << 24); -+ if (div == 0) -+ return __get_vclk(); -+ -+ return __get_vclk() >> 1; -+} -+ -+static void uart_init(void) -+{ -+ unsigned int asic_clk, clk_div; -+ -+ /* enable uart clock control */ -+ CLK_CTRL_REG1 &= ~(0x1 << UART_CLKEN_BIT); -+ -+ /* configuration shared pins to UART */ -+ SRDPIN_CTRL1_REG |= SRDPIN_UART_RXTX_BIT; -+ -+ /* configuration uart pin pullup disable */ -+ PPU_PPD1_REG |= (0x1 << RXD_PU_BIT) | (0x1 << TXD_PU_BIT); -+ -+ asic_clk = __get_asic_clk()*1000000; -+ clk_div = __uidiv(asic_clk, BAUD_RATE) - 1; -+ UART_CONF1_REG &= ~((0x1 << TX_STATUS_CLR_BIT) | (0x1 << RX_STATUS_CLR_BIT) | 0xFF); -+ UART_CONF1_REG |= (0x1 << TX_STATUS_CLR_BIT) | (0x1 << RX_STATUS_CLR_BIT) | clk_div; -+ -+#ifdef CONFIG_UART1_INIT -+ /* Disable flow control */ -+ UART_CONF1_REG |= (0x1 << CTS_SEL_BIT) | (0x1 << RTS_SEL_BIT); -+#endif -+ UART_BUF_STOPBIT_REG = (0x1F << 16) | (0x1 << 0); -+ -+ /* enable uart port */ -+ UART_CONF1_REG |= (0x1 << PORT_ENABLE_BIT); -+} -+ -+ -+/* print a char to uart */ -+static void putc(char c) -+{ -+ /* Clear uart tx buffer */ -+ L2BUF_CONF2_REG |= (0x1 << UART_TXBUF_CLR_BIT); -+ -+ /* write char to uart buffer */ -+ REG32(UART_TXBUF_ADDR) = (unsigned long)c; -+ REG32(UART_TXBUF_ADDR + ENDDING_OFFSET) = (unsigned long)'\0'; -+ -+ /* Clear uart tx count register */ -+ UART_CONF1_REG |= (0x1 << TX_STATUS_CLR_BIT); -+ -+ /* Send buffer, each time only send 1 byte */ -+ UART_CONF2_REG |= (1 << TX_COUNT_BIT) | (0x1 << TX_COUNT_VALID_BIT); -+ -+ /* Wait for finish */ -+ while((UART_CONF2_REG & TX_END_MASK) == 0) { -+ } -+} -+ -+static inline void flush(void) -+{ -+} -+ -+static inline void arch_decomp_setup(void) -+{ -+ uart_init(); -+} -+ -+/* nothing to do */ -+#define arch_decomp_wdog() -+ -+#endif /* __UNCOMPRESS_H_ */ -diff --git a/arch/arm/mach-ak39/irq.c b/arch/arm/mach-ak39/irq.c -new file mode 100755 -index 00000000..a008a164 ---- /dev/null -+++ b/arch/arm/mach-ak39/irq.c -@@ -0,0 +1,310 @@ -+/* -+ * arch/arm/mach-ak39/irq.c -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/interrupt.h> -+#include <linux/ioport.h> -+#include <linux/device.h> -+#include <linux/irq.h> -+ -+#include <mach/gpio.h> -+ -+ -+/* interrupt mask 0: mask 1: unmask */ -+#define AK_IRQ_MASK (AK_VA_SYSCTRL + 0x24) -+#define AK_FIQ_MASK (AK_VA_SYSCTRL + 0x28) -+#define AK_INT_STATUS (AK_VA_SYSCTRL + 0x4C) -+#define AK_SYSCTRL_INT_MASK (AK_VA_SYSCTRL + 0x2C) -+#define AK_SYSCTRL_INT_STATUS (AK_VA_SYSCTRL + 0x30) -+ -+#define AK_L2MEM_IRQ_ENABLE (AK_VA_L2CTRL + 0x9C) -+ -+ -+/* -+ * Disable interrupt number "irq" -+ */ -+static void ak39_mask_irq(struct irq_data *d) -+{ -+ unsigned long regval; -+ -+ regval = __raw_readl(AK_IRQ_MASK); -+ regval &= ~(1UL << d->irq); -+ __raw_writel(regval, AK_IRQ_MASK); -+} -+ -+/* -+ * Enable interrupt number "irq" -+ */ -+static void ak39_unmask_irq(struct irq_data *d) -+{ -+ unsigned long regval; -+ -+ regval = __raw_readl(AK_IRQ_MASK); -+ regval |= (1UL << d->irq); -+ __raw_writel(regval, AK_IRQ_MASK); -+} -+ -+static struct irq_chip ak39_irq_chip = { -+ .name = "module-irq", -+ .irq_mask_ack = ak39_mask_irq, -+ .irq_mask = ak39_mask_irq, -+ .irq_unmask = ak39_unmask_irq, -+}; -+ -+static void sysctrl_mask_irq(struct irq_data *d) -+{ -+ unsigned long regval; -+ -+ regval = __raw_readl(AK_SYSCTRL_INT_MASK); -+ regval &= ~(1 << (d->irq - IRQ_SYSCTRL_START)); -+ __raw_writel(regval, AK_SYSCTRL_INT_MASK); -+} -+ -+static void sysctrl_unmask_irq(struct irq_data *d) -+{ -+ unsigned long regval; -+ -+ regval = __raw_readl(AK_SYSCTRL_INT_MASK); -+ regval |= (1 << (d->irq - IRQ_SYSCTRL_START)); -+ __raw_writel(regval, AK_SYSCTRL_INT_MASK); -+} -+ -+/* enable rtc alarm to wake up systerm */ -+static int sysctrl_set_wake(struct irq_data *d, unsigned int on) -+{ -+#if 0 // wait for programming -+ -+ unsigned long clkdiv1; -+ -+ if (d->irq == IRQ_RTC_ALARM) { -+ -+ clkdiv1 = __raw_readl(AK98_CLKDIV1); -+ -+ if (on == 1) -+ clkdiv1 |= (1 << 16); -+ else -+ clkdiv1 &= ~(1 << 16); -+ -+ __raw_writel(clkdiv1, AK98_CLKDIV1); -+ -+ return 0; -+ } -+#endif -+ return 0; -+} -+ -+static struct irq_chip ak39_sysctrl_chip = { -+ .name = "sysctrl-irq", -+ .irq_mask_ack = sysctrl_mask_irq, -+ .irq_mask = sysctrl_mask_irq, -+ .irq_unmask = sysctrl_unmask_irq, -+ .irq_set_wake = sysctrl_set_wake, -+}; -+ -+static void ak39_sysctrl_handler(unsigned int irq, struct irq_desc *desc) -+{ -+ unsigned long regval_mask, regval_sta; -+ unsigned long intpnd; -+ unsigned int offset; -+ -+ regval_mask = __raw_readl(AK_SYSCTRL_INT_MASK); -+ regval_sta = __raw_readl(AK_SYSCTRL_INT_STATUS); -+ -+ intpnd = (regval_mask & 0x7FF) & (regval_sta & 0x7FF); -+ -+ for (offset = 0; intpnd && offset < 11; offset++) { -+ -+ if (intpnd & (1 << offset)) -+ intpnd &= ~(1 << offset); -+ else -+ continue; -+ -+ irq = AK39_SYSCTRL_IRQ(offset); //come back debug -+ generic_handle_irq(irq); -+ } -+} -+ -+static void ak39_gpioirq_mask(struct irq_data *d) -+{ -+ void __iomem *gpio_ctrl = AK_GPIO_INT_MASK1; -+ unsigned long regval; -+ unsigned int irq = d->irq; -+ -+ irq -= IRQ_GPIO_0; -+ gpio_ctrl += (irq / 32) * 4; -+ -+ regval = __raw_readl(gpio_ctrl); -+ regval &= ~(1 << (irq & 31)); -+ __raw_writel(regval, gpio_ctrl); -+} -+ -+static void ak39_gpioirq_unmask(struct irq_data *d) -+{ -+ void __iomem *gpio_ctrl = AK_GPIO_INT_MASK1; -+ unsigned long regval; -+ unsigned int irq = d->irq; -+ -+ irq -= IRQ_GPIO_0; -+ gpio_ctrl += (irq / 32) * 4; -+ -+ regval = __raw_readl(gpio_ctrl); -+ regval |= (1 << (irq & 31)); -+ __raw_writel(regval, gpio_ctrl); -+} -+ -+static int ak39_gpioirq_set_type(struct irq_data *d, unsigned int type) -+{ -+ void __iomem *reg_irqmod = AK_GPIO_INT_MODE1; -+ void __iomem *reg_irqpol = AK_GPIO_INTP1; -+ unsigned int irq = d->irq; -+ unsigned long regval_pol, regval_mod, offset; -+ int p, l; -+ -+ irq -= IRQ_GPIO_0; -+ -+ offset = irq & 31; -+ -+ reg_irqmod += (irq / 32) * 4; -+ reg_irqpol += (irq / 32) * 4; -+ -+ regval_mod = __raw_readl(reg_irqmod); -+ regval_pol = __raw_readl(reg_irqpol); -+ -+ switch (type) { -+ case IRQ_TYPE_EDGE_RISING: -+ p = 1; l = 0; break; -+ case IRQ_TYPE_EDGE_FALLING: -+ p = 1; l = 1; break; -+ case IRQ_TYPE_LEVEL_HIGH: -+ p = 0; l = 0; break; -+ case IRQ_TYPE_LEVEL_LOW: -+ p = 0; l = 1; break; -+ default: -+ pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n", -+ __func__, type); -+ return -ENXIO; -+ } -+ -+ if (p) -+ regval_mod |= (1 << (offset)); -+ else -+ regval_mod &= ~(1 << (offset)); -+ if (l) -+ regval_pol |= (1 << (offset)); -+ else -+ regval_pol &= ~(1 << (offset)); -+ -+ __raw_writel(regval_mod, reg_irqmod); -+ __raw_writel(regval_pol, reg_irqpol); -+ -+ return 0; -+} -+ -+static int ak39_gpio_irq_set_wake(struct irq_data *d, unsigned int on) -+{ -+ unsigned long regval; -+ -+ regval = __raw_readl(AK_WGPIO_ENABLE); -+ -+ if (d->irq >= IRQ_GPIO_0 && d->irq <= IRQ_GPIO_7) -+ regval |= (1 << (d->irq - IRQ_GPIO_0)); -+ -+ else if (d->irq>= IRQ_GPIO_12 && d->irq <= IRQ_GPIO_14) -+ regval |= (1 << (d->irq - IRQ_GPIO_12 + 8)); -+ -+ else if (d->irq == IRQ_GPIO_22) -+ regval |= (1 << (d->irq - IRQ_GPIO_22 + 11)); -+ -+ else if (d->irq >= IRQ_GPIO_27 && d->irq <= IRQ_GPIO_30) -+ regval |= (1 << (d->irq - IRQ_GPIO_27 + 12)); -+ -+ else if (d->irq >= IRQ_GPIO_39 && d->irq <= IRQ_GPIO_44) -+ regval |= (1 << (d->irq- IRQ_GPIO_41 + 16)); -+ -+ else if (d->irq >= IRQ_GPIO_47 && d->irq <= IRQ_GPIO_55) -+ regval |= (1 << (d->irq - IRQ_GPIO_47 + 22)); -+ -+ else if (d->irq == IRQ_GPIO_57) -+ regval |= (1 << (d->irq - IRQ_GPIO_57 + 31)); -+ -+ else { -+ printk("Not WGPIO IRQ: %d\n", d->irq); -+ return -1; -+ } -+ -+ __raw_writel(regval, AK_WGPIO_ENABLE); -+ -+ return 0; -+} -+ -+static struct irq_chip ak39_gpioirq_chip = { -+ .name = "gpio-irq", -+ .irq_mask_ack = ak39_gpioirq_mask, -+ .irq_mask = ak39_gpioirq_mask, -+ .irq_unmask = ak39_gpioirq_unmask, -+ .irq_set_type = ak39_gpioirq_set_type, -+ .irq_set_wake = ak39_gpio_irq_set_wake, -+}; -+ -+static void ak39_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) -+{ -+ unsigned long enabled_irq; -+ unsigned int i; -+ unsigned int off; -+ -+ for (i = 0; i < 4; i++) { -+ enabled_irq = __raw_readl(AK_GPIO_INT_MASK1 + i * 4); -+ -+ while (enabled_irq) { -+ off = __ffs(enabled_irq); -+ enabled_irq &= ~(1 << off); -+ if (test_bit(off, AK_GPIO_INTP1 + i * 4) != -+ test_bit(off, AK_GPIO_INPUT1 + i * 4)) { -+ irq = IRQ_GPIO_0 + i * 32 + off; -+ generic_handle_irq(irq); -+ } -+ } -+ } -+} -+ -+void __init ak39_init_irq(void) -+{ -+ int i; -+ -+ /* 1st, clear all interrupts */ -+ __raw_readl(AK_INT_STATUS); -+ __raw_readl(AK_SYSCTRL_INT_STATUS); -+ -+ /* 2nd, mask all interrutps */ -+ __raw_writel(0x0, AK_IRQ_MASK); -+ __raw_writel(0x0, AK_FIQ_MASK); -+ __raw_writel(0x0, AK_SYSCTRL_INT_MASK); -+ -+ /* mask all gpio interrupts */ -+ __raw_writel(0x0, AK_GPIO_INT_MASK1); -+ __raw_writel(0x0, AK_GPIO_INT_MASK2); -+ -+ /* mask all l2 interrupts */ -+ __raw_writel(0x0, AK_L2MEM_IRQ_ENABLE); -+ -+ for (i = IRQ_MEM; i <= IRQ_USBOTG_DMA; i++) { -+ irq_set_chip_and_handler(i, &ak39_irq_chip, handle_level_irq); -+ set_irq_flags(i, IRQF_VALID); -+ } -+ -+ irq_set_chained_handler(IRQ_SYSCTRL, ak39_sysctrl_handler); -+ -+ for (i = IRQ_SARADC; i <= IRQ_RTC_WATCHDOG; i++) { -+ irq_set_chip_and_handler(i, &ak39_sysctrl_chip, handle_level_irq); -+ set_irq_flags(i, IRQF_VALID); -+ } -+ irq_set_chained_handler(IRQ_GPIO, ak39_gpio_irqhandler); -+ -+ for (i = IRQ_GPIO_0; i < NR_IRQS; i++) { -+ irq_set_chip_and_handler(i, &ak39_gpioirq_chip, handle_level_irq); -+ set_irq_flags(i, IRQF_VALID); -+ } -+} -+ -diff --git a/arch/arm/mach-ak39/irq.h b/arch/arm/mach-ak39/irq.h -new file mode 100644 -index 00000000..07be10a5 ---- /dev/null -+++ b/arch/arm/mach-ak39/irq.h -@@ -0,0 +1 @@ -+void __init ak39_init_irq(void); -diff --git a/arch/arm/mach-ak39/l2cache.c b/arch/arm/mach-ak39/l2cache.c -new file mode 100644 -index 00000000..72322cc4 ---- /dev/null -+++ b/arch/arm/mach-ak39/l2cache.c -@@ -0,0 +1,27 @@ -+/* -+ * linux/arch/arm/mach-ak39/l2cache.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <mach/l2cache.h> -+ -+void l2cache_init(void) -+{ -+} -+EXPORT_SYMBOL(l2cache_init); -+ -+void l2cache_clean_finish(void) -+{ -+} -+EXPORT_SYMBOL(l2cache_clean_finish); -+ -+void l2cache_invalidate(void) -+{ -+} -+EXPORT_SYMBOL(l2cache_invalidate); -+ -diff --git a/arch/arm/mach-ak39/mach-aimer39_ak3916.c b/arch/arm/mach-ak39/mach-aimer39_ak3916.c -new file mode 100755 -index 00000000..1a5add13 ---- /dev/null -+++ b/arch/arm/mach-ak39/mach-aimer39_ak3916.c -@@ -0,0 +1,713 @@ -+/* -+ * 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/platform_device.h> -+#include <linux/irq.h> -+#include <linux/i2c.h> -+#include <linux/i2c-gpio.h> -+ -+#include <plat-anyka/wifi.h> -+#include <plat-anyka/otg-hshcd.h> -+#include <plat-anyka/ak_camera.h> -+#include <plat-anyka/aksensor.h> -+ -+#include <asm/mach/arch.h> -+#include <asm/mach-types.h> -+#include <asm/irq.h> -+ -+#include <plat/l2.h> -+#include <mach/devices.h> -+#include <mach/gpio.h> -+#include <mach-anyka/mac.h> -+#include <mach/ak_codec.h> -+ -+#include <mach/spi.h> -+#include <linux/spi/flash.h> -+#include <linux/spi/spi.h> -+#include <linux/spi/spidev.h> -+#include <plat-anyka/akmci.h> -+#include <plat-anyka/adkey.h> -+ -+#include <mach/leds-gpio.h> -+#include <linux/input.h> -+#include <plat-anyka/gpio_keys.h> -+#include <plat-anyka/bat.h> -+ -+#include <plat-anyka/ak_motor.h> -+#include "cpu.h" -+#include "irq.h" -+#include <mach/adc.h> -+#include <plat-anyka/akgpios.h> -+#include <mach/reboot.h> -+ -+#define SPI_ONCHIP_CS (0) /*means not need gpio*/ -+static unsigned long ak39_spidev_cs[AKSPI_CS_NUM] = { -+ [AKSPI_ONCHIP_CS] = SPI_ONCHIP_CS, /*gpio 25, spidev0: ak-spiflash*/ -+}; -+ -+struct ak_spi_info ak39_spi1_info = { -+ .pin_cs = ak39_spidev_cs, -+ .num_cs = ARRAY_SIZE(ak39_spidev_cs), -+ .bus_num = AKSPI_BUS_NUM1, -+ .clk_name = "spi1", -+ .mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH, -+ .xfer_mode = AKSPI_XFER_MODE_DMA, -+}; -+ -+static struct flash_platform_data ak39_spiflash_info= { -+ .bus_width = FLASH_BUS_WIDTH_4WIRE | FLASH_BUS_WIDTH_2WIRE | FLASH_BUS_WIDTH_1WIRE, -+ .type = NULL, -+}; -+ -+static struct spi_board_info ak39_spi_board_dev[] = { -+ { -+ .modalias = "ak-spiflash", -+ .bus_num = AKSPI_BUS_NUM1, -+ .chip_select = AKSPI_ONCHIP_CS, -+ .mode = SPI_MODE_0, -+ .max_speed_hz = 20*1000*1000, -+ .platform_data = &ak39_spiflash_info, -+ }, -+}; -+ -+static struct ak_motor_plat_data ak39_motor0_pdata = { -+ .gpio_phase[0] = { -+ .pin = AK_GPIO_37, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[1] = { -+ .pin = AK_GPIO_38, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[2] = { -+ .pin = AK_GPIO_39, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[3] = { -+ .pin = AK_GPIO_40, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ -+ .gpio_hit[0] = { -+ .pin = AK_GPIO_62, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_hit[1] ={ -+ .pin = AK_GPIO_63, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .irq_hit_type[0] = IRQ_TYPE_LEVEL_LOW, -+ .irq_hit_type[1] = IRQ_TYPE_LEVEL_LOW, -+ -+ .angular_speed = 100, /* angle/s */ -+}; -+ -+ -+ -+static struct ak_motor_plat_data ak39_motor1_pdata = { -+ .gpio_phase[0] = { -+ .pin = AK_GPIO_56, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[1] = { -+ .pin = AK_GPIO_58, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[2] = { -+ .pin = AK_GPIO_59, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[3] = { -+ .pin = AK_GPIO_60, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ -+ .gpio_hit[0] = { -+ .pin = AK_GPIO_61, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_hit[1] ={ -+ .pin = AK_GPIO_49, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .irq_hit_type[0] = IRQ_TYPE_LEVEL_LOW, -+ .irq_hit_type[1] = IRQ_TYPE_LEVEL_LOW, -+ -+ .angular_speed = 100, /* angle/s */ -+}; -+ -+ -+ -+/* SDIO platform data*/ -+struct ak_mci_platform_data sdio_plat_data = { -+ .irq_cd_type = IRQ_TYPE_LEVEL_LOW, -+ .detect_mode = AKMCI_PLUGIN_ALWAY, -+ .xfer_mode = AKMCI_XFER_L2DMA, -+ .mci_mode = MCI_MODE_SDIO, -+ .gpio_init = ak_gpio_set, -+ .max_speed_hz = 25*1000*1000, -+ .gpio_cd = { -+ .pin = AK_GPIO_18, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_wp = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = AK_PULLUP_ENABLE, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ } -+}; -+ -+/* MMC/SD platform data*/ -+struct ak_mci_platform_data mmc_plat_data = { -+ .irq_cd_type = IRQ_TYPE_LEVEL_LOW, -+ .detect_mode = AKMCI_DETECT_MODE_AD, -+ .xfer_mode = AKMCI_XFER_L2DMA, -+ .mci_mode = MCI_MODE_MMC_SD, -+ .max_speed_hz = 25*1000*1000, -+ .gpio_init = ak_gpio_set, -+ .gpio_cd = { -+ .pin = -1,//AK_GPIO_47, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_wp = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = AK_PULLUP_ENABLE, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ } -+}; -+ -+/* akwifi platform data */ -+struct akwifi_platform_data akwifi_pdata = { -+ .gpio_init = ak_gpio_set, -+#if defined(CONFIG_SDIO_WIFI) -+ .gpio_on = { -+ .pin= AK_GPIO_52, -+ .pulldown= -1, -+ .pullup = -1, -+ .value= AK_GPIO_OUT_HIGH, -+ .dir= AK_GPIO_DIR_OUTPUT, -+ .int_pol= -1, -+ }, -+ .gpio_off = { -+ .pin= AK_GPIO_52, -+ .pulldown= -1, -+ .pullup = -1, -+ .value= AK_GPIO_OUT_LOW, -+ .dir= AK_GPIO_DIR_OUTPUT, -+ .int_pol= -1, -+ }, -+ .power_on_delay = 10, -+ .power_off_delay = 10, -+#else -+ .gpio_on = { -+ .pin = AK_GPIO_50, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_ENABLE, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_off = { -+ .pin = AK_GPIO_50, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_ENABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .power_on_delay = 2000, -+ .power_off_delay = 0, -+#endif -+}; -+ -+struct platform_device anyka_wifi_device = { -+ .name = "anyka-wifi", -+ .id = -1, -+ .dev = { -+ .platform_data = &akwifi_pdata, -+ }, -+}; -+ -+static struct akotghc_usb_platform_data akotghc_plat_data = { -+ .gpio_init = ak_gpio_set, -+ .gpio_pwr_on = { -+ .pin = AK_GPIO_55, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_pwr_off = { -+ .pin = AK_GPIO_55, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .switch_onboard = { -+ .pin = -1, -+ }, -+ .switch_extport = { -+ .pin = -1, -+ }, -+}; -+ -+static struct ak_mac_data ak39_mac_pdata = { -+ .gpio_init = ak_gpio_set, -+ .pwr_gpio = { -+ .pin = AK_GPIO_54, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .phy_rst_gpio = { -+ .pin = AK_GPIO_53, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+}; -+ -+ -+/** -+* @brief ak pcm device struct -+ hp and spk can identify by GPIO or AD. -+ wo can initialize it in this struct. -+* @author dengzhou -+* @date 2012-07-19 -+*/ -+struct ak39_codec_platform_data ak39_codec_pdata = -+{ -+ .hpdet_gpio = -+ { -+ .pin = AK_GPIO_7, -+ .dir = AK_GPIO_DIR_INPUT, -+ .pullup = AK_PULLUP_DISABLE, -+ .pulldown = -1, -+ .value = -1, -+ .int_pol = -1, -+ }, -+ .spk_down_gpio = -+ { -+ .pin = AK_GPIO_3, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .pullup = -1, -+ .pulldown = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .int_pol = -1, -+ }, -+ .hpmute_gpio = -+ { -+ .pin = INVALID_GPIO, //AK_GPIO_29, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .pullup = -1, -+ .pulldown = -1, -+ -+ .value = AK_GPIO_OUT_LOW, -+ .int_pol = -1, -+ }, -+ -+ .hp_on_value = AK_GPIO_OUT_LOW, -+ .hpdet_irq = IRQ_GPIO_7, -+ .bIsHPmuteUsed = 0, -+ .hp_mute_enable_value = AK_GPIO_OUT_HIGH, -+ .bIsMetalfixed = 0, -+ .boutput_only = 1, -+}; -+ -+struct resource ak39_codec_resources[] = { -+ [0] = { -+ .start = 0x08000000, -+ .end = 0x0800FFFF, -+ .flags = (int)IORESOURCE_MEM, -+ .name = "akpcm_AnalogCtrlRegs", -+ }, -+ [1] = { -+ .start = 0x20110000, -+ .end = 0x2011800F, -+ .flags = (int)IORESOURCE_MEM, -+ .name = "akpcm_ADC2ModeCfgRegs", -+ }, -+}; -+ -+struct platform_device ak39_codec_device = { -+ .name = "ak39-codec", -+ .id = -1, -+ .resource = ak39_codec_resources, -+ .num_resources = ARRAY_SIZE(ak39_codec_resources), -+ .dev = { -+ .platform_data = &ak39_codec_pdata, -+ }, -+}; -+ -+ -+/* camera platform data */ -+static struct i2c_board_info ak_camara_devices[] = { -+ { -+ I2C_BOARD_INFO("aksensor", 0x1), -+ }, -+}; -+ -+static struct aksensor_camera_info ak_soc_camera_info = { -+ .buswidth = SOCAM_DATAWIDTH_8, -+ .pin_avdd = INVALID_GPIO, -+ .pin_power = AK_GPIO_48, //initialize GPIO for the power of camera. -+ .pin_reset = AK_GPIO_51, //initialize GPIO for reset of camera. -+ .link = { -+ .bus_id = 39, -+ .power = NULL, -+ .board_info = &ak_camara_devices[0], -+ .i2c_adapter_id = 0, -+ .priv = &ak_soc_camera_info, -+ } -+}; -+ -+/* fake device for soc_camera subsystem */ -+static struct platform_device soc_camera_interface = { -+ .name = "soc-camera-pdrv", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak_soc_camera_info.link, -+ } -+}; -+ -+/* Set LED parameter and initialis status */ -+static struct ak_led_data leds[] = { -+ { -+ .name = "wps_led", -+ .def_trigger = "none", -+ .gpio = { -+ .pin = AK_GPIO_57, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ } -+ }, -+ { -+ .name = "vedio_led", -+ .def_trigger = "none", -+ .gpio = { -+ .pin = AK_GPIO_30, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ } -+ }, -+}; -+ -+static struct ak_led_pdata led_pdata = { -+ .leds = leds, -+ .nr_led = ARRAY_SIZE(leds), -+}; -+ -+ -+/* unused GPIO number for the machine board is left*/ -+static unsigned int ak39_custom_gpiopin[] = { -+ AK_GPIO_4, -+ AK_GPIO_5, -+}; -+ -+static struct custom_gpio_data ak39_custom_gpios= { -+ .gpiopin = ak39_custom_gpiopin, -+ .ngpiopin = ARRAY_SIZE(ak39_custom_gpiopin), -+}; -+ -+static struct platform_device ak39_custom_gpio = { -+ .name = "akgpio", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak39_custom_gpios, -+ }, -+}; -+ -+ -+ -+/** -+ * GPIO buttons -+ */ -+static struct gpio_keys_button gpio_keys_button[] = { -+ { -+ .code = KEY_0, -+ .type = EV_KEY, -+ .gpio = AK_GPIO_0, -+ .active_low = 1, -+ .wakeup = 1, -+ .debounce_interval = 30, /* ms */ -+ .desc = "boot0", -+ .pullup = AK_PULLUP_ENABLE, -+ .pulldown = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = AK_GPIO_INT_LOWLEVEL, -+ }, -+}; -+ -+static struct akgpio_keys_platform_data gpio_keys_platform_data = { -+ .buttons = gpio_keys_button, -+ .nbuttons = ARRAY_SIZE(gpio_keys_button), -+ .rep = 0, -+}; -+ -+ -+/** -+* @brief ad-key platform device struct -+ we should initialize the correct voltage for each key. -+*/ -+struct multi_addetect multi_det[] = { -+ {.unpress_min = 3220, .unpress_max = 3258, .fixkeys = NULL, .plugdev = PLUGIN_NODEV}, // = null 3251+/-20 -+ {.unpress_min = 3259, .unpress_max = 3300, .fixkeys = NULL, .plugdev = PLUGIN_AC}, // = sddet 3261(+/-30) -+ {.unpress_min = 2230, .unpress_max = 2290, .fixkeys = NULL, .plugdev = PLUGIN_MMC}, // = sddet 2262(+/-30) -+ {.unpress_min = 1700, .unpress_max = 1780, .fixkeys = NULL, .plugdev = PLUGIN_MMC_AC}, // = sddet 1742(+/-30) -+}; -+ -+struct analog_gpio_key ak39_adkey_data = { -+ .desc = "adkey", -+ .interval = 300, /* ms */ -+ .debounce_interval = 20, /* ms */ -+ .addet = multi_det, -+ .naddet = ARRAY_SIZE(multi_det), -+ .nkey = 0, -+ .wakeup = 1, /* enable ad-key wakeup from standby mode */ -+}; -+ -+static struct platform_device ak39_adkey_device = { -+ .name = "ad-keys", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak39_adkey_data, -+ } -+}; -+ -+ -+/*ak39 battery mach info*/ -+static struct ak_bat_mach_info ak39_bat_info = { -+ .gpio_init = ak_gpio_set, -+ .usb_gpio = { -+ .active = -1, -+ .irq = -ENOSYS, -+ .delay = 0, -+ .pindata ={ -+ .pin = -1, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = -1, -+ .int_pol = -1, -+ }, -+ }, -+ -+ .ac_gpio = { -+ .is_detect_mode = BAT_CHARGE_ADC_DETECT, -+ .active = -1, -+ .irq = -1, -+ .delay = 500, -+ .pindata ={ -+ .pin = -1, -+ .pulldown = -1, -+ .pulldown = -1, -+ .value = -1, -+ .dir = -1, -+ .int_pol = -1, -+ }, -+ }, -+ -+ .full_gpio = { -+ .active = -1, -+ .irq = -ENOSYS, -+ .delay = 0, -+ .pindata ={ -+ .pin = -1, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = -1, -+ .int_pol = -1, -+ }, -+ }, -+ -+ .bat_mach_info = { -+ .voltage_sample = 6, // the sample of read voltage -+ .power_on_voltage = 3650, // discharge power on voltage limit -+ .power_on_correct = 64, // mv -+ .charge_min_voltage = 3550, // charge minute voltage (mv) -+ .max_voltage = 4200, // max battery voltage -+ .min_voltage = 3500, // min battery voltage -+ .power_off = poweroff_disable, -+ .full_capacity = 100, // battery full -+ .poweroff_cap = 0, // user read value to power off -+ .low_cap = 5, // user read value to low power warring -+ .recover_cap = 30, -+ .cpower_on_voltage = 3700, // charge power on voltage limit -+ .full_delay = 30, // unit is minute -+ .full_voltage = 4100, -+ }, -+ -+ .bat_adc = { -+ .up_resistance = 10, -+ .dw_resistance = 10, -+ .voltage_correct = 32, // battery correct factor -+ .adc_avdd = 3300, // avdd voltage -+ }, -+ -+}; -+ -+ -+static struct platform_device *ak3910_platform_devices[] __initdata = { -+ &akfha_char_device, -+ &ak39_uart0_device, -+ &ak39_motor0_device, -+ &ak39_motor1_device, -+ &ak39_spi1_device, -+ &ak39_mmc_device, -+ &ak39_sdio_device, -+ &ak39_i2c_device, -+ &ak39_custom_gpio, -+ &ak39_usb_udc_device, -+ &ak39_usb_otg_hcd_device, -+ &anyka_wifi_device, -+ &soc_camera_interface, -+ &ak39_camera_interface, -+ &ak39_ion_device, -+ &ak39_pcm_device, -+ &ak39_codec_device, -+ &ak39_mmx_device, -+ &ak39_mac_device, -+ &ak39_led_pdev, -+ &ak39_gpio_keys_device, -+ &ak39_adkey_device, -+ &ak39_battery_power, -+ &ak39_rtc_device, -+ &ak39_gpio_uart_device, -+}; -+ -+void wdt_enable(void); -+void wdt_keepalive(unsigned int heartbeat); -+ -+static void ak39_restart(char str, const char *cmd) -+{ -+ //ak39_reboot_sys_by_soft(); -+#ifdef CONFIG_AK39_WATCHDOG -+ wdt_enable(); -+ wdt_keepalive(2); -+#endif -+} -+ -+static void __init ak3910_init_machine(void) -+{ -+ adc1_init(); -+ -+ spi_register_board_info(ak39_spi_board_dev, ARRAY_SIZE(ak39_spi_board_dev)); -+ -+ ak39_spi1_device.dev.platform_data = &ak39_spi1_info; -+ -+ ak39_motor0_device.dev.platform_data = &ak39_motor0_pdata; -+ ak39_motor1_device.dev.platform_data = &ak39_motor1_pdata; -+ -+ ak39_mmc_device.dev.platform_data = &mmc_plat_data; -+ ak39_sdio_device.dev.platform_data = &sdio_plat_data; -+ -+ ak39_usb_otg_hcd_device.dev.platform_data = &akotghc_plat_data; -+ ak39_mac_device.dev.platform_data = &ak39_mac_pdata; -+ -+ ak39_led_pdev.dev.platform_data = &led_pdata; -+ ak39_gpio_keys_device.dev.platform_data = &gpio_keys_platform_data; -+ ak39_battery_power.dev.platform_data = &ak39_bat_info; -+ -+ platform_add_devices(ak3910_platform_devices, -+ ARRAY_SIZE(ak3910_platform_devices)); -+ -+ l2_init(); -+ -+ return; -+} -+ -+ -+MACHINE_START(AK39XX, "Aimer39_AK3916_MB_V1.0.0") -+/* Maintainer: */ -+ .atag_offset = 0x100, -+ .fixup = NULL, -+ .map_io = ak39_map_io, -+ .reserve = NULL, -+ .init_irq = ak39_init_irq, -+ .init_machine = ak3910_init_machine, -+ .init_early = NULL, -+ .timer = &ak39_timer, -+ .restart = ak39_restart, -+ -+MACHINE_END -+ -diff --git a/arch/arm/mach-ak39/mach-aimer39_ak3918.c b/arch/arm/mach-ak39/mach-aimer39_ak3918.c -new file mode 100755 -index 00000000..f57f1ef4 ---- /dev/null -+++ b/arch/arm/mach-ak39/mach-aimer39_ak3918.c -@@ -0,0 +1,543 @@ -+/* -+ * 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/platform_device.h> -+#include <linux/irq.h> -+#include <linux/i2c.h> -+#include <linux/i2c-gpio.h> -+ -+#include <plat-anyka/wifi.h> -+#include <plat-anyka/otg-hshcd.h> -+#include <plat-anyka/ak_camera.h> -+#include <plat-anyka/aksensor.h> -+ -+#include <asm/mach/arch.h> -+#include <asm/mach-types.h> -+#include <asm/irq.h> -+ -+#include <plat/l2.h> -+#include <mach/devices.h> -+#include <mach/gpio.h> -+#include <mach-anyka/mac.h> -+#include <mach/ak_codec.h> -+ -+#include <mach/spi.h> -+#include <linux/spi/flash.h> -+#include <linux/spi/spi.h> -+#include <linux/spi/spidev.h> -+#include <plat-anyka/akmci.h> -+#include <plat-anyka/adkey.h> -+ -+#include <mach/leds-gpio.h> -+#include <linux/input.h> -+#include <plat-anyka/gpio_keys.h> -+#include <plat-anyka/bat.h> -+ -+#include <plat-anyka/ak_motor.h> -+#include "cpu.h" -+#include "irq.h" -+#include <mach/adc.h> -+#include <plat-anyka/akgpios.h> -+ -+#define SPI_ONCHIP_CS (0) /*means not need gpio*/ -+static unsigned long ak39_spidev_cs[AKSPI_CS_NUM] = { -+ [AKSPI_ONCHIP_CS] = SPI_ONCHIP_CS, /*gpio 25, spidev0: ak-spiflash*/ -+}; -+ -+struct ak_spi_info ak39_spi1_info = { -+ .pin_cs = ak39_spidev_cs, -+ .num_cs = ARRAY_SIZE(ak39_spidev_cs), -+ .bus_num = AKSPI_BUS_NUM1, -+ .clk_name = "spi1", -+ .mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH, -+ .xfer_mode = AKSPI_XFER_MODE_DMA, -+}; -+ -+static struct flash_platform_data ak39_spiflash_info= { -+ .bus_width = FLASH_BUS_WIDTH_4WIRE | FLASH_BUS_WIDTH_2WIRE | FLASH_BUS_WIDTH_1WIRE, -+ .type = NULL, -+}; -+ -+static struct spi_board_info ak39_spi_board_dev[] = { -+ { -+ .modalias = "ak-spiflash", -+ .bus_num = AKSPI_BUS_NUM1, -+ .chip_select = AKSPI_ONCHIP_CS, -+ .mode = SPI_MODE_0, -+ .max_speed_hz = 20*1000*1000, -+ .platform_data = &ak39_spiflash_info, -+ }, -+}; -+ -+static struct ak_motor_plat_data ak39_motor0_pdata = { -+ .gpio_phase[0] = { -+ .pin = AK_GPIO_37, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[1] = { -+ .pin = AK_GPIO_38, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[2] = { -+ .pin = AK_GPIO_39, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[3] = { -+ .pin = AK_GPIO_40, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ -+ .gpio_hit[0] = { -+ .pin = AK_GPIO_62, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_hit[1] ={ -+ .pin = AK_GPIO_63, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .irq_hit_type[0] = IRQ_TYPE_LEVEL_LOW, -+ .irq_hit_type[1] = IRQ_TYPE_LEVEL_LOW, -+ -+ .angular_speed = 100, /* angle/s */ -+}; -+ -+ -+ -+static struct ak_motor_plat_data ak39_motor1_pdata = { -+ .gpio_phase[0] = { -+ .pin = AK_GPIO_56, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[1] = { -+ .pin = AK_GPIO_58, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[2] = { -+ .pin = AK_GPIO_4, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_phase[3] = { -+ .pin = AK_GPIO_50, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ -+ .gpio_hit[0] = { -+ .pin = AK_GPIO_52, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_hit[1] ={ -+ .pin = AK_GPIO_30, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .irq_hit_type[0] = IRQ_TYPE_LEVEL_LOW, -+ .irq_hit_type[1] = IRQ_TYPE_LEVEL_LOW, -+ -+ .angular_speed = 100, /* angle/s */ -+}; -+ -+ -+/* MMC/SD platform data*/ -+struct ak_mci_platform_data mmc_plat_data = { -+ .irq_cd_type = IRQ_TYPE_LEVEL_LOW, -+ .detect_mode = AKMCI_DETECT_MODE_GPIO, -+ .xfer_mode = AKMCI_XFER_L2DMA, -+ .mci_mode = MCI_MODE_MMC_SD, -+ .max_speed_hz = 25*1000*1000, -+ .gpio_init = ak_gpio_set, -+ .gpio_cd = { -+ .pin = AK_GPIO_29, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_wp = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = AK_PULLUP_ENABLE, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ } -+}; -+ -+/* akwifi platform data */ -+struct akwifi_platform_data akwifi_pdata = { -+ .gpio_init = ak_gpio_set, -+ .gpio_on = { -+ .pin = AK_GPIO_55, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_off = { -+ .pin = AK_GPIO_55, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .power_on_delay = 2000, -+ .power_off_delay = 0, -+}; -+ -+struct platform_device anyka_wifi_device = { -+ .name = "anyka-wifi", -+ .id = -1, -+ .dev = { -+ .platform_data = &akwifi_pdata, -+ }, -+}; -+ -+static struct akotghc_usb_platform_data akotghc_plat_data = { -+ .gpio_init = ak_gpio_set, -+ .gpio_pwr_on = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_pwr_off = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .switch_onboard = { -+ .pin = -1, -+ }, -+ .switch_extport = { -+ .pin = -1, -+ }, -+}; -+ -+static struct ak_mac_data ak39_mac_pdata = { -+ .gpio_init = ak_gpio_set, -+ .pwr_gpio = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .phy_rst_gpio = { -+ .pin = AK_GPIO_53, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+}; -+ -+ -+/** -+* @brief ak pcm device struct -+ hp and spk can identify by GPIO or AD. -+ wo can initialize it in this struct. -+* @author dengzhou -+* @date 2012-07-19 -+*/ -+struct ak39_codec_platform_data ak39_codec_pdata = -+{ -+ .hpdet_gpio = -+ { -+ .pin = AK_GPIO_7, -+ .dir = AK_GPIO_DIR_INPUT, -+ .pullup = AK_PULLUP_DISABLE, -+ .pulldown = -1, -+ .value = -1, -+ .int_pol = -1, -+ }, -+ .spk_down_gpio = -+ { -+ .pin = AK_GPIO_3, //AK_GPIO_16, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .pullup = -1, -+ .pulldown = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .int_pol = -1, -+ }, -+ .hpmute_gpio = -+ { -+ .pin = INVALID_GPIO, //AK_GPIO_29, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .pullup = -1, -+ .pulldown = -1, -+ -+ .value = AK_GPIO_OUT_LOW, -+ .int_pol = -1, -+ }, -+ -+ .hp_on_value = AK_GPIO_OUT_LOW, -+ .hpdet_irq = IRQ_GPIO_7, -+ .bIsHPmuteUsed = 0, -+ .hp_mute_enable_value = AK_GPIO_OUT_HIGH, -+ .bIsMetalfixed = 0, -+ .boutput_only = 1, -+}; -+ -+struct resource ak39_codec_resources[] = { -+ [0] = { -+ .start = 0x08000000, -+ .end = 0x0800FFFF, -+ .flags = (int)IORESOURCE_MEM, -+ .name = "akpcm_AnalogCtrlRegs", -+ }, -+ [1] = { -+ .start = 0x20110000, -+ .end = 0x2011800F, -+ .flags = (int)IORESOURCE_MEM, -+ .name = "akpcm_ADC2ModeCfgRegs", -+ }, -+}; -+ -+ -+struct platform_device ak39_codec_device = { -+ .name = "ak39-codec", -+ .id = -1, -+ .resource = ak39_codec_resources, -+ .num_resources = ARRAY_SIZE(ak39_codec_resources), -+ .dev = { -+ .platform_data = &ak39_codec_pdata, -+ }, -+}; -+ -+ -+/* camera platform data */ -+static struct i2c_board_info ak_camara_devices[] = { -+ { -+ I2C_BOARD_INFO("aksensor", 0x1), -+ }, -+}; -+ -+static struct aksensor_camera_info ak_soc_camera_info = { -+ .buswidth = SOCAM_DATAWIDTH_8, -+ .pin_avdd = INVALID_GPIO, -+ .pin_power = AK_GPIO_48, //initialize GPIO for the power of camera. -+ .pin_reset = AK_GPIO_51, //initialize GPIO for reset of camera. -+ .link = { -+ .bus_id = 39, -+ .power = NULL, -+ .board_info = &ak_camara_devices[0], -+ .i2c_adapter_id = 0, -+ .priv = &ak_soc_camera_info, -+ } -+}; -+ -+/* fake device for soc_camera subsystem */ -+static struct platform_device soc_camera_interface = { -+ .name = "soc-camera-pdrv", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak_soc_camera_info.link, -+ } -+}; -+ -+/* Set LED parameter and initialis status */ -+static struct ak_led_data leds[] = { -+ { -+ .name = "wps_led", -+ .def_trigger = "none", -+ .gpio = { -+ .pin = AK_GPIO_57, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ } -+ }, -+}; -+ -+static struct ak_led_pdata led_pdata = { -+ .leds = leds, -+ .nr_led = ARRAY_SIZE(leds), -+}; -+ -+ -+/* unused GPIO number for the machine board is left*/ -+static unsigned int ak39_custom_gpiopin[] = { -+ AK_GPIO_5, -+ AK_GPIO_61, -+}; -+ -+static struct custom_gpio_data ak39_custom_gpios= { -+ .gpiopin = ak39_custom_gpiopin, -+ .ngpiopin = ARRAY_SIZE(ak39_custom_gpiopin), -+}; -+ -+static struct platform_device ak39_custom_gpio = { -+ .name = "akgpio", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak39_custom_gpios, -+ }, -+}; -+ -+ -+/** -+ * GPIO buttons -+ */ -+static struct gpio_keys_button gpio_keys_button[] = { -+ { -+ .code = KEY_0, -+ .type = EV_KEY, -+ .gpio = AK_GPIO_0, -+ .active_low = 1, -+ .wakeup = 1, -+ .debounce_interval = 30, /* ms */ -+ .desc = "boot0", -+ .pullup = AK_PULLUP_ENABLE, -+ .pulldown = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = AK_GPIO_INT_LOWLEVEL, -+ }, -+}; -+ -+static struct akgpio_keys_platform_data gpio_keys_platform_data = { -+ .buttons = gpio_keys_button, -+ .nbuttons = ARRAY_SIZE(gpio_keys_button), -+ .rep = 0, -+}; -+ -+ -+static struct platform_device *ak3918_platform_devices[] __initdata = { -+ &akfha_char_device, -+ &ak39_uart0_device, -+ &ak39_motor0_device, -+ &ak39_motor1_device, -+ &ak39_spi1_device, -+ &ak39_mmc_device, -+ &ak39_i2c_device, -+ &ak39_custom_gpio, -+ &ak39_usb_udc_device, -+ &ak39_usb_otg_hcd_device, -+ &anyka_wifi_device, -+ &soc_camera_interface, -+ &ak39_camera_interface, -+ &ak39_ion_device, -+ &ak39_pcm_device, -+ &ak39_codec_device, -+ &ak39_mmx_device, -+ &ak39_mac_device, -+ &ak39_led_pdev, -+ &ak39_gpio_keys_device, -+ &ak39_rtc_device, -+}; -+ -+void wdt_enable(void); -+void wdt_keepalive(unsigned int heartbeat); -+ -+static void ak39_restart(char str, const char *cmd) -+{ -+ //ak39_reboot_sys_by_soft(); -+#ifdef CONFIG_AK39_WATCHDOG -+ wdt_enable(); -+ wdt_keepalive(2); -+#endif -+} -+ -+static void __init ak3918_init_machine(void) -+{ -+ adc1_init(); -+ -+ spi_register_board_info(ak39_spi_board_dev, ARRAY_SIZE(ak39_spi_board_dev)); -+ -+ ak39_spi1_device.dev.platform_data = &ak39_spi1_info; -+ -+ ak39_motor0_device.dev.platform_data = &ak39_motor0_pdata; -+ ak39_motor1_device.dev.platform_data = &ak39_motor1_pdata; -+ -+ ak39_mmc_device.dev.platform_data = &mmc_plat_data; -+ -+ ak39_usb_otg_hcd_device.dev.platform_data = &akotghc_plat_data; -+ ak39_mac_device.dev.platform_data = &ak39_mac_pdata; -+ -+ ak39_led_pdev.dev.platform_data = &led_pdata; -+ ak39_gpio_keys_device.dev.platform_data = &gpio_keys_platform_data; -+ -+ platform_add_devices(ak3918_platform_devices, -+ ARRAY_SIZE(ak3918_platform_devices)); -+ -+ l2_init(); -+ -+ return; -+} -+ -+ -+MACHINE_START(AK39XX, "Aimer39_AK3918_MB_V1.0.0") -+/* Maintainer: */ -+ .atag_offset = 0x100, -+ .fixup = NULL, -+ .map_io = ak39_map_io, -+ .reserve = NULL, -+ .init_irq = ak39_init_irq, -+ .init_machine = ak3918_init_machine, -+ .init_early = NULL, -+ .timer = &ak39_timer, -+ .restart = ak39_restart, -+ -+MACHINE_END -+ -diff --git a/arch/arm/mach-ak39/mach-sdk3910.c b/arch/arm/mach-ak39/mach-sdk3910.c -new file mode 100755 -index 00000000..5bc67563 ---- /dev/null -+++ b/arch/arm/mach-ak39/mach-sdk3910.c -@@ -0,0 +1,442 @@ -+/* -+ * 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/platform_device.h> -+#include <linux/irq.h> -+#include <linux/i2c.h> -+#include <linux/i2c-gpio.h> -+ -+#include <plat-anyka/otg-hshcd.h> -+#include <plat-anyka/ak_camera.h> -+#include <plat-anyka/aksensor.h> -+ -+#include <asm/mach/arch.h> -+#include <asm/mach-types.h> -+#include <asm/irq.h> -+ -+#include <plat/l2.h> -+#include <mach/devices.h> -+#include <mach/gpio.h> -+#include <mach-anyka/mac.h> -+#include <mach/ak_codec.h> -+ -+#include <mach/spi.h> -+#include <linux/spi/flash.h> -+#include <linux/spi/spi.h> -+#include <linux/spi/spidev.h> -+#include <plat-anyka/akmci.h> -+#include <plat-anyka/adkey.h> -+ -+#include <mach/leds-gpio.h> -+#include <linux/input.h> -+#include <plat-anyka/gpio_keys.h> -+#include <mach/adc.h> -+ -+#include "cpu.h" -+#include "irq.h" -+ -+ -+#define SPI_ONCHIP_CS (0) /*means not need gpio*/ -+static unsigned long ak39_spidev_cs[AKSPI_CS_NUM] = { -+ [AKSPI_ONCHIP_CS] = SPI_ONCHIP_CS, /*gpio 25, spidev0: ak-spiflash*/ -+}; -+ -+struct ak_spi_info ak39_spi1_info = { -+ .pin_cs = ak39_spidev_cs, -+ .num_cs = ARRAY_SIZE(ak39_spidev_cs), -+ .bus_num = AKSPI_BUS_NUM1, -+ .clk_name = "spi1", -+ .mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH, -+ .xfer_mode = AKSPI_XFER_MODE_DMA, -+}; -+ -+static struct flash_platform_data ak39_spiflash_info= { -+ .bus_width = FLASH_BUS_WIDTH_4WIRE | FLASH_BUS_WIDTH_2WIRE | FLASH_BUS_WIDTH_1WIRE, -+ .type = NULL, -+}; -+ -+static struct spi_board_info ak39_spi_board_dev[] = { -+ { -+ .modalias = "ak-spiflash", -+ .bus_num = AKSPI_BUS_NUM1, -+ .chip_select = AKSPI_ONCHIP_CS, -+ .mode = SPI_MODE_0, -+ .max_speed_hz = 20*1000*1000, -+ .platform_data = &ak39_spiflash_info, -+ }, -+}; -+ -+ -+/* SDIO platform data*/ -+struct ak_mci_platform_data sdio_plat_data = { -+ .irq_cd_type = IRQ_TYPE_LEVEL_LOW, -+ .detect_mode = AKMCI_PLUGIN_ALWAY, -+ .xfer_mode = AKMCI_XFER_L2DMA, -+ .mci_mode = MCI_MODE_SDIO, -+ .gpio_init = ak_gpio_set, -+ .max_speed_hz = 25*1000*1000, -+ .gpio_cd = { -+ .pin = AK_GPIO_18, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_wp = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = AK_PULLUP_ENABLE, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ } -+}; -+ -+/* MMC/SD platform data*/ -+struct ak_mci_platform_data mmc_plat_data = { -+ .irq_cd_type = IRQ_TYPE_LEVEL_LOW, -+ .detect_mode = AKMCI_DETECT_MODE_GPIO, -+ .xfer_mode = AKMCI_XFER_L2DMA, -+ .mci_mode = MCI_MODE_MMC_SD, -+ .gpio_init = ak_gpio_set, -+ .max_speed_hz = 25*1000*1000, -+ .gpio_cd = { -+ .pin = AK_GPIO_30, -+ .pulldown = -1, -+ .pullup = -1, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ }, -+ .gpio_wp = { -+ .pin = -1, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = AK_PULLUP_ENABLE, -+ .value = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = -1, -+ } -+}; -+ -+/* akwifi platform data */ -+struct platform_device anyka_wifi_device = { -+ .name = "anyka-wifi", -+ .id = -1, -+}; -+ -+static struct akotghc_usb_platform_data akotghc_plat_data = { -+ .gpio_init = ak_gpio_set, -+ .gpio_pwr_on = { -+ .pin = AK_GPIO_6, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .gpio_pwr_off = { -+ .pin = AK_GPIO_6, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .switch_onboard = { -+ .pin = -1, -+ }, -+ .switch_extport = { -+ .pin = -1, -+ }, -+}; -+ -+/* MAC platform data */ -+static struct ak_mac_data ak39_mac_pdata = { -+ .gpio_init = ak_gpio_set, -+ .pwr_gpio = { -+ .pin = INVALID_GPIO, -+ .pulldown = AK_PULLDOWN_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_HIGH, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+ .phy_rst_gpio = { -+ .pin = INVALID_GPIO, -+ .pulldown = -1, -+ .pullup = AK_PULLUP_DISABLE, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ }, -+}; -+ -+ -+/** -+* @brief ak pcm device struct -+ hp and spk can identify by GPIO or AD. -+ wo can initialize it in this struct. -+* @author dengzhou -+* @date 2012-07-19 -+*/ -+struct ak39_codec_platform_data ak39_codec_pdata = -+{ -+ .hpdet_gpio = -+ { -+ .pin = AK_GPIO_48, -+ .dir = AK_GPIO_DIR_INPUT, -+ .pullup = -1/*AK_PULLUP_DISABLE*/, -+ .pulldown = AK_PULLDOWN_ENABLE, -+ .value = -1, -+ .int_pol = -1, -+ }, -+ .spk_down_gpio = -+ { -+ .pin = INVALID_GPIO, //AK_GPIO_16, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .pullup = AK_PULLUP_ENABLE, -+ .pulldown = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .int_pol = -1, -+ }, -+ .hpmute_gpio = -+ { -+ .pin = INVALID_GPIO, //AK_GPIO_29, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .pullup = -1, -+ .pulldown = -1, -+ -+ .value = AK_GPIO_OUT_LOW, -+ .int_pol = -1, -+ }, -+ -+ .hp_on_value = AK_GPIO_OUT_LOW, -+ .hpdet_irq = IRQ_GPIO_48, -+ .bIsHPmuteUsed = 0, -+ .hp_mute_enable_value = AK_GPIO_OUT_HIGH, -+ .bIsMetalfixed = 0, -+ .boutput_only = 1, -+}; -+ -+struct resource ak39_codec_resources[] = { -+ [0] = { -+ .start = 0x08000000, -+ .end = 0x0800FFFF, -+ .flags = (int)IORESOURCE_MEM, -+ .name = "akpcm_AnalogCtrlRegs", -+ }, -+ [1] = { -+ .start = 0x20110000, -+ .end = 0x2011800F, -+ .flags = (int)IORESOURCE_MEM, -+ .name = "akpcm_ADC2ModeCfgRegs", -+ }, -+}; -+ -+ -+struct platform_device ak39_codec_device = { -+ .name = "ak39-codec", -+ .id = -1, -+ .resource = ak39_codec_resources, -+ .num_resources = ARRAY_SIZE(ak39_codec_resources), -+ .dev = { -+ .platform_data = &ak39_codec_pdata, -+ }, -+}; -+ -+ -+/* camera platform data */ -+static struct i2c_board_info ak_camara_devices[] = { -+ { -+ I2C_BOARD_INFO("aksensor", 0x1), -+ }, -+}; -+ -+static struct aksensor_camera_info ak_soc_camera_info = { -+ .buswidth = SOCAM_DATAWIDTH_8, -+ .pin_avdd = INVALID_GPIO, -+ .pin_power = AK_GPIO_3, //initialize GPIO for the power of camera. -+ .pin_reset = AK_GPIO_0, //initialize GPIO for reset of camera. -+ .link = { -+ .bus_id = 39, -+ .power = NULL, -+ .board_info = &ak_camara_devices[0], -+ .i2c_adapter_id = 0, -+ .priv = &ak_soc_camera_info, -+ } -+}; -+ -+/* fake device for soc_camera subsystem */ -+static struct platform_device soc_camera_interface = { -+ .name = "soc-camera-pdrv", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak_soc_camera_info.link, -+ } -+}; -+ -+/* Set LED parameter and initialis status */ -+static struct ak_led_data leds[] = { -+#if 0 -+ { -+ .name = "wifi_status", -+ .def_trigger = "none", -+ .gpio = { -+ .pin = AK_GPIO_0, -+ .pulldown = -1, -+// .pullup = AK_PULLUP_DISABLE, -+ .pullup = -1, -+ .value = AK_GPIO_OUT_LOW, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .int_pol = -1, -+ } -+ } -+#endif -+}; -+ -+static struct ak_led_pdata led_pdata = { -+ .leds = leds, -+ .nr_led = ARRAY_SIZE(leds), -+}; -+ -+/** -+ * GPIO buttons -+ */ -+static struct gpio_keys_button gpio_keys_button[] = { -+#if 0 -+ { -+ .code = KEY_0, -+ .type = EV_KEY, -+ .gpio = AK_GPIO_0, -+ .active_low = 1, -+ .wakeup = 1, -+ .debounce_interval = 30, /* ms */ -+ .desc = "boot0", -+ .pullup = AK_PULLUP_ENABLE, -+ .pulldown = -1, -+ .dir = AK_GPIO_DIR_INPUT, -+ .int_pol = AK_GPIO_INT_LOWLEVEL, -+ }, -+#endif -+}; -+ -+static struct akgpio_keys_platform_data gpio_keys_platform_data = { -+ .buttons = gpio_keys_button, -+ .nbuttons = ARRAY_SIZE(gpio_keys_button), -+ .rep = 0, -+}; -+ -+/** -+* @brief ad-key platform device struct -+ we should initialize the correct voltage for each key. -+*/ -+struct adgpio_key adkey[][6] = { -+ // = only ad key -+ {{ .code = KEY_LEFT, .min = 0, .max = 80}, //20+/-40 -+ { .code = KEY_RIGHT, .min = 140, .max = 200}, //174+/-30 -+ { .code = KEY_UP, .min = 400, .max = 480}, //444+/-40 -+ { .code = KEY_DOWN, .min = 620, .max = 720}, //673+/-50 -+ { .code = KEY_OK, .min = 940, .max = 1080}, //980+/-40 -+ { .code = KEY_MENU, .min = 1230, .max = 1350}}, //1308+/-40 -+#if 0 -+ // = key + sd -+ {{ .code = KEY_LEFT, .min = 0, .max = 80}, //20+/-40 -+ { .code = KEY_RIGHT, .min = 140, .max = 200}, //174+/-30 -+ { .code = KEY_UP, .min = 400, .max = 480}, //444+/-40 -+ { .code = KEY_DOWN, .min = 620, .max = 720}, //673+/-50 -+ { .code = KEY_OK, .min = 940, .max = 1080}, //980+/-40 -+ { .code = KEY_MENU, .min = 1230, .max = 1350}}, //1308+/-40 -+#endif -+}; -+ -+struct multi_addetect multi_det[] = { -+ {.unpress_min = 3220, .unpress_max = 3300, .fixkeys = adkey[0], .plugdev = PLUGIN_NODEV}, // = key 3296+/-80 -+// {.unpress_min = 1411, .unpress_max = 1591, .fixkeys = adkey[1], .plugdev = PLUGIN_MMC}, // = key+ sddet 1511+/-80) -+}; -+ -+struct analog_gpio_key ak39_adkey_data = { -+ .desc = "adkey", -+ .interval = 300, -+ .debounce_interval = 20, -+ .addet = multi_det, -+ .naddet = ARRAY_SIZE(multi_det), /*initialize the number of device*/ -+ .nkey = ARRAY_SIZE(adkey[0]), -+ .wakeup = 1, /* initialize key have function of wake up chip. */ -+}; -+ -+static struct platform_device ak39_adkey_device = { -+ .name = "ad-keys", -+ .id = -1, -+ .dev = { -+ .platform_data = &ak39_adkey_data, -+ } -+}; -+ -+static struct platform_device *ak3910_platform_devices[] __initdata = { -+ &akfha_char_device, -+ &ak39_uart0_device, -+ &ak39_uart1_device, -+ &ak39_spi1_device, -+ &ak39_mmc_device, -+ //&ak39_sdio_device, -+ &ak39_i2c_device, -+ &ak39_usb_udc_device, -+ &ak39_usb_otg_hcd_device, -+ &anyka_wifi_device, -+ &soc_camera_interface, -+ &ak39_camera_interface, -+ &ak39_ion_device, -+ &ak39_pcm_device, -+ &ak39_codec_device, -+ &ak39_mmx_device, -+ &ak39_mac_device, -+ &ak39_led_pdev, -+ &ak39_gpio_keys_device, -+ &ak39_adkey_device, -+}; -+ -+static void __init ak3910_init_machine(void) -+{ -+ adc1_init(); -+ -+ spi_register_board_info(ak39_spi_board_dev, ARRAY_SIZE(ak39_spi_board_dev)); -+ -+ ak39_spi1_device.dev.platform_data = &ak39_spi1_info; -+ -+ ak39_mmc_device.dev.platform_data = &mmc_plat_data; -+ //ak39_sdio_device.dev.platform_data = &sdio_plat_data; -+ -+ ak39_usb_otg_hcd_device.dev.platform_data = &akotghc_plat_data; -+ ak39_mac_device.dev.platform_data = &ak39_mac_pdata; -+ -+ ak39_led_pdev.dev.platform_data = &led_pdata; -+ ak39_gpio_keys_device.dev.platform_data = &gpio_keys_platform_data; -+ -+ platform_add_devices(ak3910_platform_devices, -+ ARRAY_SIZE(ak3910_platform_devices)); -+ -+ l2_init(); -+ -+ return; -+} -+ -+ -+MACHINE_START(AK39XX, "SDK3910 Board") -+/* Maintainer: */ -+ .atag_offset = 0x100, -+ .fixup = NULL, -+ .map_io = ak39_map_io, -+ .reserve = NULL, -+ .init_irq = ak39_init_irq, -+ .init_machine = ak3910_init_machine, -+ .init_early = NULL, -+ .timer = &ak39_timer, -+ .restart = NULL, -+ -+MACHINE_END -+ -diff --git a/arch/arm/mach-ak39/pm.c b/arch/arm/mach-ak39/pm.c -new file mode 100644 -index 00000000..329aa9c7 ---- /dev/null -+++ b/arch/arm/mach-ak39/pm.c -@@ -0,0 +1,154 @@ -+/* -+ * linux/arch/arm/mach-ak39/pm.c -+ */ -+ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/suspend.h> -+#include <linux/errno.h> -+#include <linux/time.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/delay.h> -+//#include <linux/anyka_cpufreq.h> -+#include <asm/cacheflush.h> -+#include <plat/l2.h> -+#include <plat/l2_exebuf.h> -+ -+void check_poweroff(void); -+ -+static suspend_state_t target_state; -+ -+#define ak39_pm_debug_init() do { } while(0) -+ -+static int ak39_pm_valid_state(suspend_state_t state) -+{ -+ switch (state) { -+ case PM_SUSPEND_ON: -+ case PM_SUSPEND_STANDBY: -+ case PM_SUSPEND_MEM: -+ return 1; -+ default: -+ return 0; -+ } -+} -+ -+/* -+ * Called after processes are frozen, but before we shutdown devices. -+ */ -+static int ak39_pm_begin(suspend_state_t state) -+{ -+ target_state = state; -+ return 0; -+} -+ -+void L2_LINK(standby) L2FUNC_NAME(standby)(unsigned long param1, -+ unsigned long param2,unsigned long param3, unsigned long param4) -+{ -+ unsigned long val; -+ -+ // invalidate and disable mmu -+ DISABLE_CACHE_MMU(); -+ -+ // check this bit and unitil both are empty -+ while(!((REG32(PHY_RAM_CFG_REG4) & (FIFO_R_EMPTY | FIFO_CMD_EMPTY)) == (FIFO_R_EMPTY | FIFO_CMD_EMPTY))) -+ ; -+ -+ // setup periodic of refresh interval and disable auto-refresh -+ REG32(PHY_RAM_CFG_REG4) &= ~(AUTO_REFRESH_EN); -+ -+ // send all bank precharge -+ DDR2_ENTER_SELFREFRESH(); -+ PM_DELAY(0x10);//at least more than 1 tck -+ -+ // set sdram mode before enter standby -+ val = REG32(0x2000e000); -+ REG32(0x2000e000) |= (0x3 << 0); -+ -+ // disable ram clock -+ REG32(PHY_CLOCK_CTRL_REG) |= RAM_CLOCK_DISABLE; -+ -+ // enter standby -+ REG32(PHY_CLOCK_DIV_REG) |= ENTER_STANDBY; -+ PM_DELAY(0x2000); //at least more than 3 tck only for selfresh -+ -+ // the system is standby ...... -+ -+ // enable ram clock -+ REG32(PHY_CLOCK_CTRL_REG) &= ~RAM_CLOCK_DISABLE; -+ -+ // restore from sdram mode after exit standby -+ REG32(0x2000e000) = val; -+ -+ /* instruction: -+ * PM_DELAY(0x1) = 128.8ns when mem clk = 200M -+ */ -+ PM_DELAY(0x10); // at least more than 1 tck prior exit self refresh -+ -+ // exit DDR2 self-refresch -+ DDR2_EXIT_SELFREFRESH(); -+ -+ // send auto refresh and open odt high -+ DDR2_ENTER_AUTOREFRESH(); -+ -+ // enable auto-refresh -+ REG32(PHY_RAM_CFG_REG4) |= AUTO_REFRESH_EN; -+ PM_DELAY(0x100); -+ -+ // enable ICache & DCache, mmu -+ ENABLE_CACHE_MMU(); -+} -+ -+static int ak39_pm_enter(suspend_state_t state) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ ak39_pm_debug_init(); -+ flush_cache_all(); -+ -+ // change from low to normal mode before enter standby if current is low mode -+ //cpu_freq_suspend_check(); -+ -+ SPECIFIC_L2BUF_EXEC(standby, 0,0,0,0); -+ -+ // check power off -+ check_poweroff(); -+ -+ // restore low mode -+ //cpu_freq_resume_check(); -+ -+ local_irq_restore(flags); -+ return 0; -+} -+ -+/* -+ * Called right prior to thawing processes. -+ */ -+static void ak39_pm_end(void) -+{ -+ target_state = PM_SUSPEND_ON; -+} -+ -+static struct platform_suspend_ops ak39_pm_ops = { -+ .valid = ak39_pm_valid_state, -+ .begin = ak39_pm_begin, -+ .enter = ak39_pm_enter, -+ .end = ak39_pm_end, -+}; -+ -+/* ak39_pm_init -+ * -+ * Attach the power management functions. This should be called -+ * from the board specific initialisation if the board supports -+ * it. -+*/ -+int __init ak39_pm_init(void) -+{ -+ printk("AK39 Power Management, (c) 2010 ANYKA\n"); -+ suspend_set_ops(&ak39_pm_ops); -+ -+ return 0; -+} -+arch_initcall(ak39_pm_init); -+ -diff --git a/arch/arm/mach-ak39/pwm_timer.c b/arch/arm/mach-ak39/pwm_timer.c -new file mode 100644 -index 00000000..25fcc255 ---- /dev/null -+++ b/arch/arm/mach-ak39/pwm_timer.c -@@ -0,0 +1,427 @@ -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/err.h> -+#include <linux/clk.h> -+#include <mach/gpio.h> -+#include <asm/io.h> -+#include <linux/module.h> -+#include <mach/pwm_timer.h> -+#include <mach/irqs.h> -+ -+struct ak_pwm_timer_info -+{ -+ int id; -+ int gpio; -+ int timerirq; -+ u8 __iomem *base; -+ T_GPIO_SHAREPIN_CFG sharepin; -+ int is_reserved; -+}; -+ -+ -+static struct ak_pwm_timer_info pt_init_info[] = { -+ {AK_PWM_TIMER1, AK_GPIO_4, IRQ_TIMER1, AK_PWM1_CTRL, ePIN_AS_PWM1, 1}, -+ {AK_PWM_TIMER2, AK_GPIO_5, IRQ_TIMER2, AK_PWM2_CTRL, ePIN_AS_PWM2, 0}, -+ {AK_PWM_TIMER3, AK_GPIO_6, IRQ_TIMER3, AK_PWM3_CTRL, ePIN_AS_PWM3, 0}, -+ {AK_PWM_TIMER4, AK_GPIO_7, IRQ_TIMER4, AK_PWM4_CTRL, ePIN_AS_PWM4, 0}, -+ {AK_PWM_TIMER5, AK_GPIO_8, IRQ_TIMER5, AK_PWM5_CTRL, ePIN_AS_PWM5, 0}, -+}; -+ -+ -+static DEFINE_MUTEX(timer_lock); -+static struct ak_pwm_timer pwm_timer[AK_PWM_TIMER_CNT]; -+static int is_initilize = 0; -+ -+#define for_each_pwm_timer(i, timer) \ -+ for((i)=0, timer=pwm_timer; i<AK_PWM_TIMER_CNT; i++, timer++) -+ -+ -+static inline int pwm_freq_is_vaild(u32 freq) -+{ -+ return ((freq >= PWM_MIN_FREQ) && (freq < PWM_MAX_FREQ)); -+} -+ -+ -+static inline int id_is_vaild(int id) -+{ -+ return ((id >= AK_PWM_TIMER1) && (id < AK_PWM_TIMER_NR)); -+} -+ -+static inline int timer_is_busy(int id) -+{ -+ return (pwm_timer[id].status == PWM_TIMER_BUSY); -+} -+ -+static inline int timer_is_reserved(int id) -+{ -+ return (pwm_timer[id].status == PWM_TIMER_RESERVED); -+} -+ -+/** -+* @brief set ducy cycle -+* write the value into corresponding regester -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] *pwm -+* @param[in] high -+* @param[in] low -+* @return int -+*/ -+static int ak_pwm_set_duty_cycle(struct ak_pwm_timer *pwm, u16 high, u16 low, u32 pre_div) -+{ -+ u32 regval; -+ REG32(pwm->base + AK_PWM_TIMER_CTRL1) = high << 16 | low; -+ -+ regval = REG32(pwm->base + AK_PWM_TIMER_CTRL2); -+ regval &= ~AK_PWM_TIMER_PRE_DIV_MASK; -+ regval |= AK_PWM_TIMER_PRE_DIV(pre_div); -+ REG32(pwm->base + AK_PWM_TIMER_CTRL2) = regval; -+ -+ return 0; -+} -+ -+ -+/** -+* @brief get current ducy cycle -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] *pwm -+* @param[out] *high -+* @param[out] *low -+* @return int -+*/ -+int ak_pwm_get_duty_cycle(struct ak_pwm_timer *pwm, unsigned short *high, unsigned short *low) -+{ -+ unsigned long regval; -+ -+ regval = __raw_readl(pwm->base + AK_PWM_TIMER_CTRL1); -+ -+ *high = regval >> 16; -+ *low = regval & 0xFFFF; -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_pwm_get_duty_cycle); -+ -+/** -+* @brief ak_pwm_config -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *pwm -+* @param[in] high -+* @param[in] low -+* @return int -+*/ -+int ak_pwm_config(struct ak_pwm_timer *pwm, unsigned short high, unsigned short low, unsigned int freq) -+{ -+ u32 pre_div; -+ BUG_ON(!pwm_freq_is_vaild(freq)); -+ -+ pre_div = (REAL_CRYSTAL_FREQ * (high + 1)+(low + 1))/freq - 1; -+ -+ pwm->pre_div = pre_div; -+ pwm->pwm_hlimit = high; -+ pwm->pwm_llimit = low; -+ -+ return ak_pwm_set_duty_cycle(pwm, high, low, pre_div); -+} -+EXPORT_SYMBOL(ak_pwm_config); -+ -+/** -+* @brief enable corresponding pwm -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] *pwm -+* @return int -+*/ -+int ak_pwm_enable(struct ak_pwm_timer *pwm) -+{ -+ T_GPIO_SHAREPIN_CFG sharepin; -+ -+ sharepin = pt_init_info[pwm->id].sharepin; -+ ak_group_config(sharepin); -+ return 0; -+} -+EXPORT_SYMBOL(ak_pwm_enable); -+ -+ -+/** -+* @brief disable corresponding pwm -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *pwm -+* @return void -+*/ -+void ak_pwm_disable(struct ak_pwm_timer *pwm) -+{ -+ ak_setpin_as_gpio(pwm->pwm_pin); -+} -+EXPORT_SYMBOL(ak_pwm_disable); -+ -+/** -+* @brief initilize the pwm/timer module. -+* @author lixinhai -+* @date 2013-06-9 -+* @return return 0 when success. -+*/ -+static int __init ak_pwm_timer_init(void) -+{ -+ int i; -+ struct ak_pwm_timer *timer; -+ -+ if(is_initilize == 1) -+ return 0; -+ -+ for_each_pwm_timer(i, timer) { -+ timer->id = i; -+ timer->base = pt_init_info[i].base; -+ if(pt_init_info[i].is_reserved == 0) -+ timer->status = PWM_TIMER_UNUSED; -+ else -+ timer->status = PWM_TIMER_RESERVED; -+ } -+ is_initilize = 1; -+ return 0; -+} -+late_initcall(ak_pwm_timer_init); -+ -+ -+/** -+* @brief request a timer. -+* @author lixinhai -+* @param[in] the pwm/timer id -+* @param[in] mode -+* @date 2013-06-9 -+* @return return the ak_pwm_timer handle. -+*/ -+static struct ak_pwm_timer *__pwm_timer_request(int id, u8 mode) -+{ -+ struct ak_pwm_timer *pt; -+ BUG_ON(!id_is_vaild(id)); -+ -+ if(is_initilize == 0) -+ ak_pwm_timer_init(); -+ -+ /*if timer is reserved or busy, request fail.*/ -+ if(timer_is_reserved(id) || timer_is_busy(id)) { -+ printk("pwm[%d] is working now. request fail.\n", id); -+ return NULL; -+ } -+ -+ pt = &pwm_timer[id]; -+ pt->mode = mode; -+ pt->status = PWM_TIMER_BUSY; -+ -+ return pt; -+} -+ -+/** -+* @brief release the timer. -+* @author lixinhai -+* @param[in] ak_pwm_timer pointer. -+* @date 2013-06-9 -+* @return void -+*/ -+static void __pwm_timer_release(struct ak_pwm_timer *pt) -+{ -+ pt->status = PWM_TIMER_UNUSED; -+} -+ -+ -+/** -+* @brief config the timer. -+* @author lixinhai -+* @param[in] ak_pwm_timer pointer -+* @param[in] timer count -+* @param[in] pre div -+* @date 2013-06-9 -+* @return success return 0, otherwise return negative value -+*/ -+int ak_timer_config(struct ak_pwm_timer *timer, u32 cnt, u8 pre_div) -+{ -+ u32 regval; -+ -+ timer->timer_cnt = cnt; -+ timer->pre_div = pre_div; -+ -+ -+ REG32(timer->base + AK_PWM_TIMER_CTRL1) = timer->timer_cnt; -+ -+ REG32(timer->base + AK_PWM_TIMER_CTRL2) = AK_TIMER_TIMEOUT_CLR; -+ -+ regval = AK_PWM_TIMER_PRE_DIV(timer->pre_div) | -+ AK_TIMER_WORK_MODE(timer->mode); -+ -+ REG32(timer->base + AK_PWM_TIMER_CTRL2) |= regval; -+ return 0; -+} -+EXPORT_SYMBOL(ak_timer_config); -+ -+ -+/** -+* @brief enable the timer. -+* @author lixinhai -+* @param[in] ak_pwm_timer pointer -+* @date 2013-06-9 -+* @return success return 0, otherwise return negative value -+*/ -+int ak_timer_enable(struct ak_pwm_timer *timer) -+{ -+ u32 regval; -+ -+ regval = AK_TIMER_FEED_TIMER | AK_PWM_TIMER_EN; -+ REG32(timer->base + AK_PWM_TIMER_CTRL2) |= regval; -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_timer_enable); -+ -+ -+/** -+* @brief enable the timer and wait for timeout. -+* @author lixinhai -+* @param[in] ak_pwm_timer pointer -+* @date 2013-06-9 -+* @return success return 0, otherwise return negative value -+*/ -+int ak_timer_enable_sync(struct ak_pwm_timer *timer) -+{ -+ ak_timer_enable(timer); -+ -+ while(!(REG32(timer->base + AK_PWM_TIMER_CTRL2)&(1<<27))) -+ ; -+ return 0; -+} -+EXPORT_SYMBOL(ak_timer_enable_sync); -+ -+ -+/** -+* @brief disable the timer. -+* @param[in] ak_pwm_timer pointer -+* @author lixinhai -+* @date 2013-06-9 -+* @return void -+*/ -+void ak_timer_disable(struct ak_pwm_timer *timer) -+{ -+ u32 regval; -+ -+ regval = REG32(timer->base + AK_PWM_TIMER_CTRL2); -+ regval &= ~AK_PWM_TIMER_EN; -+ REG32(timer->base + AK_PWM_TIMER_CTRL2) = regval; -+} -+EXPORT_SYMBOL(ak_timer_disable); -+ -+ -+/** -+* @brief request a pwm by pwm_id. -+* @param[in] pwm id -+* @author lixinhai -+* @date 2013-06-9 -+* @return ak_pwm_timer handle. -+*/ -+struct ak_pwm_timer *ak_pwm_request(int pwm_id) -+{ -+ struct ak_pwm_timer *pwm; -+ -+ mutex_lock(&timer_lock); -+ pwm = __pwm_timer_request(pwm_id, AK_PT_MODE_PWM); -+ mutex_unlock(&timer_lock); -+ return pwm; -+} -+EXPORT_SYMBOL(ak_pwm_request); -+ -+ -+/** -+* @brief the timer interrupt handler. -+* @author lixinhai -+* @date 2013-06-9 -+* @return irqreturn_t -+*/ -+static irqreturn_t timer_timeout_irq(int irq, void *dev_id) -+{ -+ struct ak_pwm_timer *timer = dev_id; -+ -+ REG32(timer->base + AK_PWM_TIMER_CTRL2) |= AK_TIMER_TIMEOUT_CLR; -+ timer->timer_cb(timer->timer_priv); -+ -+ return IRQ_HANDLED; -+} -+ -+ -+/** -+* @brief request a timer by timer_id. -+* @param[in] timer id -+* @author lixinhai -+* @date 2013-06-9 -+* @return success return 0, otherwise return negative value -+*/ -+struct ak_pwm_timer *ak_timer_request(int timer_id, bool auto_reload, int (*cb)(void* data)) -+{ -+ int ret; -+ u8 mode; -+ -+ struct ak_pwm_timer *timer; -+ mode = auto_reload ?AK_PT_MODE_TIMER_AUTO_LOAD: -+ AK_PT_MODE_TIMER_ONE_SHOT; -+ -+ mutex_lock(&timer_lock); -+ timer = __pwm_timer_request(timer_id, mode); -+ -+ if(cb != NULL) { -+ timer->timer_cb = cb; -+ -+ timer->timer_irq = pt_init_info[timer_id].timerirq; -+ -+ /*if callback function not NULL, request timer irq.*/ -+ ret = request_irq(timer->timer_irq, timer_timeout_irq, IRQF_DISABLED, "timer", timer); -+ disable_irq(timer->timer_irq); -+ if(ret) { -+ printk("request timer irq fail.\n"); -+ __pwm_timer_release(timer); -+ return NULL; -+ } -+ } -+ -+ mutex_unlock(&timer_lock); -+ return timer; -+} -+EXPORT_SYMBOL(ak_timer_request); -+ -+ -+/** -+* @brief release the pwm. -+* @param[in] ak_pwm_timer pointer -+* @author lixinhai -+* @date 2013-06-9 -+* @return success return 0, otherwise return negative value -+*/ -+void ak_pwm_release(struct ak_pwm_timer *pwm) -+{ -+ -+ mutex_lock(&timer_lock); -+ __pwm_timer_release(pwm); -+ mutex_unlock(&timer_lock); -+} -+EXPORT_SYMBOL(ak_pwm_release); -+ -+ -+/** -+* @brief release the timer. -+* @param[in] ak_pwm_timer pointer -+* @author lixinhai -+* @date 2013-06-9 -+* @return success return 0, otherwise return negative value -+*/ -+void ak_timer_release(struct ak_pwm_timer *timer) -+{ -+ mutex_lock(&timer_lock); -+ free_irq(timer->timer_irq, timer); -+ __pwm_timer_release(timer); -+ mutex_unlock(&timer_lock); -+} -+EXPORT_SYMBOL(ak_timer_release); -+ -+ -diff --git a/arch/arm/mach-ak39/reboot.c b/arch/arm/mach-ak39/reboot.c -new file mode 100644 -index 00000000..4730b726 ---- /dev/null -+++ b/arch/arm/mach-ak39/reboot.c -@@ -0,0 +1,122 @@ -+/* -+ * reboot.c - implement a interface jump to ROM code -+ * -+ * 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/delay.h> -+//#include <mach/regs-gpio.h> -+#include <mach/gpio.h> -+#include <mach/l2cache.h> -+#include <asm/io.h> -+ -+#define DIS_INTERRUPTS (0x00001FFF) -+#define RESET_DEVICE1 (0xE9A70000) -+#define RESET_DEVICE2 (0xBF7F0000) -+#define CLOSE_CLOCK1 (0x0000E9A7) -+#define CLOSE_CLOCK2 (0x0000BF7F) -+#define RESET_MULTI1 (0x003003C8) -+#define RESET_MULTI2 (0x24000000) -+#define RESET_SHARE1 (0x00000203) -+#define RESET_SHARE2 (0x00000001) -+/** -+ * @brief: ak39_jump_to_rom -+ * @author: zhongjunchao -+ * @date: 2011-10-13 -+ * -+ * @note: Invalidate I & D cache and TLBs, and then disable I & D cache and MMU -+ * At last, we jump to ROM -+ */ -+void ak39_jump_to_rom(unsigned long addr) -+{ -+ __asm__ __volatile__( -+ "1: mrc p15, 0, pc, c7, c14, 3\n\t" -+ "bne 1b\n\t" -+ "mov %0, #0x0\n\t" -+ "mcr p15, 0, %0, c8, c7, 0\n\t" -+ "mcr p15, 0, %0, c7, c5, 0\n\t" -+ "mrc p15, 0, %0, c1, c0, 0\n\t" -+ "bic %0, %0, #0x3000\n\t" -+ "bic %0, %0, #0x0005\n\t" -+ "mcr p15, 0, %0, c1, c0, 0\n\t" -+ "mov pc, %1\n\t" -+ : : "r"(0),"r"(addr)); -+} -+EXPORT_SYMBOL(ak39_jump_to_rom); -+ -+/** -+ * @brief: ak39_reboot_sys_by_soft -+ * @author: zhongjunchao -+ * @date: 2011-10-11 -+ * -+ * @note: I jump to 0x0 to reboot our system. -+ * TODO: Now on, the register config only for ak39xx. -+ */ -+void ak39_reboot_sys_by_soft(void) -+{ -+ /* disable some interrupt */ -+ REG32(AK_VA_SYSCTRL + 0x4c) &= ~DIS_INTERRUPTS; -+ printk("After disable some interrupt\n"); -+ -+ /* mask all normal interrupt */ -+ REG32(AK_VA_SYSCTRL + 0x34) = 0x0; -+ printk("After mask all normal interrupt\n"); -+ -+ /* mask all GPIO interrupt */ -+ REG32(AK_GPIO_INT_MASK1) = 0x0; -+ REG32(AK_GPIO_INT_MASK2) = 0x0; -+ printk("After disable all GPIO interrupt\n"); -+ -+ /* reset and close clock except UART1,RAM and L2 FIFO */ -+ REG32(AK_VA_SYSCTRL + 0x0C) |= RESET_DEVICE1; -+ udelay(500); -+ REG32(AK_VA_SYSCTRL + 0x0C) &= ~RESET_DEVICE1; -+ -+ REG32(AK_VA_SYSCTRL + 0x10) |= RESET_DEVICE2; -+ udelay(500); -+ REG32(AK_VA_SYSCTRL + 0x10) &= ~RESET_DEVICE2; -+ -+ REG32(AK_VA_SYSCTRL + 0x0C) |= CLOSE_CLOCK1; -+ REG32(AK_VA_SYSCTRL + 0x10) |= CLOSE_CLOCK2; -+ printk("After reset all device and close clock\n"); -+ -+ /* reset multiple-function control */ -+ REG32(AK_VA_SYSCTRL + 0x58) = RESET_MULTI1; -+ REG32(AK_VA_SYSCTRL + 0x14) = RESET_MULTI2; -+ printk("After reset multiple-function\n"); -+ -+ /* reset share pin control */ -+ REG32(AK_VA_SYSCTRL + 0x78) = RESET_SHARE1; -+ REG32(AK_VA_SYSCTRL + 0x74) = RESET_SHARE2; -+ printk("After reset all share pin\n"); -+ -+ /* reset GPIO interrupt polarity */ -+ REG32(AK_GPIO_INTP1) = 0x0; -+ REG32(AK_GPIO_INTP2) = 0x0; -+ printk("After reset all GPIO int pol\n"); -+ -+ /* reset GPIO direction */ -+ REG32(AK_GPIO_DIR1) = 0x0; -+ REG32(AK_GPIO_DIR2) = 0x0; -+ printk("After reset all GPIO dir\n"); -+ -+ /* reset GPIO pull up/down */ -+ REG32(AK_VA_SYSCTRL + 0x9C) = 0x0; -+ REG32(AK_VA_SYSCTRL + 0xA0) = 0x0; -+ REG32(AK_VA_SYSCTRL + 0xA4) = 0x0; -+ REG32(AK_VA_SYSCTRL + 0xA8) = 0x0; -+ printk("After reset all GPIO PDU\n"); -+ -+ /* disable l2 cache */ -+ l2cache_clean_finish(); -+ l2cache_invalidate(); -+ printk("After disable l2 cache\n"); -+ -+ /* jump to 0x0 anddress */ -+ ak39_jump_to_rom(0x0); -+} -+EXPORT_SYMBOL(ak39_reboot_sys_by_soft); -diff --git a/arch/arm/mach-ak39/reset.c b/arch/arm/mach-ak39/reset.c -new file mode 100755 -index 00000000..7836a0ab ---- /dev/null -+++ b/arch/arm/mach-ak39/reset.c -@@ -0,0 +1,61 @@ -+/* -+ * Copyright (C) anyka 2012 -+ * Wangsheng Gao <gao_wangsheng@anyka.oa> -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <mach/map.h> -+#include <mach/reset.h> -+ -+#undef REG32 -+#define REG32(_reg) (*(volatile unsigned long *)(_reg)) -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief soft reset module -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] which module -+* @param[in] delay millisecond second -+* @return fail or not -+*/ -+int ak39_soft_reset(u32 module) -+{ -+ BUG_ON(module < AK39_SRESET_MMCSD || module > AK39_SRESET_DRAM); -+ -+ REG32(MODULE_RESET_CON1) |= (0x1 << module); -+ mdelay(5); -+ REG32(MODULE_RESET_CON1) &= ~(0x1 << module); -+ return 0; -+} -+EXPORT_SYMBOL(ak39_soft_reset); -+ -+/***** extern call for comm drivers compatible *****/ -+int ak_soft_reset(u32 module) -+{ -+ return ak39_soft_reset(module); -+} -+EXPORT_SYMBOL(ak_soft_reset); -diff --git a/arch/arm/mach-ak39/time.c b/arch/arm/mach-ak39/time.c -new file mode 100755 -index 00000000..b1c4a405 ---- /dev/null -+++ b/arch/arm/mach-ak39/time.c -@@ -0,0 +1,214 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/err.h> -+#include <linux/clk.h> -+ -+#include <asm/io.h> -+#include <asm/mach/time.h> -+ -+#include <mach/map.h> -+ -+ -+#define AK39_TIMER1_CTRL1 (AK_VA_SYSCTRL + 0xB4) -+#define AK39_TIMER1_CTRL2 (AK_VA_SYSCTRL + 0xB8) -+#define AK39_TIMER2_CTRL1 (AK_VA_SYSCTRL + 0xBC) -+#define AK39_TIMER2_CTRL2 (AK_VA_SYSCTRL + 0xC0) -+#define AK39_TIMER3_CTRL1 (AK_VA_SYSCTRL + 0xC4) -+#define AK39_TIMER3_CTRL2 (AK_VA_SYSCTRL + 0xC8) -+#define AK39_TIMER4_CTRL1 (AK_VA_SYSCTRL + 0xCC) -+#define AK39_TIMER4_CTRL2 (AK_VA_SYSCTRL + 0xD0) -+#define AK39_TIMER5_CTRL1 (AK_VA_SYSCTRL + 0xD4) -+#define AK39_TIMER5_CTRL2 (AK_VA_SYSCTRL + 0xD8) -+ -+#define AK39_TIMER_CTRL1 AK39_TIMER1_CTRL1 -+#define AK39_TIMER_CTRL2 AK39_TIMER1_CTRL2 -+#define IRQ_TIMER IRQ_TIMER1 -+ -+#define TIMER_CNT (12000000/HZ) -+#define TIMER_USEC_SHIFT 16 -+#define TIMER_CNT_MASK (0x3F<<26) -+ -+//define timer register bits -+#define TIMER_CLEAR_BIT (1<<30) -+#define TIMER_FEED_BIT (1<<29) -+#define TIMER_ENABLE_BIT (1<<28) -+#define TIMER_STATUS_BIT (1<<27) -+#define TIMER_READ_SEL_BIT (1<<26) -+ -+//define pwm/pwm mode -+#define MODE_AUTO_RELOAD_TIMER 0x0 -+#define MODE_ONE_SHOT_TIMER 0x1 -+#define MODE_PWM 0x2 -+ -+ -+static u_int64_t ghrtick = 0; -+static unsigned long usec_per_tick; /* usec per tick, left shift 16 */ -+ -+/* copy from plat-s3c/time.c -+ * -+ * timer_mask_usec_ticks -+ * -+ * given a clock and divisor, make the value to pass into timer_ticks_to_usec -+ * to scale the ticks into usecs -+*/ -+static inline unsigned long -+timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk) -+{ -+ unsigned long den = pclk / 1000; -+ -+ return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den; -+} -+ -+static inline unsigned long timer_ticks_to_usec(unsigned long ticks) -+{ -+ unsigned long ret; -+ -+ ret = ticks * usec_per_tick; -+ ret += 1 << (TIMER_USEC_SHIFT - 4); -+ -+ return ret >> TIMER_USEC_SHIFT; -+} -+ -+/* -+ * Returns microsecond since last clock interrupt. Note that interrupts -+ * will have been disabled by do_gettimeoffset() -+ * IRQs are disabled before entering here from do_gettimeofday() -+ * -+ * FIXME: this need be checked -+ */ -+static unsigned long ak39_gettimeoffset(void) -+{ -+ unsigned long tdone; -+ unsigned long tcnt; -+ -+ /* work out how many ticks have gone since last timer interrupt */ -+ -+ //select read current count mode -+ tdone = __raw_readl(AK39_TIMER_CTRL2); -+ __raw_writel(tdone | TIMER_READ_SEL_BIT, AK39_TIMER_CTRL2); -+ -+ tcnt = __raw_readl(AK39_TIMER_CTRL1); -+ -+ //recover read mode -+ tdone = __raw_readl(AK39_TIMER_CTRL2); -+ __raw_writel(tdone & (~TIMER_READ_SEL_BIT), AK39_TIMER_CTRL2); -+ -+ tdone = TIMER_CNT - tcnt; -+ -+ if (__raw_readl(AK39_TIMER_CTRL2) & TIMER_STATUS_BIT) { /* Timer1 has generated interrupt, and not clear */ -+ -+ /* Reread timer counter */ -+ //select read current count mode -+ tdone = __raw_readl(AK39_TIMER_CTRL2); -+ __raw_writel(tdone | TIMER_READ_SEL_BIT, AK39_TIMER_CTRL2); -+ -+ tcnt = __raw_readl(AK39_TIMER_CTRL1); -+ -+ //recover read mode -+ tdone = __raw_readl(AK39_TIMER_CTRL2); -+ __raw_writel(tdone & (~TIMER_READ_SEL_BIT), AK39_TIMER_CTRL2); -+ -+ tdone = TIMER_CNT - tcnt; -+ -+ if (tcnt != 0) -+ tdone += TIMER_CNT; -+ } -+ -+ return timer_ticks_to_usec(tdone); -+} -+ -+static inline void ak39_timer_setup(void) -+{ -+ unsigned long regval; -+ -+ /* clear timeout puls, reload */ -+ regval = __raw_readl(AK39_TIMER_CTRL2); -+ __raw_writel(regval | TIMER_CLEAR_BIT, AK39_TIMER_CTRL2); -+} -+ -+/* -+ * IRQ handler for the timer -+ */ -+static irqreturn_t ak39_timer_interrupt(int irq, void *dev_id) -+{ -+ if (__raw_readl(AK39_TIMER_CTRL2) & TIMER_STATUS_BIT) { -+ -+ ghrtick += TIMER_CNT; -+ -+ timer_tick(); -+ -+ ak39_timer_setup(); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+#if 0 -+u_int64_t ak39_gethrtick(void) -+{ -+ unsigned long timecnt = 0; -+ unsigned long tdone; -+ -+ //select read current count mode -+ tdone = __raw_readl(AK39_TIMER_CTRL2); -+ __raw_writel(tdone | TIMER_READ_SEL_BIT, AK39_TIMER_CTRL2); -+ -+ timecnt = __raw_readl(AK39_TIMER_CTRL1); -+ -+ //recover read mode -+ tdone = __raw_readl(AK39_TIMER_CTRL2); -+ __raw_writel(tdone & (~TIMER_READ_SEL_BIT), AK39_TIMER_CTRL2); -+ -+ timecnt &= (~TIMER_CNT_MASK); -+ -+ return (ghrtick + (u_int64_t)(TIMER_CNT-timecnt)); -+} -+#endif -+ -+static struct irqaction ak39_timer_irq = { -+ .name = "timer tick", -+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, -+ .handler = ak39_timer_interrupt, -+}; -+ -+static void __init ak39_timer_init(void) -+{ -+ unsigned long timecnt = TIMER_CNT - 1; -+ -+ usec_per_tick = timer_mask_usec_ticks(1, 12000000); -+ -+ __raw_writel(timecnt, AK39_TIMER_CTRL1); -+ __raw_writel((TIMER_ENABLE_BIT | TIMER_FEED_BIT | (MODE_AUTO_RELOAD_TIMER << 24)), -+ AK39_TIMER_CTRL2); -+ -+ /* setup irq handler for IRQ_TIMER */ -+ setup_irq(IRQ_TIMER, &ak39_timer_irq); -+ ghrtick = 0; -+} -+ -+ -+struct sys_timer ak39_timer = { -+ .init = ak39_timer_init, -+ .offset = ak39_gettimeoffset, -+ //.resume = ak39_timer_setup -+}; -+ -diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile -index bca7e619..37da2cc8 100644 ---- a/arch/arm/mm/Makefile -+++ b/arch/arm/mm/Makefile -@@ -7,6 +7,7 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ - - obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \ - mmap.o pgd.o mmu.o vmregion.o -+obj-$(CONFIG_DEBUG_RODATA) += rodata.o - - ifneq ($(CONFIG_MMU),y) - obj-y += nommu.o -diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c -index 2a8e3805..eaa6847e 100644 ---- a/arch/arm/mm/cache-l2x0.c -+++ b/arch/arm/mm/cache-l2x0.c -@@ -32,8 +32,18 @@ static void __iomem *l2x0_base; - static DEFINE_RAW_SPINLOCK(l2x0_lock); - static u32 l2x0_way_mask; /* Bitmask of active ways */ - static u32 l2x0_size; -+static u32 l2x0_cache_id; -+static unsigned int l2x0_sets; -+static unsigned int l2x0_ways; - static unsigned long sync_reg_offset = L2X0_CACHE_SYNC; - -+static inline bool is_pl310_rev(int rev) -+{ -+ return (l2x0_cache_id & -+ (L2X0_CACHE_ID_PART_MASK | L2X0_CACHE_ID_REV_MASK)) == -+ (L2X0_CACHE_ID_PART_L310 | rev); -+} -+ - struct l2x0_regs l2x0_saved_regs; - - struct l2x0_of_data { -@@ -130,6 +140,23 @@ static void l2x0_cache_sync(void) - raw_spin_unlock_irqrestore(&l2x0_lock, flags); - } - -+#ifdef CONFIG_PL310_ERRATA_727915 -+static void l2x0_for_each_set_way(void __iomem *reg) -+{ -+ int set; -+ int way; -+ unsigned long flags; -+ -+ for (way = 0; way < l2x0_ways; way++) { -+ raw_spin_lock_irqsave(&l2x0_lock, flags); -+ for (set = 0; set < l2x0_sets; set++) -+ writel_relaxed((way << 28) | (set << 5), reg); -+ cache_sync(); -+ raw_spin_unlock_irqrestore(&l2x0_lock, flags); -+ } -+} -+#endif -+ - static void __l2x0_flush_all(void) - { - debug_writel(0x03); -@@ -143,6 +170,13 @@ static void l2x0_flush_all(void) - { - unsigned long flags; - -+#ifdef CONFIG_PL310_ERRATA_727915 -+ if (is_pl310_rev(REV_PL310_R2P0)) { -+ l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_INV_LINE_IDX); -+ return; -+ } -+#endif -+ - /* clean all ways */ - raw_spin_lock_irqsave(&l2x0_lock, flags); - __l2x0_flush_all(); -@@ -153,11 +187,20 @@ static void l2x0_clean_all(void) - { - unsigned long flags; - -+#ifdef CONFIG_PL310_ERRATA_727915 -+ if (is_pl310_rev(REV_PL310_R2P0)) { -+ l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_LINE_IDX); -+ return; -+ } -+#endif -+ - /* clean all ways */ - raw_spin_lock_irqsave(&l2x0_lock, flags); -+ debug_writel(0x03); - writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); - cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); - cache_sync(); -+ debug_writel(0x00); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); - } - -@@ -309,26 +352,24 @@ static void l2x0_unlock(u32 cache_id) - void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) - { - u32 aux; -- u32 cache_id; - u32 way_size = 0; -- int ways; - const char *type; - - l2x0_base = base; - -- cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); -+ l2x0_cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); - aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); - - aux &= aux_mask; - aux |= aux_val; - - /* Determine the number of ways */ -- switch (cache_id & L2X0_CACHE_ID_PART_MASK) { -+ switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK) { - case L2X0_CACHE_ID_PART_L310: - if (aux & (1 << 16)) -- ways = 16; -+ l2x0_ways = 16; - else -- ways = 8; -+ l2x0_ways = 8; - type = "L310"; - #ifdef CONFIG_PL310_ERRATA_753970 - /* Unmapped register. */ -@@ -337,24 +378,25 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) - outer_cache.set_debug = pl310_set_debug; - break; - case L2X0_CACHE_ID_PART_L210: -- ways = (aux >> 13) & 0xf; -+ l2x0_ways = (aux >> 13) & 0xf; - type = "L210"; - break; - default: - /* Assume unknown chips have 8 ways */ -- ways = 8; -+ l2x0_ways = 8; - type = "L2x0 series"; - break; - } - -- l2x0_way_mask = (1 << ways) - 1; -+ l2x0_way_mask = (1 << l2x0_ways) - 1; - - /* - * L2 cache Size = Way size * Number of ways - */ - way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17; -- way_size = 1 << (way_size + 3); -- l2x0_size = ways * way_size * SZ_1K; -+ way_size = SZ_1K << (way_size + 3); -+ l2x0_size = l2x0_ways * way_size; -+ l2x0_sets = way_size / CACHE_LINE_SIZE; - - /* - * Check if l2x0 controller is already enabled. -@@ -363,7 +405,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) - */ - if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) { - /* Make sure that I&D is not locked down when starting */ -- l2x0_unlock(cache_id); -+ l2x0_unlock(l2x0_cache_id); - - /* l2x0 controller is disabled */ - writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); -@@ -386,7 +428,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) - - printk(KERN_INFO "%s cache controller enabled\n", type); - printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", -- ways, cache_id, aux, l2x0_size); -+ l2x0_ways, l2x0_cache_id, aux, l2x0_size); - } - - #ifdef CONFIG_OF -diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S -index 74c2e5a3..2edb6f67 100644 ---- a/arch/arm/mm/cache-v6.S -+++ b/arch/arm/mm/cache-v6.S -@@ -272,6 +272,11 @@ v6_dma_clean_range: - * - end - virtual end address of region - */ - ENTRY(v6_dma_flush_range) -+#ifdef CONFIG_CACHE_FLUSH_RANGE_LIMIT -+ sub r2, r1, r0 -+ cmp r2, #CONFIG_CACHE_FLUSH_RANGE_LIMIT -+ bhi v6_dma_flush_dcache_all -+#endif - #ifdef CONFIG_DMA_CACHE_RWFO - ldrb r2, [r0] @ read for ownership - strb r2, [r0] @ write for ownership -@@ -294,6 +299,18 @@ ENTRY(v6_dma_flush_range) - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer - mov pc, lr - -+#ifdef CONFIG_CACHE_FLUSH_RANGE_LIMIT -+v6_dma_flush_dcache_all: -+ mov r0, #0 -+#ifdef HARVARD_CACHE -+ mcr p15, 0, r0, c7, c14, 0 @ D cache clean+invalidate -+#else -+ mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate -+#endif -+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer -+ mov pc, lr -+#endif -+ - /* - * dma_map_area(start, size, dir) - * - start - kernel virtual start address -diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c -index ee9bb363..806cc4f6 100644 ---- a/arch/arm/mm/context.c -+++ b/arch/arm/mm/context.c -@@ -18,30 +18,39 @@ - - static DEFINE_RAW_SPINLOCK(cpu_asid_lock); - unsigned int cpu_last_asid = ASID_FIRST_VERSION; --#ifdef CONFIG_SMP --DEFINE_PER_CPU(struct mm_struct *, current_mm); --#endif - - #ifdef CONFIG_ARM_LPAE --#define cpu_set_asid(asid) { \ -- unsigned long ttbl, ttbh; \ -- asm volatile( \ -- " mrrc p15, 0, %0, %1, c2 @ read TTBR0\n" \ -- " mov %1, %2, lsl #(48 - 32) @ set ASID\n" \ -- " mcrr p15, 0, %0, %1, c2 @ set TTBR0\n" \ -- : "=&r" (ttbl), "=&r" (ttbh) \ -- : "r" (asid & ~ASID_MASK)); \ -+void cpu_set_reserved_ttbr0(void) -+{ -+ unsigned long ttbl = __pa(swapper_pg_dir); -+ unsigned long ttbh = 0; -+ -+ /* -+ * Set TTBR0 to swapper_pg_dir which contains only global entries. The -+ * ASID is set to 0. -+ */ -+ asm volatile( -+ " mcrr p15, 0, %0, %1, c2 @ set TTBR0\n" -+ : -+ : "r" (ttbl), "r" (ttbh)); -+ isb(); - } - #else --#define cpu_set_asid(asid) \ -- asm(" mcr p15, 0, %0, c13, c0, 1\n" : : "r" (asid)) -+void cpu_set_reserved_ttbr0(void) -+{ -+ u32 ttb; -+ /* Copy TTBR1 into TTBR0 */ -+ asm volatile( -+ " mrc p15, 0, %0, c2, c0, 1 @ read TTBR1\n" -+ " mcr p15, 0, %0, c2, c0, 0 @ set TTBR0\n" -+ : "=r" (ttb)); -+ isb(); -+} - #endif - - /* - * We fork()ed a process, and we need a new context for the child -- * to run in. We reserve version 0 for initial tasks so we will -- * always allocate an ASID. The ASID 0 is reserved for the TTBR -- * register changing sequence. -+ * to run in. - */ - void __init_new_context(struct task_struct *tsk, struct mm_struct *mm) - { -@@ -51,9 +60,7 @@ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm) - - static void flush_context(void) - { -- /* set the reserved ASID before flushing the TLB */ -- cpu_set_asid(0); -- isb(); -+ cpu_set_reserved_ttbr0(); - local_flush_tlb_all(); - if (icache_is_vivt_asid_tagged()) { - __flush_icache_all(); -@@ -98,14 +105,7 @@ static void reset_context(void *info) - { - unsigned int asid; - unsigned int cpu = smp_processor_id(); -- struct mm_struct *mm = per_cpu(current_mm, cpu); -- -- /* -- * Check if a current_mm was set on this CPU as it might still -- * be in the early booting stages and using the reserved ASID. -- */ -- if (!mm) -- return; -+ struct mm_struct *mm = current->active_mm; - - smp_rmb(); - asid = cpu_last_asid + cpu + 1; -@@ -114,8 +114,7 @@ static void reset_context(void *info) - set_mm_context(mm, asid); - - /* set the new ASID */ -- cpu_set_asid(mm->context.id); -- isb(); -+ cpu_switch_mm(mm->pgd, mm); - } - - #else -diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c -index 5df54924..a2cf87d7 100644 ---- a/arch/arm/mm/mmu.c -+++ b/arch/arm/mm/mmu.c -@@ -563,11 +563,25 @@ static void __init *early_alloc(unsigned long sz) - return early_alloc_aligned(sz, sz); - } - --static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot) -+static pte_t * __init early_pte_alloc(pmd_t *pmd) -+{ -+ if (pmd_none(*pmd) || pmd_bad(*pmd)) -+ return early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); -+ return pmd_page_vaddr(*pmd); -+} -+ -+static void __init early_pte_install(pmd_t *pmd, pte_t *pte, unsigned long prot) -+{ -+ __pmd_populate(pmd, __pa(pte), prot); -+ BUG_ON(pmd_bad(*pmd)); -+} -+ -+static pte_t * __init early_pte_alloc_and_install(pmd_t *pmd, -+ unsigned long addr, unsigned long prot) - { - if (pmd_none(*pmd)) { -- pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); -- __pmd_populate(pmd, __pa(pte), prot); -+ pte_t *pte = early_pte_alloc(pmd); -+ early_pte_install(pmd, pte, prot); - } - BUG_ON(pmd_bad(*pmd)); - return pte_offset_kernel(pmd, addr); -@@ -577,16 +591,23 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, - unsigned long end, unsigned long pfn, - const struct mem_type *type) - { -- pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1); -+ pte_t *start_pte = early_pte_alloc(pmd); -+ pte_t *pte = start_pte + pte_index(addr); -+ -+ /* If replacing a section mapping, the whole section must be replaced */ -+ BUG_ON(pmd_bad(*pmd) && ((addr | end) & ~PMD_MASK)); -+ - do { - set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0); - pfn++; - } while (pte++, addr += PAGE_SIZE, addr != end); -+ early_pte_install(pmd, start_pte, type->prot_l1); - } - - static void __init alloc_init_section(pud_t *pud, unsigned long addr, - unsigned long end, phys_addr_t phys, -- const struct mem_type *type) -+ const struct mem_type *type, -+ bool force_pages) - { - pmd_t *pmd = pmd_offset(pud, addr); - -@@ -596,7 +617,7 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr, - * L1 entries, whereas PGDs refer to a group of L1 entries making - * up one logical pointer to an L2 table. - */ -- if (((addr | end | phys) & ~SECTION_MASK) == 0) { -+ if (((addr | end | phys) & ~SECTION_MASK) == 0 && !force_pages) { - pmd_t *p = pmd; - - #ifndef CONFIG_ARM_LPAE -@@ -620,14 +641,15 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr, - } - - static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, -- unsigned long end, unsigned long phys, const struct mem_type *type) -+ unsigned long end, unsigned long phys, const struct mem_type *type, -+ bool force_pages) - { - pud_t *pud = pud_offset(pgd, addr); - unsigned long next; - - do { - next = pud_addr_end(addr, end); -- alloc_init_section(pud, addr, next, phys, type); -+ alloc_init_section(pud, addr, next, phys, type, force_pages); - phys += next - addr; - } while (pud++, addr = next, addr != end); - } -@@ -701,7 +723,7 @@ static void __init create_36bit_mapping(struct map_desc *md, - * offsets, and we take full advantage of sections and - * supersections. - */ --static void __init create_mapping(struct map_desc *md) -+static void __init create_mapping(struct map_desc *md, bool force_pages) - { - unsigned long addr, length, end; - phys_addr_t phys; -@@ -751,7 +773,7 @@ static void __init create_mapping(struct map_desc *md) - do { - unsigned long next = pgd_addr_end(addr, end); - -- alloc_init_pud(pgd, addr, next, phys, type); -+ alloc_init_pud(pgd, addr, next, phys, type, force_pages); - - phys += next - addr; - addr = next; -@@ -772,7 +794,7 @@ void __init iotable_init(struct map_desc *io_desc, int nr) - vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm)); - - for (md = io_desc; nr; md++, nr--) { -- create_mapping(md); -+ create_mapping(md, false); - vm->addr = (void *)(md->virtual & PAGE_MASK); - vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); - vm->phys_addr = __pfn_to_phys(md->pfn); -@@ -1124,12 +1146,12 @@ static void __init devicemaps_init(struct machine_desc *mdesc) - map.virtual = 0xffff0000; - map.length = PAGE_SIZE; - map.type = MT_HIGH_VECTORS; -- create_mapping(&map); -+ create_mapping(&map, false); - - if (!vectors_high()) { - map.virtual = 0; - map.type = MT_LOW_VECTORS; -- create_mapping(&map); -+ create_mapping(&map, false); - } - - /* -@@ -1152,20 +1174,23 @@ static void __init devicemaps_init(struct machine_desc *mdesc) - static void __init kmap_init(void) - { - #ifdef CONFIG_HIGHMEM -- pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE), -+ pkmap_page_table = early_pte_alloc_and_install(pmd_off_k(PKMAP_BASE), - PKMAP_BASE, _PAGE_KERNEL_TABLE); - #endif - } - -+ - static void __init map_lowmem(void) - { - struct memblock_region *reg; -+ phys_addr_t start; -+ phys_addr_t end; -+ struct map_desc map; - - /* Map all the lowmem memory banks. */ - for_each_memblock(memory, reg) { -- phys_addr_t start = reg->base; -- phys_addr_t end = start + reg->size; -- struct map_desc map; -+ start = reg->base; -+ end = start + reg->size; - - if (end > lowmem_limit) - end = lowmem_limit; -@@ -1177,8 +1202,20 @@ static void __init map_lowmem(void) - map.length = end - start; - map.type = MT_MEMORY; - -- create_mapping(&map); -+ create_mapping(&map, false); - } -+ -+#ifdef CONFIG_DEBUG_RODATA -+ start = __pa(_stext) & PMD_MASK; -+ end = ALIGN(__pa(__end_rodata), PMD_SIZE); -+ -+ map.pfn = __phys_to_pfn(start); -+ map.virtual = __phys_to_virt(start); -+ map.length = end - start; -+ map.type = MT_MEMORY; -+ -+ create_mapping(&map, true); -+#endif - } - - /* -diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S -index 3a4b3e7b..42ac069c 100644 ---- a/arch/arm/mm/proc-v7-2level.S -+++ b/arch/arm/mm/proc-v7-2level.S -@@ -46,18 +46,13 @@ ENTRY(cpu_v7_switch_mm) - #ifdef CONFIG_ARM_ERRATA_430973 - mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB - #endif --#ifdef CONFIG_ARM_ERRATA_754322 -- dsb --#endif -- mcr p15, 0, r2, c13, c0, 1 @ set reserved context ID -- isb --1: mcr p15, 0, r0, c2, c0, 0 @ set TTB 0 -- isb - #ifdef CONFIG_ARM_ERRATA_754322 - dsb - #endif - mcr p15, 0, r1, c13, c0, 1 @ set context ID - isb -+ mcr p15, 0, r0, c2, c0, 0 @ set TTB 0 -+ isb - #endif - mov pc, lr - ENDPROC(cpu_v7_switch_mm) -diff --git a/arch/arm/mm/rodata.c b/arch/arm/mm/rodata.c -new file mode 100644 -index 00000000..9a8eb841 ---- /dev/null -+++ b/arch/arm/mm/rodata.c -@@ -0,0 +1,159 @@ -+/* -+ * linux/arch/arm/mm/rodata.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * Author: Colin Cross <ccross@android.com> -+ * -+ * Based on x86 implementation in arch/x86/mm/init_32.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/mm.h> -+#include <linux/module.h> -+ -+#include <asm/cache.h> -+#include <asm/pgtable.h> -+#include <asm/rodata.h> -+#include <asm/sections.h> -+#include <asm/tlbflush.h> -+ -+#include "mm.h" -+ -+static int kernel_set_to_readonly __read_mostly; -+ -+#ifdef CONFIG_DEBUG_RODATA_TEST -+static const int rodata_test_data = 0xC3; -+ -+static noinline void rodata_test(void) -+{ -+ int result; -+ -+ pr_info("%s: attempting to write to read-only section:\n", __func__); -+ -+ if (*(volatile int *)&rodata_test_data != 0xC3) { -+ pr_err("read only data changed before test\n"); -+ return; -+ } -+ -+ /* -+ * Attempt to to write to rodata_test_data, trapping the expected -+ * data abort. If the trap executed, result will be 1. If it didn't, -+ * result will be 0xFF. -+ */ -+ asm volatile( -+ "0: str %[zero], [%[rodata_test_data]]\n" -+ " mov %[result], #0xFF\n" -+ " b 2f\n" -+ "1: mov %[result], #1\n" -+ "2:\n" -+ -+ /* Exception fixup - if store at label 0 faults, jumps to 1 */ -+ ".pushsection __ex_table, \"a\"\n" -+ " .long 0b, 1b\n" -+ ".popsection\n" -+ -+ : [result] "=r" (result) -+ : [rodata_test_data] "r" (&rodata_test_data), [zero] "r" (0) -+ : "memory" -+ ); -+ -+ if (result == 1) -+ pr_info("write to read-only section trapped, success\n"); -+ else -+ pr_err("write to read-only section NOT trapped, test failed\n"); -+ -+ if (*(volatile int *)&rodata_test_data != 0xC3) -+ pr_err("read only data changed during write\n"); -+} -+#else -+static inline void rodata_test(void) { } -+#endif -+ -+static int set_page_attributes(unsigned long virt, int numpages, -+ pte_t (*f)(pte_t)) -+{ -+ pmd_t *pmd; -+ pte_t *pte; -+ unsigned long start = virt; -+ unsigned long end = virt + (numpages << PAGE_SHIFT); -+ unsigned long pmd_end; -+ -+ while (virt < end) { -+ pmd = pmd_off_k(virt); -+ pmd_end = min(ALIGN(virt + 1, PMD_SIZE), end); -+ -+ if ((pmd_val(*pmd) & PMD_TYPE_MASK) != PMD_TYPE_TABLE) { -+ pr_err("%s: pmd %p=%08lx for %08lx not page table\n", -+ __func__, pmd, pmd_val(*pmd), virt); -+ virt = pmd_end; -+ continue; -+ } -+ -+ while (virt < pmd_end) { -+ pte = pte_offset_kernel(pmd, virt); -+ set_pte_ext(pte, f(*pte), 0); -+ virt += PAGE_SIZE; -+ } -+ } -+ -+ flush_tlb_kernel_range(start, end); -+ -+ return 0; -+} -+ -+int set_memory_ro(unsigned long virt, int numpages) -+{ -+ return set_page_attributes(virt, numpages, pte_wrprotect); -+} -+EXPORT_SYMBOL(set_memory_ro); -+ -+int set_memory_rw(unsigned long virt, int numpages) -+{ -+ return set_page_attributes(virt, numpages, pte_mkwrite); -+} -+EXPORT_SYMBOL(set_memory_rw); -+ -+void set_kernel_text_rw(void) -+{ -+ unsigned long start = PAGE_ALIGN((unsigned long)_text); -+ unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start; -+ -+ if (!kernel_set_to_readonly) -+ return; -+ -+ pr_debug("Set kernel text: %lx - %lx to read-write\n", -+ start, start + size); -+ -+ set_memory_rw(start, size >> PAGE_SHIFT); -+} -+ -+void set_kernel_text_ro(void) -+{ -+ unsigned long start = PAGE_ALIGN((unsigned long)_text); -+ unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start; -+ -+ if (!kernel_set_to_readonly) -+ return; -+ -+ pr_info_once("Write protecting the kernel text section %lx - %lx\n", -+ start, start + size); -+ -+ pr_debug("Set kernel text: %lx - %lx to read only\n", -+ start, start + size); -+ -+ set_memory_ro(start, size >> PAGE_SHIFT); -+} -+ -+void mark_rodata_ro(void) -+{ -+ kernel_set_to_readonly = 1; -+ -+ set_kernel_text_ro(); -+ -+ rodata_test(); -+} -diff --git a/arch/arm/plat-anyka/Kconfig b/arch/arm/plat-anyka/Kconfig -new file mode 100644 -index 00000000..d5539923 ---- /dev/null -+++ b/arch/arm/plat-anyka/Kconfig -@@ -0,0 +1,15 @@ -+# arch/arm/plat-anyka/Kconfig -+# -+# Copyright 2012 Anaka Microelectronics -+# -+# Licensed under GPLv2 -+ -+config PLAT_ANYKA -+ bool -+ depends on ARCH_AK39 -+ default y -+ help -+ Base platform code for ak39xx chips common device -+ -+# low-level serial option nodes -+ -diff --git a/arch/arm/plat-anyka/Makefile b/arch/arm/plat-anyka/Makefile -new file mode 100644 -index 00000000..857eada7 ---- /dev/null -+++ b/arch/arm/plat-anyka/Makefile -@@ -0,0 +1,19 @@ -+# arch/arm/plat-anyka/Makefile -+# -+# Copyright 2012 Anyka Microelectronics -+# -+# Licensed under GPLv2 -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+# Core support for all Anyka SoCs -+ -+obj-y += l2.o -+obj-y += rtc.o -+obj-y += drv_module_lock.o -+obj-y += l2_exebuf.o -+obj-y += notify.o -+obj-y += reg.o -diff --git a/arch/arm/plat-anyka/drv_module_lock.c b/arch/arm/plat-anyka/drv_module_lock.c -new file mode 100755 -index 00000000..39528094 ---- /dev/null -+++ b/arch/arm/plat-anyka/drv_module_lock.c -@@ -0,0 +1,279 @@ -+ -+/** -+ * arch/arm/plat-anyka/drv_module_lock.c -+ */ -+ -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/semaphore.h> -+#include <linux/spinlock.h> -+#include <linux/slab.h> -+#include <plat-anyka/drv_module_lock.h> -+ -+//#define DRV_LOCK_DEBUG -+#ifdef DRV_LOCK_DEBUG -+#define PK(fmt...) printk(const char * fmt,...) -+#endif -+ -+#if defined CONFIG_ARCH_AK39 -+/* the param drv_shpin_lock[i].name indicate different lock */ -+struct ak_drv_module_lock drv_mod_lock[] = { -+ {DRV_MODULE_SDIO,AK_MODULE_LOCK_1, TYPE_LOCK_SEMAPHORE, 0, ePIN_AS_SDIO}, -+ {DRV_MODULE_SPI,AK_MODULE_LOCK_1, TYPE_LOCK_SEMAPHORE, 0, ePIN_AS_SPI1}, -+ -+}; -+#endif -+ -+static void *module_lock_array[AK_MODULE_COUNT] = { 0 }; -+ -+#define GET_DRV_LOCK_INFO(type, table, len, lock_name, lock) \ -+{ \ -+ int i; \ -+ type *drv_lock = table; \ -+ for (i = 0; i < len; i++) { \ -+ if (drv_lock[i].lock_name == lock_name) { \ -+ lock = &drv_lock[i]; \ -+ break; \ -+ } \ -+ } \ -+} -+ -+static void ak_acquire_lock(void **lock_array, -+ E_LOCK_NAME lock_name, E_LOCK_TYPE lock_type, unsigned long *flags) -+{ -+ unsigned long flag; -+ -+ switch(lock_type) { -+ case TYPE_LOCK_MUTEX: -+ mutex_lock((struct mutex *)lock_array[lock_name]); -+ break; -+ case TYPE_LOCK_SEMAPHORE: -+ down((struct semaphore *)lock_array[lock_name]); -+ break; -+ case TYPE_LOCK_SPINLOCK: -+ spin_lock((spinlock_t *)lock_array[lock_name]); -+ break; -+ case TYPE_LOCK_SPINLOCK_IRQ: -+ spin_lock_irqsave((spinlock_t *)lock_array[lock_name], flag); -+ *flags = flag; -+ break; -+ default: -+ BUG(); -+ } -+} -+ -+static void ak_release_lock(void **lock_array, -+ E_LOCK_NAME lock_name, E_LOCK_TYPE lock_type, unsigned long flags) -+{ -+ switch(lock_type) { -+ case TYPE_LOCK_MUTEX: -+ mutex_unlock((struct mutex *)lock_array[lock_name]); -+ break; -+ case TYPE_LOCK_SEMAPHORE: -+ up((struct semaphore *)lock_array[lock_name]); -+ break; -+ case TYPE_LOCK_SPINLOCK: -+ spin_unlock((spinlock_t *)lock_array[lock_name]); -+ break; -+ case TYPE_LOCK_SPINLOCK_IRQ: -+ spin_unlock_irqrestore((spinlock_t *)lock_array[lock_name], flags); -+ break; -+ default: -+ BUG(); -+ } -+} -+ -+static int ak_module_lock(E_DRV_MODULE drv_mod_name, -+ struct ak_drv_module_lock *mod_lock, int len, void **lock_array) -+{ -+ struct ak_drv_module_lock *lock = NULL; -+ GET_DRV_LOCK_INFO(struct ak_drv_module_lock, mod_lock, len, drv_mod_name, lock); -+ if (lock == NULL) -+ return -1; -+ -+ ak_acquire_lock(lock_array, lock->lock_name, lock->lock_type, &lock->flags); -+ ak_group_config(lock->sharepin_cfg); -+ return 0; -+} -+ -+static void ak_module_unlock(E_DRV_MODULE drv_mod_name, -+ struct ak_drv_module_lock *mod_lock, int len, void **lock_array) -+{ -+ struct ak_drv_module_lock *lock = NULL; -+ GET_DRV_LOCK_INFO(struct ak_drv_module_lock, mod_lock, len, drv_mod_name, lock); -+ if (lock == NULL) -+ return; -+ -+ ak_release_lock(lock_array, lock->lock_name, lock->lock_type, lock->flags); -+} -+ -+int ak_drv_module_lock(E_DRV_MODULE drv_mod_name) -+{ -+ return ak_module_lock(drv_mod_name, drv_mod_lock, -+ ARRAY_SIZE(drv_mod_lock), module_lock_array); -+} -+EXPORT_SYMBOL(ak_drv_module_lock); -+ -+void ak_drv_module_unlock(E_DRV_MODULE drv_mod_name) -+{ -+ ak_module_unlock(drv_mod_name, drv_mod_lock, -+ ARRAY_SIZE(drv_mod_lock), module_lock_array); -+} -+EXPORT_SYMBOL(ak_drv_module_unlock); -+ -+ -+static void ak_init_lock_array(void **lock_array, int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++) -+ lock_array[i] = NULL; -+} -+ -+static void ak_init_lock(void **lock_array, E_LOCK_NAME lock_name, E_LOCK_TYPE lock_type) -+{ -+ if (lock_array[lock_name] == NULL) { -+ switch (lock_type) { -+ case TYPE_LOCK_MUTEX: -+ lock_array[lock_name] = kmalloc(sizeof(struct mutex), GFP_KERNEL); -+ mutex_init((struct mutex *)lock_array[lock_name]); -+ break; -+ case TYPE_LOCK_SEMAPHORE: -+ lock_array[lock_name] = kmalloc(sizeof(struct semaphore), GFP_KERNEL); -+ sema_init((struct semaphore *)lock_array[lock_name], 1); -+ break; -+ case TYPE_LOCK_SPINLOCK: -+ case TYPE_LOCK_SPINLOCK_IRQ: -+ lock_array[lock_name] = kmalloc(sizeof(spinlock_t), GFP_KERNEL); -+ spin_lock_init((spinlock_t *)lock_array[lock_name]); -+ break; -+ default: -+ BUG(); -+ } -+ } -+} -+ -+static int ak_init_module_locks(void) -+{ -+ int i, len; -+ -+ if ((len = ARRAY_SIZE(drv_mod_lock)) == 0) -+ return -1; -+ -+ ak_init_lock_array(module_lock_array, AK_MODULE_COUNT); -+ -+ for (i = 0; i < len; i++) { -+ ak_init_lock(module_lock_array, drv_mod_lock[i].lock_name, drv_mod_lock[i].lock_type); -+ drv_mod_lock[i].flags = 0; -+ } -+ -+ return 0; -+} -+ -+ -+/* ************* CONFIG GPIO' SHARE FUNC FOR MACHINE ************ */ -+struct ak_drv_sharepin_lock *shpin_lock = NULL; -+int shpin_lock_count = 0; -+void **shpin_lock_array = NULL; -+ -+/** -+ * ak_set_sharepin_lock_table - get machine sharepin lock table valid callback -+ */ -+void ak_set_sharepin_lock_table( -+ struct ak_drv_sharepin_lock *shpin_lock_table, -+ int count, void **lock_array) -+{ -+ shpin_lock = shpin_lock_table; -+ shpin_lock_count = count; -+ shpin_lock_array = lock_array; -+} -+EXPORT_SYMBOL(ak_set_sharepin_lock_table); -+ -+static int ak_sharepin_lock(E_DRV_MODULE drv_mod_name, -+ struct ak_drv_sharepin_lock *shpin_lock, int len, void **lock_array) -+{ -+ struct ak_drv_sharepin_lock *lock = NULL; -+ GET_DRV_LOCK_INFO(struct ak_drv_sharepin_lock, shpin_lock, len, drv_mod_name, lock); -+ if (lock == NULL) -+ return -1; -+ -+ ak_acquire_lock(lock_array, lock->lock_name, lock->lock_type, &lock->flags); -+ if (lock->config_share_pin != NULL) -+ lock->config_share_pin(); -+ return 0; -+} -+ -+static void ak_sharepin_unlock(E_DRV_MODULE drv_mod_name, -+ struct ak_drv_sharepin_lock *shpin_lock, int len, void **lock_array) -+{ -+ struct ak_drv_sharepin_lock *lock = NULL; -+ GET_DRV_LOCK_INFO(struct ak_drv_sharepin_lock, shpin_lock, len, drv_mod_name, lock); -+ if (lock == NULL) -+ return; -+ -+ ak_release_lock(lock_array, lock->lock_name, lock->lock_type, lock->flags); -+} -+ -+int ak_drv_sharepin_lock(E_DRV_MODULE drv_mod_name) -+{ -+ return ak_sharepin_lock(drv_mod_name, shpin_lock, -+ shpin_lock_count, shpin_lock_array); -+} -+EXPORT_SYMBOL(ak_drv_sharepin_lock); -+ -+void ak_drv_sharepin_unlock(E_DRV_MODULE drv_mod_name) -+{ -+ ak_sharepin_unlock(drv_mod_name, shpin_lock, -+ shpin_lock_count, shpin_lock_array); -+} -+EXPORT_SYMBOL(ak_drv_sharepin_unlock); -+ -+ -+/* Brief: Init sharepin locks for drivers module -+ * param: void -+ * ret: -+ * 0: if acquire lock successed; -+ * <0: indicate the Board or products being not sharepin for mutual drivers -+ */ -+static int ak_init_sharepin_locks(void) -+{ -+ int i; -+ -+ if (shpin_lock_count == 0) -+ return -1; -+ -+ ak_init_lock_array(shpin_lock_array, AK_MODULE_COUNT); -+ -+ for (i = 0; i < shpin_lock_count; i++) { -+ ak_init_lock(shpin_lock_array, shpin_lock[i].lock_name, shpin_lock[i].lock_type); -+ shpin_lock[i].flags = 0; -+ } -+ -+ return 0; -+} -+ -+ -+void ak_drv_module_protect(E_DRV_MODULE drv_mod_name) -+{ -+ ak_drv_module_lock(drv_mod_name); -+ ak_drv_sharepin_lock(drv_mod_name); -+} -+EXPORT_SYMBOL(ak_drv_module_protect); -+ -+void ak_drv_module_unprotect(E_DRV_MODULE drv_mod_name) -+{ -+ ak_drv_sharepin_unlock(drv_mod_name); -+ ak_drv_module_unlock(drv_mod_name); -+} -+EXPORT_SYMBOL(ak_drv_module_unprotect); -+ -+static int __init ak_init_module_lock(void) -+{ -+ printk("Anyka platform share gpio locks initialize.\n"); -+ -+ ak_init_module_locks(); -+ ak_init_sharepin_locks(); -+ return 0; -+} -+subsys_initcall(ak_init_module_lock); -+ -diff --git a/arch/arm/plat-anyka/include/mach/reg.h b/arch/arm/plat-anyka/include/mach/reg.h -new file mode 100644 -index 00000000..751117b6 ---- /dev/null -+++ b/arch/arm/plat-anyka/include/mach/reg.h -@@ -0,0 +1,16 @@ -+/* -+ * reg.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef _REG_H_ -+#define _REG_H_ -+ -+void sys_ctrl_reg_set(unsigned long reg_phy_addr, unsigned long reg_mask, unsigned long reg_val); -+ -+#endif /* _REG_H_ */ -+ -diff --git a/arch/arm/plat-anyka/include/mach/regs-l2.h b/arch/arm/plat-anyka/include/mach/regs-l2.h -new file mode 100644 -index 00000000..cc4dd35f ---- /dev/null -+++ b/arch/arm/plat-anyka/include/mach/regs-l2.h -@@ -0,0 +1,54 @@ -+ -+/* -+ * arch/arm/plat-anyka/include/mach/regs-l2.h -+ */ -+#ifndef __REGS_L2_H_ -+#define __REGS_L2_H_ -+ -+#include <mach/map.h> -+ -+#define vL2DMA_ADDRBUF0 REG_VA_ADDR(AK_VA_L2CTRL, 0x00) -+#define vL2DMA_CONBUF0 REG_VA_ADDR(AK_VA_L2CTRL, 0x40) -+ -+#define L2_DMA_ADDR (AK_VA_L2CTRL + 0x00) -+#define L2_DMA_CON (AK_VA_L2CTRL + 0x40) -+#define L2_DMAREQ (AK_VA_L2CTRL + 0x80) -+#define L2_FRACDMAADDR (AK_VA_L2CTRL + 0x84) -+#define L2_CONBUF0_7 (AK_VA_L2CTRL + 0x88) -+#define L2_CONBUF8_15 (AK_VA_L2CTRL + 0x8C) -+#define L2_BUFASSIGN1 (AK_VA_L2CTRL + 0x90) -+#define L2_BUFASSIGN2 (AK_VA_L2CTRL + 0x94) -+#define L2_LDMACON (AK_VA_L2CTRL + 0x98) -+#define L2_BUFINTEN (AK_VA_L2CTRL + 0x9C) -+#define L2_BUFSTAT1 (AK_VA_L2CTRL + 0xA0) -+#define L2_BUFSTAT2 (AK_VA_L2CTRL + 0xA8) -+ -+/*************************** L2 MEMORY CONTROL *********************/ -+#define rL2_DMAREQ REG_VA_VAL(AK_VA_L2CTRL, 0x80) -+#define rL2_FRACDMAADDR REG_VA_VAL(AK_VA_L2CTRL, 0x84) -+#define rL2_CONBUF0_7 REG_VA_VAL(AK_VA_L2CTRL, 0x88) -+#define rL2_CONBUF8_15 REG_VA_VAL(AK_VA_L2CTRL, 0x8C) -+#define rL2_BUFASSIGN1 REG_VA_VAL(AK_VA_L2CTRL, 0x90) -+#define rL2_BUFASSIGN2 REG_VA_VAL(AK_VA_L2CTRL, 0x94) -+#define rL2_LDMACON REG_VA_VAL(AK_VA_L2CTRL, 0x98) -+#define rL2_BUFINTEN REG_VA_VAL(AK_VA_L2CTRL, 0x9C) -+#define rL2_BUFSTAT1 REG_VA_VAL(AK_VA_L2CTRL, 0xA0) -+#define rL2_BUFSTAT2 REG_VA_VAL(AK_VA_L2CTRL, 0xA8) -+ -+/*************************** L2 MEMORY BUFFER **********************/ -+#define rL2_ADDRBUF0 REG_VA_VAL(AK_VA_L2MEM, 0x0000) -+#define rL2_ADDRBUF1 REG_VA_VAL(AK_VA_L2MEM, 0x0200) -+#define rL2_ADDRBUF2 REG_VA_VAL(AK_VA_L2MEM, 0x0400) -+#define rL2_ADDRBUF3 REG_VA_VAL(AK_VA_L2MEM, 0x0600) -+#define rL2_ADDRBUF4 REG_VA_VAL(AK_VA_L2MEM, 0x0800) -+#define rL2_ADDRBUF5 REG_VA_VAL(AK_VA_L2MEM, 0x0A00) -+#define rL2_ADDRBUF6 REG_VA_VAL(AK_VA_L2MEM, 0x0C00) -+#define rL2_ADDRBUF7 REG_VA_VAL(AK_VA_L2MEM, 0x0E00) -+ -+#define rL2_ADDRTX1_BUF8 REG_VA_VAL(AK_VA_L2MEM, 0x1000) -+#define rL2_ADDRRX1_BUF9 REG_VA_VAL(AK_VA_L2MEM, 0x1080) -+#define rL2_ADDRTX2_BUF10 REG_VA_VAL(AK_VA_L2MEM, 0x1100) -+#define rL2_ADDRRX2_BUF11 REG_VA_VAL(AK_VA_L2MEM, 0x1180) -+ -+#endif /* __REGS_L2_H_ */ -+ -diff --git a/arch/arm/plat-anyka/include/plat/gpio_keys.h b/arch/arm/plat-anyka/include/plat/gpio_keys.h -new file mode 100644 -index 00000000..4f01565c ---- /dev/null -+++ b/arch/arm/plat-anyka/include/plat/gpio_keys.h -@@ -0,0 +1,27 @@ -+#ifndef __GPIO_KEYS_H_ -+#define __GPIO_KEYS_H_ -+ -+struct ak_gpio_keys_button { -+ /* Configuration parameters */ -+ int code; /* input event code (KEY_*, SW_*) */ -+ int gpio; -+ int active_low; -+ char *desc; -+ int type; /* input event type (EV_KEY, EV_SW) */ -+ int wakeup; /* configure the button as a wake-up source */ -+ int debounce_interval; /* debounce ticks interval in msecs */ -+ -+ char pulldown; //pulldown function flag -+ char pullup; //pullup function flag -+ char dir; //direction input/output -+ char int_pol; //interrupt polarity -+}; -+ -+struct ak_gpio_keys_platform_data { -+ struct ak_gpio_keys_button *buttons; -+ int nbuttons; -+ unsigned int rep:1; /* enable input subsystem auto repeat */ -+}; -+ -+ -+#endif /* __GPIO_KEYS_H_ */ -diff --git a/arch/arm/plat-anyka/include/plat/l2.h b/arch/arm/plat-anyka/include/plat/l2.h -new file mode 100755 -index 00000000..c559aa7e ---- /dev/null -+++ b/arch/arm/plat-anyka/include/plat/l2.h -@@ -0,0 +1,374 @@ -+/* -+ * linux/arch/arm/plat-anyka/include/plat/l2.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef __ASM_ARCH_L2_H -+#define __ASM_ARCH_L2_H -+ -+#include <mach/regs-l2.h> -+#include <mach/l2cache.h> -+ -+#define L2_DEBUG 1 -+//#undef L2_DEBUG -+ -+#undef REG32 -+#define REG32(_reg) (*(volatile unsigned long *)(_reg)) -+ -+#undef REG16 -+#define REG16(_reg) (*(volatile unsigned short *)(_reg)) -+ -+/* -+ * ANYKA L2 Control Register List and Bit map definition -+ * TODO: Add all register bit maps and move all to map.h in the future. -+*/ -+#define L2_DMA_REQ_BUF_START 24 -+#define L2_DMA_REQ_BUF_REQ_MASK (0xFFFF << 16) -+#define L2_DMA_REQ_UART_BUF_REQ_START 16 -+#define L2_DMA_REQ_FRAC_DMA_LEN_START 10 -+#define L2_DMA_REQ_FRAC_DMA_LEN_MASK (0x3F << L2_DMA_REQ_FRAC_DMA_LEN_START) -+#define L2_DMA_REQ_FRAC_DMA_REQ (1 << 9) -+#define L2_DMA_REQ_FRAC_DMA_DIR_WR (1 << 8) -+#define L2_DMA_REQ_FRAC_DMA_L2_ADDR_START 1 -+#define L2_DMA_REQ_FRAC_DMA_L2_ADDR_MASK (0x7F << L2_DMA_REQ_FRAC_DMA_L2_ADDR_START) -+#define L2_DMA_REQ_EN (1 << 0) -+ -+#define L2_FRAC_DMA_AHB_FLAG_EN (1 << 29) -+#define L2_FRAC_DMA_LDMA_FLAG_EN (1 << 28) -+ -+#define L2_FRAC_DMA_LOW_ADDR_MASK (0xFFFFFFF << 0) -+ -+#define L2_COMMON_BUF_CFG_BUF7_CLR (1 << 31) -+#define L2_COMMON_BUF_CFG_BUF6_CLR (1 << 30) -+#define L2_COMMON_BUF_CFG_BUF5_CLR (1 << 29) -+#define L2_COMMON_BUF_CFG_BUF4_CLR (1 << 28) -+#define L2_COMMON_BUF_CFG_BUF3_CLR (1 << 27) -+#define L2_COMMON_BUF_CFG_BUF2_CLR (1 << 26) -+#define L2_COMMON_BUF_CFG_BUF1_CLR (1 << 25) -+#define L2_COMMON_BUF_CFG_BUF0_CLR (1 << 24) -+#define L2_COMMON_BUF_CFG_BUF_CLR_START 24 -+#define L2_COMMON_BUF_CFG_BUF0_7_CLR_MASK (0xFF << L2_COMMON_BUF_CFG_BUF_START) -+#define L2_COMMON_BUF_CFG_BUF_VLD_START 16 -+#define L2_COMMON_BUF_CFG_BUF0_7_VLD_MASK (0xFF << L2_COMMON_BUF_CFG_BUF_VLD_START -+#define L2_COMMON_BUF_CFG_BUF_DMA_VLD_START 0 -+#define L2_COMMON_BUF_CFG_BUF_DIR_START 8 -+ -+#define L2_UART_BUF_CFG_BUF_START 16 -+ -+#define L2_UART_BUF_CFG_UART_EN_MASK (0xF << 28) -+#define L2_UART_BUF_CFG_UART_CLR_MASK (0xFF << 16) -+#define L2_UART_BUF_CFG_CPU_BUF_SEL_EN (1 << 3) -+#define L2_UART_BUF_CFG_CPU_BUF_NUM_START 4 -+#define L2_UART_BUF_CFG_CPU_BUF_NUM_MASK (0xF << L2_UART_BUF_CFG_CPU_BUF_NUM_START) -+#define L2_UART_BUF_CFG_CPU_BUF_SEL_START 0 -+#define L2_UART_BUF_CFG_CPU_BUF_SEL_MASK (0x7 << L2_UART_BUF_CFG_CPU_BUF_SEL_START) -+ -+#define L2_DMA_INTR_ENABLE_BUF_START 9 -+#define L2_DMA_INTR_ENABLE_UART_BUF_START 1 -+#define L2_DMA_INTR_ENABLE_FRAC_INTR_EN (1 << 0) -+ -+/* -+ * ANYKA L2 buffer size(buffer 0 to buffer 7), all 512Bytes. -+ * NOTE: L2 buffer 8 to 15 dedicate to UART 1 to 4 & USB 2.0 Controller, -+ * and the corresponding L2 buffer size could be 64, 128 and 256 Bytes. -+ * See ANYKA Programmer's Guide for details (ANYKA preferably). -+ */ -+#define L2_BUFFER_SIZE 512 -+ -+/* -+ * ANYKA L2 DMA waiting times in loop -+ * TODO: Must be change to waiting time based on CPU frequency when frequency APIs are done. -+ */ -+#define L2_MAX_DMA_WAIT_TIME 50 * 1000000UL -+ -+/* -+ * ANYKA DMA size in bytes per transfer (Always 64Bytes) -+ * L2 DMA transfer follows this definition. -+ */ -+#define DMA_ONE_SHOT_LEN 64 -+ -+/* -+ * ANYKA L2 Buffer Status Multiply Ratio(64) -+ * Buffer Status Register 1 & 2: The number of data = Bufn_sta * L2_BUF_STATUS_MULTIPLY_RATIO -+ */ -+#define L2_BUF_STATUS_MULTIPLY_RATIO 64 -+ -+/* -+ * L2 Buffer ID Assignment: -+ * 0 - 7: L2 common buffer, could be used by different peripherals -+ * 8 - 15: Dedicate L2 buffer for UART -+ * 16 - 18: Dedicate L2 buffer for USB -+ */ -+#define L2_COMMON_BUFFER_NUM 8 -+#define L2_UART_BUFFER_NUM 4 -+ -+#define L2_UART_BUFFER_INDEX L2_COMMON_BUFFER_NUM -+#define L2_USB_HOST_BUFFER_INDEX (L2_UART_BUFFER_INDEX + L2_UART_BUFFER_NUM) -+ -+ -+#define L2_COMMON_BUFFER_LEN 512 -+#define L2_UART_BUFFER_LEN 128 -+ -+#define L2_COMMON_BUFFER_OFFSET 0 -+#define L2_UART_BUFFER_OFFSET (L2_COMMON_BUFFER_LEN * L2_COMMON_BUFFER_NUM) -+ -+/* -+ * L2 controller working clock define -+ */ -+#define L2_CLOCK_EN (0x1 << 9) -+#define L2_CLOCK_REG (AK_VA_SYSCTRL + 0x1C) -+ -+/* -+ * AK39XX L2 device list which may use L2 memory. -+ * The devices are defined according to L2 Buffer Assignement 1 & 2 register bit sequence. -+ */ -+typedef enum { -+ ADDR_USB_EP2 = 0, /* USB 2.0 HS Controller: Endpoint 2 */ -+ ADDR_USB_EP3, /* USB 2.0 HS Controller: Endpoint 3 */ -+ ADDR_USB_EP4, /* USB 2.0 HS Controller: Endpoint 4 */ -+ ADDR_RESERVED, /* Reserved */ -+ ADDR_MMC_SD, /* MMC/SD interface */ -+ ADDR_SDIO, /* SDIO interface */ -+ ADDR_SPI1_RX = 7, /* Rx buffer of SPI1 Controller */ -+ ADDR_SPI1_TX, /* Tx buffer of SPI1 Controller */ -+ ADDR_DAC, /* DAC control module */ -+ ADDR_SPI2_RX, /* Rx buffer of SPI2 Controller */ -+ ADDR_SPI2_TX, /* Tx buffer of SPI2 Controller */ -+ ADDR_GPS, /* GPS interface */ -+ ADDR_PCM_TX, /* Tx buffer of PCM Controller */ -+ ADDR_ADC, /* ADC2 */ -+ ADDR_USB_EP5, /* USB 2.0 HS Controller: Endpoint 5 */ -+} l2_device_t; -+ -+ -+#define BUF_NULL 0xFF /* Invalid L2 buffer ID */ -+#define L2_UART_BUF_START_ID L2_COMMON_BUFFER_NUM /* UART used buffer ID from 8 */ -+ -+/* -+ * Maximum L2 DMA status value (The value in CPU-Controlled Buffer and Buffer8 ~ Buffer15 Configuration Register) -+ * The maximum DMA transfer bytes = MAX_L2_DMA_STATUS_VALUE * 64 -+ */ -+#define MAX_L2_DMA_STATUS_VALUE 0x8 -+#define MAX_L2_BUFFER_USED_TIMES 0xFFFF -+ -+/* -+ * Data transfer direction between L2 memory and external RAM -+ */ -+typedef enum { -+ BUF2MEM = 0, /* Data transfer from L2 buffer to external RAM */ -+ MEM2BUF, /* Data transfer from external RAM to L2 buffer */ -+} l2_dma_transfer_direction_t; -+ -+/* -+ * Callback function when L2 DMA/fraction DMA interrupt handler is done -+ */ -+typedef void (*l2_callback_func_t)(unsigned long data); -+ -+/* -+ * L2 buffer status -+ */ -+typedef enum { -+ L2_STAT_USED = 0, /* Current L2 buffer is used by some device */ -+ L2_STAT_IDLE, /* Current L2 buffer is NOT used by some device, thus could be allocated */ -+} l2_buffer_status_t; -+ -+/* -+ * L2 buffer information -+ */ -+typedef struct { -+ u8 id; /* L2 buffer ID (0~17) */ -+ l2_buffer_status_t usable; /* L2 buffer status(used or idle) */ -+ u16 used_time; /* Counter on L2 buffer used times */ -+} l2_buffer_info_t; -+ -+/* -+ * Information on device which use L2 memory -+ */ -+typedef struct { -+ l2_device_t device; /* Device ID */ -+ u8 id; /* TODO: Remove id in the future since array index already represent buffer id */ -+} l2_device_info_t; -+ -+/* -+ * L2 DMA usage information (including DMA/fraction DMA/external RAM/Callback function) -+ */ -+typedef struct { -+ bool dma_start; -+ bool intr_enable; -+ l2_dma_transfer_direction_t direction; -+ void *dma_addr; -+ u32 dma_op_times; -+ bool need_frac; -+ bool dma_frac_start; -+ void *dma_frac_addr; -+ u32 dma_frac_offset; -+ u32 dma_frac_data_len; -+ l2_callback_func_t callback_func; -+ unsigned long data; -+} l2_dma_info_t; -+ -+/** -+ * l2_init - Initialize linux kernel L2 memory support -+ */ -+void __init l2_init(void); -+ -+/** -+ * l2_alloc - Allocate a common L2 buffer for given device -+ * @device: Device ID which need common L2 buffer -+ * Return L2 buffer ID (0 ~ 7) -+ * -+ * Only common L2 buffers(ID 0 ~ 7) could be allocated by l2_alloc. -+ * Other L2 buffers (UART/USB used) is handled by corresponding devices directly. -+ */ -+u8 l2_alloc(l2_device_t device); -+ -+/** -+ * l2_alloc_nowait - Allocate a common L2 buffer for given device -+ * @device: Device ID which need common L2 buffer -+ * Return L2 buffer ID (0 ~ 7) -+ * -+ * Only common L2 buffers(ID 0 ~ 7) could be allocated by l2_alloc_nowait. -+ * Other L2 buffers (UART/USB used) is handled by corresponding devices directly. -+ * return BUF_NULL immediately if no buf was alloc . -+ */ -+u8 l2_alloc_nowait(l2_device_t device); -+ -+/** -+ * l2_free - Free L2 common buffer for given device -+ * @device: Device ID which need common L2 buffer -+ * Return L2 buffer ID (0 ~ 7) -+ * -+ * Only common L2 buffers(ID 0 ~ 7) could be allocated by l2_alloc. -+ * Other L2 buffers (UART/USB used) is handled by corresponding devices directly. -+ * NOTE: Return the previous L2 buffer ID if a L2 buffer has been allocated to the device. -+ * This means one device could get only one L2 buffer maximum. -+ */ -+void l2_free(l2_device_t device); -+ -+/** -+ * l2_set_dma_callback - Set callback function when L2 DMA/fraction DMA interrupt handler is done -+ * @id: L2 buffer ID -+ * @func: Callback function -+ * @data: Arguments used by callback function -+ * Return true(Always) -+ * -+ * NOTE: Caller MUST guarantee that L2 buffer ID is valid. And since the callback function is called -+ * in interrupt handler, it MUST NOT call any functions which may sleep. -+ */ -+bool l2_set_dma_callback(u8 id, l2_callback_func_t func, unsigned long data); -+ -+/** -+ * l2_combuf_dma - Start data tranferring between memory and l2 common buffer in DMA mode -+ * @ram_addr: External RAM address(Physical) -+ * @id: L2 buffer ID involved in DMA transfer -+ * @bytes: Data transfer size -+ * @direction: Data transfer direction between L2 memory and external RAM -+ * @intr_enable: Open interrupt for this L2 buffer or not -+ */ -+void l2_combuf_dma(unsigned long ram_addr, u8 id, unsigned int bytes, l2_dma_transfer_direction_t direction, bool intr_enable); -+ -+/** -+ * l2_combuf_wait_dma_finish - Wait for L2 DMA finish -+ * @id: L2 buffer ID involved in DMA transfer -+ * Return true: DMA transfer finished successfully. -+ * false: DMA transfer failed. -+ * NOTE: DMA transfer is started by l2_combuf_dma. -+ */ -+bool l2_combuf_wait_dma_finish(u8 id); -+ -+/** -+ * l2_combuf_cpu - Transfer data between memory and l2 common buffer in CPU mode -+ * @ram_addr: External RAM address(Physical) -+ * @id: L2 buffer ID -+ * @bytes: Data transfer size -+ * @direction: Data transfer direction between L2 memory and external RAM -+ * -+ * NOTE: According to XuChang, if one transfer data from Peripheral --> L2 Buffer --> RAM, -+ * special care need to be taken when data size is NOT multiple of 64Bytes. -+ * Pheripheral driver must check hardware signals to confirm data has been transfer from -+ * peripheral to L2 buffer since L2 do NOT provide some mechanism to confirm data has -+ * been in L2 Buffer. Driver can and only can call l2_combuf_cpu() to copy data from L2 -+ * Buffer --> RAM after checking hardware signals. -+ * As to 64Bytes * n size data, L2 could check Buffer Status Status Counter to confirm that -+ * Data has been transfer from peripheral to L2 buffer, so no hardware signals checking needed. -+ */ -+void l2_combuf_cpu(unsigned long ram_addr, u8 id, unsigned int bytes, l2_dma_transfer_direction_t direction); -+ -+/** -+ * l2_get_status - Get L2 buffer status -+ * @id: L2 buffer ID -+ */ -+u8 l2_get_status(u8 id); -+ -+/** -+ * l2_clr_status - Clear L2 buffer status -+ * @id: L2 buffer ID -+ */ -+void l2_clr_status(u8 id); -+ -+/** -+ * l2_set_status - Clear L2 buffer status -+ * @id: L2 buffer ID -+ * @status: Status to be set (0 ~ 8) -+ */ -+void l2_set_status(u8 id, u8 status); -+ -+static inline void l2_enable_clock(int enable) -+{ -+ if (enable) -+ REG32(L2_CLOCK_REG) &= ~L2_CLOCK_EN; -+ else -+ REG32(L2_CLOCK_REG) |= L2_CLOCK_EN; -+ return; -+} -+ -+#ifdef L2_DEBUG -+#define L2_PRINT_FUNCLINES() do { printk("%s(): line: %d\n", __func__, __LINE__); } while (0) -+ -+static inline void l2_dump_registers(void) -+{ -+ printk("ANYKA L2 Register Dumping Begin:\n"); -+ -+ printk(" rL2_DMAREQ(C080) = 0x%08X, rL2_FRACDMAADDR(C084) = 0x%0X\n", -+ (unsigned int)rL2_DMAREQ, (unsigned int)rL2_FRACDMAADDR); -+ printk(" rL2_CONBUF0_7(C088) = 0x%08X, rL2_CONBUF8_15(C08C) = 0x%0X\n", -+ (unsigned int)rL2_CONBUF0_7, (unsigned int)rL2_CONBUF8_15); -+ printk(" rL2_BUFASSIGN1(C090) = 0x%08X, rL2_BUFINTEN(C09C) = 0x%0X\n", -+ (unsigned int)rL2_BUFASSIGN1, (unsigned int)rL2_BUFINTEN); -+ printk(" rL2_BUFSTAT1(C0A0) = 0x%08X, rL2_BUFSTAT2(C0A8) = 0x%0X\n", -+ (unsigned int)rL2_BUFSTAT1, (unsigned int)rL2_BUFSTAT2); -+ -+ printk("ANYKA L2 Register Dumping End.\n"); -+} -+ -+static inline void l2_print_array(const char *name, unsigned char *array, int len) -+{ -+ int i; -+ -+ printk("%s[%d] = {\n ", name, len); -+ for (i = 0; i < len; i++) { -+ printk(" 0x%02X,", array[i]); -+ if (i % 16 == 15) -+ printk("\n "); -+ } -+ printk("};\n"); -+ -+} -+ -+#else -+#define L2_PRINT_FUNCLINES() do { } while (0) -+ -+static inline void l2_dump_registers(void) -+{ -+} -+static inline void l2_print_array(const char *name, unsigned int *array, int len) -+{ -+} -+#endif -+ -+#endif /* __ASM_ARCH_L2_H */ -+ -diff --git a/arch/arm/plat-anyka/include/plat/l2_exebuf.h b/arch/arm/plat-anyka/include/plat/l2_exebuf.h -new file mode 100755 -index 00000000..7fd4e248 ---- /dev/null -+++ b/arch/arm/plat-anyka/include/plat/l2_exebuf.h -@@ -0,0 +1,157 @@ -+#ifndef __L2_EXEBUF -+#define __L2_EXEBUF -+ -+ -+#include <linux/io.h> -+#include <mach/gpio.h> -+#include <mach/map.h> -+ -+ -+#define CPU_CHIP_ID (AK_VA_SYSCTRL + 0x00) -+#define CLOCK_DIV_REG (AK_VA_SYSCTRL + 0x04) -+#define CLOCK_CTRL_REG (AK_VA_SYSCTRL + 0x0C) -+#define PHY_CLOCK_CTRL_REG (AK_PA_SYSCTRL + 0x0C) -+#define PHY_CLOCK_DIV_REG (AK_PA_SYSCTRL + 0x04) -+#define PHY_RAM_CFG_REG4 (AK_PA_REGRAM + 0x0C) -+ -+#define RAM_CFG_REG1 (AK_VA_REGRAM + 0x00) -+#define RAM_CFG_REG2 (AK_VA_REGRAM + 0x04) -+#define RAM_CFG_REG3 (AK_VA_REGRAM + 0x08) -+#define RAM_CFG_REG4 (AK_VA_REGRAM + 0x0C) -+#define RAM_CPU_CMD (AK_VA_REGRAM + 0x10) -+#define PHY_RAM_CFG_REG1 (AK_PA_REGRAM + 0x00) -+#define PHY_RAM_CFG_REG2 (AK_PA_REGRAM + 0x04) -+#define PHY_RAM_CFG_REG3 (AK_PA_REGRAM + 0x08) -+#define PHY_RAM_CFG_REG4 (AK_PA_REGRAM + 0x0C) -+#define PHY_RAM_CPU_CMD (AK_PA_REGRAM + 0x10) -+ -+#define FIFO_R_EMPTY (1 << 16) -+#define FIFO_CMD_EMPTY (1 << 14) -+#define AUTO_REFRESH_EN (1 << 0) -+#define RAM_CLOCK_DISABLE (1 << 10) -+#define ENTER_STANDBY (1 << 13) -+#define REFRESH_PERIOD_INTERVAL (0x39f << 1) -+ -+#if 0 -+#define LED_INIT_DEBUG do {\ -+ unsigned long value;\ -+ REG32(AK_VA_SYSCTRL + 0x00a8) |= (1 << 16);\ -+ REG32(AK_VA_SYSCTRL + 0x0094) &= ~(1 << 16);\ -+ } while(0) -+#define LED_PHY_ON do {\ -+ REG32(AK_PA_SYSCTRL + 0x0098) &= ~(1 << 16);\ -+ } while(0) -+ -+#define LED_PHY_OFF do {\ -+ REG32(AK_PA_SYSCTRL + 0x0098) |= (1 << 16);\ -+ } while(0) -+ -+#define LED_VIRT_ON do {\ -+ REG32(AK_VA_SYSCTRL + 0x0098) &= ~(1 << 16);\ -+ } while(0) -+ -+#define LED_VIRT_OFF do {\ -+ REG32(AK_VA_SYSCTRL + 0x0098) |= (1 << 16);\ -+ } while(0) -+#endif -+ -+#define DISABLE_CACHE_MMU() do { \ -+ __asm__ __volatile__( \ -+ "tci_loop: mrc p15, 0, r15, c7, c14, 3\n\t" /* test,clean,invalidate D cache */\ -+ "bne tci_loop\n\t" \ -+ "mcr p15, 0, %0, c8, c7, 0\n\t" /* invalidate I & D TLBs */ \ -+ "mcr p15, 0, %0, c7, c5, 0\n\t" /* invalidate I caches */ \ -+ "mrc p15, 0, %0, c1, c0, 0\n\t" \ -+ "bic %0, %0, #0x1000\n\t" /* disable Icache */ \ -+ "bic %0, %0, #0x0005\n\t" /* disable Dcache,mmu*/ \ -+ "ldr %1, =l2_phys_run\n\t" /* load 0x480000xx address */ \ -+ "b suspend_turn_off_mmu\n\t" \ -+ " .align 5\n\t" /* 32 byte aligned */ \ -+ "suspend_turn_off_mmu:\n\t"\ -+ "mcr p15, 0, %0, c1, c0, 0\n\t"\ -+ "mov pc, %1\n\t" /* jumpto 0x480000xx then run */ \ -+ "l2_phys_run:\n\t" /* mark the real running addr--> L2 buff */\ -+ : : "r"(0),"r"(1)); \ -+ } while(0) -+ -+#define ENABLE_CACHE_MMU() do { \ -+ __asm__ __volatile__( \ -+ "mcr p15, 0, %0, c8, c7, 0\n\t" /* invalidate I & D TLBs */ \ -+ "mcr p15, 0, %0, c7, c7, 0\n\t" /* invalidate I & D caches */\ -+ "mcr p15, 0, %0, c7, c10, 4\n\t" /* Drain write buffer */ \ -+ "mrc p15, 0, %0, c1, c0, 0\n\t" \ -+ "orr %0, %0, #0x1000\n\t" \ -+ "orr %0, %0, #0x0005\n\t" \ -+ "b resume_turn_on_mmu\n\t" \ -+ " .align 5\n\t" \ -+ "resume_turn_on_mmu:\n\t" \ -+ "mcr p15, 0, %0, c1, c0, 0\n\t" \ -+ ::"r"(2)); \ -+ } while(0) -+ -+#define PM_DELAY(time) do { \ -+ __asm__ __volatile__( \ -+ "1:\n\t" \ -+ "subs %0, %0, #1\n\t" \ -+ "bne 1b\n\t" \ -+ ::"r"(time)); \ -+ } while(0) -+ -+ -+#define DDR2_ENTER_POWERDOWN() do {\ -+ /* send precharge all banks */\ -+ __raw_writel(0x0aa00400, PHY_RAM_CPU_CMD);\ -+ /* close odt and asserting low on cke ,close odt and send enter powerdown command */\ -+ __raw_writel(0x04f00000, PHY_RAM_CPU_CMD);\ -+ }while(0) -+ -+#define DDR2_EXIT_POWERDOWN() do {\ -+ /* exit precharge power-down mode after delay at least 3 tck */\ -+ /* by asserting high on cke and odt remain low */\ -+ __raw_writel(0x02f00000, PHY_RAM_CPU_CMD);\ -+ }while(0) -+ -+ -+#define DDR2_ENTER_SELFREFRESH() do {\ -+ /* send precharge all banks */\ -+ __raw_writel(0x0aa00400, PHY_RAM_CPU_CMD);\ -+ /* close odt and delay taofd=2.5 tck */\ -+ __raw_writel(0x02f00000, PHY_RAM_CPU_CMD);\ -+ PM_DELAY(0x1);\ -+ /* asserting low on cke ,close odt and entry self-refresh mode */\ -+ __raw_writel(0x04c00000, PHY_RAM_CPU_CMD);\ -+ }while(0) -+ -+#define DDR2_EXIT_SELFREFRESH() do {\ -+ /* exit self-refresh by asserting high on cke and odt remain low */\ -+ __raw_writel(0x02f00000, PHY_RAM_CPU_CMD);\ -+ /* delay txsrd=200tck as send nop cmd */ \ -+ __raw_writel(0x02f00000, PHY_RAM_CPU_CMD);\ -+ PM_DELAY(0x8);\ -+ }while(0) -+ -+#define DDR2_ENTER_AUTOREFRESH() do {\ -+ /* send auto refresh and open odt high */\ -+ __raw_writel(0x0ac00000, PHY_RAM_CPU_CMD);\ -+ __raw_writel(0x0ac00000, PHY_RAM_CPU_CMD);\ -+ __raw_writel(0x0ac00000, PHY_RAM_CPU_CMD);\ -+ }while(0) -+ -+ -+#define L2_LINK(flag) __section(.l2mem_##flag) -+#define L2FUNC_NAME(name) l2_enter_##name -+ -+#define SPECIFIC_L2BUF_EXEC(flag, param1,param2,param3,param4) do {\ -+ extern char _end_##flag[], _start_##flag[];\ -+ int len;\ -+ len = _end_##flag - _start_##flag;\ -+ l2_exec_buf(_start_##flag,len, param1,param2,param3,param4);\ -+}while(0) -+ -+int l2_exec_buf(const char *vaddr, int len, unsigned long param1, -+ unsigned long param2,unsigned long param3, unsigned long param4); -+ -+ -+#endif /* L2_EXEBUF */ -+ -+ -diff --git a/arch/arm/plat-anyka/include/plat/rtc.h b/arch/arm/plat-anyka/include/plat/rtc.h -new file mode 100644 -index 00000000..9ad3f45d ---- /dev/null -+++ b/arch/arm/plat-anyka/include/plat/rtc.h -@@ -0,0 +1,133 @@ -+/* -+ * linux/arch/arm/plat-anyka/include/plat/rtc.h -+ * -+ * AK RTC related routines -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef __ASM_ARCH_RTC_H -+#define __ASM_ARCH_RTC_H -+ -+#include <linux/module.h> -+#include <linux/fs.h> -+#include <linux/string.h> -+#include <linux/init.h> -+#include <linux/platform_device.h> -+#include <linux/interrupt.h> -+#include <linux/clk.h> -+#include <linux/log2.h> -+#include <linux/delay.h> -+ -+#include <asm/uaccess.h> -+#include <asm/io.h> -+ -+#include <mach/hardware.h> -+ -+#define EPOCH_START_YEAR (1900) -+#define RTC_START_YEAR (1980) -+#define RTC_YEAR_COUNT (127) -+ -+#define AK_RTC_CONF (AK_VA_SYSCTRL + 0x50) -+#define AK_RTC_DATA (AK_VA_SYSCTRL + 0x54) -+#define OTHER_WAKEUP_CTRL (AK_VA_SYSCTRL + 0x34) -+#define OTHER_WAKEUP_STAT (AK_VA_SYSCTRL + 0x38) -+ -+#define RTC_RDY_INT_CTRL (AK_VA_SYSCTRL + 0x2C) -+#define RTC_RDY_INT_STAT (AK_VA_SYSCTRL + 0x30) -+#define RTC_RDY_CTRL_BIT (1 << 7) -+#define RTC_RDY_STAT_BIT (1 << 7) -+ -+#define RTC_WAKEUP_EN (1 << 12) -+#define RTC_CONF_RTC_WR_EN (1 << 25) -+#define RTC_CONF_RTC_EN (1 << 24) -+#define RTC_CONF_RTC_READ ((1 << 21) | (2 << 18) | (1 << 17)) -+#define RTC_CONF_RTC_WRITE ((1 << 21) | (2 << 18) | (0 << 17)) -+ -+#define AK_RTC_REAL_TIME1 (0x0) -+#define AK_RTC_REAL_TIME2 (0x1) -+#define AK_RTC_REAL_TIME3 (0x2) -+#define AK_RTC_ALARM_TIME1 (0x3) -+#define AK_RTC_ALARM_TIME2 (0x4) -+#define AK_RTC_ALARM_TIME3 (0x5) -+#define AK_WDT_RTC_TIMER_CONF (0x6) -+#define AK_RTC_SETTING (0x7) -+#define AK_RTC_REG_MAX AK_RTC_SETTING -+ -+#define RTC_ON 1 -+#define RTC_OFF 0 -+#define RTC_SETTING_REAL_TIME_RE (1 << 4) -+#define RTC_SETTING_REAL_TIME_WR (1 << 3) -+#define RTC_WAIT_TIME_OUT 2000 -+/* -+ * When the RTC module begins to receive/send data, bit [24] of Interrupt Enable/Status -+ * Register of System Control Module (Add: 0x0800, 004C) is set to 0; and then this -+ * bit is set to 1 automatically to indicate that the data has been well received/sent -+ */ -+static void inline ak_rtc_wait_ready(void) -+{ -+ unsigned long timeout = 0; -+ -+ while (!(__raw_readl(RTC_RDY_INT_STAT) & RTC_RDY_STAT_BIT)) { -+ ++timeout; -+ if (timeout >= RTC_WAIT_TIME_OUT) { -+ //printk("--ak_rtc_wait_ready\n"); -+ break; -+ } -+ } -+} -+ -+static void inline rtc_ready_irq_enable(void) -+{ -+ unsigned long regval; -+ -+ /* -+ * Mask RTC Ready Interrupt -+ */ -+ regval = __raw_readl(RTC_RDY_INT_CTRL); -+ __raw_writel(regval | (RTC_RDY_CTRL_BIT), RTC_RDY_INT_CTRL); -+ -+ /* -+ * Wait for RTC Ready Interrupt to be cleared -+ */ -+ ak_rtc_wait_ready(); -+ -+ /* -+ * Enable RTC Register Read/Write -+ */ -+ regval = __raw_readl(AK_RTC_CONF); -+ regval |= RTC_CONF_RTC_WR_EN; -+ __raw_writel(regval, AK_RTC_CONF); -+} -+ -+static void inline rtc_ready_irq_disable(void) -+{ -+ unsigned long regval; -+ /* -+ * Disable RTC Register Read/Write -+ */ -+ regval = __raw_readl(AK_RTC_CONF); -+ regval &= ~RTC_CONF_RTC_WR_EN; -+ __raw_writel(regval, AK_RTC_CONF); -+ -+ /* -+ * Unmask RTC Ready Interrupt -+ */ -+ regval = __raw_readl(RTC_RDY_INT_CTRL); -+ __raw_writel(regval & ~RTC_RDY_CTRL_BIT, RTC_RDY_INT_CTRL); -+} -+ -+void ak_rtc_power(int op); -+ -+unsigned int ak_rtc_read(unsigned int addr); -+unsigned int ak_rtc_write(unsigned int addr, unsigned int value); -+unsigned int ak_rtc_set_wpin(bool level); -+void ak_reboot_sys_by_wtd(void); -+void ak_reboot_sys_by_wakeup(void); -+int test_rtc_inter_reg(unsigned int addr); -+ -+ -+#endif /* __ASM_ARCH_RTC_H */ -diff --git a/arch/arm/plat-anyka/l2.c b/arch/arm/plat-anyka/l2.c -new file mode 100755 -index 00000000..73b5f170 ---- /dev/null -+++ b/arch/arm/plat-anyka/l2.c -@@ -0,0 +1,1180 @@ -+/* -+ * linux/arch/arm/plat-anyka/l2.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include <linux/module.h> -+//#include <linux/init.h> -+#include <linux/ioport.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/dma-mapping.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/stddef.h> -+#include <linux/irq.h> -+#include <linux/sched.h> -+ -+#include <asm/dma.h> -+#include <asm/sizes.h> -+ -+#include <plat/l2.h> -+#include <mach/clock.h> -+ -+static l2_buffer_info_t l2_buffer_info[L2_COMMON_BUFFER_NUM]; -+static l2_dma_info_t l2_dma_info[L2_COMMON_BUFFER_NUM + L2_UART_BUFFER_NUM]; -+static bool l2_frac_started = false; /* L2 fraction DMA start flag */ -+ -+static l2_device_info_t l2_device_info[] = { -+ { ADDR_USB_EP2, BUF_NULL }, -+ { ADDR_USB_EP3, BUF_NULL }, -+ { ADDR_USB_EP4, BUF_NULL }, -+ { ADDR_RESERVED, BUF_NULL }, -+ { ADDR_MMC_SD, BUF_NULL }, -+ { ADDR_SDIO, BUF_NULL }, -+ { ADDR_RESERVED, BUF_NULL }, -+ { ADDR_SPI1_RX, BUF_NULL }, -+ { ADDR_SPI1_TX, BUF_NULL }, -+ { ADDR_DAC, BUF_NULL }, -+ { ADDR_SPI2_RX, BUF_NULL }, -+ { ADDR_SPI2_TX, BUF_NULL }, -+ { ADDR_GPS, BUF_NULL }, -+ { ADDR_PCM_TX, BUF_NULL }, -+ { ADDR_ADC, BUF_NULL }, -+ { ADDR_USB_EP5, BUF_NULL }, -+ { ADDR_RESERVED, BUF_NULL }, -+}; -+ -+static int l2_wait = 0; -+static wait_queue_head_t l2_wq; -+ -+extern void l2cache_invalidate(void); -+ -+static void l2_combuf_ctrl(u8 id, bool enable); -+static void l2_select_combuf(l2_device_t device, u8 id); -+static void l2_assert_combuf_id(u8 id); -+static void l2_assert_buf_id(u8 id); -+static void l2_clear_dma(u8 id); -+static void l2_frac_dma(unsigned long ram_addr, u8 id, u8 frac_offset, -+ unsigned int bytes, l2_dma_transfer_direction_t direction, bool intr_enable); -+static u32 l2_get_addr(u8 id); -+static bool l2_get_dma_param(unsigned int bytes, unsigned int *low, unsigned int *high); -+static void l2_dma(unsigned long ram_addr, u8 id, unsigned int bytes, -+ l2_dma_transfer_direction_t direction, bool intr_enable); -+static bool l2_wait_dma_finish(u8 id); -+static void l2_cpu(unsigned long ram_addr, u8 id, -+ unsigned long buf_offset, unsigned int bytes, l2_dma_transfer_direction_t direction); -+static irqreturn_t l2_interrupt_handler(int irq, void *dev_id); -+ -+/** -+ * l2_assert_buf_id - Assert a L2 buffer ID is valid -+ * @id: L2 buffer ID -+ * -+ * NOTE: Assert only L2 common buffer and UART buffer, USB buffer is not checked. -+ * Since this function is called internally by other L2 API, invalid id will cause -+ * linux kernel to oops for bug tracking. -+ */ -+static void l2_assert_buf_id(u8 id) -+{ -+ if (id >= L2_COMMON_BUFFER_NUM + L2_UART_BUFFER_NUM) -+ BUG(); -+} -+ -+/** -+ * l2_assert_combuf_id - Assert a L2 common buffer ID is valid -+ * @id: L2 buffer ID -+ * -+ * NOTE: Assert only L2 common buffer, UART & USB buffer is not checked. -+ * Since this function is called internally by other L2 API, invalid id will cause -+ * linux kernel to oops for bug tracking. -+ */ -+static void l2_assert_combuf_id(u8 id) -+{ -+ if (id >= L2_COMMON_BUFFER_NUM) -+ BUG(); -+} -+ -+/** -+ * l2_combuf_ctrl - L2 buffer enable/disable -+ * @id: L2 buffer ID -+ * @enable: true to enable L2 buffer, false to disable L2 buffer -+ */ -+static void l2_combuf_ctrl(u8 id, bool enable) -+{ -+ unsigned long regval; -+ unsigned long flags; -+ -+ l2_assert_buf_id(id); -+ -+ local_irq_save(flags); -+ -+ regval = rL2_CONBUF0_7; -+ if (enable) { -+ /* Enable L2 buffer & L2 Buffer DMA */ -+ regval |= (1 << (id + L2_COMMON_BUF_CFG_BUF_DMA_VLD_START)) | -+ (1 << (id + L2_COMMON_BUF_CFG_BUF_VLD_START)); -+ } else { -+ /* Disable L2 buffer & L2 Buffer DMA */ -+ regval &= ~((1 << (id + L2_COMMON_BUF_CFG_BUF_DMA_VLD_START)) | -+ (1 << (id + L2_COMMON_BUF_CFG_BUF_VLD_START))); -+ } -+ rL2_CONBUF0_7 = regval; -+ -+ local_irq_restore(flags); -+ -+} -+ -+/** -+ * l2_select_combuf - Select a L2 buffer for given device -+ * @device: Device which need to assign a L2 buffer -+ * @id: L2 buffer ID -+ */ -+static void l2_select_combuf(l2_device_t device, u8 id) -+{ -+ unsigned long regval; -+ unsigned long bits_offset; -+ -+ l2_assert_combuf_id(id); -+ -+ if ((u8)device < 10) { -+ /* -+ * USB Bulkout ~ DAC (Device 0 ~ 9) is controlled by Buffer Assignment Register 1 -+ */ -+ regval = rL2_BUFASSIGN1; -+ bits_offset = (u8)device * 3; -+ regval &= ~(0x7 << bits_offset); -+ regval |= ((id & 0x7) << bits_offset); -+ rL2_BUFASSIGN1 = regval; -+ } else { -+ /* -+ * SPI2 Rx ~ ADC (Device 10 ~ 14) is controlled by Buffer Assignment Register 2 -+ */ -+ regval = rL2_BUFASSIGN2; -+ bits_offset = ((u8)device - 10) * 3; -+ regval &= ~(0x7 << bits_offset); -+ regval |= ((id & 0x7) << bits_offset); -+ rL2_BUFASSIGN2 = regval; -+ } -+ -+} -+ -+ -+/** -+ * l2_deselect_combuf - deselect a L2 buffer for given device -+ * @device: Device which need to assign a L2 buffer -+ * @id: L2 buffer ID -+ * -+ * note: buffer 0 is reserved for softuse, no hardware is assigned -+ * so when free a l2 buffer, select to this device use buffer 0 as deselect -+ */ -+static void l2_deselect_combuf(l2_device_t device, u8 id) -+{ -+ unsigned long regval; -+ unsigned long bits_offset; -+ -+ l2_assert_combuf_id(id); -+ -+ if ((u8)device < 10) { -+ /* -+ * USB Bulkout ~ DAC (Device 0 ~ 9) is controlled by Buffer Assignment Register 1 -+ */ -+ regval = rL2_BUFASSIGN1; -+ bits_offset = (u8)device * 3; -+ regval &= ~(0x7 << bits_offset); -+ rL2_BUFASSIGN1 = regval; -+ } else { -+ /* -+ * SPI2 Rx ~ ADC (Device 10 ~ 14) is controlled by Buffer Assignment Register 2 -+ */ -+ regval = rL2_BUFASSIGN2; -+ bits_offset = ((u8)device - 10) * 3; -+ regval &= ~(0x7 << bits_offset); -+ rL2_BUFASSIGN2 = regval; -+ } -+ -+} -+ -+/** -+ * l2_clear_dma - Clear L2 buffer DMA status -+ * @id: L2 buffer ID which need to clear DMA status -+ */ -+static void l2_clear_dma(u8 id) -+{ -+ bool dmapending; -+ u8 status; -+ -+ dmapending = rL2_DMAREQ & (1 << (id + L2_DMA_REQ_BUF_START)); -+ status = l2_get_status(id); -+ -+ if (status == 0) { -+ return ; /* NO DMA request, so do nothing */ -+ } -+ -+ if(l2_dma_info[id].direction == BUF2MEM) { -+ printk("l2r:[%d]..", id); -+ while (dmapending) { -+ l2_set_status(id, 8); -+ dmapending = rL2_DMAREQ & (1 << (id + L2_DMA_REQ_BUF_START)); -+ } -+ printk("done\n"); -+ } else { -+ /* -+ * Wait until DMA request of this L2 buffer is finished. -+ */ -+ printk("l2t:[%d]..", id); -+ while (dmapending) { -+ l2_clr_status(id); -+ dmapending = rL2_DMAREQ & (1 << (id + L2_DMA_REQ_BUF_START)); -+ } -+ printk("done\n"); -+ } -+} -+ -+/** -+ * l2_frac_dma - Start data tranferring between memory and l2 common buffer in fraction DMA mode -+ * @ram_addr: External RAM address(Physical) -+ * @id: L2 buffer ID involved in DMA transfer -+ * @frac_offset: The region offset between buffer start address and transfer start address -+ * @bytes: Data transfer size -+ * @direction: Data transfer direction between L2 memory and external RAM -+ * @intr_enable: Open interrupt for this L2 buffer or not -+ * -+ * NOTE: Data transfer size should be 1~64Bytes, frac_offset should be 0~7 (*64Bytes) -+ */ -+static void l2_frac_dma(unsigned long ram_addr, u8 id, u8 frac_offset, -+ unsigned int bytes, l2_dma_transfer_direction_t direction, bool intr_enable) -+{ -+ u32 bufaddr; -+ u32 highaddr; -+ unsigned long regval; -+ unsigned long flags; -+ -+#if 0 -+ printk("%s(): ram_addr=0x%08X, l2 buffer id=%d, frac_offset=%d, bytes=%d, direction=%s, intr_enable=%d.\n", -+ __func__, (unsigned int)ram_addr, id, frac_offset, bytes, (direction == BUF2MEM)?"BUF2MEM":"MEM2BUF", intr_enable); -+#endif -+ -+ if (bytes == 0) { -+ printk("l2: no need to start fraction dma transfer: bytes=0.\n"); -+ return ; -+ } -+ -+ local_irq_save(flags); -+ -+ /* -+ * Set fraction external RAM address. -+ */ -+ highaddr = (ram_addr << 2) & 0xC0000000; -+ -+ regval = rL2_FRACDMAADDR; -+ regval &= ~(L2_FRAC_DMA_LOW_ADDR_MASK | (3<<30)); //modified by anyka chenyingyu -+ regval |= (ram_addr & L2_FRAC_DMA_LOW_ADDR_MASK) | highaddr; -+ rL2_FRACDMAADDR = regval; -+ -+ /* Set fraction DMA address */ -+ bufaddr = (id < L2_COMMON_BUFFER_NUM) ? ((id & 0x7) << 3) | (frac_offset & 0x7) : -+ (0x40 + ((id - L2_COMMON_BUFFER_NUM) << 1)) | (frac_offset & 0x1); -+ -+ /* Clear other fraction DMA request and info */ -+ regval = rL2_DMAREQ; -+ regval &= ~(L2_DMA_REQ_FRAC_DMA_LEN_MASK | L2_DMA_REQ_FRAC_DMA_L2_ADDR_MASK | -+ L2_DMA_REQ_FRAC_DMA_REQ | L2_DMA_REQ_BUF_REQ_MASK); -+ -+ switch (direction) { -+ case MEM2BUF: -+ if (bytes & 0x1) -+ bytes = bytes + 1; /* Round to even number when read data from external ram */ -+ regval |= L2_DMA_REQ_FRAC_DMA_REQ | L2_DMA_REQ_FRAC_DMA_DIR_WR | -+ (bufaddr << L2_DMA_REQ_FRAC_DMA_L2_ADDR_START) | -+ ((bytes - 1) << L2_DMA_REQ_FRAC_DMA_LEN_START); -+ rL2_DMAREQ = regval; -+ break; -+ case BUF2MEM: -+ regval &= ~(L2_DMA_REQ_FRAC_DMA_DIR_WR); -+ regval |= L2_DMA_REQ_FRAC_DMA_REQ | -+ (bufaddr << L2_DMA_REQ_FRAC_DMA_L2_ADDR_START) | -+ ((bytes - 1) << L2_DMA_REQ_FRAC_DMA_LEN_START); -+ rL2_DMAREQ = regval; -+ break; -+ default: -+ BUG(); -+ } -+ -+ if (intr_enable) { -+ regval = rL2_BUFINTEN; -+ regval |= L2_DMA_INTR_ENABLE_FRAC_INTR_EN; -+ rL2_BUFINTEN = regval; -+ } -+ -+ local_irq_restore(flags); -+} -+ -+/** -+ * l2_get_addr - Get L2 memory start address for given L2 buffer -+ * @id: L2 buffer ID -+ * Return L2 memory start address(Logical/Virtual) (NOT physical address) -+ */ -+static u32 l2_get_addr(u8 id) -+{ -+ u32 bufaddr = 0; -+ -+ if (id < L2_UART_BUFFER_INDEX) { /* L2 common buffer */ -+ bufaddr = (u32)AK_VA_L2MEM + L2_COMMON_BUFFER_OFFSET + -+ id * L2_COMMON_BUFFER_LEN; -+ } else if (id < L2_USB_HOST_BUFFER_INDEX) { /* UART L2 buffer */ -+ bufaddr = (u32)AK_VA_L2MEM + L2_UART_BUFFER_OFFSET + -+ (id - L2_COMMON_BUFFER_NUM) * L2_UART_BUFFER_LEN; -+ } else { -+ printk("l2: invalid buffer id %d.\n", (int)id); -+ } -+ -+ return bufaddr; -+} -+ -+/** -+ * l2_get_dma_param - Calculate l2 buffer big loop/small loop counter value -+ * @bytes: L2 buffer ID -+ * @low: CNT_cfg (bit[7:0] of DMA Operation Times Configuration Register) -+ * @high: CNT_cfg_H (bit[23:16] of DMA Operation Times Configuration Register) -+ * Return true when correct counter value (high/low) is found, else return false. -+ * -+ * NOTE: Use a simplified calculation method for L2 buffer 0~7 and 8~15 for bytes > 8KB -+ */ -+static bool l2_get_dma_param(unsigned int bytes, unsigned int *low, unsigned int *high) -+{ -+ unsigned int factor; -+ unsigned int dma_times = bytes / DMA_ONE_SHOT_LEN; -+ -+ if (bytes <= 8 * 1024) { -+ *low = dma_times; -+ *high = 0; -+ -+ return true; -+ } else if (dma_times & 0x7) { -+ printk("l2: Invalid L2 DMA buffer size(%u).\n", bytes); -+ return false; -+ } -+ -+ factor = 16 * 8; -+ -+ while (factor > 0) { -+ if ((dma_times % factor) == 0) { -+ *low = factor; -+ *high = dma_times / factor - 1; -+ -+ return (*high < 0xFF) ? true : false; -+ } -+ -+ factor -= 8; -+ } -+ -+ return false; -+} -+ -+ -+/** -+ * l2_dma - Start data tranferring between memory and l2 buffer in DMA mode -+ * @ram_addr: External RAM address(Physical) -+ * @id: L2 buffer ID involved in DMA transfer -+ * @bytes: Data transfer size -+ * @direction: Data transfer direction between L2 memory and external RAM -+ * @intr_enable: Open interrupt for this L2 buffer or not -+ */ -+static void l2_dma(unsigned long ram_addr, u8 id, unsigned int bytes, -+ l2_dma_transfer_direction_t direction, bool intr_enable) -+{ -+ unsigned long regid; -+ unsigned long regval; -+ unsigned long flags; -+ unsigned int cnt_low; -+ unsigned int cnt_high; -+ -+#if 0 -+ printk("%s(): ram_addr=0x%0X, id=%d, bytes=%d, direction=%d, intr_enable=%d.\n", -+ __func__, (unsigned int)ram_addr, id, bytes, direction, intr_enable); -+#endif -+ if (bytes == 0) { -+ printk("l2: no need to start dma transfer: bytes=0.\n"); -+ return ; -+ } -+ -+ if (!l2_get_dma_param(bytes, &cnt_low, &cnt_high)) { -+ printk("l2: L2 DMA buffer size error: bytes=%d.\n", bytes); -+ return ; -+ } -+ -+ if (l2_dma_info[id].dma_start || l2_dma_info[id].dma_frac_start) { -+ printk("l2: unable to start dma, dma NOT finished, buf id=%d.\n", (int)id); -+ return ; -+ } -+ -+ l2_dma_info[id].dma_op_times = bytes / DMA_ONE_SHOT_LEN; -+ l2_dma_info[id].dma_frac_data_len = bytes % DMA_ONE_SHOT_LEN; -+ l2_dma_info[id].dma_addr = (void *)ram_addr; -+ l2_dma_info[id].direction = direction; -+ l2_dma_info[id].intr_enable = intr_enable; -+ l2_dma_info[id].need_frac = false; -+ -+ if (l2_dma_info[id].dma_frac_data_len > 0) { -+ l2_dma_info[id].need_frac = true; -+ l2_dma_info[id].dma_frac_addr = (void *)(u8 *)l2_dma_info[id].dma_addr + -+ l2_dma_info[id].dma_op_times* DMA_ONE_SHOT_LEN; -+ l2_dma_info[id].dma_frac_offset = l2_dma_info[id].dma_op_times; -+ } -+ -+ if (l2_dma_info[id].dma_op_times== 0) { -+ /* -+ * If DMA transfer size < 64, we start fraction DMA immediately. -+ */ -+ -+ l2_dma_info[id].dma_start = false; -+ l2_dma_info[id].dma_frac_start = true; -+ -+ l2_frac_dma((unsigned long)l2_dma_info[id].dma_frac_addr, id, -+ l2_dma_info[id].dma_frac_offset, l2_dma_info[id].dma_frac_data_len, -+ l2_dma_info[id].direction, intr_enable); -+ return ; -+ } -+ l2_dma_info[id].dma_start = true; -+ -+ local_irq_save(flags); -+ -+ l2cache_invalidate(); -+ asm("MMU_Clean_Invalidate_Dcache:\n" "mrc p15,0,r15,c7,c14,3\n" "bne MMU_Clean_Invalidate_Dcache"); -+ -+ /* -+ * Set address of external RAM -+ */ -+ regval = (unsigned long)l2_dma_info[id].dma_addr; -+ regid = (unsigned long)vL2DMA_ADDRBUF0 + id * 4; -+ __raw_writel(regval, regid); -+ -+ /* -+ * Set DMA operation times -+ */ -+ regid = (unsigned long)vL2DMA_CONBUF0 + id * 4; -+ regval = (cnt_high << 16) | (cnt_low & 0xFF); -+ __raw_writel(regval, regid); -+ -+ /* -+ * Set DMA direction for L2 common buffer -+ */ -+ if (id < L2_COMMON_BUFFER_NUM) { -+ regval = rL2_CONBUF0_7; -+ if (l2_dma_info[id].direction == MEM2BUF) { -+ regval |= (1 << (id + L2_COMMON_BUF_CFG_BUF_DIR_START));; -+ } else { -+ regval &= ~(1 << (id + L2_COMMON_BUF_CFG_BUF_DIR_START)); -+ } -+ rL2_CONBUF0_7 = regval; -+ } -+ -+ -+ /* -+ * Start buffer DMA request -+ */ -+ regval = rL2_DMAREQ; -+ regval &= ~(L2_DMA_REQ_FRAC_DMA_REQ | L2_DMA_REQ_BUF_REQ_MASK); -+ if (id < L2_COMMON_BUFFER_NUM) { -+ regval |= (1 << (id + L2_DMA_REQ_BUF_START)); -+ } else { -+ regval |= (1 << ((id - L2_UART_BUF_START_ID + L2_UART_BUF_CFG_BUF_START))); -+ } -+ rL2_DMAREQ = regval; -+ -+ -+ /* -+ * Enable DMA interrupt now -+ */ -+ if (intr_enable) { -+ regval = rL2_BUFINTEN; -+ if (id < L2_COMMON_BUFFER_NUM) { -+ regval |= 1 << (id + L2_DMA_INTR_ENABLE_BUF_START); -+ } else { -+ regval |= 1 << (id - L2_COMMON_BUFFER_NUM + L2_DMA_INTR_ENABLE_UART_BUF_START); -+ } -+ rL2_BUFINTEN = regval; -+ } -+ -+ local_irq_restore(flags); -+} -+ -+/** -+ * l2_wait_dma_finish - Wait for L2 DMA to finish -+ * @id: L2 buffer ID involved in DMA transfer -+ * Return true: DMA transfer finished successfully. -+ * false: DMA transfer failed. -+ * NOTE: DMA transfer is started by l2_dma. -+ */ -+static bool l2_wait_dma_finish(u8 id) -+{ -+ unsigned int timeout; -+ unsigned long dmareq; -+ unsigned long dma_bit; -+ const unsigned int max_wait_time = L2_MAX_DMA_WAIT_TIME; -+ -+ timeout = 0; -+ if (l2_dma_info[id].dma_start) { -+ dma_bit = (id < L2_COMMON_BUFFER_NUM) ? (1 << (id + L2_DMA_REQ_BUF_START)) : -+ (1 << (id - L2_COMMON_BUFFER_NUM + L2_DMA_REQ_UART_BUF_REQ_START)); -+ do { -+ dmareq = rL2_DMAREQ; -+ } while((dmareq & dma_bit) && timeout++ < max_wait_time); -+ -+ l2_dma_info[id].dma_start = false; -+ -+ if (timeout >= max_wait_time) { -+ printk("l2: wait dma timeout, buf id=%d, status=%d.\n", id, l2_get_status(id)); -+ l2_clear_dma(id); -+ __raw_writel(0x0, vL2DMA_CONBUF0 + id * 4); -+ return false; -+ } -+ -+ /* -+ * If fraction DMA is NOT need, then everything is done. -+ */ -+ if (!l2_dma_info[id].need_frac) { -+ return true; -+ } -+ -+ -+ /* -+ * Start fraction DMA here for remain bytes transfer (<64Bytes). -+ */ -+ l2_dma_info[id].dma_frac_start = true; -+ l2_frac_dma((unsigned long)l2_dma_info[id].dma_frac_addr, id, -+ l2_dma_info[id].dma_frac_offset, l2_dma_info[id].dma_frac_data_len, -+ l2_dma_info[id].direction, false); -+ -+ } -+ -+ /* -+ * Fraction DMA handling starts here. -+ */ -+ if (l2_dma_info[id].dma_frac_start) { -+ timeout = 0; -+ do { -+ dmareq = rL2_DMAREQ; -+ } while((dmareq & L2_DMA_REQ_FRAC_DMA_REQ) && (timeout++ < max_wait_time)); -+ -+ l2_dma_info[id].dma_frac_start = false; -+ -+ if (timeout >= max_wait_time) { -+ printk("l2:wait frac dma timeout, buf id=%d, status=%d.\n", id, l2_get_status(id)); -+ return false; -+ } -+ -+ if ((l2_dma_info[id].direction == MEM2BUF) && -+ (l2_dma_info[id].dma_frac_data_len < 60)) { -+ -+ unsigned int bufaddr; -+ -+ bufaddr = l2_get_addr(id); -+ write_buf(0, bufaddr + (l2_dma_info[id].dma_frac_offset & 0x1FF) + 60); -+ } -+ } -+ -+ return true; -+} -+ -+/** -+ * l2_interrupt_handler - L2 memory interrupt handler -+ * @irq: IRQ number for L2 memory (Must be IRQ_L2MEM) -+ * @dev_id: Device specific information used by interrupt handler -+ * -+ * NOTE: Only shared IRQ need to check @irq & @dev_id. -+ * No need to check them here since L2 memory IRQ is NOT shared IRQ. -+ */ -+static irqreturn_t l2_interrupt_handler(int irq, void *dev_id) -+{ -+ unsigned long regval; -+ int i = 0; -+ -+ regval = rL2_DMAREQ; -+ -+ for (i = 0; i < L2_COMMON_BUFFER_NUM; i++) { -+ unsigned long dmapending = regval & (1 << ( i + L2_DMA_REQ_BUF_START)); -+ -+ if (l2_dma_info[i].dma_start && !dmapending) { -+ if (!l2_frac_started && l2_dma_info[i].need_frac) { -+ l2_dma_info[i].dma_frac_start = true; -+ l2_dma_info[i].dma_start = false; -+ -+ l2_frac_dma((unsigned long)l2_dma_info[i].dma_frac_addr, i, -+ l2_dma_info[i].dma_frac_offset, l2_dma_info[i].dma_frac_data_len, -+ l2_dma_info[i].direction, true); -+ -+ l2_frac_started = true; -+ } else { -+ /* DMA has finished */ -+ unsigned long regval; -+ -+ regval = rL2_BUFINTEN; -+ regval &= ~(1 << (i + L2_DMA_INTR_ENABLE_BUF_START)); -+ rL2_BUFINTEN = regval; -+ -+ l2_dma_info[i].dma_start = false; -+ -+ if (l2_dma_info[i].callback_func != NULL) -+ l2_dma_info[i].callback_func(l2_dma_info[i].data); -+ -+ } -+ } -+ -+ if (l2_dma_info[i].dma_frac_start) { -+ unsigned long frac_dmapending = regval & L2_DMA_REQ_FRAC_DMA_REQ; -+ if (l2_frac_started && !frac_dmapending) { -+ l2_frac_started = false; -+ -+ switch (l2_dma_info[i].direction) { -+ case MEM2BUF: -+ if (l2_dma_info[i].dma_frac_data_len <= 60) -+ __raw_writel(0x0, AK_VA_L2MEM + i * 512 + 0x1FC); -+ break; -+ case BUF2MEM: -+ if (l2_dma_info[i].dma_frac_data_len <= 512 - 4) -+ l2_clear_dma(i); -+ break; -+ default: -+ BUG(); -+ } -+ l2_dma_info[i].dma_frac_start = false; -+ -+ if (l2_dma_info[i].callback_func != NULL) -+ l2_dma_info[i].callback_func(l2_dma_info[i].data); -+ -+ } -+ } -+ -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * l2_cpu - Transfer data between memory and l2 buffer in CPU mode -+ * @ram_addr: External RAM address(Physical) -+ * @id: L2 buffer ID -+ * @buf_offset: The buffer offset -+ * @bytes: Data transfer size -+ * @direction: Data transfer direction between L2 memory and external RAM -+ */ -+static void l2_cpu(unsigned long ram_addr, u8 id, -+ unsigned long buf_offset, unsigned int bytes, l2_dma_transfer_direction_t direction) -+{ -+ int i; -+ int j; -+ unsigned long trans_no; -+ unsigned long frac_no; -+ unsigned long buf_count; -+ unsigned long buf_remain; -+ unsigned long temp_ram; -+ unsigned long temp_buf; -+ unsigned long bufaddr; -+ -+ /* -+ * L2 buffer caller MUST guarantee L2 buffer offset is 4-byte aligned -+ */ -+ if (unlikely(buf_offset % 4)) -+ BUG(); -+ -+ bufaddr = l2_get_addr(id); -+ -+ if (bufaddr == 0) { -+ return ; -+ } -+ -+ bufaddr += buf_offset; -+ trans_no = bytes / 4; -+ frac_no = bytes % 4; -+ -+ buf_count = (buf_offset + bytes) / L2_BUF_STATUS_MULTIPLY_RATIO; -+ buf_remain = (buf_offset + bytes) % L2_BUF_STATUS_MULTIPLY_RATIO; -+ -+ switch (direction) { -+ case MEM2BUF: -+ if (ram_addr % 4) { -+ for (i = 0; i < trans_no; i++) { -+ temp_ram = 0; -+ for (j = 0; j < 4; j++) -+ temp_ram |= ((read_ramb(ram_addr + i*4 + j))<<(j*8)); -+ write_buf(temp_ram, (bufaddr + i * 4)); -+ } -+ if (frac_no) { -+ temp_ram = 0; -+ for (j = 0; j < frac_no; j++) -+ temp_ram |= ((read_ramb(ram_addr + trans_no*4 + j))<<(j*8)); -+ write_buf(temp_ram, (bufaddr + trans_no * 4)); -+ } -+ } else { -+ for (i = 0; i < trans_no; i++) -+ write_buf(read_raml(ram_addr + i*4), (bufaddr + i*4)); -+ if (frac_no) -+ write_buf(read_raml(ram_addr + trans_no*4), (bufaddr + trans_no*4)); -+ } -+ -+ /* -+ * If we do NOT write data to L2 in multiple of 64Bytes, we must write something to the 4Bytes in 64Bytes- -+ * boundary so that CPU knows writing ends.. -+ */ -+ if ((buf_remain > 0) && (buf_remain <= L2_BUF_STATUS_MULTIPLY_RATIO - 4)) -+ write_buf(0, (bufaddr - buf_offset + buf_count*L2_BUF_STATUS_MULTIPLY_RATIO + L2_BUF_STATUS_MULTIPLY_RATIO - 4)); -+ break; -+ case BUF2MEM: -+ if (ram_addr % 4) { -+ for (i = 0; i < trans_no; i++) { -+ temp_buf = read_buf(bufaddr + i * 4); -+ for (j = 0; j < 4; j++) -+ write_ramb((u8)((temp_buf>>j*8) & 0xFF), (ram_addr + i*4 + j)); -+ } -+ if (frac_no) { -+ temp_buf = read_buf(bufaddr+trans_no*4); -+ for (j = 0; j < frac_no; j++) -+ write_ramb((u8)((temp_buf>>j*8) & 0xFF), (ram_addr + trans_no*4 + j)); -+ } -+ } else { -+ for (i = 0; i < trans_no; i++) -+ write_raml(read_buf(bufaddr+i*4), (ram_addr+i*4)); -+ if (frac_no) { -+ temp_buf = read_buf(bufaddr+trans_no*4); -+ temp_ram = read_raml(ram_addr+trans_no*4); -+ temp_buf &= ((1<<(frac_no*8+1))-1); -+ temp_ram &= ~((1<<(frac_no*8+1))-1); -+ temp_ram |= temp_buf; -+ write_raml(temp_ram, (ram_addr+trans_no*4)); -+ } -+ } -+ -+ /* -+ * If we do NOT read data from L2 in multiple of 64Bytes, we must read the 4Bytes in 64Bytes- -+ * boundary so that CPU knows reading ends.. -+ */ -+ if ((buf_remain > 0) && (buf_remain <= L2_BUF_STATUS_MULTIPLY_RATIO - 4)) -+ temp_buf = read_buf(bufaddr-buf_offset+buf_count*L2_BUF_STATUS_MULTIPLY_RATIO+L2_BUF_STATUS_MULTIPLY_RATIO - 4); -+ break; -+ default: -+ BUG(); -+ } -+ -+} -+ -+ -+/** -+ * l2_init - Initialize linux kernel L2 memory support -+ */ -+void __init l2_init(void) -+{ -+ int i; -+ int retval; -+ -+ /* -+ * Enable L2 controller working clock -+ */ -+ l2_enable_clock(true); -+ -+ /* -+ * Initialize all L2 common buffer status to IDLE(could be allocated) -+ */ -+ for (i = 0; i < L2_COMMON_BUFFER_NUM; i++) { -+ l2_buffer_info[i].id = (u8)i; -+ l2_buffer_info[i].usable = L2_STAT_IDLE; -+ l2_buffer_info[i].used_time = 0; -+ } -+ -+ /* L2 Memory Register initializations */ -+ rL2_DMAREQ = L2_DMA_REQ_EN; -+ rL2_FRACDMAADDR = L2_FRAC_DMA_AHB_FLAG_EN | L2_FRAC_DMA_LDMA_FLAG_EN; -+ rL2_CONBUF0_7 = 0x0; -+ rL2_CONBUF8_15 = L2_UART_BUF_CFG_UART_EN_MASK | L2_UART_BUF_CFG_UART_CLR_MASK; -+ rL2_BUFINTEN = 0x0; -+ rL2_BUFASSIGN1 = 0x0; -+ rL2_BUFASSIGN2 = 0x0; -+ -+ /* Initialize L2 DMA information status */ -+ memset(l2_dma_info, 0, ARRAY_SIZE(l2_dma_info)); -+ -+ /* Initialize global L2 fraction DMA start flag */ -+ l2_frac_started = false; -+ -+ init_waitqueue_head(&l2_wq); -+ -+ /* L2 Memory Interrupt handler registered */ -+ if ((retval = request_irq(IRQ_L2MEM, &l2_interrupt_handler, IRQF_DISABLED, "l2", NULL)) < 0) -+ printk(KERN_ERR "l2: failed to request_irq, irq number: %d, retval=%d.\n", IRQ_L2MEM, retval); -+ -+ printk("On-chip L2 memory initialized\n"); -+} -+ -+/** -+ * __l2_alloc - Allocate a common L2 buffer for given device -+ * @device: Device ID which need common L2 buffer -+ * Return L2 buffer ID (0 ~ 7) -+ * -+ * Only common L2 buffers(ID 0 ~ 7) could be allocated by __l2_alloc. -+ * Other L2 buffers (UART/USB used) is handled by corresponding devices directly. -+ */ -+static u8 __l2_alloc(l2_device_t device, bool need_wait) -+{ -+ int i; -+ u16 used_times = MAX_L2_BUFFER_USED_TIMES; -+ u8 id = BUF_NULL; -+ u8 first_id = BUF_NULL; -+ unsigned long flags; -+ bool l2_allocated = false; -+ -+ if (unlikely(device == ADDR_RESERVED)) { -+ printk("l2: unable to allocate l2 buffer for reserved device.\n"); -+ -+ return BUF_NULL; -+ } -+ -+ if (unlikely(l2_device_info[(u8)device].id != BUF_NULL)) { -+ printk("l2: device %d already have a l2 buffer %d\n", -+ (int)(u8)device, (int)(u8)l2_device_info[(u8)device].id); -+ -+ return l2_device_info[(u8)device].id; -+ } -+ -+ do { -+ local_irq_save(flags); -+ -+ l2_allocated = false; -+ -+ for (i = 1; i < L2_COMMON_BUFFER_NUM; i++) { -+ if (l2_buffer_info[i].usable == L2_STAT_IDLE) { -+ if (first_id == BUF_NULL) { -+ first_id = l2_buffer_info[i].id; -+ used_times = l2_buffer_info[i].used_time; -+ id = first_id; -+ } -+ if (l2_buffer_info[i].used_time < used_times) { -+ used_times = l2_buffer_info[i].used_time; -+ id = l2_buffer_info[i].id; -+ } -+ } -+ } -+ -+ if (unlikely(first_id == BUF_NULL)) { -+ if(!need_wait) { -+ local_irq_restore(flags); -+ return BUF_NULL; -+ } -+ local_irq_restore(flags); -+ l2_wait = 0; -+ wait_event(l2_wq, l2_wait); -+ } else { -+ l2_allocated = true; -+ } -+ } while (!l2_allocated); -+ -+ /* -+ * Got a L2 buffer successfully... -+ */ -+ l2_buffer_info[id].usable = L2_STAT_USED; -+ l2_buffer_info[id].used_time++; -+ if (l2_buffer_info[id].used_time == 0) { -+ /* -+ * In case when the new allocated L2 buffer has been used MAX_L2_BUFFER_USED_TIMES, -+ * we just clear all L2 buffer used times as a simpfied method of balancing 8 L2 buffer usage. -+ */ -+ for (i = 0; i < L2_COMMON_BUFFER_NUM; i++) -+ l2_buffer_info[i].used_time = 0; -+ } -+ -+ /* Enable L2 buffer */ -+ l2_combuf_ctrl(id, true); -+ -+ /* Change device info */ -+ l2_device_info[device].id = id; -+ -+ /* Select L2 common buffer for device */ -+ l2_select_combuf(device, id); -+ -+ local_irq_restore(flags); -+ -+ /* Clear L2 buffer status */ -+ l2_clr_status(id); -+ -+ return id; -+} -+ -+u8 l2_alloc(l2_device_t device) -+{ -+ return __l2_alloc(device, true); -+} -+EXPORT_SYMBOL(l2_alloc); -+ -+u8 l2_alloc_nowait(l2_device_t device) -+{ -+ return __l2_alloc(device, false); -+} -+EXPORT_SYMBOL(l2_alloc_nowait); -+ -+/** -+ * l2_free - Free L2 common buffer for given device -+ * @device: Device ID which need common L2 buffer -+ * Return L2 buffer ID (0 ~ 7) -+ * -+ * Only common L2 buffers(ID 0 ~ 7) could be allocated by l2_alloc. -+ * Other L2 buffers (UART/USB used) is handled by corresponding devices directly. -+ * NOTE: Return the previous L2 buffer ID if a L2 buffer has been allocated to the device. -+ * This means one device could get only one L2 buffer maximum. -+ */ -+void l2_free(l2_device_t device) -+{ -+ u8 id; -+ unsigned long regval; -+ unsigned long flags; -+ -+ id = l2_device_info[(u8)device].id; -+ if (unlikely(id == BUF_NULL)) { -+ printk("l2: trying to free invalid buffer id %d\n", (int)id); -+ return ; -+ } -+ -+ l2_clear_dma(id); -+ -+ local_irq_save(flags); -+ -+ /* -+ * Disable DMA interrupt of this L2 buffer. -+ */ -+ regval = rL2_BUFINTEN; -+ regval &= ~(1 << (id + L2_DMA_INTR_ENABLE_BUF_START)); -+ rL2_BUFINTEN = regval; -+ -+ /* Set DMA count to 0 */ -+ __raw_writel(0x0, vL2DMA_CONBUF0 + id * 4); -+ -+ /* Disable this L2 buffer */ -+ l2_combuf_ctrl(id, false); -+ l2_deselect_combuf(device, id); -+ -+ /* Clear DMA & DMA fraction flags */ -+ if (l2_dma_info[id].dma_start || l2_dma_info[id].dma_frac_start) { -+ l2_dma_info[id].dma_start = false; -+ l2_dma_info[id].dma_frac_start = false; -+ } -+ -+ l2_dma_info[id].callback_func = NULL; -+ l2_dma_info[id].data = 0; -+ -+ l2_device_info[(u8)device].id = BUF_NULL; -+ l2_buffer_info[id].usable = L2_STAT_IDLE; -+ -+ l2_wait = 1; -+ wake_up(&l2_wq); -+ -+ local_irq_restore(flags); -+ -+} -+EXPORT_SYMBOL(l2_free); -+ -+/** -+ * l2_set_dma_callback - Set callback function when L2 DMA/fraction DMA interrupt handler is done -+ * @id: L2 buffer ID -+ * @func: Callback function -+ * Return true(Always) -+ * -+ * NOTE: Caller MUST guarantee that L2 buffer ID is valid. And since the callback function is called -+ * in interrupt handler, it MUST NOT call any functions which may sleep. -+ */ -+bool l2_set_dma_callback(u8 id, l2_callback_func_t func, unsigned long data) -+{ -+ if (unlikely(id >= L2_COMMON_BUFFER_NUM)) { -+ printk(KERN_ERR "l2: Set dma callback, invalid buf id[%d].\n", id); -+ return false; -+ } -+ -+ if (unlikely(l2_dma_info[id].dma_start || l2_dma_info[id].dma_frac_start)) { -+ printk(KERN_ERR "l2: Set dma callback, dma not finished.\n"); -+ return false; -+ } -+ -+ l2_dma_info[id].callback_func = func; -+ l2_dma_info[id].data = data; -+ -+ return true; -+} -+EXPORT_SYMBOL(l2_set_dma_callback); -+ -+/** -+ * l2_combuf_dma - Start data tranferring between memory and l2 common buffer in DMA mode -+ * @ram_addr: External RAM address(Physical) -+ * @id: L2 buffer ID involved in DMA transfer -+ * @bytes: Data transfer size -+ * @direction: Data transfer direction between L2 memory and external RAM -+ * @intr_enable: Open interrupt for this L2 buffer or not -+ */ -+void l2_combuf_dma(unsigned long ram_addr, u8 id, unsigned int bytes, l2_dma_transfer_direction_t direction, bool intr_enable) -+{ -+ if (unlikely(id >= L2_COMMON_BUFFER_NUM)) { -+ printk("l2: begin common buffer dma, error buf id=[%d].\n", id); -+ return ; -+ } -+ -+ l2_dma(ram_addr, id, bytes, direction, intr_enable); -+} -+EXPORT_SYMBOL(l2_combuf_dma); -+ -+/** -+ * l2_combuf_wait_dma_finish - Wait for L2 DMA to finish -+ * @id: L2 buffer ID involved in DMA transfer -+ * Return true: DMA transfer finished successfully. -+ * false: DMA transfer failed. -+ * NOTE: DMA transfer is started by l2_combuf_dma. -+ */ -+bool l2_combuf_wait_dma_finish(u8 id) -+{ -+ if (unlikely(id >= L2_COMMON_BUFFER_NUM)) { -+ printk("l2: begin common buffer dma, error buf id=[%d].\n", id); -+ return false; -+ } -+ return l2_wait_dma_finish(id); -+} -+EXPORT_SYMBOL(l2_combuf_wait_dma_finish); -+ -+/** -+ * l2_combuf_cpu - Transfer data between memory and l2 common buffer in CPU mode -+ * @ram_addr: External RAM address(Physical) -+ * @id: L2 buffer ID -+ * @bytes: Data transfer size -+ * @direction: Data transfer direction between L2 memory and external RAM -+ * -+ * NOTE: According to XuChang, if one transfer data from Peripheral --> L2 Buffer --> RAM, -+ * special care need to be taken when data size is NOT multiple of 64Bytes. -+ * Pheripheral driver must check hardware signals to confirm data has been transfer from -+ * peripheral to L2 buffer since L2 do NOT provide some mechanism to confirm data has -+ * been in L2 Buffer. Driver can and only can call l2_combuf_cpu() to copy data from L2 -+ * Buffer --> RAM after checking hardware signals. -+ * As to 64Bytes * n size data, L2 could check Buffer Status Status Counter to confirm that -+ * Data has been transfer from peripheral to L2 buffer, so no hardware signals checking needed. -+ */ -+void l2_combuf_cpu(unsigned long ram_addr, u8 id, -+ unsigned int bytes, l2_dma_transfer_direction_t direction) -+{ -+ int i; -+ int loop; -+ int remain; -+ -+ loop = bytes / L2_BUF_STATUS_MULTIPLY_RATIO; -+ remain = bytes % L2_BUF_STATUS_MULTIPLY_RATIO; -+ -+ switch (direction) { -+ case MEM2BUF: -+ for (i = 0; i < loop; i++) { -+ -+ while (l2_get_status(id) == (L2_BUFFER_SIZE / L2_BUF_STATUS_MULTIPLY_RATIO)) -+ ; /* Waiting for L2 buffer to NOT full(means writable) */ -+ -+ l2_cpu(ram_addr + i * L2_BUF_STATUS_MULTIPLY_RATIO, id, -+ (i % 8) * L2_BUF_STATUS_MULTIPLY_RATIO, L2_BUF_STATUS_MULTIPLY_RATIO, direction); -+ } -+ if (remain > 0) { -+ while (l2_get_status(id) > 0) -+ ; /* Waiting for L2 buffer to empty */ -+ -+ l2_cpu(ram_addr + loop * L2_BUF_STATUS_MULTIPLY_RATIO, id, -+ (loop % 8) * L2_BUF_STATUS_MULTIPLY_RATIO, remain, direction); -+ } -+ break; -+ case BUF2MEM: -+ for (i = 0; i < loop; i++) { -+ while (l2_get_status(id) == 0) -+ ; /* Waiting for L2 buffer to be not empty (means readable) */ -+ -+ l2_cpu(ram_addr + i * L2_BUF_STATUS_MULTIPLY_RATIO, id, -+ (i % 8) * L2_BUF_STATUS_MULTIPLY_RATIO, L2_BUF_STATUS_MULTIPLY_RATIO, direction); -+ -+ } -+ if (remain > 0) { -+ l2_cpu(ram_addr + loop * L2_BUF_STATUS_MULTIPLY_RATIO, id, -+ (loop % 8) * L2_BUF_STATUS_MULTIPLY_RATIO, remain, direction); -+ } -+ break; -+ default: -+ BUG(); -+ } -+} -+EXPORT_SYMBOL(l2_combuf_cpu); -+ -+/** -+ * l2_get_status - Get L2 buffer status -+ * @id: L2 buffer ID -+ */ -+u8 l2_get_status(u8 id) -+{ -+ l2_assert_buf_id(id); -+ -+ return (id < L2_COMMON_BUFFER_NUM) ? (rL2_BUFSTAT1 >> (id * 4)) & 0xF : -+ (rL2_BUFSTAT2 >> ((id - L2_UART_BUF_START_ID) << 1)) & 0x3; -+} -+EXPORT_SYMBOL(l2_get_status); -+ -+/** -+ * l2_clr_status - Clear L2 buffer status -+ * @id: L2 buffer ID -+ */ -+void l2_clr_status(u8 id) -+{ -+ unsigned long flags; -+ -+ l2_assert_buf_id(id); -+ -+ local_irq_save(flags); -+ -+ if (id < L2_COMMON_BUFFER_NUM) { -+ rL2_CONBUF0_7 |= 1 << (id + L2_COMMON_BUF_CFG_BUF_CLR_START); -+ } else { -+ rL2_CONBUF8_15 |= (1 << (id - L2_UART_BUF_START_ID + L2_UART_BUF_CFG_BUF_START)); -+ } -+ -+ local_irq_restore(flags); -+ -+} -+EXPORT_SYMBOL(l2_clr_status); -+ -+/** -+ * l2_set_status - Clear L2 buffer status -+ * @id: L2 buffer ID -+ * @status: Status to be set (0 ~ 8) -+ */ -+void l2_set_status(u8 id, u8 status) -+{ -+ unsigned long regval; -+ unsigned long flags; -+ -+ l2_assert_buf_id(id); -+ -+ if ((id >= L2_COMMON_BUFFER_NUM) || status > MAX_L2_DMA_STATUS_VALUE) -+ BUG(); -+ -+ local_irq_save(flags); -+ -+ /* -+ * Enable CPU-controlled buffer function and set L2 buffer `id' status -+ * status = current number of data in the CPU controlled buffer. -+ */ -+ regval = rL2_CONBUF8_15; -+ regval &= ~(L2_UART_BUF_CFG_CPU_BUF_NUM_MASK | L2_UART_BUF_CFG_CPU_BUF_SEL_EN | -+ L2_UART_BUF_CFG_CPU_BUF_SEL_MASK); -+ regval |= (id << L2_UART_BUF_CFG_CPU_BUF_SEL_START) | L2_UART_BUF_CFG_CPU_BUF_SEL_EN | -+ (status << L2_UART_BUF_CFG_CPU_BUF_NUM_START); -+ rL2_CONBUF8_15 = regval; -+ -+ /* -+ * Disable CPU-controlled buffer function -+ */ -+ regval = rL2_CONBUF8_15; -+ regval &= ~(L2_UART_BUF_CFG_CPU_BUF_NUM_MASK | L2_UART_BUF_CFG_CPU_BUF_SEL_EN | -+ L2_UART_BUF_CFG_CPU_BUF_SEL_MASK); -+ rL2_CONBUF8_15 = regval; -+ -+ local_irq_restore(flags); -+ -+} -+EXPORT_SYMBOL(l2_set_status); -diff --git a/arch/arm/plat-anyka/l2_exebuf.c b/arch/arm/plat-anyka/l2_exebuf.c -new file mode 100755 -index 00000000..50cb314e ---- /dev/null -+++ b/arch/arm/plat-anyka/l2_exebuf.c -@@ -0,0 +1,67 @@ -+/* -+ * arch/arm/plat-anyka/l2_exebuf.c -+ */ -+#include <linux/kernel.h> -+#include <linux/interrupt.h> -+#include <plat/l2_exebuf.h> -+ -+// #define PM_DEBUG -+#define L2_BUFFER0_SIZE 512 -+ -+void (*jumpto_L2)(unsigned long param1,unsigned long param2, -+ unsigned long param3,unsigned long param4); -+ -+static void pm_print_info(const char *start, int len) -+{ -+#ifdef PM_DEBUG -+ int i; -+ unsigned char local_l2mem[L2_BUFFER0_SIZE] = {0} ; -+ -+ printk("start = %p, len = %d\n", start, len); -+ for (i = 0; i < len; i += 4) { -+ *(unsigned long *)(local_l2mem + i) = -+ *(volatile unsigned long *)(AK_VA_L2MEM + i); -+ } -+ for (i = 0; i < len; i++) { -+ printk(" 0x%02x", local_l2mem[i]); -+ if (i % 16 == 15) printk("\n"); -+ } -+#endif -+} -+ -+ -+/* -+ * copy from ddr2 to l2 memory to run, and exit standby -+ */ -+int l2_exec_buf(const char *vaddr, int len, unsigned long param1, -+unsigned long param2,unsigned long param3,unsigned long param4) -+{ -+ unsigned long i, flags ; -+ -+ //disable ARM interrupt -+ local_irq_save(flags); -+ -+ memset((void *)AK_VA_L2MEM, 0, L2_BUFFER0_SIZE); -+ -+ //copy from ddr2 to l2 memory -+ for (i = 0; i < len; i += 4) { -+ *(volatile unsigned long *)(AK_VA_L2MEM + i) = -+ *(unsigned long *)(vaddr + i); -+ } -+ -+ pm_print_info(vaddr, len); -+ -+ REG32(AK_VA_L2CTRL + 0x84) &= ~(1 << 29); -+ -+ //jumpto_L2 run -+ jumpto_L2 = (void *)(AK_VA_L2MEM); -+ jumpto_L2(param1,param2,param3,param4); -+ -+ REG32(AK_VA_L2CTRL + 0x84) |= (1 << 29); -+ -+ //enable ARM interrupt -+ local_irq_restore(flags); -+ return 0; -+} -+ -+ -diff --git a/arch/arm/plat-anyka/notify.c b/arch/arm/plat-anyka/notify.c -new file mode 100755 -index 00000000..32e8127c ---- /dev/null -+++ b/arch/arm/plat-anyka/notify.c -@@ -0,0 +1,97 @@ -+/* -+ * power_notify.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+#include <linux/device.h> -+#include <linux/module.h> -+#include <linux/notifier.h> -+#include <plat-anyka/notify.h> -+ -+static BLOCKING_NOTIFIER_HEAD(power_notifier_list); -+static BLOCKING_NOTIFIER_HEAD(addetect_notifier_list); -+ -+/* -+ * @brief register a power client notifier -+ * @author Li Xiaoping -+ * @date 2011-08-02 -+ * @param [in] nb notifier block to callback on events -+ * @return 0 -+ */ -+int power_register_client(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_register(&power_notifier_list, nb); -+} -+EXPORT_SYMBOL(power_register_client); -+ -+/* -+ * @brief unregister a power client notifier -+ * @author Li Xiaoping -+ * @date 2011-08-02 -+ * @param [in] nb notifier block to callback on events -+ * @return 0 -+ */ -+int power_unregister_client(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_unregister(&power_notifier_list, nb); -+} -+EXPORT_SYMBOL(power_unregister_client); -+ -+/* -+ * @brief notify clients of power_events -+ * @author Li Xiaoping -+ * @date 2011-08-02 -+ * @param [in] val - notifier events dispatch to clients -+ * @param [in] v - event data associated with events -+ * @return 0 -+ */ -+int power_notifier_call_chain(unsigned long val, void *v) -+{ -+ return blocking_notifier_call_chain(&power_notifier_list, val, v); -+} -+EXPORT_SYMBOL_GPL(power_notifier_call_chain); -+ -+ -+/* -+ * @brief register a ad detect notifier -+ * @author caolianming -+ * @date 2012-09-28 -+ * @param [in] nb notifier block to callback on events -+ * @return 0 -+ */ -+int addetect_register_client(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_register(&addetect_notifier_list, nb); -+} -+EXPORT_SYMBOL(addetect_register_client); -+ -+/* -+ * @brief unregister a ad detect client notifier -+ * @author caolianming -+ * @date 2012-09-28 -+ * @param [in] nb notifier block to callback on events -+ * @return 0 -+ */ -+int addetect_unregister_client(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_unregister(&addetect_notifier_list, nb); -+} -+EXPORT_SYMBOL(addetect_unregister_client); -+ -+/* -+ * @brief notify clients of ad deteced events -+ * @author caolianming -+ * @date 2012-09-28 -+ * @param [in] val - notifier events dispatch to clients -+ * @param [in] v - event data associated with events -+ * @return 0 -+ */ -+int addetect_notifier_call_chain(unsigned long val, void *v) -+{ -+ return blocking_notifier_call_chain(&addetect_notifier_list, val, v); -+} -+EXPORT_SYMBOL_GPL(addetect_notifier_call_chain); -+ -diff --git a/arch/arm/plat-anyka/reg.c b/arch/arm/plat-anyka/reg.c -new file mode 100644 -index 00000000..b00ee54a ---- /dev/null -+++ b/arch/arm/plat-anyka/reg.c -@@ -0,0 +1,50 @@ -+/* -+ * reg.c - Register Access Routines -+ * -+ * 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/io.h> -+#include <mach/reg.h> -+#include <mach/map.h> -+ -+static DEFINE_SPINLOCK(sys_ctrl_reg_lock); -+ -+/* -+ * @brief Anyka system control register setting routine -+ * @author Li Xiaoping -+ * @date 2011-07-04 -+ * @param reg_phy_addr [in] Register Physical Address -+ * @param reg_mask [in] Bit mask of the bits which need to be set -+ * @param reg_val [in] The value of the bits which need to be set -+ * @return void -+ * @note This routine is created in order to solve the problem of access the sam system control -+ * register from different kernel path (ISR, system call, etc...). -+ * @note This routine depends on that corresponding registers are mapped, currently this is -+ * done in akxx_map_io(), so be careful about akxx_map_io() changes. -+ * the akxx_ is instead of ak37_. -+ * @sample sys_ctrl_reg_set(0x0800000C, (1 << 29), (1 << 29)) will set bit 29 of -+ * Clock Control and Soft Reset Control Register to 1 -+ */ -+void sys_ctrl_reg_set(unsigned long reg_phy_addr, unsigned long reg_mask, unsigned long reg_val) -+{ -+ unsigned long flags; -+ unsigned long val; -+ unsigned long reg_virt_addr; -+ -+ BUG_ON((reg_phy_addr < AK_PA_SYSCTRL) || (reg_phy_addr > (AK_PA_SYSCTRL + AK_SZ_SYSCTRL))); -+ -+ spin_lock_irqsave(&sys_ctrl_reg_lock, flags); -+ -+ reg_virt_addr = (unsigned long)AK_VA_SYSCTRL + reg_phy_addr - AK_PA_SYSCTRL; -+ val = __raw_readl(reg_virt_addr); -+ val = (val & ~reg_mask) | (reg_val & reg_mask); -+ __raw_writel(val, reg_virt_addr); -+ -+ spin_unlock_irqrestore(&sys_ctrl_reg_lock, flags); -+} -+EXPORT_SYMBOL(sys_ctrl_reg_set); -diff --git a/arch/arm/plat-anyka/rtc.c b/arch/arm/plat-anyka/rtc.c -new file mode 100644 -index 00000000..85043e09 ---- /dev/null -+++ b/arch/arm/plat-anyka/rtc.c -@@ -0,0 +1,367 @@ -+/* -+ * linux/arch/arm/plat-anyka/rtc.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/rtc.h> -+#include <linux/delay.h> -+#include <asm/mach/time.h> -+#include <plat/rtc.h> -+ -+static int rtc_cnt = 0; -+ -+#undef REG32 -+#define REG32(_reg_) (*(volatile unsigned long *)(_reg_)) -+ -+//reboot system by watchdog -+void ak_reboot_sys_by_wtd(void) -+{ -+ unsigned long val; -+ unsigned long flags; -+ //static spinlock_t loc_lock; -+ -+ //spin_lock_init(&loc_lock); -+ //spin_lock(&loc_lock); -+ local_irq_save(flags); -+ ak_rtc_power(RTC_ON); -+ -+ //select wdt -+ val = ak_rtc_read(AK_RTC_SETTING); -+ val |= (1 << 10); -+ ak_rtc_write(AK_RTC_SETTING, val); -+ -+ //clear timer -+ val = ak_rtc_read(AK_RTC_SETTING); -+ val |= (1<<6); -+ ak_rtc_write(AK_RTC_SETTING, val); -+ -+ -+ //enable watchdog timer -+ val = ak_rtc_read(AK_WDT_RTC_TIMER_CONF); -+ val |= (1<<13); -+ ak_rtc_write(AK_WDT_RTC_TIMER_CONF, val); -+ -+ //set timer -+ val = ak_rtc_read(AK_WDT_RTC_TIMER_CONF); -+ val &= (1<<13); -+ val |= (5 & 0x1FFF); -+ ak_rtc_write(AK_WDT_RTC_TIMER_CONF, val); -+ -+ -+ //open watchdog and watchdog output -+ val = ak_rtc_read(AK_RTC_SETTING); -+ val |= ((1<<5) | (1<<2)); -+ val &= ~(1<<11); -+ ak_rtc_write(AK_RTC_SETTING, val); -+ -+ local_irq_restore(flags); -+// spin_unlock(&loc_lock); -+} -+EXPORT_SYMBOL(ak_reboot_sys_by_wtd); -+ -+void ak_reboot_sys_by_wakeup(void) -+{ -+ //static spinlock_t loc_lock; -+ struct rtc_time ptm; -+ struct rtc_time *tm = &ptm; -+ //unsigned char mdays[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; -+ unsigned long flags; -+ -+ unsigned long rtcset; -+ unsigned long rtc_time1; -+ unsigned long rtc_time2; -+ unsigned long rtc_time3; -+ -+ unsigned long rtc_alarm1; -+ unsigned long rtc_alarm2; -+ unsigned long rtc_alarm3; -+ unsigned int val_1, val_2; -+ unsigned long time; -+ -+ //spin_lock_init(&loc_lock); -+ //spin_lock(&loc_lock); -+ local_irq_save(flags); -+ ak_rtc_power(RTC_ON); -+ -+ rtcset = ak_rtc_read(AK_RTC_SETTING); -+ rtcset |= RTC_SETTING_REAL_TIME_RE; -+ ak_rtc_write(AK_RTC_SETTING, rtcset); -+ -+ rtc_time1 = ak_rtc_read(AK_RTC_REAL_TIME1); -+ rtc_time2 = ak_rtc_read(AK_RTC_REAL_TIME2); -+ rtc_time3 = ak_rtc_read(AK_RTC_REAL_TIME3); -+ -+ tm->tm_year = ((rtc_time3 >> 4) & 0x7F) - EPOCH_START_YEAR + RTC_START_YEAR; -+ tm->tm_mon = (rtc_time3 & 0xF) - 1; -+ tm->tm_mday = (rtc_time2 >> 5) & 0x1F; -+ tm->tm_hour = rtc_time2 & 0x1F; -+ tm->tm_min = (rtc_time1 >> 6) & 0x3F; -+ tm->tm_sec = rtc_time1 & 0x3F; -+ tm->tm_wday = (rtc_time2 >> 10) & 0x7; -+ tm->tm_isdst = -1; -+ -+ rtc_alarm1 = ak_rtc_read(AK_RTC_ALARM_TIME1); -+ rtc_alarm2 = ak_rtc_read(AK_RTC_ALARM_TIME2); -+ rtc_alarm3 = ak_rtc_read(AK_RTC_ALARM_TIME3); -+ -+ -+ rtc_alarm1 &= ~(0xFFF); -+ rtc_alarm2 &= ~(0x3FF); -+ rtc_alarm3 &= ~(0x7FF); -+ -+ #define DELAY_TIME 5 -+ -+ rtc_tm_to_time(tm, &time); -+ -+ time += DELAY_TIME; -+ -+ rtc_time_to_tm(time, tm); -+ /*tm->tm_sec += DELAY_TIME; -+ -+ if (tm->tm_sec >= 60) -+ { -+ tm->tm_sec -= 60; -+ tm->tm_min++; -+ if (tm->tm_min >= 60) -+ { -+ tm->tm_min = 0; -+ tm->tm_hour++; -+ if (tm->tm_hour >= 24) -+ { -+ tm->tm_hour = 0; -+ tm->tm_mday++; -+ if ((tm->tm_year%400==0) || ((tm->tm_year%100!=0) && (tm->tm_year%4==0))) -+ mdays[2] = 29; -+ if (tm->tm_mday > mdays[tm->tm_mon]) -+ { -+ tm->tm_mday = 1; -+ tm->tm_mon++; -+ if (tm->tm_mon > 12) -+ { -+ tm->tm_mon = 1; -+ tm->tm_year++; -+ } -+ } -+ } -+ } -+ -+ }*/ -+ rtc_alarm1 |= ((tm->tm_min << 6) + tm->tm_sec); -+ rtc_alarm2 |= ((tm->tm_mday << 5) + tm->tm_hour); -+ rtc_alarm3 |= (((tm->tm_year + EPOCH_START_YEAR - RTC_START_YEAR) << 4) + (tm->tm_mon + 1)); -+ -+ ak_rtc_write(AK_RTC_ALARM_TIME1, rtc_alarm1); -+ ak_rtc_write(AK_RTC_ALARM_TIME2, rtc_alarm2); -+ ak_rtc_write(AK_RTC_ALARM_TIME3, rtc_alarm3); -+ -+ val_1 = REG32(OTHER_WAKEUP_CTRL); -+ -+ -+ val_2 = ak_rtc_read(AK_RTC_SETTING); -+ -+ if (1) -+ { -+ /* enable wakeup signal */ -+ val_1 |= RTC_WAKEUP_EN;// | RTC_WAKEUP_SIGNAL_LOWACTIVE); -+ REG32(OTHER_WAKEUP_CTRL) = val_1; -+ -+ val_2 |= (1<<2); -+ ak_rtc_write(AK_RTC_SETTING, val_2); -+ } -+ -+ rtc_alarm1 = ak_rtc_read(AK_RTC_ALARM_TIME1); -+ rtc_alarm2 = ak_rtc_read(AK_RTC_ALARM_TIME2); -+ rtc_alarm3 = ak_rtc_read(AK_RTC_ALARM_TIME3); -+ -+ rtc_alarm1 |= (1<<13); -+ rtc_alarm2 |= (1<<13); -+ rtc_alarm3 |= (1<<13); -+ -+ ak_rtc_write(AK_RTC_ALARM_TIME1, rtc_alarm1); -+ ak_rtc_write(AK_RTC_ALARM_TIME2, rtc_alarm2); -+ ak_rtc_write(AK_RTC_ALARM_TIME3, rtc_alarm3); -+ -+ local_irq_restore(flags); -+// spin_unlock(&loc_lock); -+ ak_rtc_set_wpin(0); -+} -+ -+EXPORT_SYMBOL(ak_reboot_sys_by_wakeup); -+ -+void ak_rtc_power(int op) -+{ -+ unsigned long rtcconf; -+ -+ switch(op) -+ { -+ case RTC_ON: -+ if (++rtc_cnt == 1) -+ { -+ rtcconf = __raw_readl(AK_RTC_CONF); -+ rtcconf |= RTC_CONF_RTC_EN; -+ __raw_writel(rtcconf, AK_RTC_CONF); -+ } -+ break; -+ /* -+ When RTC is powered off, this bit(AK_RTC_CONF [24] ) should be set to 0 -+ */ -+ case RTC_OFF: -+ if (!(--rtc_cnt)) -+ { -+ rtcconf = __raw_readl(AK_RTC_CONF); -+ rtcconf &= ~RTC_CONF_RTC_EN; -+ __raw_writel(rtcconf, AK_RTC_CONF); -+ } -+ break; -+ default: -+ printk("Error RTC power operation.\n"); -+ break; -+ } -+} -+ -+EXPORT_SYMBOL(ak_rtc_power); -+ -+/* -+* check if internal rtc works or not -+* return -1 no rtc device;0 have rtc device -+*/ -+int test_rtc_inter_reg(unsigned int addr) -+{ -+ unsigned long regval = 0; -+ unsigned long flags; -+ int timeout = 0; -+ int ret = 0; -+ -+ local_irq_save(flags); -+ -+ // unmask rtc_ready irq -+ regval = __raw_readl(RTC_RDY_INT_CTRL); -+ __raw_writel(regval | (RTC_RDY_CTRL_BIT), RTC_RDY_INT_CTRL); -+ -+ // wait for more 1ms to access rtc register -+ while (!(__raw_readl(RTC_RDY_INT_STAT) & RTC_RDY_STAT_BIT)) -+ { -+ if (timeout++ > 1000) -+ { -+ ret = -1; -+ break; -+ } -+ udelay(1); -+ } -+ -+ // mask rtc_ready irq -+ regval = __raw_readl(RTC_RDY_INT_CTRL); -+ __raw_writel(regval & ~(RTC_RDY_CTRL_BIT), RTC_RDY_INT_CTRL); -+ -+ local_irq_restore(flags); -+ return ret; -+} -+EXPORT_SYMBOL(test_rtc_inter_reg); -+ -+unsigned int ak_rtc_read(unsigned int addr) -+{ -+ unsigned long regval = 0; -+ unsigned long flags; -+ -+ if (addr > AK_RTC_REG_MAX) { -+ printk("%s(): Invalid RTC Register, address=%d\n", -+ __func__, addr); -+ return -1; -+ } -+ -+ local_irq_save(flags); -+ -+ rtc_ready_irq_enable(); -+ -+ regval = __raw_readl(AK_RTC_CONF); -+ regval &= ~(0x3FFFFF) ; -+ regval |= (RTC_CONF_RTC_READ | (addr << 14)); -+ __raw_writel(regval, AK_RTC_CONF); -+ -+ udelay(100); -+ -+ ak_rtc_wait_ready(); -+ rtc_ready_irq_disable(); -+ local_irq_restore(flags); -+ -+ // according to ATC drivers ,this want to wait 1/32K s here -+ udelay(312); -+ -+ regval = __raw_readl(AK_RTC_DATA); -+ regval &= 0x3FFF; -+ -+ return regval; -+} -+EXPORT_SYMBOL(ak_rtc_read); -+ -+unsigned int ak_rtc_write(unsigned int addr, unsigned int value) -+{ -+ unsigned long regval = 0; -+ unsigned long flags; -+ -+ if (addr > AK_RTC_REG_MAX) { -+ printk("%s(): Invalid RTC Register, address=%d\n", -+ __func__, addr); -+ return -1; -+ } -+ -+ local_irq_save(flags); -+ -+ rtc_ready_irq_enable(); -+ -+ regval = __raw_readl(AK_RTC_CONF); -+ regval &= ~0x3FFFFF; -+ regval |= (RTC_CONF_RTC_WRITE | (addr << 14) | value); -+ __raw_writel(regval, AK_RTC_CONF); -+ -+ udelay(100); -+ -+ ak_rtc_wait_ready(); -+ -+ rtc_ready_irq_disable(); -+ -+ local_irq_restore(flags); -+ -+ // according to ATC drivers ,this want to wait 1/32K s here -+ udelay(312); -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_rtc_write); -+ -+unsigned int ak_rtc_set_wpin(bool level) -+{ -+ unsigned long regval; -+ unsigned int bit; -+ unsigned int timeout = 0; -+ -+ ak_rtc_power(RTC_ON); -+ -+ if (test_rtc_inter_reg(0) < 0) { -+ printk("Board has not RTC support. exit %s\n", __func__); -+ ak_rtc_power(RTC_OFF); -+ return -ENODEV; -+ } -+ -+ bit = level ? 8 : 7; -+ printk("---ak_rtc_set_wpin:%d---\r\n", bit); -+ regval = ak_rtc_read(AK_RTC_SETTING); -+ regval |= (1 << bit); -+ ak_rtc_write(AK_RTC_SETTING, regval); -+ -+ while (ak_rtc_read(AK_RTC_SETTING) & (1 << bit)) { -+ ++timeout; -+ if (timeout >= RTC_WAIT_TIME_OUT) { -+ //printk("--ak_rtc_set_wpin--\n"); -+ break; -+ } -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(ak_rtc_set_wpin); -diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types -index f9c9f33f..9ee01ada 100644 ---- a/arch/arm/tools/mach-types -+++ b/arch/arm/tools/mach-types -@@ -1169,3 +1169,4 @@ elite_ulk MACH_ELITE_ULK ELITE_ULK 3888 - pov2 MACH_POV2 POV2 3889 - ipod_touch_2g MACH_IPOD_TOUCH_2G IPOD_TOUCH_2G 3890 - da850_pqab MACH_DA850_PQAB DA850_PQAB 3891 -+anyka_ak39xx MACH_AK39XX AK39XX 3892 -diff --git a/arch/x86/include/asm/idle.h b/arch/x86/include/asm/idle.h -index c5d17853..02bab097 100644 ---- a/arch/x86/include/asm/idle.h -+++ b/arch/x86/include/asm/idle.h -@@ -1,13 +1,6 @@ - #ifndef _ASM_X86_IDLE_H - #define _ASM_X86_IDLE_H - --#define IDLE_START 1 --#define IDLE_END 2 -- --struct notifier_block; --void idle_notifier_register(struct notifier_block *n); --void idle_notifier_unregister(struct notifier_block *n); -- - #ifdef CONFIG_X86_64 - void enter_idle(void); - void exit_idle(void); -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 1d92a5ab..fdd151ce 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -29,19 +29,6 @@ - - #ifdef CONFIG_X86_64 - static DEFINE_PER_CPU(unsigned char, is_idle); --static ATOMIC_NOTIFIER_HEAD(idle_notifier); -- --void idle_notifier_register(struct notifier_block *n) --{ -- atomic_notifier_chain_register(&idle_notifier, n); --} --EXPORT_SYMBOL_GPL(idle_notifier_register); -- --void idle_notifier_unregister(struct notifier_block *n) --{ -- atomic_notifier_chain_unregister(&idle_notifier, n); --} --EXPORT_SYMBOL_GPL(idle_notifier_unregister); - #endif - - struct kmem_cache *task_xstate_cachep; -@@ -378,14 +365,14 @@ static inline void play_dead(void) - void enter_idle(void) - { - percpu_write(is_idle, 1); -- atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); -+ idle_notifier_call_chain(IDLE_START); - } - - static void __exit_idle(void) - { - if (x86_test_and_clear_bit_percpu(0, is_idle) == 0) - return; -- atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); -+ idle_notifier_call_chain(IDLE_END); - } - - /* Called from interrupts to signify idle end */ -diff --git a/block/genhd.c b/block/genhd.c -index 60108d9f..2ade7561 100644 ---- a/block/genhd.c -+++ b/block/genhd.c -@@ -1110,6 +1110,22 @@ static void disk_release(struct device *dev) - blk_put_queue(disk->queue); - kfree(disk); - } -+ -+static int disk_uevent(struct device *dev, struct kobj_uevent_env *env) -+{ -+ struct gendisk *disk = dev_to_disk(dev); -+ struct disk_part_iter piter; -+ struct hd_struct *part; -+ int cnt = 0; -+ -+ disk_part_iter_init(&piter, disk, 0); -+ while((part = disk_part_iter_next(&piter))) -+ cnt++; -+ disk_part_iter_exit(&piter); -+ add_uevent_var(env, "NPARTS=%u", cnt); -+ return 0; -+} -+ - struct class block_class = { - .name = "block", - }; -@@ -1128,6 +1144,7 @@ static struct device_type disk_type = { - .groups = disk_attr_groups, - .release = disk_release, - .devnode = block_devnode, -+ .uevent = disk_uevent, - }; - - #ifdef CONFIG_PROC_FS -diff --git a/block/partition-generic.c b/block/partition-generic.c -index 7b8b8d17..264028c3 100644 ---- a/block/partition-generic.c -+++ b/block/partition-generic.c -@@ -216,10 +216,21 @@ static void part_release(struct device *dev) - kfree(p); - } - -+static int part_uevent(struct device *dev, struct kobj_uevent_env *env) -+{ -+ struct hd_struct *part = dev_to_part(dev); -+ -+ add_uevent_var(env, "PARTN=%u", part->partno); -+ if (part->info && part->info->volname[0]) -+ add_uevent_var(env, "PARTNAME=%s", part->info->volname); -+ return 0; -+} -+ - struct device_type part_type = { - .name = "partition", - .groups = part_attr_groups, - .release = part_release, -+ .uevent = part_uevent, - }; - - static void delete_partition_rcu_cb(struct rcu_head *head) -diff --git a/drivers/Kconfig b/drivers/Kconfig -index d236aef7..a765f400 100644 ---- a/drivers/Kconfig -+++ b/drivers/Kconfig -@@ -96,6 +96,8 @@ source "drivers/memstick/Kconfig" - - source "drivers/leds/Kconfig" - -+source "drivers/switch/Kconfig" -+ - source "drivers/accessibility/Kconfig" - - source "drivers/infiniband/Kconfig" -diff --git a/drivers/Makefile b/drivers/Makefile -index 95952c82..b5d2823d 100644 ---- a/drivers/Makefile -+++ b/drivers/Makefile -@@ -100,6 +100,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle/ - obj-y += mmc/ - obj-$(CONFIG_MEMSTICK) += memstick/ - obj-y += leds/ -+obj-$(CONFIG_SWITCH) += switch/ - obj-$(CONFIG_INFINIBAND) += infiniband/ - obj-$(CONFIG_SGI_SN) += sn/ - obj-y += firmware/ -diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig -index 9aa618ac..1131dd73 100644 ---- a/drivers/base/Kconfig -+++ b/drivers/base/Kconfig -@@ -192,4 +192,30 @@ config DMA_SHARED_BUFFER - APIs extension; the file's descriptor can then be passed on to other - driver. - -+config SYNC -+ bool "Synchronization framework" -+ default n -+ select ANON_INODES -+ help -+ This option enables the framework for synchronization between multiple -+ drivers. Sync implementations can take advantage of hardware -+ synchronization built into devices like GPUs. -+ -+config SW_SYNC -+ bool "Software synchronization objects" -+ default n -+ depends on SYNC -+ help -+ A sync object driver that uses a 32bit counter to coordinate -+ syncrhronization. Useful when there is no hardware primitive backing -+ the synchronization. -+ -+config SW_SYNC_USER -+ bool "Userspace API for SW_SYNC" -+ default n -+ depends on SW_SYNC -+ help -+ Provides a user space API to the sw sync object. -+ *WARNING* improper use of this can result in deadlocking kernel -+ drivers from userspace. - endmenu -diff --git a/drivers/base/Makefile b/drivers/base/Makefile -index b6d1b9c4..0e4d3dad 100644 ---- a/drivers/base/Makefile -+++ b/drivers/base/Makefile -@@ -21,5 +21,8 @@ obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o - obj-$(CONFIG_REGMAP) += regmap/ - obj-$(CONFIG_SOC_BUS) += soc.o - -+obj-$(CONFIG_SYNC) += sync.o -+obj-$(CONFIG_SW_SYNC) += sw_sync.o -+ - ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG - -diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c -index 07cbbc6f..7cfb405b 100644 ---- a/drivers/base/dma-buf.c -+++ b/drivers/base/dma-buf.c -@@ -44,8 +44,26 @@ static int dma_buf_release(struct inode *inode, struct file *file) - return 0; - } - -+static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) -+{ -+ struct dma_buf *dmabuf; -+ -+ if (!is_dma_buf_file(file)) -+ return -EINVAL; -+ -+ dmabuf = file->private_data; -+ -+ /* check for overflowing the buffer's size */ -+ if (vma->vm_pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > -+ dmabuf->size >> PAGE_SHIFT) -+ return -EINVAL; -+ -+ return dmabuf->ops->mmap(dmabuf, vma); -+} -+ - static const struct file_operations dma_buf_fops = { - .release = dma_buf_release, -+ .mmap = dma_buf_mmap_internal, - }; - - /* -@@ -82,7 +100,8 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, - || !ops->unmap_dma_buf - || !ops->release - || !ops->kmap_atomic -- || !ops->kmap)) { -+ || !ops->kmap -+ || !ops->mmap)) { - return ERR_PTR(-EINVAL); - } - -@@ -406,3 +425,46 @@ void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num, - dmabuf->ops->kunmap(dmabuf, page_num, vaddr); - } - EXPORT_SYMBOL_GPL(dma_buf_kunmap); -+ -+ -+/** -+ * dma_buf_mmap - Setup up a userspace mmap with the given vma -+ * @dma_buf: [in] buffer that should back the vma -+ * @vma: [in] vma for the mmap -+ * @pgoff: [in] offset in pages where this mmap should start within the -+ * dma-buf buffer. -+ * -+ * This function adjusts the passed in vma so that it points at the file of the -+ * dma_buf operation. It alsog adjusts the starting pgoff and does bounds -+ * checking on the size of the vma. Then it calls the exporters mmap function to -+ * set up the mapping. -+ * -+ * Can return negative error values, returns 0 on success. -+ */ -+int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, -+ unsigned long pgoff) -+{ -+ if (WARN_ON(!dmabuf || !vma)) -+ return -EINVAL; -+ -+ /* check for offset overflow */ -+ if (pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) < pgoff) -+ return -EOVERFLOW; -+ -+ /* check for overflowing the buffer's size */ -+ if (pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > -+ dmabuf->size >> PAGE_SHIFT) -+ return -EINVAL; -+ -+ /* readjust the vma */ -+ if (vma->vm_file) -+ fput(vma->vm_file); -+ -+ vma->vm_file = dmabuf->file; -+ get_file(vma->vm_file); -+ -+ vma->vm_pgoff = pgoff; -+ -+ return dmabuf->ops->mmap(dmabuf, vma); -+} -+EXPORT_SYMBOL_GPL(dma_buf_mmap); -diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c -index 73ce9fbe..83aa694a 100644 ---- a/drivers/base/power/domain.c -+++ b/drivers/base/power/domain.c -@@ -11,6 +11,7 @@ - #include <linux/io.h> - #include <linux/pm_runtime.h> - #include <linux/pm_domain.h> -+#include <linux/pm_qos.h> - #include <linux/slab.h> - #include <linux/err.h> - #include <linux/sched.h> -@@ -38,11 +39,13 @@ - ktime_t __start = ktime_get(); \ - type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \ - s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \ -- struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \ -- if (__elapsed > __gpd_data->td.field) { \ -- __gpd_data->td.field = __elapsed; \ -+ struct gpd_timing_data *__td = &dev_gpd_data(dev)->td; \ -+ if (!__retval && __elapsed > __td->field) { \ -+ __td->field = __elapsed; \ - dev_warn(dev, name " latency exceeded, new value %lld ns\n", \ - __elapsed); \ -+ genpd->max_off_time_changed = true; \ -+ __td->constraint_changed = true; \ - } \ - __retval; \ - }) -@@ -211,6 +214,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd) - elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); - if (elapsed_ns > genpd->power_on_latency_ns) { - genpd->power_on_latency_ns = elapsed_ns; -+ genpd->max_off_time_changed = true; - if (genpd->name) - pr_warning("%s: Power-on latency exceeded, " - "new value %lld ns\n", genpd->name, -@@ -247,6 +251,53 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd) - - #ifdef CONFIG_PM_RUNTIME - -+static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, -+ unsigned long val, void *ptr) -+{ -+ struct generic_pm_domain_data *gpd_data; -+ struct device *dev; -+ -+ gpd_data = container_of(nb, struct generic_pm_domain_data, nb); -+ -+ mutex_lock(&gpd_data->lock); -+ dev = gpd_data->base.dev; -+ if (!dev) { -+ mutex_unlock(&gpd_data->lock); -+ return NOTIFY_DONE; -+ } -+ mutex_unlock(&gpd_data->lock); -+ -+ for (;;) { -+ struct generic_pm_domain *genpd; -+ struct pm_domain_data *pdd; -+ -+ spin_lock_irq(&dev->power.lock); -+ -+ pdd = dev->power.subsys_data ? -+ dev->power.subsys_data->domain_data : NULL; -+ if (pdd) { -+ to_gpd_data(pdd)->td.constraint_changed = true; -+ genpd = dev_to_genpd(dev); -+ } else { -+ genpd = ERR_PTR(-ENODATA); -+ } -+ -+ spin_unlock_irq(&dev->power.lock); -+ -+ if (!IS_ERR(genpd)) { -+ mutex_lock(&genpd->lock); -+ genpd->max_off_time_changed = true; -+ mutex_unlock(&genpd->lock); -+ } -+ -+ dev = dev->parent; -+ if (!dev || dev->power.ignore_children) -+ break; -+ } -+ -+ return NOTIFY_DONE; -+} -+ - /** - * __pm_genpd_save_device - Save the pre-suspend state of a device. - * @pdd: Domain data of the device to save the state of. -@@ -435,6 +486,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) - elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); - if (elapsed_ns > genpd->power_off_latency_ns) { - genpd->power_off_latency_ns = elapsed_ns; -+ genpd->max_off_time_changed = true; - if (genpd->name) - pr_warning("%s: Power-off latency exceeded, " - "new value %lld ns\n", genpd->name, -@@ -443,17 +495,6 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) - } - - genpd->status = GPD_STATE_POWER_OFF; -- genpd->power_off_time = ktime_get(); -- -- /* Update PM QoS information for devices in the domain. */ -- list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) { -- struct gpd_timing_data *td = &to_gpd_data(pdd)->td; -- -- pm_runtime_update_max_time_suspended(pdd->dev, -- td->start_latency_ns + -- td->restore_state_latency_ns + -- genpd->power_on_latency_ns); -- } - - list_for_each_entry(link, &genpd->slave_links, slave_node) { - genpd_sd_counter_dec(link->master); -@@ -514,9 +555,6 @@ static int pm_genpd_runtime_suspend(struct device *dev) - if (ret) - return ret; - -- pm_runtime_update_max_time_suspended(dev, -- dev_gpd_data(dev)->td.start_latency_ns); -- - /* - * If power.irq_safe is set, this routine will be run with interrupts - * off, so it can't use mutexes. -@@ -613,6 +651,12 @@ void pm_genpd_poweroff_unused(void) - - #else - -+static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb, -+ unsigned long val, void *ptr) -+{ -+ return NOTIFY_DONE; -+} -+ - static inline void genpd_power_off_work_fn(struct work_struct *work) {} - - #define pm_genpd_runtime_suspend NULL -@@ -1209,12 +1253,15 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, - if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) - return -EINVAL; - -- genpd_acquire_lock(genpd); -+ gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); -+ if (!gpd_data) -+ return -ENOMEM; - -- if (genpd->status == GPD_STATE_POWER_OFF) { -- ret = -EINVAL; -- goto out; -- } -+ mutex_init(&gpd_data->lock); -+ gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; -+ dev_pm_qos_add_notifier(dev, &gpd_data->nb); -+ -+ genpd_acquire_lock(genpd); - - if (genpd->prepared_count > 0) { - ret = -EAGAIN; -@@ -1227,26 +1274,35 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, - goto out; - } - -- gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); -- if (!gpd_data) { -- ret = -ENOMEM; -- goto out; -- } -- - genpd->device_count++; -+ genpd->max_off_time_changed = true; - -- dev->pm_domain = &genpd->domain; - dev_pm_get_subsys_data(dev); -+ -+ mutex_lock(&gpd_data->lock); -+ spin_lock_irq(&dev->power.lock); -+ dev->pm_domain = &genpd->domain; - dev->power.subsys_data->domain_data = &gpd_data->base; - gpd_data->base.dev = dev; -- gpd_data->need_restore = false; - list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); -+ gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF; - if (td) - gpd_data->td = *td; - -+ gpd_data->td.constraint_changed = true; -+ gpd_data->td.effective_constraint_ns = -1; -+ spin_unlock_irq(&dev->power.lock); -+ mutex_unlock(&gpd_data->lock); -+ -+ genpd_release_lock(genpd); -+ -+ return 0; -+ - out: - genpd_release_lock(genpd); - -+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb); -+ kfree(gpd_data); - return ret; - } - -@@ -1290,12 +1346,15 @@ int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev, - int pm_genpd_remove_device(struct generic_pm_domain *genpd, - struct device *dev) - { -+ struct generic_pm_domain_data *gpd_data; - struct pm_domain_data *pdd; -- int ret = -EINVAL; -+ int ret = 0; - - dev_dbg(dev, "%s()\n", __func__); - -- if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) -+ if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev) -+ || IS_ERR_OR_NULL(dev->pm_domain) -+ || pd_to_genpd(dev->pm_domain) != genpd) - return -EINVAL; - - genpd_acquire_lock(genpd); -@@ -1305,21 +1364,27 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, - goto out; - } - -- list_for_each_entry(pdd, &genpd->dev_list, list_node) { -- if (pdd->dev != dev) -- continue; -+ genpd->device_count--; -+ genpd->max_off_time_changed = true; - -- list_del_init(&pdd->list_node); -- pdd->dev = NULL; -- dev_pm_put_subsys_data(dev); -- dev->pm_domain = NULL; -- kfree(to_gpd_data(pdd)); -+ spin_lock_irq(&dev->power.lock); -+ dev->pm_domain = NULL; -+ pdd = dev->power.subsys_data->domain_data; -+ list_del_init(&pdd->list_node); -+ dev->power.subsys_data->domain_data = NULL; -+ spin_unlock_irq(&dev->power.lock); - -- genpd->device_count--; -+ gpd_data = to_gpd_data(pdd); -+ mutex_lock(&gpd_data->lock); -+ pdd->dev = NULL; -+ mutex_unlock(&gpd_data->lock); - -- ret = 0; -- break; -- } -+ genpd_release_lock(genpd); -+ -+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb); -+ kfree(gpd_data); -+ dev_pm_put_subsys_data(dev); -+ return 0; - - out: - genpd_release_lock(genpd); -@@ -1347,6 +1412,26 @@ void pm_genpd_dev_always_on(struct device *dev, bool val) - } - EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on); - -+/** -+ * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag. -+ * @dev: Device to set/unset the flag for. -+ * @val: The new value of the device's "need restore" flag. -+ */ -+void pm_genpd_dev_need_restore(struct device *dev, bool val) -+{ -+ struct pm_subsys_data *psd; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->power.lock, flags); -+ -+ psd = dev_to_psd(dev); -+ if (psd && psd->domain_data) -+ to_gpd_data(psd->domain_data)->need_restore = val; -+ -+ spin_unlock_irqrestore(&dev->power.lock, flags); -+} -+EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore); -+ - /** - * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. - * @genpd: Master PM domain to add the subdomain to. -@@ -1378,7 +1463,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, - goto out; - } - -- list_for_each_entry(link, &genpd->slave_links, slave_node) { -+ list_for_each_entry(link, &genpd->master_links, master_node) { - if (link->slave == subdomain && link->master == genpd) { - ret = -EINVAL; - goto out; -@@ -1690,6 +1775,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd, - genpd->resume_count = 0; - genpd->device_count = 0; - genpd->max_off_time_ns = -1; -+ genpd->max_off_time_changed = true; - genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; - genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; - genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; -diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c -index 66a265bf..28dee305 100644 ---- a/drivers/base/power/domain_governor.c -+++ b/drivers/base/power/domain_governor.c -@@ -14,6 +14,31 @@ - - #ifdef CONFIG_PM_RUNTIME - -+static int dev_update_qos_constraint(struct device *dev, void *data) -+{ -+ s64 *constraint_ns_p = data; -+ s32 constraint_ns = -1; -+ -+ if (dev->power.subsys_data && dev->power.subsys_data->domain_data) -+ constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns; -+ -+ if (constraint_ns < 0) { -+ constraint_ns = dev_pm_qos_read_value(dev); -+ constraint_ns *= NSEC_PER_USEC; -+ } -+ if (constraint_ns == 0) -+ return 0; -+ -+ /* -+ * constraint_ns cannot be negative here, because the device has been -+ * suspended. -+ */ -+ if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0) -+ *constraint_ns_p = constraint_ns; -+ -+ return 0; -+} -+ - /** - * default_stop_ok - Default PM domain governor routine for stopping devices. - * @dev: Device to check. -@@ -21,14 +46,52 @@ - bool default_stop_ok(struct device *dev) - { - struct gpd_timing_data *td = &dev_gpd_data(dev)->td; -+ unsigned long flags; -+ s64 constraint_ns; - - dev_dbg(dev, "%s()\n", __func__); - -- if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0) -- return true; -+ spin_lock_irqsave(&dev->power.lock, flags); -+ -+ if (!td->constraint_changed) { -+ bool ret = td->cached_stop_ok; - -- return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns -- && td->break_even_ns < dev->power.max_time_suspended_ns; -+ spin_unlock_irqrestore(&dev->power.lock, flags); -+ return ret; -+ } -+ td->constraint_changed = false; -+ td->cached_stop_ok = false; -+ td->effective_constraint_ns = -1; -+ constraint_ns = __dev_pm_qos_read_value(dev); -+ -+ spin_unlock_irqrestore(&dev->power.lock, flags); -+ -+ if (constraint_ns < 0) -+ return false; -+ -+ constraint_ns *= NSEC_PER_USEC; -+ /* -+ * We can walk the children without any additional locking, because -+ * they all have been suspended at this point and their -+ * effective_constraint_ns fields won't be modified in parallel with us. -+ */ -+ if (!dev->power.ignore_children) -+ device_for_each_child(dev, &constraint_ns, -+ dev_update_qos_constraint); -+ -+ if (constraint_ns > 0) { -+ constraint_ns -= td->start_latency_ns; -+ if (constraint_ns == 0) -+ return false; -+ } -+ td->effective_constraint_ns = constraint_ns; -+ td->cached_stop_ok = constraint_ns > td->stop_latency_ns || -+ constraint_ns == 0; -+ /* -+ * The children have been suspended already, so we don't need to take -+ * their stop latencies into account here. -+ */ -+ return td->cached_stop_ok; - } - - /** -@@ -42,9 +105,27 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) - struct generic_pm_domain *genpd = pd_to_genpd(pd); - struct gpd_link *link; - struct pm_domain_data *pdd; -- s64 min_dev_off_time_ns; -+ s64 min_off_time_ns; - s64 off_on_time_ns; -- ktime_t time_now = ktime_get(); -+ -+ if (genpd->max_off_time_changed) { -+ struct gpd_link *link; -+ -+ /* -+ * We have to invalidate the cached results for the masters, so -+ * use the observation that default_power_down_ok() is not -+ * going to be called for any master until this instance -+ * returns. -+ */ -+ list_for_each_entry(link, &genpd->slave_links, slave_node) -+ link->master->max_off_time_changed = true; -+ -+ genpd->max_off_time_changed = false; -+ genpd->cached_power_down_ok = false; -+ genpd->max_off_time_ns = -1; -+ } else { -+ return genpd->cached_power_down_ok; -+ } - - off_on_time_ns = genpd->power_off_latency_ns + - genpd->power_on_latency_ns; -@@ -61,6 +142,7 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) - to_gpd_data(pdd)->td.save_state_latency_ns; - } - -+ min_off_time_ns = -1; - /* - * Check if subdomains can be off for enough time. - * -@@ -73,8 +155,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) - if (sd_max_off_ns < 0) - continue; - -- sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now, -- sd->power_off_time)); - /* - * Check if the subdomain is allowed to be off long enough for - * the current domain to turn off and on (that's how much time -@@ -82,60 +162,64 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) - */ - if (sd_max_off_ns <= off_on_time_ns) - return false; -+ -+ if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0) -+ min_off_time_ns = sd_max_off_ns; - } - - /* - * Check if the devices in the domain can be off enough time. - */ -- min_dev_off_time_ns = -1; - list_for_each_entry(pdd, &genpd->dev_list, list_node) { - struct gpd_timing_data *td; -- struct device *dev = pdd->dev; -- s64 dev_off_time_ns; -+ s64 constraint_ns; - -- if (!dev->driver || dev->power.max_time_suspended_ns < 0) -+ if (!pdd->dev->driver) - continue; - -+ /* -+ * Check if the device is allowed to be off long enough for the -+ * domain to turn off and on (that's how much time it will -+ * have to wait worst case). -+ */ - td = &to_gpd_data(pdd)->td; -- dev_off_time_ns = dev->power.max_time_suspended_ns - -- (td->start_latency_ns + td->restore_state_latency_ns + -- ktime_to_ns(ktime_sub(time_now, -- dev->power.suspend_time))); -- if (dev_off_time_ns <= off_on_time_ns) -- return false; -- -- if (min_dev_off_time_ns > dev_off_time_ns -- || min_dev_off_time_ns < 0) -- min_dev_off_time_ns = dev_off_time_ns; -- } -+ constraint_ns = td->effective_constraint_ns; -+ /* default_stop_ok() need not be called before us. */ -+ if (constraint_ns < 0) { -+ constraint_ns = dev_pm_qos_read_value(pdd->dev); -+ constraint_ns *= NSEC_PER_USEC; -+ } -+ if (constraint_ns == 0) -+ continue; - -- if (min_dev_off_time_ns < 0) { - /* -- * There are no latency constraints, so the domain can spend -- * arbitrary time in the "off" state. -+ * constraint_ns cannot be negative here, because the device has -+ * been suspended. - */ -- genpd->max_off_time_ns = -1; -- return true; -+ constraint_ns -= td->restore_state_latency_ns; -+ if (constraint_ns <= off_on_time_ns) -+ return false; -+ -+ if (min_off_time_ns > constraint_ns || min_off_time_ns < 0) -+ min_off_time_ns = constraint_ns; - } - -+ genpd->cached_power_down_ok = true; -+ - /* -- * The difference between the computed minimum delta and the time needed -- * to turn the domain on is the maximum theoretical time this domain can -- * spend in the "off" state. -+ * If the computed minimum device off time is negative, there are no -+ * latency constraints, so the domain can spend arbitrary time in the -+ * "off" state. - */ -- min_dev_off_time_ns -= genpd->power_on_latency_ns; -+ if (min_off_time_ns < 0) -+ return true; - - /* -- * If the difference between the computed minimum delta and the time -- * needed to turn the domain off and back on on is smaller than the -- * domain's power break even time, removing power from the domain is not -- * worth it. -+ * The difference between the computed minimum subdomain or device off -+ * time and the time needed to turn the domain on is the maximum -+ * theoretical time this domain can spend in the "off" state. - */ -- if (genpd->break_even_ns > -- min_dev_off_time_ns - genpd->power_off_latency_ns) -- return false; -- -- genpd->max_off_time_ns = min_dev_off_time_ns; -+ genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns; - return true; - } - -diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c -index ebc272f8..77e3b97b 100644 ---- a/drivers/base/power/main.c -+++ b/drivers/base/power/main.c -@@ -28,6 +28,7 @@ - #include <linux/sched.h> - #include <linux/async.h> - #include <linux/suspend.h> -+#include <linux/timer.h> - - #include "../base.h" - #include "power.h" -@@ -54,6 +55,12 @@ struct suspend_stats suspend_stats; - static DEFINE_MUTEX(dpm_list_mtx); - static pm_message_t pm_transition; - -+struct dpm_watchdog { -+ struct device *dev; -+ struct task_struct *tsk; -+ struct timer_list timer; -+}; -+ - static int async_error; - - /** -@@ -389,6 +396,56 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, - return error; - } - -+/** -+ * dpm_wd_handler - Driver suspend / resume watchdog handler. -+ * -+ * Called when a driver has timed out suspending or resuming. -+ * There's not much we can do here to recover so BUG() out for -+ * a crash-dump -+ */ -+static void dpm_wd_handler(unsigned long data) -+{ -+ struct dpm_watchdog *wd = (void *)data; -+ struct device *dev = wd->dev; -+ struct task_struct *tsk = wd->tsk; -+ -+ dev_emerg(dev, "**** DPM device timeout ****\n"); -+ show_stack(tsk, NULL); -+ -+ BUG(); -+} -+ -+/** -+ * dpm_wd_set - Enable pm watchdog for given device. -+ * @wd: Watchdog. Must be allocated on the stack. -+ * @dev: Device to handle. -+ */ -+static void dpm_wd_set(struct dpm_watchdog *wd, struct device *dev) -+{ -+ struct timer_list *timer = &wd->timer; -+ -+ wd->dev = dev; -+ wd->tsk = get_current(); -+ -+ init_timer_on_stack(timer); -+ timer->expires = jiffies + HZ * 12; -+ timer->function = dpm_wd_handler; -+ timer->data = (unsigned long)wd; -+ add_timer(timer); -+} -+ -+/** -+ * dpm_wd_clear - Disable pm watchdog. -+ * @wd: Watchdog to disable. -+ */ -+static void dpm_wd_clear(struct dpm_watchdog *wd) -+{ -+ struct timer_list *timer = &wd->timer; -+ -+ del_timer_sync(timer); -+ destroy_timer_on_stack(timer); -+} -+ - /*------------------------- Resume routines -------------------------*/ - - /** -@@ -565,6 +622,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) - char *info = NULL; - int error = 0; - bool put = false; -+ struct dpm_watchdog wd; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); -@@ -577,6 +635,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) - * a resumed device, even if the device hasn't been completed yet. - */ - dev->power.is_prepared = false; -+ dpm_wd_set(&wd, dev); - - if (!dev->power.is_suspended) - goto Unlock; -@@ -631,6 +690,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) - - Unlock: - device_unlock(dev); -+ dpm_wd_clear(&wd); - complete_all(&dev->power.completion); - - TRACE_RESUME(error); -@@ -889,6 +949,11 @@ static int dpm_suspend_noirq(pm_message_t state) - if (!list_empty(&dev->power.entry)) - list_move(&dev->power.entry, &dpm_noirq_list); - put_device(dev); -+ -+ if (pm_wakeup_pending()) { -+ error = -EBUSY; -+ break; -+ } - } - mutex_unlock(&dpm_list_mtx); - if (error) -@@ -962,6 +1027,11 @@ static int dpm_suspend_late(pm_message_t state) - if (!list_empty(&dev->power.entry)) - list_move(&dev->power.entry, &dpm_late_early_list); - put_device(dev); -+ -+ if (pm_wakeup_pending()) { -+ error = -EBUSY; -+ break; -+ } - } - mutex_unlock(&dpm_list_mtx); - if (error) -@@ -1025,6 +1095,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) - pm_callback_t callback = NULL; - char *info = NULL; - int error = 0; -+ struct dpm_watchdog wd; - - dpm_wait_for_children(dev, async); - -@@ -1041,6 +1112,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) - goto Complete; - } - -+ dpm_wd_set(&wd, dev); -+ - device_lock(dev); - - if (dev->pm_domain) { -@@ -1096,6 +1169,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) - - device_unlock(dev); - -+ dpm_wd_clear(&wd); -+ - Complete: - complete_all(&dev->power.completion); - -diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c -index c365c93a..b95ebf2d 100644 ---- a/drivers/base/power/qos.c -+++ b/drivers/base/power/qos.c -@@ -352,21 +352,26 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request); - * - * Will register the notifier into a notification chain that gets called - * upon changes to the target value for the device. -+ * -+ * If the device's constraints object doesn't exist when this routine is called, -+ * it will be created (or error code will be returned if that fails). - */ - int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier) - { -- int retval = 0; -+ int ret = 0; - - mutex_lock(&dev_pm_qos_mtx); - -- /* Silently return if the constraints object is not present. */ -- if (dev->power.constraints) -- retval = blocking_notifier_chain_register( -- dev->power.constraints->notifiers, -- notifier); -+ if (!dev->power.constraints) -+ ret = dev->power.power_state.event != PM_EVENT_INVALID ? -+ dev_pm_qos_constraints_allocate(dev) : -ENODEV; -+ -+ if (!ret) -+ ret = blocking_notifier_chain_register( -+ dev->power.constraints->notifiers, notifier); - - mutex_unlock(&dev_pm_qos_mtx); -- return retval; -+ return ret; - } - EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier); - -diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c -index bb82b181..b6e9d9b7 100644 ---- a/drivers/base/power/runtime.c -+++ b/drivers/base/power/runtime.c -@@ -282,47 +282,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) - return retval != -EACCES ? retval : -EIO; - } - --struct rpm_qos_data { -- ktime_t time_now; -- s64 constraint_ns; --}; -- --/** -- * rpm_update_qos_constraint - Update a given PM QoS constraint data. -- * @dev: Device whose timing data to use. -- * @data: PM QoS constraint data to update. -- * -- * Use the suspend timing data of @dev to update PM QoS constraint data pointed -- * to by @data. -- */ --static int rpm_update_qos_constraint(struct device *dev, void *data) --{ -- struct rpm_qos_data *qos = data; -- unsigned long flags; -- s64 delta_ns; -- int ret = 0; -- -- spin_lock_irqsave(&dev->power.lock, flags); -- -- if (dev->power.max_time_suspended_ns < 0) -- goto out; -- -- delta_ns = dev->power.max_time_suspended_ns - -- ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time)); -- if (delta_ns <= 0) { -- ret = -EBUSY; -- goto out; -- } -- -- if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0) -- qos->constraint_ns = delta_ns; -- -- out: -- spin_unlock_irqrestore(&dev->power.lock, flags); -- -- return ret; --} -- - /** - * rpm_suspend - Carry out runtime suspend of given device. - * @dev: Device to suspend. -@@ -349,7 +308,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) - { - int (*callback)(struct device *); - struct device *parent = NULL; -- struct rpm_qos_data qos; - int retval; - - trace_rpm_suspend(dev, rpmflags); -@@ -444,38 +402,14 @@ static int rpm_suspend(struct device *dev, int rpmflags) - goto out; - } - -- qos.constraint_ns = __dev_pm_qos_read_value(dev); -- if (qos.constraint_ns < 0) { -- /* Negative constraint means "never suspend". */ -+ if (__dev_pm_qos_read_value(dev) < 0) { -+ /* Negative PM QoS constraint means "never suspend". */ - retval = -EPERM; - goto out; - } -- qos.constraint_ns *= NSEC_PER_USEC; -- qos.time_now = ktime_get(); - - __update_runtime_status(dev, RPM_SUSPENDING); - -- if (!dev->power.ignore_children) { -- if (dev->power.irq_safe) -- spin_unlock(&dev->power.lock); -- else -- spin_unlock_irq(&dev->power.lock); -- -- retval = device_for_each_child(dev, &qos, -- rpm_update_qos_constraint); -- -- if (dev->power.irq_safe) -- spin_lock(&dev->power.lock); -- else -- spin_lock_irq(&dev->power.lock); -- -- if (retval) -- goto fail; -- } -- -- dev->power.suspend_time = qos.time_now; -- dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1; -- - if (dev->pm_domain) - callback = dev->pm_domain->ops.runtime_suspend; - else if (dev->type && dev->type->pm) -@@ -529,8 +463,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) - - fail: - __update_runtime_status(dev, RPM_ACTIVE); -- dev->power.suspend_time = ktime_set(0, 0); -- dev->power.max_time_suspended_ns = -1; - dev->power.deferred_resume = false; - wake_up_all(&dev->power.wait_queue); - -@@ -705,9 +637,6 @@ static int rpm_resume(struct device *dev, int rpmflags) - if (dev->power.no_callbacks) - goto no_callback; /* Assume success. */ - -- dev->power.suspend_time = ktime_set(0, 0); -- dev->power.max_time_suspended_ns = -1; -- - __update_runtime_status(dev, RPM_RESUMING); - - if (dev->pm_domain) -@@ -1370,9 +1299,6 @@ void pm_runtime_init(struct device *dev) - setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn, - (unsigned long)dev); - -- dev->power.suspend_time = ktime_set(0, 0); -- dev->power.max_time_suspended_ns = -1; -- - init_waitqueue_head(&dev->power.wait_queue); - } - -@@ -1390,28 +1316,3 @@ void pm_runtime_remove(struct device *dev) - if (dev->power.irq_safe && dev->parent) - pm_runtime_put_sync(dev->parent); - } -- --/** -- * pm_runtime_update_max_time_suspended - Update device's suspend time data. -- * @dev: Device to handle. -- * @delta_ns: Value to subtract from the device's max_time_suspended_ns field. -- * -- * Update the device's power.max_time_suspended_ns field by subtracting -- * @delta_ns from it. The resulting value of power.max_time_suspended_ns is -- * never negative. -- */ --void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns) --{ -- unsigned long flags; -- -- spin_lock_irqsave(&dev->power.lock, flags); -- -- if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) { -- if (dev->power.max_time_suspended_ns > delta_ns) -- dev->power.max_time_suspended_ns -= delta_ns; -- else -- dev->power.max_time_suspended_ns = 0; -- } -- -- spin_unlock_irqrestore(&dev->power.lock, flags); --} -diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c -index 95c12f6c..48be2ad4 100644 ---- a/drivers/base/power/sysfs.c -+++ b/drivers/base/power/sysfs.c -@@ -314,22 +314,41 @@ static ssize_t wakeup_active_count_show(struct device *dev, - - static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL); - --static ssize_t wakeup_hit_count_show(struct device *dev, -- struct device_attribute *attr, char *buf) -+static ssize_t wakeup_abort_count_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ unsigned long count = 0; -+ bool enabled = false; -+ -+ spin_lock_irq(&dev->power.lock); -+ if (dev->power.wakeup) { -+ count = dev->power.wakeup->wakeup_count; -+ enabled = true; -+ } -+ spin_unlock_irq(&dev->power.lock); -+ return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); -+} -+ -+static DEVICE_ATTR(wakeup_abort_count, 0444, wakeup_abort_count_show, NULL); -+ -+static ssize_t wakeup_expire_count_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) - { - unsigned long count = 0; - bool enabled = false; - - spin_lock_irq(&dev->power.lock); - if (dev->power.wakeup) { -- count = dev->power.wakeup->hit_count; -+ count = dev->power.wakeup->expire_count; - enabled = true; - } - spin_unlock_irq(&dev->power.lock); - return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); - } - --static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL); -+static DEVICE_ATTR(wakeup_expire_count, 0444, wakeup_expire_count_show, NULL); - - static ssize_t wakeup_active_show(struct device *dev, - struct device_attribute *attr, char *buf) -@@ -398,6 +417,27 @@ static ssize_t wakeup_last_time_show(struct device *dev, - } - - static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL); -+ -+#ifdef CONFIG_PM_AUTOSLEEP -+static ssize_t wakeup_prevent_sleep_time_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ s64 msec = 0; -+ bool enabled = false; -+ -+ spin_lock_irq(&dev->power.lock); -+ if (dev->power.wakeup) { -+ msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time); -+ enabled = true; -+ } -+ spin_unlock_irq(&dev->power.lock); -+ return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); -+} -+ -+static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444, -+ wakeup_prevent_sleep_time_show, NULL); -+#endif /* CONFIG_PM_AUTOSLEEP */ - #endif /* CONFIG_PM_SLEEP */ - - #ifdef CONFIG_PM_ADVANCED_DEBUG -@@ -486,11 +526,15 @@ static struct attribute *wakeup_attrs[] = { - &dev_attr_wakeup.attr, - &dev_attr_wakeup_count.attr, - &dev_attr_wakeup_active_count.attr, -- &dev_attr_wakeup_hit_count.attr, -+ &dev_attr_wakeup_abort_count.attr, -+ &dev_attr_wakeup_expire_count.attr, - &dev_attr_wakeup_active.attr, - &dev_attr_wakeup_total_time_ms.attr, - &dev_attr_wakeup_max_time_ms.attr, - &dev_attr_wakeup_last_time_ms.attr, -+#ifdef CONFIG_PM_AUTOSLEEP -+ &dev_attr_wakeup_prevent_sleep_time_ms.attr, -+#endif - #endif - NULL, - }; -diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c -index 2a3e581b..e6ee5e80 100644 ---- a/drivers/base/power/wakeup.c -+++ b/drivers/base/power/wakeup.c -@@ -14,16 +14,15 @@ - #include <linux/suspend.h> - #include <linux/seq_file.h> - #include <linux/debugfs.h> -+#include <trace/events/power.h> - - #include "power.h" - --#define TIMEOUT 100 -- - /* - * If set, the suspend/hibernate code will abort transitions to a sleep state - * if wakeup events are registered during or immediately before the transition. - */ --bool events_check_enabled; -+bool events_check_enabled __read_mostly; - - /* - * Combined counters of registered wakeup events and wakeup events in progress. -@@ -52,6 +51,8 @@ static void pm_wakeup_timer_fn(unsigned long data); - - static LIST_HEAD(wakeup_sources); - -+static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue); -+ - /** - * wakeup_source_prepare - Prepare a new wakeup source for initialization. - * @ws: Wakeup source to prepare. -@@ -126,16 +127,19 @@ EXPORT_SYMBOL_GPL(wakeup_source_destroy); - */ - void wakeup_source_add(struct wakeup_source *ws) - { -+ unsigned long flags; -+ - if (WARN_ON(!ws)) - return; - - spin_lock_init(&ws->lock); - setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws); - ws->active = false; -+ ws->last_time = ktime_get(); - -- spin_lock_irq(&events_lock); -+ spin_lock_irqsave(&events_lock, flags); - list_add_rcu(&ws->entry, &wakeup_sources); -- spin_unlock_irq(&events_lock); -+ spin_unlock_irqrestore(&events_lock, flags); - } - EXPORT_SYMBOL_GPL(wakeup_source_add); - -@@ -145,12 +149,14 @@ EXPORT_SYMBOL_GPL(wakeup_source_add); - */ - void wakeup_source_remove(struct wakeup_source *ws) - { -+ unsigned long flags; -+ - if (WARN_ON(!ws)) - return; - -- spin_lock_irq(&events_lock); -+ spin_lock_irqsave(&events_lock, flags); - list_del_rcu(&ws->entry); -- spin_unlock_irq(&events_lock); -+ spin_unlock_irqrestore(&events_lock, flags); - synchronize_rcu(); - } - EXPORT_SYMBOL_GPL(wakeup_source_remove); -@@ -374,12 +380,33 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_enable); - */ - static void wakeup_source_activate(struct wakeup_source *ws) - { -+ unsigned int cec; -+ - ws->active = true; - ws->active_count++; - ws->last_time = ktime_get(); -+ if (ws->autosleep_enabled) -+ ws->start_prevent_time = ws->last_time; - - /* Increment the counter of events in progress. */ -- atomic_inc(&combined_event_count); -+ cec = atomic_inc_return(&combined_event_count); -+ -+ trace_wakeup_source_activate(ws->name, cec); -+} -+ -+/** -+ * wakeup_source_report_event - Report wakeup event using the given source. -+ * @ws: Wakeup source to report the event for. -+ */ -+static void wakeup_source_report_event(struct wakeup_source *ws) -+{ -+ ws->event_count++; -+ /* This is racy, but the counter is approximate anyway. */ -+ if (events_check_enabled) -+ ws->wakeup_count++; -+ -+ if (!ws->active) -+ wakeup_source_activate(ws); - } - - /** -@@ -397,10 +424,7 @@ void __pm_stay_awake(struct wakeup_source *ws) - - spin_lock_irqsave(&ws->lock, flags); - -- ws->event_count++; -- if (!ws->active) -- wakeup_source_activate(ws); -- -+ wakeup_source_report_event(ws); - del_timer(&ws->timer); - ws->timer_expires = 0; - -@@ -432,6 +456,17 @@ void pm_stay_awake(struct device *dev) - } - EXPORT_SYMBOL_GPL(pm_stay_awake); - -+#ifdef CONFIG_PM_AUTOSLEEP -+static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now) -+{ -+ ktime_t delta = ktime_sub(now, ws->start_prevent_time); -+ ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta); -+} -+#else -+static inline void update_prevent_sleep_time(struct wakeup_source *ws, -+ ktime_t now) {} -+#endif -+ - /** - * wakup_source_deactivate - Mark given wakeup source as inactive. - * @ws: Wakeup source to handle. -@@ -442,6 +477,7 @@ EXPORT_SYMBOL_GPL(pm_stay_awake); - */ - static void wakeup_source_deactivate(struct wakeup_source *ws) - { -+ unsigned int cnt, inpr, cec; - ktime_t duration; - ktime_t now; - -@@ -468,14 +504,23 @@ static void wakeup_source_deactivate(struct wakeup_source *ws) - if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time)) - ws->max_time = duration; - -+ ws->last_time = now; - del_timer(&ws->timer); - ws->timer_expires = 0; - -+ if (ws->autosleep_enabled) -+ update_prevent_sleep_time(ws, now); -+ - /* - * Increment the counter of registered wakeup events and decrement the - * couter of wakeup events in progress simultaneously. - */ -- atomic_add(MAX_IN_PROGRESS, &combined_event_count); -+ cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count); -+ trace_wakeup_source_deactivate(ws->name, cec); -+ -+ split_counters(&cnt, &inpr); -+ if (!inpr && waitqueue_active(&wakeup_count_wait_queue)) -+ wake_up(&wakeup_count_wait_queue); - } - - /** -@@ -536,8 +581,10 @@ static void pm_wakeup_timer_fn(unsigned long data) - spin_lock_irqsave(&ws->lock, flags); - - if (ws->active && ws->timer_expires -- && time_after_eq(jiffies, ws->timer_expires)) -+ && time_after_eq(jiffies, ws->timer_expires)) { - wakeup_source_deactivate(ws); -+ ws->expire_count++; -+ } - - spin_unlock_irqrestore(&ws->lock, flags); - } -@@ -564,9 +611,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) - - spin_lock_irqsave(&ws->lock, flags); - -- ws->event_count++; -- if (!ws->active) -- wakeup_source_activate(ws); -+ wakeup_source_report_event(ws); - - if (!msec) { - wakeup_source_deactivate(ws); -@@ -608,21 +653,28 @@ void pm_wakeup_event(struct device *dev, unsigned int msec) - } - EXPORT_SYMBOL_GPL(pm_wakeup_event); - --/** -- * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources. -- */ --static void pm_wakeup_update_hit_counts(void) -+static void print_active_wakeup_sources(void) - { -- unsigned long flags; - struct wakeup_source *ws; -+ int active = 0; -+ struct wakeup_source *last_activity_ws = NULL; - - rcu_read_lock(); - list_for_each_entry_rcu(ws, &wakeup_sources, entry) { -- spin_lock_irqsave(&ws->lock, flags); -- if (ws->active) -- ws->hit_count++; -- spin_unlock_irqrestore(&ws->lock, flags); -+ if (ws->active) { -+ pr_info("active wakeup source: %s\n", ws->name); -+ active = 1; -+ } else if (!active && -+ (!last_activity_ws || -+ ktime_to_ns(ws->last_time) > -+ ktime_to_ns(last_activity_ws->last_time))) { -+ last_activity_ws = ws; -+ } - } -+ -+ if (!active && last_activity_ws) -+ pr_info("last active wakeup source: %s\n", -+ last_activity_ws->name); - rcu_read_unlock(); - } - -@@ -648,32 +700,42 @@ bool pm_wakeup_pending(void) - events_check_enabled = !ret; - } - spin_unlock_irqrestore(&events_lock, flags); -+ - if (ret) -- pm_wakeup_update_hit_counts(); -+ print_active_wakeup_sources(); -+ - return ret; - } - - /** - * pm_get_wakeup_count - Read the number of registered wakeup events. - * @count: Address to store the value at. -+ * @block: Whether or not to block. - * -- * Store the number of registered wakeup events at the address in @count. Block -- * if the current number of wakeup events being processed is nonzero. -+ * Store the number of registered wakeup events at the address in @count. If -+ * @block is set, block until the current number of wakeup events being -+ * processed is zero. - * -- * Return 'false' if the wait for the number of wakeup events being processed to -- * drop down to zero has been interrupted by a signal (and the current number -- * of wakeup events being processed is still nonzero). Otherwise return 'true'. -+ * Return 'false' if the current number of wakeup events being processed is -+ * nonzero. Otherwise return 'true'. - */ --bool pm_get_wakeup_count(unsigned int *count) -+bool pm_get_wakeup_count(unsigned int *count, bool block) - { - unsigned int cnt, inpr; - -- for (;;) { -- split_counters(&cnt, &inpr); -- if (inpr == 0 || signal_pending(current)) -- break; -- pm_wakeup_update_hit_counts(); -- schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); -+ if (block) { -+ DEFINE_WAIT(wait); -+ -+ for (;;) { -+ prepare_to_wait(&wakeup_count_wait_queue, &wait, -+ TASK_INTERRUPTIBLE); -+ split_counters(&cnt, &inpr); -+ if (inpr == 0 || signal_pending(current)) -+ break; -+ -+ schedule(); -+ } -+ finish_wait(&wakeup_count_wait_queue, &wait); - } - - split_counters(&cnt, &inpr); -@@ -694,20 +756,47 @@ bool pm_get_wakeup_count(unsigned int *count) - bool pm_save_wakeup_count(unsigned int count) - { - unsigned int cnt, inpr; -+ unsigned long flags; - - events_check_enabled = false; -- spin_lock_irq(&events_lock); -+ spin_lock_irqsave(&events_lock, flags); - split_counters(&cnt, &inpr); - if (cnt == count && inpr == 0) { - saved_count = count; - events_check_enabled = true; - } -- spin_unlock_irq(&events_lock); -- if (!events_check_enabled) -- pm_wakeup_update_hit_counts(); -+ spin_unlock_irqrestore(&events_lock, flags); - return events_check_enabled; - } - -+#ifdef CONFIG_PM_AUTOSLEEP -+/** -+ * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources. -+ * @enabled: Whether to set or to clear the autosleep_enabled flags. -+ */ -+void pm_wakep_autosleep_enabled(bool set) -+{ -+ struct wakeup_source *ws; -+ ktime_t now = ktime_get(); -+ -+ rcu_read_lock(); -+ list_for_each_entry_rcu(ws, &wakeup_sources, entry) { -+ spin_lock_irq(&ws->lock); -+ if (ws->autosleep_enabled != set) { -+ ws->autosleep_enabled = set; -+ if (ws->active) { -+ if (set) -+ ws->start_prevent_time = now; -+ else -+ update_prevent_sleep_time(ws, now); -+ } -+ } -+ spin_unlock_irq(&ws->lock); -+ } -+ rcu_read_unlock(); -+} -+#endif /* CONFIG_PM_AUTOSLEEP */ -+ - static struct dentry *wakeup_sources_stats_dentry; - - /** -@@ -723,27 +812,37 @@ static int print_wakeup_source_stats(struct seq_file *m, - ktime_t max_time; - unsigned long active_count; - ktime_t active_time; -+ ktime_t prevent_sleep_time; - int ret; - - spin_lock_irqsave(&ws->lock, flags); - - total_time = ws->total_time; - max_time = ws->max_time; -+ prevent_sleep_time = ws->prevent_sleep_time; - active_count = ws->active_count; - if (ws->active) { -- active_time = ktime_sub(ktime_get(), ws->last_time); -+ ktime_t now = ktime_get(); -+ -+ active_time = ktime_sub(now, ws->last_time); - total_time = ktime_add(total_time, active_time); - if (active_time.tv64 > max_time.tv64) - max_time = active_time; -+ -+ if (ws->autosleep_enabled) -+ prevent_sleep_time = ktime_add(prevent_sleep_time, -+ ktime_sub(now, ws->start_prevent_time)); - } else { - active_time = ktime_set(0, 0); - } - -- ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t" -- "%lld\t\t%lld\t\t%lld\t\t%lld\n", -- ws->name, active_count, ws->event_count, ws->hit_count, -+ ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t" -+ "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n", -+ ws->name, active_count, ws->event_count, -+ ws->wakeup_count, ws->expire_count, - ktime_to_ms(active_time), ktime_to_ms(total_time), -- ktime_to_ms(max_time), ktime_to_ms(ws->last_time)); -+ ktime_to_ms(max_time), ktime_to_ms(ws->last_time), -+ ktime_to_ms(prevent_sleep_time)); - - spin_unlock_irqrestore(&ws->lock, flags); - -@@ -758,8 +857,9 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused) - { - struct wakeup_source *ws; - -- seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t" -- "active_since\ttotal_time\tmax_time\tlast_change\n"); -+ seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t" -+ "expire_count\tactive_since\ttotal_time\tmax_time\t" -+ "last_change\tprevent_suspend_time\n"); - - rcu_read_lock(); - list_for_each_entry_rcu(ws, &wakeup_sources, entry) -diff --git a/drivers/base/sw_sync.c b/drivers/base/sw_sync.c -new file mode 100644 -index 00000000..b4d8529e ---- /dev/null -+++ b/drivers/base/sw_sync.c -@@ -0,0 +1,262 @@ -+/* -+ * drivers/base/sw_sync.c -+ * -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/export.h> -+#include <linux/file.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/sw_sync.h> -+#include <linux/syscalls.h> -+#include <linux/uaccess.h> -+ -+static int sw_sync_cmp(u32 a, u32 b) -+{ -+ if (a == b) -+ return 0; -+ -+ return ((s32)a - (s32)b) < 0 ? -1 : 1; -+} -+ -+struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value) -+{ -+ struct sw_sync_pt *pt; -+ -+ pt = (struct sw_sync_pt *) -+ sync_pt_create(&obj->obj, sizeof(struct sw_sync_pt)); -+ -+ pt->value = value; -+ -+ return (struct sync_pt *)pt; -+} -+EXPORT_SYMBOL(sw_sync_pt_create); -+ -+static struct sync_pt *sw_sync_pt_dup(struct sync_pt *sync_pt) -+{ -+ struct sw_sync_pt *pt = (struct sw_sync_pt *) sync_pt; -+ struct sw_sync_timeline *obj = -+ (struct sw_sync_timeline *)sync_pt->parent; -+ -+ return (struct sync_pt *) sw_sync_pt_create(obj, pt->value); -+} -+ -+static int sw_sync_pt_has_signaled(struct sync_pt *sync_pt) -+{ -+ struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt; -+ struct sw_sync_timeline *obj = -+ (struct sw_sync_timeline *)sync_pt->parent; -+ -+ return sw_sync_cmp(obj->value, pt->value) >= 0; -+} -+ -+static int sw_sync_pt_compare(struct sync_pt *a, struct sync_pt *b) -+{ -+ struct sw_sync_pt *pt_a = (struct sw_sync_pt *)a; -+ struct sw_sync_pt *pt_b = (struct sw_sync_pt *)b; -+ -+ return sw_sync_cmp(pt_a->value, pt_b->value); -+} -+ -+static int sw_sync_fill_driver_data(struct sync_pt *sync_pt, -+ void *data, int size) -+{ -+ struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt; -+ -+ if (size < sizeof(pt->value)) -+ return -ENOMEM; -+ -+ memcpy(data, &pt->value, sizeof(pt->value)); -+ -+ return sizeof(pt->value); -+} -+ -+static void sw_sync_timeline_value_str(struct sync_timeline *sync_timeline, -+ char *str, int size) -+{ -+ struct sw_sync_timeline *timeline = -+ (struct sw_sync_timeline *)sync_timeline; -+ snprintf(str, size, "%d", timeline->value); -+} -+ -+static void sw_sync_pt_value_str(struct sync_pt *sync_pt, -+ char *str, int size) -+{ -+ struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt; -+ snprintf(str, size, "%d", pt->value); -+} -+ -+struct sync_timeline_ops sw_sync_timeline_ops = { -+ .driver_name = "sw_sync", -+ .dup = sw_sync_pt_dup, -+ .has_signaled = sw_sync_pt_has_signaled, -+ .compare = sw_sync_pt_compare, -+ .fill_driver_data = sw_sync_fill_driver_data, -+ .timeline_value_str = sw_sync_timeline_value_str, -+ .pt_value_str = sw_sync_pt_value_str, -+}; -+ -+ -+struct sw_sync_timeline *sw_sync_timeline_create(const char *name) -+{ -+ struct sw_sync_timeline *obj = (struct sw_sync_timeline *) -+ sync_timeline_create(&sw_sync_timeline_ops, -+ sizeof(struct sw_sync_timeline), -+ name); -+ -+ return obj; -+} -+EXPORT_SYMBOL(sw_sync_timeline_create); -+ -+void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc) -+{ -+ obj->value += inc; -+ -+ sync_timeline_signal(&obj->obj); -+} -+EXPORT_SYMBOL(sw_sync_timeline_inc); -+ -+#ifdef CONFIG_SW_SYNC_USER -+/* *WARNING* -+ * -+ * improper use of this can result in deadlocking kernel drivers from userspace. -+ */ -+ -+/* opening sw_sync create a new sync obj */ -+int sw_sync_open(struct inode *inode, struct file *file) -+{ -+ struct sw_sync_timeline *obj; -+ char task_comm[TASK_COMM_LEN]; -+ -+ get_task_comm(task_comm, current); -+ -+ obj = sw_sync_timeline_create(task_comm); -+ if (obj == NULL) -+ return -ENOMEM; -+ -+ file->private_data = obj; -+ -+ return 0; -+} -+ -+int sw_sync_release(struct inode *inode, struct file *file) -+{ -+ struct sw_sync_timeline *obj = file->private_data; -+ sync_timeline_destroy(&obj->obj); -+ return 0; -+} -+ -+long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj, unsigned long arg) -+{ -+ int fd = get_unused_fd(); -+ int err; -+ struct sync_pt *pt; -+ struct sync_fence *fence; -+ struct sw_sync_create_fence_data data; -+ -+ if (fd < 0) -+ return fd; -+ -+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) { -+ err = -EFAULT; -+ goto err; -+ } -+ -+ pt = sw_sync_pt_create(obj, data.value); -+ if (pt == NULL) { -+ err = -ENOMEM; -+ goto err; -+ } -+ -+ data.name[sizeof(data.name) - 1] = '\0'; -+ fence = sync_fence_create(data.name, pt); -+ if (fence == NULL) { -+ sync_pt_free(pt); -+ err = -ENOMEM; -+ goto err; -+ } -+ -+ data.fence = fd; -+ if (copy_to_user((void __user *)arg, &data, sizeof(data))) { -+ sync_fence_put(fence); -+ err = -EFAULT; -+ goto err; -+ } -+ -+ sync_fence_install(fence, fd); -+ -+ return 0; -+ -+err: -+ put_unused_fd(fd); -+ return err; -+} -+ -+long sw_sync_ioctl_inc(struct sw_sync_timeline *obj, unsigned long arg) -+{ -+ u32 value; -+ -+ if (copy_from_user(&value, (void __user *)arg, sizeof(value))) -+ return -EFAULT; -+ -+ sw_sync_timeline_inc(obj, value); -+ -+ return 0; -+} -+ -+long sw_sync_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct sw_sync_timeline *obj = file->private_data; -+ -+ switch (cmd) { -+ case SW_SYNC_IOC_CREATE_FENCE: -+ return sw_sync_ioctl_create_fence(obj, arg); -+ -+ case SW_SYNC_IOC_INC: -+ return sw_sync_ioctl_inc(obj, arg); -+ -+ default: -+ return -ENOTTY; -+ } -+} -+ -+static const struct file_operations sw_sync_fops = { -+ .owner = THIS_MODULE, -+ .open = sw_sync_open, -+ .release = sw_sync_release, -+ .unlocked_ioctl = sw_sync_ioctl, -+}; -+ -+static struct miscdevice sw_sync_dev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "sw_sync", -+ .fops = &sw_sync_fops, -+}; -+ -+int __init sw_sync_device_init(void) -+{ -+ return misc_register(&sw_sync_dev); -+} -+ -+void __exit sw_sync_device_remove(void) -+{ -+ misc_deregister(&sw_sync_dev); -+} -+ -+module_init(sw_sync_device_init); -+module_exit(sw_sync_device_remove); -+ -+#endif /* CONFIG_SW_SYNC_USER */ -diff --git a/drivers/base/sync.c b/drivers/base/sync.c -new file mode 100644 -index 00000000..2e359968 ---- /dev/null -+++ b/drivers/base/sync.c -@@ -0,0 +1,1015 @@ -+/* -+ * drivers/base/sync.c -+ * -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/debugfs.h> -+#include <linux/export.h> -+#include <linux/file.h> -+#include <linux/fs.h> -+#include <linux/kernel.h> -+#include <linux/poll.h> -+#include <linux/sched.h> -+#include <linux/seq_file.h> -+#include <linux/slab.h> -+#include <linux/sync.h> -+#include <linux/uaccess.h> -+ -+#include <linux/anon_inodes.h> -+ -+#define CREATE_TRACE_POINTS -+#include <trace/events/sync.h> -+ -+static void sync_fence_signal_pt(struct sync_pt *pt); -+static int _sync_pt_has_signaled(struct sync_pt *pt); -+static void sync_fence_free(struct kref *kref); -+static void sync_dump(void); -+ -+static LIST_HEAD(sync_timeline_list_head); -+static DEFINE_SPINLOCK(sync_timeline_list_lock); -+ -+static LIST_HEAD(sync_fence_list_head); -+static DEFINE_SPINLOCK(sync_fence_list_lock); -+ -+struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, -+ int size, const char *name) -+{ -+ struct sync_timeline *obj; -+ unsigned long flags; -+ -+ if (size < sizeof(struct sync_timeline)) -+ return NULL; -+ -+ obj = kzalloc(size, GFP_KERNEL); -+ if (obj == NULL) -+ return NULL; -+ -+ kref_init(&obj->kref); -+ obj->ops = ops; -+ strlcpy(obj->name, name, sizeof(obj->name)); -+ -+ INIT_LIST_HEAD(&obj->child_list_head); -+ spin_lock_init(&obj->child_list_lock); -+ -+ INIT_LIST_HEAD(&obj->active_list_head); -+ spin_lock_init(&obj->active_list_lock); -+ -+ spin_lock_irqsave(&sync_timeline_list_lock, flags); -+ list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head); -+ spin_unlock_irqrestore(&sync_timeline_list_lock, flags); -+ -+ return obj; -+} -+EXPORT_SYMBOL(sync_timeline_create); -+ -+static void sync_timeline_free(struct kref *kref) -+{ -+ struct sync_timeline *obj = -+ container_of(kref, struct sync_timeline, kref); -+ unsigned long flags; -+ -+ if (obj->ops->release_obj) -+ obj->ops->release_obj(obj); -+ -+ spin_lock_irqsave(&sync_timeline_list_lock, flags); -+ list_del(&obj->sync_timeline_list); -+ spin_unlock_irqrestore(&sync_timeline_list_lock, flags); -+ -+ kfree(obj); -+} -+ -+void sync_timeline_destroy(struct sync_timeline *obj) -+{ -+ obj->destroyed = true; -+ -+ /* -+ * If this is not the last reference, signal any children -+ * that their parent is going away. -+ */ -+ -+ if (!kref_put(&obj->kref, sync_timeline_free)) -+ sync_timeline_signal(obj); -+} -+EXPORT_SYMBOL(sync_timeline_destroy); -+ -+static void sync_timeline_add_pt(struct sync_timeline *obj, struct sync_pt *pt) -+{ -+ unsigned long flags; -+ -+ pt->parent = obj; -+ -+ spin_lock_irqsave(&obj->child_list_lock, flags); -+ list_add_tail(&pt->child_list, &obj->child_list_head); -+ spin_unlock_irqrestore(&obj->child_list_lock, flags); -+} -+ -+static void sync_timeline_remove_pt(struct sync_pt *pt) -+{ -+ struct sync_timeline *obj = pt->parent; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&obj->active_list_lock, flags); -+ if (!list_empty(&pt->active_list)) -+ list_del_init(&pt->active_list); -+ spin_unlock_irqrestore(&obj->active_list_lock, flags); -+ -+ spin_lock_irqsave(&obj->child_list_lock, flags); -+ if (!list_empty(&pt->child_list)) { -+ list_del_init(&pt->child_list); -+ } -+ spin_unlock_irqrestore(&obj->child_list_lock, flags); -+} -+ -+void sync_timeline_signal(struct sync_timeline *obj) -+{ -+ unsigned long flags; -+ LIST_HEAD(signaled_pts); -+ struct list_head *pos, *n; -+ -+ trace_sync_timeline(obj); -+ -+ spin_lock_irqsave(&obj->active_list_lock, flags); -+ -+ list_for_each_safe(pos, n, &obj->active_list_head) { -+ struct sync_pt *pt = -+ container_of(pos, struct sync_pt, active_list); -+ -+ if (_sync_pt_has_signaled(pt)) { -+ list_del_init(pos); -+ list_add(&pt->signaled_list, &signaled_pts); -+ kref_get(&pt->fence->kref); -+ } -+ } -+ -+ spin_unlock_irqrestore(&obj->active_list_lock, flags); -+ -+ list_for_each_safe(pos, n, &signaled_pts) { -+ struct sync_pt *pt = -+ container_of(pos, struct sync_pt, signaled_list); -+ -+ list_del_init(pos); -+ sync_fence_signal_pt(pt); -+ kref_put(&pt->fence->kref, sync_fence_free); -+ } -+} -+EXPORT_SYMBOL(sync_timeline_signal); -+ -+struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size) -+{ -+ struct sync_pt *pt; -+ -+ if (size < sizeof(struct sync_pt)) -+ return NULL; -+ -+ pt = kzalloc(size, GFP_KERNEL); -+ if (pt == NULL) -+ return NULL; -+ -+ INIT_LIST_HEAD(&pt->active_list); -+ kref_get(&parent->kref); -+ sync_timeline_add_pt(parent, pt); -+ -+ return pt; -+} -+EXPORT_SYMBOL(sync_pt_create); -+ -+void sync_pt_free(struct sync_pt *pt) -+{ -+ if (pt->parent->ops->free_pt) -+ pt->parent->ops->free_pt(pt); -+ -+ sync_timeline_remove_pt(pt); -+ -+ kref_put(&pt->parent->kref, sync_timeline_free); -+ -+ kfree(pt); -+} -+EXPORT_SYMBOL(sync_pt_free); -+ -+/* call with pt->parent->active_list_lock held */ -+static int _sync_pt_has_signaled(struct sync_pt *pt) -+{ -+ int old_status = pt->status; -+ -+ if (!pt->status) -+ pt->status = pt->parent->ops->has_signaled(pt); -+ -+ if (!pt->status && pt->parent->destroyed) -+ pt->status = -ENOENT; -+ -+ if (pt->status != old_status) -+ pt->timestamp = ktime_get(); -+ -+ return pt->status; -+} -+ -+static struct sync_pt *sync_pt_dup(struct sync_pt *pt) -+{ -+ return pt->parent->ops->dup(pt); -+} -+ -+/* Adds a sync pt to the active queue. Called when added to a fence */ -+static void sync_pt_activate(struct sync_pt *pt) -+{ -+ struct sync_timeline *obj = pt->parent; -+ unsigned long flags; -+ int err; -+ -+ spin_lock_irqsave(&obj->active_list_lock, flags); -+ -+ err = _sync_pt_has_signaled(pt); -+ if (err != 0) -+ goto out; -+ -+ list_add_tail(&pt->active_list, &obj->active_list_head); -+ -+out: -+ spin_unlock_irqrestore(&obj->active_list_lock, flags); -+} -+ -+static int sync_fence_release(struct inode *inode, struct file *file); -+static unsigned int sync_fence_poll(struct file *file, poll_table *wait); -+static long sync_fence_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg); -+ -+ -+static const struct file_operations sync_fence_fops = { -+ .release = sync_fence_release, -+ .poll = sync_fence_poll, -+ .unlocked_ioctl = sync_fence_ioctl, -+}; -+ -+static struct sync_fence *sync_fence_alloc(const char *name) -+{ -+ struct sync_fence *fence; -+ unsigned long flags; -+ -+ fence = kzalloc(sizeof(struct sync_fence), GFP_KERNEL); -+ if (fence == NULL) -+ return NULL; -+ -+ fence->file = anon_inode_getfile("sync_fence", &sync_fence_fops, -+ fence, 0); -+ if (fence->file == NULL) -+ goto err; -+ -+ kref_init(&fence->kref); -+ strlcpy(fence->name, name, sizeof(fence->name)); -+ -+ INIT_LIST_HEAD(&fence->pt_list_head); -+ INIT_LIST_HEAD(&fence->waiter_list_head); -+ spin_lock_init(&fence->waiter_list_lock); -+ -+ init_waitqueue_head(&fence->wq); -+ -+ spin_lock_irqsave(&sync_fence_list_lock, flags); -+ list_add_tail(&fence->sync_fence_list, &sync_fence_list_head); -+ spin_unlock_irqrestore(&sync_fence_list_lock, flags); -+ -+ return fence; -+ -+err: -+ kfree(fence); -+ return NULL; -+} -+ -+/* TODO: implement a create which takes more that one sync_pt */ -+struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt) -+{ -+ struct sync_fence *fence; -+ -+ if (pt->fence) -+ return NULL; -+ -+ fence = sync_fence_alloc(name); -+ if (fence == NULL) -+ return NULL; -+ -+ pt->fence = fence; -+ list_add(&pt->pt_list, &fence->pt_list_head); -+ sync_pt_activate(pt); -+ -+ /* -+ * signal the fence in case pt was activated before -+ * sync_pt_activate(pt) was called -+ */ -+ sync_fence_signal_pt(pt); -+ -+ return fence; -+} -+EXPORT_SYMBOL(sync_fence_create); -+ -+static int sync_fence_copy_pts(struct sync_fence *dst, struct sync_fence *src) -+{ -+ struct list_head *pos; -+ -+ list_for_each(pos, &src->pt_list_head) { -+ struct sync_pt *orig_pt = -+ container_of(pos, struct sync_pt, pt_list); -+ struct sync_pt *new_pt = sync_pt_dup(orig_pt); -+ -+ if (new_pt == NULL) -+ return -ENOMEM; -+ -+ new_pt->fence = dst; -+ list_add(&new_pt->pt_list, &dst->pt_list_head); -+ } -+ -+ return 0; -+} -+ -+static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src) -+{ -+ struct list_head *src_pos, *dst_pos, *n; -+ -+ list_for_each(src_pos, &src->pt_list_head) { -+ struct sync_pt *src_pt = -+ container_of(src_pos, struct sync_pt, pt_list); -+ bool collapsed = false; -+ -+ list_for_each_safe(dst_pos, n, &dst->pt_list_head) { -+ struct sync_pt *dst_pt = -+ container_of(dst_pos, struct sync_pt, pt_list); -+ /* collapse two sync_pts on the same timeline -+ * to a single sync_pt that will signal at -+ * the later of the two -+ */ -+ if (dst_pt->parent == src_pt->parent) { -+ if (dst_pt->parent->ops->compare(dst_pt, src_pt) == -1) { -+ struct sync_pt *new_pt = -+ sync_pt_dup(src_pt); -+ if (new_pt == NULL) -+ return -ENOMEM; -+ -+ new_pt->fence = dst; -+ list_replace(&dst_pt->pt_list, -+ &new_pt->pt_list); -+ sync_pt_free(dst_pt); -+ } -+ collapsed = true; -+ break; -+ } -+ } -+ -+ if (!collapsed) { -+ struct sync_pt *new_pt = sync_pt_dup(src_pt); -+ -+ if (new_pt == NULL) -+ return -ENOMEM; -+ -+ new_pt->fence = dst; -+ list_add(&new_pt->pt_list, &dst->pt_list_head); -+ } -+ } -+ -+ return 0; -+} -+ -+static void sync_fence_detach_pts(struct sync_fence *fence) -+{ -+ struct list_head *pos, *n; -+ -+ list_for_each_safe(pos, n, &fence->pt_list_head) { -+ struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list); -+ sync_timeline_remove_pt(pt); -+ } -+} -+ -+static void sync_fence_free_pts(struct sync_fence *fence) -+{ -+ struct list_head *pos, *n; -+ -+ list_for_each_safe(pos, n, &fence->pt_list_head) { -+ struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list); -+ sync_pt_free(pt); -+ } -+} -+ -+struct sync_fence *sync_fence_fdget(int fd) -+{ -+ struct file *file = fget(fd); -+ -+ if (file == NULL) -+ return NULL; -+ -+ if (file->f_op != &sync_fence_fops) -+ goto err; -+ -+ return file->private_data; -+ -+err: -+ fput(file); -+ return NULL; -+} -+EXPORT_SYMBOL(sync_fence_fdget); -+ -+void sync_fence_put(struct sync_fence *fence) -+{ -+ fput(fence->file); -+} -+EXPORT_SYMBOL(sync_fence_put); -+ -+void sync_fence_install(struct sync_fence *fence, int fd) -+{ -+ fd_install(fd, fence->file); -+} -+EXPORT_SYMBOL(sync_fence_install); -+ -+static int sync_fence_get_status(struct sync_fence *fence) -+{ -+ struct list_head *pos; -+ int status = 1; -+ -+ list_for_each(pos, &fence->pt_list_head) { -+ struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list); -+ int pt_status = pt->status; -+ -+ if (pt_status < 0) { -+ status = pt_status; -+ break; -+ } else if (status == 1) { -+ status = pt_status; -+ } -+ } -+ -+ return status; -+} -+ -+struct sync_fence *sync_fence_merge(const char *name, -+ struct sync_fence *a, struct sync_fence *b) -+{ -+ struct sync_fence *fence; -+ struct list_head *pos; -+ int err; -+ -+ fence = sync_fence_alloc(name); -+ if (fence == NULL) -+ return NULL; -+ -+ err = sync_fence_copy_pts(fence, a); -+ if (err < 0) -+ goto err; -+ -+ err = sync_fence_merge_pts(fence, b); -+ if (err < 0) -+ goto err; -+ -+ list_for_each(pos, &fence->pt_list_head) { -+ struct sync_pt *pt = -+ container_of(pos, struct sync_pt, pt_list); -+ sync_pt_activate(pt); -+ } -+ -+ /* -+ * signal the fence in case one of it's pts were activated before -+ * they were activated -+ */ -+ sync_fence_signal_pt(list_first_entry(&fence->pt_list_head, -+ struct sync_pt, -+ pt_list)); -+ -+ return fence; -+err: -+ sync_fence_free_pts(fence); -+ kfree(fence); -+ return NULL; -+} -+EXPORT_SYMBOL(sync_fence_merge); -+ -+static void sync_fence_signal_pt(struct sync_pt *pt) -+{ -+ LIST_HEAD(signaled_waiters); -+ struct sync_fence *fence = pt->fence; -+ struct list_head *pos; -+ struct list_head *n; -+ unsigned long flags; -+ int status; -+ -+ status = sync_fence_get_status(fence); -+ -+ spin_lock_irqsave(&fence->waiter_list_lock, flags); -+ /* -+ * this should protect against two threads racing on the signaled -+ * false -> true transition -+ */ -+ if (status && !fence->status) { -+ list_for_each_safe(pos, n, &fence->waiter_list_head) -+ list_move(pos, &signaled_waiters); -+ -+ fence->status = status; -+ } else { -+ status = 0; -+ } -+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags); -+ -+ if (status) { -+ list_for_each_safe(pos, n, &signaled_waiters) { -+ struct sync_fence_waiter *waiter = -+ container_of(pos, struct sync_fence_waiter, -+ waiter_list); -+ -+ list_del(pos); -+ waiter->callback(fence, waiter); -+ } -+ wake_up(&fence->wq); -+ } -+} -+ -+int sync_fence_wait_async(struct sync_fence *fence, -+ struct sync_fence_waiter *waiter) -+{ -+ unsigned long flags; -+ int err = 0; -+ -+ spin_lock_irqsave(&fence->waiter_list_lock, flags); -+ -+ if (fence->status) { -+ err = fence->status; -+ goto out; -+ } -+ -+ list_add_tail(&waiter->waiter_list, &fence->waiter_list_head); -+out: -+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags); -+ -+ return err; -+} -+EXPORT_SYMBOL(sync_fence_wait_async); -+ -+int sync_fence_cancel_async(struct sync_fence *fence, -+ struct sync_fence_waiter *waiter) -+{ -+ struct list_head *pos; -+ struct list_head *n; -+ unsigned long flags; -+ int ret = -ENOENT; -+ -+ spin_lock_irqsave(&fence->waiter_list_lock, flags); -+ /* -+ * Make sure waiter is still in waiter_list because it is possible for -+ * the waiter to be removed from the list while the callback is still -+ * pending. -+ */ -+ list_for_each_safe(pos, n, &fence->waiter_list_head) { -+ struct sync_fence_waiter *list_waiter = -+ container_of(pos, struct sync_fence_waiter, -+ waiter_list); -+ if (list_waiter == waiter) { -+ list_del(pos); -+ ret = 0; -+ break; -+ } -+ } -+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags); -+ return ret; -+} -+EXPORT_SYMBOL(sync_fence_cancel_async); -+ -+static bool sync_fence_check(struct sync_fence *fence) -+{ -+ /* -+ * Make sure that reads to fence->status are ordered with the -+ * wait queue event triggering -+ */ -+ smp_rmb(); -+ return fence->status != 0; -+} -+ -+int sync_fence_wait(struct sync_fence *fence, long timeout) -+{ -+ int err = 0; -+ struct sync_pt *pt; -+ -+ trace_sync_wait(fence, 1); -+ list_for_each_entry(pt, &fence->pt_list_head, pt_list) -+ trace_sync_pt(pt); -+ -+ if (timeout > 0) { -+ timeout = msecs_to_jiffies(timeout); -+ err = wait_event_interruptible_timeout(fence->wq, -+ sync_fence_check(fence), -+ timeout); -+ } else if (timeout < 0) { -+ err = wait_event_interruptible(fence->wq, -+ sync_fence_check(fence)); -+ } -+ trace_sync_wait(fence, 0); -+ -+ if (err < 0) -+ return err; -+ -+ if (fence->status < 0) { -+ pr_info("fence error %d on [%p]\n", fence->status, fence); -+ sync_dump(); -+ return fence->status; -+ } -+ -+ if (fence->status == 0) { -+ if (timeout > 0) { -+ pr_info("fence timeout on [%p] after %dms\n", fence, -+ jiffies_to_msecs(timeout)); -+ sync_dump(); -+ } -+ return -ETIME; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(sync_fence_wait); -+ -+static void sync_fence_free(struct kref *kref) -+{ -+ struct sync_fence *fence = container_of(kref, struct sync_fence, kref); -+ -+ sync_fence_free_pts(fence); -+ -+ kfree(fence); -+} -+ -+static int sync_fence_release(struct inode *inode, struct file *file) -+{ -+ struct sync_fence *fence = file->private_data; -+ unsigned long flags; -+ -+ /* -+ * We need to remove all ways to access this fence before droping -+ * our ref. -+ * -+ * start with its membership in the global fence list -+ */ -+ spin_lock_irqsave(&sync_fence_list_lock, flags); -+ list_del(&fence->sync_fence_list); -+ spin_unlock_irqrestore(&sync_fence_list_lock, flags); -+ -+ /* -+ * remove its pts from their parents so that sync_timeline_signal() -+ * can't reference the fence. -+ */ -+ sync_fence_detach_pts(fence); -+ -+ kref_put(&fence->kref, sync_fence_free); -+ -+ return 0; -+} -+ -+static unsigned int sync_fence_poll(struct file *file, poll_table *wait) -+{ -+ struct sync_fence *fence = file->private_data; -+ -+ poll_wait(file, &fence->wq, wait); -+ -+ /* -+ * Make sure that reads to fence->status are ordered with the -+ * wait queue event triggering -+ */ -+ smp_rmb(); -+ -+ if (fence->status == 1) -+ return POLLIN; -+ else if (fence->status < 0) -+ return POLLERR; -+ else -+ return 0; -+} -+ -+static long sync_fence_ioctl_wait(struct sync_fence *fence, unsigned long arg) -+{ -+ __s32 value; -+ -+ if (copy_from_user(&value, (void __user *)arg, sizeof(value))) -+ return -EFAULT; -+ -+ return sync_fence_wait(fence, value); -+} -+ -+static long sync_fence_ioctl_merge(struct sync_fence *fence, unsigned long arg) -+{ -+ int fd = get_unused_fd(); -+ int err; -+ struct sync_fence *fence2, *fence3; -+ struct sync_merge_data data; -+ -+ if (fd < 0) -+ return fd; -+ -+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) { -+ err = -EFAULT; -+ goto err_put_fd; -+ } -+ -+ fence2 = sync_fence_fdget(data.fd2); -+ if (fence2 == NULL) { -+ err = -ENOENT; -+ goto err_put_fd; -+ } -+ -+ data.name[sizeof(data.name) - 1] = '\0'; -+ fence3 = sync_fence_merge(data.name, fence, fence2); -+ if (fence3 == NULL) { -+ err = -ENOMEM; -+ goto err_put_fence2; -+ } -+ -+ data.fence = fd; -+ if (copy_to_user((void __user *)arg, &data, sizeof(data))) { -+ err = -EFAULT; -+ goto err_put_fence3; -+ } -+ -+ sync_fence_install(fence3, fd); -+ sync_fence_put(fence2); -+ return 0; -+ -+err_put_fence3: -+ sync_fence_put(fence3); -+ -+err_put_fence2: -+ sync_fence_put(fence2); -+ -+err_put_fd: -+ put_unused_fd(fd); -+ return err; -+} -+ -+static int sync_fill_pt_info(struct sync_pt *pt, void *data, int size) -+{ -+ struct sync_pt_info *info = data; -+ int ret; -+ -+ if (size < sizeof(struct sync_pt_info)) -+ return -ENOMEM; -+ -+ info->len = sizeof(struct sync_pt_info); -+ -+ if (pt->parent->ops->fill_driver_data) { -+ ret = pt->parent->ops->fill_driver_data(pt, info->driver_data, -+ size - sizeof(*info)); -+ if (ret < 0) -+ return ret; -+ -+ info->len += ret; -+ } -+ -+ strlcpy(info->obj_name, pt->parent->name, sizeof(info->obj_name)); -+ strlcpy(info->driver_name, pt->parent->ops->driver_name, -+ sizeof(info->driver_name)); -+ info->status = pt->status; -+ info->timestamp_ns = ktime_to_ns(pt->timestamp); -+ -+ return info->len; -+} -+ -+static long sync_fence_ioctl_fence_info(struct sync_fence *fence, -+ unsigned long arg) -+{ -+ struct sync_fence_info_data *data; -+ struct list_head *pos; -+ __u32 size; -+ __u32 len = 0; -+ int ret; -+ -+ if (copy_from_user(&size, (void __user *)arg, sizeof(size))) -+ return -EFAULT; -+ -+ if (size < sizeof(struct sync_fence_info_data)) -+ return -EINVAL; -+ -+ if (size > 4096) -+ size = 4096; -+ -+ data = kzalloc(size, GFP_KERNEL); -+ if (data == NULL) -+ return -ENOMEM; -+ -+ strlcpy(data->name, fence->name, sizeof(data->name)); -+ data->status = fence->status; -+ len = sizeof(struct sync_fence_info_data); -+ -+ list_for_each(pos, &fence->pt_list_head) { -+ struct sync_pt *pt = -+ container_of(pos, struct sync_pt, pt_list); -+ -+ ret = sync_fill_pt_info(pt, (u8 *)data + len, size - len); -+ -+ if (ret < 0) -+ goto out; -+ -+ len += ret; -+ } -+ -+ data->len = len; -+ -+ if (copy_to_user((void __user *)arg, data, len)) -+ ret = -EFAULT; -+ else -+ ret = 0; -+ -+out: -+ kfree(data); -+ -+ return ret; -+} -+ -+static long sync_fence_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct sync_fence *fence = file->private_data; -+ switch (cmd) { -+ case SYNC_IOC_WAIT: -+ return sync_fence_ioctl_wait(fence, arg); -+ -+ case SYNC_IOC_MERGE: -+ return sync_fence_ioctl_merge(fence, arg); -+ -+ case SYNC_IOC_FENCE_INFO: -+ return sync_fence_ioctl_fence_info(fence, arg); -+ -+ default: -+ return -ENOTTY; -+ } -+} -+ -+#ifdef CONFIG_DEBUG_FS -+static const char *sync_status_str(int status) -+{ -+ if (status > 0) -+ return "signaled"; -+ else if (status == 0) -+ return "active"; -+ else -+ return "error"; -+} -+ -+static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence) -+{ -+ int status = pt->status; -+ seq_printf(s, " %s%spt %s", -+ fence ? pt->parent->name : "", -+ fence ? "_" : "", -+ sync_status_str(status)); -+ if (pt->status) { -+ struct timeval tv = ktime_to_timeval(pt->timestamp); -+ seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec); -+ } -+ -+ if (pt->parent->ops->timeline_value_str && -+ pt->parent->ops->pt_value_str) { -+ char value[64]; -+ pt->parent->ops->pt_value_str(pt, value, sizeof(value)); -+ seq_printf(s, ": %s", value); -+ if (fence) { -+ pt->parent->ops->timeline_value_str(pt->parent, value, -+ sizeof(value)); -+ seq_printf(s, " / %s", value); -+ } -+ } else if (pt->parent->ops->print_pt) { -+ seq_printf(s, ": "); -+ pt->parent->ops->print_pt(s, pt); -+ } -+ -+ seq_printf(s, "\n"); -+} -+ -+static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) -+{ -+ struct list_head *pos; -+ unsigned long flags; -+ -+ seq_printf(s, "%s %s", obj->name, obj->ops->driver_name); -+ -+ if (obj->ops->timeline_value_str) { -+ char value[64]; -+ obj->ops->timeline_value_str(obj, value, sizeof(value)); -+ seq_printf(s, ": %s", value); -+ } else if (obj->ops->print_obj) { -+ seq_printf(s, ": "); -+ obj->ops->print_obj(s, obj); -+ } -+ -+ seq_printf(s, "\n"); -+ -+ spin_lock_irqsave(&obj->child_list_lock, flags); -+ list_for_each(pos, &obj->child_list_head) { -+ struct sync_pt *pt = -+ container_of(pos, struct sync_pt, child_list); -+ sync_print_pt(s, pt, false); -+ } -+ spin_unlock_irqrestore(&obj->child_list_lock, flags); -+} -+ -+static void sync_print_fence(struct seq_file *s, struct sync_fence *fence) -+{ -+ struct list_head *pos; -+ unsigned long flags; -+ -+ seq_printf(s, "[%p] %s: %s\n", fence, fence->name, -+ sync_status_str(fence->status)); -+ -+ list_for_each(pos, &fence->pt_list_head) { -+ struct sync_pt *pt = -+ container_of(pos, struct sync_pt, pt_list); -+ sync_print_pt(s, pt, true); -+ } -+ -+ spin_lock_irqsave(&fence->waiter_list_lock, flags); -+ list_for_each(pos, &fence->waiter_list_head) { -+ struct sync_fence_waiter *waiter = -+ container_of(pos, struct sync_fence_waiter, -+ waiter_list); -+ -+ seq_printf(s, "waiter %pF\n", waiter->callback); -+ } -+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags); -+} -+ -+static int sync_debugfs_show(struct seq_file *s, void *unused) -+{ -+ unsigned long flags; -+ struct list_head *pos; -+ -+ seq_printf(s, "objs:\n--------------\n"); -+ -+ spin_lock_irqsave(&sync_timeline_list_lock, flags); -+ list_for_each(pos, &sync_timeline_list_head) { -+ struct sync_timeline *obj = -+ container_of(pos, struct sync_timeline, -+ sync_timeline_list); -+ -+ sync_print_obj(s, obj); -+ seq_printf(s, "\n"); -+ } -+ spin_unlock_irqrestore(&sync_timeline_list_lock, flags); -+ -+ seq_printf(s, "fences:\n--------------\n"); -+ -+ spin_lock_irqsave(&sync_fence_list_lock, flags); -+ list_for_each(pos, &sync_fence_list_head) { -+ struct sync_fence *fence = -+ container_of(pos, struct sync_fence, sync_fence_list); -+ -+ sync_print_fence(s, fence); -+ seq_printf(s, "\n"); -+ } -+ spin_unlock_irqrestore(&sync_fence_list_lock, flags); -+ return 0; -+} -+ -+static int sync_debugfs_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, sync_debugfs_show, inode->i_private); -+} -+ -+static const struct file_operations sync_debugfs_fops = { -+ .open = sync_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static __init int sync_debugfs_init(void) -+{ -+ debugfs_create_file("sync", S_IRUGO, NULL, NULL, &sync_debugfs_fops); -+ return 0; -+} -+late_initcall(sync_debugfs_init); -+ -+#define DUMP_CHUNK 256 -+static char sync_dump_buf[64 * 1024]; -+void sync_dump(void) -+{ -+ struct seq_file s = { -+ .buf = sync_dump_buf, -+ .size = sizeof(sync_dump_buf) - 1, -+ }; -+ int i; -+ -+ sync_debugfs_show(&s, NULL); -+ -+ for (i = 0; i < s.count; i += DUMP_CHUNK) { -+ if ((s.count - i) > DUMP_CHUNK) { -+ char c = s.buf[i + DUMP_CHUNK]; -+ s.buf[i + DUMP_CHUNK] = 0; -+ pr_cont("%s", s.buf + i); -+ s.buf[i + DUMP_CHUNK] = c; -+ } else { -+ s.buf[s.count] = 0; -+ pr_cont("%s", s.buf + i); -+ } -+ } -+} -+#else -+static void sync_dump(void) -+{ -+} -+#endif -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index ee946865..f48cd688 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -6,6 +6,19 @@ menu "Character devices" - - source "drivers/tty/Kconfig" - -+config DEVMEM -+ bool "Memory device driver" -+ default y -+ help -+ The memory driver provides two character devices, mem and kmem, which -+ provide access to the system's memory. The mem device is a view of -+ physical memory, and each byte in the device corresponds to the -+ matching physical address. The kmem device is the same as mem, but -+ the addresses correspond to the kernel's virtual address space rather -+ than physical memory. These devices are standard parts of a Linux -+ system and most users should say Y here. You might say N if very -+ security conscience or memory is tight. -+ - config DEVKMEM - bool "/dev/kmem virtual device support" - default y -@@ -583,6 +596,10 @@ config DEVPORT - depends on ISA || PCI - default y - -+config DCC_TTY -+ tristate "DCC tty driver" -+ depends on ARM -+ - source "drivers/s390/char/Kconfig" - - config RAMOOPS -diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index 0dc5d7ce..8f188917 100644 ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -57,6 +57,7 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ - obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o - obj-$(CONFIG_TCG_TPM) += tpm/ - -+obj-$(CONFIG_DCC_TTY) += dcc_tty.o - obj-$(CONFIG_PS3_FLASH) += ps3flash.o - obj-$(CONFIG_RAMOOPS) += ramoops.o - -diff --git a/drivers/char/dcc_tty.c b/drivers/char/dcc_tty.c -new file mode 100644 -index 00000000..a787accd ---- /dev/null -+++ b/drivers/char/dcc_tty.c -@@ -0,0 +1,326 @@ -+/* drivers/char/dcc_tty.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/delay.h> -+#include <linux/console.h> -+#include <linux/hrtimer.h> -+#include <linux/tty.h> -+#include <linux/tty_driver.h> -+#include <linux/tty_flip.h> -+ -+MODULE_DESCRIPTION("DCC TTY Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION("1.0"); -+ -+static spinlock_t g_dcc_tty_lock = SPIN_LOCK_UNLOCKED; -+static struct hrtimer g_dcc_timer; -+static char g_dcc_buffer[16]; -+static int g_dcc_buffer_head; -+static int g_dcc_buffer_count; -+static unsigned g_dcc_write_delay_usecs = 1; -+static struct tty_driver *g_dcc_tty_driver; -+static struct tty_struct *g_dcc_tty; -+static int g_dcc_tty_open_count; -+ -+static void dcc_poll_locked(void) -+{ -+ char ch; -+ int rch; -+ int written; -+ -+ while (g_dcc_buffer_count) { -+ ch = g_dcc_buffer[g_dcc_buffer_head]; -+ asm( -+ "mrc 14, 0, r15, c0, c1, 0\n" -+ "mcrcc 14, 0, %1, c0, c5, 0\n" -+ "movcc %0, #1\n" -+ "movcs %0, #0\n" -+ : "=r" (written) -+ : "r" (ch) -+ ); -+ if (written) { -+ if (ch == '\n') -+ g_dcc_buffer[g_dcc_buffer_head] = '\r'; -+ else { -+ g_dcc_buffer_head = (g_dcc_buffer_head + 1) % ARRAY_SIZE(g_dcc_buffer); -+ g_dcc_buffer_count--; -+ if (g_dcc_tty) -+ tty_wakeup(g_dcc_tty); -+ } -+ g_dcc_write_delay_usecs = 1; -+ } else { -+ if (g_dcc_write_delay_usecs > 0x100) -+ break; -+ g_dcc_write_delay_usecs <<= 1; -+ udelay(g_dcc_write_delay_usecs); -+ } -+ } -+ -+ if (g_dcc_tty && !test_bit(TTY_THROTTLED, &g_dcc_tty->flags)) { -+ asm( -+ "mrc 14, 0, %0, c0, c1, 0\n" -+ "tst %0, #(1 << 30)\n" -+ "moveq %0, #-1\n" -+ "mrcne 14, 0, %0, c0, c5, 0\n" -+ : "=r" (rch) -+ ); -+ if (rch >= 0) { -+ ch = rch; -+ tty_insert_flip_string(g_dcc_tty, &ch, 1); -+ tty_flip_buffer_push(g_dcc_tty); -+ } -+ } -+ -+ -+ if (g_dcc_buffer_count) -+ hrtimer_start(&g_dcc_timer, ktime_set(0, g_dcc_write_delay_usecs * NSEC_PER_USEC), HRTIMER_MODE_REL); -+ else -+ hrtimer_start(&g_dcc_timer, ktime_set(0, 20 * NSEC_PER_MSEC), HRTIMER_MODE_REL); -+} -+ -+static int dcc_tty_open(struct tty_struct * tty, struct file * filp) -+{ -+ int ret; -+ unsigned long irq_flags; -+ -+ spin_lock_irqsave(&g_dcc_tty_lock, irq_flags); -+ if (g_dcc_tty == NULL || g_dcc_tty == tty) { -+ g_dcc_tty = tty; -+ g_dcc_tty_open_count++; -+ ret = 0; -+ } else -+ ret = -EBUSY; -+ spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags); -+ -+ printk("dcc_tty_open, tty %p, f_flags %x, returned %d\n", tty, filp->f_flags, ret); -+ -+ return ret; -+} -+ -+static void dcc_tty_close(struct tty_struct * tty, struct file * filp) -+{ -+ printk("dcc_tty_close, tty %p, f_flags %x\n", tty, filp->f_flags); -+ if (g_dcc_tty == tty) { -+ if (--g_dcc_tty_open_count == 0) -+ g_dcc_tty = NULL; -+ } -+} -+ -+static int dcc_write(const unsigned char *buf_start, int count) -+{ -+ const unsigned char *buf = buf_start; -+ unsigned long irq_flags; -+ int copy_len; -+ int space_left; -+ int tail; -+ -+ if (count < 1) -+ return 0; -+ -+ spin_lock_irqsave(&g_dcc_tty_lock, irq_flags); -+ do { -+ tail = (g_dcc_buffer_head + g_dcc_buffer_count) % ARRAY_SIZE(g_dcc_buffer); -+ copy_len = ARRAY_SIZE(g_dcc_buffer) - tail; -+ space_left = ARRAY_SIZE(g_dcc_buffer) - g_dcc_buffer_count; -+ if (copy_len > space_left) -+ copy_len = space_left; -+ if (copy_len > count) -+ copy_len = count; -+ memcpy(&g_dcc_buffer[tail], buf, copy_len); -+ g_dcc_buffer_count += copy_len; -+ buf += copy_len; -+ count -= copy_len; -+ if (copy_len < count && copy_len < space_left) { -+ space_left -= copy_len; -+ copy_len = count; -+ if (copy_len > space_left) { -+ copy_len = space_left; -+ } -+ memcpy(g_dcc_buffer, buf, copy_len); -+ buf += copy_len; -+ count -= copy_len; -+ g_dcc_buffer_count += copy_len; -+ } -+ dcc_poll_locked(); -+ space_left = ARRAY_SIZE(g_dcc_buffer) - g_dcc_buffer_count; -+ } while(count && space_left); -+ spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags); -+ return buf - buf_start; -+} -+ -+static int dcc_tty_write(struct tty_struct * tty, const unsigned char *buf, int count) -+{ -+ int ret; -+ /* printk("dcc_tty_write %p, %d\n", buf, count); */ -+ ret = dcc_write(buf, count); -+ if (ret != count) -+ printk("dcc_tty_write %p, %d, returned %d\n", buf, count, ret); -+ return ret; -+} -+ -+static int dcc_tty_write_room(struct tty_struct *tty) -+{ -+ int space_left; -+ unsigned long irq_flags; -+ -+ spin_lock_irqsave(&g_dcc_tty_lock, irq_flags); -+ space_left = ARRAY_SIZE(g_dcc_buffer) - g_dcc_buffer_count; -+ spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags); -+ return space_left; -+} -+ -+static int dcc_tty_chars_in_buffer(struct tty_struct *tty) -+{ -+ int ret; -+ asm( -+ "mrc 14, 0, %0, c0, c1, 0\n" -+ "mov %0, %0, LSR #30\n" -+ "and %0, %0, #1\n" -+ : "=r" (ret) -+ ); -+ return ret; -+} -+ -+static void dcc_tty_unthrottle(struct tty_struct * tty) -+{ -+ unsigned long irq_flags; -+ -+ spin_lock_irqsave(&g_dcc_tty_lock, irq_flags); -+ dcc_poll_locked(); -+ spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags); -+} -+ -+static enum hrtimer_restart dcc_tty_timer_func(struct hrtimer *timer) -+{ -+ unsigned long irq_flags; -+ -+ spin_lock_irqsave(&g_dcc_tty_lock, irq_flags); -+ dcc_poll_locked(); -+ spin_unlock_irqrestore(&g_dcc_tty_lock, irq_flags); -+ return HRTIMER_NORESTART; -+} -+ -+void dcc_console_write(struct console *co, const char *b, unsigned count) -+{ -+#if 1 -+ dcc_write(b, count); -+#else -+ /* blocking printk */ -+ while (count > 0) { -+ int written; -+ written = dcc_write(b, count); -+ if (written) { -+ b += written; -+ count -= written; -+ } -+ } -+#endif -+} -+ -+static struct tty_driver *dcc_console_device(struct console *c, int *index) -+{ -+ *index = 0; -+ return g_dcc_tty_driver; -+} -+ -+static int __init dcc_console_setup(struct console *co, char *options) -+{ -+ if (co->index != 0) -+ return -ENODEV; -+ return 0; -+} -+ -+ -+static struct console dcc_console = -+{ -+ .name = "ttyDCC", -+ .write = dcc_console_write, -+ .device = dcc_console_device, -+ .setup = dcc_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+}; -+ -+static struct tty_operations dcc_tty_ops = { -+ .open = dcc_tty_open, -+ .close = dcc_tty_close, -+ .write = dcc_tty_write, -+ .write_room = dcc_tty_write_room, -+ .chars_in_buffer = dcc_tty_chars_in_buffer, -+ .unthrottle = dcc_tty_unthrottle, -+}; -+ -+static int __init dcc_tty_init(void) -+{ -+ int ret; -+ -+ hrtimer_init(&g_dcc_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ g_dcc_timer.function = dcc_tty_timer_func; -+ -+ g_dcc_tty_driver = alloc_tty_driver(1); -+ if (!g_dcc_tty_driver) { -+ printk(KERN_ERR "dcc_tty_probe: alloc_tty_driver failed\n"); -+ ret = -ENOMEM; -+ goto err_alloc_tty_driver_failed; -+ } -+ g_dcc_tty_driver->owner = THIS_MODULE; -+ g_dcc_tty_driver->driver_name = "dcc"; -+ g_dcc_tty_driver->name = "ttyDCC"; -+ g_dcc_tty_driver->major = 0; // auto assign -+ g_dcc_tty_driver->minor_start = 0; -+ g_dcc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; -+ g_dcc_tty_driver->subtype = SERIAL_TYPE_NORMAL; -+ g_dcc_tty_driver->init_termios = tty_std_termios; -+ g_dcc_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; -+ tty_set_operations(g_dcc_tty_driver, &dcc_tty_ops); -+ ret = tty_register_driver(g_dcc_tty_driver); -+ if (ret) { -+ printk(KERN_ERR "dcc_tty_probe: tty_register_driver failed, %d\n", ret); -+ goto err_tty_register_driver_failed; -+ } -+ tty_register_device(g_dcc_tty_driver, 0, NULL); -+ -+ register_console(&dcc_console); -+ hrtimer_start(&g_dcc_timer, ktime_set(0, 0), HRTIMER_MODE_REL); -+ -+ return 0; -+ -+err_tty_register_driver_failed: -+ put_tty_driver(g_dcc_tty_driver); -+ g_dcc_tty_driver = NULL; -+err_alloc_tty_driver_failed: -+ return ret; -+} -+ -+static void __exit dcc_tty_exit(void) -+{ -+ int ret; -+ -+ tty_unregister_device(g_dcc_tty_driver, 0); -+ ret = tty_unregister_driver(g_dcc_tty_driver); -+ if (ret < 0) { -+ printk(KERN_ERR "dcc_tty_remove: tty_unregister_driver failed, %d\n", ret); -+ } else { -+ put_tty_driver(g_dcc_tty_driver); -+ } -+ g_dcc_tty_driver = NULL; -+} -+ -+module_init(dcc_tty_init); -+module_exit(dcc_tty_exit); -+ -+ -diff --git a/drivers/char/mem.c b/drivers/char/mem.c -index d6e9d081..67e19b63 100644 ---- a/drivers/char/mem.c -+++ b/drivers/char/mem.c -@@ -57,6 +57,7 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) - } - #endif - -+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) - #ifdef CONFIG_STRICT_DEVMEM - static inline int range_is_allowed(unsigned long pfn, unsigned long size) - { -@@ -82,7 +83,9 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) - return 1; - } - #endif -+#endif - -+#ifdef CONFIG_DEVMEM - void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr) - { - } -@@ -209,6 +212,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf, - *ppos += written; - return written; - } -+#endif /* CONFIG_DEVMEM */ -+ -+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) - - int __weak phys_mem_access_prot_allowed(struct file *file, - unsigned long pfn, unsigned long size, pgprot_t *vma_prot) -@@ -330,6 +336,7 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) - } - return 0; - } -+#endif /* CONFIG_DEVMEM */ - - #ifdef CONFIG_DEVKMEM - static int mmap_kmem(struct file *file, struct vm_area_struct *vma) -@@ -694,6 +701,8 @@ static loff_t null_lseek(struct file *file, loff_t offset, int orig) - return file->f_pos = 0; - } - -+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || defined(CONFIG_DEVPORT) -+ - /* - * The memory devices use the full 32/64 bits of the offset, and so we cannot - * check against negative addresses: they are ok. The return value is weird, -@@ -727,10 +736,14 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig) - return ret; - } - -+#endif -+ -+#if defined(CONFIG_DEVMEM) || defined(CONFIG_DEVKMEM) || defined(CONFIG_DEVPORT) - static int open_port(struct inode * inode, struct file * filp) - { - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; - } -+#endif - - #define zero_lseek null_lseek - #define full_lseek null_lseek -@@ -740,6 +753,7 @@ static int open_port(struct inode * inode, struct file * filp) - #define open_kmem open_mem - #define open_oldmem open_mem - -+#ifdef CONFIG_DEVMEM - static const struct file_operations mem_fops = { - .llseek = memory_lseek, - .read = read_mem, -@@ -748,6 +762,7 @@ static const struct file_operations mem_fops = { - .open = open_mem, - .get_unmapped_area = get_unmapped_area_mem, - }; -+#endif - - #ifdef CONFIG_DEVKMEM - static const struct file_operations kmem_fops = { -@@ -851,7 +866,9 @@ static const struct memdev { - const struct file_operations *fops; - struct backing_dev_info *dev_info; - } devlist[] = { -+#ifdef CONFIG_DEVMEM - [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi }, -+#endif - #ifdef CONFIG_DEVKMEM - [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi }, - #endif -diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig -index e24a2a1b..57f96ebb 100644 ---- a/drivers/cpufreq/Kconfig -+++ b/drivers/cpufreq/Kconfig -@@ -99,6 +99,16 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE - Be aware that not all cpufreq drivers support the conservative - governor. If unsure have a look at the help section of the - driver. Fallback governor will be the performance governor. -+ -+config CPU_FREQ_DEFAULT_GOV_INTERACTIVE -+ bool "interactive" -+ select CPU_FREQ_GOV_INTERACTIVE -+ help -+ Use the CPUFreq governor 'interactive' as default. This allows -+ you to get a full dynamic cpu frequency capable system by simply -+ loading your cpufreq low-level hardware driver, using the -+ 'interactive' governor for latency-sensitive workloads. -+ - endchoice - - config CPU_FREQ_GOV_PERFORMANCE -@@ -156,6 +166,23 @@ config CPU_FREQ_GOV_ONDEMAND - - If in doubt, say N. - -+config CPU_FREQ_GOV_INTERACTIVE -+ tristate "'interactive' cpufreq policy governor" -+ help -+ 'interactive' - This driver adds a dynamic cpufreq policy governor -+ designed for latency-sensitive workloads. -+ -+ This governor attempts to reduce the latency of clock -+ increases so that the system is more responsive to -+ interactive workloads. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called cpufreq_interactive. -+ -+ For details, take a look at linux/Documentation/cpu-freq. -+ -+ If in doubt, say N. -+ - config CPU_FREQ_GOV_CONSERVATIVE - tristate "'conservative' cpufreq governor" - depends on CPU_FREQ -diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index 9531fc2e..35835b7c 100644 ---- a/drivers/cpufreq/Makefile -+++ b/drivers/cpufreq/Makefile -@@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o - obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o - obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o - obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o -+obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o - - # CPUfreq cross-arch helpers - obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o -diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c -new file mode 100644 -index 00000000..7d1952c5 ---- /dev/null -+++ b/drivers/cpufreq/cpufreq_interactive.c -@@ -0,0 +1,1066 @@ -+/* -+ * drivers/cpufreq/cpufreq_interactive.c -+ * -+ * Copyright (C) 2010 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ * Author: Mike Chan (mike@android.com) -+ * -+ */ -+ -+#include <linux/cpu.h> -+#include <linux/cpumask.h> -+#include <linux/cpufreq.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/rwsem.h> -+#include <linux/sched.h> -+#include <linux/tick.h> -+#include <linux/time.h> -+#include <linux/timer.h> -+#include <linux/workqueue.h> -+#include <linux/kthread.h> -+#include <linux/slab.h> -+#include <asm/cputime.h> -+ -+#define CREATE_TRACE_POINTS -+#include <trace/events/cpufreq_interactive.h> -+ -+static int active_count; -+ -+struct cpufreq_interactive_cpuinfo { -+ struct timer_list cpu_timer; -+ struct timer_list cpu_slack_timer; -+ spinlock_t load_lock; /* protects the next 4 fields */ -+ u64 time_in_idle; -+ u64 time_in_idle_timestamp; -+ u64 cputime_speedadj; -+ u64 cputime_speedadj_timestamp; -+ struct cpufreq_policy *policy; -+ struct cpufreq_frequency_table *freq_table; -+ unsigned int target_freq; -+ unsigned int floor_freq; -+ u64 floor_validate_time; -+ u64 hispeed_validate_time; -+ struct rw_semaphore enable_sem; -+ int governor_enabled; -+}; -+ -+static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo); -+ -+/* realtime thread handles frequency scaling */ -+static struct task_struct *speedchange_task; -+static cpumask_t speedchange_cpumask; -+static spinlock_t speedchange_cpumask_lock; -+static struct mutex gov_lock; -+ -+/* Hi speed to bump to from lo speed when load burst (default max) */ -+static unsigned int hispeed_freq; -+ -+/* Go to hi speed when CPU load at or above this value. */ -+#define DEFAULT_GO_HISPEED_LOAD 99 -+static unsigned long go_hispeed_load = DEFAULT_GO_HISPEED_LOAD; -+ -+/* Target load. Lower values result in higher CPU speeds. */ -+#define DEFAULT_TARGET_LOAD 90 -+static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD}; -+static spinlock_t target_loads_lock; -+static unsigned int *target_loads = default_target_loads; -+static int ntarget_loads = ARRAY_SIZE(default_target_loads); -+ -+/* -+ * The minimum amount of time to spend at a frequency before we can ramp down. -+ */ -+#define DEFAULT_MIN_SAMPLE_TIME (80 * USEC_PER_MSEC) -+static unsigned long min_sample_time = DEFAULT_MIN_SAMPLE_TIME; -+ -+/* -+ * The sample rate of the timer used to increase frequency -+ */ -+#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC) -+static unsigned long timer_rate = DEFAULT_TIMER_RATE; -+ -+/* -+ * Wait this long before raising speed above hispeed, by default a single -+ * timer interval. -+ */ -+#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE -+static unsigned long above_hispeed_delay_val = DEFAULT_ABOVE_HISPEED_DELAY; -+ -+/* Non-zero means indefinite speed boost active */ -+static int boost_val; -+/* Duration of a boot pulse in usecs */ -+static int boostpulse_duration_val = DEFAULT_MIN_SAMPLE_TIME; -+/* End time of boost pulse in ktime converted to usecs */ -+static u64 boostpulse_endtime; -+ -+/* -+ * Max additional time to wait in idle, beyond timer_rate, at speeds above -+ * minimum before wakeup to reduce speed, or -1 if unnecessary. -+ */ -+#define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE) -+static int timer_slack_val = DEFAULT_TIMER_SLACK; -+ -+static int cpufreq_governor_interactive(struct cpufreq_policy *policy, -+ unsigned int event); -+ -+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE -+static -+#endif -+struct cpufreq_governor cpufreq_gov_interactive = { -+ .name = "interactive", -+ .governor = cpufreq_governor_interactive, -+ .max_transition_latency = 10000000, -+ .owner = THIS_MODULE, -+}; -+ -+static void cpufreq_interactive_timer_resched( -+ struct cpufreq_interactive_cpuinfo *pcpu) -+{ -+ unsigned long expires = jiffies + usecs_to_jiffies(timer_rate); -+ unsigned long flags; -+ -+ mod_timer_pinned(&pcpu->cpu_timer, expires); -+ if (timer_slack_val >= 0 && pcpu->target_freq > pcpu->policy->min) { -+ expires += usecs_to_jiffies(timer_slack_val); -+ mod_timer_pinned(&pcpu->cpu_slack_timer, expires); -+ } -+ -+ spin_lock_irqsave(&pcpu->load_lock, flags); -+ pcpu->time_in_idle = -+ get_cpu_idle_time_us(smp_processor_id(), -+ &pcpu->time_in_idle_timestamp); -+ pcpu->cputime_speedadj = 0; -+ pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp; -+ spin_unlock_irqrestore(&pcpu->load_lock, flags); -+} -+ -+static unsigned int freq_to_targetload(unsigned int freq) -+{ -+ int i; -+ unsigned int ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&target_loads_lock, flags); -+ -+ for (i = 0; i < ntarget_loads - 1 && freq >= target_loads[i+1]; i += 2) -+ ; -+ -+ ret = target_loads[i]; -+ spin_unlock_irqrestore(&target_loads_lock, flags); -+ return ret; -+} -+ -+/* -+ * If increasing frequencies never map to a lower target load then -+ * choose_freq() will find the minimum frequency that does not exceed its -+ * target load given the current load. -+ */ -+ -+static unsigned int choose_freq( -+ struct cpufreq_interactive_cpuinfo *pcpu, unsigned int loadadjfreq) -+{ -+ unsigned int freq = pcpu->policy->cur; -+ unsigned int prevfreq, freqmin, freqmax; -+ unsigned int tl; -+ int index; -+ -+ freqmin = 0; -+ freqmax = UINT_MAX; -+ -+ do { -+ prevfreq = freq; -+ tl = freq_to_targetload(freq); -+ -+ /* -+ * Find the lowest frequency where the computed load is less -+ * than or equal to the target load. -+ */ -+ -+ cpufreq_frequency_table_target( -+ pcpu->policy, pcpu->freq_table, loadadjfreq / tl, -+ CPUFREQ_RELATION_L, &index); -+ freq = pcpu->freq_table[index].frequency; -+ -+ if (freq > prevfreq) { -+ /* The previous frequency is too low. */ -+ freqmin = prevfreq; -+ -+ if (freq >= freqmax) { -+ /* -+ * Find the highest frequency that is less -+ * than freqmax. -+ */ -+ cpufreq_frequency_table_target( -+ pcpu->policy, pcpu->freq_table, -+ freqmax - 1, CPUFREQ_RELATION_H, -+ &index); -+ freq = pcpu->freq_table[index].frequency; -+ -+ if (freq == freqmin) { -+ /* -+ * The first frequency below freqmax -+ * has already been found to be too -+ * low. freqmax is the lowest speed -+ * we found that is fast enough. -+ */ -+ freq = freqmax; -+ break; -+ } -+ } -+ } else if (freq < prevfreq) { -+ /* The previous frequency is high enough. */ -+ freqmax = prevfreq; -+ -+ if (freq <= freqmin) { -+ /* -+ * Find the lowest frequency that is higher -+ * than freqmin. -+ */ -+ cpufreq_frequency_table_target( -+ pcpu->policy, pcpu->freq_table, -+ freqmin + 1, CPUFREQ_RELATION_L, -+ &index); -+ freq = pcpu->freq_table[index].frequency; -+ -+ /* -+ * If freqmax is the first frequency above -+ * freqmin then we have already found that -+ * this speed is fast enough. -+ */ -+ if (freq == freqmax) -+ break; -+ } -+ } -+ -+ /* If same frequency chosen as previous then done. */ -+ } while (freq != prevfreq); -+ -+ return freq; -+} -+ -+static u64 update_load(int cpu) -+{ -+ struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu); -+ u64 now; -+ u64 now_idle; -+ unsigned int delta_idle; -+ unsigned int delta_time; -+ u64 active_time; -+ -+ now_idle = get_cpu_idle_time_us(cpu, &now); -+ delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle); -+ delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp); -+ active_time = delta_time - delta_idle; -+ pcpu->cputime_speedadj += active_time * pcpu->policy->cur; -+ -+ pcpu->time_in_idle = now_idle; -+ pcpu->time_in_idle_timestamp = now; -+ return now; -+} -+ -+static void cpufreq_interactive_timer(unsigned long data) -+{ -+ u64 now; -+ unsigned int delta_time; -+ u64 cputime_speedadj; -+ int cpu_load; -+ struct cpufreq_interactive_cpuinfo *pcpu = -+ &per_cpu(cpuinfo, data); -+ unsigned int new_freq; -+ unsigned int loadadjfreq; -+ unsigned int index; -+ unsigned long flags; -+ bool boosted; -+ -+ if (!down_read_trylock(&pcpu->enable_sem)) -+ return; -+ if (!pcpu->governor_enabled) -+ goto exit; -+ -+ spin_lock_irqsave(&pcpu->load_lock, flags); -+ now = update_load(data); -+ delta_time = (unsigned int)(now - pcpu->cputime_speedadj_timestamp); -+ cputime_speedadj = pcpu->cputime_speedadj; -+ spin_unlock_irqrestore(&pcpu->load_lock, flags); -+ -+ if (WARN_ON_ONCE(!delta_time)) -+ goto rearm; -+ -+ do_div(cputime_speedadj, delta_time); -+ loadadjfreq = (unsigned int)cputime_speedadj * 100; -+ cpu_load = loadadjfreq / pcpu->target_freq; -+ boosted = boost_val || now < boostpulse_endtime; -+ -+ if (cpu_load >= go_hispeed_load || boosted) { -+ if (pcpu->target_freq < hispeed_freq) { -+ new_freq = hispeed_freq; -+ } else { -+ new_freq = choose_freq(pcpu, loadadjfreq); -+ -+ if (new_freq < hispeed_freq) -+ new_freq = hispeed_freq; -+ } -+ } else { -+ new_freq = choose_freq(pcpu, loadadjfreq); -+ } -+ -+ if (pcpu->target_freq >= hispeed_freq && -+ new_freq > pcpu->target_freq && -+ now - pcpu->hispeed_validate_time < above_hispeed_delay_val) { -+ trace_cpufreq_interactive_notyet( -+ data, cpu_load, pcpu->target_freq, -+ pcpu->policy->cur, new_freq); -+ goto rearm; -+ } -+ -+ pcpu->hispeed_validate_time = now; -+ -+ if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table, -+ new_freq, CPUFREQ_RELATION_L, -+ &index)) { -+ pr_warn_once("timer %d: cpufreq_frequency_table_target error\n", -+ (int) data); -+ goto rearm; -+ } -+ -+ new_freq = pcpu->freq_table[index].frequency; -+ -+ /* -+ * Do not scale below floor_freq unless we have been at or above the -+ * floor frequency for the minimum sample time since last validated. -+ */ -+ if (new_freq < pcpu->floor_freq) { -+ if (now - pcpu->floor_validate_time < min_sample_time) { -+ trace_cpufreq_interactive_notyet( -+ data, cpu_load, pcpu->target_freq, -+ pcpu->policy->cur, new_freq); -+ goto rearm; -+ } -+ } -+ -+ /* -+ * Update the timestamp for checking whether speed has been held at -+ * or above the selected frequency for a minimum of min_sample_time, -+ * if not boosted to hispeed_freq. If boosted to hispeed_freq then we -+ * allow the speed to drop as soon as the boostpulse duration expires -+ * (or the indefinite boost is turned off). -+ */ -+ -+ if (!boosted || new_freq > hispeed_freq) { -+ pcpu->floor_freq = new_freq; -+ pcpu->floor_validate_time = now; -+ } -+ -+ if (pcpu->target_freq == new_freq) { -+ trace_cpufreq_interactive_already( -+ data, cpu_load, pcpu->target_freq, -+ pcpu->policy->cur, new_freq); -+ goto rearm_if_notmax; -+ } -+ -+ trace_cpufreq_interactive_target(data, cpu_load, pcpu->target_freq, -+ pcpu->policy->cur, new_freq); -+ -+ pcpu->target_freq = new_freq; -+ spin_lock_irqsave(&speedchange_cpumask_lock, flags); -+ cpumask_set_cpu(data, &speedchange_cpumask); -+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); -+ wake_up_process(speedchange_task); -+ -+rearm_if_notmax: -+ /* -+ * Already set max speed and don't see a need to change that, -+ * wait until next idle to re-evaluate, don't need timer. -+ */ -+ if (pcpu->target_freq == pcpu->policy->max) -+ goto exit; -+ -+rearm: -+ if (!timer_pending(&pcpu->cpu_timer)) -+ cpufreq_interactive_timer_resched(pcpu); -+ -+exit: -+ up_read(&pcpu->enable_sem); -+ return; -+} -+ -+static void cpufreq_interactive_idle_start(void) -+{ -+ struct cpufreq_interactive_cpuinfo *pcpu = -+ &per_cpu(cpuinfo, smp_processor_id()); -+ int pending; -+ -+ if (!down_read_trylock(&pcpu->enable_sem)) -+ return; -+ if (!pcpu->governor_enabled) { -+ up_read(&pcpu->enable_sem); -+ return; -+ } -+ -+ pending = timer_pending(&pcpu->cpu_timer); -+ -+ if (pcpu->target_freq != pcpu->policy->min) { -+ /* -+ * Entering idle while not at lowest speed. On some -+ * platforms this can hold the other CPU(s) at that speed -+ * even though the CPU is idle. Set a timer to re-evaluate -+ * speed so this idle CPU doesn't hold the other CPUs above -+ * min indefinitely. This should probably be a quirk of -+ * the CPUFreq driver. -+ */ -+ if (!pending) -+ cpufreq_interactive_timer_resched(pcpu); -+ } -+ -+ up_read(&pcpu->enable_sem); -+} -+ -+static void cpufreq_interactive_idle_end(void) -+{ -+ struct cpufreq_interactive_cpuinfo *pcpu = -+ &per_cpu(cpuinfo, smp_processor_id()); -+ -+ if (!down_read_trylock(&pcpu->enable_sem)) -+ return; -+ if (!pcpu->governor_enabled) { -+ up_read(&pcpu->enable_sem); -+ return; -+ } -+ -+ /* Arm the timer for 1-2 ticks later if not already. */ -+ if (!timer_pending(&pcpu->cpu_timer)) { -+ cpufreq_interactive_timer_resched(pcpu); -+ } else if (time_after_eq(jiffies, pcpu->cpu_timer.expires)) { -+ del_timer(&pcpu->cpu_timer); -+ del_timer(&pcpu->cpu_slack_timer); -+ cpufreq_interactive_timer(smp_processor_id()); -+ } -+ -+ up_read(&pcpu->enable_sem); -+} -+ -+static int cpufreq_interactive_speedchange_task(void *data) -+{ -+ unsigned int cpu; -+ cpumask_t tmp_mask; -+ unsigned long flags; -+ struct cpufreq_interactive_cpuinfo *pcpu; -+ -+ while (1) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&speedchange_cpumask_lock, flags); -+ -+ if (cpumask_empty(&speedchange_cpumask)) { -+ spin_unlock_irqrestore(&speedchange_cpumask_lock, -+ flags); -+ schedule(); -+ -+ if (kthread_should_stop()) -+ break; -+ -+ spin_lock_irqsave(&speedchange_cpumask_lock, flags); -+ } -+ -+ set_current_state(TASK_RUNNING); -+ tmp_mask = speedchange_cpumask; -+ cpumask_clear(&speedchange_cpumask); -+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); -+ -+ for_each_cpu(cpu, &tmp_mask) { -+ unsigned int j; -+ unsigned int max_freq = 0; -+ -+ pcpu = &per_cpu(cpuinfo, cpu); -+ if (!down_read_trylock(&pcpu->enable_sem)) -+ continue; -+ if (!pcpu->governor_enabled) { -+ up_read(&pcpu->enable_sem); -+ continue; -+ } -+ -+ for_each_cpu(j, pcpu->policy->cpus) { -+ struct cpufreq_interactive_cpuinfo *pjcpu = -+ &per_cpu(cpuinfo, j); -+ -+ if (pjcpu->target_freq > max_freq) -+ max_freq = pjcpu->target_freq; -+ } -+ -+ if (max_freq != pcpu->policy->cur) -+ __cpufreq_driver_target(pcpu->policy, -+ max_freq, -+ CPUFREQ_RELATION_H); -+ trace_cpufreq_interactive_setspeed(cpu, -+ pcpu->target_freq, -+ pcpu->policy->cur); -+ -+ up_read(&pcpu->enable_sem); -+ } -+ } -+ -+ return 0; -+} -+ -+static void cpufreq_interactive_boost(void) -+{ -+ int i; -+ int anyboost = 0; -+ unsigned long flags; -+ struct cpufreq_interactive_cpuinfo *pcpu; -+ -+ spin_lock_irqsave(&speedchange_cpumask_lock, flags); -+ -+ for_each_online_cpu(i) { -+ pcpu = &per_cpu(cpuinfo, i); -+ -+ if (pcpu->target_freq < hispeed_freq) { -+ pcpu->target_freq = hispeed_freq; -+ cpumask_set_cpu(i, &speedchange_cpumask); -+ pcpu->hispeed_validate_time = -+ ktime_to_us(ktime_get()); -+ anyboost = 1; -+ } -+ -+ /* -+ * Set floor freq and (re)start timer for when last -+ * validated. -+ */ -+ -+ pcpu->floor_freq = hispeed_freq; -+ pcpu->floor_validate_time = ktime_to_us(ktime_get()); -+ } -+ -+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); -+ -+ if (anyboost) -+ wake_up_process(speedchange_task); -+} -+ -+static int cpufreq_interactive_notifier( -+ struct notifier_block *nb, unsigned long val, void *data) -+{ -+ struct cpufreq_freqs *freq = data; -+ struct cpufreq_interactive_cpuinfo *pcpu; -+ int cpu; -+ unsigned long flags; -+ -+ if (val == CPUFREQ_POSTCHANGE) { -+ pcpu = &per_cpu(cpuinfo, freq->cpu); -+ if (!down_read_trylock(&pcpu->enable_sem)) -+ return 0; -+ if (!pcpu->governor_enabled) { -+ up_read(&pcpu->enable_sem); -+ return 0; -+ } -+ -+ for_each_cpu(cpu, pcpu->policy->cpus) { -+ struct cpufreq_interactive_cpuinfo *pjcpu = -+ &per_cpu(cpuinfo, cpu); -+ spin_lock_irqsave(&pjcpu->load_lock, flags); -+ update_load(cpu); -+ spin_unlock_irqrestore(&pjcpu->load_lock, flags); -+ } -+ -+ up_read(&pcpu->enable_sem); -+ } -+ return 0; -+} -+ -+static struct notifier_block cpufreq_notifier_block = { -+ .notifier_call = cpufreq_interactive_notifier, -+}; -+ -+static ssize_t show_target_loads( -+ struct kobject *kobj, struct attribute *attr, char *buf) -+{ -+ int i; -+ ssize_t ret = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&target_loads_lock, flags); -+ -+ for (i = 0; i < ntarget_loads; i++) -+ ret += sprintf(buf + ret, "%u%s", target_loads[i], -+ i & 0x1 ? ":" : " "); -+ -+ ret += sprintf(buf + ret, "\n"); -+ spin_unlock_irqrestore(&target_loads_lock, flags); -+ return ret; -+} -+ -+static ssize_t store_target_loads( -+ struct kobject *kobj, struct attribute *attr, const char *buf, -+ size_t count) -+{ -+ int ret; -+ const char *cp; -+ unsigned int *new_target_loads = NULL; -+ int ntokens = 1; -+ int i; -+ unsigned long flags; -+ -+ cp = buf; -+ while ((cp = strpbrk(cp + 1, " :"))) -+ ntokens++; -+ -+ if (!(ntokens & 0x1)) -+ goto err_inval; -+ -+ new_target_loads = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL); -+ if (!new_target_loads) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ cp = buf; -+ i = 0; -+ while (i < ntokens) { -+ if (sscanf(cp, "%u", &new_target_loads[i++]) != 1) -+ goto err_inval; -+ -+ cp = strpbrk(cp, " :"); -+ if (!cp) -+ break; -+ cp++; -+ } -+ -+ if (i != ntokens) -+ goto err_inval; -+ -+ spin_lock_irqsave(&target_loads_lock, flags); -+ if (target_loads != default_target_loads) -+ kfree(target_loads); -+ target_loads = new_target_loads; -+ ntarget_loads = ntokens; -+ spin_unlock_irqrestore(&target_loads_lock, flags); -+ return count; -+ -+err_inval: -+ ret = -EINVAL; -+err: -+ kfree(new_target_loads); -+ return ret; -+} -+ -+static struct global_attr target_loads_attr = -+ __ATTR(target_loads, S_IRUGO | S_IWUSR, -+ show_target_loads, store_target_loads); -+ -+static ssize_t show_hispeed_freq(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%u\n", hispeed_freq); -+} -+ -+static ssize_t store_hispeed_freq(struct kobject *kobj, -+ struct attribute *attr, const char *buf, -+ size_t count) -+{ -+ int ret; -+ long unsigned int val; -+ -+ ret = strict_strtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ hispeed_freq = val; -+ return count; -+} -+ -+static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644, -+ show_hispeed_freq, store_hispeed_freq); -+ -+ -+static ssize_t show_go_hispeed_load(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%lu\n", go_hispeed_load); -+} -+ -+static ssize_t store_go_hispeed_load(struct kobject *kobj, -+ struct attribute *attr, const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = strict_strtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ go_hispeed_load = val; -+ return count; -+} -+ -+static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load, 0644, -+ show_go_hispeed_load, store_go_hispeed_load); -+ -+static ssize_t show_min_sample_time(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%lu\n", min_sample_time); -+} -+ -+static ssize_t store_min_sample_time(struct kobject *kobj, -+ struct attribute *attr, const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = strict_strtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ min_sample_time = val; -+ return count; -+} -+ -+static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644, -+ show_min_sample_time, store_min_sample_time); -+ -+static ssize_t show_above_hispeed_delay(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%lu\n", above_hispeed_delay_val); -+} -+ -+static ssize_t store_above_hispeed_delay(struct kobject *kobj, -+ struct attribute *attr, -+ const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = strict_strtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ above_hispeed_delay_val = val; -+ return count; -+} -+ -+define_one_global_rw(above_hispeed_delay); -+ -+static ssize_t show_timer_rate(struct kobject *kobj, -+ struct attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%lu\n", timer_rate); -+} -+ -+static ssize_t store_timer_rate(struct kobject *kobj, -+ struct attribute *attr, const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = strict_strtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ timer_rate = val; -+ return count; -+} -+ -+static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644, -+ show_timer_rate, store_timer_rate); -+ -+static ssize_t show_timer_slack( -+ struct kobject *kobj, struct attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%d\n", timer_slack_val); -+} -+ -+static ssize_t store_timer_slack( -+ struct kobject *kobj, struct attribute *attr, const char *buf, -+ size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = kstrtol(buf, 10, &val); -+ if (ret < 0) -+ return ret; -+ -+ timer_slack_val = val; -+ return count; -+} -+ -+define_one_global_rw(timer_slack); -+ -+static ssize_t show_boost(struct kobject *kobj, struct attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%d\n", boost_val); -+} -+ -+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr, -+ const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = kstrtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ -+ boost_val = val; -+ -+ if (boost_val) { -+ trace_cpufreq_interactive_boost("on"); -+ cpufreq_interactive_boost(); -+ } else { -+ trace_cpufreq_interactive_unboost("off"); -+ } -+ -+ return count; -+} -+ -+define_one_global_rw(boost); -+ -+static ssize_t store_boostpulse(struct kobject *kobj, struct attribute *attr, -+ const char *buf, size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = kstrtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ -+ boostpulse_endtime = ktime_to_us(ktime_get()) + boostpulse_duration_val; -+ trace_cpufreq_interactive_boost("pulse"); -+ cpufreq_interactive_boost(); -+ return count; -+} -+ -+static struct global_attr boostpulse = -+ __ATTR(boostpulse, 0200, NULL, store_boostpulse); -+ -+static ssize_t show_boostpulse_duration( -+ struct kobject *kobj, struct attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%d\n", boostpulse_duration_val); -+} -+ -+static ssize_t store_boostpulse_duration( -+ struct kobject *kobj, struct attribute *attr, const char *buf, -+ size_t count) -+{ -+ int ret; -+ unsigned long val; -+ -+ ret = kstrtoul(buf, 0, &val); -+ if (ret < 0) -+ return ret; -+ -+ boostpulse_duration_val = val; -+ return count; -+} -+ -+define_one_global_rw(boostpulse_duration); -+ -+static struct attribute *interactive_attributes[] = { -+ &target_loads_attr.attr, -+ &hispeed_freq_attr.attr, -+ &go_hispeed_load_attr.attr, -+ &above_hispeed_delay.attr, -+ &min_sample_time_attr.attr, -+ &timer_rate_attr.attr, -+ &timer_slack.attr, -+ &boost.attr, -+ &boostpulse.attr, -+ &boostpulse_duration.attr, -+ NULL, -+}; -+ -+static struct attribute_group interactive_attr_group = { -+ .attrs = interactive_attributes, -+ .name = "interactive", -+}; -+ -+static int cpufreq_interactive_idle_notifier(struct notifier_block *nb, -+ unsigned long val, -+ void *data) -+{ -+ switch (val) { -+ case IDLE_START: -+ cpufreq_interactive_idle_start(); -+ break; -+ case IDLE_END: -+ cpufreq_interactive_idle_end(); -+ break; -+ } -+ -+ return 0; -+} -+ -+static struct notifier_block cpufreq_interactive_idle_nb = { -+ .notifier_call = cpufreq_interactive_idle_notifier, -+}; -+ -+static int cpufreq_governor_interactive(struct cpufreq_policy *policy, -+ unsigned int event) -+{ -+ int rc; -+ unsigned int j; -+ struct cpufreq_interactive_cpuinfo *pcpu; -+ struct cpufreq_frequency_table *freq_table; -+ -+ switch (event) { -+ case CPUFREQ_GOV_START: -+ if (!cpu_online(policy->cpu)) -+ return -EINVAL; -+ -+ mutex_lock(&gov_lock); -+ -+ freq_table = -+ cpufreq_frequency_get_table(policy->cpu); -+ if (!hispeed_freq) -+ hispeed_freq = policy->max; -+ -+ for_each_cpu(j, policy->cpus) { -+ unsigned long expires; -+ -+ pcpu = &per_cpu(cpuinfo, j); -+ pcpu->policy = policy; -+ pcpu->target_freq = policy->cur; -+ pcpu->freq_table = freq_table; -+ pcpu->floor_freq = pcpu->target_freq; -+ pcpu->floor_validate_time = -+ ktime_to_us(ktime_get()); -+ pcpu->hispeed_validate_time = -+ pcpu->floor_validate_time; -+ down_write(&pcpu->enable_sem); -+ expires = jiffies + usecs_to_jiffies(timer_rate); -+ pcpu->cpu_timer.expires = expires; -+ add_timer_on(&pcpu->cpu_timer, j); -+ if (timer_slack_val >= 0) { -+ expires += usecs_to_jiffies(timer_slack_val); -+ pcpu->cpu_slack_timer.expires = expires; -+ add_timer_on(&pcpu->cpu_slack_timer, j); -+ } -+ pcpu->governor_enabled = 1; -+ up_write(&pcpu->enable_sem); -+ } -+ -+ /* -+ * Do not register the idle hook and create sysfs -+ * entries if we have already done so. -+ */ -+ if (++active_count > 1) { -+ mutex_unlock(&gov_lock); -+ return 0; -+ } -+ -+ rc = sysfs_create_group(cpufreq_global_kobject, -+ &interactive_attr_group); -+ if (rc) { -+ mutex_unlock(&gov_lock); -+ return rc; -+ } -+ -+ idle_notifier_register(&cpufreq_interactive_idle_nb); -+ cpufreq_register_notifier( -+ &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -+ mutex_unlock(&gov_lock); -+ break; -+ -+ case CPUFREQ_GOV_STOP: -+ mutex_lock(&gov_lock); -+ for_each_cpu(j, policy->cpus) { -+ pcpu = &per_cpu(cpuinfo, j); -+ down_write(&pcpu->enable_sem); -+ pcpu->governor_enabled = 0; -+ del_timer_sync(&pcpu->cpu_timer); -+ del_timer_sync(&pcpu->cpu_slack_timer); -+ up_write(&pcpu->enable_sem); -+ } -+ -+ if (--active_count > 0) { -+ mutex_unlock(&gov_lock); -+ return 0; -+ } -+ -+ cpufreq_unregister_notifier( -+ &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -+ idle_notifier_unregister(&cpufreq_interactive_idle_nb); -+ sysfs_remove_group(cpufreq_global_kobject, -+ &interactive_attr_group); -+ mutex_unlock(&gov_lock); -+ -+ break; -+ -+ case CPUFREQ_GOV_LIMITS: -+ if (policy->max < policy->cur) -+ __cpufreq_driver_target(policy, -+ policy->max, CPUFREQ_RELATION_H); -+ else if (policy->min > policy->cur) -+ __cpufreq_driver_target(policy, -+ policy->min, CPUFREQ_RELATION_L); -+ break; -+ } -+ return 0; -+} -+ -+static void cpufreq_interactive_nop_timer(unsigned long data) -+{ -+} -+ -+static int __init cpufreq_interactive_init(void) -+{ -+ unsigned int i; -+ struct cpufreq_interactive_cpuinfo *pcpu; -+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; -+ -+ /* Initalize per-cpu timers */ -+ for_each_possible_cpu(i) { -+ pcpu = &per_cpu(cpuinfo, i); -+ init_timer_deferrable(&pcpu->cpu_timer); -+ pcpu->cpu_timer.function = cpufreq_interactive_timer; -+ pcpu->cpu_timer.data = i; -+ init_timer(&pcpu->cpu_slack_timer); -+ pcpu->cpu_slack_timer.function = cpufreq_interactive_nop_timer; -+ spin_lock_init(&pcpu->load_lock); -+ init_rwsem(&pcpu->enable_sem); -+ } -+ -+ spin_lock_init(&target_loads_lock); -+ spin_lock_init(&speedchange_cpumask_lock); -+ mutex_init(&gov_lock); -+ speedchange_task = -+ kthread_create(cpufreq_interactive_speedchange_task, NULL, -+ "cfinteractive"); -+ if (IS_ERR(speedchange_task)) -+ return PTR_ERR(speedchange_task); -+ -+ sched_setscheduler_nocheck(speedchange_task, SCHED_FIFO, ¶m); -+ get_task_struct(speedchange_task); -+ -+ /* NB: wake up so the thread does not look hung to the freezer */ -+ wake_up_process(speedchange_task); -+ -+ return cpufreq_register_governor(&cpufreq_gov_interactive); -+} -+ -+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE -+fs_initcall(cpufreq_interactive_init); -+#else -+module_init(cpufreq_interactive_init); -+#endif -+ -+static void __exit cpufreq_interactive_exit(void) -+{ -+ cpufreq_unregister_governor(&cpufreq_gov_interactive); -+ kthread_stop(speedchange_task); -+ put_task_struct(speedchange_task); -+} -+ -+module_exit(cpufreq_interactive_exit); -+ -+MODULE_AUTHOR("Mike Chan <mike@android.com>"); -+MODULE_DESCRIPTION("'cpufreq_interactive' - A cpufreq governor for " -+ "Latency sensitive workloads"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c -index b40ee140..72f0093a 100644 ---- a/drivers/cpufreq/cpufreq_stats.c -+++ b/drivers/cpufreq/cpufreq_stats.c -@@ -316,6 +316,27 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, - return 0; - } - -+static int cpufreq_stats_create_table_cpu(unsigned int cpu) -+{ -+ struct cpufreq_policy *policy; -+ struct cpufreq_frequency_table *table; -+ int ret = -ENODEV; -+ -+ policy = cpufreq_cpu_get(cpu); -+ if (!policy) -+ return -ENODEV; -+ -+ table = cpufreq_frequency_get_table(cpu); -+ if (!table) -+ goto out; -+ -+ ret = cpufreq_stats_create_table(policy, table); -+ -+out: -+ cpufreq_cpu_put(policy); -+ return ret; -+} -+ - static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) -@@ -334,6 +355,10 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, - case CPU_DEAD_FROZEN: - cpufreq_stats_free_table(cpu); - break; -+ case CPU_DOWN_FAILED: -+ case CPU_DOWN_FAILED_FROZEN: -+ cpufreq_stats_create_table_cpu(cpu); -+ break; - } - return NOTIFY_OK; - } -diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig -index 78a666d1..a76b689e 100644 ---- a/drivers/cpuidle/Kconfig -+++ b/drivers/cpuidle/Kconfig -@@ -18,3 +18,6 @@ config CPU_IDLE_GOV_MENU - bool - depends on CPU_IDLE && NO_HZ - default y -+ -+config ARCH_NEEDS_CPU_IDLE_COUPLED -+ def_bool n -diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile -index 5634f883..38c8f69f 100644 ---- a/drivers/cpuidle/Makefile -+++ b/drivers/cpuidle/Makefile -@@ -3,3 +3,4 @@ - # - - obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ -+obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o -diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c -new file mode 100644 -index 00000000..e95c72e9 ---- /dev/null -+++ b/drivers/cpuidle/coupled.c -@@ -0,0 +1,727 @@ -+/* -+ * coupled.c - helper functions to enter the same idle state on multiple cpus -+ * -+ * Copyright (c) 2011 Google, Inc. -+ * -+ * Author: Colin Cross <ccross@android.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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/cpu.h> -+#include <linux/cpuidle.h> -+#include <linux/mutex.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+ -+#include "cpuidle.h" -+ -+/** -+ * DOC: Coupled cpuidle states -+ * -+ * On some ARM SMP SoCs (OMAP4460, Tegra 2, and probably more), the -+ * cpus cannot be independently powered down, either due to -+ * sequencing restrictions (on Tegra 2, cpu 0 must be the last to -+ * power down), or due to HW bugs (on OMAP4460, a cpu powering up -+ * will corrupt the gic state unless the other cpu runs a work -+ * around). Each cpu has a power state that it can enter without -+ * coordinating with the other cpu (usually Wait For Interrupt, or -+ * WFI), and one or more "coupled" power states that affect blocks -+ * shared between the cpus (L2 cache, interrupt controller, and -+ * sometimes the whole SoC). Entering a coupled power state must -+ * be tightly controlled on both cpus. -+ * -+ * This file implements a solution, where each cpu will wait in the -+ * WFI state until all cpus are ready to enter a coupled state, at -+ * which point the coupled state function will be called on all -+ * cpus at approximately the same time. -+ * -+ * Once all cpus are ready to enter idle, they are woken by an smp -+ * cross call. At this point, there is a chance that one of the -+ * cpus will find work to do, and choose not to enter idle. A -+ * final pass is needed to guarantee that all cpus will call the -+ * power state enter function at the same time. During this pass, -+ * each cpu will increment the ready counter, and continue once the -+ * ready counter matches the number of online coupled cpus. If any -+ * cpu exits idle, the other cpus will decrement their counter and -+ * retry. -+ * -+ * requested_state stores the deepest coupled idle state each cpu -+ * is ready for. It is assumed that the states are indexed from -+ * shallowest (highest power, lowest exit latency) to deepest -+ * (lowest power, highest exit latency). The requested_state -+ * variable is not locked. It is only written from the cpu that -+ * it stores (or by the on/offlining cpu if that cpu is offline), -+ * and only read after all the cpus are ready for the coupled idle -+ * state are are no longer updating it. -+ * -+ * Three atomic counters are used. alive_count tracks the number -+ * of cpus in the coupled set that are currently or soon will be -+ * online. waiting_count tracks the number of cpus that are in -+ * the waiting loop, in the ready loop, or in the coupled idle state. -+ * ready_count tracks the number of cpus that are in the ready loop -+ * or in the coupled idle state. -+ * -+ * To use coupled cpuidle states, a cpuidle driver must: -+ * -+ * Set struct cpuidle_device.coupled_cpus to the mask of all -+ * coupled cpus, usually the same as cpu_possible_mask if all cpus -+ * are part of the same cluster. The coupled_cpus mask must be -+ * set in the struct cpuidle_device for each cpu. -+ * -+ * Set struct cpuidle_device.safe_state to a state that is not a -+ * coupled state. This is usually WFI. -+ * -+ * Set CPUIDLE_FLAG_COUPLED in struct cpuidle_state.flags for each -+ * state that affects multiple cpus. -+ * -+ * Provide a struct cpuidle_state.enter function for each state -+ * that affects multiple cpus. This function is guaranteed to be -+ * called on all cpus at approximately the same time. The driver -+ * should ensure that the cpus all abort together if any cpu tries -+ * to abort once the function is called. The function should return -+ * with interrupts still disabled. -+ */ -+ -+/** -+ * struct cpuidle_coupled - data for set of cpus that share a coupled idle state -+ * @coupled_cpus: mask of cpus that are part of the coupled set -+ * @requested_state: array of requested states for cpus in the coupled set -+ * @ready_waiting_counts: combined count of cpus in ready or waiting loops -+ * @online_count: count of cpus that are online -+ * @refcnt: reference count of cpuidle devices that are using this struct -+ * @prevent: flag to prevent coupled idle while a cpu is hotplugging -+ */ -+struct cpuidle_coupled { -+ cpumask_t coupled_cpus; -+ int requested_state[NR_CPUS]; -+ atomic_t ready_waiting_counts; -+ int online_count; -+ int refcnt; -+ int prevent; -+}; -+ -+#define WAITING_BITS 16 -+#define MAX_WAITING_CPUS (1 << WAITING_BITS) -+#define WAITING_MASK (MAX_WAITING_CPUS - 1) -+#define READY_MASK (~WAITING_MASK) -+ -+#define CPUIDLE_COUPLED_NOT_IDLE (-1) -+ -+static DEFINE_MUTEX(cpuidle_coupled_lock); -+static DEFINE_PER_CPU(struct call_single_data, cpuidle_coupled_poke_cb); -+ -+/* -+ * The cpuidle_coupled_poked_mask mask is used to avoid calling -+ * __smp_call_function_single with the per cpu call_single_data struct already -+ * in use. This prevents a deadlock where two cpus are waiting for each others -+ * call_single_data struct to be available -+ */ -+static cpumask_t cpuidle_coupled_poked_mask; -+ -+/** -+ * cpuidle_coupled_parallel_barrier - synchronize all online coupled cpus -+ * @dev: cpuidle_device of the calling cpu -+ * @a: atomic variable to hold the barrier -+ * -+ * No caller to this function will return from this function until all online -+ * cpus in the same coupled group have called this function. Once any caller -+ * has returned from this function, the barrier is immediately available for -+ * reuse. -+ * -+ * The atomic variable a must be initialized to 0 before any cpu calls -+ * this function, will be reset to 0 before any cpu returns from this function. -+ * -+ * Must only be called from within a coupled idle state handler -+ * (state.enter when state.flags has CPUIDLE_FLAG_COUPLED set). -+ * -+ * Provides full smp barrier semantics before and after calling. -+ */ -+void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a) -+{ -+ int n = dev->coupled->online_count; -+ -+ smp_mb__before_atomic_inc(); -+ atomic_inc(a); -+ -+ while (atomic_read(a) < n) -+ cpu_relax(); -+ -+ if (atomic_inc_return(a) == n * 2) { -+ atomic_set(a, 0); -+ return; -+ } -+ -+ while (atomic_read(a) > n) -+ cpu_relax(); -+} -+ -+/** -+ * cpuidle_state_is_coupled - check if a state is part of a coupled set -+ * @dev: struct cpuidle_device for the current cpu -+ * @drv: struct cpuidle_driver for the platform -+ * @state: index of the target state in drv->states -+ * -+ * Returns true if the target state is coupled with cpus besides this one -+ */ -+bool cpuidle_state_is_coupled(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int state) -+{ -+ return drv->states[state].flags & CPUIDLE_FLAG_COUPLED; -+} -+ -+/** -+ * cpuidle_coupled_set_ready - mark a cpu as ready -+ * @coupled: the struct coupled that contains the current cpu -+ */ -+static inline void cpuidle_coupled_set_ready(struct cpuidle_coupled *coupled) -+{ -+ atomic_add(MAX_WAITING_CPUS, &coupled->ready_waiting_counts); -+} -+ -+/** -+ * cpuidle_coupled_set_not_ready - mark a cpu as not ready -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Decrements the ready counter, unless the ready (and thus the waiting) counter -+ * is equal to the number of online cpus. Prevents a race where one cpu -+ * decrements the waiting counter and then re-increments it just before another -+ * cpu has decremented its ready counter, leading to the ready counter going -+ * down from the number of online cpus without going through the coupled idle -+ * state. -+ * -+ * Returns 0 if the counter was decremented successfully, -EINVAL if the ready -+ * counter was equal to the number of online cpus. -+ */ -+static -+inline int cpuidle_coupled_set_not_ready(struct cpuidle_coupled *coupled) -+{ -+ int all; -+ int ret; -+ -+ all = coupled->online_count || (coupled->online_count << WAITING_BITS); -+ ret = atomic_add_unless(&coupled->ready_waiting_counts, -+ -MAX_WAITING_CPUS, all); -+ -+ return ret ? 0 : -EINVAL; -+} -+ -+/** -+ * cpuidle_coupled_no_cpus_ready - check if no cpus in a coupled set are ready -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Returns true if all of the cpus in a coupled set are out of the ready loop. -+ */ -+static inline int cpuidle_coupled_no_cpus_ready(struct cpuidle_coupled *coupled) -+{ -+ int r = atomic_read(&coupled->ready_waiting_counts) >> WAITING_BITS; -+ return r == 0; -+} -+ -+/** -+ * cpuidle_coupled_cpus_ready - check if all cpus in a coupled set are ready -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Returns true if all cpus coupled to this target state are in the ready loop -+ */ -+static inline bool cpuidle_coupled_cpus_ready(struct cpuidle_coupled *coupled) -+{ -+ int r = atomic_read(&coupled->ready_waiting_counts) >> WAITING_BITS; -+ return r == coupled->online_count; -+} -+ -+/** -+ * cpuidle_coupled_cpus_waiting - check if all cpus in a coupled set are waiting -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Returns true if all cpus coupled to this target state are in the wait loop -+ */ -+static inline bool cpuidle_coupled_cpus_waiting(struct cpuidle_coupled *coupled) -+{ -+ int w = atomic_read(&coupled->ready_waiting_counts) & WAITING_MASK; -+ return w == coupled->online_count; -+} -+ -+/** -+ * cpuidle_coupled_no_cpus_waiting - check if no cpus in coupled set are waiting -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Returns true if all of the cpus in a coupled set are out of the waiting loop. -+ */ -+static inline int cpuidle_coupled_no_cpus_waiting(struct cpuidle_coupled *coupled) -+{ -+ int w = atomic_read(&coupled->ready_waiting_counts) & WAITING_MASK; -+ return w == 0; -+} -+ -+/** -+ * cpuidle_coupled_get_state - determine the deepest idle state -+ * @dev: struct cpuidle_device for this cpu -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Returns the deepest idle state that all coupled cpus can enter -+ */ -+static inline int cpuidle_coupled_get_state(struct cpuidle_device *dev, -+ struct cpuidle_coupled *coupled) -+{ -+ int i; -+ int state = INT_MAX; -+ -+ /* -+ * Read barrier ensures that read of requested_state is ordered after -+ * reads of ready_count. Matches the write barriers -+ * cpuidle_set_state_waiting. -+ */ -+ smp_rmb(); -+ -+ for_each_cpu_mask(i, coupled->coupled_cpus) -+ if (cpu_online(i) && coupled->requested_state[i] < state) -+ state = coupled->requested_state[i]; -+ -+ return state; -+} -+ -+static void cpuidle_coupled_poked(void *info) -+{ -+ int cpu = (unsigned long)info; -+ cpumask_clear_cpu(cpu, &cpuidle_coupled_poked_mask); -+} -+ -+/** -+ * cpuidle_coupled_poke - wake up a cpu that may be waiting -+ * @cpu: target cpu -+ * -+ * Ensures that the target cpu exits it's waiting idle state (if it is in it) -+ * and will see updates to waiting_count before it re-enters it's waiting idle -+ * state. -+ * -+ * If cpuidle_coupled_poked_mask is already set for the target cpu, that cpu -+ * either has or will soon have a pending IPI that will wake it out of idle, -+ * or it is currently processing the IPI and is not in idle. -+ */ -+static void cpuidle_coupled_poke(int cpu) -+{ -+ struct call_single_data *csd = &per_cpu(cpuidle_coupled_poke_cb, cpu); -+ -+ if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poked_mask)) -+ __smp_call_function_single(cpu, csd, 0); -+} -+ -+/** -+ * cpuidle_coupled_poke_others - wake up all other cpus that may be waiting -+ * @dev: struct cpuidle_device for this cpu -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Calls cpuidle_coupled_poke on all other online cpus. -+ */ -+static void cpuidle_coupled_poke_others(int this_cpu, -+ struct cpuidle_coupled *coupled) -+{ -+ int cpu; -+ -+ for_each_cpu_mask(cpu, coupled->coupled_cpus) -+ if (cpu != this_cpu && cpu_online(cpu)) -+ cpuidle_coupled_poke(cpu); -+} -+ -+/** -+ * cpuidle_coupled_set_waiting - mark this cpu as in the wait loop -+ * @dev: struct cpuidle_device for this cpu -+ * @coupled: the struct coupled that contains the current cpu -+ * @next_state: the index in drv->states of the requested state for this cpu -+ * -+ * Updates the requested idle state for the specified cpuidle device, -+ * poking all coupled cpus out of idle if necessary to let them see the new -+ * state. -+ */ -+static void cpuidle_coupled_set_waiting(int cpu, -+ struct cpuidle_coupled *coupled, int next_state) -+{ -+ int w; -+ -+ coupled->requested_state[cpu] = next_state; -+ -+ /* -+ * If this is the last cpu to enter the waiting state, poke -+ * all the other cpus out of their waiting state so they can -+ * enter a deeper state. This can race with one of the cpus -+ * exiting the waiting state due to an interrupt and -+ * decrementing waiting_count, see comment below. -+ * -+ * The atomic_inc_return provides a write barrier to order the write -+ * to requested_state with the later write that increments ready_count. -+ */ -+ w = atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK; -+ if (w == coupled->online_count) -+ cpuidle_coupled_poke_others(cpu, coupled); -+} -+ -+/** -+ * cpuidle_coupled_set_not_waiting - mark this cpu as leaving the wait loop -+ * @dev: struct cpuidle_device for this cpu -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Removes the requested idle state for the specified cpuidle device. -+ */ -+static void cpuidle_coupled_set_not_waiting(int cpu, -+ struct cpuidle_coupled *coupled) -+{ -+ /* -+ * Decrementing waiting count can race with incrementing it in -+ * cpuidle_coupled_set_waiting, but that's OK. Worst case, some -+ * cpus will increment ready_count and then spin until they -+ * notice that this cpu has cleared it's requested_state. -+ */ -+ atomic_dec(&coupled->ready_waiting_counts); -+ -+ coupled->requested_state[cpu] = CPUIDLE_COUPLED_NOT_IDLE; -+} -+ -+/** -+ * cpuidle_coupled_set_done - mark this cpu as leaving the ready loop -+ * @cpu: the current cpu -+ * @coupled: the struct coupled that contains the current cpu -+ * -+ * Marks this cpu as no longer in the ready and waiting loops. Decrements -+ * the waiting count first to prevent another cpu looping back in and seeing -+ * this cpu as waiting just before it exits idle. -+ */ -+static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled) -+{ -+ cpuidle_coupled_set_not_waiting(cpu, coupled); -+ atomic_sub(MAX_WAITING_CPUS, &coupled->ready_waiting_counts); -+} -+ -+/** -+ * cpuidle_coupled_clear_pokes - spin until the poke interrupt is processed -+ * @cpu - this cpu -+ * -+ * Turns on interrupts and spins until any outstanding poke interrupts have -+ * been processed and the poke bit has been cleared. -+ * -+ * Other interrupts may also be processed while interrupts are enabled, so -+ * need_resched() must be tested after turning interrupts off again to make sure -+ * the interrupt didn't schedule work that should take the cpu out of idle. -+ * -+ * Returns 0 if need_resched was false, -EINTR if need_resched was true. -+ */ -+static int cpuidle_coupled_clear_pokes(int cpu) -+{ -+ local_irq_enable(); -+ while (cpumask_test_cpu(cpu, &cpuidle_coupled_poked_mask)) -+ cpu_relax(); -+ local_irq_disable(); -+ -+ return need_resched() ? -EINTR : 0; -+} -+ -+/** -+ * cpuidle_enter_state_coupled - attempt to enter a state with coupled cpus -+ * @dev: struct cpuidle_device for the current cpu -+ * @drv: struct cpuidle_driver for the platform -+ * @next_state: index of the requested state in drv->states -+ * -+ * Coordinate with coupled cpus to enter the target state. This is a two -+ * stage process. In the first stage, the cpus are operating independently, -+ * and may call into cpuidle_enter_state_coupled at completely different times. -+ * To save as much power as possible, the first cpus to call this function will -+ * go to an intermediate state (the cpuidle_device's safe state), and wait for -+ * all the other cpus to call this function. Once all coupled cpus are idle, -+ * the second stage will start. Each coupled cpu will spin until all cpus have -+ * guaranteed that they will call the target_state. -+ * -+ * This function must be called with interrupts disabled. It may enable -+ * interrupts while preparing for idle, and it will always return with -+ * interrupts enabled. -+ */ -+int cpuidle_enter_state_coupled(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int next_state) -+{ -+ int entered_state = -1; -+ struct cpuidle_coupled *coupled = dev->coupled; -+ -+ if (!coupled) -+ return -EINVAL; -+ -+ while (coupled->prevent) { -+ if (cpuidle_coupled_clear_pokes(dev->cpu)) { -+ local_irq_enable(); -+ return entered_state; -+ } -+ entered_state = cpuidle_enter_state(dev, drv, -+ dev->safe_state_index); -+ } -+ -+ /* Read barrier ensures online_count is read after prevent is cleared */ -+ smp_rmb(); -+ -+ cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state); -+ -+retry: -+ /* -+ * Wait for all coupled cpus to be idle, using the deepest state -+ * allowed for a single cpu. -+ */ -+ while (!cpuidle_coupled_cpus_waiting(coupled)) { -+ if (cpuidle_coupled_clear_pokes(dev->cpu)) { -+ cpuidle_coupled_set_not_waiting(dev->cpu, coupled); -+ goto out; -+ } -+ -+ if (coupled->prevent) { -+ cpuidle_coupled_set_not_waiting(dev->cpu, coupled); -+ goto out; -+ } -+ -+ entered_state = cpuidle_enter_state(dev, drv, -+ dev->safe_state_index); -+ } -+ -+ if (cpuidle_coupled_clear_pokes(dev->cpu)) { -+ cpuidle_coupled_set_not_waiting(dev->cpu, coupled); -+ goto out; -+ } -+ -+ /* -+ * All coupled cpus are probably idle. There is a small chance that -+ * one of the other cpus just became active. Increment the ready count, -+ * and spin until all coupled cpus have incremented the counter. Once a -+ * cpu has incremented the ready counter, it cannot abort idle and must -+ * spin until either all cpus have incremented the ready counter, or -+ * another cpu leaves idle and decrements the waiting counter. -+ */ -+ -+ cpuidle_coupled_set_ready(coupled); -+ while (!cpuidle_coupled_cpus_ready(coupled)) { -+ /* Check if any other cpus bailed out of idle. */ -+ if (!cpuidle_coupled_cpus_waiting(coupled)) -+ if (!cpuidle_coupled_set_not_ready(coupled)) -+ goto retry; -+ -+ cpu_relax(); -+ } -+ -+ /* all cpus have acked the coupled state */ -+ next_state = cpuidle_coupled_get_state(dev, coupled); -+ -+ entered_state = cpuidle_enter_state(dev, drv, next_state); -+ -+ cpuidle_coupled_set_done(dev->cpu, coupled); -+ -+out: -+ /* -+ * Normal cpuidle states are expected to return with irqs enabled. -+ * That leads to an inefficiency where a cpu receiving an interrupt -+ * that brings it out of idle will process that interrupt before -+ * exiting the idle enter function and decrementing ready_count. All -+ * other cpus will need to spin waiting for the cpu that is processing -+ * the interrupt. If the driver returns with interrupts disabled, -+ * all other cpus will loop back into the safe idle state instead of -+ * spinning, saving power. -+ * -+ * Calling local_irq_enable here allows coupled states to return with -+ * interrupts disabled, but won't cause problems for drivers that -+ * exit with interrupts enabled. -+ */ -+ local_irq_enable(); -+ -+ /* -+ * Wait until all coupled cpus have exited idle. There is no risk that -+ * a cpu exits and re-enters the ready state because this cpu has -+ * already decremented its waiting_count. -+ */ -+ while (!cpuidle_coupled_no_cpus_ready(coupled)) -+ cpu_relax(); -+ -+ return entered_state; -+} -+ -+static void cpuidle_coupled_update_online_cpus(struct cpuidle_coupled *coupled) -+{ -+ cpumask_t cpus; -+ cpumask_and(&cpus, cpu_online_mask, &coupled->coupled_cpus); -+ coupled->online_count = cpumask_weight(&cpus); -+} -+ -+/** -+ * cpuidle_coupled_register_device - register a coupled cpuidle device -+ * @dev: struct cpuidle_device for the current cpu -+ * -+ * Called from cpuidle_register_device to handle coupled idle init. Finds the -+ * cpuidle_coupled struct for this set of coupled cpus, or creates one if none -+ * exists yet. -+ */ -+int cpuidle_coupled_register_device(struct cpuidle_device *dev) -+{ -+ int cpu; -+ struct cpuidle_device *other_dev; -+ struct call_single_data *csd; -+ struct cpuidle_coupled *coupled; -+ -+ if (cpumask_empty(&dev->coupled_cpus)) -+ return 0; -+ -+ for_each_cpu_mask(cpu, dev->coupled_cpus) { -+ other_dev = per_cpu(cpuidle_devices, cpu); -+ if (other_dev && other_dev->coupled) { -+ coupled = other_dev->coupled; -+ goto have_coupled; -+ } -+ } -+ -+ /* No existing coupled info found, create a new one */ -+ coupled = kzalloc(sizeof(struct cpuidle_coupled), GFP_KERNEL); -+ if (!coupled) -+ return -ENOMEM; -+ -+ coupled->coupled_cpus = dev->coupled_cpus; -+ -+have_coupled: -+ dev->coupled = coupled; -+ if (WARN_ON(!cpumask_equal(&dev->coupled_cpus, &coupled->coupled_cpus))) -+ coupled->prevent++; -+ -+ cpuidle_coupled_update_online_cpus(coupled); -+ -+ coupled->refcnt++; -+ -+ csd = &per_cpu(cpuidle_coupled_poke_cb, dev->cpu); -+ csd->func = cpuidle_coupled_poked; -+ csd->info = (void *)(unsigned long)dev->cpu; -+ -+ return 0; -+} -+ -+/** -+ * cpuidle_coupled_unregister_device - unregister a coupled cpuidle device -+ * @dev: struct cpuidle_device for the current cpu -+ * -+ * Called from cpuidle_unregister_device to tear down coupled idle. Removes the -+ * cpu from the coupled idle set, and frees the cpuidle_coupled_info struct if -+ * this was the last cpu in the set. -+ */ -+void cpuidle_coupled_unregister_device(struct cpuidle_device *dev) -+{ -+ struct cpuidle_coupled *coupled = dev->coupled; -+ -+ if (cpumask_empty(&dev->coupled_cpus)) -+ return; -+ -+ if (--coupled->refcnt) -+ kfree(coupled); -+ dev->coupled = NULL; -+} -+ -+/** -+ * cpuidle_coupled_prevent_idle - prevent cpus from entering a coupled state -+ * @coupled: the struct coupled that contains the cpu that is changing state -+ * -+ * Disables coupled cpuidle on a coupled set of cpus. Used to ensure that -+ * cpu_online_mask doesn't change while cpus are coordinating coupled idle. -+ */ -+static void cpuidle_coupled_prevent_idle(struct cpuidle_coupled *coupled) -+{ -+ int cpu = get_cpu(); -+ -+ /* Force all cpus out of the waiting loop. */ -+ coupled->prevent++; -+ cpuidle_coupled_poke_others(cpu, coupled); -+ put_cpu(); -+ while (!cpuidle_coupled_no_cpus_waiting(coupled)) -+ cpu_relax(); -+} -+ -+/** -+ * cpuidle_coupled_allow_idle - allows cpus to enter a coupled state -+ * @coupled: the struct coupled that contains the cpu that is changing state -+ * -+ * Enables coupled cpuidle on a coupled set of cpus. Used to ensure that -+ * cpu_online_mask doesn't change while cpus are coordinating coupled idle. -+ */ -+static void cpuidle_coupled_allow_idle(struct cpuidle_coupled *coupled) -+{ -+ int cpu = get_cpu(); -+ -+ /* -+ * Write barrier ensures readers see the new online_count when they -+ * see prevent == false. -+ */ -+ smp_wmb(); -+ coupled->prevent--; -+ /* Force cpus out of the prevent loop. */ -+ cpuidle_coupled_poke_others(cpu, coupled); -+ put_cpu(); -+} -+ -+/** -+ * cpuidle_coupled_cpu_notify - notifier called during hotplug transitions -+ * @nb: notifier block -+ * @action: hotplug transition -+ * @hcpu: target cpu number -+ * -+ * Called when a cpu is brought on or offline using hotplug. Updates the -+ * coupled cpu set appropriately -+ */ -+static int cpuidle_coupled_cpu_notify(struct notifier_block *nb, -+ unsigned long action, void *hcpu) -+{ -+ int cpu = (unsigned long)hcpu; -+ struct cpuidle_device *dev; -+ -+ switch (action & ~CPU_TASKS_FROZEN) { -+ case CPU_UP_PREPARE: -+ case CPU_DOWN_PREPARE: -+ case CPU_ONLINE: -+ case CPU_DEAD: -+ case CPU_UP_CANCELED: -+ case CPU_DOWN_FAILED: -+ break; -+ default: -+ return NOTIFY_OK; -+ } -+ -+ mutex_lock(&cpuidle_lock); -+ -+ dev = per_cpu(cpuidle_devices, cpu); -+ if (!dev->coupled) -+ goto out; -+ -+ switch (action & ~CPU_TASKS_FROZEN) { -+ case CPU_UP_PREPARE: -+ case CPU_DOWN_PREPARE: -+ cpuidle_coupled_prevent_idle(dev->coupled); -+ break; -+ case CPU_ONLINE: -+ case CPU_DEAD: -+ cpuidle_coupled_update_online_cpus(dev->coupled); -+ /* Fall through */ -+ case CPU_UP_CANCELED: -+ case CPU_DOWN_FAILED: -+ cpuidle_coupled_allow_idle(dev->coupled); -+ break; -+ } -+ -+out: -+ mutex_unlock(&cpuidle_lock); -+ return NOTIFY_OK; -+} -+ -+static struct notifier_block cpuidle_coupled_cpu_notifier = { -+ .notifier_call = cpuidle_coupled_cpu_notify, -+}; -+ -+static int __init cpuidle_coupled_init(void) -+{ -+ return register_cpu_notifier(&cpuidle_coupled_cpu_notifier); -+} -+core_initcall(cpuidle_coupled_init); -diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c -index 2f0083a5..e81cfda2 100644 ---- a/drivers/cpuidle/cpuidle.c -+++ b/drivers/cpuidle/cpuidle.c -@@ -102,6 +102,34 @@ int cpuidle_play_dead(void) - return -ENODEV; - } - -+/** -+ * cpuidle_enter_state - enter the state and update stats -+ * @dev: cpuidle device for this cpu -+ * @drv: cpuidle driver for this cpu -+ * @next_state: index into drv->states of the state to enter -+ */ -+int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, -+ int next_state) -+{ -+ int entered_state; -+ -+ entered_state = cpuidle_enter_ops(dev, drv, next_state); -+ -+ if (entered_state >= 0) { -+ /* Update cpuidle counters */ -+ /* This can be moved to within driver enter routine -+ * but that results in multiple copies of same code. -+ */ -+ dev->states_usage[entered_state].time += -+ (unsigned long long)dev->last_residency; -+ dev->states_usage[entered_state].usage++; -+ } else { -+ dev->last_residency = 0; -+ } -+ -+ return entered_state; -+} -+ - /** - * cpuidle_idle_call - the main idle loop - * -@@ -143,23 +171,15 @@ int cpuidle_idle_call(void) - trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu); - trace_cpu_idle_rcuidle(next_state, dev->cpu); - -- entered_state = cpuidle_enter_ops(dev, drv, next_state); -+ if (cpuidle_state_is_coupled(dev, drv, next_state)) -+ entered_state = cpuidle_enter_state_coupled(dev, drv, -+ next_state); -+ else -+ entered_state = cpuidle_enter_state(dev, drv, next_state); - - trace_power_end_rcuidle(dev->cpu); - trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); - -- if (entered_state >= 0) { -- /* Update cpuidle counters */ -- /* This can be moved to within driver enter routine -- * but that results in multiple copies of same code. -- */ -- dev->states_usage[entered_state].time += -- (unsigned long long)dev->last_residency; -- dev->states_usage[entered_state].usage++; -- } else { -- dev->last_residency = 0; -- } -- - /* give the governor an opportunity to reflect on the outcome */ - if (cpuidle_curr_governor->reflect) - cpuidle_curr_governor->reflect(dev, entered_state); -@@ -387,13 +407,25 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) - - per_cpu(cpuidle_devices, dev->cpu) = dev; - list_add(&dev->device_list, &cpuidle_detected_devices); -- if ((ret = cpuidle_add_sysfs(cpu_dev))) { -- module_put(cpuidle_driver->owner); -- return ret; -- } -+ ret = cpuidle_add_sysfs(cpu_dev); -+ if (ret) -+ goto err_sysfs; -+ -+ ret = cpuidle_coupled_register_device(dev); -+ if (ret) -+ goto err_coupled; - - dev->registered = 1; - return 0; -+ -+err_coupled: -+ cpuidle_remove_sysfs(cpu_dev); -+ wait_for_completion(&dev->kobj_unregister); -+err_sysfs: -+ list_del(&dev->device_list); -+ per_cpu(cpuidle_devices, dev->cpu) = NULL; -+ module_put(cpuidle_driver->owner); -+ return ret; - } - - /** -@@ -443,6 +475,8 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) - wait_for_completion(&dev->kobj_unregister); - per_cpu(cpuidle_devices, dev->cpu) = NULL; - -+ cpuidle_coupled_unregister_device(dev); -+ - cpuidle_resume_and_unlock(); - - module_put(cpuidle_driver->owner); -diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h -index 7db18668..76e7f696 100644 ---- a/drivers/cpuidle/cpuidle.h -+++ b/drivers/cpuidle/cpuidle.h -@@ -14,6 +14,8 @@ extern struct list_head cpuidle_detected_devices; - extern struct mutex cpuidle_lock; - extern spinlock_t cpuidle_driver_lock; - extern int cpuidle_disabled(void); -+extern int cpuidle_enter_state(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int next_state); - - /* idle loop */ - extern void cpuidle_install_idle_handler(void); -@@ -30,4 +32,34 @@ extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device); - extern int cpuidle_add_sysfs(struct device *dev); - extern void cpuidle_remove_sysfs(struct device *dev); - -+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED -+bool cpuidle_state_is_coupled(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int state); -+int cpuidle_enter_state_coupled(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int next_state); -+int cpuidle_coupled_register_device(struct cpuidle_device *dev); -+void cpuidle_coupled_unregister_device(struct cpuidle_device *dev); -+#else -+static inline bool cpuidle_state_is_coupled(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int state) -+{ -+ return false; -+} -+ -+static inline int cpuidle_enter_state_coupled(struct cpuidle_device *dev, -+ struct cpuidle_driver *drv, int next_state) -+{ -+ return -1; -+} -+ -+static inline int cpuidle_coupled_register_device(struct cpuidle_device *dev) -+{ -+ return 0; -+} -+ -+static inline void cpuidle_coupled_unregister_device(struct cpuidle_device *dev) -+{ -+} -+#endif -+ - #endif /* __DRIVER_CPUIDLE_H */ -diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c -index 06335756..746f1e6b 100644 ---- a/drivers/cpuidle/governors/menu.c -+++ b/drivers/cpuidle/governors/menu.c -@@ -173,7 +173,12 @@ static inline int performance_multiplier(void) - - /* for higher loadavg, we are more reluctant */ - -- mult += 2 * get_loadavg(); -+ /* -+ * this doesn't work as intended - it is almost always 0, but can -+ * sometimes, depending on workload, spike very high into the hundreds -+ * even when the average cpu load is under 10%. -+ */ -+ /* mult += 2 * get_loadavg(); */ - - /* for IO wait tasks (per cpu!) we add 5x each */ - mult += 10 * nr_iowait_cpu(smp_processor_id()); -diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c -index 574a06b1..af75ddd4 100644 ---- a/drivers/devfreq/governor_performance.c -+++ b/drivers/devfreq/governor_performance.c -@@ -10,6 +10,7 @@ - */ - - #include <linux/devfreq.h> -+#include "governor.h" - - static int devfreq_performance_func(struct devfreq *df, - unsigned long *freq) -@@ -25,8 +26,14 @@ static int devfreq_performance_func(struct devfreq *df, - return 0; - } - -+static int performance_init(struct devfreq *devfreq) -+{ -+ return update_devfreq(devfreq); -+} -+ - const struct devfreq_governor devfreq_performance = { - .name = "performance", -+ .init = performance_init, - .get_target_freq = devfreq_performance_func, - .no_central_polling = true, - }; -diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c -index d742d4a8..fec0cdbd 100644 ---- a/drivers/devfreq/governor_powersave.c -+++ b/drivers/devfreq/governor_powersave.c -@@ -10,6 +10,7 @@ - */ - - #include <linux/devfreq.h> -+#include "governor.h" - - static int devfreq_powersave_func(struct devfreq *df, - unsigned long *freq) -@@ -22,8 +23,14 @@ static int devfreq_powersave_func(struct devfreq *df, - return 0; - } - -+static int powersave_init(struct devfreq *devfreq) -+{ -+ return update_devfreq(devfreq); -+} -+ - const struct devfreq_governor devfreq_powersave = { - .name = "powersave", -+ .init = powersave_init, - .get_target_freq = devfreq_powersave_func, - .no_central_polling = true, - }; -diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile -index cc927788..ca2d3b34 100644 ---- a/drivers/gpu/Makefile -+++ b/drivers/gpu/Makefile -@@ -1 +1 @@ --obj-y += drm/ vga/ stub/ -+obj-y += drm/ vga/ stub/ ion/ -diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig -new file mode 100644 -index 00000000..cfb11e1e ---- /dev/null -+++ b/drivers/gpu/ion/Kconfig -@@ -0,0 +1,18 @@ -+menuconfig ION -+ tristate "Ion Memory Manager" -+ select GENERIC_ALLOCATOR -+ select DMA_SHARED_BUFFER -+ help -+ Chose this option to enable the ION Memory Manager. -+ -+config ION_TEGRA -+ tristate "Ion for Tegra" -+ depends on ARCH_TEGRA && ION -+ help -+ Choose this option if you wish to use ion on an nVidia Tegra. -+ -+config ION_AK -+ tristate "Ion for AK" -+ depends on ION -+ help -+ Choose this option if you wish to use ion on an AK platform. -diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile -new file mode 100644 -index 00000000..f4a7ac1c ---- /dev/null -+++ b/drivers/gpu/ion/Makefile -@@ -0,0 +1,4 @@ -+obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \ -+ ion_carveout_heap.o ion_chunk_heap.o -+obj-$(CONFIG_ION_TEGRA) += tegra/ -+obj-$(CONFIG_ION_AK) += plat-anyka/ -diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c -new file mode 100644 -index 00000000..cb170959 ---- /dev/null -+++ b/drivers/gpu/ion/ion.c -@@ -0,0 +1,1462 @@ -+/* -+ -+ * drivers/gpu/ion/ion.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/device.h> -+#include <linux/file.h> -+#include <linux/freezer.h> -+#include <linux/fs.h> -+#include <linux/anon_inodes.h> -+#include <linux/ion.h> -+#include <linux/kthread.h> -+#include <linux/list.h> -+#include <linux/memblock.h> -+#include <linux/miscdevice.h> -+#include <linux/export.h> -+#include <linux/mm.h> -+#include <linux/mm_types.h> -+#include <linux/rbtree.h> -+#include <linux/rtmutex.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/seq_file.h> -+#include <linux/uaccess.h> -+#include <linux/debugfs.h> -+#include <linux/dma-buf.h> -+ -+#include "ion_priv.h" -+ -+/** -+ * struct ion_device - the metadata of the ion device node -+ * @dev: the actual misc device -+ * @buffers: an rb tree of all the existing buffers -+ * @buffer_lock: lock protecting the tree of buffers -+ * @lock: rwsem protecting the tree of heaps and clients -+ * @heaps: list of all the heaps in the system -+ * @user_clients: list of all the clients created from userspace -+ */ -+struct ion_device { -+ struct miscdevice dev; -+ struct rb_root buffers; -+ struct mutex buffer_lock; -+ struct rw_semaphore lock; -+ struct plist_head heaps; -+ long (*custom_ioctl) (struct ion_client *client, unsigned int cmd, -+ unsigned long arg); -+ struct rb_root clients; -+ struct dentry *debug_root; -+}; -+ -+/** -+ * struct ion_client - a process/hw block local address space -+ * @node: node in the tree of all clients -+ * @dev: backpointer to ion device -+ * @handles: an rb tree of all the handles in this client -+ * @lock: lock protecting the tree of handles -+ * @name: used for debugging -+ * @task: used for debugging -+ * -+ * A client represents a list of buffers this client may access. -+ * The mutex stored here is used to protect both handles tree -+ * as well as the handles themselves, and should be held while modifying either. -+ */ -+struct ion_client { -+ struct rb_node node; -+ struct ion_device *dev; -+ struct rb_root handles; -+ struct mutex lock; -+ const char *name; -+ struct task_struct *task; -+ pid_t pid; -+ struct dentry *debug_root; -+}; -+ -+/** -+ * ion_handle - a client local reference to a buffer -+ * @ref: reference count -+ * @client: back pointer to the client the buffer resides in -+ * @buffer: pointer to the buffer -+ * @node: node in the client's handle rbtree -+ * @kmap_cnt: count of times this client has mapped to kernel -+ * @dmap_cnt: count of times this client has mapped for dma -+ * -+ * Modifications to node, map_cnt or mapping should be protected by the -+ * lock in the client. Other fields are never changed after initialization. -+ */ -+struct ion_handle { -+ struct kref ref; -+ struct ion_client *client; -+ struct ion_buffer *buffer; -+ struct rb_node node; -+ unsigned int kmap_cnt; -+}; -+ -+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer) -+{ -+ return ((buffer->flags & ION_FLAG_CACHED) && -+ !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC)); -+} -+ -+bool ion_buffer_cached(struct ion_buffer *buffer) -+{ -+ return !!(buffer->flags & ION_FLAG_CACHED); -+} -+ -+/* this function should only be called while dev->lock is held */ -+static void ion_buffer_add(struct ion_device *dev, -+ struct ion_buffer *buffer) -+{ -+ struct rb_node **p = &dev->buffers.rb_node; -+ struct rb_node *parent = NULL; -+ struct ion_buffer *entry; -+ -+ while (*p) { -+ parent = *p; -+ entry = rb_entry(parent, struct ion_buffer, node); -+ -+ if (buffer < entry) { -+ p = &(*p)->rb_left; -+ } else if (buffer > entry) { -+ p = &(*p)->rb_right; -+ } else { -+ pr_err("%s: buffer already found.", __func__); -+ BUG(); -+ } -+ } -+ -+ rb_link_node(&buffer->node, parent, p); -+ rb_insert_color(&buffer->node, &dev->buffers); -+} -+ -+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer); -+ -+static bool ion_heap_drain_freelist(struct ion_heap *heap); -+/* this function should only be called while dev->lock is held */ -+static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, -+ struct ion_device *dev, -+ unsigned long len, -+ unsigned long align, -+ unsigned long flags) -+{ -+ struct ion_buffer *buffer; -+ struct sg_table *table; -+ struct scatterlist *sg; -+ int i, ret; -+ -+ buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL); -+ if (!buffer) -+ return ERR_PTR(-ENOMEM); -+ -+ buffer->heap = heap; -+ buffer->flags = flags; -+ kref_init(&buffer->ref); -+ -+ ret = heap->ops->allocate(heap, buffer, len, align, flags); -+ -+ if (ret) { -+ if (!(heap->flags & ION_HEAP_FLAG_DEFER_FREE)) -+ goto err2; -+ -+ ion_heap_drain_freelist(heap); -+ ret = heap->ops->allocate(heap, buffer, len, align, -+ flags); -+ if (ret) -+ goto err2; -+ } -+ -+ buffer->dev = dev; -+ buffer->size = len; -+ -+ table = heap->ops->map_dma(heap, buffer); -+ if (IS_ERR_OR_NULL(table)) { -+ heap->ops->free(buffer); -+ kfree(buffer); -+ return ERR_PTR(PTR_ERR(table)); -+ } -+ buffer->sg_table = table; -+ if (ion_buffer_fault_user_mappings(buffer)) { -+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, -+ i) { -+ if (sg_dma_len(sg) == PAGE_SIZE) -+ continue; -+ pr_err("%s: cached mappings that will be faulted in " -+ "must have pagewise sg_lists\n", __func__); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ ret = ion_buffer_alloc_dirty(buffer); -+ if (ret) -+ goto err; -+ } -+ -+ buffer->dev = dev; -+ buffer->size = len; -+ INIT_LIST_HEAD(&buffer->vmas); -+ mutex_init(&buffer->lock); -+ /* this will set up dma addresses for the sglist -- it is not -+ technically correct as per the dma api -- a specific -+ device isn't really taking ownership here. However, in practice on -+ our systems the only dma_address space is physical addresses. -+ Additionally, we can't afford the overhead of invalidating every -+ allocation via dma_map_sg. The implicit contract here is that -+ memory comming from the heaps is ready for dma, ie if it has a -+ cached mapping that mapping has been invalidated */ -+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) -+ sg_dma_address(sg) = sg_phys(sg); -+ mutex_lock(&dev->buffer_lock); -+ ion_buffer_add(dev, buffer); -+ mutex_unlock(&dev->buffer_lock); -+ return buffer; -+ -+err: -+ heap->ops->unmap_dma(heap, buffer); -+ heap->ops->free(buffer); -+err2: -+ kfree(buffer); -+ return ERR_PTR(ret); -+} -+ -+static void _ion_buffer_destroy(struct ion_buffer *buffer) -+{ -+ if (WARN_ON(buffer->kmap_cnt > 0)) -+ buffer->heap->ops->unmap_kernel(buffer->heap, buffer); -+ buffer->heap->ops->unmap_dma(buffer->heap, buffer); -+ buffer->heap->ops->free(buffer); -+ if (buffer->flags & ION_FLAG_CACHED) -+ kfree(buffer->dirty); -+ kfree(buffer); -+} -+ -+static void ion_buffer_destroy(struct kref *kref) -+{ -+ struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref); -+ struct ion_heap *heap = buffer->heap; -+ struct ion_device *dev = buffer->dev; -+ -+ mutex_lock(&dev->buffer_lock); -+ rb_erase(&buffer->node, &dev->buffers); -+ mutex_unlock(&dev->buffer_lock); -+ -+ if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) { -+ rt_mutex_lock(&heap->lock); -+ list_add(&buffer->list, &heap->free_list); -+ rt_mutex_unlock(&heap->lock); -+ wake_up(&heap->waitqueue); -+ return; -+ } -+ _ion_buffer_destroy(buffer); -+} -+ -+static void ion_buffer_get(struct ion_buffer *buffer) -+{ -+ kref_get(&buffer->ref); -+} -+ -+static int ion_buffer_put(struct ion_buffer *buffer) -+{ -+ return kref_put(&buffer->ref, ion_buffer_destroy); -+} -+ -+static void ion_buffer_add_to_handle(struct ion_buffer *buffer) -+{ -+ mutex_lock(&buffer->lock); -+ buffer->handle_count++; -+ mutex_unlock(&buffer->lock); -+} -+ -+static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) -+{ -+ /* -+ * when a buffer is removed from a handle, if it is not in -+ * any other handles, copy the taskcomm and the pid of the -+ * process it's being removed from into the buffer. At this -+ * point there will be no way to track what processes this buffer is -+ * being used by, it only exists as a dma_buf file descriptor. -+ * The taskcomm and pid can provide a debug hint as to where this fd -+ * is in the system -+ */ -+ mutex_lock(&buffer->lock); -+ buffer->handle_count--; -+ BUG_ON(buffer->handle_count < 0); -+ if (!buffer->handle_count) { -+ struct task_struct *task; -+ -+ task = current->group_leader; -+ get_task_comm(buffer->task_comm, task); -+ buffer->pid = task_pid_nr(task); -+ } -+ mutex_unlock(&buffer->lock); -+} -+ -+static struct ion_handle *ion_handle_create(struct ion_client *client, -+ struct ion_buffer *buffer) -+{ -+ struct ion_handle *handle; -+ -+ handle = kzalloc(sizeof(struct ion_handle), GFP_KERNEL); -+ if (!handle) -+ return ERR_PTR(-ENOMEM); -+ kref_init(&handle->ref); -+ rb_init_node(&handle->node); -+ handle->client = client; -+ ion_buffer_get(buffer); -+ ion_buffer_add_to_handle(buffer); -+ handle->buffer = buffer; -+ -+ return handle; -+} -+ -+static void ion_handle_kmap_put(struct ion_handle *); -+ -+static void ion_handle_destroy(struct kref *kref) -+{ -+ struct ion_handle *handle = container_of(kref, struct ion_handle, ref); -+ struct ion_client *client = handle->client; -+ struct ion_buffer *buffer = handle->buffer; -+ -+ mutex_lock(&buffer->lock); -+ while (handle->kmap_cnt) -+ ion_handle_kmap_put(handle); -+ mutex_unlock(&buffer->lock); -+ -+ if (!RB_EMPTY_NODE(&handle->node)) -+ rb_erase(&handle->node, &client->handles); -+ -+ ion_buffer_remove_from_handle(buffer); -+ ion_buffer_put(buffer); -+ -+ kfree(handle); -+} -+ -+struct ion_buffer *ion_handle_buffer(struct ion_handle *handle) -+{ -+ return handle->buffer; -+} -+ -+static void ion_handle_get(struct ion_handle *handle) -+{ -+ kref_get(&handle->ref); -+} -+ -+static int ion_handle_put(struct ion_handle *handle) -+{ -+ return kref_put(&handle->ref, ion_handle_destroy); -+} -+ -+static struct ion_handle *ion_handle_lookup(struct ion_client *client, -+ struct ion_buffer *buffer) -+{ -+ struct rb_node *n; -+ -+ for (n = rb_first(&client->handles); n; n = rb_next(n)) { -+ struct ion_handle *handle = rb_entry(n, struct ion_handle, -+ node); -+ if (handle->buffer == buffer) -+ return handle; -+ } -+ return NULL; -+} -+ -+static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle) -+{ -+ struct rb_node *n = client->handles.rb_node; -+ -+ while (n) { -+ struct ion_handle *handle_node = rb_entry(n, struct ion_handle, -+ node); -+ if (handle < handle_node) -+ n = n->rb_left; -+ else if (handle > handle_node) -+ n = n->rb_right; -+ else -+ return true; -+ } -+ return false; -+} -+ -+static void ion_handle_add(struct ion_client *client, struct ion_handle *handle) -+{ -+ struct rb_node **p = &client->handles.rb_node; -+ struct rb_node *parent = NULL; -+ struct ion_handle *entry; -+ -+ while (*p) { -+ parent = *p; -+ entry = rb_entry(parent, struct ion_handle, node); -+ -+ if (handle < entry) -+ p = &(*p)->rb_left; -+ else if (handle > entry) -+ p = &(*p)->rb_right; -+ else -+ WARN(1, "%s: buffer already found.", __func__); -+ } -+ -+ rb_link_node(&handle->node, parent, p); -+ rb_insert_color(&handle->node, &client->handles); -+} -+ -+struct ion_handle *ion_alloc(struct ion_client *client, size_t len, -+ size_t align, unsigned int heap_id_mask, -+ unsigned int flags) -+{ -+ struct ion_handle *handle; -+ struct ion_device *dev = client->dev; -+ struct ion_buffer *buffer = NULL; -+ struct ion_heap *heap; -+ -+ pr_debug("%s: len %d align %d heap_id_mask %u flags %x\n", __func__, -+ len, align, heap_id_mask, flags); -+ /* -+ * traverse the list of heaps available in this system in priority -+ * order. If the heap type is supported by the client, and matches the -+ * request of the caller allocate from it. Repeat until allocate has -+ * succeeded or all heaps have been tried -+ */ -+ if (WARN_ON(!len)) -+ return ERR_PTR(-EINVAL); -+ -+ len = PAGE_ALIGN(len); -+ -+ down_read(&dev->lock); -+ plist_for_each_entry(heap, &dev->heaps, node) { -+ /* if the caller didn't specify this heap id */ -+ if (!((1 << heap->id) & heap_id_mask)) -+ continue; -+ buffer = ion_buffer_create(heap, dev, len, align, flags); -+ if (!IS_ERR_OR_NULL(buffer)) -+ break; -+ } -+ up_read(&dev->lock); -+ -+ if (buffer == NULL) -+ return ERR_PTR(-ENODEV); -+ -+ if (IS_ERR(buffer)) -+ return ERR_PTR(PTR_ERR(buffer)); -+ -+ handle = ion_handle_create(client, buffer); -+ -+ /* -+ * ion_buffer_create will create a buffer with a ref_cnt of 1, -+ * and ion_handle_create will take a second reference, drop one here -+ */ -+ ion_buffer_put(buffer); -+ -+ if (!IS_ERR(handle)) { -+ mutex_lock(&client->lock); -+ ion_handle_add(client, handle); -+ mutex_unlock(&client->lock); -+ } -+ -+ -+ return handle; -+} -+EXPORT_SYMBOL(ion_alloc); -+ -+void ion_free(struct ion_client *client, struct ion_handle *handle) -+{ -+ bool valid_handle; -+ -+ BUG_ON(client != handle->client); -+ -+ mutex_lock(&client->lock); -+ valid_handle = ion_handle_validate(client, handle); -+ -+ if (!valid_handle) { -+ WARN(1, "%s: invalid handle passed to free.\n", __func__); -+ mutex_unlock(&client->lock); -+ return; -+ } -+ ion_handle_put(handle); -+ mutex_unlock(&client->lock); -+} -+EXPORT_SYMBOL(ion_free); -+ -+int ion_phys(struct ion_client *client, struct ion_handle *handle, -+ ion_phys_addr_t *addr, size_t *len) -+{ -+ struct ion_buffer *buffer; -+ int ret; -+ -+ mutex_lock(&client->lock); -+ if (!ion_handle_validate(client, handle)) { -+ mutex_unlock(&client->lock); -+ return -EINVAL; -+ } -+ -+ buffer = handle->buffer; -+ -+ if (!buffer->heap->ops->phys) { -+ pr_err("%s: ion_phys is not implemented by this heap.\n", -+ __func__); -+ mutex_unlock(&client->lock); -+ return -ENODEV; -+ } -+ mutex_unlock(&client->lock); -+ ret = buffer->heap->ops->phys(buffer->heap, buffer, addr, len); -+ return ret; -+} -+EXPORT_SYMBOL(ion_phys); -+ -+static void *ion_buffer_kmap_get(struct ion_buffer *buffer) -+{ -+ void *vaddr; -+ -+ if (buffer->kmap_cnt) { -+ buffer->kmap_cnt++; -+ return buffer->vaddr; -+ } -+ vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer); -+ if (IS_ERR_OR_NULL(vaddr)) -+ return vaddr; -+ buffer->vaddr = vaddr; -+ buffer->kmap_cnt++; -+ return vaddr; -+} -+ -+static void *ion_handle_kmap_get(struct ion_handle *handle) -+{ -+ struct ion_buffer *buffer = handle->buffer; -+ void *vaddr; -+ -+ if (handle->kmap_cnt) { -+ handle->kmap_cnt++; -+ return buffer->vaddr; -+ } -+ vaddr = ion_buffer_kmap_get(buffer); -+ if (IS_ERR_OR_NULL(vaddr)) -+ return vaddr; -+ handle->kmap_cnt++; -+ return vaddr; -+} -+ -+static void ion_buffer_kmap_put(struct ion_buffer *buffer) -+{ -+ buffer->kmap_cnt--; -+ if (!buffer->kmap_cnt) { -+ buffer->heap->ops->unmap_kernel(buffer->heap, buffer); -+ buffer->vaddr = NULL; -+ } -+} -+ -+static void ion_handle_kmap_put(struct ion_handle *handle) -+{ -+ struct ion_buffer *buffer = handle->buffer; -+ -+ handle->kmap_cnt--; -+ if (!handle->kmap_cnt) -+ ion_buffer_kmap_put(buffer); -+} -+ -+void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle) -+{ -+ struct ion_buffer *buffer; -+ void *vaddr; -+ -+ mutex_lock(&client->lock); -+ if (!ion_handle_validate(client, handle)) { -+ pr_err("%s: invalid handle passed to map_kernel.\n", -+ __func__); -+ mutex_unlock(&client->lock); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ buffer = handle->buffer; -+ -+ if (!handle->buffer->heap->ops->map_kernel) { -+ pr_err("%s: map_kernel is not implemented by this heap.\n", -+ __func__); -+ mutex_unlock(&client->lock); -+ return ERR_PTR(-ENODEV); -+ } -+ -+ mutex_lock(&buffer->lock); -+ vaddr = ion_handle_kmap_get(handle); -+ mutex_unlock(&buffer->lock); -+ mutex_unlock(&client->lock); -+ return vaddr; -+} -+EXPORT_SYMBOL(ion_map_kernel); -+ -+void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle) -+{ -+ struct ion_buffer *buffer; -+ -+ mutex_lock(&client->lock); -+ buffer = handle->buffer; -+ mutex_lock(&buffer->lock); -+ ion_handle_kmap_put(handle); -+ mutex_unlock(&buffer->lock); -+ mutex_unlock(&client->lock); -+} -+EXPORT_SYMBOL(ion_unmap_kernel); -+ -+static int ion_debug_client_show(struct seq_file *s, void *unused) -+{ -+ struct ion_client *client = s->private; -+ struct rb_node *n; -+ size_t sizes[ION_NUM_HEAP_IDS] = {0}; -+ const char *names[ION_NUM_HEAP_IDS] = {0}; -+ int i; -+ -+ mutex_lock(&client->lock); -+ for (n = rb_first(&client->handles); n; n = rb_next(n)) { -+ struct ion_handle *handle = rb_entry(n, struct ion_handle, -+ node); -+ unsigned int id = handle->buffer->heap->id; -+ -+ if (!names[id]) -+ names[id] = handle->buffer->heap->name; -+ sizes[id] += handle->buffer->size; -+ } -+ mutex_unlock(&client->lock); -+ -+ seq_printf(s, "%16.16s: %16.16s\n", "heap_name", "size_in_bytes"); -+ for (i = 0; i < ION_NUM_HEAP_IDS; i++) { -+ if (!names[i]) -+ continue; -+ seq_printf(s, "%16.16s: %16u\n", names[i], sizes[i]); -+ } -+ return 0; -+} -+ -+static int ion_debug_client_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, ion_debug_client_show, inode->i_private); -+} -+ -+static const struct file_operations debug_client_fops = { -+ .open = ion_debug_client_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+struct ion_client *ion_client_create(struct ion_device *dev, -+ const char *name) -+{ -+ struct ion_client *client; -+ struct task_struct *task; -+ struct rb_node **p; -+ struct rb_node *parent = NULL; -+ struct ion_client *entry; -+ char debug_name[64]; -+ pid_t pid; -+ -+ get_task_struct(current->group_leader); -+ task_lock(current->group_leader); -+ pid = task_pid_nr(current->group_leader); -+ /* don't bother to store task struct for kernel threads, -+ they can't be killed anyway */ -+ if (current->group_leader->flags & PF_KTHREAD) { -+ put_task_struct(current->group_leader); -+ task = NULL; -+ } else { -+ task = current->group_leader; -+ } -+ task_unlock(current->group_leader); -+ -+ client = kzalloc(sizeof(struct ion_client), GFP_KERNEL); -+ if (!client) { -+ if (task) -+ put_task_struct(current->group_leader); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ client->dev = dev; -+ client->handles = RB_ROOT; -+ mutex_init(&client->lock); -+ client->name = name; -+ client->task = task; -+ client->pid = pid; -+ -+ down_write(&dev->lock); -+ p = &dev->clients.rb_node; -+ while (*p) { -+ parent = *p; -+ entry = rb_entry(parent, struct ion_client, node); -+ -+ if (client < entry) -+ p = &(*p)->rb_left; -+ else if (client > entry) -+ p = &(*p)->rb_right; -+ } -+ rb_link_node(&client->node, parent, p); -+ rb_insert_color(&client->node, &dev->clients); -+ -+ snprintf(debug_name, 64, "%u", client->pid); -+ client->debug_root = debugfs_create_file(debug_name, 0664, -+ dev->debug_root, client, -+ &debug_client_fops); -+ up_write(&dev->lock); -+ -+ return client; -+} -+EXPORT_SYMBOL(ion_client_create); -+ -+void ion_client_destroy(struct ion_client *client) -+{ -+ struct ion_device *dev = client->dev; -+ struct rb_node *n; -+ -+ pr_debug("%s: %d\n", __func__, __LINE__); -+ while ((n = rb_first(&client->handles))) { -+ struct ion_handle *handle = rb_entry(n, struct ion_handle, -+ node); -+ ion_handle_destroy(&handle->ref); -+ } -+ down_write(&dev->lock); -+ if (client->task) -+ put_task_struct(client->task); -+ rb_erase(&client->node, &dev->clients); -+ debugfs_remove_recursive(client->debug_root); -+ up_write(&dev->lock); -+ -+ kfree(client); -+} -+EXPORT_SYMBOL(ion_client_destroy); -+ -+struct sg_table *ion_sg_table(struct ion_client *client, -+ struct ion_handle *handle) -+{ -+ struct ion_buffer *buffer; -+ struct sg_table *table; -+ -+ mutex_lock(&client->lock); -+ if (!ion_handle_validate(client, handle)) { -+ pr_err("%s: invalid handle passed to map_dma.\n", -+ __func__); -+ mutex_unlock(&client->lock); -+ return ERR_PTR(-EINVAL); -+ } -+ buffer = handle->buffer; -+ table = buffer->sg_table; -+ mutex_unlock(&client->lock); -+ return table; -+} -+EXPORT_SYMBOL(ion_sg_table); -+ -+static void ion_buffer_sync_for_device(struct ion_buffer *buffer, -+ struct device *dev, -+ enum dma_data_direction direction); -+ -+static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment, -+ enum dma_data_direction direction) -+{ -+ struct dma_buf *dmabuf = attachment->dmabuf; -+ struct ion_buffer *buffer = dmabuf->priv; -+ -+ ion_buffer_sync_for_device(buffer, attachment->dev, direction); -+ return buffer->sg_table; -+} -+ -+static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, -+ struct sg_table *table, -+ enum dma_data_direction direction) -+{ -+} -+ -+static int ion_buffer_alloc_dirty(struct ion_buffer *buffer) -+{ -+ unsigned long pages = buffer->sg_table->nents; -+ unsigned long length = (pages + BITS_PER_LONG - 1)/BITS_PER_LONG; -+ -+ buffer->dirty = kzalloc(length * sizeof(unsigned long), GFP_KERNEL); -+ if (!buffer->dirty) -+ return -ENOMEM; -+ return 0; -+} -+ -+struct ion_vma_list { -+ struct list_head list; -+ struct vm_area_struct *vma; -+}; -+ -+static void ion_buffer_sync_for_device(struct ion_buffer *buffer, -+ struct device *dev, -+ enum dma_data_direction dir) -+{ -+ struct scatterlist *sg; -+ int i; -+ struct ion_vma_list *vma_list; -+ -+ pr_debug("%s: syncing for device %s\n", __func__, -+ dev ? dev_name(dev) : "null"); -+ -+ if (!ion_buffer_fault_user_mappings(buffer)) -+ return; -+ -+ mutex_lock(&buffer->lock); -+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) { -+ if (!test_bit(i, buffer->dirty)) -+ continue; -+ dma_sync_sg_for_device(dev, sg, 1, dir); -+ clear_bit(i, buffer->dirty); -+ } -+ list_for_each_entry(vma_list, &buffer->vmas, list) { -+ struct vm_area_struct *vma = vma_list->vma; -+ -+ zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, -+ NULL); -+ } -+ mutex_unlock(&buffer->lock); -+} -+ -+int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -+{ -+ struct ion_buffer *buffer = vma->vm_private_data; -+ struct scatterlist *sg; -+ int i; -+ -+ mutex_lock(&buffer->lock); -+ set_bit(vmf->pgoff, buffer->dirty); -+ -+ for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) { -+ if (i != vmf->pgoff) -+ continue; -+ dma_sync_sg_for_cpu(NULL, sg, 1, DMA_BIDIRECTIONAL); -+ vm_insert_page(vma, (unsigned long)vmf->virtual_address, -+ sg_page(sg)); -+ break; -+ } -+ mutex_unlock(&buffer->lock); -+ return VM_FAULT_NOPAGE; -+} -+ -+static void ion_vm_open(struct vm_area_struct *vma) -+{ -+ struct ion_buffer *buffer = vma->vm_private_data; -+ struct ion_vma_list *vma_list; -+ -+ vma_list = kmalloc(sizeof(struct ion_vma_list), GFP_KERNEL); -+ if (!vma_list) -+ return; -+ vma_list->vma = vma; -+ mutex_lock(&buffer->lock); -+ list_add(&vma_list->list, &buffer->vmas); -+ mutex_unlock(&buffer->lock); -+ pr_debug("%s: adding %p\n", __func__, vma); -+} -+ -+static void ion_vm_close(struct vm_area_struct *vma) -+{ -+ struct ion_buffer *buffer = vma->vm_private_data; -+ struct ion_vma_list *vma_list, *tmp; -+ -+ pr_debug("%s\n", __func__); -+ mutex_lock(&buffer->lock); -+ list_for_each_entry_safe(vma_list, tmp, &buffer->vmas, list) { -+ if (vma_list->vma != vma) -+ continue; -+ list_del(&vma_list->list); -+ kfree(vma_list); -+ pr_debug("%s: deleting %p\n", __func__, vma); -+ break; -+ } -+ mutex_unlock(&buffer->lock); -+} -+ -+struct vm_operations_struct ion_vma_ops = { -+ .open = ion_vm_open, -+ .close = ion_vm_close, -+ .fault = ion_vm_fault, -+}; -+ -+static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) -+{ -+ struct ion_buffer *buffer = dmabuf->priv; -+ int ret = 0; -+ -+ if (!buffer->heap->ops->map_user) { -+ pr_err("%s: this heap does not define a method for mapping " -+ "to userspace\n", __func__); -+ return -EINVAL; -+ } -+ -+ if (ion_buffer_fault_user_mappings(buffer)) { -+ vma->vm_private_data = buffer; -+ vma->vm_ops = &ion_vma_ops; -+ ion_vm_open(vma); -+ return 0; -+ } -+ -+ if (!(buffer->flags & ION_FLAG_CACHED)) -+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); -+ -+ mutex_lock(&buffer->lock); -+ /* now map it to userspace */ -+ ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma); -+ mutex_unlock(&buffer->lock); -+ -+ if (ret) -+ pr_err("%s: failure mapping buffer to userspace\n", -+ __func__); -+ -+ return ret; -+} -+ -+static void ion_dma_buf_release(struct dma_buf *dmabuf) -+{ -+ struct ion_buffer *buffer = dmabuf->priv; -+ ion_buffer_put(buffer); -+} -+ -+static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset) -+{ -+ struct ion_buffer *buffer = dmabuf->priv; -+ return buffer->vaddr + offset * PAGE_SIZE; -+} -+ -+static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset, -+ void *ptr) -+{ -+ return; -+} -+ -+static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, -+ size_t len, -+ enum dma_data_direction direction) -+{ -+ struct ion_buffer *buffer = dmabuf->priv; -+ void *vaddr; -+ -+ if (!buffer->heap->ops->map_kernel) { -+ pr_err("%s: map kernel is not implemented by this heap.\n", -+ __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&buffer->lock); -+ vaddr = ion_buffer_kmap_get(buffer); -+ mutex_unlock(&buffer->lock); -+ if (IS_ERR(vaddr)) -+ return PTR_ERR(vaddr); -+ if (!vaddr) -+ return -ENOMEM; -+ return 0; -+} -+ -+static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, -+ size_t len, -+ enum dma_data_direction direction) -+{ -+ struct ion_buffer *buffer = dmabuf->priv; -+ -+ mutex_lock(&buffer->lock); -+ ion_buffer_kmap_put(buffer); -+ mutex_unlock(&buffer->lock); -+} -+ -+struct dma_buf_ops dma_buf_ops = { -+ .map_dma_buf = ion_map_dma_buf, -+ .unmap_dma_buf = ion_unmap_dma_buf, -+ .mmap = ion_mmap, -+ .release = ion_dma_buf_release, -+ .begin_cpu_access = ion_dma_buf_begin_cpu_access, -+ .end_cpu_access = ion_dma_buf_end_cpu_access, -+ .kmap_atomic = ion_dma_buf_kmap, -+ .kunmap_atomic = ion_dma_buf_kunmap, -+ .kmap = ion_dma_buf_kmap, -+ .kunmap = ion_dma_buf_kunmap, -+}; -+ -+struct dma_buf *ion_share_dma_buf(struct ion_client *client, -+ struct ion_handle *handle) -+{ -+ struct ion_buffer *buffer; -+ struct dma_buf *dmabuf; -+ bool valid_handle; -+ -+ mutex_lock(&client->lock); -+ valid_handle = ion_handle_validate(client, handle); -+ mutex_unlock(&client->lock); -+ if (!valid_handle) { -+ WARN(1, "%s: invalid handle passed to share.\n", __func__); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ buffer = handle->buffer; -+ ion_buffer_get(buffer); -+ dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR); -+ if (IS_ERR(dmabuf)) { -+ ion_buffer_put(buffer); -+ return dmabuf; -+ } -+ -+ return dmabuf; -+} -+EXPORT_SYMBOL(ion_share_dma_buf); -+ -+int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle) -+{ -+ struct dma_buf *dmabuf; -+ int fd; -+ -+ dmabuf = ion_share_dma_buf(client, handle); -+ if (IS_ERR(dmabuf)) -+ return PTR_ERR(dmabuf); -+ -+ fd = dma_buf_fd(dmabuf, O_CLOEXEC); -+ if (fd < 0) -+ dma_buf_put(dmabuf); -+ -+ return fd; -+} -+EXPORT_SYMBOL(ion_share_dma_buf_fd); -+ -+struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) -+{ -+ struct dma_buf *dmabuf; -+ struct ion_buffer *buffer; -+ struct ion_handle *handle; -+ -+ dmabuf = dma_buf_get(fd); -+ if (IS_ERR_OR_NULL(dmabuf)) -+ return ERR_PTR(PTR_ERR(dmabuf)); -+ /* if this memory came from ion */ -+ -+ if (dmabuf->ops != &dma_buf_ops) { -+ pr_err("%s: can not import dmabuf from another exporter\n", -+ __func__); -+ dma_buf_put(dmabuf); -+ return ERR_PTR(-EINVAL); -+ } -+ buffer = dmabuf->priv; -+ -+ mutex_lock(&client->lock); -+ /* if a handle exists for this buffer just take a reference to it */ -+ handle = ion_handle_lookup(client, buffer); -+ if (!IS_ERR_OR_NULL(handle)) { -+ ion_handle_get(handle); -+ goto end; -+ } -+ handle = ion_handle_create(client, buffer); -+ if (IS_ERR_OR_NULL(handle)) -+ goto end; -+ ion_handle_add(client, handle); -+end: -+ mutex_unlock(&client->lock); -+ dma_buf_put(dmabuf); -+ return handle; -+} -+EXPORT_SYMBOL(ion_import_dma_buf); -+ -+static int ion_sync_for_device(struct ion_client *client, int fd) -+{ -+ struct dma_buf *dmabuf; -+ struct ion_buffer *buffer; -+ -+ dmabuf = dma_buf_get(fd); -+ if (IS_ERR_OR_NULL(dmabuf)) -+ return PTR_ERR(dmabuf); -+ -+ /* if this memory came from ion */ -+ if (dmabuf->ops != &dma_buf_ops) { -+ pr_err("%s: can not sync dmabuf from another exporter\n", -+ __func__); -+ dma_buf_put(dmabuf); -+ return -EINVAL; -+ } -+ buffer = dmabuf->priv; -+ -+ dma_sync_sg_for_device(NULL, buffer->sg_table->sgl, -+ buffer->sg_table->nents, DMA_BIDIRECTIONAL); -+ dma_buf_put(dmabuf); -+ return 0; -+} -+ -+static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ struct ion_client *client = filp->private_data; -+ -+ switch (cmd) { -+ case ION_IOC_ALLOC: -+ { -+ struct ion_allocation_data data; -+ -+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) -+ return -EFAULT; -+ data.handle = ion_alloc(client, data.len, data.align, -+ data.heap_id_mask, data.flags); -+ -+ if (IS_ERR(data.handle)) -+ return PTR_ERR(data.handle); -+ -+ if (copy_to_user((void __user *)arg, &data, sizeof(data))) { -+ ion_free(client, data.handle); -+ return -EFAULT; -+ } -+ break; -+ } -+ case ION_IOC_FREE: -+ { -+ struct ion_handle_data data; -+ bool valid; -+ -+ if (copy_from_user(&data, (void __user *)arg, -+ sizeof(struct ion_handle_data))) -+ return -EFAULT; -+ mutex_lock(&client->lock); -+ valid = ion_handle_validate(client, data.handle); -+ mutex_unlock(&client->lock); -+ if (!valid) -+ return -EINVAL; -+ ion_free(client, data.handle); -+ break; -+ } -+ case ION_IOC_SHARE: -+ case ION_IOC_MAP: -+ { -+ struct ion_fd_data data; -+ -+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) -+ return -EFAULT; -+ data.fd = ion_share_dma_buf_fd(client, data.handle); -+ if (copy_to_user((void __user *)arg, &data, sizeof(data))) -+ return -EFAULT; -+ if (data.fd < 0) -+ return data.fd; -+ break; -+ } -+ case ION_IOC_IMPORT: -+ { -+ struct ion_fd_data data; -+ int ret = 0; -+ if (copy_from_user(&data, (void __user *)arg, -+ sizeof(struct ion_fd_data))) -+ return -EFAULT; -+ data.handle = ion_import_dma_buf(client, data.fd); -+ if (IS_ERR(data.handle)) { -+ ret = PTR_ERR(data.handle); -+ data.handle = NULL; -+ } -+ if (copy_to_user((void __user *)arg, &data, -+ sizeof(struct ion_fd_data))) -+ return -EFAULT; -+ if (ret < 0) -+ return ret; -+ break; -+ } -+ case ION_IOC_SYNC: -+ { -+ struct ion_fd_data data; -+ if (copy_from_user(&data, (void __user *)arg, -+ sizeof(struct ion_fd_data))) -+ return -EFAULT; -+ ion_sync_for_device(client, data.fd); -+ break; -+ } -+ case ION_IOC_CUSTOM: -+ { -+ struct ion_device *dev = client->dev; -+ struct ion_custom_data data; -+ -+ if (!dev->custom_ioctl) -+ return -ENOTTY; -+ if (copy_from_user(&data, (void __user *)arg, -+ sizeof(struct ion_custom_data))) -+ return -EFAULT; -+ return dev->custom_ioctl(client, data.cmd, data.arg); -+ } -+ default: -+ return -ENOTTY; -+ } -+ return 0; -+} -+ -+static int ion_release(struct inode *inode, struct file *file) -+{ -+ struct ion_client *client = file->private_data; -+ -+ pr_debug("%s: %d\n", __func__, __LINE__); -+ ion_client_destroy(client); -+ return 0; -+} -+ -+static int ion_open(struct inode *inode, struct file *file) -+{ -+ struct miscdevice *miscdev = file->private_data; -+ struct ion_device *dev = container_of(miscdev, struct ion_device, dev); -+ struct ion_client *client; -+ -+ pr_debug("%s: %d\n", __func__, __LINE__); -+ client = ion_client_create(dev, "user"); -+ if (IS_ERR_OR_NULL(client)) -+ return PTR_ERR(client); -+ file->private_data = client; -+ -+ return 0; -+} -+ -+static const struct file_operations ion_fops = { -+ .owner = THIS_MODULE, -+ .open = ion_open, -+ .release = ion_release, -+ .unlocked_ioctl = ion_ioctl, -+}; -+ -+static size_t ion_debug_heap_total(struct ion_client *client, -+ unsigned int id) -+{ -+ size_t size = 0; -+ struct rb_node *n; -+ -+ mutex_lock(&client->lock); -+ for (n = rb_first(&client->handles); n; n = rb_next(n)) { -+ struct ion_handle *handle = rb_entry(n, -+ struct ion_handle, -+ node); -+ if (handle->buffer->heap->id == id) -+ size += handle->buffer->size; -+ } -+ mutex_unlock(&client->lock); -+ return size; -+} -+ -+static int ion_debug_heap_show(struct seq_file *s, void *unused) -+{ -+ struct ion_heap *heap = s->private; -+ struct ion_device *dev = heap->dev; -+ struct rb_node *n; -+ size_t total_size = 0; -+ size_t total_orphaned_size = 0; -+ -+ seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size"); -+ seq_printf(s, "----------------------------------------------------\n"); -+ -+ for (n = rb_first(&dev->clients); n; n = rb_next(n)) { -+ struct ion_client *client = rb_entry(n, struct ion_client, -+ node); -+ size_t size = ion_debug_heap_total(client, heap->id); -+ if (!size) -+ continue; -+ if (client->task) { -+ char task_comm[TASK_COMM_LEN]; -+ -+ get_task_comm(task_comm, client->task); -+ seq_printf(s, "%16.s %16u %16u\n", task_comm, -+ client->pid, size); -+ } else { -+ seq_printf(s, "%16.s %16u %16u\n", client->name, -+ client->pid, size); -+ } -+ } -+ seq_printf(s, "----------------------------------------------------\n"); -+ seq_printf(s, "orphaned allocations (info is from last known client):" -+ "\n"); -+ mutex_lock(&dev->buffer_lock); -+ for (n = rb_first(&dev->buffers); n; n = rb_next(n)) { -+ struct ion_buffer *buffer = rb_entry(n, struct ion_buffer, -+ node); -+ if (buffer->heap->id != heap->id) -+ continue; -+ total_size += buffer->size; -+ if (!buffer->handle_count) { -+ seq_printf(s, "%16.s %16u %16u %d %d\n", buffer->task_comm, -+ buffer->pid, buffer->size, buffer->kmap_cnt, -+ atomic_read(&buffer->ref.refcount)); -+ total_orphaned_size += buffer->size; -+ } -+ } -+ mutex_unlock(&dev->buffer_lock); -+ seq_printf(s, "----------------------------------------------------\n"); -+ seq_printf(s, "%16.s %16u\n", "total orphaned", -+ total_orphaned_size); -+ seq_printf(s, "%16.s %16u\n", "total ", total_size); -+ seq_printf(s, "----------------------------------------------------\n"); -+ -+ if (heap->debug_show) -+ heap->debug_show(heap, s, unused); -+ -+ return 0; -+} -+ -+static int ion_debug_heap_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, ion_debug_heap_show, inode->i_private); -+} -+ -+static const struct file_operations debug_heap_fops = { -+ .open = ion_debug_heap_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static size_t ion_heap_free_list_is_empty(struct ion_heap *heap) -+{ -+ bool is_empty; -+ -+ rt_mutex_lock(&heap->lock); -+ is_empty = list_empty(&heap->free_list); -+ rt_mutex_unlock(&heap->lock); -+ -+ return is_empty; -+} -+ -+static int ion_heap_deferred_free(void *data) -+{ -+ struct ion_heap *heap = data; -+ -+ while (true) { -+ struct ion_buffer *buffer; -+ -+ wait_event_freezable(heap->waitqueue, -+ !ion_heap_free_list_is_empty(heap)); -+ -+ rt_mutex_lock(&heap->lock); -+ if (list_empty(&heap->free_list)) { -+ rt_mutex_unlock(&heap->lock); -+ continue; -+ } -+ buffer = list_first_entry(&heap->free_list, struct ion_buffer, -+ list); -+ list_del(&buffer->list); -+ rt_mutex_unlock(&heap->lock); -+ _ion_buffer_destroy(buffer); -+ } -+ -+ return 0; -+} -+ -+static bool ion_heap_drain_freelist(struct ion_heap *heap) -+{ -+ struct ion_buffer *buffer, *tmp; -+ -+ if (ion_heap_free_list_is_empty(heap)) -+ return false; -+ rt_mutex_lock(&heap->lock); -+ list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) { -+ _ion_buffer_destroy(buffer); -+ list_del(&buffer->list); -+ } -+ BUG_ON(!list_empty(&heap->free_list)); -+ rt_mutex_unlock(&heap->lock); -+ -+ -+ return true; -+} -+ -+void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) -+{ -+ struct sched_param param = { .sched_priority = 0 }; -+ -+ if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma || -+ !heap->ops->unmap_dma) -+ pr_err("%s: can not add heap with invalid ops struct.\n", -+ __func__); -+ -+ if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) { -+ INIT_LIST_HEAD(&heap->free_list); -+ rt_mutex_init(&heap->lock); -+ init_waitqueue_head(&heap->waitqueue); -+ heap->task = kthread_run(ion_heap_deferred_free, heap, -+ "%s", heap->name); -+ sched_setscheduler(heap->task, SCHED_IDLE, ¶m); -+ if (IS_ERR(heap->task)) -+ pr_err("%s: creating thread for deferred free failed\n", -+ __func__); -+ } -+ -+ heap->dev = dev; -+ down_write(&dev->lock); -+ /* use negative heap->id to reverse the priority -- when traversing -+ the list later attempt higher id numbers first */ -+ plist_node_init(&heap->node, -heap->id); -+ plist_add(&heap->node, &dev->heaps); -+ debugfs_create_file(heap->name, 0664, dev->debug_root, heap, -+ &debug_heap_fops); -+ up_write(&dev->lock); -+} -+ -+struct ion_device *ion_device_create(long (*custom_ioctl) -+ (struct ion_client *client, -+ unsigned int cmd, -+ unsigned long arg)) -+{ -+ struct ion_device *idev; -+ int ret; -+ -+ idev = kzalloc(sizeof(struct ion_device), GFP_KERNEL); -+ if (!idev) -+ return ERR_PTR(-ENOMEM); -+ -+ idev->dev.minor = MISC_DYNAMIC_MINOR; -+ idev->dev.name = "ion"; -+ idev->dev.fops = &ion_fops; -+ idev->dev.parent = NULL; -+ ret = misc_register(&idev->dev); -+ if (ret) { -+ pr_err("ion: failed to register misc device.\n"); -+ return ERR_PTR(ret); -+ } -+ -+ idev->debug_root = debugfs_create_dir("ion", NULL); -+ if (IS_ERR_OR_NULL(idev->debug_root)) -+ pr_err("ion: failed to create debug files.\n"); -+ -+ idev->custom_ioctl = custom_ioctl; -+ idev->buffers = RB_ROOT; -+ mutex_init(&idev->buffer_lock); -+ init_rwsem(&idev->lock); -+ plist_head_init(&idev->heaps); -+ idev->clients = RB_ROOT; -+ return idev; -+} -+ -+void ion_device_destroy(struct ion_device *dev) -+{ -+ misc_deregister(&dev->dev); -+ /* XXX need to free the heaps and clients ? */ -+ kfree(dev); -+} -+ -+void __init ion_reserve(struct ion_platform_data *data) -+{ -+ int i; -+ -+ for (i = 0; i < data->nr; i++) { -+ if (data->heaps[i].size == 0) -+ continue; -+ -+ if (data->heaps[i].base == 0) { -+ phys_addr_t paddr; -+ paddr = memblock_alloc_base(data->heaps[i].size, -+ data->heaps[i].align, -+ MEMBLOCK_ALLOC_ANYWHERE); -+ if (!paddr) { -+ pr_err("%s: error allocating memblock for " -+ "heap %d\n", -+ __func__, i); -+ continue; -+ } -+ data->heaps[i].base = paddr; -+ } else { -+ int ret = memblock_reserve(data->heaps[i].base, -+ data->heaps[i].size); -+ if (ret) -+ pr_err("memblock reserve of %x@%lx failed\n", -+ data->heaps[i].size, -+ data->heaps[i].base); -+ } -+ pr_info("%s: %s reserved base %lx size %d\n", __func__, -+ data->heaps[i].name, -+ data->heaps[i].base, -+ data->heaps[i].size); -+ } -+} -diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c -new file mode 100644 -index 00000000..ce8d3119 ---- /dev/null -+++ b/drivers/gpu/ion/ion_carveout_heap.c -@@ -0,0 +1,182 @@ -+/* -+ * drivers/gpu/ion/ion_carveout_heap.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+#include <linux/spinlock.h> -+ -+#include <linux/err.h> -+#include <linux/genalloc.h> -+#include <linux/io.h> -+#include <linux/ion.h> -+#include <linux/mm.h> -+#include <linux/scatterlist.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include "ion_priv.h" -+ -+#include <asm/mach/map.h> -+ -+struct ion_carveout_heap { -+ struct ion_heap heap; -+ struct gen_pool *pool; -+ ion_phys_addr_t base; -+}; -+ -+ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, -+ unsigned long size, -+ unsigned long align) -+{ -+ struct ion_carveout_heap *carveout_heap = -+ container_of(heap, struct ion_carveout_heap, heap); -+ unsigned long offset = gen_pool_alloc(carveout_heap->pool, size); -+ -+ if (!offset) -+ return ION_CARVEOUT_ALLOCATE_FAIL; -+ -+ return offset; -+} -+ -+void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, -+ unsigned long size) -+{ -+ struct ion_carveout_heap *carveout_heap = -+ container_of(heap, struct ion_carveout_heap, heap); -+ -+ if (addr == ION_CARVEOUT_ALLOCATE_FAIL) -+ return; -+ gen_pool_free(carveout_heap->pool, addr, size); -+} -+ -+static int ion_carveout_heap_phys(struct ion_heap *heap, -+ struct ion_buffer *buffer, -+ ion_phys_addr_t *addr, size_t *len) -+{ -+ *addr = buffer->priv_phys; -+ *len = buffer->size; -+ return 0; -+} -+ -+static int ion_carveout_heap_allocate(struct ion_heap *heap, -+ struct ion_buffer *buffer, -+ unsigned long size, unsigned long align, -+ unsigned long flags) -+{ -+ buffer->priv_phys = ion_carveout_allocate(heap, size, align); -+ return buffer->priv_phys == ION_CARVEOUT_ALLOCATE_FAIL ? -ENOMEM : 0; -+} -+ -+static void ion_carveout_heap_free(struct ion_buffer *buffer) -+{ -+ struct ion_heap *heap = buffer->heap; -+ -+ ion_carveout_free(heap, buffer->priv_phys, buffer->size); -+ buffer->priv_phys = ION_CARVEOUT_ALLOCATE_FAIL; -+} -+ -+struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ struct sg_table *table; -+ int ret; -+ -+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); -+ if (!table) -+ return ERR_PTR(-ENOMEM); -+ ret = sg_alloc_table(table, 1, GFP_KERNEL); -+ if (ret) { -+ kfree(table); -+ return ERR_PTR(ret); -+ } -+ sg_set_page(table->sgl, phys_to_page(buffer->priv_phys), buffer->size, -+ 0); -+ return table; -+} -+ -+void ion_carveout_heap_unmap_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ sg_free_table(buffer->sg_table); -+} -+ -+void *ion_carveout_heap_map_kernel(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ int mtype = MT_MEMORY_NONCACHED; -+ -+ if (buffer->flags & ION_FLAG_CACHED) -+ mtype = MT_MEMORY; -+ -+ return __arm_ioremap(buffer->priv_phys, buffer->size, -+ mtype); -+} -+ -+void ion_carveout_heap_unmap_kernel(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ __arm_iounmap(buffer->vaddr); -+ buffer->vaddr = NULL; -+ return; -+} -+ -+int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, -+ struct vm_area_struct *vma) -+{ -+ return remap_pfn_range(vma, vma->vm_start, -+ __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff, -+ vma->vm_end - vma->vm_start, -+ pgprot_noncached(vma->vm_page_prot)); -+} -+ -+static struct ion_heap_ops carveout_heap_ops = { -+ .allocate = ion_carveout_heap_allocate, -+ .free = ion_carveout_heap_free, -+ .phys = ion_carveout_heap_phys, -+ .map_dma = ion_carveout_heap_map_dma, -+ .unmap_dma = ion_carveout_heap_unmap_dma, -+ .map_user = ion_carveout_heap_map_user, -+ .map_kernel = ion_carveout_heap_map_kernel, -+ .unmap_kernel = ion_carveout_heap_unmap_kernel, -+}; -+ -+struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data) -+{ -+ struct ion_carveout_heap *carveout_heap; -+ -+ carveout_heap = kzalloc(sizeof(struct ion_carveout_heap), GFP_KERNEL); -+ if (!carveout_heap) -+ return ERR_PTR(-ENOMEM); -+ -+ carveout_heap->pool = gen_pool_create(12, -1); -+ if (!carveout_heap->pool) { -+ kfree(carveout_heap); -+ return ERR_PTR(-ENOMEM); -+ } -+ carveout_heap->base = heap_data->base; -+ gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size, -+ -1); -+ carveout_heap->heap.ops = &carveout_heap_ops; -+ carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT; -+ -+ return &carveout_heap->heap; -+} -+ -+void ion_carveout_heap_destroy(struct ion_heap *heap) -+{ -+ struct ion_carveout_heap *carveout_heap = -+ container_of(heap, struct ion_carveout_heap, heap); -+ -+ gen_pool_destroy(carveout_heap->pool); -+ kfree(carveout_heap); -+ carveout_heap = NULL; -+} -diff --git a/drivers/gpu/ion/ion_chunk_heap.c b/drivers/gpu/ion/ion_chunk_heap.c -new file mode 100644 -index 00000000..7f482b62 ---- /dev/null -+++ b/drivers/gpu/ion/ion_chunk_heap.c -@@ -0,0 +1,178 @@ -+/* -+ * drivers/gpu/ion/ion_chunk_heap.c -+ * -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+//#include <linux/spinlock.h> -+#include <linux/dma-mapping.h> -+#include <linux/err.h> -+#include <linux/genalloc.h> -+#include <linux/io.h> -+#include <linux/ion.h> -+#include <linux/mm.h> -+#include <linux/scatterlist.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include "ion_priv.h" -+ -+#include <asm/mach/map.h> -+ -+struct ion_chunk_heap { -+ struct ion_heap heap; -+ struct gen_pool *pool; -+ ion_phys_addr_t base; -+ unsigned long chunk_size; -+ unsigned long size; -+ unsigned long allocated; -+}; -+ -+static int ion_chunk_heap_allocate(struct ion_heap *heap, -+ struct ion_buffer *buffer, -+ unsigned long size, unsigned long align, -+ unsigned long flags) -+{ -+ struct ion_chunk_heap *chunk_heap = -+ container_of(heap, struct ion_chunk_heap, heap); -+ struct sg_table *table; -+ struct scatterlist *sg; -+ int ret, i; -+ unsigned long num_chunks; -+ -+ if (ion_buffer_fault_user_mappings(buffer)) -+ return -ENOMEM; -+ -+ num_chunks = ALIGN(size, chunk_heap->chunk_size) / -+ chunk_heap->chunk_size; -+ buffer->size = num_chunks * chunk_heap->chunk_size; -+ -+ if (buffer->size > chunk_heap->size - chunk_heap->allocated) -+ return -ENOMEM; -+ -+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); -+ if (!table) -+ return -ENOMEM; -+ ret = sg_alloc_table(table, num_chunks, GFP_KERNEL); -+ if (ret) { -+ kfree(table); -+ return ret; -+ } -+ -+ sg = table->sgl; -+ for (i = 0; i < num_chunks; i++) { -+ unsigned long paddr = gen_pool_alloc(chunk_heap->pool, -+ chunk_heap->chunk_size); -+ if (!paddr) -+ goto err; -+ sg_set_page(sg, phys_to_page(paddr), chunk_heap->chunk_size, 0); -+ sg = sg_next(sg); -+ } -+ -+ buffer->priv_virt = table; -+ chunk_heap->allocated += buffer->size; -+ return 0; -+err: -+ sg = table->sgl; -+ for (i -= 1; i >= 0; i--) { -+ gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)), -+ sg_dma_len(sg)); -+ sg = sg_next(sg); -+ } -+ sg_free_table(table); -+ kfree(table); -+ return -ENOMEM; -+} -+ -+static void ion_chunk_heap_free(struct ion_buffer *buffer) -+{ -+ struct ion_heap *heap = buffer->heap; -+ struct ion_chunk_heap *chunk_heap = -+ container_of(heap, struct ion_chunk_heap, heap); -+ struct sg_table *table = buffer->priv_virt; -+ struct scatterlist *sg; -+ int i; -+ -+ ion_heap_buffer_zero(buffer); -+ -+ for_each_sg(table->sgl, sg, table->nents, i) { -+ if (ion_buffer_cached(buffer)) -+ __dma_page_cpu_to_dev(sg_page(sg), 0, sg_dma_len(sg), -+ DMA_BIDIRECTIONAL); -+ gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)), -+ sg_dma_len(sg)); -+ } -+ chunk_heap->allocated -= buffer->size; -+ sg_free_table(table); -+ kfree(table); -+} -+ -+struct sg_table *ion_chunk_heap_map_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ return buffer->priv_virt; -+} -+ -+void ion_chunk_heap_unmap_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ return; -+} -+ -+static struct ion_heap_ops chunk_heap_ops = { -+ .allocate = ion_chunk_heap_allocate, -+ .free = ion_chunk_heap_free, -+ .map_dma = ion_chunk_heap_map_dma, -+ .unmap_dma = ion_chunk_heap_unmap_dma, -+ .map_user = ion_heap_map_user, -+ .map_kernel = ion_heap_map_kernel, -+ .unmap_kernel = ion_heap_unmap_kernel, -+}; -+ -+struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data) -+{ -+ struct ion_chunk_heap *chunk_heap; -+ -+ chunk_heap = kzalloc(sizeof(struct ion_chunk_heap), GFP_KERNEL); -+ if (!chunk_heap) -+ return ERR_PTR(-ENOMEM); -+ -+ chunk_heap->chunk_size = (unsigned long)heap_data->priv; -+ chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) + -+ PAGE_SHIFT, -1); -+ if (!chunk_heap->pool) { -+ kfree(chunk_heap); -+ return ERR_PTR(-ENOMEM); -+ } -+ chunk_heap->base = heap_data->base; -+ chunk_heap->size = heap_data->size; -+ chunk_heap->allocated = 0; -+ __dma_page_cpu_to_dev(phys_to_page(heap_data->base), 0, heap_data->size, -+ DMA_BIDIRECTIONAL); -+ gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1); -+ chunk_heap->heap.ops = &chunk_heap_ops; -+ chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK; -+ chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; -+ pr_info("%s: base %lu size %u align %ld\n", __func__, chunk_heap->base, -+ heap_data->size, heap_data->align); -+ -+ return &chunk_heap->heap; -+} -+ -+void ion_chunk_heap_destroy(struct ion_heap *heap) -+{ -+ struct ion_chunk_heap *chunk_heap = -+ container_of(heap, struct ion_chunk_heap, heap); -+ -+ gen_pool_destroy(chunk_heap->pool); -+ kfree(chunk_heap); -+ chunk_heap = NULL; -+} -diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c -new file mode 100644 -index 00000000..225ef946 ---- /dev/null -+++ b/drivers/gpu/ion/ion_heap.c -@@ -0,0 +1,190 @@ -+/* -+ * drivers/gpu/ion/ion_heap.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/err.h> -+#include <linux/ion.h> -+#include <linux/mm.h> -+#include <linux/scatterlist.h> -+#include <linux/vmalloc.h> -+#include "ion_priv.h" -+ -+void *ion_heap_map_kernel(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ struct scatterlist *sg; -+ int i, j; -+ void *vaddr; -+ pgprot_t pgprot; -+ struct sg_table *table = buffer->sg_table; -+ int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; -+ struct page **pages = vmalloc(sizeof(struct page *) * npages); -+ struct page **tmp = pages; -+ -+ if (!pages) -+ return 0; -+ -+ if (buffer->flags & ION_FLAG_CACHED) -+ pgprot = PAGE_KERNEL; -+ else -+ pgprot = pgprot_writecombine(PAGE_KERNEL); -+ -+ for_each_sg(table->sgl, sg, table->nents, i) { -+ int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE; -+ struct page *page = sg_page(sg); -+ BUG_ON(i >= npages); -+ for (j = 0; j < npages_this_entry; j++) { -+ *(tmp++) = page++; -+ } -+ } -+ vaddr = vmap(pages, npages, VM_MAP, pgprot); -+ vfree(pages); -+ -+ return vaddr; -+} -+ -+void ion_heap_unmap_kernel(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ vunmap(buffer->vaddr); -+} -+ -+int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, -+ struct vm_area_struct *vma) -+{ -+ struct sg_table *table = buffer->sg_table; -+ unsigned long addr = vma->vm_start; -+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE; -+ struct scatterlist *sg; -+ int i; -+ -+ for_each_sg(table->sgl, sg, table->nents, i) { -+ struct page *page = sg_page(sg); -+ unsigned long remainder = vma->vm_end - addr; -+ unsigned long len = sg_dma_len(sg); -+ -+ if (offset >= sg_dma_len(sg)) { -+ offset -= sg_dma_len(sg); -+ continue; -+ } else if (offset) { -+ page += offset / PAGE_SIZE; -+ len = sg_dma_len(sg) - offset; -+ offset = 0; -+ } -+ len = min(len, remainder); -+ remap_pfn_range(vma, addr, page_to_pfn(page), len, -+ vma->vm_page_prot); -+ addr += len; -+ if (addr >= vma->vm_end) -+ return 0; -+ } -+ return 0; -+} -+ -+int ion_heap_buffer_zero(struct ion_buffer *buffer) -+{ -+ struct sg_table *table = buffer->sg_table; -+ pgprot_t pgprot; -+ struct scatterlist *sg; -+ struct vm_struct *vm_struct; -+ int i, j, ret = 0; -+ -+ if (buffer->flags & ION_FLAG_CACHED) -+ pgprot = PAGE_KERNEL; -+ else -+ pgprot = pgprot_writecombine(PAGE_KERNEL); -+ -+ vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC); -+ if (!vm_struct) -+ return -ENOMEM; -+ -+ for_each_sg(table->sgl, sg, table->nents, i) { -+ struct page *page = sg_page(sg); -+ unsigned long len = sg_dma_len(sg); -+ -+ for (j = 0; j < len / PAGE_SIZE; j++) { -+ struct page *sub_page = page + j; -+ struct page **pages = &sub_page; -+ ret = map_vm_area(vm_struct, pgprot, &pages); -+ if (ret) -+ goto end; -+ memset(vm_struct->addr, 0, PAGE_SIZE); -+ unmap_kernel_range((unsigned long)vm_struct->addr, -+ PAGE_SIZE); -+ } -+ } -+end: -+ free_vm_area(vm_struct); -+ return ret; -+} -+ -+struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) -+{ -+ struct ion_heap *heap = NULL; -+ -+ switch (heap_data->type) { -+ case ION_HEAP_TYPE_SYSTEM_CONTIG: -+ heap = ion_system_contig_heap_create(heap_data); -+ break; -+ case ION_HEAP_TYPE_SYSTEM: -+ heap = ion_system_heap_create(heap_data); -+ break; -+ case ION_HEAP_TYPE_CARVEOUT: -+ heap = ion_carveout_heap_create(heap_data); -+ break; -+ case ION_HEAP_TYPE_CHUNK: -+ heap = ion_chunk_heap_create(heap_data); -+ break; -+ default: -+ pr_err("%s: Invalid heap type %d\n", __func__, -+ heap_data->type); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ if (IS_ERR_OR_NULL(heap)) { -+ pr_err("%s: error creating heap %s type %d base %lu size %u\n", -+ __func__, heap_data->name, heap_data->type, -+ heap_data->base, heap_data->size); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ heap->name = heap_data->name; -+ heap->id = heap_data->id; -+ return heap; -+} -+ -+void ion_heap_destroy(struct ion_heap *heap) -+{ -+ if (!heap) -+ return; -+ -+ switch (heap->type) { -+ case ION_HEAP_TYPE_SYSTEM_CONTIG: -+ ion_system_contig_heap_destroy(heap); -+ break; -+ case ION_HEAP_TYPE_SYSTEM: -+ ion_system_heap_destroy(heap); -+ break; -+ case ION_HEAP_TYPE_CARVEOUT: -+ ion_carveout_heap_destroy(heap); -+ break; -+ case ION_HEAP_TYPE_CHUNK: -+ ion_chunk_heap_destroy(heap); -+ break; -+ default: -+ pr_err("%s: Invalid heap type %d\n", __func__, -+ heap->type); -+ } -+} -diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/gpu/ion/ion_page_pool.c -new file mode 100644 -index 00000000..cd57b30e ---- /dev/null -+++ b/drivers/gpu/ion/ion_page_pool.c -@@ -0,0 +1,281 @@ -+/* -+ * drivers/gpu/ion/ion_mem_pool.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/debugfs.h> -+#include <linux/dma-mapping.h> -+#include <linux/err.h> -+#include <linux/fs.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/shrinker.h> -+#include "ion_priv.h" -+ -+/* #define DEBUG_PAGE_POOL_SHRINKER */ -+ -+static struct plist_head pools = PLIST_HEAD_INIT(pools); -+static struct shrinker shrinker; -+ -+struct ion_page_pool_item { -+ struct page *page; -+ struct list_head list; -+}; -+ -+static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) -+{ -+ struct page *page = alloc_pages(pool->gfp_mask, pool->order); -+ -+ if (!page) -+ return NULL; -+ /* this is only being used to flush the page for dma, -+ this api is not really suitable for calling from a driver -+ but no better way to flush a page for dma exist at this time */ -+ __dma_page_cpu_to_dev(page, 0, PAGE_SIZE << pool->order, -+ DMA_BIDIRECTIONAL); -+ return page; -+} -+ -+static void ion_page_pool_free_pages(struct ion_page_pool *pool, -+ struct page *page) -+{ -+ __free_pages(page, pool->order); -+} -+ -+static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) -+{ -+ struct ion_page_pool_item *item; -+ -+ item = kmalloc(sizeof(struct ion_page_pool_item), GFP_KERNEL); -+ if (!item) -+ return -ENOMEM; -+ -+ mutex_lock(&pool->mutex); -+ item->page = page; -+ if (PageHighMem(page)) { -+ list_add_tail(&item->list, &pool->high_items); -+ pool->high_count++; -+ } else { -+ list_add_tail(&item->list, &pool->low_items); -+ pool->low_count++; -+ } -+ mutex_unlock(&pool->mutex); -+ return 0; -+} -+ -+static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) -+{ -+ struct ion_page_pool_item *item; -+ struct page *page; -+ -+ if (high) { -+ BUG_ON(!pool->high_count); -+ item = list_first_entry(&pool->high_items, -+ struct ion_page_pool_item, list); -+ pool->high_count--; -+ } else { -+ BUG_ON(!pool->low_count); -+ item = list_first_entry(&pool->low_items, -+ struct ion_page_pool_item, list); -+ pool->low_count--; -+ } -+ -+ list_del(&item->list); -+ page = item->page; -+ kfree(item); -+ return page; -+} -+ -+void *ion_page_pool_alloc(struct ion_page_pool *pool) -+{ -+ struct page *page = NULL; -+ -+ BUG_ON(!pool); -+ -+ mutex_lock(&pool->mutex); -+ if (pool->high_count) -+ page = ion_page_pool_remove(pool, true); -+ else if (pool->low_count) -+ page = ion_page_pool_remove(pool, false); -+ mutex_unlock(&pool->mutex); -+ -+ if (!page) -+ page = ion_page_pool_alloc_pages(pool); -+ -+ return page; -+} -+ -+void ion_page_pool_free(struct ion_page_pool *pool, struct page* page) -+{ -+ int ret; -+ -+ ret = ion_page_pool_add(pool, page); -+ if (ret) -+ ion_page_pool_free_pages(pool, page); -+} -+ -+#ifdef DEBUG_PAGE_POOL_SHRINKER -+static int debug_drop_pools_set(void *data, u64 val) -+{ -+ struct shrink_control sc; -+ int objs; -+ -+ sc.gfp_mask = -1; -+ sc.nr_to_scan = 0; -+ -+ if (!val) -+ return 0; -+ -+ objs = shrinker.shrink(&shrinker, &sc); -+ sc.nr_to_scan = objs; -+ -+ shrinker.shrink(&shrinker, &sc); -+ return 0; -+} -+ -+static int debug_drop_pools_get(void *data, u64 *val) -+{ -+ struct shrink_control sc; -+ int objs; -+ -+ sc.gfp_mask = -1; -+ sc.nr_to_scan = 0; -+ -+ objs = shrinker.shrink(&shrinker, &sc); -+ *val = objs; -+ return 0; -+} -+ -+DEFINE_SIMPLE_ATTRIBUTE(debug_drop_pools_fops, debug_drop_pools_get, -+ debug_drop_pools_set, "%llu\n"); -+ -+static int debug_grow_pools_set(void *data, u64 val) -+{ -+ struct ion_page_pool *pool; -+ struct page *page; -+ -+ plist_for_each_entry(pool, &pools, list) { -+ if (val != pool->list.prio) -+ continue; -+ page = ion_page_pool_alloc_pages(pool); -+ if (page) -+ ion_page_pool_add(pool, page); -+ } -+ -+ return 0; -+} -+ -+DEFINE_SIMPLE_ATTRIBUTE(debug_grow_pools_fops, debug_drop_pools_get, -+ debug_grow_pools_set, "%llu\n"); -+#endif -+ -+static int ion_page_pool_total(bool high) -+{ -+ struct ion_page_pool *pool; -+ int total = 0; -+ -+ plist_for_each_entry(pool, &pools, list) { -+ total += high ? (pool->high_count + pool->low_count) * -+ (1 << pool->order) : -+ pool->low_count * (1 << pool->order); -+ } -+ return total; -+} -+ -+static int ion_page_pool_shrink(struct shrinker *shrinker, -+ struct shrink_control *sc) -+{ -+ struct ion_page_pool *pool; -+ int nr_freed = 0; -+ int i; -+ bool high; -+ int nr_to_scan = sc->nr_to_scan; -+ -+ if (sc->gfp_mask & __GFP_HIGHMEM) -+ high = true; -+ -+ if (nr_to_scan == 0) -+ return ion_page_pool_total(high); -+ -+ plist_for_each_entry(pool, &pools, list) { -+ for (i = 0; i < nr_to_scan; i++) { -+ struct page *page; -+ -+ mutex_lock(&pool->mutex); -+ if (high && pool->high_count) { -+ page = ion_page_pool_remove(pool, true); -+ } else if (pool->low_count) { -+ page = ion_page_pool_remove(pool, false); -+ } else { -+ mutex_unlock(&pool->mutex); -+ break; -+ } -+ mutex_unlock(&pool->mutex); -+ ion_page_pool_free_pages(pool, page); -+ nr_freed += (1 << pool->order); -+ } -+ nr_to_scan -= i; -+ } -+ -+ return ion_page_pool_total(high); -+} -+ -+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) -+{ -+ struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool), -+ GFP_KERNEL); -+ if (!pool) -+ return NULL; -+ pool->high_count = 0; -+ pool->low_count = 0; -+ INIT_LIST_HEAD(&pool->low_items); -+ INIT_LIST_HEAD(&pool->high_items); -+ pool->gfp_mask = gfp_mask; -+ pool->order = order; -+ mutex_init(&pool->mutex); -+ plist_node_init(&pool->list, order); -+ plist_add(&pool->list, &pools); -+ -+ return pool; -+} -+ -+void ion_page_pool_destroy(struct ion_page_pool *pool) -+{ -+ plist_del(&pool->list, &pools); -+ kfree(pool); -+} -+ -+static int __init ion_page_pool_init(void) -+{ -+ shrinker.shrink = ion_page_pool_shrink; -+ shrinker.seeks = DEFAULT_SEEKS; -+ shrinker.batch = 0; -+ register_shrinker(&shrinker); -+#ifdef DEBUG_PAGE_POOL_SHRINKER -+ debugfs_create_file("ion_pools_shrink", 0644, NULL, NULL, -+ &debug_drop_pools_fops); -+ debugfs_create_file("ion_pools_grow", 0644, NULL, NULL, -+ &debug_grow_pools_fops); -+#endif -+ return 0; -+} -+ -+static void __exit ion_page_pool_exit(void) -+{ -+ unregister_shrinker(&shrinker); -+} -+ -+module_init(ion_page_pool_init); -+module_exit(ion_page_pool_exit); -diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h -new file mode 100644 -index 00000000..50568147 ---- /dev/null -+++ b/drivers/gpu/ion/ion_priv.h -@@ -0,0 +1,288 @@ -+/* -+ * drivers/gpu/ion/ion_priv.h -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _ION_PRIV_H -+#define _ION_PRIV_H -+ -+#include <linux/ion.h> -+#include <linux/kref.h> -+#include <linux/mm_types.h> -+#include <linux/mutex.h> -+#include <linux/rbtree.h> -+#include <linux/sched.h> -+#include <linux/shrinker.h> -+#include <linux/types.h> -+ -+struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); -+ -+/** -+ * struct ion_buffer - metadata for a particular buffer -+ * @ref: refernce count -+ * @node: node in the ion_device buffers tree -+ * @dev: back pointer to the ion_device -+ * @heap: back pointer to the heap the buffer came from -+ * @flags: buffer specific flags -+ * @size: size of the buffer -+ * @priv_virt: private data to the buffer representable as -+ * a void * -+ * @priv_phys: private data to the buffer representable as -+ * an ion_phys_addr_t (and someday a phys_addr_t) -+ * @lock: protects the buffers cnt fields -+ * @kmap_cnt: number of times the buffer is mapped to the kernel -+ * @vaddr: the kenrel mapping if kmap_cnt is not zero -+ * @dmap_cnt: number of times the buffer is mapped for dma -+ * @sg_table: the sg table for the buffer if dmap_cnt is not zero -+ * @dirty: bitmask representing which pages of this buffer have -+ * been dirtied by the cpu and need cache maintenance -+ * before dma -+ * @vmas: list of vma's mapping this buffer -+ * @handle_count: count of handles referencing this buffer -+ * @task_comm: taskcomm of last client to reference this buffer in a -+ * handle, used for debugging -+ * @pid: pid of last client to reference this buffer in a -+ * handle, used for debugging -+*/ -+struct ion_buffer { -+ struct kref ref; -+ union { -+ struct rb_node node; -+ struct list_head list; -+ }; -+ struct ion_device *dev; -+ struct ion_heap *heap; -+ unsigned long flags; -+ size_t size; -+ union { -+ void *priv_virt; -+ ion_phys_addr_t priv_phys; -+ }; -+ struct mutex lock; -+ int kmap_cnt; -+ void *vaddr; -+ int dmap_cnt; -+ struct sg_table *sg_table; -+ unsigned long *dirty; -+ struct list_head vmas; -+ /* used to track orphaned buffers */ -+ int handle_count; -+ char task_comm[TASK_COMM_LEN]; -+ pid_t pid; -+}; -+ -+/** -+ * struct ion_heap_ops - ops to operate on a given heap -+ * @allocate: allocate memory -+ * @free: free memory -+ * @phys get physical address of a buffer (only define on -+ * physically contiguous heaps) -+ * @map_dma map the memory for dma to a scatterlist -+ * @unmap_dma unmap the memory for dma -+ * @map_kernel map memory to the kernel -+ * @unmap_kernel unmap memory to the kernel -+ * @map_user map memory to userspace -+ */ -+struct ion_heap_ops { -+ int (*allocate) (struct ion_heap *heap, -+ struct ion_buffer *buffer, unsigned long len, -+ unsigned long align, unsigned long flags); -+ void (*free) (struct ion_buffer *buffer); -+ int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer, -+ ion_phys_addr_t *addr, size_t *len); -+ struct sg_table *(*map_dma) (struct ion_heap *heap, -+ struct ion_buffer *buffer); -+ void (*unmap_dma) (struct ion_heap *heap, struct ion_buffer *buffer); -+ void * (*map_kernel) (struct ion_heap *heap, struct ion_buffer *buffer); -+ void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer); -+ int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer, -+ struct vm_area_struct *vma); -+}; -+ -+/** -+ * heap flags - flags between the heaps and core ion code -+ */ -+#define ION_HEAP_FLAG_DEFER_FREE (1 << 0) -+ -+/** -+ * struct ion_heap - represents a heap in the system -+ * @node: rb node to put the heap on the device's tree of heaps -+ * @dev: back pointer to the ion_device -+ * @type: type of heap -+ * @ops: ops struct as above -+ * @flags: flags -+ * @id: id of heap, also indicates priority of this heap when -+ * allocating. These are specified by platform data and -+ * MUST be unique -+ * @name: used for debugging -+ * @free_list: free list head if deferred free is used -+ * @lock: protects the free list -+ * @waitqueue: queue to wait on from deferred free thread -+ * @task: task struct of deferred free thread -+ * @debug_show: called when heap debug file is read to add any -+ * heap specific debug info to output -+ * -+ * Represents a pool of memory from which buffers can be made. In some -+ * systems the only heap is regular system memory allocated via vmalloc. -+ * On others, some blocks might require large physically contiguous buffers -+ * that are allocated from a specially reserved heap. -+ */ -+struct ion_heap { -+ struct plist_node node; -+ struct ion_device *dev; -+ enum ion_heap_type type; -+ struct ion_heap_ops *ops; -+ unsigned long flags; -+ unsigned int id; -+ const char *name; -+ struct list_head free_list; -+ struct rt_mutex lock; -+ wait_queue_head_t waitqueue; -+ struct task_struct *task; -+ int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); -+}; -+ -+/** -+ * ion_buffer_cached - this ion buffer is cached -+ * @buffer: buffer -+ * -+ * indicates whether this ion buffer is cached -+ */ -+bool ion_buffer_cached(struct ion_buffer *buffer); -+ -+/** -+ * ion_buffer_fault_user_mappings - fault in user mappings of this buffer -+ * @buffer: buffer -+ * -+ * indicates whether userspace mappings of this buffer will be faulted -+ * in, this can affect how buffers are allocated from the heap. -+ */ -+bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer); -+ -+/** -+ * ion_device_create - allocates and returns an ion device -+ * @custom_ioctl: arch specific ioctl function if applicable -+ * -+ * returns a valid device or -PTR_ERR -+ */ -+struct ion_device *ion_device_create(long (*custom_ioctl) -+ (struct ion_client *client, -+ unsigned int cmd, -+ unsigned long arg)); -+ -+/** -+ * ion_device_destroy - free and device and it's resource -+ * @dev: the device -+ */ -+void ion_device_destroy(struct ion_device *dev); -+ -+/** -+ * ion_device_add_heap - adds a heap to the ion device -+ * @dev: the device -+ * @heap: the heap to add -+ */ -+void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap); -+ -+/** -+ * some helpers for common operations on buffers using the sg_table -+ * and vaddr fields -+ */ -+void *ion_heap_map_kernel(struct ion_heap *, struct ion_buffer *); -+void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *); -+int ion_heap_map_user(struct ion_heap *, struct ion_buffer *, -+ struct vm_area_struct *); -+int ion_heap_buffer_zero(struct ion_buffer *buffer); -+ -+ -+/** -+ * functions for creating and destroying the built in ion heaps. -+ * architectures can add their own custom architecture specific -+ * heaps as appropriate. -+ */ -+ -+struct ion_heap *ion_heap_create(struct ion_platform_heap *); -+void ion_heap_destroy(struct ion_heap *); -+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *); -+void ion_system_heap_destroy(struct ion_heap *); -+ -+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *); -+void ion_system_contig_heap_destroy(struct ion_heap *); -+ -+struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *); -+void ion_carveout_heap_destroy(struct ion_heap *); -+ -+struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *); -+void ion_chunk_heap_destroy(struct ion_heap *); -+/** -+ * kernel api to allocate/free from carveout -- used when carveout is -+ * used to back an architecture specific custom heap -+ */ -+ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, unsigned long size, -+ unsigned long align); -+void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, -+ unsigned long size); -+/** -+ * The carveout heap returns physical addresses, since 0 may be a valid -+ * physical address, this is used to indicate allocation failed -+ */ -+#define ION_CARVEOUT_ALLOCATE_FAIL -1 -+ -+/** -+ * functions for creating and destroying a heap pool -- allows you -+ * to keep a pool of pre allocated memory to use from your heap. Keeping -+ * a pool of memory that is ready for dma, ie any cached mapping have been -+ * invalidated from the cache, provides a significant peformance benefit on -+ * many systems */ -+ -+/** -+ * struct ion_page_pool - pagepool struct -+ * @high_count: number of highmem items in the pool -+ * @low_count: number of lowmem items in the pool -+ * @high_items: list of highmem items -+ * @low_items: list of lowmem items -+ * @shrinker: a shrinker for the items -+ * @mutex: lock protecting this struct and especially the count -+ * item list -+ * @alloc: function to be used to allocate pageory when the pool -+ * is empty -+ * @free: function to be used to free pageory back to the system -+ * when the shrinker fires -+ * @gfp_mask: gfp_mask to use from alloc -+ * @order: order of pages in the pool -+ * @list: plist node for list of pools -+ * -+ * Allows you to keep a pool of pre allocated pages to use from your heap. -+ * Keeping a pool of pages that is ready for dma, ie any cached mapping have -+ * been invalidated from the cache, provides a significant peformance benefit -+ * on many systems -+ */ -+struct ion_page_pool { -+ int high_count; -+ int low_count; -+ struct list_head high_items; -+ struct list_head low_items; -+ struct mutex mutex; -+ void *(*alloc)(struct ion_page_pool *pool); -+ void (*free)(struct ion_page_pool *pool, struct page *page); -+ gfp_t gfp_mask; -+ unsigned int order; -+ struct plist_node list; -+}; -+ -+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order); -+void ion_page_pool_destroy(struct ion_page_pool *); -+void *ion_page_pool_alloc(struct ion_page_pool *); -+void ion_page_pool_free(struct ion_page_pool *, struct page *); -+ -+#endif /* _ION_PRIV_H */ -diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c -new file mode 100644 -index 00000000..6369fe8f ---- /dev/null -+++ b/drivers/gpu/ion/ion_system_heap.c -@@ -0,0 +1,417 @@ -+/* -+ * drivers/gpu/ion/ion_system_heap.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <asm/page.h> -+#include <linux/dma-mapping.h> -+#include <linux/err.h> -+#include <linux/highmem.h> -+#include <linux/ion.h> -+#include <linux/mm.h> -+#include <linux/scatterlist.h> -+#include <linux/seq_file.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include "ion_priv.h" -+ -+static unsigned int high_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | -+ __GFP_NOWARN | __GFP_NORETRY | -+ __GFP_NO_KSWAPD) & ~__GFP_WAIT; -+static unsigned int low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | -+ __GFP_NOWARN); -+static const unsigned int orders[] = {8, 4, 0}; -+static const int num_orders = ARRAY_SIZE(orders); -+static int order_to_index(unsigned int order) -+{ -+ int i; -+ for (i = 0; i < num_orders; i++) -+ if (order == orders[i]) -+ return i; -+ BUG(); -+ return -1; -+} -+ -+static unsigned int order_to_size(int order) -+{ -+ return PAGE_SIZE << order; -+} -+ -+struct ion_system_heap { -+ struct ion_heap heap; -+ struct ion_page_pool **pools; -+}; -+ -+struct page_info { -+ struct page *page; -+ unsigned int order; -+ struct list_head list; -+}; -+ -+static struct page *alloc_buffer_page(struct ion_system_heap *heap, -+ struct ion_buffer *buffer, -+ unsigned long order) -+{ -+ bool cached = ion_buffer_cached(buffer); -+ bool split_pages = ion_buffer_fault_user_mappings(buffer); -+ struct ion_page_pool *pool = heap->pools[order_to_index(order)]; -+ struct page *page; -+ -+ if (!cached) { -+ page = ion_page_pool_alloc(pool); -+ } else { -+ gfp_t gfp_flags = low_order_gfp_flags; -+ -+ if (order > 4) -+ gfp_flags = high_order_gfp_flags; -+ page = alloc_pages(gfp_flags, order); -+ if (!page) -+ return 0; -+ __dma_page_cpu_to_dev(page, 0, PAGE_SIZE << order, -+ DMA_BIDIRECTIONAL); -+ } -+ if (!page) -+ return 0; -+ -+ if (split_pages) -+ split_page(page, order); -+ return page; -+} -+ -+static void free_buffer_page(struct ion_system_heap *heap, -+ struct ion_buffer *buffer, struct page *page, -+ unsigned int order) -+{ -+ bool cached = ion_buffer_cached(buffer); -+ bool split_pages = ion_buffer_fault_user_mappings(buffer); -+ int i; -+ -+ if (!cached) { -+ struct ion_page_pool *pool = heap->pools[order_to_index(order)]; -+ ion_page_pool_free(pool, page); -+ } else if (split_pages) { -+ for (i = 0; i < (1 << order); i++) -+ __free_page(page + i); -+ } else { -+ __free_pages(page, order); -+ } -+} -+ -+ -+static struct page_info *alloc_largest_available(struct ion_system_heap *heap, -+ struct ion_buffer *buffer, -+ unsigned long size, -+ unsigned int max_order) -+{ -+ struct page *page; -+ struct page_info *info; -+ int i; -+ -+ for (i = 0; i < num_orders; i++) { -+ if (size < order_to_size(orders[i])) -+ continue; -+ if (max_order < orders[i]) -+ continue; -+ -+ page = alloc_buffer_page(heap, buffer, orders[i]); -+ if (!page) -+ continue; -+ -+ info = kmalloc(sizeof(struct page_info), GFP_KERNEL); -+ info->page = page; -+ info->order = orders[i]; -+ return info; -+ } -+ return NULL; -+} -+ -+static int ion_system_heap_allocate(struct ion_heap *heap, -+ struct ion_buffer *buffer, -+ unsigned long size, unsigned long align, -+ unsigned long flags) -+{ -+ struct ion_system_heap *sys_heap = container_of(heap, -+ struct ion_system_heap, -+ heap); -+ struct sg_table *table; -+ struct scatterlist *sg; -+ int ret; -+ struct list_head pages; -+ struct page_info *info, *tmp_info; -+ int i = 0; -+ long size_remaining = PAGE_ALIGN(size); -+ unsigned int max_order = orders[0]; -+ bool split_pages = ion_buffer_fault_user_mappings(buffer); -+ -+ INIT_LIST_HEAD(&pages); -+ while (size_remaining > 0) { -+ info = alloc_largest_available(sys_heap, buffer, size_remaining, max_order); -+ if (!info) -+ goto err; -+ list_add_tail(&info->list, &pages); -+ size_remaining -= (1 << info->order) * PAGE_SIZE; -+ max_order = info->order; -+ i++; -+ } -+ -+ table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); -+ if (!table) -+ goto err; -+ -+ if (split_pages) -+ ret = sg_alloc_table(table, PAGE_ALIGN(size) / PAGE_SIZE, -+ GFP_KERNEL); -+ else -+ ret = sg_alloc_table(table, i, GFP_KERNEL); -+ -+ if (ret) -+ goto err1; -+ -+ sg = table->sgl; -+ list_for_each_entry_safe(info, tmp_info, &pages, list) { -+ struct page *page = info->page; -+ if (split_pages) { -+ for (i = 0; i < (1 << info->order); i++) { -+ sg_set_page(sg, page + i, PAGE_SIZE, 0); -+ sg = sg_next(sg); -+ } -+ } else { -+ sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE, -+ 0); -+ sg = sg_next(sg); -+ } -+ list_del(&info->list); -+ kfree(info); -+ } -+ -+ buffer->priv_virt = table; -+ return 0; -+err1: -+ kfree(table); -+err: -+ list_for_each_entry(info, &pages, list) { -+ free_buffer_page(sys_heap, buffer, info->page, info->order); -+ kfree(info); -+ } -+ return -ENOMEM; -+} -+ -+void ion_system_heap_free(struct ion_buffer *buffer) -+{ -+ struct ion_heap *heap = buffer->heap; -+ struct ion_system_heap *sys_heap = container_of(heap, -+ struct ion_system_heap, -+ heap); -+ struct sg_table *table = buffer->sg_table; -+ bool cached = ion_buffer_cached(buffer); -+ struct scatterlist *sg; -+ LIST_HEAD(pages); -+ int i; -+ -+ /* uncached pages come from the page pools, zero them before returning -+ for security purposes (other allocations are zerod at alloc time */ -+ if (!cached) -+ ion_heap_buffer_zero(buffer); -+ -+ for_each_sg(table->sgl, sg, table->nents, i) -+ free_buffer_page(sys_heap, buffer, sg_page(sg), -+ get_order(sg_dma_len(sg))); -+ sg_free_table(table); -+ kfree(table); -+} -+ -+struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ return buffer->priv_virt; -+} -+ -+void ion_system_heap_unmap_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ return; -+} -+ -+static struct ion_heap_ops system_heap_ops = { -+ .allocate = ion_system_heap_allocate, -+ .free = ion_system_heap_free, -+ .map_dma = ion_system_heap_map_dma, -+ .unmap_dma = ion_system_heap_unmap_dma, -+ .map_kernel = ion_heap_map_kernel, -+ .unmap_kernel = ion_heap_unmap_kernel, -+ .map_user = ion_heap_map_user, -+}; -+ -+static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, -+ void *unused) -+{ -+ -+ struct ion_system_heap *sys_heap = container_of(heap, -+ struct ion_system_heap, -+ heap); -+ int i; -+ for (i = 0; i < num_orders; i++) { -+ struct ion_page_pool *pool = sys_heap->pools[i]; -+ seq_printf(s, "%d order %u highmem pages in pool = %lu total\n", -+ pool->high_count, pool->order, -+ (1 << pool->order) * PAGE_SIZE * pool->high_count); -+ seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n", -+ pool->low_count, pool->order, -+ (1 << pool->order) * PAGE_SIZE * pool->low_count); -+ } -+ return 0; -+} -+ -+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) -+{ -+ struct ion_system_heap *heap; -+ int i; -+ -+ heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL); -+ if (!heap) -+ return ERR_PTR(-ENOMEM); -+ heap->heap.ops = &system_heap_ops; -+ heap->heap.type = ION_HEAP_TYPE_SYSTEM; -+ heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; -+ heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders, -+ GFP_KERNEL); -+ if (!heap->pools) -+ goto err_alloc_pools; -+ for (i = 0; i < num_orders; i++) { -+ struct ion_page_pool *pool; -+ gfp_t gfp_flags = low_order_gfp_flags; -+ -+ if (orders[i] > 4) -+ gfp_flags = high_order_gfp_flags; -+ pool = ion_page_pool_create(gfp_flags, orders[i]); -+ if (!pool) -+ goto err_create_pool; -+ heap->pools[i] = pool; -+ } -+ heap->heap.debug_show = ion_system_heap_debug_show; -+ return &heap->heap; -+err_create_pool: -+ for (i = 0; i < num_orders; i++) -+ if (heap->pools[i]) -+ ion_page_pool_destroy(heap->pools[i]); -+ kfree(heap->pools); -+err_alloc_pools: -+ kfree(heap); -+ return ERR_PTR(-ENOMEM); -+} -+ -+void ion_system_heap_destroy(struct ion_heap *heap) -+{ -+ struct ion_system_heap *sys_heap = container_of(heap, -+ struct ion_system_heap, -+ heap); -+ int i; -+ -+ for (i = 0; i < num_orders; i++) -+ ion_page_pool_destroy(sys_heap->pools[i]); -+ kfree(sys_heap->pools); -+ kfree(sys_heap); -+} -+ -+static int ion_system_contig_heap_allocate(struct ion_heap *heap, -+ struct ion_buffer *buffer, -+ unsigned long len, -+ unsigned long align, -+ unsigned long flags) -+{ -+ buffer->priv_virt = kzalloc(len, GFP_KERNEL); -+ if (!buffer->priv_virt) -+ return -ENOMEM; -+ return 0; -+} -+ -+void ion_system_contig_heap_free(struct ion_buffer *buffer) -+{ -+ kfree(buffer->priv_virt); -+} -+ -+static int ion_system_contig_heap_phys(struct ion_heap *heap, -+ struct ion_buffer *buffer, -+ ion_phys_addr_t *addr, size_t *len) -+{ -+ *addr = virt_to_phys(buffer->priv_virt); -+ *len = buffer->size; -+ return 0; -+} -+ -+struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ struct sg_table *table; -+ int ret; -+ -+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); -+ if (!table) -+ return ERR_PTR(-ENOMEM); -+ ret = sg_alloc_table(table, 1, GFP_KERNEL); -+ if (ret) { -+ kfree(table); -+ return ERR_PTR(ret); -+ } -+ sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size, -+ 0); -+ return table; -+} -+ -+void ion_system_contig_heap_unmap_dma(struct ion_heap *heap, -+ struct ion_buffer *buffer) -+{ -+ sg_free_table(buffer->sg_table); -+ kfree(buffer->sg_table); -+} -+ -+int ion_system_contig_heap_map_user(struct ion_heap *heap, -+ struct ion_buffer *buffer, -+ struct vm_area_struct *vma) -+{ -+ unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt)); -+ return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, -+ vma->vm_end - vma->vm_start, -+ vma->vm_page_prot); -+ -+} -+ -+static struct ion_heap_ops kmalloc_ops = { -+ .allocate = ion_system_contig_heap_allocate, -+ .free = ion_system_contig_heap_free, -+ .phys = ion_system_contig_heap_phys, -+ .map_dma = ion_system_contig_heap_map_dma, -+ .unmap_dma = ion_system_contig_heap_unmap_dma, -+ .map_kernel = ion_heap_map_kernel, -+ .unmap_kernel = ion_heap_unmap_kernel, -+ .map_user = ion_system_contig_heap_map_user, -+}; -+ -+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused) -+{ -+ struct ion_heap *heap; -+ -+ heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); -+ if (!heap) -+ return ERR_PTR(-ENOMEM); -+ heap->ops = &kmalloc_ops; -+ heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG; -+ return heap; -+} -+ -+void ion_system_contig_heap_destroy(struct ion_heap *heap) -+{ -+ kfree(heap); -+} -+ -diff --git a/drivers/gpu/ion/ion_system_mapper.c b/drivers/gpu/ion/ion_system_mapper.c -new file mode 100644 -index 00000000..692458e0 ---- /dev/null -+++ b/drivers/gpu/ion/ion_system_mapper.c -@@ -0,0 +1,114 @@ -+/* -+ * drivers/gpu/ion/ion_system_mapper.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/err.h> -+#include <linux/ion.h> -+#include <linux/memory.h> -+#include <linux/mm.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include "ion_priv.h" -+/* -+ * This mapper is valid for any heap that allocates memory that already has -+ * a kernel mapping, this includes vmalloc'd memory, kmalloc'd memory, -+ * pages obtained via io_remap, etc. -+ */ -+static void *ion_kernel_mapper_map(struct ion_mapper *mapper, -+ struct ion_buffer *buffer, -+ struct ion_mapping **mapping) -+{ -+ if (!((1 << buffer->heap->type) & mapper->heap_mask)) { -+ pr_err("%s: attempting to map an unsupported heap\n", __func__); -+ return ERR_PTR(-EINVAL); -+ } -+ /* XXX REVISIT ME!!! */ -+ *((unsigned long *)mapping) = (unsigned long)buffer->priv; -+ return buffer->priv; -+} -+ -+static void ion_kernel_mapper_unmap(struct ion_mapper *mapper, -+ struct ion_buffer *buffer, -+ struct ion_mapping *mapping) -+{ -+ if (!((1 << buffer->heap->type) & mapper->heap_mask)) -+ pr_err("%s: attempting to unmap an unsupported heap\n", -+ __func__); -+} -+ -+static void *ion_kernel_mapper_map_kernel(struct ion_mapper *mapper, -+ struct ion_buffer *buffer, -+ struct ion_mapping *mapping) -+{ -+ if (!((1 << buffer->heap->type) & mapper->heap_mask)) { -+ pr_err("%s: attempting to unmap an unsupported heap\n", -+ __func__); -+ return ERR_PTR(-EINVAL); -+ } -+ return buffer->priv; -+} -+ -+static int ion_kernel_mapper_map_user(struct ion_mapper *mapper, -+ struct ion_buffer *buffer, -+ struct vm_area_struct *vma, -+ struct ion_mapping *mapping) -+{ -+ int ret; -+ -+ switch (buffer->heap->type) { -+ case ION_HEAP_KMALLOC: -+ { -+ unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv)); -+ ret = remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, -+ vma->vm_end - vma->vm_start, -+ vma->vm_page_prot); -+ break; -+ } -+ case ION_HEAP_VMALLOC: -+ ret = remap_vmalloc_range(vma, buffer->priv, vma->vm_pgoff); -+ break; -+ default: -+ pr_err("%s: attempting to map unsupported heap to userspace\n", -+ __func__); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static struct ion_mapper_ops ops = { -+ .map = ion_kernel_mapper_map, -+ .map_kernel = ion_kernel_mapper_map_kernel, -+ .map_user = ion_kernel_mapper_map_user, -+ .unmap = ion_kernel_mapper_unmap, -+}; -+ -+struct ion_mapper *ion_system_mapper_create(void) -+{ -+ struct ion_mapper *mapper; -+ mapper = kzalloc(sizeof(struct ion_mapper), GFP_KERNEL); -+ if (!mapper) -+ return ERR_PTR(-ENOMEM); -+ mapper->type = ION_SYSTEM_MAPPER; -+ mapper->ops = &ops; -+ mapper->heap_mask = (1 << ION_HEAP_VMALLOC) | (1 << ION_HEAP_KMALLOC); -+ return mapper; -+} -+ -+void ion_system_mapper_destroy(struct ion_mapper *mapper) -+{ -+ kfree(mapper); -+} -+ -diff --git a/drivers/gpu/ion/plat-anyka/Makefile b/drivers/gpu/ion/plat-anyka/Makefile -new file mode 100755 -index 00000000..5d2c60ec ---- /dev/null -+++ b/drivers/gpu/ion/plat-anyka/Makefile -@@ -0,0 +1 @@ -+obj-y += ak_ion.o -diff --git a/drivers/gpu/ion/plat-anyka/ak_ion.c b/drivers/gpu/ion/plat-anyka/ak_ion.c -new file mode 100755 -index 00000000..9cc80298 ---- /dev/null -+++ b/drivers/gpu/ion/plat-anyka/ak_ion.c -@@ -0,0 +1,96 @@ -+/* -+ * drivers/gpu/plat-anyka/ak_ion.c -+ * -+ * Copyright (C) 2011 Anyka, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/err.h> -+#include <linux/ion.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include "../ion_priv.h" -+ -+struct ion_device *idev; -+struct ion_mapper *anyka_user_mapper; -+int num_heaps; -+struct ion_heap **heaps; -+ -+int ak_ion_probe(struct platform_device *pdev) -+{ -+ struct ion_platform_data *pdata = pdev->dev.platform_data; -+ int err; -+ int i; -+ -+ num_heaps = pdata->nr; -+ -+ heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL); -+ -+ idev = ion_device_create(NULL); -+ if (IS_ERR_OR_NULL(idev)) { -+ kfree(heaps); -+ return PTR_ERR(idev); -+ } -+ -+ /* create the heaps as specified in the board file */ -+ for (i = 0; i < num_heaps; i++) { -+ struct ion_platform_heap *heap_data = &pdata->heaps[i]; -+ -+ heaps[i] = ion_heap_create(heap_data); -+ if (IS_ERR_OR_NULL(heaps[i])) { -+ err = PTR_ERR(heaps[i]); -+ goto err; -+ } -+ ion_device_add_heap(idev, heaps[i]); -+ } -+ platform_set_drvdata(pdev, idev); -+ return 0; -+err: -+ for (i = 0; i < num_heaps; i++) { -+ if (heaps[i]) -+ ion_heap_destroy(heaps[i]); -+ } -+ kfree(heaps); -+ return err; -+} -+ -+int ak_ion_remove(struct platform_device *pdev) -+{ -+ struct ion_device *idev = platform_get_drvdata(pdev); -+ int i; -+ -+ ion_device_destroy(idev); -+ for (i = 0; i < num_heaps; i++) -+ ion_heap_destroy(heaps[i]); -+ kfree(heaps); -+ return 0; -+} -+ -+static struct platform_driver ak_ion_driver = { -+ .probe = ak_ion_probe, -+ .remove = ak_ion_remove, -+ .driver = { .name = "ion-ak" } -+}; -+ -+static int __init ak_ion_init(void) -+{ -+ return platform_driver_register(&ak_ion_driver); -+} -+ -+static void __exit ak_ion_exit(void) -+{ -+ platform_driver_unregister(&ak_ion_driver); -+} -+ -+module_init(ak_ion_init); -+module_exit(ak_ion_exit); -+ -diff --git a/drivers/gpu/ion/tegra/Makefile b/drivers/gpu/ion/tegra/Makefile -new file mode 100644 -index 00000000..11cd003f ---- /dev/null -+++ b/drivers/gpu/ion/tegra/Makefile -@@ -0,0 +1 @@ -+obj-y += tegra_ion.o -diff --git a/drivers/gpu/ion/tegra/tegra_ion.c b/drivers/gpu/ion/tegra/tegra_ion.c -new file mode 100644 -index 00000000..7af6e168 ---- /dev/null -+++ b/drivers/gpu/ion/tegra/tegra_ion.c -@@ -0,0 +1,96 @@ -+/* -+ * drivers/gpu/tegra/tegra_ion.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/err.h> -+#include <linux/ion.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include "../ion_priv.h" -+ -+struct ion_device *idev; -+struct ion_mapper *tegra_user_mapper; -+int num_heaps; -+struct ion_heap **heaps; -+ -+int tegra_ion_probe(struct platform_device *pdev) -+{ -+ struct ion_platform_data *pdata = pdev->dev.platform_data; -+ int err; -+ int i; -+ -+ num_heaps = pdata->nr; -+ -+ heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL); -+ -+ idev = ion_device_create(NULL); -+ if (IS_ERR_OR_NULL(idev)) { -+ kfree(heaps); -+ return PTR_ERR(idev); -+ } -+ -+ /* create the heaps as specified in the board file */ -+ for (i = 0; i < num_heaps; i++) { -+ struct ion_platform_heap *heap_data = &pdata->heaps[i]; -+ -+ heaps[i] = ion_heap_create(heap_data); -+ if (IS_ERR_OR_NULL(heaps[i])) { -+ err = PTR_ERR(heaps[i]); -+ goto err; -+ } -+ ion_device_add_heap(idev, heaps[i]); -+ } -+ platform_set_drvdata(pdev, idev); -+ return 0; -+err: -+ for (i = 0; i < num_heaps; i++) { -+ if (heaps[i]) -+ ion_heap_destroy(heaps[i]); -+ } -+ kfree(heaps); -+ return err; -+} -+ -+int tegra_ion_remove(struct platform_device *pdev) -+{ -+ struct ion_device *idev = platform_get_drvdata(pdev); -+ int i; -+ -+ ion_device_destroy(idev); -+ for (i = 0; i < num_heaps; i++) -+ ion_heap_destroy(heaps[i]); -+ kfree(heaps); -+ return 0; -+} -+ -+static struct platform_driver ion_driver = { -+ .probe = tegra_ion_probe, -+ .remove = tegra_ion_remove, -+ .driver = { .name = "ion-tegra" } -+}; -+ -+static int __init ion_init(void) -+{ -+ return platform_driver_register(&ion_driver); -+} -+ -+static void __exit ion_exit(void) -+{ -+ platform_driver_unregister(&ion_driver); -+} -+ -+module_init(ion_init); -+module_exit(ion_exit); -+ -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index ffddcba3..1283fa3b 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -55,6 +55,27 @@ config HIDRAW - - If unsure, say Y. - -+config UHID -+ tristate "User-space I/O driver support for HID subsystem" -+ depends on HID -+ default n -+ ---help--- -+ Say Y here if you want to provide HID I/O Drivers from user-space. -+ This allows to write I/O drivers in user-space and feed the data from -+ the device into the kernel. The kernel parses the HID reports, loads the -+ corresponding HID Device Driver or provides input devices on top of your -+ user-space device. -+ -+ This driver cannot be used to parse HID-reports in user-space and write -+ special HID-drivers. You should use hidraw for that. -+ Instead, this driver allows to write the transport-layer driver in -+ user-space like USB-HID and Bluetooth-HID do in kernel-space. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called uhid. -+ - source "drivers/hid/usbhid/Kconfig" - - menu "Special HID drivers" -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 22f1d16c..9dca8459 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -8,6 +8,7 @@ ifdef CONFIG_DEBUG_FS - endif - - obj-$(CONFIG_HID) += hid.o -+obj-$(CONFIG_UHID) += uhid.o - - hid-$(CONFIG_HIDRAW) += hidraw.o - -diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c -index 21e473e7..43669731 100644 ---- a/drivers/hid/hid-input.c -+++ b/drivers/hid/hid-input.c -@@ -1204,6 +1204,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) - * UGCI) cram a lot of unrelated inputs into the - * same interface. */ - hidinput->report = report; -+ if (hid->driver->input_register && -+ hid->driver->input_register(hid, hidinput)) -+ goto out_cleanup; - if (input_register_device(hidinput->input)) - goto out_cleanup; - hidinput = NULL; -@@ -1218,6 +1221,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) - goto out_unwind; - } - -+ if (hidinput && hid->driver->input_register && -+ hid->driver->input_register(hid, hidinput)) -+ goto out_cleanup; -+ - if (hidinput && input_register_device(hidinput->input)) - goto out_cleanup; - -diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c -index 7cf3ffe4..8427463b 100644 ---- a/drivers/hid/hid-magicmouse.c -+++ b/drivers/hid/hid-magicmouse.c -@@ -387,8 +387,10 @@ static int magicmouse_raw_event(struct hid_device *hdev, - return 1; - } - --static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) -+static int magicmouse_setup_input(struct hid_device *hdev, struct hid_input *hi) - { -+ struct input_dev *input = hi->input; -+ - __set_bit(EV_KEY, input->evbit); - - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { -@@ -471,6 +473,8 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h - __set_bit(EV_MSC, input->evbit); - __set_bit(MSC_RAW, input->mscbit); - } -+ -+ return 0; - } - - static int magicmouse_input_mapping(struct hid_device *hdev, -@@ -523,12 +527,6 @@ static int magicmouse_probe(struct hid_device *hdev, - goto err_free; - } - -- /* We do this after hid-input is done parsing reports so that -- * hid-input uses the most natural button and axis IDs. -- */ -- if (msc->input) -- magicmouse_setup_input(msc->input, hdev); -- - if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) - report = hid_register_report(hdev, HID_INPUT_REPORT, - MOUSE_REPORT_ID); -@@ -593,6 +591,7 @@ static struct hid_driver magicmouse_driver = { - .remove = magicmouse_remove, - .raw_event = magicmouse_raw_event, - .input_mapping = magicmouse_input_mapping, -+ .input_register = magicmouse_setup_input, - }; - - static int __init magicmouse_init(void) -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index e754dff1..7a180b99 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -330,6 +330,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, - if (field->physical == HID_DG_STYLUS) - return -1; - -+ /* Only map fields from TouchScreen or TouchPad collections. -+ * We need to ignore fields that belong to other collections -+ * such as Mouse that might have the same GenericDesktop usages. */ -+ if (field->application == HID_DG_TOUCHSCREEN) -+ set_bit(INPUT_PROP_DIRECT, hi->input->propbit); -+ else if (field->application == HID_DG_TOUCHPAD) -+ set_bit(INPUT_PROP_POINTER, hi->input->propbit); -+ else -+ return 0; -+ - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_GENDESK: -diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c -new file mode 100644 -index 00000000..714cd8cc ---- /dev/null -+++ b/drivers/hid/uhid.c -@@ -0,0 +1,572 @@ -+/* -+ * User-space I/O driver support for HID subsystem -+ * Copyright (c) 2012 David Herrmann -+ */ -+ -+/* -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the Free -+ * Software Foundation; either version 2 of the License, or (at your option) -+ * any later version. -+ */ -+ -+#include <linux/atomic.h> -+#include <linux/device.h> -+#include <linux/fs.h> -+#include <linux/hid.h> -+#include <linux/input.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/poll.h> -+#include <linux/sched.h> -+#include <linux/spinlock.h> -+#include <linux/uhid.h> -+#include <linux/wait.h> -+ -+#define UHID_NAME "uhid" -+#define UHID_BUFSIZE 32 -+ -+struct uhid_device { -+ struct mutex devlock; -+ bool running; -+ -+ __u8 *rd_data; -+ uint rd_size; -+ -+ struct hid_device *hid; -+ struct uhid_event input_buf; -+ -+ wait_queue_head_t waitq; -+ spinlock_t qlock; -+ __u8 head; -+ __u8 tail; -+ struct uhid_event *outq[UHID_BUFSIZE]; -+ -+ struct mutex report_lock; -+ wait_queue_head_t report_wait; -+ atomic_t report_done; -+ atomic_t report_id; -+ struct uhid_event report_buf; -+}; -+ -+static struct miscdevice uhid_misc; -+ -+static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev) -+{ -+ __u8 newhead; -+ -+ newhead = (uhid->head + 1) % UHID_BUFSIZE; -+ -+ if (newhead != uhid->tail) { -+ uhid->outq[uhid->head] = ev; -+ uhid->head = newhead; -+ wake_up_interruptible(&uhid->waitq); -+ } else { -+ hid_warn(uhid->hid, "Output queue is full\n"); -+ kfree(ev); -+ } -+} -+ -+static int uhid_queue_event(struct uhid_device *uhid, __u32 event) -+{ -+ unsigned long flags; -+ struct uhid_event *ev; -+ -+ ev = kzalloc(sizeof(*ev), GFP_KERNEL); -+ if (!ev) -+ return -ENOMEM; -+ -+ ev->type = event; -+ -+ spin_lock_irqsave(&uhid->qlock, flags); -+ uhid_queue(uhid, ev); -+ spin_unlock_irqrestore(&uhid->qlock, flags); -+ -+ return 0; -+} -+ -+static int uhid_hid_start(struct hid_device *hid) -+{ -+ struct uhid_device *uhid = hid->driver_data; -+ -+ return uhid_queue_event(uhid, UHID_START); -+} -+ -+static void uhid_hid_stop(struct hid_device *hid) -+{ -+ struct uhid_device *uhid = hid->driver_data; -+ -+ hid->claimed = 0; -+ uhid_queue_event(uhid, UHID_STOP); -+} -+ -+static int uhid_hid_open(struct hid_device *hid) -+{ -+ struct uhid_device *uhid = hid->driver_data; -+ -+ return uhid_queue_event(uhid, UHID_OPEN); -+} -+ -+static void uhid_hid_close(struct hid_device *hid) -+{ -+ struct uhid_device *uhid = hid->driver_data; -+ -+ uhid_queue_event(uhid, UHID_CLOSE); -+} -+ -+static int uhid_hid_input(struct input_dev *input, unsigned int type, -+ unsigned int code, int value) -+{ -+ struct hid_device *hid = input_get_drvdata(input); -+ struct uhid_device *uhid = hid->driver_data; -+ unsigned long flags; -+ struct uhid_event *ev; -+ -+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC); -+ if (!ev) -+ return -ENOMEM; -+ -+ ev->type = UHID_OUTPUT_EV; -+ ev->u.output_ev.type = type; -+ ev->u.output_ev.code = code; -+ ev->u.output_ev.value = value; -+ -+ spin_lock_irqsave(&uhid->qlock, flags); -+ uhid_queue(uhid, ev); -+ spin_unlock_irqrestore(&uhid->qlock, flags); -+ -+ return 0; -+} -+ -+static int uhid_hid_parse(struct hid_device *hid) -+{ -+ struct uhid_device *uhid = hid->driver_data; -+ -+ return hid_parse_report(hid, uhid->rd_data, uhid->rd_size); -+} -+ -+static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum, -+ __u8 *buf, size_t count, unsigned char rtype) -+{ -+ struct uhid_device *uhid = hid->driver_data; -+ __u8 report_type; -+ struct uhid_event *ev; -+ unsigned long flags; -+ int ret; -+ size_t uninitialized_var(len); -+ struct uhid_feature_answer_req *req; -+ -+ if (!uhid->running) -+ return -EIO; -+ -+ switch (rtype) { -+ case HID_FEATURE_REPORT: -+ report_type = UHID_FEATURE_REPORT; -+ break; -+ case HID_OUTPUT_REPORT: -+ report_type = UHID_OUTPUT_REPORT; -+ break; -+ case HID_INPUT_REPORT: -+ report_type = UHID_INPUT_REPORT; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret = mutex_lock_interruptible(&uhid->report_lock); -+ if (ret) -+ return ret; -+ -+ ev = kzalloc(sizeof(*ev), GFP_KERNEL); -+ if (!ev) { -+ ret = -ENOMEM; -+ goto unlock; -+ } -+ -+ spin_lock_irqsave(&uhid->qlock, flags); -+ ev->type = UHID_FEATURE; -+ ev->u.feature.id = atomic_inc_return(&uhid->report_id); -+ ev->u.feature.rnum = rnum; -+ ev->u.feature.rtype = report_type; -+ -+ atomic_set(&uhid->report_done, 0); -+ uhid_queue(uhid, ev); -+ spin_unlock_irqrestore(&uhid->qlock, flags); -+ -+ ret = wait_event_interruptible_timeout(uhid->report_wait, -+ atomic_read(&uhid->report_done), 5 * HZ); -+ -+ /* -+ * Make sure "uhid->running" is cleared on shutdown before -+ * "uhid->report_done" is set. -+ */ -+ smp_rmb(); -+ if (!ret || !uhid->running) { -+ ret = -EIO; -+ } else if (ret < 0) { -+ ret = -ERESTARTSYS; -+ } else { -+ spin_lock_irqsave(&uhid->qlock, flags); -+ req = &uhid->report_buf.u.feature_answer; -+ -+ if (req->err) { -+ ret = -EIO; -+ } else { -+ ret = 0; -+ len = min(count, -+ min_t(size_t, req->size, UHID_DATA_MAX)); -+ memcpy(buf, req->data, len); -+ } -+ -+ spin_unlock_irqrestore(&uhid->qlock, flags); -+ } -+ -+ atomic_set(&uhid->report_done, 1); -+ -+unlock: -+ mutex_unlock(&uhid->report_lock); -+ return ret ? ret : len; -+} -+ -+static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count, -+ unsigned char report_type) -+{ -+ struct uhid_device *uhid = hid->driver_data; -+ __u8 rtype; -+ unsigned long flags; -+ struct uhid_event *ev; -+ -+ switch (report_type) { -+ case HID_FEATURE_REPORT: -+ rtype = UHID_FEATURE_REPORT; -+ break; -+ case HID_OUTPUT_REPORT: -+ rtype = UHID_OUTPUT_REPORT; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (count < 1 || count > UHID_DATA_MAX) -+ return -EINVAL; -+ -+ ev = kzalloc(sizeof(*ev), GFP_KERNEL); -+ if (!ev) -+ return -ENOMEM; -+ -+ ev->type = UHID_OUTPUT; -+ ev->u.output.size = count; -+ ev->u.output.rtype = rtype; -+ memcpy(ev->u.output.data, buf, count); -+ -+ spin_lock_irqsave(&uhid->qlock, flags); -+ uhid_queue(uhid, ev); -+ spin_unlock_irqrestore(&uhid->qlock, flags); -+ -+ return count; -+} -+ -+static struct hid_ll_driver uhid_hid_driver = { -+ .start = uhid_hid_start, -+ .stop = uhid_hid_stop, -+ .open = uhid_hid_open, -+ .close = uhid_hid_close, -+ .hidinput_input_event = uhid_hid_input, -+ .parse = uhid_hid_parse, -+}; -+ -+static int uhid_dev_create(struct uhid_device *uhid, -+ const struct uhid_event *ev) -+{ -+ struct hid_device *hid; -+ int ret; -+ -+ if (uhid->running) -+ return -EALREADY; -+ -+ uhid->rd_size = ev->u.create.rd_size; -+ if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE) -+ return -EINVAL; -+ -+ uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL); -+ if (!uhid->rd_data) -+ return -ENOMEM; -+ -+ if (copy_from_user(uhid->rd_data, ev->u.create.rd_data, -+ uhid->rd_size)) { -+ ret = -EFAULT; -+ goto err_free; -+ } -+ -+ hid = hid_allocate_device(); -+ if (IS_ERR(hid)) { -+ ret = PTR_ERR(hid); -+ goto err_free; -+ } -+ -+ strncpy(hid->name, ev->u.create.name, 127); -+ hid->name[127] = 0; -+ strncpy(hid->phys, ev->u.create.phys, 63); -+ hid->phys[63] = 0; -+ strncpy(hid->uniq, ev->u.create.uniq, 63); -+ hid->uniq[63] = 0; -+ -+ hid->ll_driver = &uhid_hid_driver; -+ hid->hid_get_raw_report = uhid_hid_get_raw; -+ hid->hid_output_raw_report = uhid_hid_output_raw; -+ hid->bus = ev->u.create.bus; -+ hid->vendor = ev->u.create.vendor; -+ hid->product = ev->u.create.product; -+ hid->version = ev->u.create.version; -+ hid->country = ev->u.create.country; -+ hid->driver_data = uhid; -+ hid->dev.parent = uhid_misc.this_device; -+ -+ uhid->hid = hid; -+ uhid->running = true; -+ -+ ret = hid_add_device(hid); -+ if (ret) { -+ hid_err(hid, "Cannot register HID device\n"); -+ goto err_hid; -+ } -+ -+ return 0; -+ -+err_hid: -+ hid_destroy_device(hid); -+ uhid->hid = NULL; -+ uhid->running = false; -+err_free: -+ kfree(uhid->rd_data); -+ return ret; -+} -+ -+static int uhid_dev_destroy(struct uhid_device *uhid) -+{ -+ if (!uhid->running) -+ return -EINVAL; -+ -+ /* clear "running" before setting "report_done" */ -+ uhid->running = false; -+ smp_wmb(); -+ atomic_set(&uhid->report_done, 1); -+ wake_up_interruptible(&uhid->report_wait); -+ -+ hid_destroy_device(uhid->hid); -+ kfree(uhid->rd_data); -+ -+ return 0; -+} -+ -+static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) -+{ -+ if (!uhid->running) -+ return -EINVAL; -+ -+ hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, -+ min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0); -+ -+ return 0; -+} -+ -+static int uhid_dev_feature_answer(struct uhid_device *uhid, -+ struct uhid_event *ev) -+{ -+ unsigned long flags; -+ -+ if (!uhid->running) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&uhid->qlock, flags); -+ -+ /* id for old report; drop it silently */ -+ if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id) -+ goto unlock; -+ if (atomic_read(&uhid->report_done)) -+ goto unlock; -+ -+ memcpy(&uhid->report_buf, ev, sizeof(*ev)); -+ atomic_set(&uhid->report_done, 1); -+ wake_up_interruptible(&uhid->report_wait); -+ -+unlock: -+ spin_unlock_irqrestore(&uhid->qlock, flags); -+ return 0; -+} -+ -+static int uhid_char_open(struct inode *inode, struct file *file) -+{ -+ struct uhid_device *uhid; -+ -+ uhid = kzalloc(sizeof(*uhid), GFP_KERNEL); -+ if (!uhid) -+ return -ENOMEM; -+ -+ mutex_init(&uhid->devlock); -+ mutex_init(&uhid->report_lock); -+ spin_lock_init(&uhid->qlock); -+ init_waitqueue_head(&uhid->waitq); -+ init_waitqueue_head(&uhid->report_wait); -+ uhid->running = false; -+ atomic_set(&uhid->report_done, 1); -+ -+ file->private_data = uhid; -+ nonseekable_open(inode, file); -+ -+ return 0; -+} -+ -+static int uhid_char_release(struct inode *inode, struct file *file) -+{ -+ struct uhid_device *uhid = file->private_data; -+ unsigned int i; -+ -+ uhid_dev_destroy(uhid); -+ -+ for (i = 0; i < UHID_BUFSIZE; ++i) -+ kfree(uhid->outq[i]); -+ -+ kfree(uhid); -+ -+ return 0; -+} -+ -+static ssize_t uhid_char_read(struct file *file, char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ struct uhid_device *uhid = file->private_data; -+ int ret; -+ unsigned long flags; -+ size_t len; -+ -+ /* they need at least the "type" member of uhid_event */ -+ if (count < sizeof(__u32)) -+ return -EINVAL; -+ -+try_again: -+ if (file->f_flags & O_NONBLOCK) { -+ if (uhid->head == uhid->tail) -+ return -EAGAIN; -+ } else { -+ ret = wait_event_interruptible(uhid->waitq, -+ uhid->head != uhid->tail); -+ if (ret) -+ return ret; -+ } -+ -+ ret = mutex_lock_interruptible(&uhid->devlock); -+ if (ret) -+ return ret; -+ -+ if (uhid->head == uhid->tail) { -+ mutex_unlock(&uhid->devlock); -+ goto try_again; -+ } else { -+ len = min(count, sizeof(**uhid->outq)); -+ if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) { -+ ret = -EFAULT; -+ } else { -+ kfree(uhid->outq[uhid->tail]); -+ uhid->outq[uhid->tail] = NULL; -+ -+ spin_lock_irqsave(&uhid->qlock, flags); -+ uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE; -+ spin_unlock_irqrestore(&uhid->qlock, flags); -+ } -+ } -+ -+ mutex_unlock(&uhid->devlock); -+ return ret ? ret : len; -+} -+ -+static ssize_t uhid_char_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ struct uhid_device *uhid = file->private_data; -+ int ret; -+ size_t len; -+ -+ /* we need at least the "type" member of uhid_event */ -+ if (count < sizeof(__u32)) -+ return -EINVAL; -+ -+ ret = mutex_lock_interruptible(&uhid->devlock); -+ if (ret) -+ return ret; -+ -+ memset(&uhid->input_buf, 0, sizeof(uhid->input_buf)); -+ len = min(count, sizeof(uhid->input_buf)); -+ if (copy_from_user(&uhid->input_buf, buffer, len)) { -+ ret = -EFAULT; -+ goto unlock; -+ } -+ -+ switch (uhid->input_buf.type) { -+ case UHID_CREATE: -+ ret = uhid_dev_create(uhid, &uhid->input_buf); -+ break; -+ case UHID_DESTROY: -+ ret = uhid_dev_destroy(uhid); -+ break; -+ case UHID_INPUT: -+ ret = uhid_dev_input(uhid, &uhid->input_buf); -+ break; -+ case UHID_FEATURE_ANSWER: -+ ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); -+ break; -+ default: -+ ret = -EOPNOTSUPP; -+ } -+ -+unlock: -+ mutex_unlock(&uhid->devlock); -+ -+ /* return "count" not "len" to not confuse the caller */ -+ return ret ? ret : count; -+} -+ -+static unsigned int uhid_char_poll(struct file *file, poll_table *wait) -+{ -+ struct uhid_device *uhid = file->private_data; -+ -+ poll_wait(file, &uhid->waitq, wait); -+ -+ if (uhid->head != uhid->tail) -+ return POLLIN | POLLRDNORM; -+ -+ return 0; -+} -+ -+static const struct file_operations uhid_fops = { -+ .owner = THIS_MODULE, -+ .open = uhid_char_open, -+ .release = uhid_char_release, -+ .read = uhid_char_read, -+ .write = uhid_char_write, -+ .poll = uhid_char_poll, -+ .llseek = no_llseek, -+}; -+ -+static struct miscdevice uhid_misc = { -+ .fops = &uhid_fops, -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = UHID_NAME, -+}; -+ -+static int __init uhid_init(void) -+{ -+ return misc_register(&uhid_misc); -+} -+ -+static void __exit uhid_exit(void) -+{ -+ misc_deregister(&uhid_misc); -+} -+ -+module_init(uhid_init); -+module_exit(uhid_exit); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>"); -+MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem"); -diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index ea8736bc..af663a88 100644 ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -723,6 +723,30 @@ config I2C_XLR - This driver can also be built as a module. If so, the module - will be called i2c-xlr. - -+config I2C_ANYKA -+ bool "Anyka I2C drivers support" -+ depends on ARCH_AK39 -+ help -+ Say Y here to enable support for I2C driver for Anyka chip. -+ -+choice -+ bool "I2C driver" -+ depends on I2C_ANYKA -+ -+config I2C_AK39_HW -+ bool "i2c controller" -+ depends on I2C_ANYKA -+ help -+ Say Y here to enable support for I2C driver by chip controller. -+ -+config I2C_GPIO_SOFT -+ bool "i2c software simulate by gpios" -+ depends on I2C_ANYKA && I2C_ALGOBIT -+ help -+ Say Y here to enable support I2C driver by GPIOs simulate -+ -+endchoice -+ - comment "External I2C/SMBus adapter drivers" - - config I2C_DIOLAN_U2C -diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile -index 2f05d7b6..969fdc8b 100644 ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -72,6 +72,8 @@ obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o - obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o - obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o - obj-$(CONFIG_I2C_XLR) += i2c-xlr.o -+obj-$(CONFIG_I2C_AK39_HW) += i2c-ak39.o -+obj-$(CONFIG_I2C_GPIO_SOFT) += i2c-gpio-soft.o - - # External I2C/SMBus adapter drivers - obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o -diff --git a/drivers/i2c/busses/i2c-ak39.c b/drivers/i2c/busses/i2c-ak39.c -new file mode 100755 -index 00000000..3a88d6f1 ---- /dev/null -+++ b/drivers/i2c/busses/i2c-ak39.c -@@ -0,0 +1,931 @@ -+/* linux/drivers/i2c/busses/i2c-ak39.c -+ * -+ * Copyright (C) 2010 Anyka -+ * -+ * AK39xx I2C Controller -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+*/ -+ -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <linux/i2c.h> -+#include <linux/err.h> -+#include <linux/platform_device.h> -+#include <linux/clk.h> -+#include <linux/cpufreq.h> -+#include <linux/semaphore.h> -+ -+#include <asm/irq.h> -+#include <mach/clock.h> -+#include <asm/gpio.h> -+#include <mach/i2c.h> -+#include <mach/reset.h> -+ -+#define AK39_I2C_INTERRUPT_MODE -+//#define AK39_I2C_POLL_MODE -+ -+/* i2c controller state */ -+enum ak39_i2c_state { -+ STATE_READ, -+ STATE_WRITE -+}; -+ -+enum read_data_addr { -+ READ_ADDR, -+ READ_DATA -+}; -+ -+struct ak39_i2c { -+ spinlock_t lock; -+ wait_queue_head_t wait; -+ unsigned int suspended:1; -+ -+ struct i2c_msg *msg; -+ unsigned int msg_num; -+ unsigned int msg_idx; -+ unsigned int msg_ptr; -+ -+ unsigned int irq; -+ unsigned long clkrate; -+ -+ enum ak39_i2c_state state; -+ enum read_data_addr read_value; -+ -+ void __iomem *regs; -+ struct clk *clk; -+ struct device *dev; -+ struct resource *ioarea; -+ struct i2c_adapter adap; -+ -+#ifdef CONFIG_CPU_FREQ -+ struct notifier_block freq_transition; -+#endif -+}; -+ -+static struct semaphore xfer_sem; -+ -+/* ~~~~~~~~~~~ poll mode ~~~~~~~~~~~~~~~~~~~~~~~~~ */ -+ -+#ifdef AK39_I2C_POLL_MODE -+ -+/* -+ * Poll the i2c status register until the specified bit is set. -+ * Return 1 if transfer finished. -+ */ -+static short ak39_poll_status(void) -+{ -+ do { -+ } while (!(__raw_readl(AK39_I2C_CTRL) & INT_PEND_FLAG)); -+ -+ return 1; -+} -+ -+static int xfer_read(struct ak39_i2c *i2c, unsigned char *buf, int length) -+{ -+ int i,j, ctrl_value; -+ unsigned long ret, reg_value; -+ unsigned char *p = buf; -+ int idx = 0; -+ -+ if((length - 1) > 15) -+ ctrl_value = 16; -+ else -+ ctrl_value = length; -+ -+ ret = __raw_readl(AK39_I2C_CTRL); -+ ret |= (AK39_I2C_START | AK39_I2C_ACKEN | AK39_I2C_TXRXSEL | AK39_I2C_CLR_DELAY); -+ ret &= ~((0xf) << AK39_I2C_TRX_BYTE); -+ ret |= ((ctrl_value - 1) << AK39_I2C_TRX_BYTE); -+ ret &= ~(INT_PEND_FLAG); -+ __raw_writel(ret, AK39_I2C_CTRL); -+ -+ -+ for (i = 0; i < length / 16; i++) { -+ if (!ak39_poll_status()) { -+ dev_dbg(&i2c->adap.dev, "RXRDY timeout\n"); -+ return -ETIMEDOUT; -+ } -+ -+ for (j = 0; j < 4; j++) { -+ reg_value = __raw_readl(AK39_I2C_DATA0 + j * 4); -+ *(unsigned long *)p = reg_value; -+ p +=4; -+ } -+ } -+ -+ if (!ak39_poll_status()) { -+ dev_dbg(&i2c->adap.dev, "RXRDY timeout\n"); -+ return -ETIMEDOUT; -+ } -+ -+ idx = 0; -+ for (; idx < (length % 16) / 4; idx++) { -+ unsigned long regval = __raw_readl(AK39_I2C_DATA0 + idx * 4); -+ *(unsigned long *)p = regval; -+ p +=4; -+ } -+ -+ if (length % 4) { -+ unsigned long regval; -+ if (!ak39_poll_status()) { -+ dev_dbg(&i2c->adap.dev, "RXRDY timeout\n"); -+ return -ETIMEDOUT; -+ } -+ -+ regval = __raw_readl(AK39_I2C_DATA0 + idx / 4); -+ for (i = 0; i < length % 4; i++) { -+ *p++ = (regval >> (i * 8)) & 0xFF; -+ } -+ } -+ -+ return 0; -+} -+ -+static void wait_xfer_write(struct ak39_i2c *i2c, int length) -+{ -+ unsigned long ret; -+ -+ ret = __raw_readl(AK39_I2C_CTRL); -+ ret |= (AK39_I2C_START); -+ ret &= ~(AK39_I2C_TXRXSEL | INT_PEND_FLAG); -+ ret &= ~((0xf) << AK39_I2C_TRX_BYTE); -+ ret |= ((length - 1)<< AK39_I2C_TRX_BYTE); -+ __raw_writel(ret, AK39_I2C_CTRL); -+ -+ if (!ak39_poll_status()) { -+ dev_info(&i2c->adap.dev, "TXRDY timeout\n"); -+ return ; -+ } -+} -+ -+static int xfer_write(struct ak39_i2c *i2c, unsigned char *buf, int length) -+{ -+ unsigned int i; -+ unsigned long reg_value; -+ unsigned int num_count, num_char; -+ int ctrl_value, num_bck = length; -+ unsigned char *p = buf; -+ -+ if((length - 1) > 15) -+ ctrl_value = 16; -+ else -+ ctrl_value = length; -+ -+ num_count = num_bck / 16; -+ num_char = num_bck % 16; -+ -+ while(num_count--) { -+ for(i = 0; i < 4; i++) { -+ reg_value = *(unsigned long *)p; -+ p += 4; -+ __raw_writel(reg_value, AK39_I2C_DATA0 + i * 4); -+ } -+ -+ wait_xfer_write(i2c, 16); -+ } -+ if(num_char > 0) { -+ unsigned long value = 0; -+ for(i = 0; i < num_char; i+=4) { -+ value = *(unsigned long *)p; -+ p +=4; -+ __raw_writel(value, AK39_I2C_DATA0 + i); -+ } -+ wait_xfer_write(i2c, num_char); -+ } -+ -+ return 0; -+} -+ -+static int ak39_i2c_doxfer(struct ak39_i2c *i2c, struct i2c_msg *msgs, int num) -+{ -+ unsigned int addr = (msgs->addr & 0x7f) << 1; -+ int i, ret, rw_flag; -+ -+ dev_dbg(&i2c->adap.dev, "ak39_i2c_doxfer: processing %d messages:\n", num); -+ -+ for (i = 0; i < num; i++) { -+ if (msgs->flags & I2C_M_RD) { -+ addr |= AK39_I2C_READ; -+ rw_flag = 1; -+ } else { -+ rw_flag = 0; -+ } -+ if (msgs->flags & I2C_M_REV_DIR_ADDR) -+ addr ^= 1; -+ -+ __raw_writel((AK39_I2C_CMD_EN | AK39_I2C_START_BIT)|addr, AK39_I2C_CMD1); -+ if(msgs->len && msgs->buf) { -+ if (rw_flag == 1) -+ ret = xfer_read(i2c, msgs->buf, msgs->len); -+ else -+ ret = xfer_write(i2c, msgs->buf, msgs->len); -+ -+ if (ret) -+ return ret; -+ } -+ dev_dbg(&i2c->adap.dev, "transfer complete\n"); -+ msgs++; /* next message */ -+ } -+ return i; -+} -+#endif -+ -+/* ~~~~~~~~~~~ INTER MODE ~~~~~~~~~~~~~~~~~~~ */ -+ -+#ifdef AK39_I2C_INTERRUPT_MODE -+ -+static void clear_int_flag(void) -+{ -+ unsigned long tmp; -+ -+ tmp = __raw_readl(AK39_I2C_CTRL); -+ tmp &= ~INT_PEND_FLAG; -+ __raw_writel(tmp, AK39_I2C_CTRL); -+} -+ -+/* irq disable functions */ -+static void ak39_i2c_disable_irq(struct ak39_i2c *i2c) -+{ -+ unsigned long tmp; -+ -+ tmp = __raw_readl(AK39_I2C_CTRL); -+ __raw_writel(tmp & ~AK39_I2C_INTEN, AK39_I2C_CTRL); -+} -+ -+static inline void ak39_i2c_master_complete(struct ak39_i2c *i2c, int ret) -+{ -+ dev_dbg(i2c->dev, "master_complete %d\n", ret); -+ -+ i2c->msg_ptr = 0; -+ i2c->msg = NULL; -+ i2c->msg_num = 0; -+ if (ret) -+ i2c->msg_idx = ret; -+ -+ wake_up(&i2c->wait); -+} -+ -+static inline void ak39_i2c_stop(struct ak39_i2c *i2c, int ret) -+{ -+ dev_dbg(i2c->dev, "STOP\n"); -+ -+ ak39_i2c_master_complete(i2c, ret); -+ ak39_i2c_disable_irq(i2c); -+} -+ -+static int ak39_i2c_irq_transfer(struct ak39_i2c *i2c) -+{ -+ unsigned int addr = (i2c->msg->addr & 0x7f) << 1; -+ unsigned int num_char, i, length; -+ unsigned long stat, regval = 0; -+ unsigned char *p = i2c->msg->buf; -+ -+read_next: -+ if(i2c->msg_idx < i2c->msg_num) { -+ if (i2c->msg->len == 0) { -+ ak39_i2c_stop(i2c, 0); -+ return 0; -+ } -+ -+ stat = __raw_readl(AK39_I2C_CTRL); -+ stat &= ~(0xf << 9); -+ if (i2c->msg->flags & I2C_M_RD) { -+ addr |= AK39_I2C_READ ; -+ i2c->state = STATE_READ ; -+ stat |= AK39_I2C_TXRXSEL ; -+ } -+ else { -+ i2c->state = STATE_WRITE ; -+ stat &= ~AK39_I2C_TXRXSEL ; -+ } -+ -+ if (i2c->msg->flags & I2C_M_REV_DIR_ADDR) -+ addr ^= 1; -+ -+ __raw_writel((AK39_I2C_CMD_EN | AK39_I2C_START_BIT)|addr, AK39_I2C_CMD1); -+ -+ switch(i2c->state) { -+ case STATE_WRITE: -+ -+ if (i2c->msg->len > 16) { -+ printk("Error, needed debug more data transmitted.\n"); -+ return 0; -+ } -+ if (i2c->msg_ptr < i2c->msg->len) { -+ -+ num_char = i2c->msg->len % 16; -+ -+ if (num_char > 0) { -+ __raw_writel(stat | ((num_char - 1) << 9), AK39_I2C_CTRL); -+ for(i = 0; i < num_char; i+=4) { -+ regval = *(unsigned long *)p; -+ p += 4; -+ __raw_writel(regval, AK39_I2C_DATA0 + i); -+ } -+ i2c->msg_ptr += num_char; -+ } -+ -+ if(i2c->msg_ptr >= i2c->msg->len){ -+ i2c->msg_ptr = 0; -+ i2c->msg_idx++; -+ i2c->msg++; -+ } -+ -+ stat = __raw_readl(AK39_I2C_CTRL); -+ __raw_writel(stat | AK39_I2C_START, AK39_I2C_CTRL); -+ } -+ break; -+ -+ case STATE_READ: -+ length = i2c->msg->len; -+ -+ if (i2c->msg->len > 16) { -+ printk("Error, needed debug more data transmitted.\n"); -+ return 0; -+ } -+ __raw_writel(stat | ((length - 1) << 9), AK39_I2C_CTRL); -+ -+ if(i2c->read_value == READ_ADDR) { -+ stat = __raw_readl(AK39_I2C_CTRL); -+ __raw_writel(stat | AK39_I2C_START, AK39_I2C_CTRL); -+ i2c->read_value = READ_DATA; -+ } else { -+ if (i2c->msg_ptr < i2c->msg->len) { -+ -+ num_char = i2c->msg->len % 16; -+ -+ if (num_char > 0) { -+ for (i = 0; i < num_char; i+=4) { -+ regval = __raw_readl(AK39_I2C_DATA0 + i); -+ *(unsigned long *)p = regval; -+ p += 4; -+ } -+ i2c->msg_ptr += num_char; -+ } -+ -+ if (i2c->msg_ptr >= i2c->msg->len) { -+ /* we need to go to the next i2c message */ -+ dev_dbg(i2c->dev, "READ: Next Message\n"); -+ -+ i2c->msg_ptr = 0; -+ i2c->msg_idx++; -+ i2c->msg++; -+ -+ if(i2c->msg_idx >= i2c->msg_num) { -+ ak39_i2c_stop(i2c, 0); -+ return 0; -+ } -+ } -+ i2c->read_value = READ_ADDR; -+ goto read_next; -+ } -+ } -+ break; -+ } -+ } -+ else { -+ ak39_i2c_stop(i2c, 0); -+ } -+ return 0; -+} -+ -+/* ak39_i2c_irq -+ * -+ * top level IRQ servicing routine -+*/ -+static irqreturn_t ak39_i2c_irq(int irqno, void *dev_id) -+{ -+ struct ak39_i2c *i2c = dev_id; -+ -+ clear_int_flag(); -+ -+ /* pretty much this leaves us with the fact that we've -+ * transmitted or received whatever byte we last sent */ -+ -+ ak39_i2c_irq_transfer(i2c); -+ -+ return IRQ_HANDLED; -+} -+ -+static int ak39_i2c_doxfer(struct ak39_i2c *i2c, struct i2c_msg *msgs, int num) -+{ -+ unsigned long timeout, stat; -+ int ret; -+ -+ if (i2c->suspended) -+ return -EIO; -+ -+ spin_lock_irq(&i2c->lock); -+ i2c->msg = msgs; -+ i2c->msg_num = num; -+ i2c->msg_ptr = 0; -+ i2c->msg_idx = 0; -+ i2c->read_value = READ_ADDR; -+ -+ ak39_i2c_irq_transfer(i2c); -+ stat = __raw_readl(AK39_I2C_CTRL); -+ stat |= AK39_I2C_INTEN | AK39_I2C_ACKEN; -+ __raw_writel(stat, AK39_I2C_CTRL); -+ -+ spin_unlock_irq(&i2c->lock); -+ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); -+ -+ ret = i2c->msg_idx; -+ -+ /* having these next two as dev_err() makes life very -+ * noisy when doing an i2cdetect */ -+ -+ if (timeout == 0) -+ dev_info(i2c->dev, "timeout\n"); -+ else if (ret != num) -+ dev_info(i2c->dev, "incomplete xfer (%d)\n", ret); -+ -+ return ret; -+} -+#endif -+ -+ -+/* ak39_i2c_xfer -+ * -+ * first port of call from the i2c bus code when an message needs -+ * transferring across the i2c bus. -+*/ -+static int ak39_i2c_xfer(struct i2c_adapter *adap, -+ struct i2c_msg *msgs, int num) -+{ -+ struct ak39_i2c *i2c = (struct ak39_i2c *)adap->algo_data; -+ int retry; -+ int ret; -+ -+ down(&xfer_sem); -+ for (retry = 0; retry < adap->retries; retry++) { -+ -+ ret = ak39_i2c_doxfer(i2c, msgs, num); -+ -+ if (ret != -EAGAIN) -+ { -+ up(&xfer_sem); -+ return ret; -+ } -+ -+ dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); -+ -+ udelay(100); -+ } -+ -+ up(&xfer_sem); -+ return -EREMOTEIO; -+} -+ -+/* declare our i2c functionality */ -+static u32 ak39_i2c_func(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; -+} -+ -+/* i2c bus registration info */ -+ -+static const struct i2c_algorithm ak39_i2c_algorithm = { -+ .master_xfer = ak39_i2c_xfer, -+ .functionality = ak39_i2c_func, -+}; -+ -+/* ak39_i2c_calcdivisor -+ * -+ * return the divisor settings for a given frequency -+*/ -+static int ak39_i2c_calcdivisor(unsigned long clkin, unsigned int wanted, -+ unsigned int *div1, unsigned int *divs) -+{ -+ unsigned int calc_divs = clkin / wanted / 2; -+ unsigned int calc_div1; -+ -+ if (calc_divs > (16*16)) -+ calc_div1 = 512; -+ else -+ calc_div1 = 16; -+ -+ calc_divs /= calc_div1; -+ -+ if (calc_divs == 0) -+ calc_divs = 1; -+ if (calc_divs > 16) -+ calc_divs = 16; -+ -+ *divs = calc_divs; -+ *div1 = calc_div1; -+ -+ return clkin / ((calc_divs * 2)* calc_div1); -+} -+ -+/* ak39_i2c_clockrate -+ * -+ * work out a divisor for the user requested frequency setting, -+ * either by the requested frequency, or scanning the acceptable -+ * range of frequencies until something is found -+*/ -+static int ak39_i2c_clockrate(struct ak39_i2c *i2c, unsigned int *got) -+{ -+ struct ak39_platform_i2c *pdata = i2c->dev->platform_data; -+ unsigned long clkin = ak_get_asic_clk(); -+ unsigned int divs, div1; -+ unsigned long target_frequency; -+ u32 i2c_val, sda_delay; -+ int freq; -+ -+ i2c->clkrate = clkin; -+ clkin /= 1000; /* clkin now in KHz */ -+ -+ dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency); -+ -+ target_frequency = pdata->frequency ? pdata->frequency : 100000; -+ //target_frequency *= 4; -+ target_frequency /= 1000; /* Target frequency now in KHz */ -+ -+ freq = ak39_i2c_calcdivisor(clkin, target_frequency, &div1, &divs); -+ if (freq > target_frequency) { -+ dev_err(i2c->dev, -+ "Unable to achieve desired frequency %luKHz." \ -+ " Lowest achievable %dKHz\n", target_frequency, freq); -+ // return -EINVAL; -+ } -+ -+ *got = freq; -+ -+ i2c_val = __raw_readl(AK39_I2C_CTRL); -+ i2c_val &= ~(AK39_TX_CLK_DIV | AK39_I2C_TXDIV_512); -+ i2c_val |= (divs-1); -+ -+ if (div1 == 512) -+ i2c_val |= AK39_I2C_TXDIV_512; -+ -+ __raw_writel(i2c_val, AK39_I2C_CTRL); -+ -+ if (pdata->sda_delay) { -+ sda_delay = (freq / 1000) * pdata->sda_delay; -+ sda_delay /= 1000000; -+ sda_delay = DIV_ROUND_UP(sda_delay, 5); -+ if (sda_delay > 3) -+ sda_delay = AK39_I2C_CLR_DELAY; -+ -+ sda_delay |= AK39_I2C_SDA_DELAY; -+ } else -+ sda_delay = ~AK39_I2C_CLR_DELAY; -+ -+ i2c_val |= sda_delay; -+ __raw_writel(i2c_val, AK39_I2C_CTRL); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_CPU_FREQ -+ -+#define freq_to_i2c(_n) container_of(_n, struct ak39_i2c, freq_transition) -+ -+static int ak39_i2c_cpufreq_transition(struct notifier_block *nb, -+ unsigned long val, void *data) -+{ -+ struct ak39_i2c *i2c = freq_to_i2c(nb); -+ struct cpufreq_freqs *freqs = (struct cpufreq_freqs *)data; -+ unsigned int old_clk = freqs->old_cpufreq.asic_clk; -+ unsigned int new_clk = freqs->new_cpufreq.asic_clk; -+ unsigned long flags; -+ unsigned int got; -+ int ret; -+ -+ if (val == CPUFREQ_PRECHANGE) -+ { -+ down(&xfer_sem); -+ } -+ else if (val == CPUFREQ_POSTCHANGE) -+ { -+ if (old_clk != new_clk) -+ { -+ spin_lock_irqsave(&i2c->lock, flags); -+ ret = ak39_i2c_clockrate(i2c, &got); -+ //printk("setting freq %u\n", got); -+ spin_unlock_irqrestore(&i2c->lock, flags); -+ -+ if (ret < 0) -+ dev_err(i2c->dev, "cannot find frequency\n"); -+ else -+ dev_info(i2c->dev, "setting freq %d\n", got); -+ -+ } -+ up(&xfer_sem); -+ } -+ -+ return 0; -+} -+ -+static inline int ak39_i2c_register_cpufreq(struct ak39_i2c *i2c) -+{ -+ i2c->freq_transition.notifier_call = ak39_i2c_cpufreq_transition; -+ return cpufreq_register_notifier(&i2c->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+static inline void ak39_i2c_deregister_cpufreq(struct ak39_i2c *i2c) -+{ -+ cpufreq_unregister_notifier(&i2c->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+#else -+static inline int ak39_i2c_register_cpufreq(struct ak39_i2c *i2c) -+{ -+ return 0; -+} -+static inline void ak39_i2c_deregister_cpufreq(struct ak39_i2c *i2c) -+{ -+} -+#endif -+ -+/* ak39_i2c_init -+ * -+ * initialise the controller, set the IO lines and frequency -+*/ -+static int ak39_i2c_init(struct ak39_i2c *i2c) -+{ -+ struct ak39_platform_i2c *pdata; -+ unsigned int freq ; -+ -+ /* -+ * Reset I2C Controller -+ */ -+ ak39_soft_reset(AK39_SRESET_I2C); -+ -+ /* get the plafrom data */ -+ pdata = i2c->dev->platform_data; -+ -+ /* inititalise the gpio */ -+ ak_group_config(ePIN_AS_I2C); -+ -+ __raw_writel(AK39_I2C_INTEN | AK39_I2C_ACKEN, AK39_I2C_CTRL); -+ -+ /* we need to work out the divisors for the clock... */ -+ if (ak39_i2c_clockrate(i2c, &freq) != 0) { -+ __raw_writel(0, AK39_I2C_CTRL); -+ dev_err(i2c->dev, "cannot meet bus frequency required\n"); -+ return -EINVAL; -+ } -+ -+ /* todo - check that the i2c lines aren't being dragged anywhere */ -+ -+ dev_dbg(i2c->dev, "bus frequency set to %d KHz\n", freq); -+ return 0; -+} -+ -+ -+/* ak39_i2c_probe -+ * -+ * called by the bus driver when a suitable device is found -+*/ -+static int ak39_i2c_probe(struct platform_device *pdev) -+{ -+ struct ak39_i2c *i2c; -+ struct ak39_platform_i2c *pdata; -+ struct resource *res; -+ int ret; -+ -+ pdata = pdev->dev.platform_data; -+ if (!pdata) { -+ dev_err(&pdev->dev, "no platform data\n"); -+ return -EINVAL; -+ } -+ -+ i2c = kzalloc(sizeof(struct ak39_i2c), GFP_KERNEL); -+ if (!i2c) { -+ dev_err(&pdev->dev, "no memory for state\n"); -+ return -ENOMEM; -+ } -+ -+ strlcpy(i2c->adap.name, "ak39-i2c", sizeof(i2c->adap.name)); -+ i2c->adap.owner = THIS_MODULE; -+ i2c->adap.algo = &ak39_i2c_algorithm; -+ i2c->adap.retries = 2; -+ i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ -+ spin_lock_init(&i2c->lock); -+ init_waitqueue_head(&i2c->wait); -+ -+ /* find the clock and enable it */ -+ -+ i2c->dev = &pdev->dev; -+ i2c->clk = clk_get(&pdev->dev, "i2c"); -+ if (IS_ERR(i2c->clk)) { -+ dev_err(&pdev->dev, "cannot get clock\n"); -+ ret = -ENOENT; -+ goto err_noclk; -+ } -+ -+ dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); -+ -+ clk_enable(i2c->clk); -+ -+ /* map the registers */ -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res == NULL) { -+ dev_err(&pdev->dev, "cannot find IO resource\n"); -+ ret = -ENOENT; -+ goto err_clk; -+ } -+ -+ i2c->ioarea = request_mem_region(res->start, resource_size(res), pdev->name); -+ if (i2c->ioarea == NULL) { -+ dev_err(&pdev->dev, "cannot request IO\n"); -+ ret = -ENXIO; -+ goto err_clk; -+ } -+ -+ i2c->regs = ioremap(res->start, resource_size(res)); -+ if (i2c->regs == NULL) { -+ dev_err(&pdev->dev, "cannot map IO\n"); -+ ret = -ENXIO; -+ goto err_ioarea; -+ } -+ -+ dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res); -+ -+ /* setup info block for the i2c core */ -+ -+ i2c->adap.algo_data = i2c; -+ i2c->adap.dev.parent = &pdev->dev; -+ -+ /* initialise the i2c controller */ -+ -+ ret = ak39_i2c_init(i2c); -+ if (ret != 0) -+ goto err_iomap; -+ -+ /* find the IRQ for this unit (note, this relies on the init call to -+ * ensure no current IRQs pending -+ */ -+ i2c->irq = ret = platform_get_irq(pdev, 0); -+ if (ret <= 0) { -+ dev_err(&pdev->dev, "cannot find IRQ\n"); -+ goto err_iomap; -+ } -+ -+#ifdef AK39_I2C_INTERRUPT_MODE -+ ret = request_irq(i2c->irq, ak39_i2c_irq, IRQF_DISABLED, dev_name(&pdev->dev), i2c); -+ if (ret != 0) { -+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); -+ goto err_iomap; -+ } -+#endif -+ -+ sema_init(&xfer_sem, 1); -+ ret = ak39_i2c_register_cpufreq(i2c); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); -+ goto err_irq; -+ } -+ -+ i2c->adap.nr = pdata->bus_num; -+ ret = i2c_add_numbered_adapter(&i2c->adap); -+ -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to add bus to i2c core\n"); -+ goto err_cpufreq; -+ } -+ -+ platform_set_drvdata(pdev, i2c); -+ -+ dev_info(&pdev->dev, "%s: AK39 I2C adapter\n", dev_name(&i2c->adap.dev)); -+ -+ return 0; -+ -+ err_cpufreq: -+ ak39_i2c_deregister_cpufreq(i2c); -+ -+ err_irq: -+ free_irq(i2c->irq, i2c); -+ -+ err_iomap: -+ iounmap(i2c->regs); -+ -+ err_ioarea: -+ release_resource(i2c->ioarea); -+ kfree(i2c->ioarea); -+ -+ err_clk: -+ clk_disable(i2c->clk); -+ clk_put(i2c->clk); -+ -+ err_noclk: -+ kfree(i2c); -+ return ret; -+} -+ -+ -+/* ak39_i2c_remove -+ * -+ * called when device is removed from the bus -+*/ -+static int ak39_i2c_remove(struct platform_device *pdev) -+{ -+ struct ak39_i2c *i2c = platform_get_drvdata(pdev); -+ -+ ak39_i2c_deregister_cpufreq(i2c); -+ -+ i2c_del_adapter(&i2c->adap); -+ free_irq(i2c->irq, i2c); -+ -+ clk_disable(i2c->clk); -+ clk_put(i2c->clk); -+ -+ iounmap(i2c->regs); -+ -+ release_resource(i2c->ioarea); -+ -+ kfree(i2c->ioarea); -+ kfree(i2c); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int ak39_i2c_suspend_noirq(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct ak39_i2c *i2c = platform_get_drvdata(pdev); -+ struct ak39_platform_i2c *pdata = pdev->dev.platform_data; -+ int i; -+ -+ down(&xfer_sem); -+ i2c->suspended = 1; -+ -+ clk_disable(i2c->clk); -+ clk_put(i2c->clk); -+ -+ for (i=0; i<pdata->npins; i++) -+ ak_gpio_set(&(pdata->gpios[i])); -+ -+ return 0; -+} -+ -+static int ak39_i2c_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct ak39_i2c *i2c = platform_get_drvdata(pdev); -+ -+ i2c->suspended = 0; -+ clk_enable(i2c->clk); -+ ak39_i2c_init(i2c); -+ up(&xfer_sem); -+ return 0; -+} -+ -+static struct dev_pm_ops ak39_i2c_dev_pm_ops = { -+ .suspend_noirq = ak39_i2c_suspend_noirq, -+ .resume = ak39_i2c_resume, -+}; -+ -+#define AK39_DEV_PM_OPS (&ak39_i2c_dev_pm_ops) -+#else -+#define AK39_DEV_PM_OPS NULL -+#endif -+ -+/* device driver for platform bus bits */ -+static struct platform_driver ak39_i2c_driver = { -+ .probe = ak39_i2c_probe, -+ .remove = ak39_i2c_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "i2c-ak39", -+ .pm = AK39_DEV_PM_OPS, -+ }, -+}; -+ -+static int __init i2c_adap_ak39_init(void) -+{ -+ return platform_driver_register(&ak39_i2c_driver); -+} -+subsys_initcall(i2c_adap_ak39_init); -+ -+static void __exit i2c_adap_ak39_exit(void) -+{ -+ platform_driver_unregister(&ak39_i2c_driver); -+} -+module_exit(i2c_adap_ak39_exit); -+ -+MODULE_DESCRIPTION("AK39 I2C Bus driver"); -+MODULE_AUTHOR("Anaka, <xxx@xxx.com>"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/i2c/busses/i2c-gpio-soft.c b/drivers/i2c/busses/i2c-gpio-soft.c -new file mode 100644 -index 00000000..37984874 ---- /dev/null -+++ b/drivers/i2c/busses/i2c-gpio-soft.c -@@ -0,0 +1,287 @@ -+/* -+ * Bitbanging I2C bus driver using the GPIO API -+ * -+ * Copyright (C) 2007 Atmel Corporation -+ * -+ * 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/i2c.h> -+#include <linux/i2c-algo-bit.h> -+#include <linux/i2c-gpio.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/platform_device.h> -+#include <linux/gpio.h> -+#include <linux/of_gpio.h> -+#include <linux/of_i2c.h> -+#include <asm/gpio.h> -+ -+ -+struct i2c_gpio_private_data { -+ struct i2c_adapter adap; -+ struct i2c_algo_bit_data bit_data; -+ struct i2c_gpio_platform_data pdata; -+}; -+ -+/* Toggle SDA by changing the direction of the pin */ -+static void i2c_gpio_setsda_dir(void *data, int state) -+{ -+ struct i2c_gpio_platform_data *pdata = data; -+ -+ if (state) -+ ak_gpio_dircfg(pdata->sda_pin, AK_GPIO_DIR_INPUT); -+ else { -+ ak_gpio_dircfg(pdata->sda_pin, AK_GPIO_DIR_OUTPUT); -+ ak_gpio_setpin(pdata->sda_pin, AK_GPIO_OUT_LOW); -+ } -+} -+ -+/* -+ * Toggle SDA by changing the output value of the pin. This is only -+ * valid for pins configured as open drain (i.e. setting the value -+ * high effectively turns off the output driver.) -+ */ -+static void i2c_gpio_setsda_val(void *data, int state) -+{ -+ struct i2c_gpio_platform_data *pdata = data; -+ -+ ak_gpio_setpin(pdata->sda_pin, state); -+} -+ -+/* Toggle SCL by changing the direction of the pin. */ -+static void i2c_gpio_setscl_dir(void *data, int state) -+{ -+ struct i2c_gpio_platform_data *pdata = data; -+ -+ if (state) -+ ak_gpio_dircfg(pdata->scl_pin, AK_GPIO_DIR_INPUT); -+ else { -+ ak_gpio_dircfg(pdata->scl_pin, AK_GPIO_DIR_OUTPUT); -+ ak_gpio_setpin(pdata->sda_pin, AK_GPIO_OUT_LOW); -+ } -+} -+ -+/* -+ * Toggle SCL by changing the output value of the pin. This is used -+ * for pins that are configured as open drain and for output-only -+ * pins. The latter case will break the i2c protocol, but it will -+ * often work in practice. -+ */ -+static void i2c_gpio_setscl_val(void *data, int state) -+{ -+ struct i2c_gpio_platform_data *pdata = data; -+ -+ ak_gpio_setpin(pdata->scl_pin, state); -+} -+ -+static int i2c_gpio_getsda(void *data) -+{ -+ struct i2c_gpio_platform_data *pdata = data; -+ -+ return ak_gpio_getpin(pdata->sda_pin); -+} -+ -+static int i2c_gpio_getscl(void *data) -+{ -+ struct i2c_gpio_platform_data *pdata = data; -+ -+ return ak_gpio_getpin(pdata->scl_pin); -+} -+ -+static int __devinit of_i2c_gpio_probe(struct device_node *np, -+ struct i2c_gpio_platform_data *pdata) -+{ -+ u32 reg; -+ -+ if (of_gpio_count(np) < 2) -+ return -ENODEV; -+ -+ pdata->sda_pin = of_get_gpio(np, 0); -+ pdata->scl_pin = of_get_gpio(np, 1); -+ -+ if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) { -+ pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", -+ np->full_name, pdata->sda_pin, pdata->scl_pin); -+ return -ENODEV; -+ } -+ -+ of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); -+ -+ if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) -+ pdata->timeout = msecs_to_jiffies(reg); -+ -+ pdata->sda_is_open_drain = -+ of_property_read_bool(np, "i2c-gpio,sda-open-drain"); -+ pdata->scl_is_open_drain = -+ of_property_read_bool(np, "i2c-gpio,scl-open-drain"); -+ pdata->scl_is_output_only = -+ of_property_read_bool(np, "i2c-gpio,scl-output-only"); -+ -+ return 0; -+} -+ -+static int __devinit i2c_gpio_probe(struct platform_device *pdev) -+{ -+ struct i2c_gpio_private_data *priv; -+ struct i2c_gpio_platform_data *pdata; -+ struct i2c_algo_bit_data *bit_data; -+ struct i2c_adapter *adap; -+ int ret; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ adap = &priv->adap; -+ bit_data = &priv->bit_data; -+ pdata = &priv->pdata; -+ -+ if (pdev->dev.of_node) { -+ ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata); -+ if (ret) -+ return ret; -+ } else { -+ if (!pdev->dev.platform_data) -+ return -ENXIO; -+ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); -+ } -+ -+ ret = ak_gpio_request(pdata->sda_pin, "sda"); -+ if (ret) -+ goto err_request_sda; -+ ret = ak_gpio_request(pdata->scl_pin, "scl"); -+ if (ret) -+ goto err_request_scl; -+ -+ if (pdata->sda_is_open_drain) { -+ ak_gpio_dircfg(pdata->sda_pin, AK_GPIO_DIR_OUTPUT); -+ ak_gpio_setpin(pdata->sda_pin, AK_GPIO_OUT_HIGH); -+ bit_data->setsda = i2c_gpio_setsda_val; -+ } else { -+ ak_gpio_dircfg(pdata->sda_pin, AK_GPIO_DIR_INPUT); -+ bit_data->setsda = i2c_gpio_setsda_dir; -+ } -+ -+ if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { -+ ak_gpio_dircfg(pdata->sda_pin, AK_GPIO_DIR_OUTPUT); -+ ak_gpio_setpin(pdata->sda_pin, AK_GPIO_OUT_HIGH); -+ bit_data->setscl = i2c_gpio_setscl_val; -+ } else { -+ ak_gpio_dircfg(pdata->sda_pin, AK_GPIO_DIR_INPUT); -+ bit_data->setscl = i2c_gpio_setscl_dir; -+ } -+ -+ if (!pdata->scl_is_output_only) -+ bit_data->getscl = i2c_gpio_getscl; -+ bit_data->getsda = i2c_gpio_getsda; -+ -+ if (pdata->udelay) -+ bit_data->udelay = pdata->udelay; -+ else if (pdata->scl_is_output_only) -+ bit_data->udelay = 50; /* 10 kHz */ -+ else -+ bit_data->udelay = 5; /* 100 kHz */ -+ -+ if (pdata->timeout) -+ bit_data->timeout = pdata->timeout; -+ else -+ bit_data->timeout = HZ / 10; /* 100 ms */ -+ -+ bit_data->data = pdata; -+ -+ adap->owner = THIS_MODULE; -+ snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); -+ adap->algo_data = bit_data; -+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ adap->dev.parent = &pdev->dev; -+ adap->dev.of_node = pdev->dev.of_node; -+ -+ /* -+ * If "dev->id" is negative we consider it as zero. -+ * The reason to do so is to avoid sysfs names that only make -+ * sense when there are multiple adapters. -+ */ -+ adap->nr = (pdev->id != -1) ? pdev->id : 0; -+ ret = i2c_bit_add_numbered_bus(adap); -+ if (ret) -+ goto err_add_bus; -+ -+ of_i2c_register_devices(adap); -+ -+ platform_set_drvdata(pdev, priv); -+ -+ dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", -+ pdata->sda_pin, pdata->scl_pin, -+ pdata->scl_is_output_only -+ ? ", no clock stretching" : ""); -+ -+ return 0; -+ -+err_add_bus: -+ ak_gpio_free(pdata->scl_pin); -+err_request_scl: -+ ak_gpio_free(pdata->sda_pin); -+err_request_sda: -+ return ret; -+} -+ -+static int __devexit i2c_gpio_remove(struct platform_device *pdev) -+{ -+ struct i2c_gpio_private_data *priv; -+ struct i2c_gpio_platform_data *pdata; -+ struct i2c_adapter *adap; -+ -+ priv = platform_get_drvdata(pdev); -+ adap = &priv->adap; -+ pdata = &priv->pdata; -+ -+ i2c_del_adapter(adap); -+ ak_gpio_free(pdata->scl_pin); -+ ak_gpio_free(pdata->sda_pin); -+ -+ return 0; -+} -+ -+#if defined(CONFIG_OF) -+static const struct of_device_id i2c_gpio_dt_ids[] = { -+ { .compatible = "i2c-gpio", }, -+ { /* sentinel */ } -+}; -+ -+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); -+#endif -+ -+static struct platform_driver i2c_gpio_driver = { -+ .driver = { -+ .name = "i2c-gpio", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(i2c_gpio_dt_ids), -+ }, -+ .probe = i2c_gpio_probe, -+ .remove = __devexit_p(i2c_gpio_remove), -+}; -+ -+static int __init i2c_gpio_init(void) -+{ -+ int ret; -+ -+ ret = platform_driver_register(&i2c_gpio_driver); -+ if (ret) -+ printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); -+ -+ return ret; -+} -+subsys_initcall(i2c_gpio_init); -+ -+static void __exit i2c_gpio_exit(void) -+{ -+ platform_driver_unregister(&i2c_gpio_driver); -+} -+module_exit(i2c_gpio_exit); -+ -+MODULE_AUTHOR("Anyka ltd company"); -+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:i2c-gpio"); -diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig -index 33259798..69d36863 100644 ---- a/drivers/input/Kconfig -+++ b/drivers/input/Kconfig -@@ -165,6 +165,15 @@ config INPUT_APMPOWER - To compile this driver as a module, choose M here: the - module will be called apm-power. - -+config INPUT_KEYRESET -+ tristate "Reset key" -+ depends on INPUT -+ ---help--- -+ Say Y here if you want to reboot when some keys are pressed; -+ -+ To compile this driver as a module, choose M here: the -+ module will be called keyreset. -+ - comment "Input Device Drivers" - - source "drivers/input/keyboard/Kconfig" -diff --git a/drivers/input/Makefile b/drivers/input/Makefile -index b173a13a..cf643bee 100644 ---- a/drivers/input/Makefile -+++ b/drivers/input/Makefile -@@ -25,3 +25,4 @@ obj-$(CONFIG_INPUT_MISC) += misc/ - - obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o - obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o -+obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o -diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c -index 4b2e10d5..a9374387 100644 ---- a/drivers/input/evdev.c -+++ b/drivers/input/evdev.c -@@ -23,6 +23,7 @@ - #include <linux/input/mt.h> - #include <linux/major.h> - #include <linux/device.h> -+#include <linux/wakelock.h> - #include "input-compat.h" - - struct evdev { -@@ -43,6 +44,9 @@ struct evdev_client { - unsigned int tail; - unsigned int packet_head; /* [future] position of the first element of next packet */ - spinlock_t buffer_lock; /* protects access to buffer, head and tail */ -+ struct wake_lock wake_lock; -+ bool use_wake_lock; -+ char name[28]; - struct fasync_struct *fasync; - struct evdev *evdev; - struct list_head node; -@@ -80,10 +84,14 @@ static void evdev_pass_event(struct evdev_client *client, - client->buffer[client->tail].value = 0; - - client->packet_head = client->tail; -+ if (client->use_wake_lock) -+ wake_unlock(&client->wake_lock); - } - - if (event->type == EV_SYN && event->code == SYN_REPORT) { - client->packet_head = client->head; -+ if (client->use_wake_lock) -+ wake_lock(&client->wake_lock); - kill_fasync(&client->fasync, SIGIO, POLL_IN); - } - -@@ -264,6 +272,8 @@ static int evdev_release(struct inode *inode, struct file *file) - mutex_unlock(&evdev->mutex); - - evdev_detach_client(evdev, client); -+ if (client->use_wake_lock) -+ wake_lock_destroy(&client->wake_lock); - kfree(client); - - evdev_close_device(evdev); -@@ -315,6 +325,8 @@ static int evdev_open(struct inode *inode, struct file *file) - - client->bufsize = bufsize; - spin_lock_init(&client->buffer_lock); -+ snprintf(client->name, sizeof(client->name), "%s-%d", -+ dev_name(&evdev->dev), task_tgid_vnr(current)); - client->evdev = evdev; - evdev_attach_client(evdev, client); - -@@ -382,6 +394,9 @@ static int evdev_fetch_next_event(struct evdev_client *client, - if (have_event) { - *event = client->buffer[client->tail++]; - client->tail &= client->bufsize - 1; -+ if (client->use_wake_lock && -+ client->packet_head == client->tail) -+ wake_unlock(&client->wake_lock); - } - - spin_unlock_irq(&client->buffer_lock); -@@ -654,6 +669,35 @@ static int evdev_handle_mt_request(struct input_dev *dev, - return 0; - } - -+static int evdev_enable_suspend_block(struct evdev *evdev, -+ struct evdev_client *client) -+{ -+ if (client->use_wake_lock) -+ return 0; -+ -+ spin_lock_irq(&client->buffer_lock); -+ wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name); -+ client->use_wake_lock = true; -+ if (client->packet_head != client->tail) -+ wake_lock(&client->wake_lock); -+ spin_unlock_irq(&client->buffer_lock); -+ return 0; -+} -+ -+static int evdev_disable_suspend_block(struct evdev *evdev, -+ struct evdev_client *client) -+{ -+ if (!client->use_wake_lock) -+ return 0; -+ -+ spin_lock_irq(&client->buffer_lock); -+ client->use_wake_lock = false; -+ wake_lock_destroy(&client->wake_lock); -+ spin_unlock_irq(&client->buffer_lock); -+ -+ return 0; -+} -+ - static long evdev_do_ioctl(struct file *file, unsigned int cmd, - void __user *p, int compat_mode) - { -@@ -735,6 +779,15 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, - - case EVIOCSKEYCODE_V2: - return evdev_handle_set_keycode_v2(dev, p); -+ -+ case EVIOCGSUSPENDBLOCK: -+ return put_user(client->use_wake_lock, ip); -+ -+ case EVIOCSSUSPENDBLOCK: -+ if (p) -+ return evdev_enable_suspend_block(evdev, client); -+ else -+ return evdev_disable_suspend_block(evdev, client); - } - - size = _IOC_SIZE(cmd); -diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig -index f354813a..3e362083 100644 ---- a/drivers/input/keyboard/Kconfig -+++ b/drivers/input/keyboard/Kconfig -@@ -580,4 +580,35 @@ config KEYBOARD_W90P910 - To compile this driver as a module, choose M here: the - module will be called w90p910_keypad. - -+config KEYBOARD_AKKEY -+ tristate "Anyka gpio-keys support" -+ depends on ARCH_AK39 -+ help -+ This driver implements support for buttons connected -+ to GPIO pins of various CPUs (and some other chips). -+ -+ To compile this driver as a module, choose M here: the -+ module will be called akgpio_keys. -+ -+config KEYBOARD_AK_KEYPAD -+ tristate "Anyka matrix-keypad support" -+ depends on ARCH_AK39 -+ help -+ This driver implements support for buttons connected -+ to GPIO pins of various CPUs (and some other chips). -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ak_matrix_keypad. -+ -+config KEYBOARD_ADKEY -+ tristate "ADC simulate gpio keys support" -+ depends on ARCH_AK39 -+# select INPUT_POLLDEV -+ help -+ This driver implements support for AD-KEY connected -+ to ADC pin. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called akad-key. -+ - endif -diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile -index df7061f1..30cf1c52 100644 ---- a/drivers/input/keyboard/Makefile -+++ b/drivers/input/keyboard/Makefile -@@ -52,3 +52,6 @@ obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o - obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o - obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o - obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o -+obj-$(CONFIG_KEYBOARD_AKKEY) += akgpio_keys.o -+obj-$(CONFIG_KEYBOARD_AK_KEYPAD) += akmatrix_keypad.o -+obj-$(CONFIG_KEYBOARD_ADKEY) += akad-keys.o -diff --git a/drivers/input/keyboard/akad-keys.c b/drivers/input/keyboard/akad-keys.c -new file mode 100755 -index 00000000..a8eec235 ---- /dev/null -+++ b/drivers/input/keyboard/akad-keys.c -@@ -0,0 +1,358 @@ -+/* -+ * drivers/input/keyboard/akad-keys.c -+ */ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/input-polldev.h> -+#include <linux/interrupt.h> -+#include <linux/jiffies.h> -+#include <linux/slab.h> -+#include <linux/platform_device.h> -+#include <linux/errno.h> -+#include <linux/pm.h> -+#include <plat-anyka/adkey.h> -+#include <plat-anyka/notify.h> -+ -+#include <mach/gpio.h> -+#include <mach/adc.h> -+ -+//#define ADKEY_DEBUG -+ -+#ifdef ADKEY_DEBUG -+#define pr_dbg(fmt...) printk(fmt) -+#else -+#define pr_dbg(fmt...) -+#endif -+ -+#define DRV_NAME "ad-keys" -+ -+struct adgpio_key_data { -+ struct input_dev *input; -+ struct adgpio_key *keys; -+ struct timer_list timer; -+ /* private: */ -+ struct delayed_work work; -+ -+ struct semaphore sem; -+ -+ struct multi_addetect *addet; -+ int naddet; -+ -+ int poll_interval; -+ int debounce_interval; -+ int keycode; -+ int nkey; -+ -+ unsigned char loop; -+ unsigned char press; -+ unsigned char sync_me; -+}; -+ -+static void adkeys_poll(struct adgpio_key_data *adkey); -+ -+static void adkey_input_queue_work(struct adgpio_key_data *adkey) -+{ -+ unsigned long delay; -+ -+ delay = msecs_to_jiffies(adkey->poll_interval); -+ if (delay >= HZ) -+ delay = round_jiffies_relative(delay); -+ -+ queue_delayed_work(system_freezable_wq, &adkey->work, delay); -+} -+ -+static void adkey_input_device_work(struct work_struct *work) -+{ -+ struct adgpio_key_data *adkey = -+ container_of(work, struct adgpio_key_data, work.work); -+ -+ adkeys_poll(adkey); -+ adkey_input_queue_work(adkey); -+} -+ -+static void addetect_plugin_notify(T_ad_check state) -+{ -+ static bool dev1_flag = false; -+ static bool dev2_flag = false; -+ static bool dev3_flag = false; -+ static bool dev4_flag = false; -+ -+ pr_dbg("adkey: plugin device state: 0x%0x\n", state); -+ -+ if ((state & PLUGIN_DEV1) && (!dev1_flag)) { -+ addetect_notifier_call_chain(ADDEDECT_DEV1_PLUGIN, NULL); -+ dev1_flag = true; -+ } else if ((!(state & PLUGIN_DEV1)) && dev1_flag){ -+ addetect_notifier_call_chain(ADDEDECT_DEV1_PLUGOUT, NULL); -+ dev1_flag = false; -+ } -+ -+ if ((state & PLUGIN_DEV2) && (!dev2_flag)) { -+ addetect_notifier_call_chain(ADDEDECT_DEV2_PLUGIN, NULL); -+ dev2_flag = true; -+ } else if ((!(state & PLUGIN_DEV2)) && dev2_flag){ -+ addetect_notifier_call_chain(ADDEDECT_DEV2_PLUGOUT, NULL); -+ dev2_flag = false; -+ } -+ -+ if ((state & PLUGIN_DEV3) && (!dev3_flag)) { -+ addetect_notifier_call_chain(ADDEDECT_DEV3_PLUGIN, NULL); -+ dev3_flag = true; -+ } else if ((!(state & PLUGIN_DEV3)) && dev3_flag) { -+ addetect_notifier_call_chain(ADDEDECT_DEV3_PLUGOUT, NULL); -+ dev3_flag = false; -+ } -+ -+ if ((state & PLUGIN_DEV4) && (!dev4_flag)) { -+ addetect_notifier_call_chain(ADDEDECT_DEV4_PLUGIN, NULL); -+ dev4_flag = true; -+ } else if ((!(state & PLUGIN_DEV4)) && dev4_flag) { -+ addetect_notifier_call_chain(ADDEDECT_DEV4_PLUGOUT, NULL); -+ dev4_flag = false; -+ } -+} -+ -+static void adkeys_timer(unsigned long _data) -+{ -+ struct adgpio_key_data *adkey = (struct adgpio_key_data *)_data; -+ struct input_dev *input_dev = adkey->input; -+ int advol, i, code; -+ -+ if (!adkey->press) { -+ adkey->sync_me = 0; -+ } else { -+ advol = adc1_read_ad5(); -+ pr_dbg("timer: volatge: %d\n", advol); -+ -+ i = 0; -+ do { -+ if ((advol > adkey->keys[i].min)&&(advol < adkey->keys[i].max)) { -+ pr_dbg("timer: volatge: %d\n", advol); -+ code = adkey->keys[i].code; -+ if ((code == adkey->keycode)&&(i == adkey->loop)) -+ break; -+ } -+ i++; -+ } while(i < adkey->nkey); -+ } -+ -+ /* report the key */ -+ input_event(input_dev, EV_KEY, adkey->keycode, adkey->press); -+ input_sync(input_dev); -+} -+ -+static void adkeys_poll(struct adgpio_key_data *adkey) -+{ -+ int advol, i; -+ static struct adgpio_key *prev_keys = NULL; -+ static T_ad_check state = PLUGIN_INVALID; -+ static int is_change_flag = 0; -+ -+ advol = adc1_read_ad5(); -+ pr_dbg("poll: volatge: %d\n", advol); -+ -+ for (i = 0; i < adkey->naddet; i++) { -+ if ((advol > adkey->addet[i].unpress_min) -+ &&(advol < adkey->addet[i].unpress_max)) { -+ -+ adkey->keys = adkey->addet[i].fixkeys; -+ if ((prev_keys != adkey->keys) || (state != adkey->addet[i].plugdev)) { -+ prev_keys = adkey->keys; -+ state = adkey->addet[i].plugdev; -+ is_change_flag = 1; -+ } else { -+ is_change_flag = 0; -+ } -+ break; -+ } -+ } -+ -+ if (is_change_flag) { -+ addetect_plugin_notify(state); -+ } -+ -+ i = 0; -+ do { -+ if ((adkey->keys != NULL) -+ && (advol > adkey->keys[i].min) && (advol < adkey->keys[i].max)) { -+ adkey->press = 1; -+ adkey->sync_me = 1; -+ -+ adkey->keycode = adkey->keys[i].code; -+ adkey->loop = i; -+ break; -+ } else -+ adkey->press = 0; -+ -+ i++; -+ } while(i < adkey->nkey); -+ -+ if (adkey->sync_me) { -+ mod_timer(&adkey->timer, -+ jiffies + msecs_to_jiffies(adkey->debounce_interval)); -+ } -+} -+ -+static int analog_gpio_probe(struct platform_device *pdev) -+{ -+ struct adgpio_key_data *adkey; -+ struct input_dev *input_dev; -+ struct analog_gpio_key *pdata = NULL; -+ int i, err; -+ -+ pdata = pdev->dev.platform_data; -+ if (!pdata) -+ return -ENODEV; -+ -+ adkey = kzalloc(sizeof(struct adgpio_key_data)+ -+ pdata->naddet*sizeof(struct multi_addetect)+ -+ pdata->nkey*sizeof(struct adgpio_key), GFP_KERNEL); -+ if (!adkey) -+ return -ENOMEM; -+ -+ input_dev = input_allocate_device(); -+ if (!input_dev) { -+ err = -ENOMEM; -+ goto fail; -+ } -+ -+ platform_set_drvdata(pdev, adkey); -+ -+ adkey->input = input_dev; -+ if ((pdata->addet) && (pdata->naddet > 0)) { -+ adkey->addet = pdata->addet; -+ adkey->naddet = pdata->naddet; -+ adkey->keys = pdata->addet[0].fixkeys; -+ } -+ adkey->nkey = pdata->nkey; -+ -+ if (pdata->interval <= 0) -+ adkey->poll_interval = 500; -+ else -+ adkey->poll_interval = pdata->interval; -+ -+ if (pdata->debounce_interval <= 0) -+ adkey->debounce_interval = 20; -+ else -+ adkey->debounce_interval = pdata->debounce_interval; -+ -+ adkey->press = 0; -+ adkey->sync_me = 0; -+ -+ input_dev->name = pdev->name; -+ input_dev->phys = DRV_NAME"/input0"; -+ input_dev->id.bustype = BUS_HOST; -+ input_dev->id.vendor = 0x0001; -+ input_dev->id.product = 0x0010; -+ input_dev->id.version = 0x00100; -+ input_dev->dev.parent = &pdev->dev; -+ -+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); -+ input_dev->keycode = adkey->keys; -+ input_dev->keycodesize = sizeof(struct adgpio_key); -+ input_dev->keycodemax = adkey->nkey; -+ -+ for (i = 0; i < adkey->nkey; i++) -+ set_bit(adkey->keys[i].code, input_dev->keybit); -+ clear_bit(KEY_RESERVED, input_dev->keybit); -+ -+ input_set_capability(input_dev, EV_MSC, MSC_SCAN); -+ -+ INIT_DELAYED_WORK(&adkey->work, adkey_input_device_work); -+ -+ /* Only start polling if polling is enabled */ -+ adkey_input_queue_work(adkey); -+ -+ setup_timer(&adkey->timer, adkeys_timer, (unsigned long)adkey); -+ -+ err = input_register_device(adkey->input); -+ if (err) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ printk(KERN_ERR "Adkey: failed to register driver, error: %d\n", err); -+ platform_set_drvdata(pdev, NULL); -+ input_free_device(input_dev); -+ kfree(adkey); -+ return err; -+} -+ -+static int analog_gpio_remove(struct platform_device *pdev) -+{ -+ struct adgpio_key_data *adkey = platform_get_drvdata(pdev); -+ -+ cancel_delayed_work_sync(&adkey->work); -+ -+ input_unregister_device(adkey->input); -+ -+ input_free_device(adkey->input); -+ -+ del_timer_sync(&adkey->timer); -+ kfree(adkey); -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_PM -+static int analog_gpio_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ struct adgpio_key_data *adkey = platform_get_drvdata(pdev); -+ struct analog_gpio_key *pdata = pdev->dev.platform_data; -+ -+ if (pdata->wakeup > 0) -+ adkey_wakeup_enable(true); -+ -+ del_timer_sync(&adkey->timer); -+ -+ return 0; -+} -+ -+static int analog_gpio_resume(struct platform_device *pdev) -+{ -+ //struct adgpio_key_data *adkey = platform_get_drvdata(pdev); -+ struct analog_gpio_key *pdata = pdev->dev.platform_data; -+ -+ if (pdata->wakeup > 0) -+ adkey_wakeup_enable(false); -+ -+ return 0; -+} -+#else -+#define analog_gpio_suspend NULL -+#define analog_gpio_resume NULL -+#endif -+ -+static struct platform_driver analog_ops = { -+ .probe = analog_gpio_probe, -+ .remove = __devexit_p(analog_gpio_remove), -+ .suspend = analog_gpio_suspend, -+ .resume = analog_gpio_resume, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = DRV_NAME, -+ }, -+}; -+ -+static int __init analog_gpio_key_init(void) -+{ -+ printk("Init ADC simulate gpio keys driver.\n"); -+ return platform_driver_register(&analog_ops); -+} -+ -+static void __exit analog_gpio_key_exit(void) -+{ -+ platform_driver_unregister(&analog_ops); -+} -+ -+late_initcall(analog_gpio_key_init); -+module_exit(analog_gpio_key_exit); -+ -+MODULE_AUTHOR("Anyka Microelectronic Ltd."); -+MODULE_DESCRIPTION("Anyka ADC simulate gpio keys driver"); -+MODULE_ALIAS("platform:" DRV_NAME); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/keyboard/akgpio_keys.c b/drivers/input/keyboard/akgpio_keys.c -new file mode 100755 -index 00000000..923775a1 ---- /dev/null -+++ b/drivers/input/keyboard/akgpio_keys.c -@@ -0,0 +1,1003 @@ -+/* -+ * Driver for keys on GPIO lines capable of generating interrupts. -+ * -+ * Copyright 2005 Phil Blundell -+ * Copyright 2010, 2011 David Jander <david@protonic.nl> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ /* -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ */ -+ -+#include <linux/module.h> -+ -+#include <linux/init.h> -+#include <linux/fs.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/sched.h> -+#include <linux/pm.h> -+#include <linux/slab.h> -+#include <linux/sysctl.h> -+#include <linux/proc_fs.h> -+#include <linux/delay.h> -+#include <linux/platform_device.h> -+#include <linux/input.h> -+#include <linux/workqueue.h> -+#include <linux/gpio.h> -+#include <linux/of_platform.h> -+#include <linux/of_gpio.h> -+#include <linux/spinlock.h> -+#include <plat-anyka/gpio_keys.h> -+ -+#include <mach/gpio.h> -+ -+struct gpio_button_data { -+ const struct gpio_keys_button *button; -+ struct input_dev *input; -+ struct timer_list timer; -+ struct work_struct work; -+ unsigned int timer_debounce; /* in msecs */ -+ unsigned int irq; -+ spinlock_t lock; -+ bool disabled; -+ bool key_pressed; -+}; -+ -+struct gpio_keys_drvdata { -+ struct input_dev *input; -+ struct mutex disable_lock; -+ unsigned int n_buttons; -+ int (*enable)(struct device *dev); -+ void (*disable)(struct device *dev); -+ struct gpio_button_data data[0]; -+}; -+ -+/* -+ * SYSFS interface for enabling/disabling keys and switches: -+ * -+ * There are 4 attributes under /sys/devices/platform/gpio-keys/ -+ * keys [ro] - bitmap of keys (EV_KEY) which can be -+ * disabled -+ * switches [ro] - bitmap of switches (EV_SW) which can be -+ * disabled -+ * disabled_keys [rw] - bitmap of keys currently disabled -+ * disabled_switches [rw] - bitmap of switches currently disabled -+ * -+ * Userland can change these values and hence disable event generation -+ * for each key (or switch). Disabling a key means its interrupt line -+ * is disabled. -+ * -+ * For example, if we have following switches set up as gpio-keys: -+ * SW_DOCK = 5 -+ * SW_CAMERA_LENS_COVER = 9 -+ * SW_KEYPAD_SLIDE = 10 -+ * SW_FRONT_PROXIMITY = 11 -+ * This is read from switches: -+ * 11-9,5 -+ * Next we want to disable proximity (11) and dock (5), we write: -+ * 11,5 -+ * to file disabled_switches. Now proximity and dock IRQs are disabled. -+ * This can be verified by reading the file disabled_switches: -+ * 11,5 -+ * If we now want to enable proximity (11) switch we write: -+ * 5 -+ * to disabled_switches. -+ * -+ * We can disable only those keys which don't allow sharing the irq. -+ */ -+ -+/** -+ * get_n_events_by_type() - returns maximum number of events per @type -+ * @type: type of button (%EV_KEY, %EV_SW) -+ * -+ * Return value of this function can be used to allocate bitmap -+ * large enough to hold all bits for given type. -+ */ -+static inline int get_n_events_by_type(int type) -+{ -+ BUG_ON(type != EV_SW && type != EV_KEY); -+ -+ return (type == EV_KEY) ? KEY_CNT : SW_CNT; -+} -+ -+/** -+ * gpio_keys_disable_button() - disables given GPIO button -+ * @bdata: button data for button to be disabled -+ * -+ * Disables button pointed by @bdata. This is done by masking -+ * IRQ line. After this function is called, button won't generate -+ * input events anymore. Note that one can only disable buttons -+ * that don't share IRQs. -+ * -+ * Make sure that @bdata->disable_lock is locked when entering -+ * this function to avoid races when concurrent threads are -+ * disabling buttons at the same time. -+ */ -+static void gpio_keys_disable_button(struct gpio_button_data *bdata) -+{ -+ if (!bdata->disabled) { -+ /* -+ * Disable IRQ and possible debouncing timer. -+ */ -+ disable_irq(bdata->irq); -+ if (bdata->timer_debounce) -+ del_timer_sync(&bdata->timer); -+ -+ bdata->disabled = true; -+ } -+} -+ -+/** -+ * gpio_keys_enable_button() - enables given GPIO button -+ * @bdata: button data for button to be disabled -+ * -+ * Enables given button pointed by @bdata. -+ * -+ * Make sure that @bdata->disable_lock is locked when entering -+ * this function to avoid races with concurrent threads trying -+ * to enable the same button at the same time. -+ */ -+static void gpio_keys_enable_button(struct gpio_button_data *bdata) -+{ -+ if (bdata->disabled) { -+ enable_irq(bdata->irq); -+ bdata->disabled = false; -+ } -+} -+ -+/** -+ * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons -+ * @ddata: pointer to drvdata -+ * @buf: buffer where stringified bitmap is written -+ * @type: button type (%EV_KEY, %EV_SW) -+ * @only_disabled: does caller want only those buttons that are -+ * currently disabled or all buttons that can be -+ * disabled -+ * -+ * This function writes buttons that can be disabled to @buf. If -+ * @only_disabled is true, then @buf contains only those buttons -+ * that are currently disabled. Returns 0 on success or negative -+ * errno on failure. -+ */ -+static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata, -+ char *buf, unsigned int type, -+ bool only_disabled) -+{ -+ int n_events = get_n_events_by_type(type); -+ unsigned long *bits; -+ ssize_t ret; -+ int i; -+ -+ bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL); -+ if (!bits) -+ return -ENOMEM; -+ -+ for (i = 0; i < ddata->n_buttons; i++) { -+ struct gpio_button_data *bdata = &ddata->data[i]; -+ -+ if (bdata->button->type != type) -+ continue; -+ -+ if (only_disabled && !bdata->disabled) -+ continue; -+ -+ __set_bit(bdata->button->code, bits); -+ } -+ -+ ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events); -+ buf[ret++] = '\n'; -+ buf[ret] = '\0'; -+ -+ kfree(bits); -+ -+ return ret; -+} -+ -+/** -+ * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap -+ * @ddata: pointer to drvdata -+ * @buf: buffer from userspace that contains stringified bitmap -+ * @type: button type (%EV_KEY, %EV_SW) -+ * -+ * This function parses stringified bitmap from @buf and disables/enables -+ * GPIO buttons accordingly. Returns 0 on success and negative error -+ * on failure. -+ */ -+static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, -+ const char *buf, unsigned int type) -+{ -+ int n_events = get_n_events_by_type(type); -+ unsigned long *bits; -+ ssize_t error; -+ int i; -+ -+ bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL); -+ if (!bits) -+ return -ENOMEM; -+ -+ error = bitmap_parselist(buf, bits, n_events); -+ if (error) -+ goto out; -+ -+ /* First validate */ -+ for (i = 0; i < ddata->n_buttons; i++) { -+ struct gpio_button_data *bdata = &ddata->data[i]; -+ -+ if (bdata->button->type != type) -+ continue; -+ -+ if (test_bit(bdata->button->code, bits) && -+ !bdata->button->can_disable) { -+ error = -EINVAL; -+ goto out; -+ } -+ } -+ -+ mutex_lock(&ddata->disable_lock); -+ -+ for (i = 0; i < ddata->n_buttons; i++) { -+ struct gpio_button_data *bdata = &ddata->data[i]; -+ -+ if (bdata->button->type != type) -+ continue; -+ -+ if (test_bit(bdata->button->code, bits)) -+ gpio_keys_disable_button(bdata); -+ else -+ gpio_keys_enable_button(bdata); -+ } -+ -+ mutex_unlock(&ddata->disable_lock); -+ -+out: -+ kfree(bits); -+ return error; -+} -+ -+#define ATTR_SHOW_FN(name, type, only_disabled) \ -+static ssize_t gpio_keys_show_##name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ char *buf) \ -+{ \ -+ struct platform_device *pdev = to_platform_device(dev); \ -+ struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \ -+ \ -+ return gpio_keys_attr_show_helper(ddata, buf, \ -+ type, only_disabled); \ -+} -+ -+ATTR_SHOW_FN(keys, EV_KEY, false); -+ATTR_SHOW_FN(switches, EV_SW, false); -+ATTR_SHOW_FN(disabled_keys, EV_KEY, true); -+ATTR_SHOW_FN(disabled_switches, EV_SW, true); -+ -+/* -+ * ATTRIBUTES: -+ * -+ * /sys/devices/platform/gpio-keys/keys [ro] -+ * /sys/devices/platform/gpio-keys/switches [ro] -+ */ -+static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL); -+static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL); -+ -+#define ATTR_STORE_FN(name, type) \ -+static ssize_t gpio_keys_store_##name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, \ -+ size_t count) \ -+{ \ -+ struct platform_device *pdev = to_platform_device(dev); \ -+ struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \ -+ ssize_t error; \ -+ \ -+ error = gpio_keys_attr_store_helper(ddata, buf, type); \ -+ if (error) \ -+ return error; \ -+ \ -+ return count; \ -+} -+ -+ATTR_STORE_FN(disabled_keys, EV_KEY); -+ATTR_STORE_FN(disabled_switches, EV_SW); -+ -+/* -+ * ATTRIBUTES: -+ * -+ * /sys/devices/platform/gpio-keys/disabled_keys [rw] -+ * /sys/devices/platform/gpio-keys/disables_switches [rw] -+ */ -+static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO, -+ gpio_keys_show_disabled_keys, -+ gpio_keys_store_disabled_keys); -+static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO, -+ gpio_keys_show_disabled_switches, -+ gpio_keys_store_disabled_switches); -+ -+static struct attribute *gpio_keys_attrs[] = { -+ &dev_attr_keys.attr, -+ &dev_attr_switches.attr, -+ &dev_attr_disabled_keys.attr, -+ &dev_attr_disabled_switches.attr, -+ NULL, -+}; -+ -+static struct attribute_group gpio_keys_attr_group = { -+ .attrs = gpio_keys_attrs, -+}; -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief init gpio -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *button -+* @return fail or not -+*/ -+static int gpio_init_data(const struct gpio_keys_button *button) -+{ -+ ak_setpin_as_gpio(button->gpio); -+ ak_gpio_cfgpin(button->gpio, button->dir); -+ if (button->pullup == AK_PULLUP_ENABLE || button->pullup == AK_PULLUP_DISABLE) -+ ak_gpio_pullup(button->gpio, button->pullup); -+ if (button->pulldown == AK_PULLDOWN_ENABLE || button->pulldown == AK_PULLDOWN_DISABLE) -+ ak_gpio_pulldown(button->gpio, button->pulldown); -+ ak_gpio_intpol(button->gpio, button->int_pol); -+ -+ return 0; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief revert irq polarity -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] irq, int_pol -+* @return none -+*/ -+static void revert_irq_polarity(unsigned int irq, char int_pol) -+{ -+ ak_gpio_intpol(ak_irq_to_gpio(irq), int_pol); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief report event to user -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *bdata -+* @return none -+*/ -+static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) -+{ -+ const struct gpio_keys_button *button = bdata->button; -+ struct input_dev *input = bdata->input; -+ unsigned int type = button->type ?: EV_KEY; -+ int state = (ak_gpio_getpin(button->gpio) ? 1 : 0) ^ button->active_low; -+ -+ if (type == EV_ABS) { -+ if (state) -+ input_event(input, type, button->code, button->value); -+ } else { -+ input_event(input, type, button->code, !!state); -+ } -+ input_sync(input); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief keys work function -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *work -+* @return none -+*/ -+static void gpio_keys_gpio_work_func(struct work_struct *work) -+{ -+ struct gpio_button_data *bdata = -+ container_of(work, struct gpio_button_data, work); -+ -+ gpio_keys_gpio_report_event(bdata); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief keys timer -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] _data -+* @return none -+*/ -+static void gpio_keys_gpio_timer(unsigned long _data) -+{ -+ struct gpio_button_data *bdata = (struct gpio_button_data *)_data; -+ -+ schedule_work(&bdata->work); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief keys isr -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] int irq, void *dev_id -+* @return IRQ_HANDLED -+*/ -+static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) -+{ -+ struct gpio_button_data *bdata = dev_id; -+ const struct gpio_keys_button *button = bdata->button; -+ int gpio_level; -+ -+ BUG_ON(irq != bdata->irq); -+ -+ gpio_level = ak_gpio_getpin(button->gpio); -+ //disalbe gpio_irq when the button down -+ if ((gpio_level && button->int_pol) || (!gpio_level && !button->int_pol)) -+ revert_irq_polarity(irq, !button->int_pol); -+ -+ //enable gpiot_irq when the button up -+ if ((!gpio_level && button->int_pol) || (gpio_level && !button->int_pol)) -+ revert_irq_polarity(irq, button->int_pol); -+ -+ if (bdata->timer_debounce) -+ mod_timer(&bdata->timer, -+ jiffies + msecs_to_jiffies(bdata->timer_debounce)); -+ else -+ schedule_work(&bdata->work); -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief keys timer isr -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] _data -+* @return none -+*/ -+static void gpio_keys_irq_timer(unsigned long _data) -+{ -+ struct gpio_button_data *bdata = (struct gpio_button_data *)_data; -+ struct input_dev *input = bdata->input; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&bdata->lock, flags); -+ if (bdata->key_pressed) { -+ input_event(input, EV_KEY, bdata->button->code, 0); -+ input_sync(input); -+ bdata->key_pressed = false; -+ } -+ spin_unlock_irqrestore(&bdata->lock, flags); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief keys irq isr -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] int irq, void *dev_id -+* @return IRQ_HANDLED -+*/ -+static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) -+{ -+ struct gpio_button_data *bdata = dev_id; -+ const struct gpio_keys_button *button = bdata->button; -+ struct input_dev *input = bdata->input; -+ unsigned long flags; -+ -+ BUG_ON(irq != bdata->irq); -+ -+ spin_lock_irqsave(&bdata->lock, flags); -+ -+ if (!bdata->key_pressed) { -+ input_event(input, EV_KEY, button->code, 1); -+ input_sync(input); -+ -+ if (!bdata->timer_debounce) { -+ input_event(input, EV_KEY, button->code, 0); -+ input_sync(input); -+ goto out; -+ } -+ -+ bdata->key_pressed = true; -+ } -+ -+ if (bdata->timer_debounce) -+ mod_timer(&bdata->timer, -+ jiffies + msecs_to_jiffies(bdata->timer_debounce)); -+out: -+ spin_unlock_irqrestore(&bdata->lock, flags); -+ return IRQ_HANDLED; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief setup key -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *pdev,... -+* @return fail or not -+*/ -+static int __devinit gpio_keys_setup_key(struct platform_device *pdev, -+ struct input_dev *input, -+ struct gpio_button_data *bdata, -+ const struct gpio_keys_button *button) -+{ -+ const char *desc = button->desc ? button->desc : "gpio_keys"; -+ struct device *dev = &pdev->dev; -+ irq_handler_t isr; -+ unsigned long irqflags; -+ int irq, error; -+ -+ bdata->input = input; -+ bdata->button = button; -+ spin_lock_init(&bdata->lock); -+ -+ if (gpio_is_valid(button->gpio)) { -+ -+ error = gpio_init_data(button); -+ if (error < 0) { -+ dev_err(dev, "gpio-keys: failed to configure input" -+ " direction and pull up/down for GPIO %d, error %d\n", -+ button->gpio, error); -+ gpio_free(button->gpio); -+ goto fail; -+ } -+ -+ if (button->debounce_interval) { -+ error = gpio_set_debounce(button->gpio, -+ button->debounce_interval * 1000); -+ /* use timer if gpiolib doesn't provide debounce */ -+ if (error < 0) -+ bdata->timer_debounce = button->debounce_interval; -+ } -+ -+ irq = ak_gpio_to_irq(button->gpio); -+ if (irq < 0) { -+ error = irq; -+ dev_err(dev, -+ "Unable to get irq number for GPIO %d, error %d\n", -+ button->gpio, error); -+ goto fail; -+ } -+ bdata->irq = irq; -+ -+ INIT_WORK(&bdata->work, gpio_keys_gpio_work_func); -+ setup_timer(&bdata->timer, -+ gpio_keys_gpio_timer, (unsigned long)bdata); -+ -+ isr = gpio_keys_gpio_isr; -+ irqflags = (button->active_low)?(IRQF_TRIGGER_LOW):(IRQF_TRIGGER_HIGH); -+ -+ } else { -+ if (!button->irq) { -+ dev_err(dev, "No IRQ specified\n"); -+ return -EINVAL; -+ } -+ bdata->irq = button->irq; -+ -+ if (button->type && button->type != EV_KEY) { -+ dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n"); -+ return -EINVAL; -+ } -+ -+ bdata->timer_debounce = button->debounce_interval; -+ setup_timer(&bdata->timer, -+ gpio_keys_irq_timer, (unsigned long)bdata); -+ -+ isr = gpio_keys_irq_isr; -+ irqflags = 0; -+ } -+ -+ input_set_capability(input, button->type ?: EV_KEY, button->code); -+ -+ /* -+ * If platform has specified that the button can be disabled, -+ * we don't want it to share the interrupt line. -+ */ -+ if (!button->can_disable) -+ irqflags |= IRQF_SHARED; -+ -+ error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata); -+ if (error < 0) { -+ dev_err(dev, "Unable to claim irq %d; error %d\n", -+ bdata->irq, error); -+ goto fail; -+ } -+ -+ return 0; -+ -+fail: -+ if (gpio_is_valid(button->gpio)) -+ gpio_free(button->gpio); -+ -+ return error; -+} -+ -+static int gpio_keys_open(struct input_dev *input) -+{ -+ struct gpio_keys_drvdata *ddata = input_get_drvdata(input); -+ -+ return ddata->enable ? ddata->enable(input->dev.parent) : 0; -+} -+ -+static void gpio_keys_close(struct input_dev *input) -+{ -+ struct gpio_keys_drvdata *ddata = input_get_drvdata(input); -+ -+ if (ddata->disable) -+ ddata->disable(input->dev.parent); -+} -+ -+/* -+ * Handlers for alternative sources of platform_data -+ */ -+#ifdef CONFIG_OF -+/* -+ * Translate OpenFirmware node properties into platform_data -+ */ -+static int gpio_keys_get_devtree_pdata(struct device *dev, -+ struct akgpio_keys_platform_data *pdata) -+{ -+ struct device_node *node, *pp; -+ int i; -+ struct gpio_keys_button *buttons; -+ u32 reg; -+ -+ node = dev->of_node; -+ if (node == NULL) -+ return -ENODEV; -+ -+ memset(pdata, 0, sizeof *pdata); -+ -+ pdata->rep = !!of_get_property(node, "autorepeat", NULL); -+ -+ /* First count the subnodes */ -+ pdata->nbuttons = 0; -+ pp = NULL; -+ while ((pp = of_get_next_child(node, pp))) -+ pdata->nbuttons++; -+ -+ if (pdata->nbuttons == 0) -+ return -ENODEV; -+ -+ buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL); -+ if (!buttons) -+ return -ENOMEM; -+ -+ pp = NULL; -+ i = 0; -+ while ((pp = of_get_next_child(node, pp))) { -+ enum of_gpio_flags flags; -+ -+ if (!of_find_property(pp, "gpios", NULL)) { -+ pdata->nbuttons--; -+ dev_warn(dev, "Found button without gpios\n"); -+ continue; -+ } -+ buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags); -+ buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW; -+ -+ if (of_property_read_u32(pp, "linux,code", ®)) { -+ dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio); -+ goto out_fail; -+ } -+ buttons[i].code = reg; -+ -+ buttons[i].desc = of_get_property(pp, "label", NULL); -+ -+ if (of_property_read_u32(pp, "linux,input-type", ®) == 0) -+ buttons[i].type = reg; -+ else -+ buttons[i].type = EV_KEY; -+ -+ buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); -+ -+ if (of_property_read_u32(pp, "debounce-interval", ®) == 0) -+ buttons[i].debounce_interval = reg; -+ else -+ buttons[i].debounce_interval = 5; -+ -+ i++; -+ } -+ -+ pdata->buttons = buttons; -+ -+ return 0; -+ -+out_fail: -+ kfree(buttons); -+ return -ENODEV; -+} -+ -+static struct of_device_id gpio_keys_of_match[] = { -+ { .compatible = "gpio-keys", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, gpio_keys_of_match); -+ -+#else -+ -+static int gpio_keys_get_devtree_pdata(struct device *dev, -+ struct akgpio_keys_platform_data *altp) -+{ -+ return -ENODEV; -+} -+ -+#define gpio_keys_of_match NULL -+ -+#endif -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief gpio_remove_key -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *bdata -+* @return none -+*/ -+static void gpio_remove_key(struct gpio_button_data *bdata) -+{ -+ free_irq(bdata->irq, bdata); -+ if (bdata->timer_debounce) -+ del_timer_sync(&bdata->timer); -+ cancel_work_sync(&bdata->work); -+ if (gpio_is_valid(bdata->button->gpio)) -+ gpio_free(bdata->button->gpio); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief gpio_keys_probe -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *pdev -+* @return fail or not -+*/ -+static int __devinit gpio_keys_probe(struct platform_device *pdev) -+{ -+ const struct akgpio_keys_platform_data *pdata = pdev->dev.platform_data; -+ struct gpio_keys_drvdata *ddata; -+ struct device *dev = &pdev->dev; -+ struct akgpio_keys_platform_data alt_pdata; -+ struct input_dev *input; -+ int i, error; -+ int wakeup = 0; -+ -+ if (!pdata) { -+ error = gpio_keys_get_devtree_pdata(dev, &alt_pdata); -+ if (error) -+ return error; -+ pdata = &alt_pdata; -+ } -+ -+ ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + -+ pdata->nbuttons * sizeof(struct gpio_button_data), -+ GFP_KERNEL); -+ input = input_allocate_device(); -+ if (!ddata || !input) { -+ dev_err(dev, "failed to allocate state\n"); -+ error = -ENOMEM; -+ goto fail1; -+ } -+ -+ ddata->input = input; -+ ddata->n_buttons = pdata->nbuttons; -+ ddata->enable = pdata->enable; -+ ddata->disable = pdata->disable; -+ mutex_init(&ddata->disable_lock); -+ -+ platform_set_drvdata(pdev, ddata); -+ input_set_drvdata(input, ddata); -+ -+ input->name = pdata->name ? : pdev->name; -+ input->phys = "gpio-keys/input0"; -+ input->dev.parent = &pdev->dev; -+ input->open = gpio_keys_open; -+ input->close = gpio_keys_close; -+ -+ input->id.bustype = BUS_HOST; -+ input->id.vendor = 0x0001; -+ input->id.product = 0x0001; -+ input->id.version = 0x0100; -+ -+ /* Enable auto repeat feature of Linux input subsystem */ -+ if (pdata->rep) -+ __set_bit(EV_REP, input->evbit); -+ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ const struct gpio_keys_button *button = &pdata->buttons[i]; -+ struct gpio_button_data *bdata = &ddata->data[i]; -+ -+ error = gpio_keys_setup_key(pdev, input, bdata, button); -+ if (error) -+ goto fail2; -+ -+ if (button->wakeup) -+ wakeup = 1; -+ } -+ -+ error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); -+ if (error) { -+ dev_err(dev, "Unable to export keys/switches, error: %d\n", -+ error); -+ goto fail2; -+ } -+ -+ error = input_register_device(input); -+ if (error) { -+ dev_err(dev, "Unable to register input device, error: %d\n", -+ error); -+ goto fail3; -+ } -+ -+ /* get current state of buttons that are connected to GPIOs */ -+ for (i = 0; i < pdata->nbuttons; i++) { -+ struct gpio_button_data *bdata = &ddata->data[i]; -+ if (gpio_is_valid(bdata->button->gpio)) -+ gpio_keys_gpio_report_event(bdata); -+ } -+ input_sync(input); -+ -+ device_init_wakeup(&pdev->dev, wakeup); -+ -+ return 0; -+ -+ fail3: -+ sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); -+ fail2: -+ while (--i >= 0) -+ gpio_remove_key(&ddata->data[i]); -+ -+ platform_set_drvdata(pdev, NULL); -+ fail1: -+ input_free_device(input); -+ kfree(ddata); -+ /* If we have no platform_data, we allocated buttons dynamically. */ -+ if (!pdev->dev.platform_data) -+ kfree(pdata->buttons); -+ -+ return error; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief gpio keys remove -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *pdev -+* @return fail or not -+*/ -+static int __devexit gpio_keys_remove(struct platform_device *pdev) -+{ -+ struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); -+ struct input_dev *input = ddata->input; -+ int i; -+ -+ sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); -+ -+ device_init_wakeup(&pdev->dev, 0); -+ -+ for (i = 0; i < ddata->n_buttons; i++) -+ gpio_remove_key(&ddata->data[i]); -+ -+ input_unregister_device(input); -+ -+ /* -+ * If we had no platform_data, we allocated buttons dynamically, and -+ * must free them here. ddata->data[0].button is the pointer to the -+ * beginning of the allocated array. -+ */ -+ if (!pdev->dev.platform_data) -+ kfree(ddata->data[0].button); -+ -+ kfree(ddata); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+/** -+* @Copyright (C) Anyka 2012 -+* @brief gpio_keys_suspend -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *dev -+* @return 0 -+*/ -+static int gpio_keys_suspend(struct device *dev) -+{ -+ struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); -+ int i; -+ -+ if (device_may_wakeup(dev)) { -+ for (i = 0; i < ddata->n_buttons; i++) { -+ struct gpio_button_data *bdata = &ddata->data[i]; -+ if (bdata->button->wakeup) -+ enable_irq_wake(bdata->irq); -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief gpio_keys_resume -+* @date 2013-5-14 -+* @param[out] void -+* @param[in] *dev -+* @return 0 -+*/ -+static int gpio_keys_resume(struct device *dev) -+{ -+ struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); -+ int i; -+ -+ for (i = 0; i < ddata->n_buttons; i++) { -+ struct gpio_button_data *bdata = &ddata->data[i]; -+ if (bdata->button->wakeup && device_may_wakeup(dev)) -+ disable_irq_wake(bdata->irq); -+ -+ if (gpio_is_valid(bdata->button->gpio)) -+ gpio_keys_gpio_report_event(bdata); -+ } -+ input_sync(ddata->input); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); -+ -+static struct platform_driver gpio_keys_device_driver = { -+ .probe = gpio_keys_probe, -+ .remove = __devexit_p(gpio_keys_remove), -+ .driver = { -+ .name = "akgpio-keys", -+ .owner = THIS_MODULE, -+ .pm = &gpio_keys_pm_ops, -+ .of_match_table = gpio_keys_of_match, -+ } -+}; -+ -+static int __init gpio_keys_init(void) -+{ -+ return platform_driver_register(&gpio_keys_device_driver); -+} -+ -+static void __exit gpio_keys_exit(void) -+{ -+ platform_driver_unregister(&gpio_keys_device_driver); -+} -+ -+module_init(gpio_keys_init); -+module_exit(gpio_keys_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>"); -+MODULE_DESCRIPTION("Keyboard driver for GPIOs"); -+MODULE_ALIAS("platform:gpio-keys"); -diff --git a/drivers/input/keyboard/akmatrix_keypad.c b/drivers/input/keyboard/akmatrix_keypad.c -new file mode 100755 -index 00000000..2978f8d7 ---- /dev/null -+++ b/drivers/input/keyboard/akmatrix_keypad.c -@@ -0,0 +1,708 @@ -+/** -+* @file ak_matrix_keypad.c -+* @brief GPIO driven matrix keyboard driver -+* Copyright C 2011 Anyka CO.,LTD -+* Based on matrix_keypad.c -+* -+* This program is free software; you can redistribute it and/or modify -+* it under the terms of the GNU General Public License version 2 as -+* published by the Free Software Foundation. -+* -+* @author zhou wenyong -+* @date 2011-08-05 -+* @note 2010-12-24 created by cao_lianming -+* @note 2011-06-25 integrate and optimize matrix keypad driver -- -+* only one copy code exists now. we use the same code whether -+* or not keypad is connected aw9523, whether or not there is a -+* grounding line. -+* @note 2011-06-27 fix a bug imported from previous version, which is that -+* driver can not work properly if there is grounding line in 3X3 -+* or 4X4 matrix keypad -+* @note 2011-07-08 fix the issue of incorrect responsing to long press -+* of menu key -+* -+* Notes: if the comments look like inaesthetic, try to press -+* Alt+F12(source insight) -+*/ -+ -+#include <linux/types.h> -+#include <linux/delay.h> -+#include <linux/platform_device.h> -+#include <linux/init.h> -+#include <linux/input.h> -+#include <linux/irq.h> -+#include <linux/interrupt.h> -+#include <linux/jiffies.h> -+#include <linux/module.h> -+#include <linux/gpio.h> -+#include <linux/input/akmatrix_keypad.h> -+#include <mach/gpio.h> -+#include <linux/slab.h> -+ -+/* -+ structure used to present the keypad -+*/ -+struct matrix_keypad { -+ struct matrix_keypad_platform_data *pdata; -+ struct input_dev *input_dev; -+ unsigned short *keycodes; -+ unsigned int row_shift; -+ -+ uint32_t last_key_state[MATRIX_MAX_COLS]; -+ struct delayed_work work; -+ bool scan_pending; -+ bool stopped; -+ spinlock_t lock; -+ bool start_close_int; -+}; -+ -+/** -+* @brief get the value of gpio (this function may sleep) -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] gpio -+* @return int -+*/ -+static inline int ak_gpio_get_value_cansleep(unsigned gpio) -+{ -+ might_sleep(); -+ return ak_gpio_getpin(gpio); -+} -+/** -+* @brief set the value of gpio (this function may sleep) -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] gpio -+* @param[in] value -+* @return void -+*/ -+static inline void ak_gpio_set_value_cansleep(unsigned gpio, int value) -+{ -+ might_sleep(); -+ ak_gpio_setpin(gpio, value); -+} -+ -+/** -+* @brief called by activate_other_col (refer to it) -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdata -+* @param[in] col -+* @param[in] on -+* @return void -+*/ -+static void __activate_col(const struct matrix_keypad_platform_data *pdata, -+ int col, bool on) -+{ -+ bool level_on = pdata->active_low; -+ int i; -+ -+ for (i=0; i<pdata->num_col_gpios;i++) -+ { -+ if (i == col) -+ continue; -+ if (on) -+ { -+ ak_gpio_setpin(pdata->col_gpios[i], level_on); -+ } -+ else -+ { -+ ak_gpio_setpin(pdata->col_gpios[i], !level_on); -+ } -+ } -+} -+ -+/** -+* @brief activate other colums -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdata -+* @param[in] col -- the column excluded -+* @param[in] on -+* @return void -+*/ -+static void activate_other_col(const struct matrix_keypad_platform_data *pdata, -+ int col, bool on) -+{ -+ __activate_col(pdata, col, on); -+ -+ if (on && pdata->col_scan_delay_us) -+ udelay(pdata->col_scan_delay_us); -+} -+ -+/** -+* @brief get the value of gpio (can sleep) -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdata -+* @param[in] row -+* @return bool -+*/ -+static bool row_asserted(const struct matrix_keypad_platform_data *pdata, -+ int row) -+{ -+ return ak_gpio_get_value_cansleep(pdata->row_gpios[row]) ? -+ !pdata->active_low : pdata->active_low; -+} -+ -+/** -+* @brief enable_row_irqs -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *keypad -+* @return void -+*/ -+static void enable_row_irqs(struct matrix_keypad *keypad) -+{ -+ const struct matrix_keypad_platform_data *pdata = keypad->pdata; -+ int i; -+ -+ -+ for (i = 0; i < pdata->num_row_gpios; i++) -+ enable_irq(ak_gpio_to_irq(pdata->row_gpios[i])); -+} -+ -+/** -+* @brief disable_row_irqs -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *keypad -+* @return void -+*/ -+static void disable_row_irqs(struct matrix_keypad *keypad) -+{ -+ const struct matrix_keypad_platform_data *pdata = keypad->pdata; -+ int i; -+ -+ -+ for (i = 0; i < pdata->num_row_gpios; i++) -+ disable_irq_nosync(ak_gpio_to_irq(pdata->row_gpios[i])); -+} -+ -+/** -+* @brief print the CODE of button pressed -- for debugging -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] code -+* @param[in] state -+* @return void -+*/ -+static void print_code(int code, int state) -+{ -+ switch(code) -+ { -+ case KEY_VOLUMEUP: -+ printk("KEY_VOLUMEUP "); break; -+ case KEY_RIGHT: -+ printk("KEY_RIGHT "); break; -+ case KEY_MENU: -+ printk("KEY_MENU "); break; -+ case KEY_UP: -+ printk("KEY_UP "); break; -+ case KEY_REPLY: -+ printk("KEY_CENTER "); break; -+ case KEY_DOWN: -+ printk("KEY_DOWN "); break; -+ case KEY_VOLUMEDOWN: -+ printk("KEY_VOLUMEDOWN "); break; -+ case KEY_LEFT: -+ printk("KEY_LEFT "); break; -+ case KEY_HOME: -+ printk("KEY_HOME "); break; -+ case KEY_BACK: -+ printk("KEY_BACK "); break; -+ } -+ printk("%s \n", state?"Down":"Up"); -+ -+ -+} -+ -+EXPORT_SYMBOL(print_code); -+ -+/** -+* @brief This gets the keys from keyboard and reports it to input -+* subsystem -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[out] *work -+* @return void -+*/ -+static void matrix_keypad_scan(struct work_struct *work) -+{ -+ struct matrix_keypad *keypad = -+ container_of(work, struct matrix_keypad, work.work); -+ struct input_dev *input_dev = keypad->input_dev; -+ const struct matrix_keypad_platform_data *pdata = keypad->pdata; -+ uint32_t new_state[MATRIX_MAX_COLS]; -+ int row, col, code, num_cols; -+ -+ memset(new_state, 0, sizeof(new_state)); -+ -+ -+ num_cols = pdata->num_col_gpios; -+ if (pdata->grounding) -+ num_cols++; -+ for (col = 0; col < num_cols; col++) -+ { -+ activate_other_col(pdata, col, true); -+ for (row = 0; row < pdata->num_row_gpios; row++) -+ { -+ new_state[col] |= -+ row_asserted(pdata, row) ? (1 << row) : 0; -+ -+ } -+ -+ activate_other_col(pdata, col, false); -+ } -+ -+ /* -+ * if the button pressed is connected to the grounding line, the state of -+ * the row input line connected to the button pressed will keep low level -+ * when we activate other lines -+ */ -+ if (pdata->grounding) -+ { -+ for (row=0; row < pdata->num_row_gpios; row++) -+ { -+ for (col=0; col<num_cols; col++) -+ if ( !(new_state[col]&(1<<row))) -+ break; -+ if (col == num_cols) -+ { -+ //grounding line at the end -+ for (col=0; col<num_cols-1; col++) -+ { -+ new_state[col] = new_state[col] & (~(1<<row)); -+ } -+ } -+ } -+ -+ } -+ /* update input status, needed if keypad is connected to AW9523 */ -+ ak_gpio_getpin(pdata->row_gpios[0]); -+ -+ num_cols = pdata->num_col_gpios; -+ if (pdata->grounding) -+ num_cols++; -+ for (col = 0; col < num_cols; col++) { -+ uint32_t bits_changed; -+ -+ bits_changed = (keypad->last_key_state[col] ^ new_state[col]); -+ -+ -+ if (bits_changed == 0) -+ continue; -+ -+ for (row = 0; row < pdata->num_row_gpios; row++) { -+ if ((bits_changed & (1 << row)) == 0) -+ continue; -+ -+ code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); -+ input_event(input_dev, EV_MSC, MSC_SCAN, code); -+ input_report_key(input_dev, -+ keypad->keycodes[code], -+ new_state[col] & (1 << row)); -+ //print_code(keypad->keycodes[code], new_state[col] & (1 << row)); -+ } -+ } -+ input_sync(input_dev); -+ -+ memcpy(keypad->last_key_state, new_state, sizeof(new_state)); -+ -+ -+ /* Enable IRQs again */ -+ spin_lock_irq(&keypad->lock); -+ keypad->scan_pending = false; -+ enable_row_irqs(keypad); -+ spin_unlock_irq(&keypad->lock); -+} -+ -+/** -+* @brief matrix keypad interrupt routine -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] irq -+* @param[out] *id -+* @return irqreturn_t -+*/ -+static irqreturn_t matrix_keypad_interrupt(int irq, void *id) -+{ -+ struct matrix_keypad *keypad = id; -+ unsigned long flags; -+ -+ -+ spin_lock_irqsave(&keypad->lock, flags); -+ -+ /* -+ * See if another IRQ beaten us to it and scheduled the -+ * scan already. In that case we should not try to -+ * disable IRQs again. -+ */ -+ if (unlikely(keypad->scan_pending || keypad->stopped)) -+ goto out; -+ -+ disable_row_irqs(keypad); -+ keypad->scan_pending = true; -+ schedule_delayed_work(&keypad->work, -+ msecs_to_jiffies(keypad->pdata->debounce_ms)); -+ -+out: -+ /* -+ * if disable_row_irqs(keypad); in init_matrix_gpio is not reached, then -+ * we need excuting it here. otherwise system can not start successfully if -+ * one key is pressed on OS starts. -+ */ -+ if (!keypad->start_close_int) -+ { -+ disable_row_irqs(keypad); -+ keypad->start_close_int = true; -+ } -+ spin_unlock_irqrestore(&keypad->lock, flags); -+ return IRQ_HANDLED; -+} -+ -+/** -+* @brief start the keypad -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *dev -+* @return int -+*/ -+static int matrix_keypad_start(struct input_dev *dev) -+{ -+ struct matrix_keypad *keypad = input_get_drvdata(dev); -+ -+ keypad->stopped = false; -+ mb(); -+ -+ /* -+ * Schedule an immediate key scan to capture current key state; -+ * columns will be activated and IRQs be enabled after the scan. -+ */ -+ schedule_delayed_work(&keypad->work, 0); -+ -+ return 0; -+} -+ -+/** -+* @brief stop the keypad -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[out] *dev -+* @return void -+*/ -+static void matrix_keypad_stop(struct input_dev *dev) -+{ -+ struct matrix_keypad *keypad = input_get_drvdata(dev); -+ -+ keypad->stopped = true; -+ mb(); -+ flush_work(&keypad->work.work); -+ /* -+ * matrix_keypad_scan() will leave IRQs enabled; -+ * we should disable them now. -+ */ -+ disable_row_irqs(keypad); -+} -+ -+#ifdef CONFIG_PM -+/** -+* @brief matrix_keypad_suspend -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdev -+* @param[in] state -+* @return int -+*/ -+static int matrix_keypad_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ struct matrix_keypad *keypad = platform_get_drvdata(pdev); -+ const struct matrix_keypad_platform_data *pdata = keypad->pdata; -+ int i; -+ -+ matrix_keypad_stop(keypad->input_dev); -+ -+ if (device_may_wakeup(&pdev->dev)) -+ for (i = 0; i < pdata->num_row_gpios; i++) -+ enable_irq_wake(ak_gpio_to_irq(pdata->row_gpios[i])); -+ -+ return 0; -+} -+ -+/** -+* @brief matrix_keypad_resume -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdev -+* @return int -+*/ -+static int matrix_keypad_resume(struct platform_device *pdev) -+{ -+ struct matrix_keypad *keypad = platform_get_drvdata(pdev); -+ const struct matrix_keypad_platform_data *pdata = keypad->pdata; -+ int i; -+ -+ if (device_may_wakeup(&pdev->dev)) -+ for (i = 0; i < pdata->num_row_gpios; i++) -+ disable_irq_wake(ak_gpio_to_irq(pdata->row_gpios[i])); -+ -+ matrix_keypad_start(keypad->input_dev); -+ -+ return 0; -+} -+#else -+#define matrix_keypad_suspend NULL -+#define matrix_keypad_resume NULL -+#endif -+ -+/** -+* @brief init_matrix_gpio -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdev -+* @param[in] *keypad -+* @return int __devinit -+*/ -+static int __devinit init_matrix_gpio(struct platform_device *pdev, -+ struct matrix_keypad *keypad) -+{ -+ struct matrix_keypad_platform_data *pdata = keypad->pdata; -+ int i, err = -(EINVAL); -+ unsigned long flags; -+ -+ /* to fix the bug: can not start OS if one key is pressed on OS starts */ -+ keypad->start_close_int = false; -+ /* initialized strobe lines as outputs, activated */ -+ for (i = 0; i < pdata->num_col_gpios; i++) { -+ -+ err = ak_gpio_request(pdata->col_gpios[i], "matrix_kbd_col"); -+ if (err) { -+ dev_err(&pdev->dev, -+ "failed to request GPIO%d for COL%d\n", -+ pdata->col_gpios[i], i); -+ goto err_free_cols; -+ } -+ pdata->col_gpios_cfginfo.pin = pdata->col_gpios[i]; -+ ak_gpio_set(&(pdata->col_gpios_cfginfo)); -+ -+ } -+ -+ for (i = 0; i < pdata->num_row_gpios; i++) { -+ -+ err = ak_gpio_request(pdata->row_gpios[i], "matrix_kbd_row"); -+ if (err) { -+ dev_err(&pdev->dev, -+ "failed to request GPIO%d for ROW%d\n", -+ pdata->row_gpios[i], i); -+ goto err_free_rows; -+ } -+ pdata->row_gpios_cfginfo.pin = pdata->row_gpios[i]; -+ ak_gpio_set(&(pdata->row_gpios_cfginfo)); -+ ak_gpio_intcfg(pdata->row_gpios[i], AK_GPIO_INT_ENABLE); -+ } -+ -+ -+ for (i = 0; i < pdata->num_row_gpios; i++) { -+ err = request_irq(ak_gpio_to_irq(pdata->row_gpios[i]), -+ matrix_keypad_interrupt, -+ IRQF_DISABLED, -+ "matrix-keypad", keypad); -+ if (err) { -+ dev_err(&pdev->dev, -+ "Unable to acquire interrupt for GPIO line %i\n", -+ pdata->row_gpios[i]); -+ goto err_free_irqs; -+ } -+ } -+ -+ /* update input status, needed if keypad is connected to AW9523 */ -+ ak_gpio_getpin(pdata->row_gpios[0]); -+ -+ spin_lock_irqsave(&keypad->lock, flags); -+ /* initialized as disabled - enabled by input->open */ -+ if (!keypad->start_close_int) -+ { -+ disable_row_irqs(keypad); -+ keypad->start_close_int = true; -+ } -+ spin_unlock_irqrestore(&keypad->lock, flags); -+ return 0; -+ -+err_free_irqs: -+ while (--i >= 0) -+ free_irq(ak_gpio_to_irq(pdata->row_gpios[i]), keypad); -+ i = pdata->num_row_gpios; -+err_free_rows: -+ while (--i >= 0) -+ ak_gpio_free(pdata->row_gpios[i]); -+ i = pdata->num_col_gpios; -+err_free_cols: -+ while (--i >= 0) -+ ak_gpio_free(pdata->col_gpios[i]); -+ -+ return err; -+} -+ -+/** -+* @brief matrix_keypad_probe -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdev -+* @return int __devinit -+*/ -+static int __devinit matrix_keypad_probe(struct platform_device *pdev) -+{ -+ struct matrix_keypad_platform_data *pdata; -+ const struct matrix_keymap_data *keymap_data; -+ struct matrix_keypad *keypad; -+ struct input_dev *input_dev; -+ unsigned short *keycodes; -+ unsigned int row_shift; -+ int err; -+ -+ pdata = pdev->dev.platform_data; -+ if (!pdata) { -+ dev_err(&pdev->dev, "no platform data defined\n"); -+ return -EINVAL; -+ } -+ -+ keymap_data = pdata->keymap_data; -+ if (!keymap_data) { -+ dev_err(&pdev->dev, "no keymap data defined\n"); -+ return -EINVAL; -+ } -+ -+ row_shift = get_count_order(pdata->num_col_gpios); -+ if (pdata->grounding) -+ row_shift++; -+ -+ keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); -+ keycodes = kzalloc((pdata->num_row_gpios << (row_shift)) * -+ sizeof(*keycodes), -+ GFP_KERNEL); -+ input_dev = input_allocate_device(); -+ if (!keypad || !keycodes || !input_dev) { -+ err = -ENOMEM; -+ goto err_free_mem; -+ } -+ -+ keypad->input_dev = input_dev; -+ keypad->pdata = pdata; -+ keypad->keycodes = keycodes; -+ -+ keypad->row_shift = row_shift; -+ keypad->stopped = true; -+ INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); -+ spin_lock_init(&keypad->lock); -+ -+ input_dev->name = pdev->name; -+ input_dev->id.bustype = BUS_HOST; -+ input_dev->dev.parent = &pdev->dev; -+ input_dev->evbit[0] = BIT_MASK(EV_KEY);// | BIT_MASK(EV_REP); -+ input_dev->open = matrix_keypad_start; -+ input_dev->close = matrix_keypad_stop; -+ -+ input_dev->keycode = keycodes; -+ input_dev->keycodesize = sizeof(*keycodes); -+ input_dev->keycodemax = pdata->num_row_gpios << (row_shift); -+ -+ matrix_keypad_build_keymap(keymap_data, row_shift, -+ input_dev->keycode, input_dev->keybit); -+ -+ input_set_capability(input_dev, EV_MSC, MSC_SCAN); -+ input_set_drvdata(input_dev, keypad); -+ -+ err = init_matrix_gpio(pdev, keypad); -+ if (err) -+ goto err_free_mem; -+ -+ err = input_register_device(keypad->input_dev); -+ if (err) -+ goto err_free_mem; -+ -+ device_init_wakeup(&pdev->dev, pdata->wakeup); -+ platform_set_drvdata(pdev, keypad); -+ -+ return 0; -+ -+err_free_mem: -+ input_free_device(input_dev); -+ kfree(keycodes); -+ kfree(keypad); -+ return err; -+} -+ -+/** -+* @brief called when the device is removed -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] *pdev -+* @return int __devexit -+*/ -+static int __devexit matrix_keypad_remove(struct platform_device *pdev) -+{ -+ struct matrix_keypad *keypad = platform_get_drvdata(pdev); -+ const struct matrix_keypad_platform_data *pdata = keypad->pdata; -+ int i; -+ -+ device_init_wakeup(&pdev->dev, 0); -+ -+ for (i = 0; i < pdata->num_row_gpios; i++) { -+ free_irq(ak_gpio_to_irq(pdata->row_gpios[i]), keypad); -+ ak_gpio_free(pdata->row_gpios[i]); -+ } -+ -+ for (i = 0; i < pdata->num_col_gpios; i++) -+ ak_gpio_free(pdata->col_gpios[i]); -+ -+ input_unregister_device(keypad->input_dev); -+ platform_set_drvdata(pdev, NULL); -+ kfree(keypad->keycodes); -+ kfree(keypad); -+ -+ return 0; -+} -+ -+static struct platform_driver matrix_keypad_driver = { -+ .probe = matrix_keypad_probe, -+ .remove = __devexit_p(matrix_keypad_remove), -+ .suspend = matrix_keypad_suspend, -+ .resume = matrix_keypad_resume, -+ .driver = { -+ .name = "matrix-keypad", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+/** -+* @brief matrix_keypad_init -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] void -+* @return int __init -+*/ -+static int __init matrix_keypad_init(void) -+{ -+ return platform_driver_register(&matrix_keypad_driver); -+} -+ -+/** -+* @brief matrix_keypad_exit -+* @author zhou wenyong -+* @date 2011-08-05 -+* @param[in] void -+* @return void __exit -+*/ -+static void __exit matrix_keypad_exit(void) -+{ -+ platform_driver_unregister(&matrix_keypad_driver); -+} -+ -+module_init(matrix_keypad_init); -+module_exit(matrix_keypad_exit); -+ -+MODULE_AUTHOR("Anyka <xxx@anyka.oa>"); -+MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:matrix-keypad"); -+ -diff --git a/drivers/input/keyreset.c b/drivers/input/keyreset.c -new file mode 100644 -index 00000000..36208fe0 ---- /dev/null -+++ b/drivers/input/keyreset.c -@@ -0,0 +1,239 @@ -+/* drivers/input/keyreset.c -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/input.h> -+#include <linux/keyreset.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/reboot.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/syscalls.h> -+ -+ -+struct keyreset_state { -+ struct input_handler input_handler; -+ unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; -+ unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; -+ unsigned long key[BITS_TO_LONGS(KEY_CNT)]; -+ spinlock_t lock; -+ int key_down_target; -+ int key_down; -+ int key_up; -+ int restart_disabled; -+ int (*reset_fn)(void); -+}; -+ -+int restart_requested; -+static void deferred_restart(struct work_struct *dummy) -+{ -+ restart_requested = 2; -+ sys_sync(); -+ restart_requested = 3; -+ kernel_restart(NULL); -+} -+static DECLARE_WORK(restart_work, deferred_restart); -+ -+static void keyreset_event(struct input_handle *handle, unsigned int type, -+ unsigned int code, int value) -+{ -+ unsigned long flags; -+ struct keyreset_state *state = handle->private; -+ -+ if (type != EV_KEY) -+ return; -+ -+ if (code >= KEY_MAX) -+ return; -+ -+ if (!test_bit(code, state->keybit)) -+ return; -+ -+ spin_lock_irqsave(&state->lock, flags); -+ if (!test_bit(code, state->key) == !value) -+ goto done; -+ __change_bit(code, state->key); -+ if (test_bit(code, state->upbit)) { -+ if (value) { -+ state->restart_disabled = 1; -+ state->key_up++; -+ } else -+ state->key_up--; -+ } else { -+ if (value) -+ state->key_down++; -+ else -+ state->key_down--; -+ } -+ if (state->key_down == 0 && state->key_up == 0) -+ state->restart_disabled = 0; -+ -+ pr_debug("reset key changed %d %d new state %d-%d-%d\n", code, value, -+ state->key_down, state->key_up, state->restart_disabled); -+ -+ if (value && !state->restart_disabled && -+ state->key_down == state->key_down_target) { -+ state->restart_disabled = 1; -+ if (restart_requested) -+ panic("keyboard reset failed, %d", restart_requested); -+ if (state->reset_fn) { -+ restart_requested = state->reset_fn(); -+ } else { -+ pr_info("keyboard reset\n"); -+ schedule_work(&restart_work); -+ restart_requested = 1; -+ } -+ } -+done: -+ spin_unlock_irqrestore(&state->lock, flags); -+} -+ -+static int keyreset_connect(struct input_handler *handler, -+ struct input_dev *dev, -+ const struct input_device_id *id) -+{ -+ int i; -+ int ret; -+ struct input_handle *handle; -+ struct keyreset_state *state = -+ container_of(handler, struct keyreset_state, input_handler); -+ -+ for (i = 0; i < KEY_MAX; i++) { -+ if (test_bit(i, state->keybit) && test_bit(i, dev->keybit)) -+ break; -+ } -+ if (i == KEY_MAX) -+ return -ENODEV; -+ -+ handle = kzalloc(sizeof(*handle), GFP_KERNEL); -+ if (!handle) -+ return -ENOMEM; -+ -+ handle->dev = dev; -+ handle->handler = handler; -+ handle->name = "keyreset"; -+ handle->private = state; -+ -+ ret = input_register_handle(handle); -+ if (ret) -+ goto err_input_register_handle; -+ -+ ret = input_open_device(handle); -+ if (ret) -+ goto err_input_open_device; -+ -+ pr_info("using input dev %s for key reset\n", dev->name); -+ -+ return 0; -+ -+err_input_open_device: -+ input_unregister_handle(handle); -+err_input_register_handle: -+ kfree(handle); -+ return ret; -+} -+ -+static void keyreset_disconnect(struct input_handle *handle) -+{ -+ input_close_device(handle); -+ input_unregister_handle(handle); -+ kfree(handle); -+} -+ -+static const struct input_device_id keyreset_ids[] = { -+ { -+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT, -+ .evbit = { BIT_MASK(EV_KEY) }, -+ }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(input, keyreset_ids); -+ -+static int keyreset_probe(struct platform_device *pdev) -+{ -+ int ret; -+ int key, *keyp; -+ struct keyreset_state *state; -+ struct keyreset_platform_data *pdata = pdev->dev.platform_data; -+ -+ if (!pdata) -+ return -EINVAL; -+ -+ state = kzalloc(sizeof(*state), GFP_KERNEL); -+ if (!state) -+ return -ENOMEM; -+ -+ spin_lock_init(&state->lock); -+ keyp = pdata->keys_down; -+ while ((key = *keyp++)) { -+ if (key >= KEY_MAX) -+ continue; -+ state->key_down_target++; -+ __set_bit(key, state->keybit); -+ } -+ if (pdata->keys_up) { -+ keyp = pdata->keys_up; -+ while ((key = *keyp++)) { -+ if (key >= KEY_MAX) -+ continue; -+ __set_bit(key, state->keybit); -+ __set_bit(key, state->upbit); -+ } -+ } -+ -+ if (pdata->reset_fn) -+ state->reset_fn = pdata->reset_fn; -+ -+ state->input_handler.event = keyreset_event; -+ state->input_handler.connect = keyreset_connect; -+ state->input_handler.disconnect = keyreset_disconnect; -+ state->input_handler.name = KEYRESET_NAME; -+ state->input_handler.id_table = keyreset_ids; -+ ret = input_register_handler(&state->input_handler); -+ if (ret) { -+ kfree(state); -+ return ret; -+ } -+ platform_set_drvdata(pdev, state); -+ return 0; -+} -+ -+int keyreset_remove(struct platform_device *pdev) -+{ -+ struct keyreset_state *state = platform_get_drvdata(pdev); -+ input_unregister_handler(&state->input_handler); -+ kfree(state); -+ return 0; -+} -+ -+ -+struct platform_driver keyreset_driver = { -+ .driver.name = KEYRESET_NAME, -+ .probe = keyreset_probe, -+ .remove = keyreset_remove, -+}; -+ -+static int __init keyreset_init(void) -+{ -+ return platform_driver_register(&keyreset_driver); -+} -+ -+static void __exit keyreset_exit(void) -+{ -+ return platform_driver_unregister(&keyreset_driver); -+} -+ -+module_init(keyreset_init); -+module_exit(keyreset_exit); -diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig -index 7faf4a7f..66550c2b 100644 ---- a/drivers/input/misc/Kconfig -+++ b/drivers/input/misc/Kconfig -@@ -279,6 +279,17 @@ config INPUT_ATI_REMOTE2 - To compile this driver as a module, choose M here: the module will be - called ati_remote2. - -+config INPUT_KEYCHORD -+ tristate "Key chord input driver support" -+ help -+ Say Y here if you want to enable the key chord driver -+ accessible at /dev/keychord. This driver can be used -+ for receiving notifications when client specified key -+ combinations are pressed. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called keychord. -+ - config INPUT_KEYSPAN_REMOTE - tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" - depends on EXPERIMENTAL -@@ -407,6 +418,11 @@ config INPUT_SGI_BTNS - To compile this driver as a module, choose M here: the - module will be called sgi_btns. - -+config INPUT_GPIO -+ tristate "GPIO driver support" -+ help -+ Say Y here if you want to support gpio based keys, wheels etc... -+ - config HP_SDC_RTC - tristate "HP SDC Real Time Clock" - depends on (GSC || HP300) && SERIO -diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile -index f55cdf49..f8cb5221 100644 ---- a/drivers/input/misc/Makefile -+++ b/drivers/input/misc/Makefile -@@ -25,8 +25,10 @@ obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o - obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o - obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o - obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o -+obj-$(CONFIG_INPUT_GPIO) += gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o - obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o - obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o -+obj-$(CONFIG_INPUT_KEYCHORD) += keychord.o - obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o - obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o - obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o -diff --git a/drivers/input/misc/gpio_axis.c b/drivers/input/misc/gpio_axis.c -new file mode 100644 -index 00000000..0acf4a57 ---- /dev/null -+++ b/drivers/input/misc/gpio_axis.c -@@ -0,0 +1,192 @@ -+/* drivers/input/misc/gpio_axis.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/gpio.h> -+#include <linux/gpio_event.h> -+#include <linux/interrupt.h> -+#include <linux/slab.h> -+ -+struct gpio_axis_state { -+ struct gpio_event_input_devs *input_devs; -+ struct gpio_event_axis_info *info; -+ uint32_t pos; -+}; -+ -+uint16_t gpio_axis_4bit_gray_map_table[] = { -+ [0x0] = 0x0, [0x1] = 0x1, /* 0000 0001 */ -+ [0x3] = 0x2, [0x2] = 0x3, /* 0011 0010 */ -+ [0x6] = 0x4, [0x7] = 0x5, /* 0110 0111 */ -+ [0x5] = 0x6, [0x4] = 0x7, /* 0101 0100 */ -+ [0xc] = 0x8, [0xd] = 0x9, /* 1100 1101 */ -+ [0xf] = 0xa, [0xe] = 0xb, /* 1111 1110 */ -+ [0xa] = 0xc, [0xb] = 0xd, /* 1010 1011 */ -+ [0x9] = 0xe, [0x8] = 0xf, /* 1001 1000 */ -+}; -+uint16_t gpio_axis_4bit_gray_map(struct gpio_event_axis_info *info, uint16_t in) -+{ -+ return gpio_axis_4bit_gray_map_table[in]; -+} -+ -+uint16_t gpio_axis_5bit_singletrack_map_table[] = { -+ [0x10] = 0x00, [0x14] = 0x01, [0x1c] = 0x02, /* 10000 10100 11100 */ -+ [0x1e] = 0x03, [0x1a] = 0x04, [0x18] = 0x05, /* 11110 11010 11000 */ -+ [0x08] = 0x06, [0x0a] = 0x07, [0x0e] = 0x08, /* 01000 01010 01110 */ -+ [0x0f] = 0x09, [0x0d] = 0x0a, [0x0c] = 0x0b, /* 01111 01101 01100 */ -+ [0x04] = 0x0c, [0x05] = 0x0d, [0x07] = 0x0e, /* 00100 00101 00111 */ -+ [0x17] = 0x0f, [0x16] = 0x10, [0x06] = 0x11, /* 10111 10110 00110 */ -+ [0x02] = 0x12, [0x12] = 0x13, [0x13] = 0x14, /* 00010 10010 10011 */ -+ [0x1b] = 0x15, [0x0b] = 0x16, [0x03] = 0x17, /* 11011 01011 00011 */ -+ [0x01] = 0x18, [0x09] = 0x19, [0x19] = 0x1a, /* 00001 01001 11001 */ -+ [0x1d] = 0x1b, [0x15] = 0x1c, [0x11] = 0x1d, /* 11101 10101 10001 */ -+}; -+uint16_t gpio_axis_5bit_singletrack_map( -+ struct gpio_event_axis_info *info, uint16_t in) -+{ -+ return gpio_axis_5bit_singletrack_map_table[in]; -+} -+ -+static void gpio_event_update_axis(struct gpio_axis_state *as, int report) -+{ -+ struct gpio_event_axis_info *ai = as->info; -+ int i; -+ int change; -+ uint16_t state = 0; -+ uint16_t pos; -+ uint16_t old_pos = as->pos; -+ for (i = ai->count - 1; i >= 0; i--) -+ state = (state << 1) | gpio_get_value(ai->gpio[i]); -+ pos = ai->map(ai, state); -+ if (ai->flags & GPIOEAF_PRINT_RAW) -+ pr_info("axis %d-%d raw %x, pos %d -> %d\n", -+ ai->type, ai->code, state, old_pos, pos); -+ if (report && pos != old_pos) { -+ if (ai->type == EV_REL) { -+ change = (ai->decoded_size + pos - old_pos) % -+ ai->decoded_size; -+ if (change > ai->decoded_size / 2) -+ change -= ai->decoded_size; -+ if (change == ai->decoded_size / 2) { -+ if (ai->flags & GPIOEAF_PRINT_EVENT) -+ pr_info("axis %d-%d unknown direction, " -+ "pos %d -> %d\n", ai->type, -+ ai->code, old_pos, pos); -+ change = 0; /* no closest direction */ -+ } -+ if (ai->flags & GPIOEAF_PRINT_EVENT) -+ pr_info("axis %d-%d change %d\n", -+ ai->type, ai->code, change); -+ input_report_rel(as->input_devs->dev[ai->dev], -+ ai->code, change); -+ } else { -+ if (ai->flags & GPIOEAF_PRINT_EVENT) -+ pr_info("axis %d-%d now %d\n", -+ ai->type, ai->code, pos); -+ input_event(as->input_devs->dev[ai->dev], -+ ai->type, ai->code, pos); -+ } -+ input_sync(as->input_devs->dev[ai->dev]); -+ } -+ as->pos = pos; -+} -+ -+static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id) -+{ -+ struct gpio_axis_state *as = dev_id; -+ gpio_event_update_axis(as, 1); -+ return IRQ_HANDLED; -+} -+ -+int gpio_event_axis_func(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, int func) -+{ -+ int ret; -+ int i; -+ int irq; -+ struct gpio_event_axis_info *ai; -+ struct gpio_axis_state *as; -+ -+ ai = container_of(info, struct gpio_event_axis_info, info); -+ if (func == GPIO_EVENT_FUNC_SUSPEND) { -+ for (i = 0; i < ai->count; i++) -+ disable_irq(gpio_to_irq(ai->gpio[i])); -+ return 0; -+ } -+ if (func == GPIO_EVENT_FUNC_RESUME) { -+ for (i = 0; i < ai->count; i++) -+ enable_irq(gpio_to_irq(ai->gpio[i])); -+ return 0; -+ } -+ -+ if (func == GPIO_EVENT_FUNC_INIT) { -+ *data = as = kmalloc(sizeof(*as), GFP_KERNEL); -+ if (as == NULL) { -+ ret = -ENOMEM; -+ goto err_alloc_axis_state_failed; -+ } -+ as->input_devs = input_devs; -+ as->info = ai; -+ if (ai->dev >= input_devs->count) { -+ pr_err("gpio_event_axis: bad device index %d >= %d " -+ "for %d:%d\n", ai->dev, input_devs->count, -+ ai->type, ai->code); -+ ret = -EINVAL; -+ goto err_bad_device_index; -+ } -+ -+ input_set_capability(input_devs->dev[ai->dev], -+ ai->type, ai->code); -+ if (ai->type == EV_ABS) { -+ input_set_abs_params(input_devs->dev[ai->dev], ai->code, -+ 0, ai->decoded_size - 1, 0, 0); -+ } -+ for (i = 0; i < ai->count; i++) { -+ ret = gpio_request(ai->gpio[i], "gpio_event_axis"); -+ if (ret < 0) -+ goto err_request_gpio_failed; -+ ret = gpio_direction_input(ai->gpio[i]); -+ if (ret < 0) -+ goto err_gpio_direction_input_failed; -+ ret = irq = gpio_to_irq(ai->gpio[i]); -+ if (ret < 0) -+ goto err_get_irq_num_failed; -+ ret = request_irq(irq, gpio_axis_irq_handler, -+ IRQF_TRIGGER_RISING | -+ IRQF_TRIGGER_FALLING, -+ "gpio_event_axis", as); -+ if (ret < 0) -+ goto err_request_irq_failed; -+ } -+ gpio_event_update_axis(as, 0); -+ return 0; -+ } -+ -+ ret = 0; -+ as = *data; -+ for (i = ai->count - 1; i >= 0; i--) { -+ free_irq(gpio_to_irq(ai->gpio[i]), as); -+err_request_irq_failed: -+err_get_irq_num_failed: -+err_gpio_direction_input_failed: -+ gpio_free(ai->gpio[i]); -+err_request_gpio_failed: -+ ; -+ } -+err_bad_device_index: -+ kfree(as); -+ *data = NULL; -+err_alloc_axis_state_failed: -+ return ret; -+} -diff --git a/drivers/input/misc/gpio_event.c b/drivers/input/misc/gpio_event.c -new file mode 100644 -index 00000000..c7f396ab ---- /dev/null -+++ b/drivers/input/misc/gpio_event.c -@@ -0,0 +1,239 @@ -+/* drivers/input/misc/gpio_event.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/input.h> -+#include <linux/gpio_event.h> -+#include <linux/hrtimer.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+ -+struct gpio_event { -+ struct gpio_event_input_devs *input_devs; -+ const struct gpio_event_platform_data *info; -+ void *state[0]; -+}; -+ -+static int gpio_input_event( -+ struct input_dev *dev, unsigned int type, unsigned int code, int value) -+{ -+ int i; -+ int devnr; -+ int ret = 0; -+ int tmp_ret; -+ struct gpio_event_info **ii; -+ struct gpio_event *ip = input_get_drvdata(dev); -+ -+ for (devnr = 0; devnr < ip->input_devs->count; devnr++) -+ if (ip->input_devs->dev[devnr] == dev) -+ break; -+ if (devnr == ip->input_devs->count) { -+ pr_err("gpio_input_event: unknown device %p\n", dev); -+ return -EIO; -+ } -+ -+ for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) { -+ if ((*ii)->event) { -+ tmp_ret = (*ii)->event(ip->input_devs, *ii, -+ &ip->state[i], -+ devnr, type, code, value); -+ if (tmp_ret) -+ ret = tmp_ret; -+ } -+ } -+ return ret; -+} -+ -+static int gpio_event_call_all_func(struct gpio_event *ip, int func) -+{ -+ int i; -+ int ret; -+ struct gpio_event_info **ii; -+ -+ if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) { -+ ii = ip->info->info; -+ for (i = 0; i < ip->info->info_count; i++, ii++) { -+ if ((*ii)->func == NULL) { -+ ret = -ENODEV; -+ pr_err("gpio_event_probe: Incomplete pdata, " -+ "no function\n"); -+ goto err_no_func; -+ } -+ if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend) -+ continue; -+ ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i], -+ func); -+ if (ret) { -+ pr_err("gpio_event_probe: function failed\n"); -+ goto err_func_failed; -+ } -+ } -+ return 0; -+ } -+ -+ ret = 0; -+ i = ip->info->info_count; -+ ii = ip->info->info + i; -+ while (i > 0) { -+ i--; -+ ii--; -+ if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend) -+ continue; -+ (*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1); -+err_func_failed: -+err_no_func: -+ ; -+ } -+ return ret; -+} -+ -+static void __maybe_unused gpio_event_suspend(struct gpio_event *ip) -+{ -+ gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND); -+ if (ip->info->power) -+ ip->info->power(ip->info, 0); -+} -+ -+static void __maybe_unused gpio_event_resume(struct gpio_event *ip) -+{ -+ if (ip->info->power) -+ ip->info->power(ip->info, 1); -+ gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME); -+} -+ -+static int gpio_event_probe(struct platform_device *pdev) -+{ -+ int err; -+ struct gpio_event *ip; -+ struct gpio_event_platform_data *event_info; -+ int dev_count = 1; -+ int i; -+ int registered = 0; -+ -+ event_info = pdev->dev.platform_data; -+ if (event_info == NULL) { -+ pr_err("gpio_event_probe: No pdata\n"); -+ return -ENODEV; -+ } -+ if ((!event_info->name && !event_info->names[0]) || -+ !event_info->info || !event_info->info_count) { -+ pr_err("gpio_event_probe: Incomplete pdata\n"); -+ return -ENODEV; -+ } -+ if (!event_info->name) -+ while (event_info->names[dev_count]) -+ dev_count++; -+ ip = kzalloc(sizeof(*ip) + -+ sizeof(ip->state[0]) * event_info->info_count + -+ sizeof(*ip->input_devs) + -+ sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL); -+ if (ip == NULL) { -+ err = -ENOMEM; -+ pr_err("gpio_event_probe: Failed to allocate private data\n"); -+ goto err_kp_alloc_failed; -+ } -+ ip->input_devs = (void*)&ip->state[event_info->info_count]; -+ platform_set_drvdata(pdev, ip); -+ -+ for (i = 0; i < dev_count; i++) { -+ struct input_dev *input_dev = input_allocate_device(); -+ if (input_dev == NULL) { -+ err = -ENOMEM; -+ pr_err("gpio_event_probe: " -+ "Failed to allocate input device\n"); -+ goto err_input_dev_alloc_failed; -+ } -+ input_set_drvdata(input_dev, ip); -+ input_dev->name = event_info->name ? -+ event_info->name : event_info->names[i]; -+ input_dev->event = gpio_input_event; -+ ip->input_devs->dev[i] = input_dev; -+ } -+ ip->input_devs->count = dev_count; -+ ip->info = event_info; -+ if (event_info->power) -+ ip->info->power(ip->info, 1); -+ -+ err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT); -+ if (err) -+ goto err_call_all_func_failed; -+ -+ for (i = 0; i < dev_count; i++) { -+ err = input_register_device(ip->input_devs->dev[i]); -+ if (err) { -+ pr_err("gpio_event_probe: Unable to register %s " -+ "input device\n", ip->input_devs->dev[i]->name); -+ goto err_input_register_device_failed; -+ } -+ registered++; -+ } -+ -+ return 0; -+ -+err_input_register_device_failed: -+ gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); -+err_call_all_func_failed: -+ if (event_info->power) -+ ip->info->power(ip->info, 0); -+ for (i = 0; i < registered; i++) -+ input_unregister_device(ip->input_devs->dev[i]); -+ for (i = dev_count - 1; i >= registered; i--) { -+ input_free_device(ip->input_devs->dev[i]); -+err_input_dev_alloc_failed: -+ ; -+ } -+ kfree(ip); -+err_kp_alloc_failed: -+ return err; -+} -+ -+static int gpio_event_remove(struct platform_device *pdev) -+{ -+ struct gpio_event *ip = platform_get_drvdata(pdev); -+ int i; -+ -+ gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); -+ if (ip->info->power) -+ ip->info->power(ip->info, 0); -+ for (i = 0; i < ip->input_devs->count; i++) -+ input_unregister_device(ip->input_devs->dev[i]); -+ kfree(ip); -+ return 0; -+} -+ -+static struct platform_driver gpio_event_driver = { -+ .probe = gpio_event_probe, -+ .remove = gpio_event_remove, -+ .driver = { -+ .name = GPIO_EVENT_DEV_NAME, -+ }, -+}; -+ -+static int __devinit gpio_event_init(void) -+{ -+ return platform_driver_register(&gpio_event_driver); -+} -+ -+static void __exit gpio_event_exit(void) -+{ -+ platform_driver_unregister(&gpio_event_driver); -+} -+ -+module_init(gpio_event_init); -+module_exit(gpio_event_exit); -+ -+MODULE_DESCRIPTION("GPIO Event Driver"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c -new file mode 100644 -index 00000000..eefd0272 ---- /dev/null -+++ b/drivers/input/misc/gpio_input.c -@@ -0,0 +1,390 @@ -+/* drivers/input/misc/gpio_input.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/gpio.h> -+#include <linux/gpio_event.h> -+#include <linux/hrtimer.h> -+#include <linux/input.h> -+#include <linux/interrupt.h> -+#include <linux/slab.h> -+#include <linux/pm_wakeup.h> -+ -+enum { -+ DEBOUNCE_UNSTABLE = BIT(0), /* Got irq, while debouncing */ -+ DEBOUNCE_PRESSED = BIT(1), -+ DEBOUNCE_NOTPRESSED = BIT(2), -+ DEBOUNCE_WAIT_IRQ = BIT(3), /* Stable irq state */ -+ DEBOUNCE_POLL = BIT(4), /* Stable polling state */ -+ -+ DEBOUNCE_UNKNOWN = -+ DEBOUNCE_PRESSED | DEBOUNCE_NOTPRESSED, -+}; -+ -+struct gpio_key_state { -+ struct gpio_input_state *ds; -+ uint8_t debounce; -+}; -+ -+struct gpio_input_state { -+ struct gpio_event_input_devs *input_devs; -+ const struct gpio_event_input_info *info; -+ struct hrtimer timer; -+ int use_irq; -+ int debounce_count; -+ spinlock_t irq_lock; -+ struct wakeup_source *ws; -+ struct gpio_key_state key_state[0]; -+}; -+ -+static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer) -+{ -+ int i; -+ int pressed; -+ struct gpio_input_state *ds = -+ container_of(timer, struct gpio_input_state, timer); -+ unsigned gpio_flags = ds->info->flags; -+ unsigned npolarity; -+ int nkeys = ds->info->keymap_size; -+ const struct gpio_event_direct_entry *key_entry; -+ struct gpio_key_state *key_state; -+ unsigned long irqflags; -+ uint8_t debounce; -+ bool sync_needed; -+ -+#if 0 -+ key_entry = kp->keys_info->keymap; -+ key_state = kp->key_state; -+ for (i = 0; i < nkeys; i++, key_entry++, key_state++) -+ pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, -+ gpio_read_detect_status(key_entry->gpio)); -+#endif -+ key_entry = ds->info->keymap; -+ key_state = ds->key_state; -+ sync_needed = false; -+ spin_lock_irqsave(&ds->irq_lock, irqflags); -+ for (i = 0; i < nkeys; i++, key_entry++, key_state++) { -+ debounce = key_state->debounce; -+ if (debounce & DEBOUNCE_WAIT_IRQ) -+ continue; -+ if (key_state->debounce & DEBOUNCE_UNSTABLE) { -+ debounce = key_state->debounce = DEBOUNCE_UNKNOWN; -+ enable_irq(gpio_to_irq(key_entry->gpio)); -+ if (gpio_flags & GPIOEDF_PRINT_KEY_UNSTABLE) -+ pr_info("gpio_keys_scan_keys: key %x-%x, %d " -+ "(%d) continue debounce\n", -+ ds->info->type, key_entry->code, -+ i, key_entry->gpio); -+ } -+ npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); -+ pressed = gpio_get_value(key_entry->gpio) ^ npolarity; -+ if (debounce & DEBOUNCE_POLL) { -+ if (pressed == !(debounce & DEBOUNCE_PRESSED)) { -+ ds->debounce_count++; -+ key_state->debounce = DEBOUNCE_UNKNOWN; -+ if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) -+ pr_info("gpio_keys_scan_keys: key %x-" -+ "%x, %d (%d) start debounce\n", -+ ds->info->type, key_entry->code, -+ i, key_entry->gpio); -+ } -+ continue; -+ } -+ if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) { -+ if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) -+ pr_info("gpio_keys_scan_keys: key %x-%x, %d " -+ "(%d) debounce pressed 1\n", -+ ds->info->type, key_entry->code, -+ i, key_entry->gpio); -+ key_state->debounce = DEBOUNCE_PRESSED; -+ continue; -+ } -+ if (!pressed && (debounce & DEBOUNCE_PRESSED)) { -+ if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) -+ pr_info("gpio_keys_scan_keys: key %x-%x, %d " -+ "(%d) debounce pressed 0\n", -+ ds->info->type, key_entry->code, -+ i, key_entry->gpio); -+ key_state->debounce = DEBOUNCE_NOTPRESSED; -+ continue; -+ } -+ /* key is stable */ -+ ds->debounce_count--; -+ if (ds->use_irq) -+ key_state->debounce |= DEBOUNCE_WAIT_IRQ; -+ else -+ key_state->debounce |= DEBOUNCE_POLL; -+ if (gpio_flags & GPIOEDF_PRINT_KEYS) -+ pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) " -+ "changed to %d\n", ds->info->type, -+ key_entry->code, i, key_entry->gpio, pressed); -+ input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, -+ key_entry->code, pressed); -+ sync_needed = true; -+ } -+ if (sync_needed) { -+ for (i = 0; i < ds->input_devs->count; i++) -+ input_sync(ds->input_devs->dev[i]); -+ } -+ -+#if 0 -+ key_entry = kp->keys_info->keymap; -+ key_state = kp->key_state; -+ for (i = 0; i < nkeys; i++, key_entry++, key_state++) { -+ pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, -+ gpio_read_detect_status(key_entry->gpio)); -+ } -+#endif -+ -+ if (ds->debounce_count) -+ hrtimer_start(timer, ds->info->debounce_time, HRTIMER_MODE_REL); -+ else if (!ds->use_irq) -+ hrtimer_start(timer, ds->info->poll_time, HRTIMER_MODE_REL); -+ else -+ __pm_relax(ds->ws); -+ -+ spin_unlock_irqrestore(&ds->irq_lock, irqflags); -+ -+ return HRTIMER_NORESTART; -+} -+ -+static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id) -+{ -+ struct gpio_key_state *ks = dev_id; -+ struct gpio_input_state *ds = ks->ds; -+ int keymap_index = ks - ds->key_state; -+ const struct gpio_event_direct_entry *key_entry; -+ unsigned long irqflags; -+ int pressed; -+ -+ if (!ds->use_irq) -+ return IRQ_HANDLED; -+ -+ key_entry = &ds->info->keymap[keymap_index]; -+ -+ if (ds->info->debounce_time.tv64) { -+ spin_lock_irqsave(&ds->irq_lock, irqflags); -+ if (ks->debounce & DEBOUNCE_WAIT_IRQ) { -+ ks->debounce = DEBOUNCE_UNKNOWN; -+ if (ds->debounce_count++ == 0) { -+ __pm_stay_awake(ds->ws); -+ hrtimer_start( -+ &ds->timer, ds->info->debounce_time, -+ HRTIMER_MODE_REL); -+ } -+ if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE) -+ pr_info("gpio_event_input_irq_handler: " -+ "key %x-%x, %d (%d) start debounce\n", -+ ds->info->type, key_entry->code, -+ keymap_index, key_entry->gpio); -+ } else { -+ disable_irq_nosync(irq); -+ ks->debounce = DEBOUNCE_UNSTABLE; -+ } -+ spin_unlock_irqrestore(&ds->irq_lock, irqflags); -+ } else { -+ pressed = gpio_get_value(key_entry->gpio) ^ -+ !(ds->info->flags & GPIOEDF_ACTIVE_HIGH); -+ if (ds->info->flags & GPIOEDF_PRINT_KEYS) -+ pr_info("gpio_event_input_irq_handler: key %x-%x, %d " -+ "(%d) changed to %d\n", -+ ds->info->type, key_entry->code, keymap_index, -+ key_entry->gpio, pressed); -+ input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, -+ key_entry->code, pressed); -+ input_sync(ds->input_devs->dev[key_entry->dev]); -+ } -+ return IRQ_HANDLED; -+} -+ -+static int gpio_event_input_request_irqs(struct gpio_input_state *ds) -+{ -+ int i; -+ int err; -+ unsigned int irq; -+ unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; -+ -+ for (i = 0; i < ds->info->keymap_size; i++) { -+ err = irq = gpio_to_irq(ds->info->keymap[i].gpio); -+ if (err < 0) -+ goto err_gpio_get_irq_num_failed; -+ err = request_irq(irq, gpio_event_input_irq_handler, -+ req_flags, "gpio_keys", &ds->key_state[i]); -+ if (err) { -+ pr_err("gpio_event_input_request_irqs: request_irq " -+ "failed for input %d, irq %d\n", -+ ds->info->keymap[i].gpio, irq); -+ goto err_request_irq_failed; -+ } -+ if (ds->info->info.no_suspend) { -+ err = enable_irq_wake(irq); -+ if (err) { -+ pr_err("gpio_event_input_request_irqs: " -+ "enable_irq_wake failed for input %d, " -+ "irq %d\n", -+ ds->info->keymap[i].gpio, irq); -+ goto err_enable_irq_wake_failed; -+ } -+ } -+ } -+ return 0; -+ -+ for (i = ds->info->keymap_size - 1; i >= 0; i--) { -+ irq = gpio_to_irq(ds->info->keymap[i].gpio); -+ if (ds->info->info.no_suspend) -+ disable_irq_wake(irq); -+err_enable_irq_wake_failed: -+ free_irq(irq, &ds->key_state[i]); -+err_request_irq_failed: -+err_gpio_get_irq_num_failed: -+ ; -+ } -+ return err; -+} -+ -+int gpio_event_input_func(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, int func) -+{ -+ int ret; -+ int i; -+ unsigned long irqflags; -+ struct gpio_event_input_info *di; -+ struct gpio_input_state *ds = *data; -+ char *wlname; -+ -+ di = container_of(info, struct gpio_event_input_info, info); -+ -+ if (func == GPIO_EVENT_FUNC_SUSPEND) { -+ if (ds->use_irq) -+ for (i = 0; i < di->keymap_size; i++) -+ disable_irq(gpio_to_irq(di->keymap[i].gpio)); -+ hrtimer_cancel(&ds->timer); -+ return 0; -+ } -+ if (func == GPIO_EVENT_FUNC_RESUME) { -+ spin_lock_irqsave(&ds->irq_lock, irqflags); -+ if (ds->use_irq) -+ for (i = 0; i < di->keymap_size; i++) -+ enable_irq(gpio_to_irq(di->keymap[i].gpio)); -+ hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); -+ spin_unlock_irqrestore(&ds->irq_lock, irqflags); -+ return 0; -+ } -+ -+ if (func == GPIO_EVENT_FUNC_INIT) { -+ if (ktime_to_ns(di->poll_time) <= 0) -+ di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC); -+ -+ *data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) * -+ di->keymap_size, GFP_KERNEL); -+ if (ds == NULL) { -+ ret = -ENOMEM; -+ pr_err("gpio_event_input_func: " -+ "Failed to allocate private data\n"); -+ goto err_ds_alloc_failed; -+ } -+ ds->debounce_count = di->keymap_size; -+ ds->input_devs = input_devs; -+ ds->info = di; -+ wlname = kasprintf(GFP_KERNEL, "gpio_input:%s%s", -+ input_devs->dev[0]->name, -+ (input_devs->count > 1) ? "..." : ""); -+ -+ ds->ws = wakeup_source_register(wlname); -+ kfree(wlname); -+ if (!ds->ws) { -+ ret = -ENOMEM; -+ pr_err("gpio_event_input_func: " -+ "Failed to allocate wakeup source\n"); -+ goto err_ws_failed; -+ } -+ -+ spin_lock_init(&ds->irq_lock); -+ -+ for (i = 0; i < di->keymap_size; i++) { -+ int dev = di->keymap[i].dev; -+ if (dev >= input_devs->count) { -+ pr_err("gpio_event_input_func: bad device " -+ "index %d >= %d for key code %d\n", -+ dev, input_devs->count, -+ di->keymap[i].code); -+ ret = -EINVAL; -+ goto err_bad_keymap; -+ } -+ input_set_capability(input_devs->dev[dev], di->type, -+ di->keymap[i].code); -+ ds->key_state[i].ds = ds; -+ ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; -+ } -+ -+ for (i = 0; i < di->keymap_size; i++) { -+ ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in"); -+ if (ret) { -+ pr_err("gpio_event_input_func: gpio_request " -+ "failed for %d\n", di->keymap[i].gpio); -+ goto err_gpio_request_failed; -+ } -+ ret = gpio_direction_input(di->keymap[i].gpio); -+ if (ret) { -+ pr_err("gpio_event_input_func: " -+ "gpio_direction_input failed for %d\n", -+ di->keymap[i].gpio); -+ goto err_gpio_configure_failed; -+ } -+ } -+ -+ ret = gpio_event_input_request_irqs(ds); -+ -+ spin_lock_irqsave(&ds->irq_lock, irqflags); -+ ds->use_irq = ret == 0; -+ -+ pr_info("GPIO Input Driver: Start gpio inputs for %s%s in %s " -+ "mode\n", input_devs->dev[0]->name, -+ (input_devs->count > 1) ? "..." : "", -+ ret == 0 ? "interrupt" : "polling"); -+ -+ hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ ds->timer.function = gpio_event_input_timer_func; -+ hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); -+ spin_unlock_irqrestore(&ds->irq_lock, irqflags); -+ return 0; -+ } -+ -+ ret = 0; -+ spin_lock_irqsave(&ds->irq_lock, irqflags); -+ hrtimer_cancel(&ds->timer); -+ if (ds->use_irq) { -+ for (i = di->keymap_size - 1; i >= 0; i--) { -+ int irq = gpio_to_irq(di->keymap[i].gpio); -+ if (ds->info->info.no_suspend) -+ disable_irq_wake(irq); -+ free_irq(irq, &ds->key_state[i]); -+ } -+ } -+ spin_unlock_irqrestore(&ds->irq_lock, irqflags); -+ -+ for (i = di->keymap_size - 1; i >= 0; i--) { -+err_gpio_configure_failed: -+ gpio_free(di->keymap[i].gpio); -+err_gpio_request_failed: -+ ; -+ } -+err_bad_keymap: -+ wakeup_source_unregister(ds->ws); -+err_ws_failed: -+ kfree(ds); -+err_ds_alloc_failed: -+ return ret; -+} -diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c -new file mode 100644 -index 00000000..eaa9e89d ---- /dev/null -+++ b/drivers/input/misc/gpio_matrix.c -@@ -0,0 +1,441 @@ -+/* drivers/input/misc/gpio_matrix.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/gpio.h> -+#include <linux/gpio_event.h> -+#include <linux/hrtimer.h> -+#include <linux/interrupt.h> -+#include <linux/slab.h> -+#include <linux/wakelock.h> -+ -+struct gpio_kp { -+ struct gpio_event_input_devs *input_devs; -+ struct gpio_event_matrix_info *keypad_info; -+ struct hrtimer timer; -+ struct wake_lock wake_lock; -+ int current_output; -+ unsigned int use_irq:1; -+ unsigned int key_state_changed:1; -+ unsigned int last_key_state_changed:1; -+ unsigned int some_keys_pressed:2; -+ unsigned int disabled_irq:1; -+ unsigned long keys_pressed[0]; -+}; -+ -+static void clear_phantom_key(struct gpio_kp *kp, int out, int in) -+{ -+ struct gpio_event_matrix_info *mi = kp->keypad_info; -+ int key_index = out * mi->ninputs + in; -+ unsigned short keyentry = mi->keymap[key_index]; -+ unsigned short keycode = keyentry & MATRIX_KEY_MASK; -+ unsigned short dev = keyentry >> MATRIX_CODE_BITS; -+ -+ if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) { -+ if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) -+ pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " -+ "cleared\n", keycode, out, in, -+ mi->output_gpios[out], mi->input_gpios[in]); -+ __clear_bit(key_index, kp->keys_pressed); -+ } else { -+ if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) -+ pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " -+ "not cleared\n", keycode, out, in, -+ mi->output_gpios[out], mi->input_gpios[in]); -+ } -+} -+ -+static int restore_keys_for_input(struct gpio_kp *kp, int out, int in) -+{ -+ int rv = 0; -+ int key_index; -+ -+ key_index = out * kp->keypad_info->ninputs + in; -+ while (out < kp->keypad_info->noutputs) { -+ if (test_bit(key_index, kp->keys_pressed)) { -+ rv = 1; -+ clear_phantom_key(kp, out, in); -+ } -+ key_index += kp->keypad_info->ninputs; -+ out++; -+ } -+ return rv; -+} -+ -+static void remove_phantom_keys(struct gpio_kp *kp) -+{ -+ int out, in, inp; -+ int key_index; -+ -+ if (kp->some_keys_pressed < 3) -+ return; -+ -+ for (out = 0; out < kp->keypad_info->noutputs; out++) { -+ inp = -1; -+ key_index = out * kp->keypad_info->ninputs; -+ for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) { -+ if (test_bit(key_index, kp->keys_pressed)) { -+ if (inp == -1) { -+ inp = in; -+ continue; -+ } -+ if (inp >= 0) { -+ if (!restore_keys_for_input(kp, out + 1, -+ inp)) -+ break; -+ clear_phantom_key(kp, out, inp); -+ inp = -2; -+ } -+ restore_keys_for_input(kp, out, in); -+ } -+ } -+ } -+} -+ -+static void report_key(struct gpio_kp *kp, int key_index, int out, int in) -+{ -+ struct gpio_event_matrix_info *mi = kp->keypad_info; -+ int pressed = test_bit(key_index, kp->keys_pressed); -+ unsigned short keyentry = mi->keymap[key_index]; -+ unsigned short keycode = keyentry & MATRIX_KEY_MASK; -+ unsigned short dev = keyentry >> MATRIX_CODE_BITS; -+ -+ if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) { -+ if (keycode == KEY_RESERVED) { -+ if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) -+ pr_info("gpiomatrix: unmapped key, %d-%d " -+ "(%d-%d) changed to %d\n", -+ out, in, mi->output_gpios[out], -+ mi->input_gpios[in], pressed); -+ } else { -+ if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS) -+ pr_info("gpiomatrix: key %x, %d-%d (%d-%d) " -+ "changed to %d\n", keycode, -+ out, in, mi->output_gpios[out], -+ mi->input_gpios[in], pressed); -+ input_report_key(kp->input_devs->dev[dev], keycode, pressed); -+ } -+ } -+} -+ -+static void report_sync(struct gpio_kp *kp) -+{ -+ int i; -+ -+ for (i = 0; i < kp->input_devs->count; i++) -+ input_sync(kp->input_devs->dev[i]); -+} -+ -+static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer) -+{ -+ int out, in; -+ int key_index; -+ int gpio; -+ struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer); -+ struct gpio_event_matrix_info *mi = kp->keypad_info; -+ unsigned gpio_keypad_flags = mi->flags; -+ unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH); -+ -+ out = kp->current_output; -+ if (out == mi->noutputs) { -+ out = 0; -+ kp->last_key_state_changed = kp->key_state_changed; -+ kp->key_state_changed = 0; -+ kp->some_keys_pressed = 0; -+ } else { -+ key_index = out * mi->ninputs; -+ for (in = 0; in < mi->ninputs; in++, key_index++) { -+ gpio = mi->input_gpios[in]; -+ if (gpio_get_value(gpio) ^ !polarity) { -+ if (kp->some_keys_pressed < 3) -+ kp->some_keys_pressed++; -+ kp->key_state_changed |= !__test_and_set_bit( -+ key_index, kp->keys_pressed); -+ } else -+ kp->key_state_changed |= __test_and_clear_bit( -+ key_index, kp->keys_pressed); -+ } -+ gpio = mi->output_gpios[out]; -+ if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) -+ gpio_set_value(gpio, !polarity); -+ else -+ gpio_direction_input(gpio); -+ out++; -+ } -+ kp->current_output = out; -+ if (out < mi->noutputs) { -+ gpio = mi->output_gpios[out]; -+ if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) -+ gpio_set_value(gpio, polarity); -+ else -+ gpio_direction_output(gpio, polarity); -+ hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL); -+ return HRTIMER_NORESTART; -+ } -+ if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) { -+ if (kp->key_state_changed) { -+ hrtimer_start(&kp->timer, mi->debounce_delay, -+ HRTIMER_MODE_REL); -+ return HRTIMER_NORESTART; -+ } -+ kp->key_state_changed = kp->last_key_state_changed; -+ } -+ if (kp->key_state_changed) { -+ if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS) -+ remove_phantom_keys(kp); -+ key_index = 0; -+ for (out = 0; out < mi->noutputs; out++) -+ for (in = 0; in < mi->ninputs; in++, key_index++) -+ report_key(kp, key_index, out, in); -+ report_sync(kp); -+ } -+ if (!kp->use_irq || kp->some_keys_pressed) { -+ hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL); -+ return HRTIMER_NORESTART; -+ } -+ -+ /* No keys are pressed, reenable interrupt */ -+ for (out = 0; out < mi->noutputs; out++) { -+ if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) -+ gpio_set_value(mi->output_gpios[out], polarity); -+ else -+ gpio_direction_output(mi->output_gpios[out], polarity); -+ } -+ for (in = 0; in < mi->ninputs; in++) -+ enable_irq(gpio_to_irq(mi->input_gpios[in])); -+ wake_unlock(&kp->wake_lock); -+ return HRTIMER_NORESTART; -+} -+ -+static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id) -+{ -+ int i; -+ struct gpio_kp *kp = dev_id; -+ struct gpio_event_matrix_info *mi = kp->keypad_info; -+ unsigned gpio_keypad_flags = mi->flags; -+ -+ if (!kp->use_irq) { -+ /* ignore interrupt while registering the handler */ -+ kp->disabled_irq = 1; -+ disable_irq_nosync(irq_in); -+ return IRQ_HANDLED; -+ } -+ -+ for (i = 0; i < mi->ninputs; i++) -+ disable_irq_nosync(gpio_to_irq(mi->input_gpios[i])); -+ for (i = 0; i < mi->noutputs; i++) { -+ if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) -+ gpio_set_value(mi->output_gpios[i], -+ !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH)); -+ else -+ gpio_direction_input(mi->output_gpios[i]); -+ } -+ wake_lock(&kp->wake_lock); -+ hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); -+ return IRQ_HANDLED; -+} -+ -+static int gpio_keypad_request_irqs(struct gpio_kp *kp) -+{ -+ int i; -+ int err; -+ unsigned int irq; -+ unsigned long request_flags; -+ struct gpio_event_matrix_info *mi = kp->keypad_info; -+ -+ switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) { -+ default: -+ request_flags = IRQF_TRIGGER_FALLING; -+ break; -+ case GPIOKPF_ACTIVE_HIGH: -+ request_flags = IRQF_TRIGGER_RISING; -+ break; -+ case GPIOKPF_LEVEL_TRIGGERED_IRQ: -+ request_flags = IRQF_TRIGGER_LOW; -+ break; -+ case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH: -+ request_flags = IRQF_TRIGGER_HIGH; -+ break; -+ } -+ -+ for (i = 0; i < mi->ninputs; i++) { -+ err = irq = gpio_to_irq(mi->input_gpios[i]); -+ if (err < 0) -+ goto err_gpio_get_irq_num_failed; -+ err = request_irq(irq, gpio_keypad_irq_handler, request_flags, -+ "gpio_kp", kp); -+ if (err) { -+ pr_err("gpiomatrix: request_irq failed for input %d, " -+ "irq %d\n", mi->input_gpios[i], irq); -+ goto err_request_irq_failed; -+ } -+ err = enable_irq_wake(irq); -+ if (err) { -+ pr_err("gpiomatrix: set_irq_wake failed for input %d, " -+ "irq %d\n", mi->input_gpios[i], irq); -+ } -+ disable_irq(irq); -+ if (kp->disabled_irq) { -+ kp->disabled_irq = 0; -+ enable_irq(irq); -+ } -+ } -+ return 0; -+ -+ for (i = mi->noutputs - 1; i >= 0; i--) { -+ free_irq(gpio_to_irq(mi->input_gpios[i]), kp); -+err_request_irq_failed: -+err_gpio_get_irq_num_failed: -+ ; -+ } -+ return err; -+} -+ -+int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, int func) -+{ -+ int i; -+ int err; -+ int key_count; -+ struct gpio_kp *kp; -+ struct gpio_event_matrix_info *mi; -+ -+ mi = container_of(info, struct gpio_event_matrix_info, info); -+ if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) { -+ /* TODO: disable scanning */ -+ return 0; -+ } -+ -+ if (func == GPIO_EVENT_FUNC_INIT) { -+ if (mi->keymap == NULL || -+ mi->input_gpios == NULL || -+ mi->output_gpios == NULL) { -+ err = -ENODEV; -+ pr_err("gpiomatrix: Incomplete pdata\n"); -+ goto err_invalid_platform_data; -+ } -+ key_count = mi->ninputs * mi->noutputs; -+ -+ *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) * -+ BITS_TO_LONGS(key_count), GFP_KERNEL); -+ if (kp == NULL) { -+ err = -ENOMEM; -+ pr_err("gpiomatrix: Failed to allocate private data\n"); -+ goto err_kp_alloc_failed; -+ } -+ kp->input_devs = input_devs; -+ kp->keypad_info = mi; -+ for (i = 0; i < key_count; i++) { -+ unsigned short keyentry = mi->keymap[i]; -+ unsigned short keycode = keyentry & MATRIX_KEY_MASK; -+ unsigned short dev = keyentry >> MATRIX_CODE_BITS; -+ if (dev >= input_devs->count) { -+ pr_err("gpiomatrix: bad device index %d >= " -+ "%d for key code %d\n", -+ dev, input_devs->count, keycode); -+ err = -EINVAL; -+ goto err_bad_keymap; -+ } -+ if (keycode && keycode <= KEY_MAX) -+ input_set_capability(input_devs->dev[dev], -+ EV_KEY, keycode); -+ } -+ -+ for (i = 0; i < mi->noutputs; i++) { -+ err = gpio_request(mi->output_gpios[i], "gpio_kp_out"); -+ if (err) { -+ pr_err("gpiomatrix: gpio_request failed for " -+ "output %d\n", mi->output_gpios[i]); -+ goto err_request_output_gpio_failed; -+ } -+ if (gpio_cansleep(mi->output_gpios[i])) { -+ pr_err("gpiomatrix: unsupported output gpio %d," -+ " can sleep\n", mi->output_gpios[i]); -+ err = -EINVAL; -+ goto err_output_gpio_configure_failed; -+ } -+ if (mi->flags & GPIOKPF_DRIVE_INACTIVE) -+ err = gpio_direction_output(mi->output_gpios[i], -+ !(mi->flags & GPIOKPF_ACTIVE_HIGH)); -+ else -+ err = gpio_direction_input(mi->output_gpios[i]); -+ if (err) { -+ pr_err("gpiomatrix: gpio_configure failed for " -+ "output %d\n", mi->output_gpios[i]); -+ goto err_output_gpio_configure_failed; -+ } -+ } -+ for (i = 0; i < mi->ninputs; i++) { -+ err = gpio_request(mi->input_gpios[i], "gpio_kp_in"); -+ if (err) { -+ pr_err("gpiomatrix: gpio_request failed for " -+ "input %d\n", mi->input_gpios[i]); -+ goto err_request_input_gpio_failed; -+ } -+ err = gpio_direction_input(mi->input_gpios[i]); -+ if (err) { -+ pr_err("gpiomatrix: gpio_direction_input failed" -+ " for input %d\n", mi->input_gpios[i]); -+ goto err_gpio_direction_input_failed; -+ } -+ } -+ kp->current_output = mi->noutputs; -+ kp->key_state_changed = 1; -+ -+ hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ kp->timer.function = gpio_keypad_timer_func; -+ wake_lock_init(&kp->wake_lock, WAKE_LOCK_SUSPEND, "gpio_kp"); -+ err = gpio_keypad_request_irqs(kp); -+ kp->use_irq = err == 0; -+ -+ pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for " -+ "%s%s in %s mode\n", input_devs->dev[0]->name, -+ (input_devs->count > 1) ? "..." : "", -+ kp->use_irq ? "interrupt" : "polling"); -+ -+ if (kp->use_irq) -+ wake_lock(&kp->wake_lock); -+ hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); -+ -+ return 0; -+ } -+ -+ err = 0; -+ kp = *data; -+ -+ if (kp->use_irq) -+ for (i = mi->noutputs - 1; i >= 0; i--) -+ free_irq(gpio_to_irq(mi->input_gpios[i]), kp); -+ -+ hrtimer_cancel(&kp->timer); -+ wake_lock_destroy(&kp->wake_lock); -+ for (i = mi->noutputs - 1; i >= 0; i--) { -+err_gpio_direction_input_failed: -+ gpio_free(mi->input_gpios[i]); -+err_request_input_gpio_failed: -+ ; -+ } -+ for (i = mi->noutputs - 1; i >= 0; i--) { -+err_output_gpio_configure_failed: -+ gpio_free(mi->output_gpios[i]); -+err_request_output_gpio_failed: -+ ; -+ } -+err_bad_keymap: -+ kfree(kp); -+err_kp_alloc_failed: -+err_invalid_platform_data: -+ return err; -+} -diff --git a/drivers/input/misc/gpio_output.c b/drivers/input/misc/gpio_output.c -new file mode 100644 -index 00000000..2aac2fad ---- /dev/null -+++ b/drivers/input/misc/gpio_output.c -@@ -0,0 +1,97 @@ -+/* drivers/input/misc/gpio_output.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/gpio.h> -+#include <linux/gpio_event.h> -+ -+int gpio_event_output_event( -+ struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, -+ void **data, unsigned int dev, unsigned int type, -+ unsigned int code, int value) -+{ -+ int i; -+ struct gpio_event_output_info *oi; -+ oi = container_of(info, struct gpio_event_output_info, info); -+ if (type != oi->type) -+ return 0; -+ if (!(oi->flags & GPIOEDF_ACTIVE_HIGH)) -+ value = !value; -+ for (i = 0; i < oi->keymap_size; i++) -+ if (dev == oi->keymap[i].dev && code == oi->keymap[i].code) -+ gpio_set_value(oi->keymap[i].gpio, value); -+ return 0; -+} -+ -+int gpio_event_output_func( -+ struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, -+ void **data, int func) -+{ -+ int ret; -+ int i; -+ struct gpio_event_output_info *oi; -+ oi = container_of(info, struct gpio_event_output_info, info); -+ -+ if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) -+ return 0; -+ -+ if (func == GPIO_EVENT_FUNC_INIT) { -+ int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH); -+ -+ for (i = 0; i < oi->keymap_size; i++) { -+ int dev = oi->keymap[i].dev; -+ if (dev >= input_devs->count) { -+ pr_err("gpio_event_output_func: bad device " -+ "index %d >= %d for key code %d\n", -+ dev, input_devs->count, -+ oi->keymap[i].code); -+ ret = -EINVAL; -+ goto err_bad_keymap; -+ } -+ input_set_capability(input_devs->dev[dev], oi->type, -+ oi->keymap[i].code); -+ } -+ -+ for (i = 0; i < oi->keymap_size; i++) { -+ ret = gpio_request(oi->keymap[i].gpio, -+ "gpio_event_output"); -+ if (ret) { -+ pr_err("gpio_event_output_func: gpio_request " -+ "failed for %d\n", oi->keymap[i].gpio); -+ goto err_gpio_request_failed; -+ } -+ ret = gpio_direction_output(oi->keymap[i].gpio, -+ output_level); -+ if (ret) { -+ pr_err("gpio_event_output_func: " -+ "gpio_direction_output failed for %d\n", -+ oi->keymap[i].gpio); -+ goto err_gpio_direction_output_failed; -+ } -+ } -+ return 0; -+ } -+ -+ ret = 0; -+ for (i = oi->keymap_size - 1; i >= 0; i--) { -+err_gpio_direction_output_failed: -+ gpio_free(oi->keymap[i].gpio); -+err_gpio_request_failed: -+ ; -+ } -+err_bad_keymap: -+ return ret; -+} -+ -diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c -new file mode 100644 -index 00000000..a5ea27ad ---- /dev/null -+++ b/drivers/input/misc/keychord.c -@@ -0,0 +1,391 @@ -+/* -+ * drivers/input/misc/keychord.c -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+*/ -+ -+#include <linux/poll.h> -+#include <linux/slab.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/spinlock.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/keychord.h> -+#include <linux/sched.h> -+ -+#define KEYCHORD_NAME "keychord" -+#define BUFFER_SIZE 16 -+ -+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); -+MODULE_DESCRIPTION("Key chord input driver"); -+MODULE_SUPPORTED_DEVICE("keychord"); -+MODULE_LICENSE("GPL"); -+ -+#define NEXT_KEYCHORD(kc) ((struct input_keychord *) \ -+ ((char *)kc + sizeof(struct input_keychord) + \ -+ kc->count * sizeof(kc->keycodes[0]))) -+ -+struct keychord_device { -+ struct input_handler input_handler; -+ int registered; -+ -+ /* list of keychords to monitor */ -+ struct input_keychord *keychords; -+ int keychord_count; -+ -+ /* bitmask of keys contained in our keychords */ -+ unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; -+ /* current state of the keys */ -+ unsigned long keystate[BITS_TO_LONGS(KEY_CNT)]; -+ /* number of keys that are currently pressed */ -+ int key_down; -+ -+ /* second input_device_id is needed for null termination */ -+ struct input_device_id device_ids[2]; -+ -+ spinlock_t lock; -+ wait_queue_head_t waitq; -+ unsigned char head; -+ unsigned char tail; -+ __u16 buff[BUFFER_SIZE]; -+}; -+ -+static int check_keychord(struct keychord_device *kdev, -+ struct input_keychord *keychord) -+{ -+ int i; -+ -+ if (keychord->count != kdev->key_down) -+ return 0; -+ -+ for (i = 0; i < keychord->count; i++) { -+ if (!test_bit(keychord->keycodes[i], kdev->keystate)) -+ return 0; -+ } -+ -+ /* we have a match */ -+ return 1; -+} -+ -+static void keychord_event(struct input_handle *handle, unsigned int type, -+ unsigned int code, int value) -+{ -+ struct keychord_device *kdev = handle->private; -+ struct input_keychord *keychord; -+ unsigned long flags; -+ int i, got_chord = 0; -+ -+ if (type != EV_KEY || code >= KEY_MAX) -+ return; -+ -+ spin_lock_irqsave(&kdev->lock, flags); -+ /* do nothing if key state did not change */ -+ if (!test_bit(code, kdev->keystate) == !value) -+ goto done; -+ __change_bit(code, kdev->keystate); -+ if (value) -+ kdev->key_down++; -+ else -+ kdev->key_down--; -+ -+ /* don't notify on key up */ -+ if (!value) -+ goto done; -+ /* ignore this event if it is not one of the keys we are monitoring */ -+ if (!test_bit(code, kdev->keybit)) -+ goto done; -+ -+ keychord = kdev->keychords; -+ if (!keychord) -+ goto done; -+ -+ /* check to see if the keyboard state matches any keychords */ -+ for (i = 0; i < kdev->keychord_count; i++) { -+ if (check_keychord(kdev, keychord)) { -+ kdev->buff[kdev->head] = keychord->id; -+ kdev->head = (kdev->head + 1) % BUFFER_SIZE; -+ got_chord = 1; -+ break; -+ } -+ /* skip to next keychord */ -+ keychord = NEXT_KEYCHORD(keychord); -+ } -+ -+done: -+ spin_unlock_irqrestore(&kdev->lock, flags); -+ -+ if (got_chord) { -+ pr_info("keychord: got keychord id %d. Any tasks: %d\n", -+ keychord->id, -+ !list_empty_careful(&kdev->waitq.task_list)); -+ wake_up_interruptible(&kdev->waitq); -+ } -+} -+ -+static int keychord_connect(struct input_handler *handler, -+ struct input_dev *dev, -+ const struct input_device_id *id) -+{ -+ int i, ret; -+ struct input_handle *handle; -+ struct keychord_device *kdev = -+ container_of(handler, struct keychord_device, input_handler); -+ -+ /* -+ * ignore this input device if it does not contain any keycodes -+ * that we are monitoring -+ */ -+ for (i = 0; i < KEY_MAX; i++) { -+ if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit)) -+ break; -+ } -+ if (i == KEY_MAX) -+ return -ENODEV; -+ -+ handle = kzalloc(sizeof(*handle), GFP_KERNEL); -+ if (!handle) -+ return -ENOMEM; -+ -+ handle->dev = dev; -+ handle->handler = handler; -+ handle->name = KEYCHORD_NAME; -+ handle->private = kdev; -+ -+ ret = input_register_handle(handle); -+ if (ret) -+ goto err_input_register_handle; -+ -+ ret = input_open_device(handle); -+ if (ret) -+ goto err_input_open_device; -+ -+ pr_info("keychord: using input dev %s for fevent\n", dev->name); -+ -+ return 0; -+ -+err_input_open_device: -+ input_unregister_handle(handle); -+err_input_register_handle: -+ kfree(handle); -+ return ret; -+} -+ -+static void keychord_disconnect(struct input_handle *handle) -+{ -+ input_close_device(handle); -+ input_unregister_handle(handle); -+ kfree(handle); -+} -+ -+/* -+ * keychord_read is used to read keychord events from the driver -+ */ -+static ssize_t keychord_read(struct file *file, char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ struct keychord_device *kdev = file->private_data; -+ __u16 id; -+ int retval; -+ unsigned long flags; -+ -+ if (count < sizeof(id)) -+ return -EINVAL; -+ count = sizeof(id); -+ -+ if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK)) -+ return -EAGAIN; -+ -+ retval = wait_event_interruptible(kdev->waitq, -+ kdev->head != kdev->tail); -+ if (retval) -+ return retval; -+ -+ spin_lock_irqsave(&kdev->lock, flags); -+ /* pop a keychord ID off the queue */ -+ id = kdev->buff[kdev->tail]; -+ kdev->tail = (kdev->tail + 1) % BUFFER_SIZE; -+ spin_unlock_irqrestore(&kdev->lock, flags); -+ -+ if (copy_to_user(buffer, &id, count)) -+ return -EFAULT; -+ -+ return count; -+} -+ -+/* -+ * keychord_write is used to configure the driver -+ */ -+static ssize_t keychord_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ struct keychord_device *kdev = file->private_data; -+ struct input_keychord *keychords = 0; -+ struct input_keychord *keychord, *next, *end; -+ int ret, i, key; -+ unsigned long flags; -+ -+ if (count < sizeof(struct input_keychord)) -+ return -EINVAL; -+ keychords = kzalloc(count, GFP_KERNEL); -+ if (!keychords) -+ return -ENOMEM; -+ -+ /* read list of keychords from userspace */ -+ if (copy_from_user(keychords, buffer, count)) { -+ kfree(keychords); -+ return -EFAULT; -+ } -+ -+ /* unregister handler before changing configuration */ -+ if (kdev->registered) { -+ input_unregister_handler(&kdev->input_handler); -+ kdev->registered = 0; -+ } -+ -+ spin_lock_irqsave(&kdev->lock, flags); -+ /* clear any existing configuration */ -+ kfree(kdev->keychords); -+ kdev->keychords = 0; -+ kdev->keychord_count = 0; -+ kdev->key_down = 0; -+ memset(kdev->keybit, 0, sizeof(kdev->keybit)); -+ memset(kdev->keystate, 0, sizeof(kdev->keystate)); -+ kdev->head = kdev->tail = 0; -+ -+ keychord = keychords; -+ end = (struct input_keychord *)((char *)keychord + count); -+ -+ while (keychord < end) { -+ next = NEXT_KEYCHORD(keychord); -+ if (keychord->count <= 0 || next > end) { -+ pr_err("keychord: invalid keycode count %d\n", -+ keychord->count); -+ goto err_unlock_return; -+ } -+ if (keychord->version != KEYCHORD_VERSION) { -+ pr_err("keychord: unsupported version %d\n", -+ keychord->version); -+ goto err_unlock_return; -+ } -+ -+ /* keep track of the keys we are monitoring in keybit */ -+ for (i = 0; i < keychord->count; i++) { -+ key = keychord->keycodes[i]; -+ if (key < 0 || key >= KEY_CNT) { -+ pr_err("keychord: keycode %d out of range\n", -+ key); -+ goto err_unlock_return; -+ } -+ __set_bit(key, kdev->keybit); -+ } -+ -+ kdev->keychord_count++; -+ keychord = next; -+ } -+ -+ kdev->keychords = keychords; -+ spin_unlock_irqrestore(&kdev->lock, flags); -+ -+ ret = input_register_handler(&kdev->input_handler); -+ if (ret) { -+ kfree(keychords); -+ kdev->keychords = 0; -+ return ret; -+ } -+ kdev->registered = 1; -+ -+ return count; -+ -+err_unlock_return: -+ spin_unlock_irqrestore(&kdev->lock, flags); -+ kfree(keychords); -+ return -EINVAL; -+} -+ -+static unsigned int keychord_poll(struct file *file, poll_table *wait) -+{ -+ struct keychord_device *kdev = file->private_data; -+ -+ poll_wait(file, &kdev->waitq, wait); -+ -+ if (kdev->head != kdev->tail) -+ return POLLIN | POLLRDNORM; -+ -+ return 0; -+} -+ -+static int keychord_open(struct inode *inode, struct file *file) -+{ -+ struct keychord_device *kdev; -+ -+ kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL); -+ if (!kdev) -+ return -ENOMEM; -+ -+ spin_lock_init(&kdev->lock); -+ init_waitqueue_head(&kdev->waitq); -+ -+ kdev->input_handler.event = keychord_event; -+ kdev->input_handler.connect = keychord_connect; -+ kdev->input_handler.disconnect = keychord_disconnect; -+ kdev->input_handler.name = KEYCHORD_NAME; -+ kdev->input_handler.id_table = kdev->device_ids; -+ -+ kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT; -+ __set_bit(EV_KEY, kdev->device_ids[0].evbit); -+ -+ file->private_data = kdev; -+ -+ return 0; -+} -+ -+static int keychord_release(struct inode *inode, struct file *file) -+{ -+ struct keychord_device *kdev = file->private_data; -+ -+ if (kdev->registered) -+ input_unregister_handler(&kdev->input_handler); -+ kfree(kdev); -+ -+ return 0; -+} -+ -+static const struct file_operations keychord_fops = { -+ .owner = THIS_MODULE, -+ .open = keychord_open, -+ .release = keychord_release, -+ .read = keychord_read, -+ .write = keychord_write, -+ .poll = keychord_poll, -+}; -+ -+static struct miscdevice keychord_misc = { -+ .fops = &keychord_fops, -+ .name = KEYCHORD_NAME, -+ .minor = MISC_DYNAMIC_MINOR, -+}; -+ -+static int __init keychord_init(void) -+{ -+ return misc_register(&keychord_misc); -+} -+ -+static void __exit keychord_exit(void) -+{ -+ misc_deregister(&keychord_misc); -+} -+ -+module_init(keychord_init); -+module_exit(keychord_exit); -diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig -index 2a214191..f102a924 100644 ---- a/drivers/input/touchscreen/Kconfig -+++ b/drivers/input/touchscreen/Kconfig -@@ -451,6 +451,12 @@ config TOUCHSCREEN_TNETV107X - To compile this driver as a module, choose M here: the - module will be called tnetv107x-ts. - -+config TOUCHSCREEN_SYNAPTICS_I2C_RMI -+ tristate "Synaptics i2c touchscreen" -+ depends on I2C -+ help -+ This enables support for Synaptics RMI over I2C based touchscreens. -+ - config TOUCHSCREEN_TOUCHRIGHT - tristate "Touchright serial touchscreen" - select SERIO -@@ -792,6 +798,35 @@ config TOUCHSCREEN_TSC2007 - To compile this driver as a module, choose M here: the - module will be called tsc2007. - -+config TOUCHSCREEN_ANYKA -+ bool "Anyka extra touchscreen" -+ depends on ARCH_AK39 -+ help -+ This item enable extra touchscreen interface for Anyka platform. -+ -+config TOUCHSCREEN_CP2007 -+ tristate "cp2007 based touchscreen" -+ depends on TOUCHSCREEN_ANYKA -+ default y -+ help -+ Say Y here if you have a CP2007 based touchscreen. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called tscp2007. -+ -+config TOUCHSCREEN_CP2017 -+ tristate "cp2017 based touchscreen" -+ depends on TOUCHSCREEN_ANYKA -+ help -+ Say Y here if you have a CP2017 based touchscreen. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called tscp2017. -+ - config TOUCHSCREEN_W90X900 - tristate "W90P910 touchscreen driver" - depends on HAVE_CLK -diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile -index 3d5cf8cb..55706d47 100644 ---- a/drivers/input/touchscreen/Makefile -+++ b/drivers/input/touchscreen/Makefile -@@ -51,12 +51,14 @@ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o - obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o - obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o - obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o -+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI) += synaptics_i2c_rmi.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o - obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o - obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o - obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o -+obj-$(CONFIG_TOUCHSCREEN_CP2007) += tscp2007.o - obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o - obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o - obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o -diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi.c b/drivers/input/touchscreen/synaptics_i2c_rmi.c -new file mode 100644 -index 00000000..5729602c ---- /dev/null -+++ b/drivers/input/touchscreen/synaptics_i2c_rmi.c -@@ -0,0 +1,675 @@ -+/* drivers/input/keyboard/synaptics_i2c_rmi.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/earlysuspend.h> -+#include <linux/hrtimer.h> -+#include <linux/i2c.h> -+#include <linux/input.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/synaptics_i2c_rmi.h> -+ -+static struct workqueue_struct *synaptics_wq; -+ -+struct synaptics_ts_data { -+ uint16_t addr; -+ struct i2c_client *client; -+ struct input_dev *input_dev; -+ int use_irq; -+ bool has_relative_report; -+ struct hrtimer timer; -+ struct work_struct work; -+ uint16_t max[2]; -+ int snap_state[2][2]; -+ int snap_down_on[2]; -+ int snap_down_off[2]; -+ int snap_up_on[2]; -+ int snap_up_off[2]; -+ int snap_down[2]; -+ int snap_up[2]; -+ uint32_t flags; -+ int reported_finger_count; -+ int8_t sensitivity_adjust; -+ int (*power)(int on); -+ struct early_suspend early_suspend; -+}; -+ -+#ifdef CONFIG_HAS_EARLYSUSPEND -+static void synaptics_ts_early_suspend(struct early_suspend *h); -+static void synaptics_ts_late_resume(struct early_suspend *h); -+#endif -+ -+static int synaptics_init_panel(struct synaptics_ts_data *ts) -+{ -+ int ret; -+ -+ ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x10); /* page select = 0x10 */ -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n"); -+ goto err_page_select_failed; -+ } -+ ret = i2c_smbus_write_byte_data(ts->client, 0x41, 0x04); /* Set "No Clip Z" */ -+ if (ret < 0) -+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for No Clip Z\n"); -+ -+ ret = i2c_smbus_write_byte_data(ts->client, 0x44, -+ ts->sensitivity_adjust); -+ if (ret < 0) -+ pr_err("synaptics_ts: failed to set Sensitivity Adjust\n"); -+ -+err_page_select_failed: -+ ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x04); /* page select = 0x04 */ -+ if (ret < 0) -+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n"); -+ ret = i2c_smbus_write_byte_data(ts->client, 0xf0, 0x81); /* normal operation, 80 reports per second */ -+ if (ret < 0) -+ printk(KERN_ERR "synaptics_ts_resume: i2c_smbus_write_byte_data failed\n"); -+ return ret; -+} -+ -+static void synaptics_ts_work_func(struct work_struct *work) -+{ -+ int i; -+ int ret; -+ int bad_data = 0; -+ struct i2c_msg msg[2]; -+ uint8_t start_reg; -+ uint8_t buf[15]; -+ struct synaptics_ts_data *ts = container_of(work, struct synaptics_ts_data, work); -+ int buf_len = ts->has_relative_report ? 15 : 13; -+ -+ msg[0].addr = ts->client->addr; -+ msg[0].flags = 0; -+ msg[0].len = 1; -+ msg[0].buf = &start_reg; -+ start_reg = 0x00; -+ msg[1].addr = ts->client->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].len = buf_len; -+ msg[1].buf = buf; -+ -+ /* printk("synaptics_ts_work_func\n"); */ -+ for (i = 0; i < ((ts->use_irq && !bad_data) ? 1 : 10); i++) { -+ ret = i2c_transfer(ts->client->adapter, msg, 2); -+ if (ret < 0) { -+ printk(KERN_ERR "synaptics_ts_work_func: i2c_transfer failed\n"); -+ bad_data = 1; -+ } else { -+ /* printk("synaptics_ts_work_func: %x %x %x %x %x %x" */ -+ /* " %x %x %x %x %x %x %x %x %x, ret %d\n", */ -+ /* buf[0], buf[1], buf[2], buf[3], */ -+ /* buf[4], buf[5], buf[6], buf[7], */ -+ /* buf[8], buf[9], buf[10], buf[11], */ -+ /* buf[12], buf[13], buf[14], ret); */ -+ if ((buf[buf_len - 1] & 0xc0) != 0x40) { -+ printk(KERN_WARNING "synaptics_ts_work_func:" -+ " bad read %x %x %x %x %x %x %x %x %x" -+ " %x %x %x %x %x %x, ret %d\n", -+ buf[0], buf[1], buf[2], buf[3], -+ buf[4], buf[5], buf[6], buf[7], -+ buf[8], buf[9], buf[10], buf[11], -+ buf[12], buf[13], buf[14], ret); -+ if (bad_data) -+ synaptics_init_panel(ts); -+ bad_data = 1; -+ continue; -+ } -+ bad_data = 0; -+ if ((buf[buf_len - 1] & 1) == 0) { -+ /* printk("read %d coordinates\n", i); */ -+ break; -+ } else { -+ int pos[2][2]; -+ int f, a; -+ int base; -+ /* int x = buf[3] | (uint16_t)(buf[2] & 0x1f) << 8; */ -+ /* int y = buf[5] | (uint16_t)(buf[4] & 0x1f) << 8; */ -+ int z = buf[1]; -+ int w = buf[0] >> 4; -+ int finger = buf[0] & 7; -+ -+ /* int x2 = buf[3+6] | (uint16_t)(buf[2+6] & 0x1f) << 8; */ -+ /* int y2 = buf[5+6] | (uint16_t)(buf[4+6] & 0x1f) << 8; */ -+ /* int z2 = buf[1+6]; */ -+ /* int w2 = buf[0+6] >> 4; */ -+ /* int finger2 = buf[0+6] & 7; */ -+ -+ /* int dx = (int8_t)buf[12]; */ -+ /* int dy = (int8_t)buf[13]; */ -+ int finger2_pressed; -+ -+ /* printk("x %4d, y %4d, z %3d, w %2d, F %d, 2nd: x %4d, y %4d, z %3d, w %2d, F %d, dx %4d, dy %4d\n", */ -+ /* x, y, z, w, finger, */ -+ /* x2, y2, z2, w2, finger2, */ -+ /* dx, dy); */ -+ -+ base = 2; -+ for (f = 0; f < 2; f++) { -+ uint32_t flip_flag = SYNAPTICS_FLIP_X; -+ for (a = 0; a < 2; a++) { -+ int p = buf[base + 1]; -+ p |= (uint16_t)(buf[base] & 0x1f) << 8; -+ if (ts->flags & flip_flag) -+ p = ts->max[a] - p; -+ if (ts->flags & SYNAPTICS_SNAP_TO_INACTIVE_EDGE) { -+ if (ts->snap_state[f][a]) { -+ if (p <= ts->snap_down_off[a]) -+ p = ts->snap_down[a]; -+ else if (p >= ts->snap_up_off[a]) -+ p = ts->snap_up[a]; -+ else -+ ts->snap_state[f][a] = 0; -+ } else { -+ if (p <= ts->snap_down_on[a]) { -+ p = ts->snap_down[a]; -+ ts->snap_state[f][a] = 1; -+ } else if (p >= ts->snap_up_on[a]) { -+ p = ts->snap_up[a]; -+ ts->snap_state[f][a] = 1; -+ } -+ } -+ } -+ pos[f][a] = p; -+ base += 2; -+ flip_flag <<= 1; -+ } -+ base += 2; -+ if (ts->flags & SYNAPTICS_SWAP_XY) -+ swap(pos[f][0], pos[f][1]); -+ } -+ if (z) { -+ input_report_abs(ts->input_dev, ABS_X, pos[0][0]); -+ input_report_abs(ts->input_dev, ABS_Y, pos[0][1]); -+ } -+ input_report_abs(ts->input_dev, ABS_PRESSURE, z); -+ input_report_abs(ts->input_dev, ABS_TOOL_WIDTH, w); -+ input_report_key(ts->input_dev, BTN_TOUCH, finger); -+ finger2_pressed = finger > 1 && finger != 7; -+ input_report_key(ts->input_dev, BTN_2, finger2_pressed); -+ if (finger2_pressed) { -+ input_report_abs(ts->input_dev, ABS_HAT0X, pos[1][0]); -+ input_report_abs(ts->input_dev, ABS_HAT0Y, pos[1][1]); -+ } -+ -+ if (!finger) -+ z = 0; -+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z); -+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); -+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[0][0]); -+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[0][1]); -+ input_mt_sync(ts->input_dev); -+ if (finger2_pressed) { -+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z); -+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); -+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[1][0]); -+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[1][1]); -+ input_mt_sync(ts->input_dev); -+ } else if (ts->reported_finger_count > 1) { -+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); -+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); -+ input_mt_sync(ts->input_dev); -+ } -+ ts->reported_finger_count = finger; -+ input_sync(ts->input_dev); -+ } -+ } -+ } -+ if (ts->use_irq) -+ enable_irq(ts->client->irq); -+} -+ -+static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer) -+{ -+ struct synaptics_ts_data *ts = container_of(timer, struct synaptics_ts_data, timer); -+ /* printk("synaptics_ts_timer_func\n"); */ -+ -+ queue_work(synaptics_wq, &ts->work); -+ -+ hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); -+ return HRTIMER_NORESTART; -+} -+ -+static irqreturn_t synaptics_ts_irq_handler(int irq, void *dev_id) -+{ -+ struct synaptics_ts_data *ts = dev_id; -+ -+ /* printk("synaptics_ts_irq_handler\n"); */ -+ disable_irq_nosync(ts->client->irq); -+ queue_work(synaptics_wq, &ts->work); -+ return IRQ_HANDLED; -+} -+ -+static int synaptics_ts_probe( -+ struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct synaptics_ts_data *ts; -+ uint8_t buf0[4]; -+ uint8_t buf1[8]; -+ struct i2c_msg msg[2]; -+ int ret = 0; -+ uint16_t max_x, max_y; -+ int fuzz_x, fuzz_y, fuzz_p, fuzz_w; -+ struct synaptics_i2c_rmi_platform_data *pdata; -+ unsigned long irqflags; -+ int inactive_area_left; -+ int inactive_area_right; -+ int inactive_area_top; -+ int inactive_area_bottom; -+ int snap_left_on; -+ int snap_left_off; -+ int snap_right_on; -+ int snap_right_off; -+ int snap_top_on; -+ int snap_top_off; -+ int snap_bottom_on; -+ int snap_bottom_off; -+ uint32_t panel_version; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { -+ printk(KERN_ERR "synaptics_ts_probe: need I2C_FUNC_I2C\n"); -+ ret = -ENODEV; -+ goto err_check_functionality_failed; -+ } -+ -+ ts = kzalloc(sizeof(*ts), GFP_KERNEL); -+ if (ts == NULL) { -+ ret = -ENOMEM; -+ goto err_alloc_data_failed; -+ } -+ INIT_WORK(&ts->work, synaptics_ts_work_func); -+ ts->client = client; -+ i2c_set_clientdata(client, ts); -+ pdata = client->dev.platform_data; -+ if (pdata) -+ ts->power = pdata->power; -+ if (ts->power) { -+ ret = ts->power(1); -+ if (ret < 0) { -+ printk(KERN_ERR "synaptics_ts_probe power on failed\n"); -+ goto err_power_failed; -+ } -+ } -+ -+ ret = i2c_smbus_write_byte_data(ts->client, 0xf4, 0x01); /* device command = reset */ -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_write_byte_data failed\n"); -+ /* fail? */ -+ } -+ { -+ int retry = 10; -+ while (retry-- > 0) { -+ ret = i2c_smbus_read_byte_data(ts->client, 0xe4); -+ if (ret >= 0) -+ break; -+ msleep(100); -+ } -+ } -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); -+ goto err_detect_failed; -+ } -+ printk(KERN_INFO "synaptics_ts_probe: Product Major Version %x\n", ret); -+ panel_version = ret << 8; -+ ret = i2c_smbus_read_byte_data(ts->client, 0xe5); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); -+ goto err_detect_failed; -+ } -+ printk(KERN_INFO "synaptics_ts_probe: Product Minor Version %x\n", ret); -+ panel_version |= ret; -+ -+ ret = i2c_smbus_read_byte_data(ts->client, 0xe3); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); -+ goto err_detect_failed; -+ } -+ printk(KERN_INFO "synaptics_ts_probe: product property %x\n", ret); -+ -+ if (pdata) { -+ while (pdata->version > panel_version) -+ pdata++; -+ ts->flags = pdata->flags; -+ ts->sensitivity_adjust = pdata->sensitivity_adjust; -+ irqflags = pdata->irqflags; -+ inactive_area_left = pdata->inactive_left; -+ inactive_area_right = pdata->inactive_right; -+ inactive_area_top = pdata->inactive_top; -+ inactive_area_bottom = pdata->inactive_bottom; -+ snap_left_on = pdata->snap_left_on; -+ snap_left_off = pdata->snap_left_off; -+ snap_right_on = pdata->snap_right_on; -+ snap_right_off = pdata->snap_right_off; -+ snap_top_on = pdata->snap_top_on; -+ snap_top_off = pdata->snap_top_off; -+ snap_bottom_on = pdata->snap_bottom_on; -+ snap_bottom_off = pdata->snap_bottom_off; -+ fuzz_x = pdata->fuzz_x; -+ fuzz_y = pdata->fuzz_y; -+ fuzz_p = pdata->fuzz_p; -+ fuzz_w = pdata->fuzz_w; -+ } else { -+ irqflags = 0; -+ inactive_area_left = 0; -+ inactive_area_right = 0; -+ inactive_area_top = 0; -+ inactive_area_bottom = 0; -+ snap_left_on = 0; -+ snap_left_off = 0; -+ snap_right_on = 0; -+ snap_right_off = 0; -+ snap_top_on = 0; -+ snap_top_off = 0; -+ snap_bottom_on = 0; -+ snap_bottom_off = 0; -+ fuzz_x = 0; -+ fuzz_y = 0; -+ fuzz_p = 0; -+ fuzz_w = 0; -+ } -+ -+ ret = i2c_smbus_read_byte_data(ts->client, 0xf0); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); -+ goto err_detect_failed; -+ } -+ printk(KERN_INFO "synaptics_ts_probe: device control %x\n", ret); -+ -+ ret = i2c_smbus_read_byte_data(ts->client, 0xf1); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); -+ goto err_detect_failed; -+ } -+ printk(KERN_INFO "synaptics_ts_probe: interrupt enable %x\n", ret); -+ -+ ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0); /* disable interrupt */ -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_write_byte_data failed\n"); -+ goto err_detect_failed; -+ } -+ -+ msg[0].addr = ts->client->addr; -+ msg[0].flags = 0; -+ msg[0].len = 1; -+ msg[0].buf = buf0; -+ buf0[0] = 0xe0; -+ msg[1].addr = ts->client->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].len = 8; -+ msg[1].buf = buf1; -+ ret = i2c_transfer(ts->client->adapter, msg, 2); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_transfer failed\n"); -+ goto err_detect_failed; -+ } -+ printk(KERN_INFO "synaptics_ts_probe: 0xe0: %x %x %x %x %x %x %x %x\n", -+ buf1[0], buf1[1], buf1[2], buf1[3], -+ buf1[4], buf1[5], buf1[6], buf1[7]); -+ -+ ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x10); /* page select = 0x10 */ -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n"); -+ goto err_detect_failed; -+ } -+ ret = i2c_smbus_read_word_data(ts->client, 0x02); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_word_data failed\n"); -+ goto err_detect_failed; -+ } -+ ts->has_relative_report = !(ret & 0x100); -+ printk(KERN_INFO "synaptics_ts_probe: Sensor properties %x\n", ret); -+ ret = i2c_smbus_read_word_data(ts->client, 0x04); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_word_data failed\n"); -+ goto err_detect_failed; -+ } -+ ts->max[0] = max_x = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8); -+ ret = i2c_smbus_read_word_data(ts->client, 0x06); -+ if (ret < 0) { -+ printk(KERN_ERR "i2c_smbus_read_word_data failed\n"); -+ goto err_detect_failed; -+ } -+ ts->max[1] = max_y = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8); -+ if (ts->flags & SYNAPTICS_SWAP_XY) -+ swap(max_x, max_y); -+ -+ ret = synaptics_init_panel(ts); /* will also switch back to page 0x04 */ -+ if (ret < 0) { -+ printk(KERN_ERR "synaptics_init_panel failed\n"); -+ goto err_detect_failed; -+ } -+ -+ ts->input_dev = input_allocate_device(); -+ if (ts->input_dev == NULL) { -+ ret = -ENOMEM; -+ printk(KERN_ERR "synaptics_ts_probe: Failed to allocate input device\n"); -+ goto err_input_dev_alloc_failed; -+ } -+ ts->input_dev->name = "synaptics-rmi-touchscreen"; -+ set_bit(EV_SYN, ts->input_dev->evbit); -+ set_bit(EV_KEY, ts->input_dev->evbit); -+ set_bit(BTN_TOUCH, ts->input_dev->keybit); -+ set_bit(BTN_2, ts->input_dev->keybit); -+ set_bit(EV_ABS, ts->input_dev->evbit); -+ inactive_area_left = inactive_area_left * max_x / 0x10000; -+ inactive_area_right = inactive_area_right * max_x / 0x10000; -+ inactive_area_top = inactive_area_top * max_y / 0x10000; -+ inactive_area_bottom = inactive_area_bottom * max_y / 0x10000; -+ snap_left_on = snap_left_on * max_x / 0x10000; -+ snap_left_off = snap_left_off * max_x / 0x10000; -+ snap_right_on = snap_right_on * max_x / 0x10000; -+ snap_right_off = snap_right_off * max_x / 0x10000; -+ snap_top_on = snap_top_on * max_y / 0x10000; -+ snap_top_off = snap_top_off * max_y / 0x10000; -+ snap_bottom_on = snap_bottom_on * max_y / 0x10000; -+ snap_bottom_off = snap_bottom_off * max_y / 0x10000; -+ fuzz_x = fuzz_x * max_x / 0x10000; -+ fuzz_y = fuzz_y * max_y / 0x10000; -+ ts->snap_down[!!(ts->flags & SYNAPTICS_SWAP_XY)] = -inactive_area_left; -+ ts->snap_up[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x + inactive_area_right; -+ ts->snap_down[!(ts->flags & SYNAPTICS_SWAP_XY)] = -inactive_area_top; -+ ts->snap_up[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y + inactive_area_bottom; -+ ts->snap_down_on[!!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_left_on; -+ ts->snap_down_off[!!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_left_off; -+ ts->snap_up_on[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x - snap_right_on; -+ ts->snap_up_off[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x - snap_right_off; -+ ts->snap_down_on[!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_top_on; -+ ts->snap_down_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_top_off; -+ ts->snap_up_on[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_on; -+ ts->snap_up_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_off; -+ printk(KERN_INFO "synaptics_ts_probe: max_x %d, max_y %d\n", max_x, max_y); -+ printk(KERN_INFO "synaptics_ts_probe: inactive_x %d %d, inactive_y %d %d\n", -+ inactive_area_left, inactive_area_right, -+ inactive_area_top, inactive_area_bottom); -+ printk(KERN_INFO "synaptics_ts_probe: snap_x %d-%d %d-%d, snap_y %d-%d %d-%d\n", -+ snap_left_on, snap_left_off, snap_right_on, snap_right_off, -+ snap_top_on, snap_top_off, snap_bottom_on, snap_bottom_off); -+ input_set_abs_params(ts->input_dev, ABS_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0); -+ input_set_abs_params(ts->input_dev, ABS_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0); -+ input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, fuzz_p, 0); -+ input_set_abs_params(ts->input_dev, ABS_TOOL_WIDTH, 0, 15, fuzz_w, 0); -+ input_set_abs_params(ts->input_dev, ABS_HAT0X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0); -+ input_set_abs_params(ts->input_dev, ABS_HAT0Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0); -+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0); -+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0); -+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, fuzz_p, 0); -+ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 15, fuzz_w, 0); -+ /* ts->input_dev->name = ts->keypad_info->name; */ -+ ret = input_register_device(ts->input_dev); -+ if (ret) { -+ printk(KERN_ERR "synaptics_ts_probe: Unable to register %s input device\n", ts->input_dev->name); -+ goto err_input_register_device_failed; -+ } -+ if (client->irq) { -+ ret = request_irq(client->irq, synaptics_ts_irq_handler, irqflags, client->name, ts); -+ if (ret == 0) { -+ ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0x01); /* enable abs int */ -+ if (ret) -+ free_irq(client->irq, ts); -+ } -+ if (ret == 0) -+ ts->use_irq = 1; -+ else -+ dev_err(&client->dev, "request_irq failed\n"); -+ } -+ if (!ts->use_irq) { -+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ ts->timer.function = synaptics_ts_timer_func; -+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); -+ } -+#ifdef CONFIG_HAS_EARLYSUSPEND -+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; -+ ts->early_suspend.suspend = synaptics_ts_early_suspend; -+ ts->early_suspend.resume = synaptics_ts_late_resume; -+ register_early_suspend(&ts->early_suspend); -+#endif -+ -+ printk(KERN_INFO "synaptics_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling"); -+ -+ return 0; -+ -+err_input_register_device_failed: -+ input_free_device(ts->input_dev); -+ -+err_input_dev_alloc_failed: -+err_detect_failed: -+err_power_failed: -+ kfree(ts); -+err_alloc_data_failed: -+err_check_functionality_failed: -+ return ret; -+} -+ -+static int synaptics_ts_remove(struct i2c_client *client) -+{ -+ struct synaptics_ts_data *ts = i2c_get_clientdata(client); -+ unregister_early_suspend(&ts->early_suspend); -+ if (ts->use_irq) -+ free_irq(client->irq, ts); -+ else -+ hrtimer_cancel(&ts->timer); -+ input_unregister_device(ts->input_dev); -+ kfree(ts); -+ return 0; -+} -+ -+static int synaptics_ts_suspend(struct i2c_client *client, pm_message_t mesg) -+{ -+ int ret; -+ struct synaptics_ts_data *ts = i2c_get_clientdata(client); -+ -+ if (ts->use_irq) -+ disable_irq(client->irq); -+ else -+ hrtimer_cancel(&ts->timer); -+ ret = cancel_work_sync(&ts->work); -+ if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */ -+ enable_irq(client->irq); -+ ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0); /* disable interrupt */ -+ if (ret < 0) -+ printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n"); -+ -+ ret = i2c_smbus_write_byte_data(client, 0xf0, 0x86); /* deep sleep */ -+ if (ret < 0) -+ printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n"); -+ if (ts->power) { -+ ret = ts->power(0); -+ if (ret < 0) -+ printk(KERN_ERR "synaptics_ts_resume power off failed\n"); -+ } -+ return 0; -+} -+ -+static int synaptics_ts_resume(struct i2c_client *client) -+{ -+ int ret; -+ struct synaptics_ts_data *ts = i2c_get_clientdata(client); -+ -+ if (ts->power) { -+ ret = ts->power(1); -+ if (ret < 0) -+ printk(KERN_ERR "synaptics_ts_resume power on failed\n"); -+ } -+ -+ synaptics_init_panel(ts); -+ -+ if (ts->use_irq) -+ enable_irq(client->irq); -+ -+ if (!ts->use_irq) -+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); -+ else -+ i2c_smbus_write_byte_data(ts->client, 0xf1, 0x01); /* enable abs int */ -+ -+ return 0; -+} -+ -+#ifdef CONFIG_HAS_EARLYSUSPEND -+static void synaptics_ts_early_suspend(struct early_suspend *h) -+{ -+ struct synaptics_ts_data *ts; -+ ts = container_of(h, struct synaptics_ts_data, early_suspend); -+ synaptics_ts_suspend(ts->client, PMSG_SUSPEND); -+} -+ -+static void synaptics_ts_late_resume(struct early_suspend *h) -+{ -+ struct synaptics_ts_data *ts; -+ ts = container_of(h, struct synaptics_ts_data, early_suspend); -+ synaptics_ts_resume(ts->client); -+} -+#endif -+ -+static const struct i2c_device_id synaptics_ts_id[] = { -+ { SYNAPTICS_I2C_RMI_NAME, 0 }, -+ { } -+}; -+ -+static struct i2c_driver synaptics_ts_driver = { -+ .probe = synaptics_ts_probe, -+ .remove = synaptics_ts_remove, -+#ifndef CONFIG_HAS_EARLYSUSPEND -+ .suspend = synaptics_ts_suspend, -+ .resume = synaptics_ts_resume, -+#endif -+ .id_table = synaptics_ts_id, -+ .driver = { -+ .name = SYNAPTICS_I2C_RMI_NAME, -+ }, -+}; -+ -+static int __devinit synaptics_ts_init(void) -+{ -+ synaptics_wq = create_singlethread_workqueue("synaptics_wq"); -+ if (!synaptics_wq) -+ return -ENOMEM; -+ return i2c_add_driver(&synaptics_ts_driver); -+} -+ -+static void __exit synaptics_ts_exit(void) -+{ -+ i2c_del_driver(&synaptics_ts_driver); -+ if (synaptics_wq) -+ destroy_workqueue(synaptics_wq); -+} -+ -+module_init(synaptics_ts_init); -+module_exit(synaptics_ts_exit); -+ -+MODULE_DESCRIPTION("Synaptics Touchscreen Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/touchscreen/tscp2007.c b/drivers/input/touchscreen/tscp2007.c -new file mode 100755 -index 00000000..5fe2e0ba ---- /dev/null -+++ b/drivers/input/touchscreen/tscp2007.c -@@ -0,0 +1,409 @@ -+/* -+ * drivers/input/touchscreen/tscp2007.c -+ * -+ * Copyright (c) 2008 MtekVision Co., Ltd. -+ * Kwangwoo Lee <kwlee@mtekvision.com> -+ * -+ * Using code from: -+ * - ads7846.c -+ * Copyright (c) 2005 David Brownell -+ * Copyright (c) 2006 Nokia Corporation -+ * - corgi_ts.c -+ * Copyright (C) 2004-2005 Richard Purdie -+ * - omap_ts.[hc], ads7846.h, ts_osk.c -+ * Copyright (C) 2002 MontaVista Software -+ * Copyright (C) 2004 Texas Instruments -+ * Copyright (C) 2005 Dirk Behme -+ * -+ * 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/slab.h> -+#include <linux/swab.h> -+#include <linux/input.h> -+#include <linux/interrupt.h> -+#include <linux/i2c.h> -+#include <plat-anyka/tscp2007.h> -+ -+ -+#define tscp2007_MEASURE_TEMP0 (0x0 << 4) -+#define tscp2007_MEASURE_AUX (0x2 << 4) -+#define tscp2007_MEASURE_TEMP1 (0x4 << 4) -+#define tscp2007_ACTIVATE_XN (0x8 << 4) -+#define tscp2007_ACTIVATE_YN (0x9 << 4) -+#define tscp2007_ACTIVATE_YP_XN (0xa << 4) -+#define tscp2007_SETUP (0xb << 4) -+#define tscp2007_MEASURE_X (0xc << 4) -+#define tscp2007_MEASURE_Y (0xd << 4) -+#define tscp2007_MEASURE_Z1 (0xe << 4) -+#define tscp2007_MEASURE_Z2 (0xf << 4) -+ -+#define tscp2007_POWER_OFF_IRQ_EN (0x0 << 2) -+#define tscp2007_ADC_ON_IRQ_DIS0 (0x1 << 2) -+#define tscp2007_ADC_OFF_IRQ_EN (0x2 << 2) -+#define tscp2007_ADC_ON_IRQ_DIS1 (0x3 << 2) -+ -+#define tscp2007_12BIT (0x0 << 1) -+#define tscp2007_8BIT (0x1 << 1) -+ -+#define MAX_12BIT ((1 << 12) - 1) -+ -+#define ADC_ON_12BIT (tscp2007_12BIT | tscp2007_ADC_ON_IRQ_DIS0) -+ -+#define READ_Y (ADC_ON_12BIT | tscp2007_MEASURE_Y) -+#define READ_Z1 (ADC_ON_12BIT | tscp2007_MEASURE_Z1) -+#define READ_Z2 (ADC_ON_12BIT | tscp2007_MEASURE_Z2) -+#define READ_X (ADC_ON_12BIT | tscp2007_MEASURE_X) -+#define PWRDOWN (tscp2007_12BIT | tscp2007_POWER_OFF_IRQ_EN) -+ -+struct ts_event { -+ u16 x; -+ u16 y; -+ u16 z1, z2; -+}; -+ -+struct tscp2007 { -+ struct input_dev *input; -+ char phys[32]; -+ -+ struct i2c_client *client; -+ -+ u16 model; -+ u16 x_plate_ohms; -+ u16 max_rt; -+ unsigned long poll_delay; -+ unsigned long poll_period; -+ -+ int irq; -+ -+ wait_queue_head_t wait; -+ bool stopped; -+ -+ unsigned int intpin; -+ int (*get_pendown_state)(unsigned int pin); -+ void (*clear_penirq)(void); -+}; -+ -+static inline int tscp2007_xfer(struct tscp2007 *tsc, u8 cmd) -+{ -+ s32 data; -+ u16 val; -+ -+ data = i2c_smbus_read_word_data(tsc->client, cmd); -+ if (data < 0) { -+ dev_err(&tsc->client->dev, "i2c io error: %d\n", data); -+ return data; -+ } -+ -+ /* The protocol and raw data format from i2c interface: -+ * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P -+ * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit]. -+ */ -+ val = swab16(data) >> 4; -+ -+ dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val); -+ -+ return val; -+} -+ -+static void tscp2007_read_values(struct tscp2007 *tsc, struct ts_event *tc) -+{ -+ /* y- still on; turn on only y+ (and ADC) */ -+ tc->y = tscp2007_xfer(tsc, READ_Y); -+ -+ /* turn y- off, x+ on, then leave in lowpower */ -+ tc->x = tscp2007_xfer(tsc, READ_X); -+ -+ /* turn y+ off, x- on; we'll use formula #1 */ -+ tc->z1 = tscp2007_xfer(tsc, READ_Z1); -+ tc->z2 = tscp2007_xfer(tsc, READ_Z2); -+ -+ /* Prepare for next touch reading - power down ADC, enable PENIRQ */ -+ tscp2007_xfer(tsc, PWRDOWN); -+} -+ -+static u32 tscp2007_calculate_pressure(struct tscp2007 *tsc, struct ts_event *tc) -+{ -+ u32 rt = 0; -+ -+ /* range filtering */ -+ if (tc->x == MAX_12BIT) -+ tc->x = 0; -+ -+ if (likely(tc->x && tc->z1)) { -+ /* compute touch pressure resistance using equation #1 */ -+ rt = tc->z2 - tc->z1; -+ rt *= tc->x; -+ rt *= tsc->x_plate_ohms; -+ rt /= tc->z1; -+ rt = (rt + 2047) >> 12; -+ } -+ -+ return rt; -+} -+ -+static bool tscp2007_is_pen_down(struct tscp2007 *ts) -+{ -+ /* -+ * NOTE: We can't rely on the pressure to determine the pen down -+ * state, even though this controller has a pressure sensor. -+ * The pressure value can fluctuate for quite a while after -+ * lifting the pen and in some cases may not even settle at the -+ * expected value. -+ * -+ * The only safe way to check for the pen up condition is in the -+ * work function by reading the pen signal state (it's a GPIO -+ * and IRQ). Unfortunately such callback is not always available, -+ * in that case we assume that the pen is down and expect caller -+ * to fall back on the pressure reading. -+ */ -+ -+ if (!ts->get_pendown_state) -+ return true; -+ -+ return ts->get_pendown_state(ts->intpin); -+} -+ -+static irqreturn_t tscp2007_soft_irq(int irq, void *handle) -+{ -+ struct tscp2007 *ts = handle; -+ struct input_dev *input = ts->input; -+ struct ts_event tc; -+ u32 rt; -+ -+ while (!ts->stopped && tscp2007_is_pen_down(ts)) { -+ -+ /* pen is down, continue with the measurement */ -+ tscp2007_read_values(ts, &tc); -+ -+ rt = tscp2007_calculate_pressure(ts, &tc); -+ -+ if (rt == 0 && !ts->get_pendown_state) { -+ /* -+ * If pressure reported is 0 and we don't have -+ * callback to check pendown state, we have to -+ * assume that pen was lifted up. -+ */ -+ break; -+ } -+ -+ if (rt <= ts->max_rt) { -+ dev_dbg(&ts->client->dev, -+ "DOWN point(%4d,%4d), pressure (%4u)\n", -+ tc.x, tc.y, rt); -+ -+ input_report_key(input, BTN_TOUCH, 1); -+ input_report_abs(input, ABS_X, tc.x); -+ input_report_abs(input, ABS_Y, tc.y); -+ input_report_abs(input, ABS_PRESSURE, rt); -+ -+ input_sync(input); -+ -+ } else { -+ /* -+ * Sample found inconsistent by debouncing or pressure is -+ * beyond the maximum. Don't report it to user space, -+ * repeat at least once more the measurement. -+ */ -+ dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); -+ } -+ -+ wait_event_timeout(ts->wait, ts->stopped, -+ msecs_to_jiffies(ts->poll_period)); -+ } -+ -+ dev_dbg(&ts->client->dev, "UP\n"); -+ -+ input_report_key(input, BTN_TOUCH, 0); -+ input_report_abs(input, ABS_PRESSURE, 0); -+ input_sync(input); -+ -+ if (ts->clear_penirq) -+ ts->clear_penirq(); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t tscp2007_hard_irq(int irq, void *handle) -+{ -+ struct tscp2007 *ts = handle; -+ -+ if (!ts->get_pendown_state || likely(ts->get_pendown_state(ts->intpin))) -+ return IRQ_WAKE_THREAD; -+ -+ if (ts->clear_penirq) -+ ts->clear_penirq(); -+ -+ return IRQ_HANDLED; -+} -+ -+static void tscp2007_stop(struct tscp2007 *ts) -+{ -+ ts->stopped = true; -+ mb(); -+ wake_up(&ts->wait); -+ -+ disable_irq(ts->irq); -+} -+ -+static int tscp2007_open(struct input_dev *input_dev) -+{ -+ struct tscp2007 *ts = input_get_drvdata(input_dev); -+ int err; -+ -+ ts->stopped = false; -+ mb(); -+ -+ enable_irq(ts->irq); -+ -+ /* Prepare for touch readings - power down ADC and enable PENIRQ */ -+ err = tscp2007_xfer(ts, PWRDOWN); -+ if (err < 0) { -+ tscp2007_stop(ts); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static void tscp2007_close(struct input_dev *input_dev) -+{ -+ struct tscp2007 *ts = input_get_drvdata(input_dev); -+ -+ tscp2007_stop(ts); -+} -+ -+static int __devinit tscp2007_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct tscp2007 *ts; -+ struct tscp2007_platform_data *pdata = client->dev.platform_data; -+ struct input_dev *input_dev; -+ int err; -+ -+ if (!pdata) { -+ dev_err(&client->dev, "platform data is required!\n"); -+ return -EINVAL; -+ } -+ -+ if (!i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_READ_WORD_DATA)) -+ return -EIO; -+ -+ ts = kzalloc(sizeof(struct tscp2007), GFP_KERNEL); -+ input_dev = input_allocate_device(); -+ if (!ts || !input_dev) { -+ err = -ENOMEM; -+ goto err_free_mem; -+ } -+ -+ ts->client = client; -+ ts->irq = client->irq; -+ ts->input = input_dev; -+ init_waitqueue_head(&ts->wait); -+ -+ ts->model = pdata->model; -+ ts->x_plate_ohms = pdata->x_plate_ohms; -+ ts->max_rt = pdata->max_rt ? : MAX_12BIT; -+ ts->poll_delay = pdata->poll_delay ? : 1; -+ ts->poll_period = pdata->poll_period ? : 1; -+ ts->get_pendown_state = pdata->get_pendown_state; -+ ts->clear_penirq = pdata->clear_penirq; -+ ts->intpin = pdata->intpin_info.pin; -+ -+ if (pdata->x_plate_ohms == 0) { -+ dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); -+ err = -EINVAL; -+ goto err_free_mem; -+ } -+ -+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); -+ -+ input_dev->name = "tscp2007 Touchscreen"; -+ input_dev->phys = ts->phys; -+ input_dev->id.bustype = BUS_I2C; -+ -+ input_dev->open = tscp2007_open; -+ input_dev->close = tscp2007_close; -+ -+ input_set_drvdata(input_dev, ts); -+ -+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); -+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); -+ -+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0); -+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0); -+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, -+ pdata->fuzzz, 0); -+ -+ if (pdata->init_platform_hw) -+ pdata->init_platform_hw(&pdata->intpin_info); -+ -+ err = request_threaded_irq(ts->irq, tscp2007_hard_irq, tscp2007_soft_irq, -+ IRQF_ONESHOT, client->dev.driver->name, ts); -+ if (err < 0) { -+ dev_err(&client->dev, "irq %d busy?\n", ts->irq); -+ goto err_free_mem; -+ } -+ -+ tscp2007_stop(ts); -+ -+ err = input_register_device(input_dev); -+ if (err) -+ goto err_free_irq; -+ -+ i2c_set_clientdata(client, ts); -+ -+ return 0; -+ -+ err_free_irq: -+ free_irq(ts->irq, ts); -+ if (pdata->exit_platform_hw) -+ pdata->exit_platform_hw(); -+ err_free_mem: -+ input_free_device(input_dev); -+ kfree(ts); -+ return err; -+} -+ -+static int __devexit tscp2007_remove(struct i2c_client *client) -+{ -+ struct tscp2007 *ts = i2c_get_clientdata(client); -+ struct tscp2007_platform_data *pdata = client->dev.platform_data; -+ -+ free_irq(ts->irq, ts); -+ -+ if (pdata->exit_platform_hw) -+ pdata->exit_platform_hw(); -+ -+ input_unregister_device(ts->input); -+ kfree(ts); -+ -+ return 0; -+} -+ -+static const struct i2c_device_id tscp2007_idtable[] = { -+ { "tscp2007", 0 }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(i2c, tscp2007_idtable); -+ -+static struct i2c_driver tscp2007_driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "tscp2007" -+ }, -+ .id_table = tscp2007_idtable, -+ .probe = tscp2007_probe, -+ .remove = __devexit_p(tscp2007_remove), -+}; -+ -+module_i2c_driver(tscp2007_driver); -+ -+MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>"); -+MODULE_DESCRIPTION("tscp2007 TouchScreen Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index ff4b8cfd..19820ee5 100644 ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -289,6 +289,12 @@ config LEDS_BD2802 - This option enables support for BD2802GU RGB LED driver chips - accessed via the I2C bus. - -+config LEDS_AK39 -+ tristate "LED Support for the AK39 LEDS" -+ depends on LEDS_CLASS && ARCH_AK39 -+ help -+ This option enables support for the AK39 LEDS -+ - config LEDS_INTEL_SS4200 - tristate "LED driver for Intel NAS SS4200 series" - depends on LEDS_CLASS -@@ -468,6 +474,12 @@ config LEDS_TRIGGER_DEFAULT_ON - This allows LEDs to be initialised in the ON state. - If unsure, say Y. - -+config LEDS_TRIGGER_SLEEP -+ tristate "LED Sleep Mode Trigger" -+ depends on LEDS_TRIGGERS && HAS_EARLYSUSPEND -+ help -+ This turns LEDs on when the screen is off but the cpu still running. -+ - comment "iptables trigger is under Netfilter config (LED target)" - depends on LEDS_TRIGGERS - -diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index 890481cb..b054e8a7 100644 ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -45,6 +45,7 @@ obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o - obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o - obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o - obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o -+obj-$(CONFIG_LEDS_AK39) += leds-ak39.o - - # LED SPI Drivers - obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o -@@ -56,3 +57,4 @@ obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o - obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o - obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o - obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o -+obj-$(CONFIG_LEDS_TRIGGER_SLEEP) += ledtrig-sleep.o -diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c -index 46b4c766..a85ce094 100644 ---- a/drivers/leds/led-triggers.c -+++ b/drivers/leds/led-triggers.c -@@ -102,6 +102,12 @@ EXPORT_SYMBOL_GPL(led_trigger_show); - void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) - { - unsigned long flags; -+ char *event = NULL; -+ char *envp[2]; -+ const char *name; -+ -+ name = trigger ? trigger->name : "none"; -+ event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name); - - /* Remove any existing trigger */ - if (led_cdev->trigger) { -@@ -122,6 +128,13 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) - if (trigger->activate) - trigger->activate(led_cdev); - } -+ -+ if (event) { -+ envp[0] = event; -+ envp[1] = NULL; -+ kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp); -+ kfree(event); -+ } - } - EXPORT_SYMBOL_GPL(led_trigger_set); - -diff --git a/drivers/leds/leds-ak39.c b/drivers/leds/leds-ak39.c -new file mode 100755 -index 00000000..9b9882e0 ---- /dev/null -+++ b/drivers/leds/leds-ak39.c -@@ -0,0 +1,127 @@ -+/* drivers/leds/leds-ak98-factory.c -+ * -+ * Copyright (c) 2012 anyka -+ * -+ * AK98- LEDs GPIO driver -+ * -+ * 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/init.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/leds.h> -+#include <linux/gpio.h> -+#include <linux/module.h> -+ -+#include <mach/hardware.h> -+#include <mach/gpio.h> -+#include <mach/leds-gpio.h> -+ -+struct ak_led_instance { -+ struct led_classdev cdev; -+ struct ak_led_data *led; -+}; -+ -+struct ak_led_class { -+ struct ak_led_instance *instance; -+ int nr_instance; -+}; -+ -+static void ak_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) -+{ -+ unsigned int active_level = 0; -+ -+ struct ak_led_instance *instance = container_of(led_cdev, struct ak_led_instance, cdev); -+ struct ak_led_data *led = instance->led; -+ -+ active_level = (value ? (led->gpio.value == AK_GPIO_OUT_HIGH ? AK_GPIO_OUT_LOW : AK_GPIO_OUT_HIGH) -+ : led->gpio.value); -+ ak_gpio_setpin(led->gpio.pin, active_level); -+ -+} -+ -+static int ak_led_remove(struct platform_device *dev) -+{ -+ int i; -+ struct ak_led_class *class = platform_get_drvdata(dev); -+ struct ak_led_instance *instance = class->instance; -+ -+ for (i = 0; i < class->nr_instance; i++) -+ led_classdev_unregister(&(instance + i)->cdev); -+ -+ kfree(instance); -+ kfree(class); -+ -+ return 0; -+} -+ -+static int ak_led_probe(struct platform_device *dev) -+{ -+ int i, ret; -+ struct ak_led_pdata *pdata = dev->dev.platform_data; -+ struct ak_led_data *leds = pdata->leds; -+ struct ak_led_instance *instance; -+ struct ak_led_class *class; -+ -+ class = kzalloc(sizeof(struct ak_led_class), GFP_KERNEL); -+ instance = kzalloc(sizeof(struct ak_led_instance)*(pdata->nr_led), GFP_KERNEL); -+ if (!class || !instance) { -+ dev_err(&dev->dev, "No memory for device\n"); -+ return -ENOMEM; -+ } -+ -+ class->instance = instance; -+ class->nr_instance = pdata->nr_led; -+ platform_set_drvdata(dev, class); -+ -+ for (i = 0; i < class->nr_instance; i++) { -+ /* Default GPIO configure according to board defined */ -+ ak_gpio_set(&((leds + i)->gpio)); -+ (instance + i)->cdev.name = (leds + i)->name; -+ (instance + i)->cdev.default_trigger = (leds + i)->def_trigger; -+ (instance + i)->cdev.brightness_set = ak_led_brightness_set; -+ (instance + i)->cdev.flags |= LED_CORE_SUSPENDRESUME; -+ (instance + i)->led = (leds + i); -+ -+ ret = led_classdev_register(&dev->dev, &(instance + i)->cdev); -+ if (ret < 0) { -+ dev_err(&dev->dev, "led_classdev_register failed\n"); -+ kfree(instance); -+ kfree(class); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static struct platform_driver ak_led_driver = { -+ .probe = ak_led_probe, -+ .remove = ak_led_remove, -+ .driver = { -+ .name = "ak_led", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init ak_led_init(void) -+{ -+ return platform_driver_register(&ak_led_driver); -+} -+ -+static void __exit ak_led_exit(void) -+{ -+ platform_driver_unregister(&ak_led_driver); -+} -+ -+module_init(ak_led_init); -+module_exit(ak_led_exit); -+ -+MODULE_AUTHOR("Hongguang Du <anyka>"); -+MODULE_DESCRIPTION("AK LED driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ak_led"); -diff --git a/drivers/leds/ledtrig-sleep.c b/drivers/leds/ledtrig-sleep.c -new file mode 100644 -index 00000000..f1640421 ---- /dev/null -+++ b/drivers/leds/ledtrig-sleep.c -@@ -0,0 +1,80 @@ -+/* drivers/leds/ledtrig-sleep.c -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/earlysuspend.h> -+#include <linux/leds.h> -+#include <linux/suspend.h> -+ -+static int ledtrig_sleep_pm_callback(struct notifier_block *nfb, -+ unsigned long action, -+ void *ignored); -+ -+DEFINE_LED_TRIGGER(ledtrig_sleep) -+static struct notifier_block ledtrig_sleep_pm_notifier = { -+ .notifier_call = ledtrig_sleep_pm_callback, -+ .priority = 0, -+}; -+ -+static void ledtrig_sleep_early_suspend(struct early_suspend *h) -+{ -+ led_trigger_event(ledtrig_sleep, LED_FULL); -+} -+ -+static void ledtrig_sleep_early_resume(struct early_suspend *h) -+{ -+ led_trigger_event(ledtrig_sleep, LED_OFF); -+} -+ -+static struct early_suspend ledtrig_sleep_early_suspend_handler = { -+ .suspend = ledtrig_sleep_early_suspend, -+ .resume = ledtrig_sleep_early_resume, -+}; -+ -+static int ledtrig_sleep_pm_callback(struct notifier_block *nfb, -+ unsigned long action, -+ void *ignored) -+{ -+ switch (action) { -+ case PM_HIBERNATION_PREPARE: -+ case PM_SUSPEND_PREPARE: -+ led_trigger_event(ledtrig_sleep, LED_OFF); -+ return NOTIFY_OK; -+ case PM_POST_HIBERNATION: -+ case PM_POST_SUSPEND: -+ led_trigger_event(ledtrig_sleep, LED_FULL); -+ return NOTIFY_OK; -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+static int __init ledtrig_sleep_init(void) -+{ -+ led_trigger_register_simple("sleep", &ledtrig_sleep); -+ register_pm_notifier(&ledtrig_sleep_pm_notifier); -+ register_early_suspend(&ledtrig_sleep_early_suspend_handler); -+ return 0; -+} -+ -+static void __exit ledtrig_sleep_exit(void) -+{ -+ unregister_early_suspend(&ledtrig_sleep_early_suspend_handler); -+ unregister_pm_notifier(&ledtrig_sleep_pm_notifier); -+ led_trigger_unregister_simple(ledtrig_sleep); -+} -+ -+module_init(ledtrig_sleep_init); -+module_exit(ledtrig_sleep_exit); -+ -diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig -index ce1e7ba9..3dee99a5 100644 ---- a/drivers/media/video/Kconfig -+++ b/drivers/media/video/Kconfig -@@ -1057,6 +1057,14 @@ config SOC_CAMERA_OV9740 - help - This is a ov9740 camera driver - -+menuconfig LINUX_AKSENSOR -+ tristate "aksensor support" -+ depends on SOC_CAMERA && I2C -+ help -+ This is a aksensor driver -+ -+source "drivers/media/video/plat-anyka/Kconfig" -+ - config MX1_VIDEO - bool - -@@ -1115,6 +1123,13 @@ config VIDEO_OMAP2 - ---help--- - This is a v4l2 driver for the TI OMAP2 camera capture interface - -+config VIDEO_AK -+ tristate "AK Camera Interface driver" -+ depends on VIDEO_DEV && SOC_CAMERA -+ select VIDEOBUF_DMA_CONTIG -+ ---help--- -+ This is a v4l2 driver for the AK Platform Camera Interface -+ - config VIDEO_MX2_HOSTSUPPORT - bool - -diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile -index a6282a3a..2010202e 100644 ---- a/drivers/media/video/Makefile -+++ b/drivers/media/video/Makefile -@@ -96,6 +96,7 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o - obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o - obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o - obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o -+obj-y += plat-anyka/ - - # And now the v4l2 drivers: - -@@ -182,6 +183,7 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o - obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o - obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o - obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o -+obj-$(CONFIG_VIDEO_AK) += plat-anyka/ak_camera.o plat-anyka/ak39_isp.o - - obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o - -diff --git a/drivers/media/video/plat-anyka/Kconfig b/drivers/media/video/plat-anyka/Kconfig -new file mode 100755 -index 00000000..b2edcdf9 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/Kconfig -@@ -0,0 +1,42 @@ -+config SENSOR_GC0308 -+ tristate "gc0308 sensor support" -+ depends on LINUX_AKSENSOR -+ help -+ This is a gc0308 sensor driver -+ -+config SENSOR_OV2643 -+ tristate "ov2643 sensor support" -+ depends on LINUX_AKSENSOR -+ help -+ This is a ov2643 sensor driver -+ -+config SENSOR_OV7725 -+ tristate "ov7725 sensor support" -+ depends on LINUX_AKSENSOR -+ help -+ This is a ov7725 sensor driver -+ -+config SENSOR_HM1375 -+ tristate "hm1375 sensor support" -+ depends on LINUX_AKSENSOR -+ help -+ This is a hm1375 sensor driver -+ -+config SENSOR_OV9712 -+ tristate "ov9712 sensor support" -+ depends on LINUX_AKSENSOR -+ help -+ This is a ov9712 sensor driver -+ -+config SENSOR_OV2710 -+ tristate "ov2710 sensor support" -+ depends on LINUX_AKSENSOR -+ help -+ This is a ov2710 sensor driver -+ -+config SENSOR_AR0130 -+ tristate "ar0130 sensor support" -+ depends on LINUX_AKSENSOR -+ help -+ This is a ar0130 sensor driver -+ -diff --git a/drivers/media/video/plat-anyka/Makefile b/drivers/media/video/plat-anyka/Makefile -new file mode 100755 -index 00000000..b8aeb4e6 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/Makefile -@@ -0,0 +1,11 @@ -+# sensor -+obj-$(CONFIG_SENSOR_GC0308) += camera_gc0308.o -+obj-$(CONFIG_SENSOR_OV2643) += camera_ov2643.o -+obj-$(CONFIG_SENSOR_OV7725) += camera_ov7725.o -+obj-$(CONFIG_SENSOR_HM1375) += camera_hm1375.o -+obj-$(CONFIG_SENSOR_OV9712) += camera_ov9712.o -+obj-$(CONFIG_SENSOR_OV2710) += camera_ov2710.o -+obj-$(CONFIG_SENSOR_AR0130) += camera_ar0130.o -+ -+# wrap sensor -+obj-$(CONFIG_LINUX_AKSENSOR) += wrap_sensor.o aksensor.o -diff --git a/drivers/media/video/plat-anyka/ak39_isp.c b/drivers/media/video/plat-anyka/ak39_isp.c -new file mode 100755 -index 00000000..23073a21 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/ak39_isp.c -@@ -0,0 +1,2166 @@ -+#include <linux/slab.h> -+#include <linux/hardirq.h> -+#include <linux/delay.h> -+#include <linux/dma-mapping.h> -+#include <asm/cacheflush.h> -+#include <plat-anyka/aksensor.h> -+ -+#include "ak39_isp.h" -+ -+//#define ISP_DEBUG -+#ifdef ISP_DEBUG -+#define isp_dbg(stuff...) printk(KERN_INFO " ISP: " stuff) -+#else -+#define isp_dbg(fmt, args...) do{}while(0) -+#endif -+ -+#define isp_info(stuff...) printk(KERN_INFO " ISP: " stuff) -+ -+#define BRIGHTNESS_CHART_SIZE 64 -+#define HISTOGRAM_SIZE (1024*3) -+ -+static unsigned long histo_arr[256] = {0}; -+ -+//the gamma_table by called build_gamma_table() -+unsigned long gamma_table[7][BRIGHTNESS_CHART_SIZE] = { -+ { 0x15141312, 0x18171615, 0x1b1b1a19, 0x1f1e1d1c, 0x22212120, //disable gamma -+ 0x26252423, 0x29282727, 0x2d2c2b2a, 0x302f2e2d, 0x33333231, -+ 0x37363534, 0x3a393838, 0x3e3d3c3b, 0x41403f3e, 0x44444342, -+ 0x48474645, 0x4b4a4a49, 0x4f4e4d4c, 0x52515050, 0x56555453, -+ 0x59585756, 0x5c5c5b5a, 0x605f5e5d, 0x63626261, 0x67666564, -+ 0x6a696868, 0x6e6d6c6b, 0x71706f6e, 0x74747372, 0x78777675, -+ 0x7b7a7a79, 0x7f7e7d7c, 0x82818080, 0x85858483, 0x89888786, -+ 0x8c8b8b8a, 0x908f8e8d, 0x93929191, 0x97969594, 0x9a999897, -+ 0x9d9d9c9b, 0xa1a09f9e, 0xa4a3a3a2, 0xa8a7a6a5, 0xabaaa9a9, -+ 0xafaeadac, 0xb2b1b0af, 0xb5b5b4b3, 0xb9b8b7b6, 0xbcbbbbba, -+ 0xc0bfbebd, 0xc3c2c1c1, 0xc7c6c5c4, 0xcac9c8c7, 0xcdcccccb, -+ 0xd1d0cfce, 0xd4d3d2d2, 0xd8d7d6d5, 0xdbdad9d8, 0xdededddc, -+ 0xe2e1e0df, 0xe5e4e4e3, 0xe9e8e7e6, 0xecebeaea}, -+ { 0x0c080400, 0x201c1810, 0x26252422, 0x24252626, 0x27262525, //ycx -+ 0x29282827, 0x2a2a2929, 0x2d2c2c2b, 0x31302f2e, 0x35343332, -+ 0x39383736, 0x3d3c3b3a, 0x41403f3e, 0x46454342, 0x4a494847, -+ 0x4f4e4c4b, 0x53525150, 0x58575554, 0x5c5b5a59, 0x5f5e5e5d, -+ 0x62616160, 0x65646363, 0x69676766, 0x6d6c6b6a, 0x7371706f, -+ 0x78777574, 0x7c7b7a79, 0x807f7e7d, 0x85838281, 0x89888786, -+ 0x8d8c8b8a, 0x92918f8e, 0x97959493, 0x9b9a9998, 0x9f9e9d9c, -+ 0xa3a2a1a0, 0xa7a6a5a4, 0xaaa9a9a8, 0xaeadacab, 0xb1b0b0af, -+ 0xb5b4b3b2, 0xb8b7b6b5, 0xbcbbbab9, 0xc0bfbebd, 0xc3c2c1c1, -+ 0xc6c5c4c4, 0xc8c7c7c6, 0xcacac9c9, 0xcbcbcbca, 0xcecdcccc, -+ 0xd1d0cfce, 0xd5d4d3d2, 0xd9d8d7d6, 0xdddcdbda, 0xe1e0dfde, -+ 0xe4e4e3e2, 0xe8e7e6e5, 0xecebeae9, 0xf0efeeed, 0xf3f2f1f1, -+ 0xf6f5f5f4, 0xf9f8f8f7, 0xfcfbfaf9, 0xfefefdfc}, -+ { 0x10101010, 0x11111111, 0x12121212, 0x14131313, 0x15151514, 0x17171616, 0x19191818, 0x1b1b1a1a, -+ 0x1e1e1d1c, 0x20201f1f, 0x23222121, 0x25252423, 0x28272726, 0x2b2a2a29, 0x2e2d2c2c, 0x31302f2f, -+ 0x34333232, 0x37363635, 0x3a393938, 0x3d3c3c3b, 0x403f3f3e, 0x44434241, 0x47464544, 0x4a494948, -+ 0x4d4d4c4b, 0x51504f4e, 0x54535251, 0x57565655, 0x5b5a5958, 0x5f5e5d5c, 0x62616060, 0x65646362, -+ 0x68676665, 0x6b6a6969, 0x6e6e6d6c, 0x7271706f, 0x76757473, 0x7a797877, 0x7e7d7c7b, 0x8281807f, -+ 0x87868583, 0x8c8b8988, 0x91908e8d, 0x95949492, 0x99989796, 0x9d9c9b9a, 0xa09f9f9e, 0xa4a3a2a1, -+ 0xa8a7a6a5, 0xadabaaa9, 0xb1b0afae, 0xb5b4b3b2, 0xb9b8b7b6, 0xbebdbbba, 0xc2c1c0bf, 0xc7c5c4c3, -+ 0xcbcac9c8, 0xd0cfcdcc, 0xd4d3d2d1, 0xd9d8d7d5, 0xdedcdbda, 0xe2e1e0df, 0xe7e6e5e3, 0xebebe9e8}, -+ { 0x11111010, 0x14131212, 0x16151514, 0x18181717, 0x1b1a1a19, 0x1e1d1c1c, 0x20201f1e, 0x24232221, -+ 0x27262524, 0x2a292928, 0x2e2d2c2b, 0x3231302f, 0x37363533, 0x3b3b3938, 0x403f3e3d, 0x44434241, -+ 0x49474645, 0x4d4c4b4a, 0x5251504e, 0x57565553, 0x5c5b5a58, 0x61605f5d, 0x66656462, 0x6b6a6968, -+ 0x716f6e6d, 0x76747372, 0x7b797877, 0x807e7d7c, 0x84838281, 0x89888786, 0x8e8d8b8a, 0x9291908f, -+ 0x96959493, 0x9b9a9897, 0x9e9d9c9c, 0xa2a1a09f, 0xa6a5a4a3, 0xa9a8a8a7, 0xadacabaa, 0xb0afaead, -+ 0xb3b2b1b1, 0xb6b5b4b4, 0xb9b8b7b7, 0xbbbbbab9, 0xbebebdbc, 0xc1c0c0bf, 0xc4c3c2c2, 0xc6c5c5c4, -+ 0xc8c8c7c7, 0xcbcacac9, 0xcdcdcccc, 0xd0cfcfce, 0xd2d2d1d0, 0xd4d4d3d3, 0xd7d6d6d5, 0xd9d8d8d7, -+ 0xdbdbdada, 0xdedddcdc, 0xe0dfdfde, 0xe2e2e1e0, 0xe4e4e3e3, 0xe7e6e5e5, 0xe9e8e8e7, 0xebebeae9}, -+ { 0x10101010, 0x12121111, 0x13131312, 0x15151414, 0x17161615, 0x19181817, 0x1b1b1a19, 0x1e1d1d1c, -+ 0x21201f1f, 0x25242322, 0x29282726, 0x2e2c2b2a, 0x3332302f, 0x37363534, 0x3c3b3a38, 0x41403f3d, -+ 0x47464443, 0x4d4b4a48, 0x5351504e, 0x59575654, 0x5f5d5c5a, 0x65636260, 0x6b6a6867, 0x71706e6d, -+ 0x77767473, 0x7d7c7a79, 0x8382807f, 0x89878684, 0x8e8d8b8a, 0x9392908f, 0x98969594, 0x9c9b9a99, -+ 0xa09f9e9d, 0xa4a3a2a1, 0xa8a7a6a5, 0xacabaaa9, 0xafaeadad, 0xb2b1b1b0, 0xb5b5b4b3, 0xb8b8b7b6, -+ 0xbbbabab9, 0xbebdbdbc, 0xc1c0bfbf, 0xc3c3c2c1, 0xc6c5c5c4, 0xc8c7c7c6, 0xcac9c9c8, 0xcccbcbca, -+ 0xcecdcdcc, 0xd0cfcfce, 0xd2d1d1d0, 0xd4d3d3d2, 0xd6d5d5d4, 0xd8d7d7d6, 0xdad9d9d8, 0xdcdbdbda, -+ 0xdedddddc, 0xe0dfdfde, 0xe1e1e0e0, 0xe3e3e2e2, 0xe5e5e4e4, 0xe7e7e6e6, 0xe9e9e8e8, 0xebebeaea}, -+ { 0x10101010, 0x10101010, 0x11111111, 0x12121211, 0x13131312, 0x15151414, 0x17171616, 0x1a191918, -+ 0x1e1d1c1b, 0x2221201f, 0x27262523, 0x2e2c2a29, 0x32302f2e, 0x36353433, 0x3b393837, 0x3f3e3d3c, -+ 0x45434241, 0x4a494746, 0x504e4d4b, 0x55545251, 0x5b5a5857, 0x615f5e5c, 0x67656462, 0x6d6b6a68, -+ 0x7371706e, 0x79777674, 0x7f7d7c7a, 0x85838280, 0x8b898886, 0x908f8d8c, 0x96949392, 0x9b9a9897, -+ 0xa09f9e9c, 0xa5a4a2a1, 0xa9a8a7a6, 0xaeadacaa, 0xb2b1b0af, 0xb6b5b4b3, 0xb9b9b8b7, 0xbdbcbbba, -+ 0xc0c0bfbe, 0xc4c3c2c1, 0xc7c6c5c4, 0xc9c9c8c7, 0xcccbcbca, 0xcfcecdcd, 0xd1d0d0cf, 0xd3d3d2d1, -+ 0xd5d5d4d4, 0xd7d7d6d6, 0xd9d8d8d8, 0xdbdadad9, 0xdcdcdbdb, 0xdfdedddd, 0xe1e0e0df, 0xe3e2e2e1, -+ 0xe5e4e4e3, 0xe6e6e5e5, 0xe7e7e7e6, 0xe8e8e8e7, 0xe9e9e8e8, 0xe9e9e9e9, 0xeaeaeaea, 0xebebeaea}, -+ { 0x15131110, 0x1c1a1817, 0x23211f1e, 0x2a282725, 0x32302e2c, 0x39383634, 0x3d3c3b3a, 0x42413f3e, -+ 0x46454443, 0x4b4a4948, 0x504f4e4c, 0x55545251, 0x5a595756, 0x5f5e5c5b, 0x64636260, 0x68676666, -+ 0x6c6b6a69, 0x706f6e6d, 0x74737271, 0x78777675, 0x7c7b7a79, 0x807f7e7d, 0x84838281, 0x89888785, -+ 0x8d8c8b8a, 0x91908f8e, 0x95949392, 0x99989796, 0x9c9b9a99, 0x9f9e9d9c, 0xa2a1a0a0, 0xa5a4a4a3, -+ 0xa8a7a7a6, 0xabaaaaa9, 0xaeadadac, 0xb1b0b0af, 0xb4b3b3b2, 0xb7b6b5b5, 0xbab9b8b8, 0xbcbcbbba, -+ 0xbfbfbebd, 0xc2c1c1c0, 0xc5c4c3c3, 0xc7c7c6c5, 0xc9c9c8c8, 0xcbcacaca, 0xcdcccccb, 0xcfcececd, -+ 0xd1d0d0cf, 0xd3d2d2d1, 0xd4d4d3d3, 0xd6d6d5d5, 0xd8d8d7d7, 0xdad9d9d8, 0xdcdbdbda, 0xdddddcdc, -+ 0xdfdfdede, 0xe1e0e0df, 0xe2e2e2e1, 0xe4e4e3e3, 0xe6e5e5e5, 0xe8e7e7e6, 0xe9e9e8e8, 0xebebeaea}, -+}; -+ -+/* YUV 640x480, continuous mode, temporarily used */ -+void setup_yuv_video_out(struct isp_struct *pcdev) -+{ -+ pcdev->isp_ctrltbl[3] = 0x00000000; -+ pcdev->isp_ctrltbl[4] = 0x00000000; -+ pcdev->isp_ctrltbl[5] = 0x00000000; -+ pcdev->isp_ctrltbl[6] = 0x00000000; -+ pcdev->isp_ctrltbl[7] = 0x00000000; -+ pcdev->isp_ctrltbl[8] = 0x00000000; -+ pcdev->isp_ctrltbl[9] = 0x00000000; -+ pcdev->isp_ctrltbl[10] = 0x00000000; -+ pcdev->isp_ctrltbl[11] = 0x00000000; -+ pcdev->isp_ctrltbl[12] = 0x00000000; -+ pcdev->isp_ctrltbl[13] = 0x00001c68; -+ pcdev->isp_ctrltbl[14] = 0x00005538; -+ pcdev->isp_ctrltbl[15] = 0x00008e08; -+ pcdev->isp_ctrltbl[16] = 0x4000c6d8; -+ pcdev->isp_ctrltbl[23] = 0x00000000; -+ pcdev->isp_ctrltbl[24] = 0x00000000; -+ pcdev->isp_ctrltbl[27] = 0x00022bb0; -+ pcdev->isp_ctrltbl[28] = 0x0027bbb0; -+ pcdev->isp_ctrltbl[29] = 0x00000000; -+ pcdev->isp_ctrltbl[30] = 0x00000000; -+ pcdev->isp_ctrltbl[31] = 0x00000000; -+ -+ pcdev->img_ctrltbl1[15] = 0x00000000; -+ -+ pcdev->osd_chktbl[0] = 0x00008080; -+ pcdev->osd_chktbl[1] = 0x00ff8080; -+ pcdev->osd_chktbl[2] = 0x00c08080; -+ pcdev->osd_chktbl[3] = 0x00266ac0; -+ pcdev->osd_chktbl[4] = 0x0071408a; -+ pcdev->osd_chktbl[5] = 0x004b554a; -+ pcdev->osd_chktbl[6] = 0x00599540; -+ pcdev->osd_chktbl[7] = 0x000ec075; -+ pcdev->osd_chktbl[8] = 0x0034aab5; -+ pcdev->osd_chktbl[9] = 0x00786085; -+ pcdev->osd_chktbl[10] = 0x002c8aa0; -+ pcdev->osd_chktbl[11] = 0x0068d535; -+ pcdev->osd_chktbl[12] = 0x0034aa5a; -+ pcdev->osd_chktbl[13] = 0x0043e9ab; -+ pcdev->osd_chktbl[14] = 0x004b55a5; -+ pcdev->osd_chktbl[15] = 0x00008080; -+ pcdev->osd_chktbl[16] = 0x00000000; -+ pcdev->osd_chktbl[17] = 0x00000000; -+ pcdev->osd_chktbl[18] = 0x00000000; -+ pcdev->osd_chktbl[19] = 0x00000000; -+ pcdev->osd_chktbl[20] = 0x00000000; -+ pcdev->osd_chktbl[21] = 0x00000000; -+ pcdev->osd_chktbl[22] = 0x00000000; -+ pcdev->osd_chktbl[23] = 0x00000000; -+ pcdev->osd_chktbl[24] = 0x00000000; -+ pcdev->osd_chktbl[25] = 0x00000000; -+ pcdev->osd_chktbl[26] = 0x00000000; -+ pcdev->osd_chktbl[27] = 0x00000000; -+ pcdev->osd_chktbl[28] = 0x00000000; -+ pcdev->osd_chktbl[29] = 0x00000000; -+ pcdev->osd_chktbl[30] = 0x00000000; -+ pcdev->osd_chktbl[31] = 0x00000000; -+ -+ pcdev->img_ctrltbl2[25] = 0x00000000; -+ pcdev->img_ctrltbl2[26] = 0x00009000; -+} -+ -+ -+void setup_yuv_video_bypass(struct isp_struct *pcdev) -+{ -+ pcdev->isp_ctrltbl[3] = 0x00000000; -+ pcdev->isp_ctrltbl[4] = 0x00000000; -+ pcdev->isp_ctrltbl[5] = 0x00000000; -+ pcdev->isp_ctrltbl[6] = 0x00000000; -+ pcdev->isp_ctrltbl[7] = 0x00000000; -+ pcdev->isp_ctrltbl[8] = 0x00000000; -+ pcdev->isp_ctrltbl[9] = 0x00000000; -+ pcdev->isp_ctrltbl[10] = 0x00000000; -+ pcdev->isp_ctrltbl[11] = 0x00000000; -+ pcdev->isp_ctrltbl[12] = 0x00000000; -+ pcdev->isp_ctrltbl[13] = 0x00001c68; -+ pcdev->isp_ctrltbl[14] = 0x00005538; -+ pcdev->isp_ctrltbl[15] = 0x00008e08; -+ pcdev->isp_ctrltbl[16] = 0x4000c6d8; -+ pcdev->isp_ctrltbl[23] = 0x00000000; -+ pcdev->isp_ctrltbl[24] = 0x00000000; -+ pcdev->isp_ctrltbl[27] = 0x0001e0f8; -+ pcdev->isp_ctrltbl[28] = 0x002770f8; -+ pcdev->isp_ctrltbl[29] = 0x00000000; -+ pcdev->isp_ctrltbl[30] = 0x00000000; -+ pcdev->isp_ctrltbl[31] = 0x00000000; -+ -+ pcdev->img_ctrltbl1[15] = 0x00000000; -+ -+ //0x2000002c -+// memset(pcdev->osd_chktbl, 0 , sizeof(pcdev->osd_chktbl)); -+ pcdev->osd_chktbl[0] = 0x00008080; -+ pcdev->osd_chktbl[1] = 0x00ff8080; -+ pcdev->osd_chktbl[2] = 0x00c08080; -+ pcdev->osd_chktbl[3] = 0x00266ac0; -+ pcdev->osd_chktbl[4] = 0x0071408a; -+ pcdev->osd_chktbl[5] = 0x004b554a; -+ pcdev->osd_chktbl[6] = 0x00599540; -+ pcdev->osd_chktbl[7] = 0x000ec075; -+ pcdev->osd_chktbl[8] = 0x0034aab5; -+ pcdev->osd_chktbl[9] = 0x00786085; -+ pcdev->osd_chktbl[10] = 0x002c8aa0; -+ pcdev->osd_chktbl[11] = 0x0068d535; -+ pcdev->osd_chktbl[12] = 0x0034aa5a; -+ pcdev->osd_chktbl[13] = 0x0043e9ab; -+ pcdev->osd_chktbl[14] = 0x004b55a5; -+ pcdev->osd_chktbl[15] = 0x00008080; -+ pcdev->osd_chktbl[16] = 0x00000000; -+ pcdev->osd_chktbl[17] = 0x00000000; -+ pcdev->osd_chktbl[18] = 0x00000000; -+ pcdev->osd_chktbl[19] = 0x00000000; -+ pcdev->osd_chktbl[20] = 0x00000000; -+ pcdev->osd_chktbl[21] = 0x00000000; -+ pcdev->osd_chktbl[22] = 0x00000000; -+ pcdev->osd_chktbl[23] = 0x00000000; -+ pcdev->osd_chktbl[24] = 0x00000000; -+ pcdev->osd_chktbl[25] = 0x00000000; -+ pcdev->osd_chktbl[26] = 0x00000000; -+ pcdev->osd_chktbl[27] = 0x00000000; -+ pcdev->osd_chktbl[28] = 0x00000000; -+ pcdev->osd_chktbl[29] = 0x00000000; -+ pcdev->osd_chktbl[30] = 0x00000000; -+ pcdev->osd_chktbl[31] = 0x00000000; -+ -+ pcdev->img_ctrltbl2[25] = 0x00000000; -+ pcdev->img_ctrltbl2[26] = 0x00000000; -+} -+ -+void setup_rgb_video(struct isp_struct *pcdev) -+{ -+ pcdev->isp_ctrltbl[3] = 0x00000000; -+ pcdev->isp_ctrltbl[4] = 0x00000000; -+ pcdev->isp_ctrltbl[5] = 0x00000000; -+ pcdev->isp_ctrltbl[6] = 0x00000000; -+ pcdev->isp_ctrltbl[7] = 0x00000000; -+ pcdev->isp_ctrltbl[8] = 0x00000000; -+ pcdev->isp_ctrltbl[9] = 0x00000000; -+ pcdev->isp_ctrltbl[10] = 0x00000000; -+ pcdev->isp_ctrltbl[11] = 0x00000000; -+ pcdev->isp_ctrltbl[12] = 0x00000000; -+ pcdev->isp_ctrltbl[13] = 0x00005fbd; -+ pcdev->isp_ctrltbl[14] = 0x00011f37; -+ pcdev->isp_ctrltbl[15] = 0x0001deb1; -+ pcdev->isp_ctrltbl[16] = 0x40029e2b; -+ pcdev->isp_ctrltbl[23] = 0x00000000; -+ pcdev->isp_ctrltbl[24] = 0x00000000; -+ pcdev->isp_ctrltbl[27] = 0x0001ed68; -+ pcdev->isp_ctrltbl[28] = 0x01537168; -+ pcdev->isp_ctrltbl[29] = 0x00000000; -+ pcdev->isp_ctrltbl[30] = 0x00000000; -+ pcdev->isp_ctrltbl[31] = 0x00000000; -+ -+ pcdev->img_ctrltbl1[15] = 0x00000000; -+ -+ //0x2000002c -+ pcdev->osd_chktbl[0] = 0x00008080; -+ pcdev->osd_chktbl[1] = 0x00ff8080; -+ pcdev->osd_chktbl[2] = 0x00c08080; -+ pcdev->osd_chktbl[3] = 0x00266ac0; -+ pcdev->osd_chktbl[4] = 0x0071408a; -+ pcdev->osd_chktbl[5] = 0x004b554a; -+ pcdev->osd_chktbl[6] = 0x00599540; -+ pcdev->osd_chktbl[7] = 0x000ec075; -+ pcdev->osd_chktbl[8] = 0x0034aab5; -+ pcdev->osd_chktbl[9] = 0x00786085; -+ pcdev->osd_chktbl[10] = 0x002c8aa0; -+ pcdev->osd_chktbl[11] = 0x0068d535; -+ pcdev->osd_chktbl[12] = 0x0034aa5a; -+ pcdev->osd_chktbl[13] = 0x0043e9ab; -+ pcdev->osd_chktbl[14] = 0x004b55a5; -+ pcdev->osd_chktbl[15] = 0x00008080; -+ pcdev->osd_chktbl[16] = 0x00000000; -+ pcdev->osd_chktbl[17] = 0x00000000; -+ pcdev->osd_chktbl[18] = 0x00000000; -+ pcdev->osd_chktbl[19] = 0x00000000; -+ pcdev->osd_chktbl[20] = 0x00000000; -+ pcdev->osd_chktbl[21] = 0x00000000; -+ pcdev->osd_chktbl[22] = 0x00000000; -+ pcdev->osd_chktbl[23] = 0x00000000; -+ pcdev->osd_chktbl[24] = 0x00000000; -+ pcdev->osd_chktbl[25] = 0x00000000; -+ pcdev->osd_chktbl[26] = 0x00000000; -+ pcdev->osd_chktbl[27] = 0x00000000; -+ pcdev->osd_chktbl[28] = 0x00000000; -+ pcdev->osd_chktbl[29] = 0x00000000; -+ pcdev->osd_chktbl[30] = 0x00000000; -+ pcdev->osd_chktbl[31] = 0x00000000; -+ -+ pcdev->img_ctrltbl2[25] = 0x00000000; -+ pcdev->img_ctrltbl2[26] = 0x00008800; -+} -+ -+void isp_restart_update_param(struct isp_struct *isp) -+{ -+ // disable the status, then enable -+ REG32(isp->base + ISP_IRQ_STATUS) |= -+ (1 << (12+ISP_FRAME_UPDATE))|(1 << ISP_FRAME_UPDATE); -+} -+ -+void isp_update_regtable(struct isp_struct *isp, int force) -+{ -+ if (force) -+ REG32(isp->base + ISP_ORDER_CTRL) = ((3<<30) | (isp->addr & 0x3fffffff)); -+ else -+ REG32(isp->base + ISP_ORDER_CTRL) = ((1<<31) | (isp->addr & 0x3fffffff)); -+} -+ -+ -+int update_cur_mode_class(struct isp_struct *isp) -+{ -+ switch(isp->cur_mode) { -+ case ISP_JPEG_MODE: -+ case ISP_JPEG_VIDEO: -+ isp->cur_mode_class = ISP_JPEG_CLASS; -+ break; -+ case ISP_YUV_OUT: -+ case ISP_YUV_BYPASS: -+ case ISP_YUV_MERGER_OUT: -+ case ISP_YUV_BIG: -+ case ISP_YUV_VIDEO_OUT: -+ case ISP_YUV_VIDEO_BYPASS: -+ case ISP_YUV_VIDEO_MERGER_OUT: -+ isp->cur_mode_class = ISP_YUV_CLASS; -+ break; -+ case ISP_RGB_OUT: -+ case ISP_RGB_VIDEO_OUT: -+ case ISP_RGB_BIG: -+ isp->cur_mode_class = ISP_RGB_CLASS; -+ break; -+ } -+ return 0; -+} -+static void __isp_set_white_pram(struct isp_struct *isp, -+ unsigned int co_g, unsigned int co_r, unsigned int co_b) -+{ -+ isp->img_ctrltbl1[0] &= ~(0xffffff); -+ isp->img_ctrltbl1[1] &= ~(0xfff); -+ isp->img_ctrltbl1[0] |= ((co_g & 0xfff) << 12)|(co_r & 0xfff); -+ isp->img_ctrltbl1[1] |= (co_b & 0xfff); -+} -+ -+static int isp_set_auto_wb_support(struct isp_struct *isp, -+ struct isp_auto_white_balance *ctrl) -+{ -+ int i; -+ -+ for (i = 0; i < 6; i++) -+ isp->isp_ctrltbl[17+i] &= ~(0x3ff << 22); -+ isp->isp_ctrltbl[25] = 0x0; -+ isp->isp_ctrltbl[26] = 0x0; -+ -+ isp->isp_ctrltbl[17] |= ((ctrl->r_high & 0x3ff) << 22); -+ isp->isp_ctrltbl[18] |= ((ctrl->r_low & 0x3ff) << 22); -+ isp->isp_ctrltbl[19] |= ((ctrl->g_high & 0x3ff) << 22); -+ isp->isp_ctrltbl[20] |= ((ctrl->g_low & 0x3ff) << 22); -+ isp->isp_ctrltbl[21] |= ((ctrl->b_high & 0x3ff) << 22); -+ isp->isp_ctrltbl[22] |= ((ctrl->b_low & 0x3ff) << 22); -+ -+ // enable white balance calculate -+ isp->isp_ctrltbl[25] = (1 << 31)|((ctrl->grb_high & 0x3ff) << 20) -+ |((ctrl->grb_low & 0x3ff) << 10) -+ |(ctrl->gr_low & 0x3ff); -+ isp->isp_ctrltbl[26] = ((ctrl->gb_high & 0x3ff) << 20) -+ |((ctrl->gb_high & 0x3ff) << 10) -+ |(ctrl->gb_low & 0x3ff); -+ -+ -+ isp->wb_param.co_g = 1024; -+ isp->wb_param.co_r = 1024; -+ isp->wb_param.co_b = 1024; -+ -+ __isp_set_white_pram(isp, isp->wb_param.co_g, -+ isp->wb_param.co_r, isp->wb_param.co_b); -+ return 0; -+} -+ -+static void __isp_set_color_crr(struct isp_struct *isp, struct isp_color_correct *ctrl, -+ int row, int col) -+{ -+ int min[3][3]; -+ unsigned long cmd = 0; -+ int value, i, j; -+ -+ memset(min, 0, 9 * sizeof(int)); -+ min[0][0] = min[1][1] = min[2][2] = (1 << 10); -+ -+ if (ctrl->cc_thrs_high - ctrl->cc_thrs_low <= 1) { -+ ctrl->cc_thrs_high = ctrl->cc_thrs_low + 1; -+ } -+ -+ for (i = 0; i < row; i++) { -+ for (j= 0; j<col; j++) -+ isp_dbg(" ctrl->ccMtrx[%d][%d] = %d\n", i, j, ctrl->ccMtrx[i][j]); -+ } -+ -+ for (i = 0; i < row; i++) { -+ ctrl->ccMtrx[i][0] = (ctrl->ccMtrx[i][0] > 2560)? 2560 -+ : ((ctrl->ccMtrx[i][0] < -2560) ? (-2560) : ctrl->ccMtrx[i][0]); -+ ctrl->ccMtrx[i][1] = (ctrl->ccMtrx[i][1] > 2560)? 2560 -+ : ((ctrl->ccMtrx[i][1] < -2560) ? (-2560) : ctrl->ccMtrx[i][1]); -+ ctrl->ccMtrx[i][2] = (ctrl->ccMtrx[i][2] > 2560)? 2560 -+ : ((ctrl->ccMtrx[i][2] < -2560) ? (-2560) : ctrl->ccMtrx[i][2]); -+ -+ value = (ctrl->ccMtrx[i][0] - min[i][0])/(ctrl->cc_thrs_high - ctrl->cc_thrs_low); -+ cmd = ((value & 0x1fff) << CC_CALVAL_BIT) | ((ctrl->ccMtrx[i][0] & 0x1fff) << CC_TMPVAL_BIT); -+ isp->img_ctrltbl1[2+3*i] = cmd; -+ -+ value = (ctrl->ccMtrx[i][1] - min[i][1])/(ctrl->cc_thrs_high - ctrl->cc_thrs_low); -+ cmd = ((value & 0x1fff) << CC_CALVAL_BIT) | ((ctrl->ccMtrx[i][1] & 0x1fff) << CC_TMPVAL_BIT); -+ isp->img_ctrltbl1[2+3*i+1] = cmd; -+ -+ value = (ctrl->ccMtrx[i][2] - min[i][2])/(ctrl->cc_thrs_high - ctrl->cc_thrs_low); -+ cmd = ((value & 0x1fff) << CC_CALVAL_BIT) | ((ctrl->ccMtrx[i][2] & 0x1fff) << CC_TMPVAL_BIT); -+ isp->img_ctrltbl1[2+3*i+2] = cmd; -+ } -+ -+ // enable color correction -+ isp->img_ctrltbl1[11] |= ((1 << 31)|((ctrl->cc_thrs_high & 0x7ff) << 11) -+ |(ctrl->cc_thrs_low & 0x7ff)); -+} -+ -+static void __isp_set_uv_saturation(struct isp_struct *isp, struct isp_saturation *ctrl) -+{ -+ ctrl->Chigh = (ctrl->Chigh > 255) ? 255 : (ctrl->Chigh < 0) ? 0 : ctrl->Chigh; -+ ctrl->Clow = (ctrl->Clow > 255) ? 255 : (ctrl->Clow < 0) ? 0 : ctrl->Clow; -+ -+ if (ctrl->Chigh <= ctrl->Clow) -+ ctrl->Chigh = ctrl->Clow + 1; -+ -+ if (ctrl->Khigh <= ctrl->Klow) -+ ctrl->Khigh = ctrl->Klow + 1; -+ -+ // enable saturation adjust -+ ctrl->Kslope = (ctrl->Khigh - ctrl->Klow) * 256 / (ctrl->Chigh - ctrl->Clow); -+ isp->img_ctrltbl1[13] |= (1 << 31)|(ctrl->Klow << 20)|(ctrl->Khigh << 10)|ctrl->Kslope; -+ isp->img_ctrltbl1[14] |= (ctrl->Chigh << 24)|(ctrl->Clow << 16); -+} -+ -+static void __isp_set_brigtness(struct isp_struct *isp, -+ struct isp_brightness_enhance *ctrl) -+{ -+ ctrl->y_thrs = (ctrl->y_thrs > 2048) ? 2048 : ctrl->y_thrs; -+ ctrl->y_edgek = (ctrl->y_edgek > 2048) ? 2048 : ctrl->y_edgek; -+ ctrl->ygain = (ctrl->ygain > 64) ? 63 : -+ ((ctrl->ygain < -64) ? -63 : ctrl->ygain); -+ -+ isp->img_ctrltbl1[12] = (ctrl->ygain << Y_GAIN_BIT) -+ |(((ctrl->y_thrs * 9) & 0x7ff) << Y_EDGE_THRS_BIT) -+ |((ctrl->y_edgek & 0x7ff) << Y_EDGE_K_BIT); -+ -+ // enable edge(brightness) adjust -+ isp->img_ctrltbl1[11] |= (1 << 29); -+ // enable iso filter -+ //isp->img_ctrltbl1[13] |= (1 << 30); -+} -+ -+static void __isp_set_gamma(struct isp_struct *isp, unsigned long *gamma) -+{ -+ int i; -+ -+ for(i = 0; i < BRIGHTNESS_CHART_SIZE; i++) { -+ isp->img_lumitbl[i] = gamma[i]; -+ } -+} -+ -+static void __isp_clear_lens_param(struct isp_struct *isp) -+{ -+ int i; -+ -+ for (i = 0; i < 10; i++) -+ isp->isp_ctrltbl[3+i] = 0x0; -+ -+ for (i = 0; i < 10; i++) -+ isp->isp_ctrltbl[13+i] &= ~(0x3fffff); -+ -+ isp->isp_ctrltbl[23] = 0x0; -+ isp->isp_ctrltbl[24] = 0x0; -+} -+ -+static void __isp_set_lens_correct(struct isp_struct *isp, struct isp_lens_correct *ctrl) -+{ -+ int width = isp->lens_use_width; -+ int height = isp->lens_use_height; -+ unsigned long cmd; -+ int value = 0, i; -+ -+ // lens coef setting -+ for (i = 0; i < 10; i++) { -+ ctrl->lens_coefa[i] = (ctrl->lens_coefa[i] > 1023)?1023 -+ : ((ctrl->lens_coefa[i] < -1023) ? (-1023): ctrl->lens_coefa[i]); -+ ctrl->lens_coefb[i] = (ctrl->lens_coefb[i] > 1023)?1023 -+ : ((ctrl->lens_coefb[i] < -1023) ? (-1023): ctrl->lens_coefb[i]); -+ ctrl->lens_coefc[i] = (ctrl->lens_coefc[i] > 511)?511 -+ : ((ctrl->lens_coefc[i] < -511) ? (-511): ctrl->lens_coefc[i]); -+ -+ isp->isp_ctrltbl[3+i] = ((ctrl->lens_coefa[i] & 0x7ff) << LENS_COEFA_BIT) -+ |((ctrl->lens_coefb[i] & 0x7ff) << LENS_COEFB_BIT) -+ |(ctrl->lens_coefc[i] & 0x3ff); -+ } -+ -+ if ((width <= 0) || (height <= 0)) { -+ width = isp->fmt_width; -+ height = isp->fmt_height; -+ } -+ -+ // lens range setting -+ value = (width/2) * (width/2) + (height/2) * (height/2); -+ cmd = value / 22; -+ for (i = 0; i < 10; i++) { -+ isp->isp_ctrltbl[13+i] |= (cmd * (2*i+1)) & 0x3fffff; -+ } -+ -+ isp->isp_ctrltbl[23] = ((ctrl->lens_yref & 0x1fff) << LENS_YREF_BIT) -+ |(ctrl->lens_xref & 0x1fff); -+ isp->isp_ctrltbl[24] = (1 << 31)|(((ctrl->lens_xref * ctrl->lens_xref) -+ + (ctrl->lens_yref * ctrl->lens_yref)) & 0x7ffffff); -+} -+ -+ -+int isp_check_irq(struct isp_struct *isp) -+{ -+ unsigned int irq_status; -+ int retval = 0; -+ //int ch_flag = 0; -+ -+ irq_status = REG32(isp->base + ISP_IRQ_STATUS); -+ //printk("isp irq: %#x, %d\n", irq_status, ((irq_status >> 27) & 0x1f)); -+ if (!(irq_status & (1 << ISP_FRAME_UPDATE))) { -+ isp_restart_update_param(isp); -+ isp_update_regtable(isp, 1); -+ retval = -EINTR; -+ } -+ -+ if (irq_status & (1 << ISP_FRAME_UPDATE)) { -+ if (isp->auto_wb_param_en) -+ isp_update_auto_wb_param(isp); -+ -+ //isp_set_histogram(isp, NULL); -+ //isp_get_histogram(isp); -+ } -+ -+#if 0 -+ if (irq_status & (1 << ISP_CH1_UPDMA_OVERFLOW)) { -+ printk("ch1 updma overflow\n"); -+ } -+ -+ if (!(irq_status & (1<<ISP_CH1_ONE_FRAME_END))) { -+ REG32(isp->base + ISP_IRQ_STATUS) |= -+ (1<<(12+ISP_CH1_ONE_FRAME_END))|(1<<ISP_CH1_ONE_FRAME_END); -+ ch_flag = 1; -+ } -+ -+ if (isp->chl2_enable) { -+ if (!(irq_status & (1<<ISP_CH2_ONE_FRAME_END))) { -+ REG32(isp->base + ISP_IRQ_STATUS) |= -+ (1<<(12+ISP_CH2_ONE_FRAME_END))|(1<<ISP_CH2_ONE_FRAME_END); -+ ch_flag = 1; -+ } -+ } -+ -+ if (ch_flag) { -+ isp_stop_capturing(isp); -+ //udelay(100); -+ isp_start_capturing(isp); -+ retval = -EINTR; -+ } -+ -+ if (irq_status & (1<<ISP_BIG_PIC_MODE_DONE)) -+ retval = 0; -+#endif -+ -+ if (retval < 0) { -+ printk("ISP interrupt exception. irq status=0x%08x\n", irq_status); -+ } -+ -+ return retval; -+} -+ -+int isp_clear_irq_status(struct isp_struct *isp) -+{ -+ REG32(isp->base + ISP_IRQ_STATUS) |= 0x7ff; -+ return 0; -+} -+ -+int isp_clear_irq(struct isp_struct *isp) -+{ -+ REG32(isp->base + ISP_IRQ_STATUS) = 0; -+ return 0; -+} -+ -+void isp_set_even_frame(struct isp_struct *isp, -+ unsigned long yaddr_chl1, unsigned long yaddr_chl2) -+{ -+ int size; -+ -+ size = isp->chl1_width * isp->chl1_height; -+ isp->img_ctrltbl2[12] = yaddr_chl1; -+ isp->img_ctrltbl2[14] = yaddr_chl1 + size; -+ isp->img_ctrltbl2[16] = yaddr_chl1 + size * 5 / 4; -+ -+ if (isp->chl2_enable) { -+ size = isp->chl2_width * isp->chl2_height; -+ //isp->img_ctrltbl2[18] &= (3 << 30); -+ isp->img_ctrltbl2[18] = yaddr_chl2 & ~(3 << 30); -+ isp->img_ctrltbl2[20] = yaddr_chl2 + size; -+ isp->img_ctrltbl2[22] = yaddr_chl2 + size * 5 /4; -+ } -+} -+ -+void isp_set_odd_frame(struct isp_struct *isp, -+ unsigned long yaddr_chl1, unsigned long yaddr_chl2) -+{ -+ int size; -+ -+ size = isp->chl1_width * isp->chl1_height; -+ isp->img_ctrltbl2[13] = yaddr_chl1; -+ isp->img_ctrltbl2[15] = yaddr_chl1 + size; -+ isp->img_ctrltbl2[17] = yaddr_chl1 + size * 5 / 4; -+ -+ if (isp->chl2_enable) { -+ size = isp->chl2_width * isp->chl2_height; -+ isp->img_ctrltbl2[19] = yaddr_chl2; -+ isp->img_ctrltbl2[21] = yaddr_chl2 + size; -+ isp->img_ctrltbl2[23] = yaddr_chl2 + size * 5 /4; -+ } -+} -+ -+static int update_image_size(struct isp_struct *isp) -+{ -+ int iwidth = isp->cut_width; -+ int iheight = isp->cut_height; -+ -+ // the follow setup parameter only ov9712 -+ if (isp->cur_mode_class == ISP_RGB_CLASS) { -+ iwidth -= 4; -+ iheight -= 4; -+ } -+ -+ iwidth = (isp->demo_sac_en)?(iwidth-8):iwidth; -+ iheight = (isp->demo_sac_en)?(iheight-6):iheight; -+ -+ if (isp->uv_isoflt_en || isp->yedge_en) { -+ iwidth = iwidth - 6; -+ iheight = iheight - 6; -+ } -+ -+ iwidth = (isp->rgb_filter_en)?(iwidth-4):iwidth; -+ iheight = (isp->rgb_filter_en)?(iheight-4):iheight; -+ -+ isp->img_ctrltbl2[24] = ((iheight & 0x1fff) << OSD_SIZE_V_BIT) -+ |(iwidth & 0x1fff); -+ -+ // save is here, used for lens_range -+ isp->lens_use_width = iwidth; -+ isp->lens_use_height = iheight; -+ -+ isp_dbg("%s: osd total size[w=%d h=%d]\n", __func__, iwidth, iheight); -+ return 0; -+} -+ -+int isp_set_osd(struct isp_struct *isp, struct isp_osd_info *osd_info) -+{ -+ int base = 1; -+ -+ if (osd_info->channel == 2) -+ base = 4; -+ -+ isp->img_ctrltbl2[base] = 0; -+ isp->img_ctrltbl2[base + 1] = 0; -+ isp->img_ctrltbl2[base + 2] = 0; -+ -+ isp->img_ctrltbl2[base + 1] = ((osd_info->color_transparency & 0xf) << 28) -+ |(osd_info->start_ypos << 13) | osd_info->start_xpos; -+ isp->img_ctrltbl2[base + 2] = (osd_info->end_ypos << 13) | osd_info->end_xpos; -+ -+ if (osd_info->enable) -+ isp->img_ctrltbl2[base] = (1 << 31) | (osd_info->phys_addr & 0x3fffffff); -+ else -+ isp->img_ctrltbl2[base] = (0 << 31) | (osd_info->phys_addr & 0x3fffffff); -+ -+ return 0; -+} -+ -+int isp_set_channel1_scale(struct isp_struct *isp, int width, int height) -+{ -+ int xrate, yrate; -+ -+ if (height < 0 || width < 0) { -+ printk(KERN_ERR "%s: channel1 scale remain the same\n", __func__); -+ return -EINVAL; -+ } -+ -+ xrate = (65536)/(width - 1); -+ yrate = (65536)/(height - 1); -+ -+ isp_dbg("%s: xrate=%d yrate=%d width=%d height=%d\n", __func__, -+ xrate, yrate, width, height); -+ -+ isp->img_ctrltbl2[8] &= ~((0x1fff << 13)|0x1fff); -+ -+ isp->img_ctrltbl2[7] = (yrate << 16)|xrate; -+ isp->img_ctrltbl2[8] |= (height << 13)|width; -+ isp->img_ctrltbl2[9] |= (0xff << UPSCALE_FRAME_CTRL); -+ -+ isp->chl1_width = width; -+ isp->chl1_height = height; -+ -+ return 0; -+} -+ -+ -+int isp_set_cutter_window(struct isp_struct *isp, int xpos, int ypos, int width, int height) -+{ -+ struct isp_demosaic demosac; -+ struct isp_rgb_filter rgb_filter; -+ int iwidth = width; -+ int iheight = height; -+ -+ isp_dbg("%s. entry. iwidth=%d iheight=%d\n", __func__, -+ iwidth, iheight); -+ -+ if (width > isp->fmt_width || height > isp->fmt_height) { -+ printk(KERN_ERR"%s: invalid cutter window size\n", __func__); -+ return -EINVAL; -+ } -+ -+ if (xpos > isp->fmt_width || ypos > isp->fmt_height) { -+ printk(KERN_ERR"%s: invalid cutter window position\n", __func__); -+ return -EINVAL; -+ } -+ -+ if (width < 0 || height < 0 || xpos < 0 || ypos < 0) { -+ printk(KERN_WARNING"%s: cutter window remain the same\n", __func__); -+ return -EINVAL; -+ } -+ -+ isp->sub_sample = 0; -+ xpos -= xpos % 4; -+ -+ // the follow setup parameter only ov9712 -+ if (isp->cur_mode_class == ISP_RGB_CLASS) { -+ xpos = 3; -+ ypos = 3; -+ iwidth -= 4; -+ iheight -= 4; -+ } -+ -+ isp->isp_ctrltbl[0] = (isp->sub_sample << DSMP_RTO_BIT) -+ |(ypos << CUT_STRY_BIT)|xpos; -+ isp->isp_ctrltbl[1] = (iheight << CUT_WINH_BIT) | iwidth; -+ -+ if (isp->cur_mode_class == ISP_RGB_CLASS) { -+ demosac.enable = 1; -+ rgb_filter.enable = 1; -+ } else { -+ demosac.enable = 0; -+ rgb_filter.enable = 0; -+ } -+ -+ // should enable demo saic in RGB module -+ if (isp->demo_sac_thres <= 0) { -+ demosac.threshold = 1300; -+ isp->demo_sac_thres = demosac.threshold; -+ } else -+ demosac.threshold = isp->demo_sac_thres; -+ isp_set_demosaic(isp, &demosac); -+ -+ // enable rgb filter (noise remove) -+ if (isp->rgb_filter_thres <= 0) { -+ rgb_filter.threshold = 142; -+ isp->rgb_filter_thres = rgb_filter.threshold; -+ } else -+ rgb_filter.threshold = isp->rgb_filter_thres; -+ isp_set_rgb_filter(isp, &rgb_filter); -+ -+ isp->cut_width = width; -+ isp->cut_height = height; -+ -+ update_image_size(isp); -+ return 0; -+} -+ -+int isp_set_channel2(struct isp_struct *isp, struct isp_channel2_info *chl2_info) -+{ -+ int width = chl2_info->width; -+ int height = chl2_info->height; -+ -+ isp_dbg("%s:\n\twidth=%d height=%d isp->chl1_width=%d isp->chl1_height=%d chl2_info->enable=%d\n", -+ __func__, width, height, isp->chl1_width, isp->chl1_height, chl2_info->enable); -+ -+ if ((isp->cur_mode_class == ISP_RGB_CLASS) -+ &&((isp->fmt_def_width == 640)||(isp->fmt_def_height == 480)) -+ &&((width == 640)||(height == 480))) { -+ printk(KERN_ERR "isp: chl2 isn't support VGA output as sensor VGA input\n"); -+ return -EINVAL; -+ } -+ -+ /* CH2 support output size up to as follow */ -+ if ((width > 720) || (height > 576)) { -+ printk(KERN_ERR "isp: size is higher, chl2 isn't support.\n"); -+ return -EINVAL; -+ } -+ -+ if ((isp->chl1_width < width)||(isp->chl1_height < height)) { -+ printk(KERN_ERR "%s: wrong channel2 width and height.\n", __func__); -+ return -EINVAL; -+ } -+ -+ isp->img_ctrltbl2[10] = (65536 / (height-1) << 16) | (65536 / (width -1)); -+ isp->img_ctrltbl2[11] = (height << 10) | width; -+ -+ /* Enable channel 2 */ -+ if (chl2_info->enable) { -+ isp->img_ctrltbl2[9] |= 0xff << 24; -+ } else { -+ isp->img_ctrltbl2[9] &= ~(0xff << 24); -+ } -+ -+ isp->chl2_width = width; -+ isp->chl2_height = height; -+ isp->chl2_enable = chl2_info->enable; -+ -+ return 0; -+} -+ -+int isp_set_occlusion_area(struct isp_struct *isp, struct isp_occlusion_info *oclu_info) -+{ -+ int target_area; -+ -+ if (oclu_info->number > 4 || oclu_info->number < 1) -+ return -EINVAL; -+ -+ target_area = (oclu_info->number - 1) * 2 + 16; -+ if (oclu_info->channel == 2) -+ target_area += 4 * 2; -+ -+ isp->img_ctrltbl1[target_area] = (oclu_info->start_ypos << 16) | oclu_info->start_xpos; -+ isp->img_ctrltbl1[target_area + 1] = (oclu_info->end_ypos << 16) | oclu_info->end_xpos; -+ -+ /* Enable the occlusion for target area */ -+ if (!oclu_info->enable) { -+ isp->img_ctrltbl1[target_area] &= ~(1 << 31); -+ } else { -+ isp->img_ctrltbl1[target_area] |= (1 << 31); -+ } -+ -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_occlusion_color(struct isp_struct *isp, struct isp_occlusion_color *color_info) -+{ -+ isp->img_ctrltbl2[0] = 0x0; -+ -+ isp->img_ctrltbl2[0] = ((color_info->color_type & 3) << 30) -+ |((color_info->transparency & 0xf) << 24) -+ |((color_info->y_component & 0xff) << 16) -+ |((color_info->u_component & 0xff) << 8) -+ |(color_info->v_component & 0xff); -+ -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_zoom(struct isp_struct *isp, struct isp_zoom_info *info) -+{ -+ struct isp_channel2_info chl2; -+ int offset_w = 0, offset_h = 0; -+ -+ isp_dbg("%s: entry. \ncut_xpos=%d cut_ypos=%d cut_width=%d cut_height=%d\n" -+ "out_width=%d out_height=%d channel=%d chl2_enable=%d\n", __func__, -+ info->cut_xpos, info->cut_ypos, info->cut_width, info->cut_height, -+ info->out_width, info->out_height, info->channel, isp->chl2_enable); -+ -+ if ((info->out_width > 1280) || (info->out_height > 720)) { -+ printk(KERN_ERR "isp: output scale is too big\n"); -+ return -EINVAL; -+ } -+ -+ if ((info->cut_width < 6 || info->cut_height < 6) -+ ||(info->out_width < 18 || info->out_height < 18)) { -+ printk(KERN_ERR "isp: the scale of ch1 remain the same\n"); -+ return -EINVAL; -+ } -+ -+ if (isp->cur_mode_class == ISP_RGB_CLASS) { -+ offset_w = 18; -+ offset_h = 16; -+ } else if (isp->cur_mode_class == ISP_YUV_CLASS) { -+ offset_w = 6; -+ offset_h = 6; -+ } -+ -+ if (isp->chl2_enable) { -+ // the second channel is not support up scale -+ if (info->channel == 2) { -+ if ((info->cut_width < info->out_width+offset_w)||(info->cut_height < info->out_height+offset_h)) { -+ printk(KERN_ERR "isp: ch2 isn't support up-scale.\n"); -+ return -EINVAL; -+ } -+ } else if ((info->channel == 1)||(info->channel == 0)) { -+ if ((info->cut_width < isp->chl2_width+offset_w)||(info->cut_height < isp->chl2_height+offset_h)) { -+ printk(KERN_ERR "isp: cut window should be larger than ch2 output.\n"); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ // enable master channel default, 0 also indicate ch1 -+ if ((info->channel == 1) || (info->channel == 0)) { -+ // the master channel support up-scale ratio up to is 3 -+ if (info->out_width > info->cut_width * 3 || info->out_height > info->cut_height * 3) { -+ printk(KERN_ERR "isp: ch1 up-scale ratio too big\n"); -+ return -EINVAL; -+ } -+ -+ // the master channel support down-scale up to is 1/2 -+ if ((info->out_width < (info->cut_width >> 1)) -+ || (info->out_height < (info->cut_height >> 1))) { -+ printk(KERN_ERR "isp: ch1 down-scale ratio too big\n"); -+ return -EINVAL; -+ } -+ -+ if (isp_set_channel1_scale(isp, info->out_width, info->out_height) < 0) -+ return -EINVAL; -+ -+ -+ } else if ((info->channel == 2) && (isp->chl2_enable)) { -+ // the second channel support down-scale up to is 1/8 -+ if ((info->out_width < (info->cut_width >> 3)) -+ || (info->out_height < (info->cut_height >> 3))) { -+ printk(KERN_ERR "isp: ch2 down-scale ratio too big\n"); -+ return -EINVAL; -+ } -+ -+ chl2.width = info->out_width; -+ chl2.height = info->out_height; -+ chl2.enable = 1; -+ if (isp_set_channel2(isp, &chl2) < 0) -+ return -EINVAL; -+ } -+ -+ if (isp_set_cutter_window(isp, info->cut_xpos, info->cut_ypos, info->cut_width, info->cut_height) < 0) -+ return -EINVAL; -+ return 0; -+} -+ -+int isp_set_crop(struct isp_struct *isp, struct v4l2_rect rect) -+{ -+ if (rect.width > isp->fmt_width || rect.height > isp->fmt_height) { -+ printk(KERN_ERR"%s: invalid cutter window size\n", __func__); -+ return -EINVAL; -+ } -+ -+ isp->isp_ctrltbl[0] &= (3 << DSMP_RTO_BIT); -+ if (1/*YUV_DATA*/) { //align four byte when YUV data input -+ rect.left = ALIGN(rect.left, 4); -+ } -+ isp->isp_ctrltbl[0] |= (rect.top << ISP_WIN_HEIGHT_OFFSET) | rect.left; -+ isp->isp_ctrltbl[1] = (rect.height << ISP_WIN_HEIGHT_OFFSET) | rect.width; -+ -+ //update_image_size(isp); -+ -+ return isp_set_channel1_scale(isp, rect.width, rect.height); -+} -+ -+/* *******this interface response to set image param ****** */ -+int isp_set_black_balance(struct isp_struct *isp, struct isp_black_balance *ctrl) -+{ -+ int i; -+ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ BUG_ON(ctrl == NULL); -+ -+ for (i = 0; i < 3; i++) -+ isp->isp_ctrltbl[13+i] &= ~(0x3ff << BB_PARM_BIT); -+ -+ if (ctrl->enable == 0) { -+ isp->blkb_en = 0; -+ } else { -+ isp->isp_ctrltbl[13] |= (ctrl->r_offset << BB_PARM_BIT); -+ isp->isp_ctrltbl[14] |= (ctrl->g_offset << BB_PARM_BIT); -+ isp->isp_ctrltbl[15] |= (ctrl->b_offset << BB_PARM_BIT); -+ -+ isp->blkb_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_lens_correct(struct isp_struct *isp, struct isp_lens_correct *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ BUG_ON(ctrl == NULL); -+ -+ __isp_clear_lens_param(isp); -+ -+ if (ctrl->enable == 0) { -+ isp->lens_crr_en = 0; -+ } else { -+ __isp_set_lens_correct(isp, ctrl); -+ isp->isp_ctrltbl[24] |= (1 << 31); -+ isp->lens_crr_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_demosaic(struct isp_struct *isp, struct isp_demosaic *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ BUG_ON(ctrl == NULL); -+ -+ if ((ctrl->threshold < 0)||(ctrl->threshold > 4095)) { -+ printk(KERN_ERR "invalid parameter. error\n"); -+ return -EINVAL; -+ } -+ -+ isp->isp_ctrltbl[2] = 0x0; -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) { -+ isp->demo_sac_en = 0; -+ goto out; -+ } -+ -+ // always enable demo saic for rgb -+ if (ctrl->enable == 0) { -+ isp->isp_ctrltbl[2] = (1 << 12)|(isp->demo_sac_thres & 0xfff); -+ } else { -+ isp->isp_ctrltbl[2] = (1 << 12)|(ctrl->threshold & 0xfff); -+ isp->demo_sac_thres = ctrl->threshold; -+ } -+ isp->demo_sac_en = 1; -+ -+out: -+ update_image_size(isp); -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+// noise remove -+int isp_set_rgb_filter(struct isp_struct *isp, struct isp_rgb_filter *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ BUG_ON(ctrl == NULL); -+ -+ if ((ctrl->threshold < 0)||(ctrl->threshold > 1024)) { -+ printk("invalid parameter. error\n"); -+ return -EINVAL; -+ } -+ -+ isp->img_ctrltbl1[1] &= ~(0x3ff << 12); -+ -+ //disable rgb filter -+ if (isp->cur_mode_class != ISP_RGB_CLASS) { -+ isp->img_ctrltbl1[1] &= ~(1 << 31); -+ isp->rgb_filter_en = 0; -+ isp->rgb_filter_en_flag = 0; -+ goto out; -+ } -+ -+ if (ctrl->enable == 0) { -+ if (isp->defect_pixel_en == 0) { -+ isp->img_ctrltbl1[1] &= ~(1 << 31); -+ isp->rgb_filter_en = 0; -+ } -+ isp->rgb_filter_en_flag = 0; -+ } else { //enable rgb filter and set threshold -+ isp->img_ctrltbl1[1] |= (1 << 31)|((ctrl->threshold & 0x3ff) << 12); -+ isp->rgb_filter_thres = ctrl->threshold; -+ isp->rgb_filter_en = 1; -+ isp->rgb_filter_en_flag = 1; -+ } -+out: -+ update_image_size(isp); -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_uv_iso_filter(struct isp_struct *isp, struct isp_uv_filter *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ BUG_ON(ctrl == NULL); -+ -+ if (ctrl->enable == 0) { -+ //if (isp->yedge_en == 0) { -+ isp->img_ctrltbl1[13] &= ~(1 << 30); -+ isp->uv_isoflt_en = 0; -+ //} -+ //isp->uv_isoflt_en_flag = 0; -+ } else { -+ isp->img_ctrltbl1[13] |= (1 << 30); -+ isp->uv_isoflt_en = 1; -+ //isp->uv_isoflt_en_flag = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+// bad pixel defect and fixed -+int isp_set_defect_pixel(struct isp_struct *isp, struct isp_defect_pixel *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ BUG_ON(ctrl == NULL); -+ -+ isp->img_ctrltbl1[1] &= ~(0x3 << 28); -+ -+ if (ctrl->enable == 0) { -+ //disable defect pixel remove -+ isp->img_ctrltbl1[1] &= ~(1 << 30); -+ isp->defect_pixel_en = 0; -+ -+ //disable rgb filter -+ if (isp->rgb_filter_en_flag == 0) { -+ isp->img_ctrltbl1[1] &= ~(1 << 31); -+ isp->rgb_filter_en = 0; -+ } -+ } else { -+ //enable defect pixel remove and set dfp_cf_sel -+ isp->img_ctrltbl1[1] |= (0x3 << 30)|((ctrl->threshold & 0x3) << 28); -+ isp->defect_pixel_en = 1; -+ isp->rgb_filter_en = 1; -+ } -+ -+ update_image_size(isp); -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_manu_wb(struct isp_struct *isp, struct isp_white_balance *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ BUG_ON(ctrl == NULL); -+ -+ if (ctrl->enable == 0) { -+ // disable color correction -+ ctrl->co_r = 1024; -+ ctrl->co_g = 1024; -+ ctrl->co_b = 1024; -+ -+ isp->wb_param_en = 0; -+ } else { -+ //enable manu while balance, disable auto while balance -+ isp->wb_param_en = 1; -+ isp->auto_wb_param_en = 0; -+ } -+ -+ __isp_set_white_pram(isp, ctrl->co_g, ctrl->co_r, ctrl->co_b); -+ -+ //isp_update_regtable(isp, 0); -+ -+ //save the value -+ isp->wb_param.co_r = ctrl->co_r; -+ isp->wb_param.co_g = ctrl->co_g; -+ isp->wb_param.co_b = ctrl->co_b; -+ -+ return 0; -+} -+ -+int isp_set_auto_wb(struct isp_struct *isp, struct isp_auto_white_balance *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ BUG_ON(ctrl == NULL); -+ -+ // no use auto while balance -+ if (ctrl->enable == 0) { -+ isp->wb_param.co_r = 1024; -+ isp->wb_param.co_g = 1024; -+ isp->wb_param.co_b = 1024; -+ -+ __isp_set_white_pram(isp, isp->wb_param.co_g, -+ isp->wb_param.co_r, isp->wb_param.co_b); -+ -+ // disable white balance calculate -+ isp->isp_ctrltbl[25] &= ~(1 << 31); -+ isp->auto_wb_param_en = 0; -+ } else { -+ // enable white balance calculate -+ isp_set_auto_wb_support(isp, ctrl); -+ -+ isp->wb_param_en = 0; -+ isp->auto_wb_param_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_color_correct(struct isp_struct *isp, struct isp_color_correct *ctrl) -+{ -+ int i; -+ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ BUG_ON(ctrl == NULL); -+ -+ isp->img_ctrltbl1[11] &= ~(0x3fffff); -+ for (i = 0; i < 9; i++) -+ isp->img_ctrltbl1[2+i] = 0x0; -+ -+ if (ctrl->enable == 0) { -+ // disable color correction -+ isp->img_ctrltbl1[11] &= ~(1 << 31); -+ isp->color_crr_en = 0; -+ } else { -+ __isp_set_color_crr(isp, ctrl, 3, 3); -+ isp->color_crr_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_gamma_calc(struct isp_struct *isp, struct isp_gamma_calculate *ctrl) -+{ -+ int i; -+ -+ isp_dbg("%s enter.\n", __func__); -+ -+ BUG_ON(ctrl == NULL); -+ -+ if (ctrl->enable == 0) { -+ memset(isp->img_lumitbl, 0, sizeof(unsigned long)*BRIGHTNESS_CHART_SIZE); -+ // disable brightness chart table -+ isp->img_ctrltbl1[11] &= ~(1 << 30); -+ isp->gamma_calc_en = 0; -+ -+ //isp_update_regtable(isp, 0); -+ } else { -+ if (ctrl->is_sync == 0) { -+ for(i = 0; i < 32/*BRIGHTNESS_CHART_SIZE >> 1*/; i++) -+ isp->img_lumitbl[i] = ctrl->gamma[i]; -+ } -+ -+ if (ctrl->is_sync == 1) { -+ for(i = 0; i < 32/*BRIGHTNESS_CHART_SIZE >> 1*/; i++) -+ isp->img_lumitbl[32+i] = ctrl->gamma[i]; -+ -+ // enable brightness adjust -+ isp->img_ctrltbl1[11] |= (1 << 30); -+ isp->gamma_calc_en = 1; -+ -+ //isp_update_regtable(isp, 0); -+ } -+ } -+ -+ return 0; -+} -+ -+int isp_set_brightness_enhance(struct isp_struct *isp, struct isp_brightness_enhance *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ BUG_ON(ctrl == NULL); -+ -+ isp->img_ctrltbl1[12] = 0x0; -+ -+ if (ctrl->enable == 0) { -+ // disable edge(brightness) adjust -+ isp->img_ctrltbl1[11] &= ~(1 << 29); -+ isp->yedge_en = 0; -+ #if 0 -+ // disable isofilter -+ if (isp->uv_isoflt_en_flag == 0) { -+ isp->img_ctrltbl1[13] &= ~(1 << 30); -+ isp->uv_isoflt_en = 0; -+ } -+ #endif -+ } else { -+ __isp_set_brigtness(isp, ctrl); -+ -+ isp->yedge_en = 1; -+ //isp->uv_isoflt_en = 1; -+ } -+ -+ update_image_size(isp); -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_uv_saturation(struct isp_struct *isp, struct isp_saturation *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ BUG_ON(ctrl == NULL); -+ -+ isp->img_ctrltbl1[13] &= ~0x3fffffff; -+ isp->img_ctrltbl1[14] &= ~(0xffff << 16); -+ -+ if (ctrl->enable == 0) { -+ // disable saturation adjust -+ isp->img_ctrltbl1[13] &= ~(1 << 31); -+ isp->uv_saturate_en = 0; -+ } else { -+ __isp_set_uv_saturation(isp, ctrl); -+ -+ isp->uv_saturate_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_histogram(struct isp_struct *isp, struct isp_histogram *ctrl) -+{ -+ unsigned long regval; -+ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ //BUG_ON(ctrl == NULL); -+#if 0 -+ if (ctrl->enable == 0) { -+ -+ isp->histo_en = 0; -+ } else { -+#endif -+ do { -+ regval = REG32(isp->base + ISP_HISTO_CFG); -+ } while(regval >> 31); -+ -+ REG32(isp->base + ISP_HISTO_CFG) = (1 << 31) -+ |(isp->histo_phyaddr & 0x3fffffff); -+ isp->histo_en = 1; -+// } -+ -+ return 0; -+} -+ -+int isp_set_special_effect(struct isp_struct *isp, struct isp_special_effect *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ BUG_ON(ctrl == NULL); -+ -+ isp->img_ctrltbl1[0] &= ~(0xff) << 24; -+ isp->img_ctrltbl1[14] &= ~(0xffff); -+ isp->img_ctrltbl1[15] = 0x0; -+ -+ if (ctrl->enable == 0) { -+ //disable yuv and yuv_solar -+ isp->img_ctrltbl1[11] &= ~(0x3 << 27); -+ -+ isp->yuv_effect_en = 0; -+ isp->yuv_solar_en = 0; -+ } else { -+ isp->img_ctrltbl1[0] |= (ctrl->solar_thrs & 0xff) << YUV_SOLAR_THRD_BIT; -+ isp->img_ctrltbl1[14] |= ((ctrl->y_eff_coefa < 0) << (SPEC_YCOEFA_BIT+7)) -+ |(((abs(ctrl->y_eff_coefa)) & 0x7f) << SPEC_YCOEFA_BIT) -+ |((ctrl->y_eff_coefb & 0xff) << SPEC_YCOEFB_BIT); -+ -+ isp->img_ctrltbl1[15] = ((ctrl->u_eff_coefa < 0) << (SPEC_UCOEFA_BIT+7)) -+ |(((abs(ctrl->u_eff_coefa)) & 0x7f) << SPEC_UCOEFA_BIT) -+ |(ctrl->u_eff_coefb << SPEC_UCOEFB_BIT) -+ |((ctrl->v_eff_coefa < 0) << (SPEC_VCOEFA_BIT+7)) -+ |(((abs(ctrl->v_eff_coefa)) & 0x7f) << SPEC_VCOEFA_BIT) -+ |(ctrl->v_eff_coefb << SPEC_VCOEFB_BIT); -+ -+ //enable yuv and yuv_solar -+ isp->img_ctrltbl1[11] |= (0x3 << 27); -+ isp->yuv_effect_en = 1; -+ isp->yuv_solar_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+ -+/* ~~~~~~~~~~ ISP control ~~~~~~~~~ */ -+int isp_set_brightness(struct isp_struct *isp, struct v4l2_ctrl *ctrl) -+{ -+ struct isp_brightness_enhance bl_edge; -+ -+ isp_dbg("%s. enter. ctrl->val=%d\n", __func__, ctrl->val); -+ -+ memset(&bl_edge, 0, sizeof(struct isp_brightness_yedge)); -+ isp->img_ctrltbl1[12] = 0x0; -+ -+#if 0 -+ // ctrl->val is 0 indicate edge enhance closed -+ if (ctrl->val == ISP_BRIGHTNESS_0) { -+ // disable edge(brightness) adjust -+ isp->img_ctrltbl1[11] &= ~(1 << 29); -+ isp->yedge_en = 0; -+ -+ // disable isofilter -+ if (isp->uv_isoflt_en_flag == 0) { -+ isp->img_ctrltbl1[13] &= ~(1 << 30); -+ isp->uv_isoflt_en = 0; -+ } -+ } else { -+ -+#endif -+ bl_edge.y_edgek = 1000; -+ bl_edge.y_thrs = 2; -+ -+ switch(ctrl->val) { -+ case ISP_BRIGHTNESS_0: -+ bl_edge.ygain = -30; -+ break; -+ case ISP_BRIGHTNESS_1: -+ bl_edge.ygain = -15; -+ break; -+ case ISP_BRIGHTNESS_2: -+ bl_edge.ygain = 0; -+ break; -+ case ISP_BRIGHTNESS_3: -+ bl_edge.ygain = 10; -+ break; -+ case ISP_BRIGHTNESS_4: -+ bl_edge.ygain = 20; -+ break; -+ case ISP_BRIGHTNESS_5: -+ bl_edge.ygain = 30; -+ break; -+ case ISP_BRIGHTNESS_6: -+ bl_edge.ygain = 40; -+ break; -+ } -+ -+ __isp_set_brigtness(isp, &bl_edge); -+ -+ isp->yedge_en = 1; -+ //isp->uv_isoflt_en = 1; -+ //} -+ -+ update_image_size(isp); -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_gamma(struct isp_struct *isp, struct v4l2_ctrl *ctrl) -+{ -+ isp_dbg("%s. enter. ctrl->val=%d\n", __func__, ctrl->val); -+ #if 0 -+ if (ctrl->val == ISP_GAMMA_0) { -+ memset(isp->img_lumitbl, 0, sizeof(unsigned long)*BRIGHTNESS_CHART_SIZE); -+ // disable brightness chart table -+ isp->img_ctrltbl1[11] &= ~(1 << 30); -+ isp->gamma_calc_en = 0; -+ } else { -+ #endif -+ switch(ctrl->val) { -+ case ISP_GAMMA_0: -+ __isp_set_gamma(isp, gamma_table[0]); -+ break; -+ case ISP_GAMMA_1: -+ __isp_set_gamma(isp, gamma_table[1]); -+ break; -+ case ISP_GAMMA_2: -+ __isp_set_gamma(isp, gamma_table[2]); -+ break; -+ case ISP_GAMMA_3: -+ __isp_set_gamma(isp, gamma_table[3]); -+ break; -+ case ISP_GAMMA_4: -+ __isp_set_gamma(isp, gamma_table[4]); -+ break; -+ case ISP_GAMMA_5: -+ __isp_set_gamma(isp, gamma_table[5]); -+ break; -+ case ISP_GAMMA_6: -+ __isp_set_gamma(isp, gamma_table[6]); -+ break; -+ } -+ -+ // enable brightness adjust -+ isp->img_ctrltbl1[11] |= (1 << 30); -+ isp->gamma_calc_en = 1; -+ //} -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+int isp_set_saturation(struct isp_struct *isp, struct v4l2_ctrl *ctrl) -+{ -+ struct isp_saturation satu; -+ -+ isp_dbg("%s. enter. ctrl->val=%d\n", __func__, ctrl->val); -+ -+ memset(&satu, 0, sizeof(struct isp_saturation)); -+ isp->img_ctrltbl1[13] &= ~0x3fffffff; -+ isp->img_ctrltbl1[14] &= ~(0xffff << 16); -+ -+ if (ctrl->val == ISP_SATURATION_0) { -+ // disable saturation adjust -+ isp->img_ctrltbl1[13] &= ~(1 << 31); -+ isp->uv_saturate_en = 0; -+ } else { -+ switch(ctrl->val) { -+ case ISP_SATURATION_1: -+ satu.Chigh = 5; -+ satu.Clow = 0; -+ //tmp->Khigh should be 300-800 -+ satu.Khigh = 300; -+ satu.Klow = 249;//280; -+ break; -+ case ISP_SATURATION_2: -+ satu.Chigh = 5; -+ satu.Clow = 0; -+ satu.Khigh = 350; -+ satu.Klow = 249; -+ break; -+ case ISP_SATURATION_3: -+ satu.Chigh = 5; -+ satu.Clow = 0; -+ satu.Khigh = 400; -+ satu.Klow = 249; -+ break; -+ case ISP_SATURATION_4: -+ satu.Chigh = 5; -+ satu.Clow = 0; -+ satu.Khigh = 450; -+ satu.Klow = 249; -+ break; -+ case ISP_SATURATION_5: -+ satu.Chigh = 5; -+ satu.Clow = 0; -+ satu.Khigh = 500; -+ satu.Klow = 249; -+ break; -+ case ISP_SATURATION_6: -+ satu.Chigh = 5; -+ satu.Clow = 0; -+ satu.Khigh = 550; -+ satu.Klow = 249; -+ break; -+ } -+ -+ __isp_set_uv_saturation(isp, &satu); -+ -+ isp->uv_saturate_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+//��ɫУ��ÿ��sensor����һ�� -+// brief: return -1 is indicate the function is not support YUV data -+int isp_set_sharpness(struct isp_struct *isp, struct v4l2_ctrl *ctrl) -+{ -+ -+ struct isp_color_correct colcon; -+ int i; -+ -+ isp_dbg("%s enter. ctrl->val=%d\n", __func__, ctrl->val); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) { -+ return 0; -+ } -+ -+ memset(&colcon, 0, sizeof(struct isp_color_correct)); -+ isp->img_ctrltbl1[11] &= ~(0x3fffff); -+ for (i = 0; i < 9; i++) -+ isp->img_ctrltbl1[2+i] = 0x0; -+ -+ if (ctrl->val == ISP_SHARPNESS_0) { -+ // disable color correction -+ isp->img_ctrltbl1[11] &= ~(1 << 31); -+ isp->color_crr_en = 0; -+ } else { -+ switch(ctrl->val) { -+ case ISP_SHARPNESS_1: -+ colcon.cc_thrs_low = 40; -+ colcon.cc_thrs_high = 41; -+ colcon.ccMtrx[0][0] = 1024; -+ colcon.ccMtrx[0][1] = 150; -+ colcon.ccMtrx[0][2] = -150; -+ colcon.ccMtrx[1][0] = 150; -+ colcon.ccMtrx[1][1] = 1024; -+ colcon.ccMtrx[1][2] = -150; -+ colcon.ccMtrx[2][0] = 301; -+ colcon.ccMtrx[2][1] = -301; -+ colcon.ccMtrx[2][2] = 1024; -+ break; -+ case ISP_SHARPNESS_2: -+ case ISP_SHARPNESS_3: -+ case ISP_SHARPNESS_4: -+ case ISP_SHARPNESS_5: -+ case ISP_SHARPNESS_6: -+ break; -+ } -+ -+ __isp_set_color_crr(isp, &colcon, 3, 3); -+ -+ isp->color_crr_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) -+ -+struct awb_rgb_param { -+ unsigned short r[3]; -+ unsigned short b[3]; -+}; -+ -+int isp_update_auto_wb_param(struct isp_struct *isp) -+{ -+ unsigned long co_g = 0, co_r = 0, co_b = 0; -+ unsigned short co_r_tmp, co_b_tmp; -+ unsigned short nr1, nr2, nr3; -+ unsigned short nb1, nb2, nb3; -+ static struct awb_rgb_param rb_arr; -+ static int count = 0; -+ -+ //first update register -+ REG32(isp->base + ISP_RGB_DATA) = 1; -+ -+ //then read value from register -+ co_r = REG32(isp->base + ISP_RGB_DATA); -+ co_g = REG32(isp->base + ISP_RGB_DATA); -+ co_b = REG32(isp->base + ISP_RGB_DATA); -+ //isp_dbg("[%ld %ld %ld]\n", co_r, co_g, co_b); -+ -+ if ((co_r > 0) && (co_g > 0) && (co_b > 0)) { -+ co_r >>= 10; -+ co_b >>= 10; -+ -+ if ((co_r > 0) && (co_b > 0)) { -+ co_r_tmp = co_g/co_r; -+ co_b_tmp = co_g/co_b; -+ -+ rb_arr.r[count] = co_r_tmp; -+ rb_arr.b[count] = co_b_tmp; -+ if (count >= 2) { -+ //isp_dbg("[r[0]:%d r[1]:%d r[2]:%d]\n", -+ // rb_arr.r[0],rb_arr.r[1],rb_arr.r[2]); -+ -+ nr1 = ABS_DIFF(rb_arr.r[0], rb_arr.r[1]); -+ nr2 = ABS_DIFF(rb_arr.r[0], rb_arr.r[2]); -+ nr3 = ABS_DIFF(rb_arr.r[1], rb_arr.r[2]); -+ -+ nb1 = ABS_DIFF(rb_arr.b[0], rb_arr.b[1]); -+ nb2 = ABS_DIFF(rb_arr.b[0], rb_arr.b[2]); -+ nb3 = ABS_DIFF(rb_arr.b[1], rb_arr.b[2]); -+ -+ if (((co_r_tmp > 700) && (co_r_tmp < 1700)) && -+ ((nr1+nr2)<30 || (nr1+nr3)<30 || (nr2+nr3)<30)) -+ isp->wb_param.co_r = co_r_tmp; -+ -+ if (((co_b_tmp > 700) && (co_b_tmp < 1700)) && -+ ((nb1+nb2)<30 || (nb1+nb3)<30 || (nb2+nb3)<30)) -+ isp->wb_param.co_b = co_b_tmp; -+ -+ rb_arr.r[0] = rb_arr.r[1]; -+ rb_arr.r[1] = rb_arr.r[2]; -+ -+ rb_arr.b[0] = rb_arr.b[1]; -+ rb_arr.b[1] = rb_arr.b[2]; -+ } else { -+ isp->wb_param.co_r = co_r_tmp; -+ isp->wb_param.co_b = co_b_tmp; -+ count = count+1; -+ } -+ -+ isp->wb_param.co_g = 1024; -+ } -+ } -+ -+ //isp_dbg("co_r %d, co_g %d, co_b %d\n", -+ // isp->wb_param.co_r, isp->wb_param.co_g, isp->wb_param.co_b); -+ -+ __isp_set_white_pram(isp, isp->wb_param.co_g, -+ isp->wb_param.co_r, isp->wb_param.co_b); -+ -+ isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+// brief: return -1 is indicate the function is not support YUV data -+int isp_auto_set_wb_param(struct isp_struct *isp, struct v4l2_ctrl *ctrl) -+{ -+ struct isp_auto_white_balance auto_wb_param; -+ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) { -+ return 0; -+ } -+ -+ memset(&auto_wb_param, 0, sizeof(struct isp_auto_white_balance)); -+ memset(&isp->wb_param, 0, sizeof(struct isp_wb_param)); -+ -+ // no use auto while balance -+ if (ctrl->val == 0) { -+ isp->wb_param.co_r = 1024; -+ isp->wb_param.co_g = 1024; -+ isp->wb_param.co_b = 1024; -+ -+ __isp_set_white_pram(isp, isp->wb_param.co_g, -+ isp->wb_param.co_r, isp->wb_param.co_b); -+ -+ // disable white balance calculate -+ isp->isp_ctrltbl[25] &= ~(1 << 31); -+ isp->auto_wb_param_en = 0; -+ } else { -+ auto_wb_param.r_high = 984; -+ auto_wb_param.r_low = 555; -+ auto_wb_param.g_high = 988; -+ auto_wb_param.g_low = 718; -+ auto_wb_param.b_high = 979; -+ auto_wb_param.b_low = 542; -+ -+ auto_wb_param.grb_high = 826; -+ auto_wb_param.grb_low = 437; -+ auto_wb_param.gr_high = 822; -+ auto_wb_param.gr_low = 433; -+ auto_wb_param.gb_high = 818; -+ auto_wb_param.gb_low = 420; -+ -+ isp_set_auto_wb_support(isp, &auto_wb_param); -+ -+ //disable manu while balance, enable auto while balance -+ isp->wb_param_en = 0; -+ isp->auto_wb_param_en = 1; -+ } -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+// brief: return -1 is indicate the function is not support YUV data -+int isp_manu_set_wb_param(struct isp_struct *isp, struct v4l2_ctrl *ctrl) -+{ -+ isp_dbg("%s enter.\n", __func__); -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) { -+ return 0; -+ } -+ -+ memset(&isp->wb_param, 0, sizeof(struct isp_wb_param)); -+ -+ if (ctrl->val == ISP_MANU_WB_0) { -+ // disable color correction -+ isp->wb_param.co_r = 1024; -+ isp->wb_param.co_g = 1024; -+ isp->wb_param.co_b = 1024; -+ -+ isp->wb_param_en = 0; -+ } else { -+ switch(ctrl->val) { -+ case ISP_MANU_WB_1: -+ isp->wb_param.co_r = 1137; -+ isp->wb_param.co_g = 1024; -+ isp->wb_param.co_b = 1108; -+ break; -+ case ISP_MANU_WB_2: -+ isp->wb_param.co_r = 1235; -+ isp->wb_param.co_g = 1024; -+ isp->wb_param.co_b = 1345; -+ break; -+ case ISP_MANU_WB_3: -+ isp->wb_param.co_r = 1489; -+ isp->wb_param.co_g = 1024; -+ isp->wb_param.co_b = 1427; -+ break; -+ case ISP_MANU_WB_4: -+ case ISP_MANU_WB_5: -+ case ISP_MANU_WB_6: -+ break; -+ } -+ -+ //enable manu while balance, disable auto while balance -+ isp->wb_param_en = 1; -+ isp->auto_wb_param_en = 0; -+ } -+ -+ __isp_set_white_pram(isp, isp->wb_param.co_g, -+ isp->wb_param.co_r, isp->wb_param.co_b); -+ -+ //isp_update_regtable(isp, 0); -+ return 0; -+} -+ -+static unsigned int brightness_average(struct isp_struct *isp) -+{ -+ unsigned int sum = 0, tmp = 0; -+ unsigned int average; -+ int i; -+ -+ for (i = 0; i < 256; i++) { -+ sum += i *(histo_arr[i]); -+ tmp += (histo_arr[i]); -+ } -+ -+ if (tmp == 0) -+ tmp = 1; -+ -+ average = sum/tmp; -+ //isp_dbg("[%d] %d %d\n", average, sum, tmp); -+ return average; -+} -+ -+void update_exposure_value(struct isp_struct *isp) -+{ -+ unsigned int value; -+ static int flags_max = 0, flags_min = 0; -+ -+ value = brightness_average(isp); -+ -+ if ((value > 0xB4) && (flags_max < 2)) { -+ //isp_dbg(" >0xB4 -> 0x48\n"); -+ flags_max++; -+ flags_min = 0; -+ aksensor_set_param(0x14, 0x48); -+ } else if ((value < 0x60) && (flags_min < 2)) { -+ //isp_dbg(" <0x60 -> 0x40\n"); -+ flags_max = 0; -+ flags_min++; -+ aksensor_set_param(0x14, 0x40); -+ } -+} -+ -+/* compress histogram */ -+int isp_get_histogram(struct isp_struct *isp) -+{ -+ int i, j; -+ -+ if (isp->cur_mode_class != ISP_RGB_CLASS) -+ return 0; -+ -+ for (i = 0, j = 0; i < HISTOGRAM_SIZE; i = i+12, j++) { -+ histo_arr[j] = ((isp->histo_base[i+11]<<16)|(isp->histo_base[i+10]<<8)|(isp->histo_base[i+9])) -+ +((isp->histo_base[i+8]<<16)|(isp->histo_base[i+7]<<8)|(isp->histo_base[i+6])) -+ +((isp->histo_base[i+5]<<16)|(isp->histo_base[i+4]<<8)|(isp->histo_base[i+3])) -+ +((isp->histo_base[i+2]<<16)|(isp->histo_base[i+1]<<8)|(isp->histo_base[i])); -+ } -+ -+ schedule_delayed_work(&isp->work, msecs_to_jiffies(20)); -+ return 0; -+} -+ -+int isp_apply_mode(struct isp_struct *isp) -+{ -+ int width = isp->fmt_width; -+ int height = isp->fmt_height; -+ int ret = 0; -+ -+ isp_dbg("%s: width=%d, height=%d\n", __func__, width, height); -+ switch(isp->cur_mode_class) { -+ case ISP_YUV_CLASS: -+ switch(isp->cur_mode) { -+ -+ // ISP_YUV_OUT mode is direct output, and is not support minor channel output -+ case ISP_YUV_OUT: -+ REG32(isp->base + ISP_FMT_CHK) = (width * 2 | (height << 14)); -+ REG32(isp->base + ISP_IMG_PARA) = 0x80001000; -+ REG32(isp->base + ISP_IRQ_STATUS) = 0x040017ff; -+ REG32(isp->base + ISP_PERI_PARA) = 0x200340c0; -+ break; -+ -+ // ISP_YUV_BYPASS mode is support minor channel output -+ case ISP_YUV_BYPASS: -+ setup_yuv_video_bypass(isp); -+ -+ REG32(isp->base + ISP_FMT_CHK) = (width * 2 | (height << 14)); -+ REG32(isp->base + ISP_IMG_PARA) = 0x80001000; -+ REG32(isp->base + ISP_IRQ_STATUS) = 0x040017ff; -+ REG32(isp->base + ISP_PERI_PARA) = 0x000104c0; -+ break; -+ -+ case ISP_YUV_VIDEO_OUT: -+ setup_yuv_video_out(isp); -+ -+ REG32(isp->base + ISP_FMT_CHK) = (width * 2 | (height << 14)); -+ REG32(isp->base + ISP_IMG_PARA) = 0x80001000; -+ REG32(isp->base + ISP_IRQ_STATUS) = 0x044007ff; -+ REG32(isp->base + ISP_PERI_PARA) = 0x000340c5; -+ break; -+ -+ case ISP_YUV_VIDEO_BYPASS: -+ setup_yuv_video_bypass(isp); -+ -+ REG32(isp->base + ISP_FMT_CHK) = (width * 2 | (height << 14)); -+ REG32(isp->base + ISP_IMG_PARA) = 0x80001000; -+ REG32(isp->base + ISP_IRQ_STATUS) = 0x000017ff; -+ REG32(isp->base + ISP_PERI_PARA) = 0x000104c5; -+ break; -+ -+ case ISP_YUV_MERGER_OUT: -+ case ISP_YUV_VIDEO_MERGER_OUT: -+ case ISP_YUV_BIG: -+ break; -+ -+ default: -+ break; -+ } -+ -+ isp_update_regtable(isp, 1); -+ break; -+ -+ case ISP_RGB_CLASS: -+ setup_rgb_video(isp); -+ -+ REG32(isp->base + ISP_FMT_CHK) = (width | (height<<14)); -+ REG32(isp->base + ISP_IMG_PARA) = 0x80000800; -+ //REG32(isp->base + ISP_HISTO_CFG) = 0x00000000; -+ REG32(isp->base + ISP_IRQ_STATUS) = 0x000017ff; -+ -+ switch(isp->cur_mode) { -+ case ISP_RGB_OUT: -+ REG32(isp->base + ISP_PERI_PARA) = 0x000120c0; -+ break; -+ -+ case ISP_RGB_VIDEO_OUT: -+ REG32(isp->base + ISP_PERI_PARA) = 0x000120c5; -+ break; -+ -+ case ISP_RGB_BIG: -+ break; -+ -+ default: -+ break; -+ } -+ -+ isp_update_regtable(isp, 1); -+ break; -+ -+ case ISP_JPEG_CLASS: -+ switch(isp->cur_mode) { -+ case ISP_JPEG_MODE: -+ case ISP_JPEG_VIDEO: -+ break; -+ -+ default: -+ break; -+ } -+ break; -+ -+ default: -+ printk("Unrecognized mode %d\n", isp->cur_mode); -+ } -+ -+ return ret; -+} -+ -+/* -+ * Note: To enable raw upload, the 14th bit of peripheral parameter register must be -+ * set, otherwise the data cannot be captured -+ */ -+void isp_start_capturing(struct isp_struct *isp) -+{ -+ unsigned long peri_status; -+ -+ //REG32(isp->base + ISP_PERI_PARA) &= ~(1 << 28); -+ -+ switch(isp->cur_mode) { -+ case ISP_YUV_OUT: -+ case ISP_YUV_VIDEO_OUT: -+ case ISP_YUV_BIG: -+ case ISP_JPEG_MODE: -+ case ISP_JPEG_VIDEO: -+ case ISP_RGB_BIG: -+ peri_status = REG32(isp->base + ISP_PERI_PARA); -+ peri_status |= (3 << 30) | (1 << 14); -+ REG32(isp->base + ISP_PERI_PARA) = peri_status; -+ break; -+ default: -+ REG32(isp->base + ISP_PERI_PARA) |= (3 << 30); -+ } -+} -+ -+void isp_stop_capturing(struct isp_struct *isp) -+{ -+ unsigned long peri_status; -+ -+ peri_status = REG32(isp->base + ISP_PERI_PARA); -+ peri_status |= (1 << 30); -+ peri_status &= ~(1 << 31); -+ REG32(isp->base + ISP_PERI_PARA) = peri_status; -+} -+ -+ -+void isp_dump_register(struct isp_struct *isp) -+{ -+ int i; -+ -+ printk("0x20000000=0x%08lx\n", REG32(isp->base + ISP_PERI_PARA)); -+ printk("0x20000004=0x%08lx\n", REG32(isp->base + ISP_FMT_CHK)); -+ printk("0x20000008=0x%08lx\n", REG32(isp->base + ISP_IMG_PARA)); -+ printk("0x200000014=0x%08lx\n", REG32(isp->base + ISP_IRQ_STATUS)); -+ printk("0x20000001c=0x%08lx\n", REG32(isp->base + ISP_ORDER_CTRL)); -+ -+ printk("0x200000020:\n"); -+ REG32(isp->base + 0x20) = 0x00000001; -+ for (i = 0; i <28; i++) { -+ printk("%02d: 0x%08lx\t", i, REG32(isp->base + 0x20)); -+ if (i % 5 == 0) -+ printk("\n"); -+ } -+ printk("\n"); -+ -+ printk("0x200000024:\n"); -+ REG32(isp->base + 0x24) = 0x00000001; -+ for (i = 0; i <28; i++) { -+ printk("%02d: 0x%08lx\t", i, REG32(isp->base + 0x24)); -+ if (i % 5 == 0) -+ printk("\n"); -+ } -+ printk("\n"); -+ -+ printk("0x200000028:\n"); -+ REG32(isp->base + 0x28) = 0x00000001; -+ for (i = 0; i <64; i++) { -+ printk("%02d: 0x%08lx\t", i, REG32(isp->base + 0x28)); -+ if (i % 5 == 0) -+ printk("\n"); -+ } -+ printk("\n"); -+ -+ printk("0x20000002c:\n"); -+ REG32(isp->base + 0x2c) = 0x00000001; -+ for (i = 0; i <28; i++) { -+ printk("%02d: 0x%08lx\t", i, REG32(isp->base + 0x2c)); -+ if (i % 5 == 0) -+ printk("\n"); -+ } -+ printk("\n"); -+ -+ printk("0x200000030:\n"); -+ REG32(isp->base + 0x30) = 0x00000001; -+ for (i = 0; i <27; i++) { -+ printk("%02d: 0x%08lx\t", i, REG32(isp->base + 0x30)); -+ if (i % 5 == 0) -+ printk("\n"); -+ } -+ printk("\n"); -+} -+ -+int isp_module_init(struct isp_struct *isp) -+{ -+ //register table total size is (32 * 4 * 6) = 768byte. here is more than real size. -+ isp->bytes = 1024; -+ isp->area = dma_alloc_coherent(NULL, isp->bytes, &isp->addr, GFP_KERNEL); -+ if (!isp->area) { -+ printk(KERN_ERR"Failed to allocate memory for register table\n"); -+ return -1; -+ } -+ -+ memset(isp->area, 0, isp->bytes); -+ isp_dbg("isp device init: isp->area=0x%p, isp->addr=0x%p, isp->bytes=%d\n", -+ isp->area, (void *)isp->addr, isp->bytes); -+ -+ isp->isp_ctrltbl = (unsigned long *)isp->area; //0x20, register table -+ isp->img_ctrltbl1 = isp->isp_ctrltbl + 32; //0x24 -+ isp->img_lumitbl = isp->img_ctrltbl1 + 32; //0x28 -+ isp->osd_chktbl = isp->img_lumitbl + 64; //0x2c -+ isp->img_ctrltbl2 = isp->osd_chktbl + 32; //0x30 -+ -+ isp->histo_base = dma_alloc_coherent(NULL, HISTOGRAM_SIZE, &isp->histo_phyaddr, GFP_KERNEL); -+ if (isp->histo_base == NULL) { -+ printk("no memory for histopram %d\n", -ENOMEM); -+ } -+ memset(isp->histo_base, 0, HISTOGRAM_SIZE); -+ -+ isp_dbg("Allocate %d bytes for register table\n", isp->bytes); -+ -+ return 0; -+} -+ -+ -+void isp_module_fini(struct isp_struct *isp) -+{ -+ dma_free_coherent(NULL, HISTOGRAM_SIZE, isp->histo_base, isp->histo_phyaddr); -+ dma_free_coherent(NULL, isp->bytes, isp->area, isp->addr); -+} -+ -+ -+#if 0 -+void build_gamma_table(struct isp_struct *isp) -+{ -+ int i; -+ unsigned char lum_table[256] = {0}; -+ -+ // generate lum correction parameter -+ for (i=0; i<256; i++) { -+ if(i<=13) -+ lum_table[i]=(unsigned char)(0.46154*i +0); -+ if (13<i && i<=21) -+ lum_table[i]=(unsigned char)(2*i -20); -+ if (21<i&&i<=26) -+ lum_table[i]=(unsigned char)(4*i -62); -+ if (26<i && i<=36) -+ lum_table[i]=(unsigned char)(2.4*i -20.4); -+ if (36<i && i<=48) -+ lum_table[i]=(unsigned char)(2.1667*i -12); -+ if (48<i && i<=61) -+ lum_table[i]=(unsigned char)(1.5385*i +18.154); -+ if (61<i && i<=73) -+ lum_table[i]=(unsigned char)(1.5*i +20.5); -+ if (73<i && i<=93) -+ lum_table[i]=(unsigned char)(0.95*i +60.65); -+ if (93<i && i<=114) -+ lum_table[i]=(unsigned char)(0.80952*i +73.714); -+ if (114<i && i<=135) -+ lum_table[i]=(unsigned char)(0.7619*i +79.091); -+ if (135<i && i<=157) -+ lum_table[i]=(unsigned char)(0.63636*i +96.091); -+ if (157<i && i<=190) -+ lum_table[i]=(unsigned char)(0.36364*i +138.91); -+ if (190<i && i<=221) -+ lum_table[i]=(unsigned char)(0.25806*i +158.97); -+ if (221<i && i<=241) -+ lum_table[i]=(unsigned char)(0.95*i +6.05); -+ if (241<i && i<=255) { -+ lum_table[i]=(unsigned char)((1.4286*i -109.29)>255?254:(1.4286*i -109.29)); -+ } -+ } -+ -+ for (i=5; i<247; i++) { -+ lum_table[i]=(unsigned char)((lum_table[i-5]+lum_table[i-4] -+ +lum_table[i-3]+lum_table[i-2] -+ +lum_table[i-1]+lum_table[i] -+ +lum_table[i+1]+lum_table[i+2] -+ +lum_table[i+3]+lum_table[i+4] -+ +lum_table[i+5]+lum_table[i+6] -+ +lum_table[i+7])/13); -+ } -+ -+ //copy to isp->img_lumitbl -+ for(i = 0; i < 256; i+=4) { -+ isp->img_lumitbl[i>>2] = lum_table[i]|(lum_table[i+1] << 8) -+ |(lum_table[i+2] << 16)|(lum_table[i+3] << 24); -+ } -+ -+ printk("\n"); -+ for(i = 0; i < 64; i++) { -+ printk("%08x ", isp->img_lumitbl[i]); -+ if ((i != 0) && (i % 5 == 0)) -+ printk("\n"); -+ } -+} -+#endif -+ -diff --git a/drivers/media/video/plat-anyka/ak39_isp.h b/drivers/media/video/plat-anyka/ak39_isp.h -new file mode 100755 -index 00000000..7140ae41 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/ak39_isp.h -@@ -0,0 +1,333 @@ -+#ifndef _AK39_ISP_H -+#define _AK39_ISP_H -+ -+#include <linux/videodev2.h> -+#include <media/v4l2-ctrls.h> -+ -+#include <plat-anyka/isp_interface.h> -+ -+#define ISP_PERI_PARA 0x00 -+#define ISP_FMT_CHK 0x04 -+#define ISP_IMG_PARA 0x08 -+#define ISP_HISTO_CFG 0x10 -+#define ISP_IRQ_STATUS 0x14 -+#define ISP_RGB_DATA 0x18 -+#define ISP_ORDER_CTRL 0x1c -+ -+#define ISP_FRAME_UPDATE (0) -+#define ISP_RAW_UPDMA_OVERFLOW (1) -+#define ISP_BIG_PIC_MODE_DONE (2) -+#define ISP_CH1_UPDMA_OVERFLOW (3) -+#define ISP_CH1_ONE_FRAME_END (4) -+#define ISP_PCLK_VER_ERR (5) -+#define ISP_PCLK_HOR_ERR (6) -+#define ISP_CH2_ONE_FRAME_END (7) -+#define ISP_HIST_END (8) -+#define ISP_RAW_UPLOAD (9) -+#define ISP_ALL_FARME_END (10) -+ -+ -+//dsamp rto + cut pos -+#define DSMP_RTO_BIT 30 -+#define CUT_STRY_BIT 13 -+#define CUT_STRX_BIT 0 -+ -+//cut winsize -+#define CUT_WINH_BIT 13 -+#define CUT_WINW_BIT 0 -+ -+//demosaic -+#define DEMO_ENABLE_BIT 12 // demosaic enable -+#define DEMO_THRD_BIT 0 // [11:0] demosaic threshold, asic presice+2 -+ -+//lens coef, 0~9, 10times aa[10:0],bb[10:0],cc[9:0] -+#define LENS_COEFA_BIT 21 -+#define LENS_COEFB_BIT 10 -+#define LENS_COEFC_BIT 0 // c=[9:0]+1'b0 -+ -+//lens range 0~9 10 times + black level parm / white balance parm -+#define LENS_RANGE_BIT 0 // [21:0] -+#define BB_PARM_BIT 22 // [31:22] black level parm, R,G,B -+#define WB_SETPARM_BIT 22 // [31:22] white balance set parm, r/g/b_high/low, -+#define RAW_DMA_CYL_BIT 28 // [31:28] raw DMA download min cycle, min val = 2 -+ -+//lens refpos center point{3��b0, yref[12:0], 3��b0, xref[12:0]} -+#define LENS_YREF_BIT 16 // [28:16] -+#define LENS_XREF_BIT 0 // [12:0] -+ -+//lens istsqr -+#define LENS_ENABLE_BIT 31 // lens correction enable -+#define LENS_1STSQR_BIT 0 // [26:0](xref)^2 + (yref) ^2 -+ -+//WB calculate parm -+#define WB_PARMCAL_EN_BIT 31 //white balance parameter calculate enable -+#define WB_GRB_HIGH_BIT 20 // [29:20] grb_high -+#define WB_GRR_LOW_BIT 10 // [19:10] grb_low -+#define WB_GR_LOW_BIT 0 // [9:0] gr_low -+#define WB_GR_HIGH_BIT 20 // [29:20] gr_high -+#define WB_GB_HIGH_BIT 10 // [19:10] gb_high -+#define WB_GB_LOW_BIT 0 // [9:0] gb_low -+ -+ -+#define ISP_WIN_HEIGHT_OFFSET (13) -+#define ISP_WIN_WIDTH_OFFSET (0) -+ -+#define UPSCALE_FRAME_CTRL (16) -+#define DOWNSCALE_FRAME_CTRL (24) -+ -+#define CC_CALVAL_BIT 16 // [28:16] (tmp(I, j) �Cmin(I, j) ) /( high-low) -+#define CC_TMPVAL_BIT 0 // [12:0] tmp(i, j) -+ -+// Y gain edge enhance -+#define Y_GAIN_BIT 24 // [31:24] -+#define Y_EDGE_THRS_BIT 12 // [22:12] ythrs * 9 -+#define Y_EDGE_K_BIT 0 // [10:0] k/9*2048 -+ -+//uv saturation1 -+#define UVSATUR_EN_BIT 31 -+#define ISOFLT_EN_BIT 30 -+#define UVSATUR_K_LOW_BIT 20 // [29:20] 10bit, xx.xxxx xxxx klow*256, 0.1~3 -+#define UVSATUR_K_HIGH_BIT 10 // [19:10] 10bit, khigh*256, 0.1~3 -+#define UVSATUR_K_SLOPE_BIT 0 // [9:0] (iHigh - iLow) * 256 / (CHigh - CLow) -+ -+// uv saturation 2 -+#define UVSATUR_CHIGH_BIT 24 // [31:24] 0~255 -+#define UVSATUR_CLOW_BIT 16 // [23:16] 0~255 -+#define SPEC_YCOEFA_BIT 8 // [15:8] Y effect A -64~64 -+#define SPEC_YCOEFB_BIT 0 // [7:0] B 0~255 -+ -+// uv special effect -+#define YUV_SOLAR_THRD_BIT 24 // [31:24] yuv_eff_solar_thd -+#define SPEC_UCOEFA_BIT 24 // [31:24] U effect -64~64 -+#define SPEC_UCOEFB_BIT 16 // [23:16] B 0~255 -+#define SPEC_VCOEFA_BIT 8 // [15:8] V effect -64~64 -+#define SPEC_VCOEFB_BIT 0 // [7:0] B 0~255 -+ -+ -+#define OSD_SIZE_H_BIT 0 -+#define OSD_SIZE_V_BIT 16 -+ -+enum { -+ ISP_BRIGHTNESS_0 = 0, -+ ISP_BRIGHTNESS_1, -+ ISP_BRIGHTNESS_2, -+ ISP_BRIGHTNESS_3, -+ ISP_BRIGHTNESS_4, -+ ISP_BRIGHTNESS_5, -+ ISP_BRIGHTNESS_6 -+}; -+ -+enum { -+ ISP_GAMMA_0 = 0, -+ ISP_GAMMA_1, -+ ISP_GAMMA_2, -+ ISP_GAMMA_3, -+ ISP_GAMMA_4, -+ ISP_GAMMA_5, -+ ISP_GAMMA_6 -+}; -+ -+// isp saturation enum defined -+enum { -+ ISP_SATURATION_0 = 0, -+ ISP_SATURATION_1, -+ ISP_SATURATION_2, -+ ISP_SATURATION_3, -+ ISP_SATURATION_4, -+ ISP_SATURATION_5, -+ ISP_SATURATION_6 -+}; -+ -+enum { -+ ISP_SHARPNESS_0 = 0, -+ ISP_SHARPNESS_1, -+ ISP_SHARPNESS_2, -+ ISP_SHARPNESS_3, -+ ISP_SHARPNESS_4, -+ ISP_SHARPNESS_5, -+ ISP_SHARPNESS_6 -+}; -+ -+enum { -+ ISP_MANU_WB_0 = 0, -+ ISP_MANU_WB_1, -+ ISP_MANU_WB_2, -+ ISP_MANU_WB_3, -+ ISP_MANU_WB_4, -+ ISP_MANU_WB_5, -+ ISP_MANU_WB_6 -+}; -+ -+//enum for sub sample -+typedef enum -+{ -+ SUBSMP_1X, /*no sub sample*/ -+ SUBSMP_2X, /*sub sample 1/2 * 1/2 */ -+ SUBSMP_4X, /*sub sample 1/4 * 1/4 */ -+ SUBSMP_8X /*sub sample 1/8 * 1/8 */ -+} T_SUBSMP_RTO; -+ -+//define the image sensor controller register address -+#undef REG32 -+#define REG32(_reg_) (*(volatile unsigned long *)(_reg_)) -+ -+struct isp_brightness_yedge { -+ unsigned short yedgeK; -+ unsigned short ythresold; -+ signed char ygain; -+}; -+ -+struct isp_wb_param { -+ unsigned short co_r; -+ unsigned short co_g; -+ unsigned short co_b; -+}; -+ -+struct isp_struct { -+ void __iomem *base; -+ enum isp_working_mode cur_mode; -+ enum isp_mode_class cur_mode_class; -+ -+ /*the input size from sensor*/ -+ int fmt_width; -+ int fmt_height; -+ -+ /* indicate VGA size */ -+ int fmt_def_width; -+ int fmt_def_height; -+ -+ /*the input size from sensor*/ -+ int cut_width; -+ int cut_height; -+ -+ /* master channel output size*/ -+ int chl1_width; -+ int chl1_height; -+ -+ /* minor channel */ -+ int chl2_width; -+ int chl2_height; -+ int chl2_enable; -+ -+ int lens_use_width; // used for lens correct, width -+ int lens_use_height; // used for lens correct, height -+ -+ int demo_sac_en; -+ unsigned int demo_sac_thres; -+ int rgb_filter_en; -+ int rgb_filter_en_flag; -+ unsigned int rgb_filter_thres; -+ -+ int yedge_en; -+ int uv_isoflt_en; -+ int uv_isoflt_en_flag; -+ int gamma_calc_en; -+ int uv_saturate_en; -+ int auto_wb_param_en; -+ int wb_param_en; -+ int color_crr_en; -+ int yuv_effect_en; -+ int yuv_solar_en; -+ int defect_pixel_en; -+ int blkb_en; // black balance enable flag -+ int lens_crr_en; -+ int histo_en; -+ -+ T_SUBSMP_RTO sub_sample; //0:1x,1:2x,2:4x,3:8x -+ struct isp_wb_param wb_param; -+ unsigned char *area; /* virtual pointer */ -+ dma_addr_t addr; /* physical address */ -+ size_t bytes; /* buffer size in bytes */ -+ unsigned long *isp_ctrltbl; /* ISP control Information */ -+ unsigned long *img_ctrltbl1; /* Image backend process control information 1 */ -+ unsigned long *img_lumitbl; /* Image luminosity transformation table */ -+ unsigned long *osd_chktbl; /* OSD color check table */ -+ unsigned long *img_ctrltbl2; /* Image backend process control information 2 */ -+ dma_addr_t histo_phyaddr; -+ unsigned char *histo_base; -+ -+ struct delayed_work work; -+}; -+ -+void isp_start_capturing(struct isp_struct *isp); -+ -+void isp_stop_capturing(struct isp_struct *isp); -+ -+static inline void isp_clear_irq_counter(struct isp_struct *isp) -+{ -+ REG32(isp->base + ISP_IRQ_STATUS) |= 1 << 26; -+} -+ -+static inline bool isp_capture_running(struct isp_struct *isp) -+{ -+ return REG32(isp->base + ISP_PERI_PARA) & (1 << 31); -+} -+ -+static inline bool isp_is_continuous(struct isp_struct *isp) -+{ -+ return REG32(isp->base + ISP_PERI_PARA) & (1 << 2); -+} -+ -+static inline bool isp_is_capturing_odd(struct isp_struct *isp) -+{ -+ return REG32(isp->base + ISP_IRQ_STATUS) & (1 << 27); -+} -+ -+ -+void isp_update_regtable(struct isp_struct *isp, int force); -+int update_cur_mode_class(struct isp_struct *isp); -+ -+void isp_set_even_frame(struct isp_struct *isp, -+ unsigned long yaddr_chl1, unsigned long yaddr_chl2); -+void isp_set_odd_frame(struct isp_struct *isp, -+ unsigned long yaddr_chl1, unsigned long yaddr_chl2); -+ -+int isp_check_irq(struct isp_struct *isp); -+int isp_clear_irq(struct isp_struct *isp); -+int isp_clear_irq_status(struct isp_struct *isp); -+ -+int isp_set_osd(struct isp_struct *isp, struct isp_osd_info *); -+int isp_set_channel2(struct isp_struct *isp, struct isp_channel2_info *); -+int isp_set_occlusion_area(struct isp_struct *isp, struct isp_occlusion_info *); -+int isp_set_occlusion_color(struct isp_struct *isp, struct isp_occlusion_color *); -+int isp_set_channel1_scale(struct isp_struct *isp, int width, int height); -+int isp_set_cutter_window(struct isp_struct *isp, int xpos, int ypos, int width, int height); -+int isp_set_zoom(struct isp_struct *isp, struct isp_zoom_info *info); -+int isp_set_crop(struct isp_struct *isp, struct v4l2_rect rect); -+int isp_set_brightness(struct isp_struct *isp, struct v4l2_ctrl *ctrl); -+int isp_set_gamma(struct isp_struct *isp, struct v4l2_ctrl *ctrl); -+int isp_set_saturation(struct isp_struct *isp, struct v4l2_ctrl *ctrl); -+int isp_set_sharpness(struct isp_struct *isp, struct v4l2_ctrl *ctrl); -+int isp_update_auto_wb_param(struct isp_struct *isp); -+int isp_auto_set_wb_param(struct isp_struct *isp, struct v4l2_ctrl *ctrl); -+int isp_manu_set_wb_param(struct isp_struct *isp, struct v4l2_ctrl *ctrl); -+ -+ -+/* *******this interface response to set image param ****** */ -+int isp_set_black_balance(struct isp_struct *isp, struct isp_black_balance *ctrl); -+int isp_set_lens_correct(struct isp_struct *isp, struct isp_lens_correct *ctrl); -+int isp_set_demosaic(struct isp_struct *isp, struct isp_demosaic *ctrl); -+int isp_set_rgb_filter(struct isp_struct *isp, struct isp_rgb_filter *ctrl); -+int isp_set_uv_iso_filter(struct isp_struct *isp, struct isp_uv_filter *ctrl); -+int isp_set_defect_pixel(struct isp_struct *isp, struct isp_defect_pixel *ctrl); -+int isp_set_manu_wb(struct isp_struct *isp, struct isp_white_balance *ctrl); -+int isp_set_auto_wb(struct isp_struct *isp, struct isp_auto_white_balance *ctrl); -+int isp_set_color_correct(struct isp_struct *isp, struct isp_color_correct *ctrl); -+int isp_set_gamma_calc(struct isp_struct *isp, struct isp_gamma_calculate *ctrl); -+int isp_set_brightness_enhance(struct isp_struct *isp, struct isp_brightness_enhance *ctrl); -+int isp_set_uv_saturation(struct isp_struct *isp, struct isp_saturation *ctrl); -+int isp_set_histogram(struct isp_struct *isp, struct isp_histogram *ctrl); -+int isp_get_histogram(struct isp_struct *isp); -+int isp_set_special_effect(struct isp_struct *isp, struct isp_special_effect *ctrl); -+ -+int isp_apply_mode(struct isp_struct *isp); -+void isp_start_capturing(struct isp_struct *isp); -+void isp_dump_register(struct isp_struct *isp); -+ -+int isp_module_init(struct isp_struct *isp); -+void isp_module_fini(struct isp_struct *isp); -+ -+int isp_set_histogram(struct isp_struct *isp, struct isp_histogram *ctrl); -+void update_exposure_value(struct isp_struct *isp); -+ -+#endif -diff --git a/drivers/media/video/plat-anyka/ak_camera.c b/drivers/media/video/plat-anyka/ak_camera.c -new file mode 100755 -index 00000000..bc2c281f ---- /dev/null -+++ b/drivers/media/video/plat-anyka/ak_camera.c -@@ -0,0 +1,1545 @@ -+/* -+ * @file ak camera.c -+ * @camera host driver for ak -+ * @Copyright (C) 2010 Anyka (Guangzhou) Microelectronics Technology Co -+ * @author wu_daochao -+ * @date 2011-04 -+ * @version -+ * @for more information , please refer to AK980x Programmer's Guide Mannul -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/slab.h> -+#include <linux/hardirq.h> -+#include <linux/interrupt.h> -+#include <linux/irqreturn.h> -+#include <linux/sched.h> -+#include <linux/clk.h> -+#include <linux/gpio.h> -+#include <linux/delay.h> -+#include <linux/platform_device.h> -+#include <linux/videodev2.h> -+ -+#include <asm/io.h> -+#include <asm/cacheflush.h> -+ -+#include <media/soc_camera.h> -+#include <media/videobuf-core.h> -+#include <media/videobuf-dma-contig.h> -+#include <media/soc_mediabus.h> -+ -+#include <mach/gpio.h> -+#include <mach/clock.h> -+#include <mach/reset.h> -+#include <plat-anyka/ak_camera.h> -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/isp_interface.h> -+ -+#include "ak39_isp.h" -+ -+ -+//#define CAMIF_DEBUG -+#ifdef CAMIF_DEBUG -+#define isp_dbg(fmt...) printk(KERN_INFO " ISP: " fmt) -+#else -+#define isp_dbg(fmt, args...) do{}while(0) -+#endif -+ -+#define CAMDBG(fmt, args...) do{}while(0) -+ -+struct ak_buffer { -+ struct videobuf_buffer vb; -+ enum v4l2_mbus_pixelcode code; -+ int inwork; -+}; -+ -+struct ak_camera_dev { -+ struct soc_camera_host soc_host; -+ struct soc_camera_device *icd; -+ struct ak_camera_pdata *pdata; -+ -+ void __iomem *base; // mapped baseaddress for CI register(0x2000c000) -+ struct resource *res; -+ struct clk *clk; // camera controller clk. it's parent is vclk defined in clock.c -+ struct clk *cis_sclk; // cis_sclk clock for sensor -+ unsigned int irq; -+ unsigned int dma_running; -+ /* members to manage the dma and buffer*/ -+ struct list_head capture; -+ struct ak_buffer *active; -+ spinlock_t lock; /* for videobuf_queue , passed in init_videobuf */ -+ -+ /* personal members for platform relative */ -+ unsigned long mclk; -+ -+ struct isp_struct isp; -+ enum isp_working_mode def_mode; -+ unsigned char *osd_swbuff; -+ unsigned char *osd_buff; -+}; -+ -+struct ak_camera_cam { -+ /* Client output, as seen by the CEU */ -+ unsigned int width; -+ unsigned int height; -+}; -+ -+#define ISP_TIMEOUT (1) //unit: s -+#define EMPTY_FRAME_NUM (2) -+ -+static const char *ak_cam_driver_description = "AK_Camera"; -+static int irq_buf_empty_flag = 0; -+static int irq_need_baffle = 0; -+ -+extern void *getRecordSyncSamples(void); -+ -+/* for ak_videobuf_release */ -+static void free_buffer(struct videobuf_queue *vq, struct ak_buffer *buf) -+{ -+ struct soc_camera_device *icd = vq->priv_data; -+ struct videobuf_buffer *vb = &buf->vb; -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ -+ isp_dbg("%s (vb=0x%p) buf[%d] 0x%08lx %d\n", -+ __func__, vb, vb->i, vb->baddr, vb->bsize); -+ -+ BUG_ON(in_interrupt()); -+ -+ /* This waits until this buffer is out of danger, i.e., until it is no -+ * longer in STATE_QUEUED or STATE_ACTIVE */ -+ if (vb->state == VIDEOBUF_ACTIVE && !pcdev->dma_running) { -+ printk("free_buffer: dma_running=%d, doesn't neee to wait\n", pcdev->dma_running); -+ vb->state = VIDEOBUF_ERROR; -+ list_del(&vb->queue); -+ } else { -+ videobuf_waiton(vq, vb, 0, 0); -+ } -+ videobuf_dma_contig_free(vq, vb); -+ -+ vb->state = VIDEOBUF_NEEDS_INIT; -+} -+ -+/* Called when application apply buffers */ -+static int ak_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, -+ unsigned int *size) -+{ -+ struct soc_camera_device *icd = vq->priv_data; -+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, -+ icd->current_fmt->host_fmt); -+ -+ bytes_per_line = icd->user_width * 3 /2; -+ if (bytes_per_line < 0) -+ return bytes_per_line; -+ -+ *size = bytes_per_line * icd->user_height; -+ -+ if (*count < 4) { -+ printk("if use video mode, vbuf num isn't less than 4\n"); -+ *count = 4; -+ } -+ -+ if (*size * *count > CONFIG_VIDEO_RESERVED_MEM_SIZE) -+ *count = (CONFIG_VIDEO_RESERVED_MEM_SIZE) / *size; -+ -+ isp_dbg("%s count=%d, size=%d, bytes_per_line=%d\n", -+ __func__, *count, *size, bytes_per_line); -+ -+ return 0; -+} -+ -+/* platform independent */ -+static int ak_videobuf_prepare(struct videobuf_queue *vq, -+ struct videobuf_buffer *vb, enum v4l2_field field) -+{ -+ struct soc_camera_device *icd = vq->priv_data; -+ struct ak_buffer *buf = container_of(vb, struct ak_buffer, vb); -+ int ret; -+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, -+ icd->current_fmt->host_fmt); -+ -+ isp_dbg("%s (vb=0x%p) buf[%d] vb->baddr=0x%08lx vb->bsize=%d bytes_per_line=%d\n", -+ __func__, vb, vb->i, vb->baddr, vb->bsize, bytes_per_line); -+ -+ bytes_per_line = icd->user_width * 3 /2; -+ -+ if (bytes_per_line < 0) -+ return bytes_per_line; -+ -+ /* Added list head initialization on alloc */ -+ WARN_ON(!list_empty(&vb->queue)); -+ -+#if 0 -+//#ifdef ISP_DEBUG -+ /* -+ * This can be useful if you want to see if we actually fill -+ * the buffer with something -+ */ -+ memset((void *)vb->baddr, 0xaa, vb->bsize); -+#endif -+ -+ BUG_ON(NULL == icd->current_fmt); -+ -+ /* I think, in buf_prepare you only have to protect global data, -+ * the actual buffer is yours */ -+ buf->inwork = 1; -+ -+ if (buf->code != icd->current_fmt->code || -+ vb->width != icd->user_width || -+ vb->height != icd->user_height || -+ vb->field != field) { -+ buf->code = icd->current_fmt->code; -+ vb->width = icd->user_width; -+ vb->height = icd->user_height; -+ vb->field = field; -+ vb->state = VIDEOBUF_NEEDS_INIT; -+ } -+ -+ vb->size = bytes_per_line * vb->height; -+ if (0 != vb->baddr && vb->bsize < vb->size) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ if (vb->state == VIDEOBUF_NEEDS_INIT) { -+ ret = videobuf_iolock(vq, vb, NULL); -+ if (ret) -+ goto fail; -+ -+ vb->state = VIDEOBUF_PREPARED; -+ } -+ -+ buf->inwork = 0; -+ -+ return 0; -+ -+fail: -+ free_buffer(vq, buf); -+out: -+ buf->inwork = 0; -+ return ret; -+} -+ -+static void ak_videobuf_queue(struct videobuf_queue *vq, -+ struct videobuf_buffer *vb) -+{ -+ struct soc_camera_device *icd = vq->priv_data; -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ struct ak_buffer *buf = container_of(vb, struct ak_buffer, vb); -+ u32 yaddr_chl1, yaddr_chl2, size; -+ static int ch2_sync = 0; -+ -+ isp_dbg("%s (vb=0x%p) buf[%d] baddr = 0x%08lx, bsize = %d\n", -+ __func__, vb, vb->i, vb->baddr, vb->bsize); -+ -+ list_add_tail(&vb->queue, &pcdev->capture); -+ -+ vb->state = VIDEOBUF_ACTIVE; -+ size = vb->width * vb->height; -+ yaddr_chl1 = videobuf_to_dma_contig(vb); /* for mater channel */ -+ yaddr_chl2 = yaddr_chl1 + size * 3 / 2; /* for secondary channel */ -+ -+ switch(pcdev->isp.cur_mode) { -+ case ISP_YUV_OUT: -+ case ISP_YUV_BYPASS: -+ case ISP_RGB_OUT: -+ /* for single mode */ -+ if (!pcdev->active) { -+ pcdev->active = buf; -+ pcdev->dma_running = 1; -+ -+ isp_set_even_frame(&pcdev->isp, yaddr_chl1, yaddr_chl2); -+ isp_apply_mode(&pcdev->isp); -+ isp_start_capturing(&pcdev->isp); -+ -+ isp_dbg("queue[single]: vbuf[%d] start run.\n", vb->i); -+ } -+ break; -+ -+ case ISP_YUV_VIDEO_OUT: -+ case ISP_YUV_VIDEO_BYPASS: -+ case ISP_RGB_VIDEO_OUT: -+ /* for continous mode */ -+ if (!pcdev->active) { -+ pcdev->active = buf; -+ pcdev->dma_running = 0; -+ ch2_sync = 1; -+ -+ isp_set_even_frame(&pcdev->isp, yaddr_chl1, yaddr_chl2); -+ isp_dbg("queue[continue]: vbuf1[%d]\n", vb->i); -+ return; -+ } -+ -+ if (!pcdev->dma_running) { -+ pcdev->dma_running = 1; -+ -+ if (ch2_sync) { -+ ch2_sync = 0; -+ irq_buf_empty_flag = 0; -+ -+ isp_set_odd_frame(&pcdev->isp, yaddr_chl1, yaddr_chl2); -+ isp_apply_mode(&pcdev->isp); -+ isp_start_capturing(&pcdev->isp); -+ -+ isp_dbg("queue[continue]: vbuf2[%d] start.\n", vb->i); -+ return; -+ } -+ -+ // ensure that can update yaddr immediately -+ if (isp_is_capturing_odd(&pcdev->isp)) -+ isp_set_even_frame(&pcdev->isp, yaddr_chl1, yaddr_chl2); -+ else -+ isp_set_odd_frame(&pcdev->isp, yaddr_chl1, yaddr_chl2); -+ -+ } -+ break; -+ default: -+ printk("The working mode of ISP hasn't been initialized.\n"); -+ } -+} -+ -+static void ak_videobuf_release(struct videobuf_queue *vq, -+ struct videobuf_buffer *vb) -+{ -+ struct ak_buffer *buf = container_of(vb, struct ak_buffer, vb); -+// struct soc_camera_device *icd = vq->priv_data; -+// struct device *dev = icd->parent; -+ -+ isp_dbg("%s (vb=0x%p) buf[%d] 0x%08lx %d\n", -+ __func__, vb, vb->i, vb->baddr, vb->bsize); -+ -+ switch (vb->state) { -+ case VIDEOBUF_ACTIVE: -+ CAMDBG("vb status: ACTIVE\n"); -+ break; -+ case VIDEOBUF_QUEUED: -+ CAMDBG("vb status: QUEUED\n"); -+ break; -+ case VIDEOBUF_PREPARED: -+ CAMDBG("vb status: PREPARED\n"); -+ break; -+ default: -+ CAMDBG("vb status: unknown\n"); -+ break; -+ } -+ -+ free_buffer(vq, buf); -+} -+ -+static struct videobuf_queue_ops ak_videobuf_ops = { -+ .buf_setup = ak_videobuf_setup, -+ .buf_prepare = ak_videobuf_prepare, -+ .buf_queue = ak_videobuf_queue, -+ .buf_release = ak_videobuf_release, -+}; -+ -+/* platform code*/ -+static int ak_camera_setup_dma(struct ak_camera_dev *pcdev) -+{ -+ struct videobuf_buffer *vb_active = &pcdev->active->vb; -+ struct videobuf_buffer *vb; -+ struct list_head *next; -+ unsigned long yaddr_chl1_active, yaddr_chl2_active; -+ unsigned long yaddr_chl1_next, yaddr_chl2_next; -+ int size; -+ -+ size = vb_active->width * vb_active->height; -+ yaddr_chl1_active = videobuf_to_dma_contig(vb_active); -+ yaddr_chl2_active = yaddr_chl1_active + size * 3 / 2; -+ -+ /* for single mode */ -+ if (!isp_is_continuous(&pcdev->isp)) { -+ isp_set_even_frame(&pcdev->isp, yaddr_chl1_active, yaddr_chl2_active); -+ isp_update_regtable(&pcdev->isp, 1); -+ isp_start_capturing(&pcdev->isp); -+ return 0; -+ } -+ -+ /* ISP is in the continuous mode */ -+ next = pcdev->capture.next; -+ next = next->next; -+ if (next == &pcdev->capture) { -+ isp_dbg("irq: the next vbuf is empty.\n"); -+ //isp_stop_capturing(&pcdev->isp); -+ irq_buf_empty_flag = 1; -+ irq_need_baffle = 1; -+ pcdev->dma_running = 0; -+ goto out; -+ } else -+ irq_buf_empty_flag = 0; -+ -+ vb = list_entry(next, struct videobuf_buffer, queue); -+ -+ /* setup the DMA address for transferring */ -+ yaddr_chl1_next = videobuf_to_dma_contig(vb); -+ yaddr_chl2_next = yaddr_chl1_next + size * 3 / 2; -+ if (isp_is_capturing_odd(&pcdev->isp)) -+ isp_set_even_frame(&pcdev->isp, yaddr_chl1_next, yaddr_chl2_next); -+ else -+ isp_set_odd_frame(&pcdev->isp, yaddr_chl1_next, yaddr_chl2_next); -+out: -+ isp_update_regtable(&pcdev->isp, 0); -+ return 0; -+} -+ -+/* platform code please fix me */ -+static void ak_camera_wakeup(struct ak_camera_dev *pcdev, -+ struct videobuf_buffer *vb, -+ struct ak_buffer *buf) -+{ -+ struct captureSync *adctime; -+ struct timeval cam_tv; -+ unsigned long adc_stamp; -+ unsigned long useconds; -+ unsigned long long actuallyBytes = 0; -+ -+ isp_dbg("%s (vb=0x%p) buf[%d], baddr = 0x%08lx, bsize = %d\n", -+ __func__, vb, vb->i, vb->baddr, vb->bsize); -+ -+ do_gettimeofday(&cam_tv); -+ -+ adctime = getRecordSyncSamples(); -+ -+ /* figure out the timestamp of frame */ -+ //adc_stamp = (unsigned long)(( adctime->adcCapture_bytes * 1000) / ( adctime->rate * ( adctime->frame_bits / 8 ) ) ); -+ actuallyBytes = adctime->adcCapture_bytes * (unsigned long long)1000; -+ if ( actuallyBytes != 0 ) { -+ do_div( actuallyBytes, ( adctime->rate * ( adctime->frame_bits / 8 ) ) ); -+ adc_stamp = actuallyBytes; -+ }else { //if current no audio -+ adc_stamp = 1000; //any value. -+ } -+ -+ if (cam_tv.tv_sec > adctime->tv.tv_sec) { -+ useconds = cam_tv.tv_usec + 1000000 - adctime->tv.tv_usec; -+ } else { -+ useconds = cam_tv.tv_usec - adctime->tv.tv_usec; -+ } -+ -+ vb->ts.tv_usec = (adc_stamp % 1000) * 1000 + useconds; -+ -+ if(vb->ts.tv_usec >= 1000000) { -+ vb->ts.tv_sec = adc_stamp / 1000 + 1; -+ vb->ts.tv_usec = vb->ts.tv_usec % 1000000; -+ } else { -+ vb->ts.tv_sec = adc_stamp / 1000; -+ } -+ -+ /* We don't have much to do if the capturing list is empty */ -+ if (list_empty(&pcdev->capture)) { -+ pcdev->active = NULL; -+ pcdev->dma_running = 0; -+ -+ //REG32(&pcdev->isp.base + ISP_PERI_PARA) &= ~(1 << 29); -+ //REG32(&pcdev->isp.base + ISP_PERI_PARA) |= (1 << 28); -+ -+ isp_stop_capturing(&pcdev->isp); -+ printk("isp-irq: vbuf queue is empty.\n"); -+ return; -+ } -+ -+ if (!irq_buf_empty_flag) { -+ list_del_init(&vb->queue); -+ vb->state = VIDEOBUF_DONE; -+ vb->field_count++; -+ // here, current frame commit to video_buffer layer -+ wake_up(&vb->done); -+ -+ isp_dbg("wakeup (vb=0x%p) buf[%d], baddr = 0x%08lx, bsize = %d\n", -+ vb, vb->i, vb->baddr, vb->bsize); -+ } -+ -+ pcdev->active = list_entry(pcdev->capture.next, -+ struct ak_buffer, vb.queue); -+ -+ ak_camera_setup_dma(pcdev); -+} -+ -+/* fix me */ -+static irqreturn_t ak_camera_dma_irq(int channel, void *data) -+{ -+ struct ak_camera_dev *pcdev = data; -+ struct ak_buffer *buf; -+ struct videobuf_buffer *vb; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&pcdev->lock, flags); -+ -+ /*Fixme: isp_check_irq must be improved */ -+ if (isp_check_irq(&pcdev->isp) < 0) -+ goto out; -+ -+ // throw the last irq when video mode working stopped. -+ if (irq_need_baffle) { -+ irq_need_baffle = 0; -+ goto out; -+ } -+ -+ vb = &pcdev->active->vb; -+ buf = container_of(vb, struct ak_buffer, vb); -+ //buf = pcdev->active; -+ WARN_ON(buf->inwork || list_empty(&vb->queue)); -+ -+ ak_camera_wakeup(pcdev, vb, buf); -+ -+out: -+ isp_clear_irq_status(&pcdev->isp); -+ spin_unlock_irqrestore(&pcdev->lock, flags); -+ return IRQ_HANDLED; -+} -+ -+static void isp_work(struct work_struct *work) -+{ -+ struct isp_struct *isp = container_of(work, struct isp_struct, work.work); -+ -+ update_exposure_value(isp); -+} -+ -+ -+#if 0 -+/* for debugging osd function of ISP */ -+static int create_osd_picture(struct ak_camera_dev *pcdev) -+{ -+ int startX, startY, endX, endY; -+ int picsize; -+ int osd_width, osd_height; -+ int i; -+ -+ startX = startY = 0; -+ endX = endY = 100; -+ osd_width = endX - startX + 1; -+ osd_height = endY - startY + 1; -+ picsize = osd_width * osd_height; -+ -+ if (!pcdev->osd_swbuff) { -+ pcdev->osd_swbuff = kmalloc(picsize, GFP_KERNEL); -+ if (!pcdev->osd_swbuff) -+ return -1; -+ } -+ -+ if (!pcdev->osd_buff) { -+ pcdev->osd_buff = kmalloc(picsize / 2 + picsize %2, GFP_KERNEL); -+ if (!pcdev->osd_buff) -+ return -1; -+ } -+ memset(pcdev->osd_buff, 0, (picsize / 2 + picsize % 2)); -+ -+ for (i = 0; i <picsize/2; i++) -+ pcdev->osd_swbuff[i] = 3; -+ -+ for (i = picsize/2; i <picsize; i++) -+ pcdev->osd_swbuff[i+1] = 4; -+ -+ for(i = 0; i<picsize/2; i++) -+ pcdev->osd_buff[i] = (pcdev->osd_swbuff[2*i] &0xf) | ((pcdev->osd_swbuff[2*i+1]&0xf)<<4); -+ -+ if(picsize%2) -+ pcdev->osd_buff[i] = pcdev->osd_swbuff[2*i]; -+ -+ return 0; -+} -+#endif -+ -+static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) -+{ -+ return container_of(ctrl->handler, struct soc_camera_device, -+ ctrl_handler); -+} -+ -+static int ak_camera_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -+{ -+// struct soc_camera_device *icd = ctrl_to_icd(ctrl); -+// struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+// struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+// struct ak_camera_dev *pcdev = ici->priv; -+ -+ isp_dbg("entry %s, ctrl->id=%x\n", __func__, ctrl->id); -+ -+ switch (ctrl->id) { -+ case V4L2_CID_BRIGHTNESS: -+ isp_dbg("%s(): V4L2_CID_BRIGHTNESS\n", __func__); -+ break; -+ case V4L2_CID_GAMMA: -+ isp_dbg("%s(): V4L2_CID_GAMMA\n", __func__); -+ break; -+ case V4L2_CID_SATURATION: -+ isp_dbg("%s(): V4L2_CID_SATURATION\n", __func__); -+ break; -+ case V4L2_CID_SHARPNESS: -+ isp_dbg("%s(): V4L2_CID_SHARPNESS\n", __func__); -+ break; -+ case V4L2_CID_DO_WHITE_BALANCE: -+ isp_dbg("%s(): V4L2_CID_DO_WHITE_BALANCE\n", __func__); -+ break; -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ isp_dbg("%s(): V4L2_CID_AUTO_WHITE_BALANCE\n", __func__); -+ break; -+ } -+ -+ return 0; -+} -+ -+/* -+ * @the isp standard control should be implemented here. -+ */ -+static int ak_camera_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct v4l2_control control; -+ struct soc_camera_device *icd = ctrl_to_icd(ctrl); -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ -+ isp_dbg("entry %s\n", __func__); -+ -+ if (pcdev->isp.cur_mode_class == ISP_RGB_CLASS) { -+ switch (ctrl->id) { -+ case V4L2_CID_BRIGHTNESS: -+ if (isp_set_brightness(&pcdev->isp, ctrl) == 0) -+ return 0; -+ break; -+ case V4L2_CID_GAMMA: -+ if (isp_set_gamma(&pcdev->isp, ctrl) == 0) -+ return 0; -+ break; -+ case V4L2_CID_SATURATION: -+ if (isp_set_saturation(&pcdev->isp, ctrl) == 0) -+ return 0; -+ break; -+ case V4L2_CID_SHARPNESS: -+ if (isp_set_sharpness(&pcdev->isp, ctrl) == 0) -+ return 0; -+ break; -+ case V4L2_CID_DO_WHITE_BALANCE: -+ if (isp_manu_set_wb_param(&pcdev->isp, ctrl) == 0) -+ return 0; -+ break; -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ if (isp_auto_set_wb_param(&pcdev->isp, ctrl) == 0) -+ return 0; -+ break; -+ } -+ } -+ -+ control.id = ctrl->id; -+ control.value = ctrl->val; -+ v4l2_subdev_call(sd, core, s_ctrl, &control); -+ -+ return 0; -+} -+ -+ -+static const struct v4l2_ctrl_ops ak_camera_ctrl_ops = { -+ .g_volatile_ctrl = ak_camera_g_volatile_ctrl, -+ .s_ctrl = ak_camera_s_ctrl, -+}; -+ -+static void set_sensor_cis_sclk(unsigned int cis_sclk) -+{ -+ unsigned long regval; -+ unsigned int cis_sclk_div; -+ -+ unsigned int peri_pll = ak_get_peri_pll_clk()/1000000; -+ -+ cis_sclk_div = peri_pll/cis_sclk - 1; -+ -+ regval = REG32(CLOCK_PERI_PLL_CTRL2); -+ regval &= ~(0x3f << 10); -+ regval |= (cis_sclk_div << 10); -+ REG32(CLOCK_PERI_PLL_CTRL2) = (1 << 19)|regval; -+ -+ isp_dbg("%s() cis_sclk=%dMHz peri_pll=%dMHz cis_sclk_div=%d\n", -+ __func__, cis_sclk, peri_pll, cis_sclk_div); -+} -+ -+ -+/* -+ * @Called when the /dev/videox is opened. -+ */ -+static int ak_camera_add_device(struct soc_camera_device *icd) -+{ -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ struct ak_camera_cam *cam; -+ int cis_sclk; -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ /* The ak camera host driver only support one image sensor */ -+ if (pcdev->icd) -+ return -EBUSY; -+ -+ dev_info(icd->parent, "AK Camera driver attached to camera %d\n", -+ icd->devnum); -+ -+ /* for debugging. Capture list should be empty when the video opened. */ -+ if (!list_empty(&pcdev->capture)) { -+ printk("Bug: pcdev->capture is not empty\n"); -+ list_del_init(&pcdev->capture); -+ } -+ -+ /********** config sensor module **********/ -+ //get sensor clk and power up the sensor -+ cis_sclk = v4l2_subdev_call(sd, core, init, 0); -+ if (cis_sclk <= 0) { -+ cis_sclk = 24; -+ } -+ -+ //set cis_sclk, the sensor present working 24MHz -+ clk_enable(pcdev->cis_sclk); -+ set_sensor_cis_sclk(cis_sclk); -+ -+ // load the default setting for sensor -+ v4l2_subdev_call(sd, core, load_fw); -+ -+ /********** config isp module **********/ -+ ak_soft_reset(AK_SRESET_CAMERA); -+ //set shared GPIO to CAMERA function -+ ak_group_config(ePIN_AS_CAMERA); -+ // enable isp clock -+ clk_enable(pcdev->clk); -+ -+ pcdev->icd = icd; -+ -+ /* FIXME Here, add out control */ -+ if (!icd->host_priv) { -+ v4l2_ctrl_new_std(&icd->ctrl_handler, &ak_camera_ctrl_ops, -+ V4L2_CID_BRIGHTNESS, ISP_BRIGHTNESS_0, -+ ISP_BRIGHTNESS_6, 1, ISP_BRIGHTNESS_2); -+ v4l2_ctrl_new_std(&icd->ctrl_handler, &ak_camera_ctrl_ops, -+ V4L2_CID_GAMMA, ISP_GAMMA_0, -+ ISP_GAMMA_6, 1, ISP_GAMMA_0); -+ v4l2_ctrl_new_std(&icd->ctrl_handler, &ak_camera_ctrl_ops, -+ V4L2_CID_SATURATION, ISP_SATURATION_0, -+ ISP_SATURATION_6, 1, ISP_SATURATION_1); -+ v4l2_ctrl_new_std(&icd->ctrl_handler, &ak_camera_ctrl_ops, -+ V4L2_CID_SHARPNESS, ISP_SHARPNESS_0, -+ ISP_SHARPNESS_6, 1, ISP_SHARPNESS_1); -+ v4l2_ctrl_new_std(&icd->ctrl_handler, &ak_camera_ctrl_ops, -+ V4L2_CID_DO_WHITE_BALANCE, ISP_MANU_WB_0, -+ ISP_MANU_WB_6, 1, ISP_MANU_WB_0); -+ v4l2_ctrl_new_std(&icd->ctrl_handler, &ak_camera_ctrl_ops, -+ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); -+ -+ /* FIXME: subwindow is lost between close / open */ -+ cam = kzalloc(sizeof(*cam), GFP_KERNEL); -+ if (!cam) -+ return -ENOMEM; -+ -+ /* We are called with current camera crop, initialise subrect with it */ -+ icd->host_priv = cam; -+ } else { -+ cam = icd->host_priv; -+ } -+ -+ return 0; -+} -+ -+/* -+ * @Called when the /dev/videox is closed. -+ */ -+static void ak_camera_remove_device(struct soc_camera_device *icd) -+{ -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ BUG_ON(icd != pcdev->icd); -+ -+ v4l2_subdev_call(sd, core, reset, 0); -+ -+ isp_clear_irq(&pcdev->isp); -+ isp_stop_capturing(&pcdev->isp); -+ -+ /* disable sensor clk */ -+ clk_disable(pcdev->cis_sclk); -+ -+ /* disable the clock of isp module */ -+ clk_disable(pcdev->clk); -+ -+ //ak_soft_reset(AK_SRESET_CAMERA); -+ -+ dev_info(icd->parent, "AK Camera driver detached from camera %d\n", -+ icd->devnum); -+ -+ pcdev->active = NULL; -+ pcdev->icd = NULL; -+ -+ CAMDBG("Leave %s\n", __func__); -+} -+ -+/* platform independent finished */ -+static int ak_camera_querycap(struct soc_camera_host *ici, -+ struct v4l2_capability *cap) -+{ -+ isp_dbg("entry %s\n", __func__); -+ -+ /* cap->name is set by the friendly caller:-> */ -+ strlcpy(cap->card, ak_cam_driver_description, sizeof(cap->card)); -+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; -+ -+ return 0; -+} -+ -+static int ak_camera_cropcap(struct soc_camera_device *icd, -+ struct v4l2_cropcap *crop) -+{ -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ -+ isp_dbg("enter %s\n", __func__); -+ -+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ -+ // isp support crop, need complete. -+ return v4l2_subdev_call(sd, video, cropcap, crop); -+} -+ -+static int ak_camera_get_crop(struct soc_camera_device *icd, -+ struct v4l2_crop *crop) -+{ -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ //struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ //struct ak_camera_dev *pcdev = ici->priv; -+ -+ isp_dbg("entry %s\n", __func__); -+ -+ return v4l2_subdev_call(sd, video, g_crop, crop); -+} -+ -+static int ak_camera_set_crop(struct soc_camera_device *icd, -+ struct v4l2_crop *crop) -+{ -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ int ret, width, height; -+ -+ isp_dbg("entry %s\n", __func__); -+ -+ if (pcdev->dma_running) { -+ /* make sure streaming is not started */ -+ v4l2_err(&ici->v4l2_dev, -+ "Cannot change crop when streaming is ON\n"); -+ return -EBUSY; -+ } -+ -+ width = crop->c.width - crop->c.left; -+ height = crop->c.height - crop->c.top; -+ if ((crop->c.top < 0 || crop->c.left < 0) -+ ||(((width * 3) < 18) || (height * 3) < 18) -+ ||((width > 1280) || (height > 720))) { -+ v4l2_err(&ici->v4l2_dev, -+ "doesn't support negative values for top & left\n"); -+ return -EINVAL; -+ } -+ -+ if ((ret = isp_set_crop(&pcdev->isp, crop->c)) < 0) -+ ret = v4l2_subdev_call(sd, video, s_crop, crop); -+ -+ return ret; -+} -+ -+ -+/* -+ * @Called before ak_camera_set_fmt. -+ */ -+static int ak_camera_try_fmt(struct soc_camera_device *icd, -+ struct v4l2_format *f) -+{ -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ const struct soc_camera_format_xlate *xlate; -+ struct v4l2_pix_format *pix = &f->fmt.pix; -+ struct v4l2_mbus_framefmt mf; -+ int ret; -+ /* TODO: limit to ak hardware capabilities */ -+ CAMDBG("entry %s\n", __func__); -+ -+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); -+ if (!xlate) { -+ dev_warn(icd->parent, "Format %x not found\n", -+ pix->pixelformat); -+ return -EINVAL; -+ } -+ -+ mf.width = pix->width; -+ mf.height = pix->height; -+ mf.field = pix->field; -+ mf.colorspace = pix->colorspace; -+ mf.code = xlate->code; -+ -+ /* limit to sensor capabilities */ -+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ pix->width = mf.width; -+ pix->height = mf.height; -+ pix->field = mf.field; -+ pix->colorspace = mf.colorspace; -+ -+ return 0; -+} -+ -+/* platform independent finished */ -+static int ak_camera_set_fmt(struct soc_camera_device *icd, -+ struct v4l2_format *f) -+{ -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ const struct soc_camera_format_xlate *xlate; -+ struct v4l2_pix_format *pix = &f->fmt.pix; -+ struct v4l2_mbus_framefmt mf; -+ struct v4l2_cropcap cropcap; -+ int ret, buswidth; -+ -+ isp_dbg("entry %s\n", __func__); -+ -+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); -+ if (!xlate) { -+ dev_warn(icd->parent, "Format %x not found\n", -+ pix->pixelformat); -+ return -EINVAL; -+ } -+ -+ //if (YUV_OUT) -+ -+ buswidth = xlate->host_fmt->bits_per_sample; -+ if (buswidth > 10) { -+ dev_warn(icd->parent, -+ "bits-per-sample %d for format %x unsupported\n", -+ buswidth, pix->pixelformat); -+ return -EINVAL; -+ } -+ -+ mf.width = pix->width; -+ mf.height = pix->height; -+ mf.field = pix->field; -+ mf.colorspace = pix->colorspace; -+ mf.code = xlate->code; -+ icd->current_fmt = xlate; -+ -+ v4l2_subdev_call(sd, video, cropcap, &cropcap); -+ if (mf.width != cropcap.bounds.width -+ || mf.height != cropcap.bounds.height) { -+ mf.width = cropcap.defrect.width; -+ mf.height = cropcap.defrect.height; -+ } -+ -+ isp_dbg("%s. mf.width = %d, mf.height = %d\n", -+ __func__, mf.width, mf.height); -+ -+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); -+ if (ret < 0) -+ return ret; -+ -+ if (mf.code != xlate->code) -+ return -EINVAL; -+ -+ /* recored the VGA size used for check to enable isp ch2 when RGB input*/ -+ pcdev->isp.fmt_def_width = mf.width; -+ pcdev->isp.fmt_def_height = mf.height; -+ -+ /* -+ * @fmt_width and fmt_height is the input image size of sensor. -+ * @chl1_width and chl1_height is the output image size for user. -+ */ -+ pcdev->isp.fmt_width = pix->width; -+ pcdev->isp.fmt_height = pix->height; -+ pcdev->isp.chl1_width = pix->width; -+ pcdev->isp.chl1_height= pix->height; -+ -+ isp_set_cutter_window(&pcdev->isp, 0, 0, mf.width, mf.height); -+ isp_set_channel1_scale(&pcdev->isp, pix->width, pix->height); -+ -+ isp_dbg("%s: chl1_width=%d, chl1_height=%d\n", __func__, -+ pcdev->isp.chl1_width, pcdev->isp.chl1_height); -+ -+ return ret; -+} -+ -+static int ak_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, -+ struct soc_camera_format_xlate *xlate) -+{ -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ struct device *dev = icd->parent; -+ struct soc_camera_host *ici = to_soc_camera_host(dev); -+ struct ak_camera_dev *pcdev = ici->priv; -+ int ret, formats = 0; -+ enum v4l2_mbus_pixelcode code; -+ const struct soc_mbus_pixelfmt *fmt; -+ -+ CAMDBG("entry %s\n", __func__); -+ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); -+ if (ret < 0) -+ /* No more formats */ -+ return 0; -+ -+ /* -+ * @Note: ISP only support yuv420 output and jpeg out. -+ * FIXME1: We miss jpeg here. -+ * FIXME2: the output squence of YUV is actually UYVY. -+ */ -+ fmt = soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8); -+ if (!fmt) { -+ dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); -+ return 0; -+ } -+ CAMDBG("get format %s code=%d from sensor\n", fmt->name, code); -+ -+ /* Generic pass-through */ -+ formats++; -+ if (xlate) { -+ xlate->host_fmt = fmt; -+ xlate->code = code; -+ xlate++; -+ -+ /* -+ * @decide the default working mode of isp -+ * @prefer RGB mode -+ */ -+ if (code < V4L2_MBUS_FMT_Y8_1X8) { -+ pcdev->def_mode = ISP_RGB_VIDEO_OUT; -+ //pcdev->def_mode = ISP_RGB_OUT; -+ } -+ -+ if ((pcdev->def_mode != ISP_RGB_VIDEO_OUT) -+ && (pcdev->def_mode != ISP_RGB_OUT)) { -+ pcdev->def_mode = ISP_YUV_VIDEO_BYPASS; -+ //pcdev->def_mode = ISP_YUV_BYPASS; -+ } -+ pcdev->isp.cur_mode = pcdev->def_mode; -+ update_cur_mode_class(&pcdev->isp); -+ -+ dev_dbg(dev, "Providing format %s in pass-through mode\n", -+ fmt->name); -+ } -+ -+ return formats; -+} -+ -+static void ak_camera_put_formats(struct soc_camera_device *icd) -+{ -+ CAMDBG("entry %s\n", __func__); -+ kfree(icd->host_priv); -+ icd->host_priv = NULL; -+ CAMDBG("leave %s\n", __func__); -+} -+ -+static int isp_set_sensor_param(struct isp_struct *isp, struct isp_config_sensor_reg *ctrl) -+{ -+ if (ctrl->enable) -+ aksensor_set_param(ctrl->cmd, ctrl->data); -+ return 0; -+} -+ -+/* -+ * The private interface of ISP for application user. -+ */ -+ static int ak_camera_set_parm(struct soc_camera_device *icd, -+ struct v4l2_streamparm *a) -+{ -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ struct isp_mode_info *mode_info; -+ int retval = 0, *parm_type; -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ parm_type = (int *)a->parm.raw_data; -+ switch(*parm_type) { -+ case ISP_PARM_MODE: -+ mode_info = (struct isp_mode_info *)parm_type; -+ if (!pcdev->dma_running) { -+ pcdev->isp.cur_mode = mode_info->mode; -+ -+ update_cur_mode_class(&pcdev->isp); -+ isp_apply_mode(&pcdev->isp); -+ -+ printk("%s: change working mode to %d\n", __func__, mode_info->mode); -+ } else { -+ printk("%s: working mode can not be changed when dma is running\n", __func__); -+ retval = -EBUSY; -+ } -+ break; -+ case ISP_PARM_CHANNEL2: -+ retval = isp_set_channel2(&pcdev->isp, (struct isp_channel2_info *)parm_type); -+ break; -+ case ISP_PARM_OSD: -+ retval = isp_set_osd(&pcdev->isp, (struct isp_osd_info *)parm_type); -+ break; -+ case ISP_PARM_OCCLUSION: -+ retval = isp_set_occlusion_area(&pcdev->isp, (struct isp_occlusion_info *)parm_type); -+ break; -+ case ISP_PARM_OCCLUSION_COLOR: -+ retval = isp_set_occlusion_color(&pcdev->isp, (struct isp_occlusion_color *)parm_type); -+ break; -+ case ISP_PARM_ZOOM: -+ retval = isp_set_zoom(&pcdev->isp, (struct isp_zoom_info *)parm_type); -+ break; -+ case ISP_CID_BLACK_BALANCE: -+ retval = isp_set_black_balance(&pcdev->isp, (struct isp_black_balance *)parm_type); -+ break; -+ case ISP_CID_LENS: -+ retval = isp_set_lens_correct(&pcdev->isp, (struct isp_lens_correct *)parm_type); -+ break; -+ case ISP_CID_DEMOSAIC: -+ retval = isp_set_demosaic(&pcdev->isp, (struct isp_demosaic *)parm_type); -+ break; -+ case ISP_CID_RGB_FILTER: -+ retval = isp_set_rgb_filter(&pcdev->isp, (struct isp_rgb_filter *)parm_type); -+ break; -+ case ISP_CID_UV_FILTER: -+ retval = isp_set_uv_iso_filter(&pcdev->isp, (struct isp_uv_filter *)parm_type); -+ break; -+ case ISP_CID_DEFECT_PIXEL: -+ retval = isp_set_defect_pixel(&pcdev->isp, (struct isp_defect_pixel *)parm_type); -+ break; -+ case ISP_CID_WHITE_BALANCE: -+ retval = isp_set_manu_wb(&pcdev->isp, (struct isp_white_balance *)parm_type); -+ break; -+ case ISP_CID_AUTO_WHITE_BALANCE: -+ retval = isp_set_auto_wb(&pcdev->isp, (struct isp_auto_white_balance *)parm_type); -+ break; -+ case ISP_CID_COLOR: -+ retval = isp_set_color_correct(&pcdev->isp, (struct isp_color_correct *)parm_type); -+ break; -+ case ISP_CID_GAMMA: -+ retval = isp_set_gamma_calc(&pcdev->isp, (struct isp_gamma_calculate *)parm_type); -+ break; -+ case ISP_CID_BRIGHTNESS_ENHANCE: -+ retval = isp_set_brightness_enhance(&pcdev->isp, (struct isp_brightness_enhance *)parm_type); -+ break; -+ case ISP_CID_SATURATION: -+ retval = isp_set_uv_saturation(&pcdev->isp, (struct isp_saturation *)parm_type); -+ break; -+ case ISP_CID_HISTOGRAM: -+ retval = isp_set_histogram(&pcdev->isp, (struct isp_histogram *)parm_type); -+ break; -+ case ISP_CID_SPECIAL_EFFECT: -+ retval = isp_set_special_effect(&pcdev->isp, (struct isp_special_effect *)parm_type); -+ break; -+ case ISP_CID_SET_SENSOR_PARAM: -+ retval = isp_set_sensor_param(&pcdev->isp, (struct isp_config_sensor_reg *)parm_type); -+ break; -+ default: -+ retval = -EINVAL; -+ printk("%s: private control encounter unknown type\n", __func__); -+ } -+ -+ CAMDBG("leave %s\n", __func__); -+ -+ return retval; -+} -+ -+ -+ static int ak_camera_get_parm(struct soc_camera_device *icd, -+ struct v4l2_streamparm *a) -+{ -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ struct isp_channel2_info *chl2_info; -+ struct isp_white_balance *co_rgb_info; -+ struct isp_mode_info *mode_info; -+ int retval = 0, *parm_type; -+ -+ parm_type = (int *)a->parm.raw_data; -+ -+ switch(*parm_type) { -+ case ISP_PARM_MODE: -+ mode_info = (struct isp_mode_info *)parm_type; -+ mode_info->mode = pcdev->isp.cur_mode; -+ break; -+ case ISP_PARM_CHANNEL2: -+ chl2_info = (struct isp_channel2_info *)parm_type; -+ chl2_info->width = pcdev->isp.chl2_width; -+ chl2_info->height = pcdev->isp.chl2_height; -+ chl2_info->enable = pcdev->isp.chl2_enable; -+ break; -+ case ISP_CID_WHITE_BALANCE: -+ case ISP_CID_AUTO_WHITE_BALANCE: -+ co_rgb_info = (struct isp_white_balance *)parm_type; -+ co_rgb_info->co_r = pcdev->isp.wb_param.co_r; -+ co_rgb_info->co_g = pcdev->isp.wb_param.co_g; -+ co_rgb_info->co_b = pcdev->isp.wb_param.co_b; -+ break; -+ default: -+ retval = -EINVAL; -+ printk("%s: private control encounter unknown type\n", __func__); -+ break; -+ } -+ -+ CAMDBG("leave %s\n", __func__); -+ -+ return retval; -+} -+ -+ -+/* Maybe belong platform code fix me */ -+static int ak_camera_set_bus_param(struct soc_camera_device *icd) -+{ -+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; -+ unsigned long common_flags; -+ int ret; -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ /* AK39 supports 8bit and 10bit buswidth */ -+ ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); -+ if (!ret) { -+ common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS); -+ if (!common_flags) { -+ dev_warn(icd->parent, -+ "Flags incompatible: camera 0x%x, host 0x%x\n", -+ cfg.flags, CSI_BUS_FLAGS); -+ return -EINVAL; -+ } -+ } else if (ret != -ENOIOCTLCMD) { -+ return ret; -+ } else { -+ common_flags = CSI_BUS_FLAGS; -+ } -+ -+ /* Make choises, based on platform choice */ -+ if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && -+ (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { -+ if (!pcdev->pdata || -+ pcdev->pdata->flags & AK_CAMERA_VSYNC_HIGH) -+ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; -+ else -+ common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; -+ } -+ -+ if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && -+ (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { -+ if (!pcdev->pdata || -+ pcdev->pdata->flags & AK_CAMERA_PCLK_RISING) -+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; -+ else -+ common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; -+ } -+ -+ if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && -+ (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { -+ if (!pcdev->pdata || -+ pcdev->pdata->flags & AK_CAMERA_DATA_HIGH) -+ common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; -+ else -+ common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; -+ } -+ -+ cfg.flags = common_flags; -+ ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); -+ if (ret < 0 && ret != -ENOIOCTLCMD) { -+ dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", -+ common_flags, ret); -+ return ret; -+ } -+ -+ CAMDBG("leave %s\n", __func__); -+ -+ return 0; -+} -+ -+/* platform independent finished*/ -+static void ak_camera_init_videobuf(struct videobuf_queue *q, -+ struct soc_camera_device *icd) -+{ -+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -+ struct ak_camera_dev *pcdev = ici->priv; -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ videobuf_queue_dma_contig_init(q, &ak_videobuf_ops, icd->parent, -+ &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, -+ V4L2_FIELD_NONE, -+ sizeof(struct ak_buffer), icd, &icd->video_lock); -+ -+ CAMDBG("leave %s\n", __func__); -+} -+ -+/* platform independent finished*/ -+static int ak_camera_reqbufs(struct soc_camera_device *icd, -+ struct v4l2_requestbuffers *p) -+{ -+ int i; -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ /* This is for locking debugging only. I removed spinlocks and now I -+ * check whether .prepare is ever called on a linked buffer, or whether -+ * a dma IRQ can occur for an in-work or unlinked buffer. Until now -+ * it hadn't triggered */ -+ for (i = 0; i < p->count; i++) { -+ struct ak_buffer *buf = container_of(icd->vb_vidq.bufs[i], -+ struct ak_buffer, vb); -+ buf->inwork = 0; -+ INIT_LIST_HEAD(&buf->vb.queue); -+ } -+ -+ CAMDBG("leave %s\n", __func__); -+ -+ return 0; -+} -+ -+/* platform independent */ -+static unsigned int ak_camera_poll(struct file *file, poll_table *pt) -+{ -+ struct soc_camera_device *icd = file->private_data; -+ struct ak_buffer *buf; -+ -+ buf = list_entry(icd->vb_vidq.stream.next, struct ak_buffer, -+ vb.stream); -+ -+ poll_wait(file, &buf->vb.done, pt); -+ -+ if (buf->vb.state == VIDEOBUF_DONE || -+ buf->vb.state == VIDEOBUF_ERROR) { -+ return POLLIN | POLLRDNORM; -+ } -+ -+ return 0; -+} -+ -+ -+static struct soc_camera_host_ops ak_soc_camera_host_ops = { -+ .owner = THIS_MODULE, -+ .add = ak_camera_add_device, -+ .remove = ak_camera_remove_device, -+ .get_formats = ak_camera_get_formats, -+ .put_formats = ak_camera_put_formats, -+ .set_bus_param = ak_camera_set_bus_param, -+ .cropcap = ak_camera_cropcap, -+ .get_crop = ak_camera_get_crop, -+ .set_crop = ak_camera_set_crop, -+ .set_fmt = ak_camera_set_fmt, -+ .try_fmt = ak_camera_try_fmt, -+ .init_videobuf = ak_camera_init_videobuf, -+ .reqbufs = ak_camera_reqbufs, -+ .poll = ak_camera_poll, -+ .querycap = ak_camera_querycap, -+ .set_parm = ak_camera_set_parm, -+ .get_parm = ak_camera_get_parm, -+}; -+ -+static int ak_camera_probe(struct platform_device *pdev) -+{ -+ struct ak_camera_dev *pcdev; -+ struct resource *res; -+ struct clk *clk, *cis_sclk; -+ void __iomem *base; -+ unsigned int irq; -+ int err = 0; -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irq = platform_get_irq(pdev, 0); -+ if (!res || irq < 0) { -+ printk("platform_get_irq | platform_get_resource\n"); -+ err = -ENODEV; -+ goto exit; -+ } -+ -+ /* -+ * @get isp working clock -+ */ -+ clk = clk_get(&pdev->dev, "camera"); -+ if (IS_ERR(clk)) { -+ err = PTR_ERR(clk); -+ goto exit; -+ } -+ -+ /* -+ * @get cis_sclk for sensor -+ */ -+ cis_sclk = clk_get(&pdev->dev, "sensor"); -+ if (IS_ERR(cis_sclk)) { -+ err = PTR_ERR(cis_sclk); -+ goto exit_put_clk; -+ } -+ -+ /* -+ ** @allocate memory to struct ak_camera, including struct soc_camera_host -+ ** @and struct v4l2_device -+ */ -+ pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); -+ if (!pcdev) { -+ err = -ENOMEM; -+ goto exit_put_cisclk; -+ } -+ -+ /* @initailization for struct pcdev */ -+ pcdev->res = res; -+ pcdev->clk = clk; -+ pcdev->cis_sclk = cis_sclk; -+ pcdev->dma_running = 0; -+ -+ pcdev->pdata = pdev->dev.platform_data; -+ if (!pcdev->pdata) { -+ err = -ENODEV; -+ goto exit_put_cisclk; -+ } -+ -+ if (pcdev->mclk > 0) -+ pcdev->mclk = pcdev->pdata->mclk; -+ else { -+ dev_warn(&pdev->dev, -+ "Platform mclk == 0! Please, fix your platform data. " -+ "Using default 24MHz\n"); -+ pcdev->mclk = 24; -+ } -+ -+ INIT_LIST_HEAD(&pcdev->capture); -+ spin_lock_init(&pcdev->lock); -+ -+ /* -+ * Request the regions. -+ */ -+ if (!request_mem_region(res->start, resource_size(res), AK_CAM_DRV_NAME)) { -+ err = -EBUSY; -+ goto exit_kfree; -+ } -+ -+ base = ioremap_nocache(res->start, resource_size(res)); -+ if (!base) { -+ err = -ENOMEM; -+ goto exit_release; -+ } -+ pcdev->irq = irq; -+ pcdev->base = base; -+ -+ /* -+ * @initialize pcdev->isp_struct -+ */ -+ pcdev->isp.base = base; -+ if (isp_module_init(&pcdev->isp) < 0) { -+ err = -ENOMEM; -+ goto exit_iounmap; -+ } -+ -+ /* -+ * request irq -+ */ -+ err = request_irq(irq, ak_camera_dma_irq, IRQF_DISABLED, "ak_camera", pcdev); -+ if (err) { -+ err = -EBUSY; -+ goto exit_freeisp; -+ } -+ -+ INIT_DELAYED_WORK(&pcdev->isp.work, isp_work); -+ -+ /* -+ ** @register soc_camera_host -+ */ -+ pcdev->soc_host.drv_name = AK_CAM_DRV_NAME; -+ pcdev->soc_host.ops = &ak_soc_camera_host_ops; -+ pcdev->soc_host.priv = pcdev; -+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev; -+ pcdev->soc_host.nr = pdev->id; -+ -+ err = soc_camera_host_register(&pcdev->soc_host); -+ if (err) { -+ goto exit_freeirq; -+ } -+ -+ dev_info(&pdev->dev, "AK Camera driver loaded\n"); -+ -+ return 0; -+ -+exit_freeirq: -+ free_irq(irq, pcdev); -+exit_freeisp: -+ isp_module_fini(&pcdev->isp); -+exit_iounmap: -+ iounmap(base); -+exit_release: -+ release_mem_region(res->start, resource_size(res)); -+exit_kfree: -+ kfree(pcdev); -+exit_put_cisclk: -+ clk_put(cis_sclk); -+exit_put_clk: -+ clk_put(clk); -+exit: -+ return err; -+} -+ -+static int ak_camera_remove(struct platform_device *pdev) -+{ -+ -+ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); -+ struct ak_camera_dev *pcdev = container_of(soc_host, -+ struct ak_camera_dev, soc_host); -+ struct resource *res; -+ -+ CAMDBG("entry %s\n", __func__); -+ -+ /* free irq */ -+ free_irq(pcdev->irq, pcdev); -+ -+ /* free clk */ -+ clk_put(pcdev->clk); -+ clk_put(pcdev->cis_sclk); -+ -+ soc_camera_host_unregister(soc_host); -+ -+ iounmap(pcdev->base); -+ -+ res = pcdev->res; -+ release_mem_region(res->start, resource_size(res)); -+ -+ /* -+ * @deconstruct the isp object. -+ */ -+ isp_module_fini(&pcdev->isp); -+ -+ kfree(pcdev); -+ -+ dev_info(&pdev->dev, "AK Camera driver unloaded\n"); -+ -+ return 0; -+} -+ -+static struct platform_driver ak_camera_driver = { -+ .probe = ak_camera_probe, -+ .remove = ak_camera_remove, -+ .driver = { -+ .name = AK_CAM_DRV_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init ak_camera_init(void) -+{ -+ CAMDBG("entry %s\n", __func__); -+ -+ return platform_driver_register(&ak_camera_driver); -+} -+ -+static void __exit ak_camera_exit(void) -+{ -+ CAMDBG("entry %s\n", __func__); -+ -+ platform_driver_unregister(&ak_camera_driver); -+} -+ -+module_init(ak_camera_init); -+module_exit(ak_camera_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("wu_daochao <wu_daochao@anyka.oa>"); -+MODULE_DESCRIPTION("Driver for ak Camera Interface"); -+ -diff --git a/drivers/media/video/plat-anyka/aksensor.c b/drivers/media/video/plat-anyka/aksensor.c -new file mode 100755 -index 00000000..0da78b9a ---- /dev/null -+++ b/drivers/media/video/plat-anyka/aksensor.c -@@ -0,0 +1,750 @@ -+/* -+ * ak sensor Driver -+ * -+ * Copyright (C) 2012 Anyka -+ * -+ * Based on anykaplatform driver, -+ * -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/i2c.h> -+#include <linux/slab.h> -+#include <linux/delay.h> -+#include <linux/v4l2-mediabus.h> -+#include <linux/videodev2.h> -+ -+#include <media/soc_camera.h> -+#include <media/v4l2-chip-ident.h> -+#include <media/v4l2-subdev.h> -+#include <media/v4l2-ctrls.h> -+ -+#include <plat-anyka/aksensor.h> -+#include <mach/gpio.h> -+ -+//#define SENSOR_DEBUG -+#ifdef SENSOR_DEBUG -+#define sensor_dbg(fmt...) printk(KERN_INFO "Sensor: " fmt) -+#else -+#define sensor_dbg(fmt, args...) do{}while(0) -+#endif -+ -+#define SENDBG(fmt, args...) do{}while(0) -+ -+static struct sensor_info *cur_sensor_info; -+static const struct aksensor_color_format *cur_sensor_cfmts; -+ -+T_CAMERA_WORKMODE g_mode = CAMERA_WMODE_REC; -+static struct i2c_client *g_client; -+ -+struct aksensor_priv { -+ struct v4l2_subdev subdev; -+ struct v4l2_ctrl_handler hdl; -+ struct aksensor_camera_info *info; -+ const struct aksensor_color_format *cfmt; -+ struct aksensor_win_size win; -+ int model; -+}; -+ -+static struct sensor_info *sensor_info_array[SENSOR_MAX_SUPPORT]; -+ -+int register_sensor(struct sensor_info *si) -+{ -+ int i, ret; -+ -+ if (!si) -+ return -1; -+ -+ if ((si->sensor_id <=0) || (si->handler == NULL)) -+ return -1; -+ -+ ret = -1; -+ for (i = 0; i < SENSOR_MAX_SUPPORT; i++) { -+ if (sensor_info_array[i] != NULL) -+ continue; -+ -+ sensor_info_array[i] = si; -+ ret = 0; -+ SENDBG("register sensor(id=0x%x) successfully\n", si->sensor_id); -+ break; -+ } -+ -+ if (i == SENSOR_MAX_SUPPORT) -+ SENDBG("register sensor(id=0x%x) failed!(no enough space)\n", si->sensor_id); -+ -+ return ret; -+} -+EXPORT_SYMBOL(register_sensor); -+ -+/** -+ * @brief camera probe pointer -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param -+ * @return sensor_info * camera device pointer -+ * @retval -+ */ -+static struct sensor_info *probe_sensors(struct i2c_client *client) -+{ -+ int i, read_id; -+ -+ for (i = 0; i < SENSOR_MAX_SUPPORT; i++) -+ { -+ if (sensor_info_array[i]) -+ { -+ sensor_info_array[i]->handler->cam_open_func(); -+ read_id = sensor_info_array[i]->handler->cam_read_id_func(); -+ -+ if (!(strcmp(sensor_info_array[i]->sensor_name, "hm1375"))) -+ read_id = read_id & 0x0fff; -+ -+ if ((read_id == sensor_info_array[i]->sensor_id) -+ && ((read_id != 0xffff) || (read_id != 0xff))) { -+ -+ dev_info(&client->dev, "Probing %s Sensor ID: 0x%x\n", -+ sensor_info_array[i]->sensor_name, read_id); -+ -+ return sensor_info_array[i]; -+ } else { -+ sensor_info_array[i]->handler->cam_close_func(); -+ } -+ } -+ } -+ -+ return NULL; -+} -+ -+ -+s32 aksensor_i2c_write_byte_short(u8 daddr, u16 raddr, u8 *data, u32 size) -+{ -+ unsigned char msg[3]; -+ msg[0] = raddr >> 8; -+ msg[1] = raddr & 0xff; -+ msg[2] = *data; -+ -+// printk("msg=0x%02x%02x, 0x%02x(write)\n", msg[0], msg[1], msg[2]); -+ return i2c_master_send(g_client, msg, 3); -+} -+ -+s32 aksensor_i2c_read_byte_short(u8 daddr, u16 raddr) -+{ -+ unsigned char msg[2]; -+ unsigned char data; -+ -+ g_client->addr = daddr/2; -+ msg[0] = raddr >> 8; -+ msg[1] = raddr & 0xff; -+ -+ i2c_master_send(g_client, msg, 2); -+ -+ i2c_master_recv(g_client, &data, 1); -+ -+ // printk("msg=0x%02x%02x, 0x%02x(read)\n", msg[0], msg[1], data); -+ -+ return data; -+} -+ -+s32 aksensor_i2c_write_word_data(u8 daddr, u16 raddr, u16 *data, u32 size) -+{ -+ unsigned char msg[4]; -+ -+ msg[0] = raddr >> 8; //high 8bit first send -+ msg[1] = raddr & 0xff; //low 8bit second send -+ msg[2] = *data & 0xff; //low 8bit first send -+ msg[3] = *data >> 8; //high 8bit second send -+ -+ g_client->addr = daddr >> 1; -+ -+ //printk("(cmd): 0x%02x %02x, (data): %02x %02x\n", msg[0], msg[1], msg[2], msg[3]); -+ return i2c_master_send(g_client, msg, 4); -+} -+ -+s32 aksensor_i2c_read_word_data(u8 daddr, u16 raddr) -+{ -+ unsigned char msg[4]; -+ unsigned char buf[2]; -+ -+ msg[0] = raddr >> 8; //high 8bit first send -+ msg[1] = raddr & 0xff; //low 8bit second send -+ -+ g_client->addr = daddr >> 1; -+ -+ i2c_master_send(g_client, msg, 2); -+ -+ i2c_master_recv(g_client, buf, 2); -+ -+ return (buf[1] << 8)|buf[0]; -+} -+ -+s32 aksensor_i2c_write_byte_data(u8 daddr, u8 raddr, u8 *data, u32 size) -+{ -+ return i2c_smbus_write_byte_data(g_client, raddr, *data); -+} -+ -+s32 aksensor_i2c_read_byte_data(u8 daddr, u8 raddr) -+{ -+ g_client->addr = daddr/2; -+ return i2c_smbus_read_byte_data(g_client,raddr); -+} -+ -+/*****************************************/ -+static struct aksensor_priv *to_aksensor(const struct i2c_client *client) -+{ -+ return container_of(i2c_get_clientdata(client), struct aksensor_priv, subdev); -+} -+ -+static int aksensor_init(struct v4l2_subdev *sd, u32 val) -+{ -+ int ret; -+ SENDBG("entry %s\n", __func__); -+ if (cur_sensor_info->handler != NULL) -+ { -+ cur_sensor_info->handler->cam_open_func(); -+ ret = cur_sensor_info->handler->cam_mclk; -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int aksensor_loadfw(struct v4l2_subdev *sd) -+{ -+ SENDBG("entry %s\n", __func__); -+ if ((cur_sensor_info->handler != NULL) -+ && (cur_sensor_info->handler->cam_init_func != NULL)) -+ { -+ if (cur_sensor_info->handler->cam_init_func()) -+ return AK_TRUE; -+ } -+ return AK_FALSE; -+} -+ -+static int aksensor_reset( struct v4l2_subdev *sd, u32 val ) -+{ -+// struct i2c_client *client = v4l2_get_subdevdata(sd); -+// struct aksensor_priv *priv = i2c_get_clientdata(client); -+ -+ SENDBG("entry %s\n", __func__); -+ -+ //priv->win.width = VGA_WIDTH; -+ //priv->win.height = VGA_HEIGHT; -+ -+ if (NULL != cur_sensor_info->handler) { -+ cur_sensor_info->handler->cam_close_func(); -+ } -+ -+ return 0; -+} -+ -+static int aksensor_g_chip_ident(struct v4l2_subdev *sd, -+ struct v4l2_dbg_chip_ident *id) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct aksensor_priv *priv = to_aksensor(client); -+ -+ id->ident = priv->model; -+ id->revision = 0; -+ -+ return 0; -+} -+ -+static int aksensor_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -+{ -+ int ret = 0; -+ sensor_dbg("entry %s\n", __func__); -+ //if (cur_sensor_info->ctrls) -+ // ret = cur_sensor_info->ctrls->ops->queryctrl(ctrl); -+ return ret; -+} -+static int aksensor_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+// struct v4l2_ctrl v4l2ctrl; -+ -+ sensor_dbg("entry %s\n", __func__); -+#if 0 -+ if (cur_sensor_info->ctrls) { -+ cur_sensor_info->ctrls->ops->g_volatile_ctrl(&v4l2ctrl); -+ ctrl->id = v4l2ctrl.id; -+ ctrl->val = v4l2ctrl.val; -+ } -+#endif -+ return 0; -+} -+static int aksensor_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -+{ -+ int ret = 0; -+ struct v4l2_ctrl v4l2ctrl; -+ -+ sensor_dbg("entry %s\n", __func__); -+ -+ if (cur_sensor_info->ctrls) { -+ v4l2ctrl.id = ctrl->id; -+ v4l2ctrl.val = ctrl->value; -+ ret = cur_sensor_info->ctrls->ops->s_ctrl(&v4l2ctrl); -+ } -+ return ret; -+} -+ -+static struct v4l2_subdev_core_ops aksensor_subdev_core_ops = { -+ .init = aksensor_init, -+ .load_fw = aksensor_loadfw, -+ .reset = aksensor_reset, -+ .g_chip_ident = aksensor_g_chip_ident, -+ .queryctrl = aksensor_queryctrl, -+ .g_ctrl = aksensor_g_ctrl, -+ .s_ctrl = aksensor_s_ctrl, -+}; -+ -+ -+/* -+ * soc_camera_ops function -+ */ -+static int aksensor_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ SENDBG("entry %s\n", __func__); -+ SENDBG("%s==>enable=%d\n", __func__, enable); -+ SENDBG("leave %s\n", __func__); -+ return 0; -+} -+ -+static int aksensor_get_params(struct i2c_client *client, -+ enum v4l2_mbus_pixelcode code) -+{ -+ struct aksensor_priv *priv = to_aksensor(client); -+ int ret = -EINVAL; -+ int i; -+ -+ SENDBG("entry %s\n", __func__); -+ -+ /* -+ * select format -+ */ -+ priv->cfmt = NULL; -+ for (i = 0; i < cur_sensor_info->num_formats; i++) { -+ if (code == cur_sensor_cfmts[i].code) { -+ priv->cfmt = cur_sensor_cfmts + i; -+ break; -+ } -+ } -+ if (!priv->cfmt) -+ goto aksensor_set_fmt_error; -+ -+ return 0; -+ -+aksensor_set_fmt_error: -+ priv->cfmt = NULL; -+ return ret; -+} -+ -+/* first called by soc_camera_prove to initialize icd->user_width... */ -+static int aksensor_g_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *mf) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct aksensor_priv *priv = container_of(sd, struct aksensor_priv, subdev); -+ int ret; -+ -+ SENDBG("entry %s\n", __func__); -+ -+ if (!priv->cfmt) { -+ SENDBG("select VGA for first time\n"); -+ ret = aksensor_get_params(client, V4L2_MBUS_FMT_YUYV8_2X8); -+ if (ret < 0) -+ return ret; -+ } -+ -+ mf->width = priv->win.width; -+ mf->height = priv->win.height; -+ mf->code = priv->cfmt->code; -+ mf->colorspace = priv->cfmt->colorspace; -+ mf->field = V4L2_FIELD_NONE; -+ -+ return 0; -+} -+ -+ -+static int aksensor_try_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *mf) -+{ -+ SENDBG("entry %s\n", __func__); -+ SENDBG("leave %s\n", __func__); -+ -+ return 0; -+} -+ -+static int aksensor_s_fmt(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *mf) -+{ -+ struct aksensor_priv *priv = container_of(sd, struct aksensor_priv, subdev); -+// struct v4l2_pix_format *pix = &f->fmt.pix; -+ -+ T_BOOL bRet = AK_FALSE; -+ int ret = -EINVAL; -+ -+ sensor_dbg("entry %s\n", __func__); -+ -+ //�л�ģʽǰ��������һ��mode -+ if ( V4L2_BUF_TYPE_PRIVATE == mf->reserved[0]) -+ { -+ g_mode = mf->reserved[1]; -+ } -+ priv->win.width = mf->width; -+ priv->win.height =mf->height; -+ -+ sensor_dbg("---%s. g_mode=%d mf->width=%d mf->height=%d\n", -+ __func__, g_mode, mf->width, mf->height); -+ -+ switch (g_mode) -+ { -+ case CAMERA_WMODE_PREV: -+ if (cur_sensor_info->handler->cam_set_to_prev_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_prev_func(mf->width, mf->height); -+ break; -+ case CAMERA_WMODE_CAP: -+ if (cur_sensor_info->handler->cam_set_to_cap_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_cap_func(mf->width, mf->height); -+ break; -+ case CAMERA_WMODE_REC: -+ if (cur_sensor_info->handler->cam_set_to_record_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_record_func(mf->width, mf->height); -+ break; -+ default : -+ if (cur_sensor_info->handler->cam_set_to_record_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_record_func(mf->width, mf->height); -+ break; -+ } -+ -+ if ( bRet ) -+ ret = 0; -+ -+ SENDBG("leave %s\n", __func__); -+ return ret; -+} -+ -+ -+ -+static int aksensor_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct aksensor_priv *priv = to_aksensor(client); -+ int i; -+ -+ sensor_dbg("entry %s. priv=%p\n", __func__, priv); -+ -+ for (i = 0; i < cur_sensor_info->num_resolution; ++i) { -+ if (!strcmp(cur_sensor_info->resolution[i].name, "720P")) -+ break; -+ } -+ // the resolution is 720P or larger -+ if (i == cur_sensor_info->num_resolution) -+ --i; -+ a->bounds.width = cur_sensor_info->resolution[i].width; -+ a->bounds.height = cur_sensor_info->resolution[i].height; -+ a->bounds.left = 0; -+ a->bounds.top = 0; -+ -+ a->defrect.width = priv->win.width; -+ a->defrect.height = priv->win.height; -+ a->defrect.left = 0; -+ a->defrect.top = 0; -+ -+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ a->pixelaspect.numerator = 1; -+ a->pixelaspect.denominator = 1; -+ -+ sensor_dbg("%s.\n" -+ " a->bounds.width=%d, a->bounds.height=%d\n" -+ " a->defrect.width=%d, a->defrect.height=%d\n", -+ __func__, -+ a->bounds.width, a->bounds.height, -+ a->defrect.width, a->defrect.height); -+ return 0; -+} -+ -+static int aksensor_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct aksensor_priv *priv = to_aksensor(client); -+ -+ sensor_dbg("entry %s\n", __func__); -+ -+ a->c.left = 0; -+ a->c.top = 0; -+ a->c.width = priv->win.width; -+ a->c.height = priv->win.height; -+ -+ return 0; -+} -+ -+static int aksensor_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct aksensor_priv *priv = to_aksensor(client); -+ int ret = -EINVAL; -+ T_BOOL bRet = AK_FALSE; -+ -+ sensor_dbg("entry %s\n", __func__); -+ -+ priv->win.width = a->c.width; -+ priv->win.height =a->c.height; -+ -+ switch (g_mode) -+ { -+ case CAMERA_WMODE_PREV: -+ if (cur_sensor_info->handler->cam_set_to_prev_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_prev_func(a->c.width, a->c.height); -+ break; -+ case CAMERA_WMODE_CAP: -+ if (cur_sensor_info->handler->cam_set_to_cap_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_cap_func(a->c.width, a->c.height); -+ break; -+ case CAMERA_WMODE_REC: -+ if (cur_sensor_info->handler->cam_set_to_record_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_record_func(a->c.width, a->c.height); -+ break; -+ default : -+ if (cur_sensor_info->handler->cam_set_to_record_func != NULL) -+ bRet = cur_sensor_info->handler->cam_set_to_record_func(a->c.width, a->c.height); -+ break; -+ } -+ -+ if ( bRet ) -+ ret = 0; -+ -+ return ret; -+} -+ -+static int aksensor_video_probe(struct i2c_client *client) -+{ -+ struct aksensor_priv *priv = to_aksensor(client); -+ const char *devname; -+ -+ SENDBG("entry %s\n", __func__); -+ -+ /* -+ * check and show product ID and manufacturer ID -+ */ -+ g_client = client; -+ if (cur_sensor_info != NULL) { -+ dev_info(&client->dev, "Probing %s Sensor ID 0x%x\n", -+ cur_sensor_info->sensor_name, -+ cur_sensor_info->sensor_id); -+ } else { -+ cur_sensor_info = probe_sensors(client); -+ if (cur_sensor_info == NULL) { -+ dev_err(&client->dev, "Sensor ID error\n"); -+ return -ENODEV; -+ } -+ } -+ cur_sensor_cfmts = cur_sensor_info->formats; -+ -+ devname = "aksensor"; -+ priv->model = cur_sensor_info->sensor_id; -+ -+ return 0; -+} -+ -+static int aksensor_enum_fmt(struct v4l2_subdev *sd, unsigned int index, -+ enum v4l2_mbus_pixelcode *code) -+{ -+ if (index >= cur_sensor_info->num_formats) -+ return -EINVAL; -+ -+ *code = cur_sensor_cfmts[index].code; -+ return 0; -+} -+ -+static int aksensor_g_mbus_config(struct v4l2_subdev *sd, -+ struct v4l2_mbus_config *cfg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client); -+ -+ SENDBG("entry %s\n", __func__); -+ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | -+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | -+ V4L2_MBUS_DATA_ACTIVE_HIGH; -+ cfg->type = V4L2_MBUS_PARALLEL; -+ cfg->flags = soc_camera_apply_board_flags(icl, cfg); -+ SENDBG("leave %s\n", __func__); -+ -+ return 0; -+} -+ -+static struct v4l2_subdev_video_ops aksensor_subdev_video_ops = { -+ .s_stream = aksensor_s_stream, -+ .g_mbus_fmt = aksensor_g_fmt, -+ .s_mbus_fmt = aksensor_s_fmt, -+ .try_mbus_fmt = aksensor_try_fmt, -+ .cropcap = aksensor_cropcap, -+ .g_crop = aksensor_g_crop, -+ .s_crop = aksensor_s_crop, -+ .enum_mbus_fmt = aksensor_enum_fmt, -+ .g_mbus_config = aksensor_g_mbus_config, -+}; -+ -+static struct v4l2_subdev_ops aksensor_subdev_ops = { -+ .core = &aksensor_subdev_core_ops, -+ .video = &aksensor_subdev_video_ops, -+}; -+ -+void aksensor_set_param(unsigned int cmd, unsigned int data) -+{ -+ cur_sensor_info->handler->cam_set_sensor_param_func(cmd, data); -+} -+EXPORT_SYMBOL(aksensor_set_param); -+ -+/* -+ * i2c_driver function -+ */ -+static int aksensor_probe(struct i2c_client *client, -+ const struct i2c_device_id *did) -+{ -+ struct aksensor_priv *priv; -+ struct soc_camera_link *icl = soc_camera_i2c_to_link(client); -+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); -+ int i, ret; -+ -+ SENDBG("entry %s\n", __func__); -+ -+ if (!icl || !icl->priv) { -+ dev_err(&client->dev, "AKSENSOR: missing platform data!\n"); -+ return -EINVAL; -+ } -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -+ dev_err(&adapter->dev, -+ "I2C-Adapter doesn't support " -+ "I2C_FUNC_SMBUS_BYTE_DATA\n"); -+ return -EIO; -+ } -+ -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) { -+ return -ENOMEM; -+ } -+ -+ priv->info = icl->priv; -+ v4l2_i2c_subdev_init(&priv->subdev, client, &aksensor_subdev_ops); -+ -+ ret = aksensor_video_probe(client); -+ -+ if (ret) { -+ kfree(priv); -+ return ret; -+ } -+ -+ v4l2_ctrl_handler_init(&priv->hdl, cur_sensor_info->nr_ctrls); -+ for (i = 0; i < cur_sensor_info->nr_ctrls; i++) -+ v4l2_ctrl_new_custom(&priv->hdl, &cur_sensor_info->ctrls[i], NULL); -+ priv->subdev.ctrl_handler = &priv->hdl; -+ if (priv->hdl.error) { -+ int err = priv->hdl.error; -+ v4l2_ctrl_handler_free(&priv->hdl); -+ kfree(priv); -+ return err; -+ } -+ -+ // init sensor resolution, default VGA -+ for (i = 0; i < cur_sensor_info->num_resolution; i++) -+ if (!strcmp(cur_sensor_info->resolution[i].name, "VGA")) { -+ priv->win.width = cur_sensor_info->resolution[i].width; -+ priv->win.height = cur_sensor_info->resolution[i].height; -+ } -+ sensor_dbg("%s: priv->win.width=%d priv->win.height=%d\n", -+ __func__, priv->win.width, priv->win.height); -+ return ret; -+} -+ -+static int aksensor_remove(struct i2c_client *client) -+{ -+ struct aksensor_priv *priv = to_aksensor(client); -+ -+ if (NULL != cur_sensor_info->handler) { -+ cur_sensor_info->handler->cam_close_func(); -+ cur_sensor_info->handler = NULL; -+ } -+ -+ v4l2_device_unregister_subdev(&priv->subdev); -+ v4l2_ctrl_handler_free(&priv->hdl); -+ kfree(priv); -+ return 0; -+} -+ -+static const struct i2c_device_id aksensor_id[] = { -+ { "aksensor", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, aksensor); -+ -+static struct i2c_driver aksensor_i2c_driver = { -+ .driver = { -+ .name = "aksensor", -+ }, -+ .probe = aksensor_probe, -+ .remove = aksensor_remove, -+ .id_table = aksensor_id, -+}; -+ -+/** -+ * @brief get GPIO pin value -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param GPIO pin type -+ * @return GPIO pin value -+ * @retval -+ */ -+T_U32 cam_getpin(T_CAMERA_PINTYPE pin_type) -+{ -+ T_U32 pin = INVALID_GPIO; -+ -+// SENDBG("entry %s\n", __func__); -+ -+ if (AK_NULL != g_client) -+ { -+ struct aksensor_priv *priv = to_aksensor(g_client); -+ -+ switch (pin_type) -+ { -+ case PIN_AVDD: -+ pin = priv->info->pin_avdd; -+ break; -+ case PIN_POWER: -+ pin = priv->info->pin_power; -+ break; -+ case PIN_RESET: -+ pin = priv->info->pin_reset; -+ break; -+ default : -+ break; -+ } -+ } -+ -+ return pin; -+} -+ -+/* -+ * module function -+ */ -+ -+static int __init aksensor_module_init(void) -+{ -+ SENDBG("entry %s\n", __func__); -+ -+ return i2c_add_driver(&aksensor_i2c_driver); -+} -+ -+static void __exit aksensor_module_exit(void) -+{ -+ SENDBG("entry %s\n", __func__); -+ -+ i2c_del_driver(&aksensor_i2c_driver); -+} -+ -+module_init(aksensor_module_init); -+module_exit(aksensor_module_exit); -+ -+MODULE_DESCRIPTION("SoC Camera driver for aksensor"); -+MODULE_AUTHOR("dengzhou"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/media/video/plat-anyka/camera_ar0130.c b/drivers/media/video/plat-anyka/camera_ar0130.c -new file mode 100755 -index 00000000..5a00810d ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ar0130.c -@@ -0,0 +1,1068 @@ -+/** -+ * @file camera_ar0130.c -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author caolianming -+ * @date 2013-07-31 -+ * @version 1.0 -+ * @ref -+ */ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/cam_com_sensor.h> -+#include "camera_ar0130.h" -+#else -+#include "akdefine.h" -+#include "cam_com_sensor.h" -+#include "camera_ar0130.h" -+#include "Gpio_config.h" -+#endif -+ -+#if defined (USE_CAMERA_AR0130) || defined (CONFIG_SENSOR_AR0130) -+ -+#define CAM_EN_LEVEL 0 -+#define CAM_RESET_LEVEL 0 -+ -+#define CAMERA_SCCB_ADDR 0x20 -+#define CAMERA_AR0130_ID 0x0130 -+ -+#define AR0130_CAMERA_MCLK 27 -+ -+static T_CAMERA_TYPE camera_ar0130_type = CAMERA_2M; -+static T_NIGHT_MODE night_mode = CAMERA_DAY_MODE; -+static T_CAMERA_MODE s_ar0130_CurMode = CAMERA_MODE_VGA; -+ -+#if 0 -+static T_VOID camera_setbit(T_U16 reg, T_U8 bit, T_U8 value) -+{ -+ T_U8 tmp; -+ -+ tmp = sccb_read_short(CAMERA_SCCB_ADDR, reg); -+ if (value == 1) -+ { -+ tmp |= 0x1 << bit; -+ } -+ else -+ { -+ tmp &= ~(0x1 << bit); -+ } -+ -+ sccb_write_word(CAMERA_SCCB_ADDR, reg, &tmp, 1); -+} -+#endif -+static T_U32 cam_ar0130_read_id(T_VOID); -+ -+static T_BOOL camera_set_param(const T_U16 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 temp_value; -+ T_U16 data; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ data = tabParameter[i + 1]; -+ sccb_write_word(CAMERA_SCCB_ADDR, tabParameter[i], &data, 1); -+ -+ if ((tabParameter[i] != 0x0000) || (tabParameter[i] != 0x0022) -+ || (tabParameter[i] != 0x0100) || (tabParameter[i] != 0x0101)) -+ { -+ temp_value = sccb_read_short(CAMERA_SCCB_ADDR, tabParameter[i]); -+ if (temp_value != tabParameter[i + 1]) -+ { -+ akprintf(C1, M_DRVSYS, "set parameter error!\n"); -+ akprintf(C1, M_DRVSYS, "reg 0x%x write data is 0x%x, read data is 0x%x!\n", tabParameter[i], tabParameter[i + 1], temp_value); -+ -+ return AK_FALSE; -+ } -+ } -+ } -+ -+ i += 2; -+ } -+ -+ return AK_TRUE; -+} -+ -+static T_VOID read_camera_reg(const T_U16 tabParameter[]) -+{ -+ unsigned short data; -+ int i = 0; -+ -+ while (1) { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) { -+ break; -+ } else if (DELAY_FLAG != tabParameter[i]) { -+ data = sccb_read_word(CAMERA_SCCB_ADDR, tabParameter[i]); -+ //printk("read: [0x%04x 0x%04x]\n", tabParameter[i], data); -+ } -+ i += 2; -+ } -+} -+ -+static T_VOID camera_setup(const T_U16 tabParameter[]) -+{ -+ int i = 0; -+ T_U16 data; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ data = tabParameter[i + 1]; -+ sccb_write_word(CAMERA_SCCB_ADDR, tabParameter[i], &data, 2); -+ } -+ i += 2; -+ } -+} -+ -+static T_VOID cam_ar0130_open(T_VOID) -+{ -+ gpio_set_pin_dir(GPIO_CAMERA_AVDD, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_CHIP_ENABLE); -+ gpio_set_pin_dir(GPIO_CAMERA_CHIP_ENABLE, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, CAM_EN_LEVEL); -+ mini_delay(10); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_RESET); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, CAM_RESET_LEVEL); -+ mini_delay(10); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, !CAM_RESET_LEVEL); -+ -+ mini_delay(20); -+} -+ -+static T_BOOL cam_ar0130_close(T_VOID) -+{ -+ //sccb software standby mode -+// T_U8 Reg0x3d = 0x48; -+// T_U8 Reg0xc3 = 0x00; -+ -+// sccb_write_word(CAMERA_SCCB_ADDR, 0x3d, &Reg0x3d, 1); -+// sccb_write_word(CAMERA_SCCB_ADDR, 0xc3, &Reg0xc3, 1); -+ -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, !CAM_EN_LEVEL); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, !gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_INPUT); -+ -+ gpio_set_pin_dir(GPIO_I2C_SCL, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SCL, GPIO_LEVEL_LOW); -+ gpio_set_pin_dir(GPIO_I2C_SDA, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SDA, GPIO_LEVEL_LOW); -+ -+ return AK_TRUE; -+} -+ -+static T_U32 cam_ar0130_read_id(T_VOID) -+{ -+#if 0 -+ T_U8 value = 0x00; -+ T_U32 id = 0; -+ -+ sccb_init(GPIO_I2C_SCL, GPIO_I2C_SDA); //init sccb first here!! -+ -+ value = sccb_read_short(CAMERA_SCCB_ADDR, 0x0001); -+ id = value << 8; -+ value = sccb_read_short(CAMERA_SCCB_ADDR, 0x0002); -+ id |= value; -+ -+ return id; -+#else -+ return CAMERA_AR0130_ID; -+#endif -+} -+ -+/** -+ * @brief initialize the parameters of camera, should be done after reset and open camera to initialize -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @return T_BOOL -+ * @retval AK_TRUE if success, else AK_FALSE -+ */ -+static T_BOOL cam_ar0130_init(void) -+{ -+ if (!camera_set_param(INIT_TAB)) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ night_mode = CAMERA_DAY_MODE; -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief Set camera mode to specify image quality, SXGA/VGA/CIF etc -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] mode mode value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_mode(T_CAMERA_MODE mode) -+{ -+ s_ar0130_CurMode = mode; -+ switch(mode) { -+ case CAMERA_MODE_UXGA: -+ camera_setup(UXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_SXGA: -+ camera_setup(SXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_VGA: -+ camera_setup(VGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_CIF: -+ camera_setup(CIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QVGA: -+ camera_setup(QVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_QCIF: -+ camera_setup(QCIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QQVGA: -+ camera_setup(QQVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_PREV: -+ camera_setup(PREV_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_REC: -+ camera_setup(RECORD_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_720P: -+ camera_setup(RECORD_720P_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ default: -+ s_ar0130_CurMode = CAMERA_MODE_VGA; -+ akprintf(C1, M_DRVSYS, "set camera mode parameter error!\n"); -+ break; -+ } -+#if 0 -+ if (mode == CAMERA_MODE_720P) -+ read_camera_reg(RECORD_720P_TAB); -+#endif -+} -+ -+/** -+ * @brief Set camera exposure mode -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] exposure exposure mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_exposure(T_CAMERA_EXPOSURE exposure) -+{ -+ switch(exposure) -+ { -+ case EXPOSURE_WHOLE: -+ camera_setup(EXPOSURE_WHOLE_TAB); -+ break; -+ case EXPOSURE_CENTER: -+ camera_setup(EXPOSURE_CENTER_TAB); -+ break; -+ case EXPOSURE_MIDDLE: -+ camera_setup(EXPOSURE_MIDDLE_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set exposure parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera brightness level -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] brightness brightness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_brightness(T_CAMERA_BRIGHTNESS brightness) -+{ -+ switch(brightness) -+ { -+ case CAMERA_BRIGHTNESS_0: -+ camera_setup(BRIGHTNESS_0_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_1: -+ camera_setup(BRIGHTNESS_1_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_2: -+ camera_setup(BRIGHTNESS_2_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_3: -+ camera_setup(BRIGHTNESS_3_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_4: -+ camera_setup(BRIGHTNESS_4_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_5: -+ camera_setup(BRIGHTNESS_5_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_6: -+ camera_setup(BRIGHTNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set brightness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera contrast level -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] contrast contrast value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_contrast(T_CAMERA_CONTRAST contrast) -+{ -+ switch(contrast) -+ { -+ case CAMERA_CONTRAST_1: -+ camera_setup(CONTRAST_1_TAB); -+ break; -+ case CAMERA_CONTRAST_2: -+ camera_setup(CONTRAST_2_TAB); -+ break; -+ case CAMERA_CONTRAST_3: -+ camera_setup(CONTRAST_3_TAB); -+ break; -+ case CAMERA_CONTRAST_4: -+ camera_setup(CONTRAST_4_TAB); -+ break; -+ case CAMERA_CONTRAST_5: -+ camera_setup(CONTRAST_5_TAB); -+ break; -+ case CAMERA_CONTRAST_6: -+ camera_setup(CONTRAST_6_TAB); -+ break; -+ case CAMERA_CONTRAST_7: -+ camera_setup(CONTRAST_7_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set contrast parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera saturation level -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] saturation saturation value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_saturation(T_CAMERA_SATURATION saturation) -+{ -+ switch(saturation) -+ { -+ case CAMERA_SATURATION_1: -+ camera_setup(SATURATION_1_TAB); -+ break; -+ case CAMERA_SATURATION_2: -+ camera_setup(SATURATION_2_TAB); -+ break; -+ case CAMERA_SATURATION_3: -+ camera_setup(SATURATION_3_TAB); -+ break; -+ case CAMERA_SATURATION_4: -+ camera_setup(SATURATION_4_TAB); -+ break; -+ case CAMERA_SATURATION_5: -+ camera_setup(SATURATION_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set saturation parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera sharpness level -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] sharpness sharpness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_sharpness(T_CAMERA_SHARPNESS sharpness) -+{ -+ switch(sharpness) -+ { -+ case CAMERA_SHARPNESS_0: -+ camera_setup(SHARPNESS_0_TAB); -+ break; -+ case CAMERA_SHARPNESS_1: -+ camera_setup(SHARPNESS_1_TAB); -+ break; -+ case CAMERA_SHARPNESS_2: -+ camera_setup(SHARPNESS_2_TAB); -+ break; -+ case CAMERA_SHARPNESS_3: -+ camera_setup(SHARPNESS_3_TAB); -+ break; -+ case CAMERA_SHARPNESS_4: -+ camera_setup(SHARPNESS_4_TAB); -+ break; -+ case CAMERA_SHARPNESS_5: -+ camera_setup(SHARPNESS_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set sharpness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera AWB mode -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] awb AWB mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_AWB(T_CAMERA_AWB awb) -+{ -+ switch(awb) -+ { -+ case AWB_AUTO: -+ camera_setup(AWB_AUTO_TAB); -+ break; -+ case AWB_SUNNY: -+ camera_setup(AWB_SUNNY_TAB); -+ break; -+ case AWB_CLOUDY: -+ camera_setup(AWB_CLOUDY_TAB); -+ break; -+ case AWB_OFFICE: -+ camera_setup(AWB_OFFICE_TAB); -+ break; -+ case AWB_HOME: -+ camera_setup(AWB_HOME_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set AWB mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera mirror mode -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] mirror mirror mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_mirror(T_CAMERA_MIRROR mirror) -+{ -+ switch(mirror) -+ { -+ case CAMERA_MIRROR_V: -+ break; -+ case CAMERA_MIRROR_H: -+ break; -+ case CAMERA_MIRROR_NORMAL: -+ break; -+ case CAMERA_MIRROR_FLIP: -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set mirror parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera effect mode -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] effect effect mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ar0130_set_effect(T_CAMERA_EFFECT effect) -+{ -+ switch(effect) -+ { -+ case CAMERA_EFFECT_NORMAL: -+ camera_setup(EFFECT_NORMAL_TAB); -+ break; -+ case CAMERA_EFFECT_SEPIA: -+ camera_setup(EFFECT_SEPIA_TAB); -+ break; -+ case CAMERA_EFFECT_ANTIQUE: -+ camera_setup(EFFECT_ANTIQUE_TAB); -+ break; -+ case CAMERA_EFFECT_BLUE: -+ camera_setup(EFFECT_BLUISH_TAB); -+ break; -+ case CAMERA_EFFECT_GREEN: -+ camera_setup(EFFECT_GREENISH_TAB); -+ break; -+ case CAMERA_EFFECT_RED: -+ camera_setup(EFFECT_REDDISH_TAB); -+ break; -+ case CAMERA_EFFECT_NEGATIVE: -+ camera_setup(EFFECT_NEGATIVE_TAB); -+ break; -+ case CAMERA_EFFECT_BW: -+ camera_setup(EFFECT_BW_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set camer effect parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief set camera window -+ * @author cao_lianming -+ * @date 2013-07-31 -+ * @param[in] srcWidth window width -+ * @param[in] srcHeight window height -+ * @return T_S32 -+ * @retval 0 if error mode -+ * @retval 1 if success -+ * @retval -1 if failed -+ */ -+static T_S32 cam_ar0130_set_digital_zoom(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ return 1; -+} -+ -+static T_VOID cam_ar0130_set_night_mode(T_NIGHT_MODE mode) -+{ -+ switch(mode) -+ { -+ case CAMERA_DAY_MODE: -+ camera_setup(DAY_MODE_TAB); -+ night_mode = CAMERA_DAY_MODE; -+ break; -+ case CAMERA_NIGHT_MODE: -+ camera_setup(NIGHT_MODE_TAB); -+ night_mode = CAMERA_NIGHT_MODE; -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set night mode parameter error!\n"); -+ break; -+ } -+} -+ -+static T_VOID cam_ar0130_set_anti_flicker(T_U32 value) -+{ -+ switch(value) { -+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: -+ //camera_setup(ANTI_FLICKER_DISABLE_TAB); -+ akprintf(C1, M_DRVSYS, "Anti-flicker not support 'Disable', Error." -+ " please select other frequency!\n"); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: -+ camera_setup(ANTI_FLICKER_50HZ_TAB); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: -+ camera_setup(ANTI_FLICKER_60HZ_TAB); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: -+ //camera_setup(ANTI_FLICKER_AUTO_TAB); -+ akprintf(C1, M_DRVSYS, "Anti-flicker not support 'Auto', Error." -+ " please select other frequency!\n"); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set Anti-flicker parameter error!\n"); -+ break; -+ } -+} -+ -+static T_BOOL cam_ar0130_set_to_cap(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_VGA; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 1024)) -+ { -+ Cammode = CAMERA_MODE_SXGA; -+ } -+ else if ((srcWidth <= 1600) && (srcHeight <= 1200)) -+ { -+ Cammode = CAMERA_MODE_UXGA; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "ar0130 unsupport %d & %d mode!\n", srcWidth, srcHeight); -+ return AK_FALSE; -+ } -+ -+ cam_ar0130_set_mode(Cammode); -+ cam_ar0130_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ar0130_set_to_prev(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_ar0130_set_mode(CAMERA_MODE_PREV); -+ cam_ar0130_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ar0130_set_to_record(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_REC; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "200W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_ar0130_set_mode(Cammode); -+ cam_ar0130_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_CAMERA_TYPE cam_ar0130_get_type(T_VOID) -+{ -+ return camera_ar0130_type; -+} -+ -+static T_VOID cam_ar0130_set_sensor_param(T_U32 cmd, T_U32 data) -+{ -+ T_U16 value; -+ -+ value = (T_U16)data; -+ sccb_write_word(CAMERA_SCCB_ADDR, (T_U16)cmd, &value, 1); -+} -+ -+static T_CAMERA_FUNCTION_HANDLER ar0130_function_handler = -+{ -+ AR0130_CAMERA_MCLK, -+ cam_ar0130_open, -+ cam_ar0130_close, -+ cam_ar0130_read_id, -+ cam_ar0130_init, -+ cam_ar0130_set_mode, -+ cam_ar0130_set_exposure, -+ cam_ar0130_set_brightness, -+ cam_ar0130_set_contrast, -+ cam_ar0130_set_saturation, -+ cam_ar0130_set_sharpness, -+ cam_ar0130_set_AWB, -+ cam_ar0130_set_mirror, -+ cam_ar0130_set_effect, -+ cam_ar0130_set_digital_zoom, -+ cam_ar0130_set_night_mode, -+ AK_NULL, -+ cam_ar0130_set_anti_flicker, -+ cam_ar0130_set_to_cap, -+ cam_ar0130_set_to_prev, -+ cam_ar0130_set_to_record, -+ cam_ar0130_get_type, -+ cam_ar0130_set_sensor_param -+}; -+ -+#ifndef CONFIG_LINUX_AKSENSOR -+static int camera_ar0130_reg(void) -+{ -+ camera_reg_dev(CAMERA_AR0130_ID, &ar0130_function_handler); -+ return 0; -+} -+ -+#ifdef __CC_ARM -+#pragma arm section rwdata = "__initcall_", zidata = "__initcall_" -+#endif -+module_init(camera_ar0130_reg) -+#ifdef __CC_ARM -+#pragma arm section -+#endif -+ -+#else -+static const char * awb_menu[] = { -+ [AWB_AUTO] = "auto", -+ [AWB_SUNNY] = "sunny", -+ [AWB_CLOUDY] = "cloudy", -+ [AWB_OFFICE] = "office", -+ [AWB_HOME] = "home", -+ [AWB_NIGHT] = "night", -+}; -+ -+static const char * effect_menu[] = { -+ [CAMERA_EFFECT_NORMAL] = "normal", -+ [CAMERA_EFFECT_SEPIA] = "sepia", -+ [CAMERA_EFFECT_ANTIQUE] = "antique", -+ [CAMERA_EFFECT_BLUE] = "blue", -+ [CAMERA_EFFECT_GREEN] = "green", -+ [CAMERA_EFFECT_RED] = "red", -+ [CAMERA_EFFECT_NEGATIVE] = "negative", -+ [CAMERA_EFFECT_BW] = "bw", -+ [CAMERA_EFFECT_BWN] = "bwn", -+ [CAMERA_EFFECT_AQUA] = "aqua", -+ [CAMERA_EFFECT_COOL] = "cool", -+ [CAMERA_EFFECT_WARM] = "warm", -+}; -+ -+static const char * resolution_menu[] = { -+ [0] = "1280x960", -+ [1] = "1280x720", -+ [2] = "640x480", -+}; -+ -+static const char * hflip_menu[] = { -+ [0] = "normal", -+ [1] = "horizontal flip", -+}; -+ -+static const char * vflip_menu[] = { -+ [0] = "normal", -+ [1] = "vertical flip", -+}; -+ -+static const char * night_menu[] = { -+ [CAMERA_DAY_MODE] = "daylight", -+ [CAMERA_NIGHT_MODE] = "night", -+}; -+ -+static const char * anti_flicker_menu[] = { -+ [V4L2_CID_POWER_LINE_FREQUENCY_DISABLED] = "Disable", -+ [V4L2_CID_POWER_LINE_FREQUENCY_50HZ] = "50Hz", -+ [V4L2_CID_POWER_LINE_FREQUENCY_60HZ] = "60Hz", -+ [V4L2_CID_POWER_LINE_FREQUENCY_AUTO] = "Auto", -+}; -+ -+static int ar0130_s_ctl(struct v4l2_ctrl *ctrl) -+{ -+ int ret = -EINVAL; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ if (ar0130_function_handler.cam_set_AWB_func) { -+ ar0130_function_handler.cam_set_AWB_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_COLORFX: -+ if (ar0130_function_handler.cam_set_effect_func) { -+ ar0130_function_handler.cam_set_effect_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ -+ case V4L2_CID_BRIGHTNESS: -+ if (ar0130_function_handler.cam_set_brightness_func) { -+ ar0130_function_handler.cam_set_brightness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_CONTRAST: -+ if (ar0130_function_handler.cam_set_contrast_func) { -+ ar0130_function_handler.cam_set_contrast_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SATURATION: -+ if (ar0130_function_handler.cam_set_saturation_func) { -+ ar0130_function_handler.cam_set_saturation_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SHARPNESS: -+ if (ar0130_function_handler.cam_set_sharpness_func) { -+ ar0130_function_handler.cam_set_sharpness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_HFLIP: -+ if (ar0130_function_handler.cam_set_mirror_func) { -+ ar0130_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_H : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_VFLIP: -+ if (ar0130_function_handler.cam_set_mirror_func) { -+ ar0130_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_V : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_NIGHTMODE: -+ if (ar0130_function_handler.cam_set_night_mode_func) { -+ ar0130_function_handler.cam_set_night_mode_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY: -+ if (ar0130_function_handler.cam_set_anti_flicker_func) { -+ ar0130_function_handler.cam_set_anti_flicker_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+}; -+ -+static struct v4l2_ctrl_ops ar0130_ctrl_ops = { -+ .s_ctrl = ar0130_s_ctl, -+}; -+ -+static const struct v4l2_ctrl_config ar0130_ctrls[] = { -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_AUTO_WHITE_BALANCE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "AWB", -+ .min = 0, -+ .max = ARRAY_SIZE(awb_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = awb_menu, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_COLORFX, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Effect", -+ .min = 0, -+ .max = ARRAY_SIZE(effect_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = effect_menu, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Horizontal Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(hflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = hflip_menu, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Vetical Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(vflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = vflip_menu, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_PICTURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Resolution", -+ .min = 0, -+ .max = ARRAY_SIZE(resolution_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = resolution_menu, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_NIGHTMODE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Night mode", -+ .min = 0, -+ .max = ARRAY_SIZE(night_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = night_menu, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_BRIGHTNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Brightness", -+ .min = 0, -+ .max = CAMERA_BRIGHTNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .min = 0, -+ .max = CAMERA_CONTRAST_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .min = 0, -+ .max = CAMERA_SATURATION_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_SHARPNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Sharpness", -+ .min = 0, -+ .max = CAMERA_SHARPNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ar0130_ctrl_ops, -+ .id = V4L2_CID_POWER_LINE_FREQUENCY, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "anti flicker", -+ .min = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, -+ .max = V4L2_CID_POWER_LINE_FREQUENCY_AUTO, -+ .step = 0, -+ .def = V4L2_CID_POWER_LINE_FREQUENCY_50HZ, -+ .flags = 0, -+ .menu_skip_mask = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, -+ .qmenu = anti_flicker_menu, -+ } -+}; -+ -+ -+/* -+ * supported format list -+ */ -+static const struct aksensor_color_format ar0130_formats[] = { -+ { -+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+}; -+ -+static const struct aksensor_win_size ar0130_win[] = { -+ {.name = "VGA", .width = 640, .height = 480}, -+ {.name = "720P", .width = 1280, .height = 720}, -+ {.name = "960P", .width = 1280, .height = 960}, -+}; -+ -+static struct sensor_info ar0130_sensor_info = { -+ .sensor_name = "ar0130", -+ .sensor_id = CAMERA_AR0130_ID, -+ .ctrls = ar0130_ctrls, -+ .nr_ctrls = ARRAY_SIZE(ar0130_ctrls), -+ .formats = ar0130_formats, -+ .num_formats = ARRAY_SIZE(ar0130_formats), -+ .resolution = ar0130_win, -+ .num_resolution = ARRAY_SIZE(ar0130_win), -+ .handler = &ar0130_function_handler, -+}; -+ -+static int ar0130_module_init(void) -+{ -+ return register_sensor(&ar0130_sensor_info); -+} -+module_init(ar0130_module_init) -+#endif -+ -+#endif -+ -+ -diff --git a/drivers/media/video/plat-anyka/camera_ar0130.h b/drivers/media/video/plat-anyka/camera_ar0130.h -new file mode 100755 -index 00000000..219a18fe ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ar0130.h -@@ -0,0 +1,467 @@ -+/** -+ * @file camera_ar0130.h -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author caolianming -+ * @date 2013-07-31 -+ * @version 1.0 -+ * @ref -+ */ -+#ifndef __CAMERA_AR0130_H__ -+#define __CAMERA_AR0130_H__ -+ -+ -+#if defined (USE_CAMERA_AR0130) || defined (CONFIG_SENSOR_AR0130) -+ -+#undef DELAY_FLAG -+#undef END_FLAG -+#define DELAY_FLAG 0xfd // first parameter is 0xfe, then 2nd parameter is delay time count -+#define END_FLAG 0xfe // first parameter is 0xff, then parameter table is over -+ -+static const T_U16 INIT_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 UXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 VGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QVGA_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QCIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QQVGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 PREV_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 RECORD_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+//[720p--30fps] -+static const T_U16 RECORD_720P_TAB[] = -+{ -+ 0x301A, 0x0001, // RESET_REGISTER -+ 0x301A, 0x10D8, // RESET_REGISTER -+ -+ DELAY_FLAG, 200, //DELAY= 200 -+ -+ 0x3088, 0x8000, // SEQ_CTRL_PORT -+ 0x3086, 0x0225, // SEQ_DATA_PORT -+ 0x3086, 0x5050, // SEQ_DATA_PORT -+ 0x3086, 0x2D26, // SEQ_DATA_PORT -+ 0x3086, 0x0828, // SEQ_DATA_PORT -+ 0x3086, 0x0D17, // SEQ_DATA_PORT -+ 0x3086, 0x0926, // SEQ_DATA_PORT -+ 0x3086, 0x0028, // SEQ_DATA_PORT -+ 0x3086, 0x0526, // SEQ_DATA_PORT -+ 0x3086, 0xA728, // SEQ_DATA_PORT -+ 0x3086, 0x0725, // SEQ_DATA_PORT -+ 0x3086, 0x8080, // SEQ_DATA_PORT -+ 0x3086, 0x2917, // SEQ_DATA_PORT -+ 0x3086, 0x0525, // SEQ_DATA_PORT -+ 0x3086, 0x0040, // SEQ_DATA_PORT -+ 0x3086, 0x2702, // SEQ_DATA_PORT -+ 0x3086, 0x1616, // SEQ_DATA_PORT -+ 0x3086, 0x2706, // SEQ_DATA_PORT -+ 0x3086, 0x1736, // SEQ_DATA_PORT -+ 0x3086, 0x26A6, // SEQ_DATA_PORT -+ 0x3086, 0x1703, // SEQ_DATA_PORT -+ 0x3086, 0x26A4, // SEQ_DATA_PORT -+ 0x3086, 0x171F, // SEQ_DATA_PORT -+ 0x3086, 0x2805, // SEQ_DATA_PORT -+ 0x3086, 0x2620, // SEQ_DATA_PORT -+ 0x3086, 0x2804, // SEQ_DATA_PORT -+ 0x3086, 0x2520, // SEQ_DATA_PORT -+ 0x3086, 0x2027, // SEQ_DATA_PORT -+ 0x3086, 0x0017, // SEQ_DATA_PORT -+ 0x3086, 0x1E25, // SEQ_DATA_PORT -+ 0x3086, 0x0020, // SEQ_DATA_PORT -+ 0x3086, 0x2117, // SEQ_DATA_PORT -+ 0x3086, 0x1028, // SEQ_DATA_PORT -+ 0x3086, 0x051B, // SEQ_DATA_PORT -+ 0x3086, 0x1703, // SEQ_DATA_PORT -+ 0x3086, 0x2706, // SEQ_DATA_PORT -+ 0x3086, 0x1703, // SEQ_DATA_PORT -+ 0x3086, 0x1741, // SEQ_DATA_PORT -+ 0x3086, 0x2660, // SEQ_DATA_PORT -+ 0x3086, 0x17AE, // SEQ_DATA_PORT -+ 0x3086, 0x2500, // SEQ_DATA_PORT -+ 0x3086, 0x9027, // SEQ_DATA_PORT -+ 0x3086, 0x0026, // SEQ_DATA_PORT -+ 0x3086, 0x1828, // SEQ_DATA_PORT -+ 0x3086, 0x002E, // SEQ_DATA_PORT -+ 0x3086, 0x2A28, // SEQ_DATA_PORT -+ 0x3086, 0x081E, // SEQ_DATA_PORT -+ 0x3086, 0x0831, // SEQ_DATA_PORT -+ 0x3086, 0x1440, // SEQ_DATA_PORT -+ 0x3086, 0x4014, // SEQ_DATA_PORT -+ 0x3086, 0x2020, // SEQ_DATA_PORT -+ 0x3086, 0x1410, // SEQ_DATA_PORT -+ 0x3086, 0x1034, // SEQ_DATA_PORT -+ 0x3086, 0x1400, // SEQ_DATA_PORT -+ 0x3086, 0x1014, // SEQ_DATA_PORT -+ 0x3086, 0x0020, // SEQ_DATA_PORT -+ 0x3086, 0x1400, // SEQ_DATA_PORT -+ 0x3086, 0x4013, // SEQ_DATA_PORT -+ 0x3086, 0x1802, // SEQ_DATA_PORT -+ 0x3086, 0x1470, // SEQ_DATA_PORT -+ 0x3086, 0x7004, // SEQ_DATA_PORT -+ 0x3086, 0x1470, // SEQ_DATA_PORT -+ 0x3086, 0x7003, // SEQ_DATA_PORT -+ 0x3086, 0x1470, // SEQ_DATA_PORT -+ 0x3086, 0x7017, // SEQ_DATA_PORT -+ 0x3086, 0x2002, // SEQ_DATA_PORT -+ 0x3086, 0x1400, // SEQ_DATA_PORT -+ 0x3086, 0x2002, // SEQ_DATA_PORT -+ 0x3086, 0x1400, // SEQ_DATA_PORT -+ 0x3086, 0x5004, // SEQ_DATA_PORT -+ 0x3086, 0x1400, // SEQ_DATA_PORT -+ 0x3086, 0x2004, // SEQ_DATA_PORT -+ 0x3086, 0x1400, // SEQ_DATA_PORT -+ 0x3086, 0x5022, // SEQ_DATA_PORT -+ 0x3086, 0x0314, // SEQ_DATA_PORT -+ 0x3086, 0x0020, // SEQ_DATA_PORT -+ 0x3086, 0x0314, // SEQ_DATA_PORT -+ 0x3086, 0x0050, // SEQ_DATA_PORT -+ 0x3086, 0x2C2C, // SEQ_DATA_PORT -+ 0x3086, 0x2C2C, // SEQ_DATA_PORT -+ 0x309E, 0x0000, // ERS_PROG_START_ADDR -+ -+ DELAY_FLAG, 200, //DELAY= 200 -+ -+ 0x30E4, 0x6372, // ADC_BITS_6_7 -+ 0x30E2, 0x7253, // ADC_BITS_4_5 -+ 0x30E0, 0x5470, // ADC_BITS_2_3 -+ 0x30E6, 0xC4CC, // ADC_CONFIG1 -+ 0x30E8, 0x8050, // ADC_CONFIG2 -+ 0x3082, 0x0029, // OPERATION_MODE_CTRL -+ 0x30B0, 0x1300, // DIGITAL_TEST -+ 0x30D4, 0xE007, // COLUMN_CORRECTION -+ 0x301A, 0x10DC, // RESET_REGISTER -+ 0x301A, 0x10D8, // RESET_REGISTER -+ 0x3044, 0x0400, // DARK_CONTROL -+ 0x3EDA, 0x0F03, // DAC_LD_14_15 -+ 0x3ED8, 0x01EF, // DAC_LD_12_13 -+ 0x3012, 0x02A0, // COARSE_INTEGRATION_TIME -+ 0x3032, 0x0000, // DIGITAL_BINNING -+ 0x3002, 0x003e, // Y_ADDR_START -+ 0x3004, 0x0004, // X_ADDR_START -+ 0x3006, 0x030d, // Y_ADDR_END -+ 0x3008, 0x0503, // X_ADDR_END -+ 0x300A, 0x02EE, // FRAME_LENGTH_LINES -+ 0x300C, 0x0CE4, // LINE_LENGTH_PCK, 30fps -+ 0x301A, 0x10D8, // RESET_REGISTER -+ 0x31D0, 0x0001, // HDR_COMP -+ -+ //Load = PLL Enabled 27Mhz to 74.25Mhz -+ 0x302C, 0x0002, // VT_SYS_CLK_DIV -+ 0x302A, 0x0004, // VT_PIX_CLK_DIV -+ 0x302E, 0x0002, // PRE_PLL_CLK_DIV -+ 0x3030, 0x002C, // PLL_MULTIPLIER -+ 0x30B0, 0x0000, // DIGITAL_TEST -+ DELAY_FLAG, 100, //DELAY= 100 -+ -+ //LOAD= Disable Embedded Data and Stats -+ 0x3064, 0x1802, // SMIA_TEST, EMBEDDED_STATS_EN, 0x0000 -+ 0x3064, 0x1802, // SMIA_TEST, EMBEDDED_DATA, 0x0000 -+ -+ 0x30BA, 0x0008, //20120502 -+ -+ 0x301A, 0x10DC, // RESET_REGISTER -+ -+ DELAY_FLAG, 200, //DELAY= 200 -+ -+ END_FLAG, END_FLAG -+}; -+ -+ -+/**************** Camera Exposure Table ****************/ -+static const T_U16 EXPOSURE_WHOLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EXPOSURE_CENTER_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EXPOSURE_MIDDLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Brightness Table ****************/ -+static const T_U16 BRIGHTNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Contrast Table ****************/ -+static const T_U16 CONTRAST_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_7_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Saturation Table ****************/ -+static const T_U16 SATURATION_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Sharpness Table ****************/ -+static const T_U16 SHARPNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera AWB Table ****************/ -+static const T_U16 AWB_AUTO_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_SUNNY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_CLOUDY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_OFFICE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_HOME_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Effect Table ****************/ -+static const T_U16 EFFECT_NORMAL_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_SEPIA_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_ANTIQUE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_BLUISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_GREENISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_REDDISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_NEGATIVE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_BW_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera night/day mode ****************/ -+static const T_U16 DAY_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 NIGHT_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera anti-flicker mode ****************/ -+static const T_U16 ANTI_FLICKER_DISABLE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 ANTI_FLICKER_50HZ_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 ANTI_FLICKER_60HZ_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 ANTI_FLICKER_AUTO_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+#endif -+#endif -diff --git a/drivers/media/video/plat-anyka/camera_gc0308.c b/drivers/media/video/plat-anyka/camera_gc0308.c -new file mode 100755 -index 00000000..13bb841e ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_gc0308.c -@@ -0,0 +1,1141 @@ -+/** -+ * @file camera_gc0308.c -+ * @brief camera driver file -+ * Copyright (C) 2010 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-09-21 -+ * @version 1.0 -+ * @ref -+ */ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/cam_com_sensor.h> -+#include "camera_gc0308.h" -+#else -+#include "akdefine.h" -+#include "cam_com_sensor.h" -+#include "camera_gc0308.h" -+#include "Gpio_config.h" -+#endif -+ -+#if defined (USE_CAMERA_GC0308) || defined (CONFIG_SENSOR_GC0308) -+ -+#define CAM_EN_LEVEL 0 -+#define CAM_RESET_LEVEL 0 -+ -+#define CAMERA_SCCB_ADDR 0x42 -+#define CAMERA_GC0308_ID 0x9b -+ -+#define GC0308_CAMERA_MCLK 24 //28 -+ -+static T_CAMERA_TYPE camera_gc0308_type = CAMERA_P3M; -+static T_NIGHT_MODE night_mode = CAMERA_DAY_MODE; -+static T_CAMERA_MODE s_gc0308_CurMode = CAMERA_MODE_VGA; -+ -+ -+/* -+static T_VOID camera_setbit(T_U8 reg, T_U8 bit, T_U8 value) -+{ -+ T_U8 tmp; -+ -+ tmp = sccb_read_data(CAMERA_SCCB_ADDR, reg); -+ if (value == 1) -+ tmp |= 0x1 << bit; -+ else -+ tmp &= ~(0x1 << bit); -+ sccb_write_data(CAMERA_SCCB_ADDR, reg, &tmp, 1); -+} -+*/ -+ -+static T_BOOL camera_set_param(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ //T_U8 temp_value; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)(&tabParameter[i + 1]), 1); -+ /*if (!((tabParameter[i] == 0x0e) && (tabParameter[i + 1] & 0x02)) -+ && !((tabParameter[i] == 0x10) && (tabParameter[i + 1] & 0x26)) -+ && !((tabParameter[i] == 0x14) && (tabParameter[i + 1] & 0x10)) -+ && !((tabParameter[i] == 0x17) && (tabParameter[i + 1] & 0x01)) -+ && !((tabParameter[i] == 0x66) && (tabParameter[i + 1] & 0xe8)) -+ && !((tabParameter[i] == 0x68) && (tabParameter[i + 1] & 0xa2))) -+ { -+ temp_value = sccb_read_data(CAMERA_SCCB_ADDR, tabParameter[i]); -+ if (temp_value != tabParameter[i + 1]) -+ { -+ akprintf(C1, M_DRVSYS, "set parameter error!\n"); -+ akprintf(C1, M_DRVSYS, "reg 0x%02x write data is 0x%02x, read data is 0x%02x!\n", tabParameter[i], tabParameter[i + 1], temp_value); -+ -+ return AK_FALSE; -+ } -+ }*/ -+ } -+ -+ i += 2; -+ } -+ -+ return AK_TRUE; -+} -+ -+static T_VOID camera_setup(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)&tabParameter[i + 1], 1); -+ } -+ i += 2; -+ } -+} -+ -+static T_VOID cam_gc0308_open(T_VOID) -+{ -+ gpio_set_pin_dir(GPIO_CAMERA_AVDD, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_CHIP_ENABLE); -+ gpio_set_pin_dir(GPIO_CAMERA_CHIP_ENABLE, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, CAM_EN_LEVEL); -+ mini_delay(10); -+ -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_RESET); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, CAM_RESET_LEVEL); -+ mini_delay(10); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, !CAM_RESET_LEVEL); -+ -+ mini_delay(20); -+ -+} -+ -+static T_BOOL cam_gc0308_close(T_VOID) -+{ -+ //sccb software standby mode -+ T_U8 Reg0x1a = 0x2b; -+ T_U8 Reg0x25 = 0x00; -+ sccb_write_data(CAMERA_SCCB_ADDR, 0x1a, &Reg0x1a, 1); -+ sccb_write_data(CAMERA_SCCB_ADDR, 0x25, &Reg0x25, 1); -+ -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, !CAM_EN_LEVEL); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, !gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_INPUT); -+ -+ gpio_set_pin_dir(GPIO_I2C_SCL, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SCL, GPIO_LEVEL_LOW); -+ gpio_set_pin_dir(GPIO_I2C_SDA, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SDA, GPIO_LEVEL_LOW); -+ -+ return AK_TRUE; -+} -+ -+static T_U32 cam_gc0308_read_id(T_VOID) -+{ -+ T_U8 value = 0x00; -+ T_U32 id = 0; -+ -+ sccb_init(GPIO_I2C_SCL, GPIO_I2C_SDA); -+ -+ value = sccb_read_data(CAMERA_SCCB_ADDR, 0x00); -+ id |= value; -+ -+ //akprintf(C1, M_DRVSYS, "i2c addr 0x%x, cam_gc0308_read_id = 0x%x\r\n", CAMERA_SCCB_ADDR, id); -+ return id; -+} -+ -+/** -+ * @brief initialize the parameters of camera, should be done after reset and open camera to initialize -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @return T_BOOL -+ * @retval AK_TRUE if success, else AK_FALSE -+ */ -+static T_BOOL cam_gc0308_init(void) -+{ -+ if (!camera_set_param(INIT_TAB)) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ night_mode = CAMERA_DAY_MODE; -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief Set camera mode to specify image quality, SXGA/VGA/CIF/ etc -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @param[in] mode mode value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_mode(T_CAMERA_MODE mode) -+{ -+ s_gc0308_CurMode = mode; -+ switch(mode) -+ { -+ case CAMERA_MODE_VGA: -+ camera_setup(VGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_CIF: -+ camera_setup(CIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QVGA: -+ camera_setup(QVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_QCIF: -+ camera_setup(QCIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QQVGA: -+ camera_setup(QQVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_PREV: //preview mode -+ camera_setup(PREV_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_REC: //record mode -+ camera_setup(RECORD_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ default: -+ s_gc0308_CurMode = CAMERA_MODE_VGA; -+ akprintf(C1, M_DRVSYS, "set camera mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera exposure mode -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @param[in] exposure exposure mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_exposure(T_CAMERA_EXPOSURE exposure) -+{ -+ switch(exposure) -+ { -+ case EXPOSURE_WHOLE: -+ camera_setup(EXPOSURE_WHOLE_TAB); -+ break; -+ case EXPOSURE_CENTER: -+ camera_setup(EXPOSURE_CENTER_TAB); -+ break; -+ case EXPOSURE_MIDDLE: -+ camera_setup(EXPOSURE_MIDDLE_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set exposure parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera brightness level -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @param[in] brightness brightness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_brightness(T_CAMERA_BRIGHTNESS brightness) -+{ -+ switch(brightness) -+ { -+ case CAMERA_BRIGHTNESS_0: -+ camera_setup(BRIGHTNESS_0_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_1: -+ camera_setup(BRIGHTNESS_1_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_2: -+ camera_setup(BRIGHTNESS_2_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_3: -+ camera_setup(BRIGHTNESS_3_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_4: -+ camera_setup(BRIGHTNESS_4_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_5: -+ camera_setup(BRIGHTNESS_5_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_6: -+ camera_setup(BRIGHTNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set brightness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera contrast level -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @param[in] contrast contrast value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_contrast(T_CAMERA_CONTRAST contrast) -+{ -+ switch(contrast) -+ { -+ case CAMERA_CONTRAST_1: -+ camera_setup(CONTRAST_1_TAB); -+ break; -+ case CAMERA_CONTRAST_2: -+ camera_setup(CONTRAST_2_TAB); -+ break; -+ case CAMERA_CONTRAST_3: -+ camera_setup(CONTRAST_3_TAB); -+ break; -+ case CAMERA_CONTRAST_4: -+ camera_setup(CONTRAST_4_TAB); -+ break; -+ case CAMERA_CONTRAST_5: -+ camera_setup(CONTRAST_5_TAB); -+ break; -+ case CAMERA_CONTRAST_6: -+ camera_setup(CONTRAST_6_TAB); -+ break; -+ case CAMERA_CONTRAST_7: -+ camera_setup(CONTRAST_7_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set contrast parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera saturation level -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @param[in] saturation saturation value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_saturation(T_CAMERA_SATURATION saturation) -+{ -+ switch(saturation) -+ { -+ case CAMERA_SATURATION_1: -+ camera_setup(SATURATION_1_TAB); -+ break; -+ case CAMERA_SATURATION_2: -+ camera_setup(SATURATION_2_TAB); -+ break; -+ case CAMERA_SATURATION_3: -+ camera_setup(SATURATION_3_TAB); -+ break; -+ case CAMERA_SATURATION_4: -+ camera_setup(SATURATION_4_TAB); -+ break; -+ case CAMERA_SATURATION_5: -+ camera_setup(SATURATION_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set saturation parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera sharpness level -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @param[in] sharpness sharpness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_sharpness(T_CAMERA_SHARPNESS sharpness) -+{ -+ switch(sharpness) -+ { -+ case CAMERA_SHARPNESS_0: -+ camera_setup(SHARPNESS_0_TAB); -+ break; -+ case CAMERA_SHARPNESS_1: -+ camera_setup(SHARPNESS_1_TAB); -+ break; -+ case CAMERA_SHARPNESS_2: -+ camera_setup(SHARPNESS_2_TAB); -+ break; -+ case CAMERA_SHARPNESS_3: -+ camera_setup(SHARPNESS_3_TAB); -+ break; -+ case CAMERA_SHARPNESS_4: -+ camera_setup(SHARPNESS_4_TAB); -+ break; -+ case CAMERA_SHARPNESS_5: -+ camera_setup(SHARPNESS_5_TAB); -+ break; -+ case CAMERA_SHARPNESS_6: -+ camera_setup(SHARPNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set sharpness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera AWB mode -+ * @author xia_wenting -+ * @date 2011-01-11 -+ * @param[in] awb AWB mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_AWB(T_CAMERA_AWB awb) -+{ -+ switch(awb) -+ { -+ case AWB_AUTO: -+ camera_setup(AWB_AUTO_TAB); -+ break; -+ case AWB_SUNNY: -+ camera_setup(AWB_SUNNY_TAB); -+ break; -+ case AWB_CLOUDY: -+ camera_setup(AWB_CLOUDY_TAB); -+ break; -+ case AWB_OFFICE: -+ camera_setup(AWB_OFFICE_TAB); -+ break; -+ case AWB_HOME: -+ camera_setup(AWB_HOME_TAB); -+ break; -+ case AWB_NIGHT: -+ camera_setup(AWB_NIGHT_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set AWB mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera mirror mode -+ * @author xia_wenting -+ * @date 2011-03-21 -+ * @param[in] mirror mirror mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_mirror(T_CAMERA_MIRROR mirror) -+{ -+ switch(mirror) -+ { -+ case CAMERA_MIRROR_V: -+ camera_setup(MIRROR_V_TAB); -+ break; -+ case CAMERA_MIRROR_H: -+ camera_setup(MIRROR_H_TAB); -+ break; -+ case CAMERA_MIRROR_NORMAL: -+ camera_setup(MIRROR_NORMAL_TAB); -+ break; -+ case CAMERA_MIRROR_FLIP: -+ camera_setup(MIRROR_FLIP_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "camera gc0308 set mirror parameter error!\n"); -+ break; -+ } -+} -+ -+ -+/** -+ * @brief Set camera effect mode -+ * @author xia_wenting -+ * @date 2011-03-21 -+ * @param[in] effect effect mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_gc0308_set_effect(T_CAMERA_EFFECT effect) -+{ -+ switch(effect) -+ { -+ case CAMERA_EFFECT_NORMAL: -+ camera_setup(EFFECT_NORMAL_TAB); -+ break; -+ case CAMERA_EFFECT_SEPIA: -+ camera_setup(EFFECT_SEPIA_TAB); -+ break; -+ case CAMERA_EFFECT_ANTIQUE: -+ camera_setup(EFFECT_ANTIQUE_TAB); -+ break; -+ case CAMERA_EFFECT_BLUE: -+ camera_setup(EFFECT_BLUISH_TAB); -+ break; -+ case CAMERA_EFFECT_GREEN: -+ camera_setup(EFFECT_GREENISH_TAB); -+ break; -+ case CAMERA_EFFECT_NEGATIVE: -+ camera_setup(EFFECT_NEGATIVE_TAB); -+ break; -+ case CAMERA_EFFECT_BW: -+ camera_setup(EFFECT_BW_TAB); -+ break; -+ case CAMERA_EFFECT_BWN: -+ camera_setup(EFFECT_BWN_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set camer effect parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief set camera window -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] srcWidth window width -+ * @param[in] srcHeight window height -+ * @return T_S32 -+ * @retval 0 if error mode -+ * @retval 1 if success -+ * @retval -1 if failed -+ */ -+static T_S32 cam_gc0308_set_digital_zoom(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_U16 hrefstart = 0, vrefstart = 0; -+ T_U8 high_bit = 0, low_bit = 0; -+ T_CAMERA_MODE Cammode = s_gc0308_CurMode; -+ T_U8 Camera_window_table[] = -+ { -+ 0x46, 0, -+ 0x47, 0, -+ 0x48, 0, -+ 0x49, 0, -+ 0x4a, 0, -+ 0x4b, 0, -+ 0x4c, 0, -+ END_FLAG, END_FLAG -+ }; -+ -+ akprintf(C1, M_DRVSYS, "set window size %d, %d, %d\r\n", Cammode, srcWidth, srcHeight); -+ -+ if (((srcWidth == 640) && (srcHeight == 480)) -+ || ((srcWidth == 352) && (srcHeight == 288)) -+ || ((srcWidth == 320) && (srcHeight == 240)) -+ || ((srcWidth == 176) && (srcHeight == 144))) -+ { -+ return 1; -+ } -+ -+ switch (s_gc0308_CurMode) -+ { -+ case CAMERA_MODE_VGA: -+ hrefstart = (640 - srcWidth) / 2; -+ vrefstart = (480 - srcHeight) / 2; -+ break; -+ -+ case CAMERA_MODE_CIF: -+ hrefstart = (352 - srcWidth) / 2; -+ vrefstart = (288 - srcHeight) / 2; -+ break; -+ -+ case CAMERA_MODE_QVGA: -+ hrefstart = (320 - srcWidth) / 2; -+ vrefstart = (240 - srcHeight) / 2; -+ break; -+ -+ case CAMERA_MODE_QCIF: -+ hrefstart = (176 - srcWidth) / 2; -+ vrefstart = (144 - srcHeight) / 2; -+ break; -+ -+ case CAMERA_MODE_QQVGA: -+ hrefstart = (160 - srcWidth) / 2; -+ vrefstart = (120 - srcHeight) / 2; -+ break; -+ -+ case CAMERA_MODE_PREV: -+ hrefstart = (640 - srcWidth) / 2; -+ vrefstart = (480 - srcHeight) / 2; -+ break; -+ -+ case CAMERA_MODE_REC: -+ hrefstart = (640 - srcWidth) / 2; -+ vrefstart = (480 - srcHeight) / 2; -+ break; -+ -+ default: -+ akprintf(C1, M_DRVSYS, "unsupported WINDOWING in mode %d!!\n", s_gc0308_CurMode); -+ return 0; -+ } -+ -+ high_bit = hrefstart >> 8; //horizontal frame start high 3-bit -+ low_bit = hrefstart & 0xff; //horizontal frame start low 8-bit -+ Camera_window_table[1] = 0x80 | (high_bit & 0x07); -+ Camera_window_table[5] = low_bit; -+ Camera_window_table[11] = srcWidth >> 8; -+ Camera_window_table[13] = srcWidth & 0xff; -+ -+ high_bit = vrefstart >> 8; //vertical frame start high 2-bit -+ low_bit = vrefstart & 0xff; //vertical frame start low 8-bit -+ Camera_window_table[1] = 0x80 | (high_bit & 0x30); -+ Camera_window_table[3] = low_bit; -+ Camera_window_table[7] = srcHeight >> 8; -+ Camera_window_table[9] = srcHeight & 0xff; -+ -+ if (camera_set_param(Camera_window_table) == AK_TRUE) -+ { -+ return 1; -+ } -+ else -+ { -+ return -1; -+ } -+} -+ -+static T_VOID cam_gc0308_set_night_mode(T_NIGHT_MODE mode) -+{ -+ switch(mode) -+ { -+ case CAMERA_DAY_MODE: -+ camera_setup(DAY_MODE_TAB); -+ night_mode = CAMERA_DAY_MODE; -+ break; -+ case CAMERA_NIGHT_MODE: -+ camera_setup(NIGHT_MODE_TAB); -+ night_mode = CAMERA_NIGHT_MODE; -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set night mode parameter error!\n"); -+ break; -+ } -+} -+ -+static T_VOID cam_gc0308_set_anti_flicker(T_U32 value) -+{ -+ switch(value) { -+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: -+ camera_setup(ANTI_FLICKER_DISABLE_TAB); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: -+ camera_setup(ANTI_FLICKER_50HZ_TAB); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: -+ camera_setup(ANTI_FLICKER_60HZ_TAB); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: -+ camera_setup(ANTI_FLICKER_AUTO_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set Anti-flicker parameter error!\n"); -+ break; -+ } -+} -+ -+static T_BOOL cam_gc0308_set_to_cap(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_VGA; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "30W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_gc0308_set_mode(Cammode); -+ cam_gc0308_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(200); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_gc0308_set_to_prev(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_gc0308_set_mode(CAMERA_MODE_PREV); -+ cam_gc0308_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(200); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_gc0308_set_to_record(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_REC; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "30W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_gc0308_set_mode(Cammode); -+ cam_gc0308_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(200); -+ return AK_TRUE; -+} -+ -+static T_CAMERA_TYPE cam_gc0308_get_type(T_VOID) -+{ -+ return camera_gc0308_type; -+} -+ -+static T_VOID cam_gc0308_set_sensor_param(T_U32 cmd, T_U32 data) -+{ -+ T_U8 value; -+ -+ value = (T_U8)data; -+ sccb_write_data(CAMERA_SCCB_ADDR, (T_U8)cmd, &value, 1); -+} -+ -+static T_CAMERA_FUNCTION_HANDLER gc0308_function_handler = -+{ -+ GC0308_CAMERA_MCLK, -+ cam_gc0308_open, -+ cam_gc0308_close, -+ cam_gc0308_read_id, -+ cam_gc0308_init, -+ cam_gc0308_set_mode, -+ cam_gc0308_set_exposure, -+ cam_gc0308_set_brightness, -+ cam_gc0308_set_contrast, -+ cam_gc0308_set_saturation, -+ cam_gc0308_set_sharpness, -+ cam_gc0308_set_AWB, -+ cam_gc0308_set_mirror, -+ cam_gc0308_set_effect, -+ cam_gc0308_set_digital_zoom, -+ cam_gc0308_set_night_mode, -+ AK_NULL, -+ cam_gc0308_set_anti_flicker, -+ cam_gc0308_set_to_cap, -+ cam_gc0308_set_to_prev, -+ cam_gc0308_set_to_record, -+ cam_gc0308_get_type, -+ cam_gc0308_set_sensor_param -+}; -+ -+#ifndef CONFIG_LINUX_AKSENSOR -+static int camera_gc0308_reg(void) -+{ -+ camera_reg_dev(CAMERA_GC0308_ID, &gc0308_function_handler); -+ return 0; -+} -+ -+#ifdef __CC_ARM -+#pragma arm section rwdata = "__initcall_", zidata = "__initcall_" -+#endif -+module_init(camera_gc0308_reg) -+#ifdef __CC_ARM -+#pragma arm section -+#endif -+ -+ -+#else -+ -+static const char * exposure_menu[] = { -+ [EXPOSURE_WHOLE] = "whole", -+ [EXPOSURE_CENTER] = "center", -+ [EXPOSURE_MIDDLE] = "middle", -+}; -+static const char * awb_menu[] = { -+ [AWB_AUTO] = "auto", -+ [AWB_SUNNY] = "sunny", -+ [AWB_CLOUDY] = "cloudy", -+ [AWB_OFFICE] = "office", -+ [AWB_HOME] = "home", -+ [AWB_NIGHT] = "night", -+}; -+static const char * effect_menu[] = { -+ [CAMERA_EFFECT_NORMAL] = "normal", -+ [CAMERA_EFFECT_SEPIA] = "sepia", -+ [CAMERA_EFFECT_ANTIQUE] = "antique", -+ [CAMERA_EFFECT_BLUE] = "blue", -+ [CAMERA_EFFECT_GREEN] = "green", -+ [CAMERA_EFFECT_RED] = "red", -+ [CAMERA_EFFECT_NEGATIVE] = "negative", -+ [CAMERA_EFFECT_BW] = "bw", -+ [CAMERA_EFFECT_BWN] = "bwn", -+ [CAMERA_EFFECT_AQUA] = "aqua", -+ [CAMERA_EFFECT_COOL] = "cool", -+ [CAMERA_EFFECT_WARM] = "warm", -+}; -+ -+static const char * resolution_menu[] = { -+ [0] = "640x480", -+ [1] = "352x288", -+ [2] = "320x240", -+ [3] = "176x144", -+ [4] = "160x120", -+}; -+ -+static const char * hflip_menu[] = { -+ [0] = "normal", -+ [1] = "horizontal flip", -+}; -+ -+static const char * vflip_menu[] = { -+ [0] = "normal", -+ [1] = "vertical flip", -+}; -+ -+static const char * night_menu[] = { -+ [CAMERA_DAY_MODE] = "daylight", -+ [CAMERA_NIGHT_MODE] = "night", -+}; -+ -+static const char * anti_flicker_menu[] = { -+ [V4L2_CID_POWER_LINE_FREQUENCY_DISABLED] = "Disable", -+ [V4L2_CID_POWER_LINE_FREQUENCY_50HZ] = "50Hz", -+ [V4L2_CID_POWER_LINE_FREQUENCY_60HZ] = "60Hz", -+ [V4L2_CID_POWER_LINE_FREQUENCY_AUTO] = "Auto", -+}; -+ -+static int gc0308_s_ctl(struct v4l2_ctrl *ctrl) -+{ -+ int ret = -EINVAL; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_EXPOSURE: -+ if (gc0308_function_handler.cam_set_exposure_func) { -+ gc0308_function_handler.cam_set_exposure_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ if (gc0308_function_handler.cam_set_AWB_func) { -+ gc0308_function_handler.cam_set_AWB_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_COLORFX: -+ if (gc0308_function_handler.cam_set_effect_func) { -+ gc0308_function_handler.cam_set_effect_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_BRIGHTNESS: -+ if (gc0308_function_handler.cam_set_brightness_func) { -+ gc0308_function_handler.cam_set_brightness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_CONTRAST: -+ if (gc0308_function_handler.cam_set_contrast_func) { -+ gc0308_function_handler.cam_set_contrast_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SATURATION: -+ if (gc0308_function_handler.cam_set_saturation_func) { -+ gc0308_function_handler.cam_set_saturation_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SHARPNESS: -+ if (gc0308_function_handler.cam_set_sharpness_func) { -+ gc0308_function_handler.cam_set_sharpness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_HFLIP: -+ if (gc0308_function_handler.cam_set_mirror_func) { -+ gc0308_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_H : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_VFLIP: -+ if (gc0308_function_handler.cam_set_mirror_func) { -+ gc0308_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_V : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_NIGHTMODE: -+ if (gc0308_function_handler.cam_set_night_mode_func) { -+ gc0308_function_handler.cam_set_night_mode_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY: -+ if (gc0308_function_handler.cam_set_anti_flicker_func) { -+ gc0308_function_handler.cam_set_anti_flicker_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+}; -+ -+static struct v4l2_ctrl_ops gc0308_ctrl_ops = { -+ .s_ctrl = gc0308_s_ctl, -+}; -+ -+static const struct v4l2_ctrl_config gc0308_ctrls[] = { -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_EXPOSURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Exposure", -+ .min = 0, -+ .max = ARRAY_SIZE(exposure_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = exposure_menu, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_AUTO_WHITE_BALANCE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "AWB", -+ .min = 0, -+ .max = ARRAY_SIZE(awb_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = awb_menu, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_COLORFX, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Effect", -+ .min = 0, -+ .max = ARRAY_SIZE(effect_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = effect_menu, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Horizontal Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(hflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = hflip_menu, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Vetical Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(vflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = vflip_menu, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_PICTURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Resolution", -+ .min = 0, -+ .max = ARRAY_SIZE(resolution_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = resolution_menu, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_NIGHTMODE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Night mode", -+ .min = 0, -+ .max = ARRAY_SIZE(night_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = night_menu, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_BRIGHTNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Brightness", -+ .min = 0, -+ .max = CAMERA_BRIGHTNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .min = 0, -+ .max = CAMERA_CONTRAST_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .min = 0, -+ .max = CAMERA_SATURATION_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_SHARPNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Sharpness", -+ .min = 0, -+ .max = CAMERA_SHARPNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &gc0308_ctrl_ops, -+ .id = V4L2_CID_POWER_LINE_FREQUENCY, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "anti flicker", -+ .min = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, -+ .max = V4L2_CID_POWER_LINE_FREQUENCY_AUTO, -+ .step = 0, -+ .def = V4L2_CID_POWER_LINE_FREQUENCY_50HZ, -+ .flags = 0, -+ .menu_skip_mask = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, -+ .qmenu = anti_flicker_menu, -+ } -+}; -+ -+/* -+ * supported format list -+ */ -+static const struct aksensor_color_format gc0308_formats[] = { -+ { -+ .code = V4L2_MBUS_FMT_YUYV8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_YVYU8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_UYVY8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+}; -+ -+static const struct aksensor_win_size gc0308_win[] = { -+ {.name = "VGA", .width = 640, .height = 480}, -+}; -+ -+ -+static struct sensor_info gc0308_sensor_info = { -+ .sensor_name = "gc0308", -+ .sensor_id = CAMERA_GC0308_ID, -+ .ctrls = gc0308_ctrls, -+ .nr_ctrls = ARRAY_SIZE(gc0308_ctrls), -+ .formats = gc0308_formats, -+ .num_formats = ARRAY_SIZE(gc0308_formats), -+ .resolution = gc0308_win, -+ .num_resolution = ARRAY_SIZE(gc0308_win), -+ .handler = &gc0308_function_handler, -+}; -+ -+static int gc0308_module_init(void) -+{ -+ return register_sensor(&gc0308_sensor_info); -+} -+module_init(gc0308_module_init) -+#endif -+ -+#endif -+ -diff --git a/drivers/media/video/plat-anyka/camera_gc0308.h b/drivers/media/video/plat-anyka/camera_gc0308.h -new file mode 100755 -index 00000000..895219c4 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_gc0308.h -@@ -0,0 +1,1410 @@ -+/** -+ * @file camera_gc0308.h -+ * @brief camera driver file -+ * Copyright (C) 2010 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-09-21 -+ * @version 1.0 -+ * @ref -+ */ -+#ifndef __CAMERA_GC0308_H__ -+#define __CAMERA_GC0308_H__ -+ -+#if defined (USE_CAMERA_GC0308) || defined (CONFIG_SENSOR_GC0308) -+ -+#undef DELAY_FLAG -+#undef END_FLAG -+#define DELAY_FLAG 0xfb // first parameter is 0xfb, then 2nd parameter is delay time count -+#define END_FLAG 0xfc // first parameter is 0xfc, then parameter table is over -+ -+ -+static const T_U8 INIT_TAB[] = -+{ -+#if 1 -+ /* -+ 0xfe, 0x00, -+ 0x01, 0xb5, //28M guding 25fps -+ 0x02, 0x98, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0xa0, -+ 0xe4, 0x02, -+ 0xe5, 0x80, -+ 0xe6, 0x02, -+ 0xe7, 0x80, -+ 0xe8, 0x02, -+ 0xe9, 0x80, -+ 0xea, 0x02, -+ 0xeb, 0x80,*/ -+ -+ 0xfe, 0x00, -+ 0x01, 0x6a, //24M guding 25fps -+ 0x02, 0x70, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0x96, -+ 0xe4, 0x02, -+ 0xe5, 0x58, -+ 0xe6, 0x02, -+ 0xe7, 0x58, -+ 0xe8, 0x02, -+ 0xe9, 0x58, -+ 0xea, 0x0e, -+ 0xeb, 0xa6, -+ -+ 0xec, 0x20, //[5:4]exp_level [3:0]minimum exposure high 4 bits -+ 0x05, 0x00, // row_start_high -+ 0x06, 0x00, // row_start_low -+ 0x07, 0x00, // col_start_high -+ 0x08, 0x00, // col_start_low -+ 0x09, 0x01, //[8]cis_win_height 488 -+ 0x0a, 0xe8, //[7:0]cis_win_height -+ 0x0b, 0x02, //[9:8]cis_win_width 648 -+ 0x0c, 0x88, //[7:0]cis_win_width -+ 0x0d, 0x02, //vs_st -+ 0x0e, 0x02, //vs_et -+ 0x10, 0x26, //[7:4]restg_width, [3:0]sh_width -+ 0x11, 0x0d, //fd//[7:4]tx_width, [3:0]space width,*2 -+ 0x12, 0x2a, //sh_delay -+ 0x13, 0x00, //[3:0] row_tail_width -+ 0x14, 0x10, //[7]hsync_always ,[6] NA, [5:4] CFA sequence -+ // [3:2]NA, [1]upside_down, [0] mirror -+ 0x15, 0x0a, //[7:6]output_mode,,[5:4]restg_mode,[3:2]sdark_mode, [1]new exposure,[0]badframe_en -+ 0x16, 0x05, //[7:5]NA, [4]capture_ad_data_edge, [3:0]Number of A/D pipe stages -+ 0x17, 0x01, //[7:6]analog_opa_r,[5]coltest_en, [4]ad_test_enable, -+ //[3]tx_allow,[2]black sun correction,[1:0]black sun control reg -+ 0x18, 0x44, //[7]NA, [6:4]column gain ee, [3]NA, [2:0]column gain eo -+ 0x19, 0x44, //[7]NA, [6:4]column gain oe, [3]NA, [2:0]column gain oo -+ 0x1a, 0x2a, //1e//[7]rsv1,[6]rsv0, [5:4]coln_r, -+ //[3:2]colg_r column gain opa bias current, [1]clk_delay, [0] apwd -+ 0x1b, 0x00, //[7:2]NA, [1:0]BIN4 AND BIN2 -+ 0x1c, 0x49, //c1//[7]hrst_enbale, [6:4]da_rsg, [3]tx high enable, [2]NA, [1:0]da18_r -+ 0x1d, 0x9a, //08//[7]vref_en, [6:4]da_vef, [3]da25_en, [2]NA, [1:0]da25_r,set da25 voltage -+ 0x1e, 0x61, //60//[7]LP_MTD,[6:5]opa_r,ADC's operating current, [4:2]NA, [1:0]sref -+ 0x1f, 0x12, //[7:6]NA, [5:4]sync_drv, [3:2]data_drv, [1:0]pclk_drv -+ -+ 0x20, 0xff, //[7]bks[6]gamma[5]cc[4]ee[3]intp[2]dn[1]dd[0]lsc -+ 0x21, 0xf8, //[7]na[6]na[5]skin_ee[4]cbcr_hue_en[3]y_as_en[2]auto_gray_en[1]y_gamma_en[0]na -+ 0x22, 0x57, //[7]na [6]auto_dndd [5]auto_ee [4]auto_sa [3]na [2]abs [1]awb [0]na -+ 0x24, 0xa0, //a2 -+ 0x25, 0x0f, -+ //output sync_mode -+ 0x26, 0x02, ////02 -+ 0x2f, 0x01, //debug mode3 -+ -+ //grab -+ 0x30, 0xf7, //blk mode [7]dark current mode:1 use exp rated dark ,0 use ndark row calculated -+ //[1]dark_current_en//[0]offset_en -+ 0x31, 0x50, //blk_value limit.64 low align to 11bits;8 for 256 range -+ 0x32, 0x00, //global offset -+ 0x39, 0x04, // exp_ate_darkc -+ 0x3a, 0x20, //{7:6}offset submode {5:0}offset ratio -+ 0x3b, 0x20, //{7:6}darkc submode {5:0}dark current ratio -+ 0x3c, 0x00, //manual g1 offset -+ 0x3d, 0x00, //manual r offset -+ 0x3e, 0x00, //manual b offset -+ 0x3f, 0x00, //manual g2 offset -+ //gain -+ 0x50, 0x14, //10 //global gain -+ -+ 0x53, 0x80, //G -+ 0x54, 0x80, //R channel gain -+ 0x55, 0x80, //B channel gain -+ 0x56, 0x80, -+ -+ //LSC_t -+ 0x8b, 0x20, //r2 -+ 0x8c, 0x20, //g2 -+ 0x8d, 0x20, //b2 -+ 0x8e, 0x14, //r4 -+ 0x8f, 0x10, //g4 -+ 0x90, 0x14, //b4 -+ 0x91, 0x3c, //[7]singed4 [6:0]row_cneter -+ 0x92, 0x50, //col_center -+ 0x5d, 0x12, //decrease 1 -+ 0x5e, 0x1a, //decrease 2 -+ 0x5f, 0x24, //decrease 3 -+ -+ //DNDD_t -+ 0x60, 0x07, //[4]zero weight mode -+ //[3]share mode -+ //[,]c weight mode -+ //[,]lsc decrease mode -+ //[,]b mode -+ 0x61, 0x15, //[7:6]na -+ //[5:4]c weight adap ratio -+ //[,:2]dn lsc ratio -+ //[,:0]b ratio -+ 0x62, 0x08, //b base -+ //0x63,0x02,//b increase RO -+ 0x64, 0x02, //03//[7:4]n base [3:0]c weight -+ //0x65, , //[7:4]n increase [3:0]c coeff -+ 0x66, 0xe8, //dark_th ,bright_th -+ 0x67, 0x86, //flat high, flat low -+ 0x68, 0xa2, //[7:4]dd limit [1:0]dd ratio -+ -+ //asde_t -+ 0x69, 0x18, //gain high th -+ 0x6a, 0x0f, //[7:4]dn_c slop //[3]use post_gain [2]use pre_gain [1]use global gain [0]use col gain -+ 0x6b, 0x00, //[7:4]dn_b slop [3:0]dn_n slop -+ 0x6c, 0x5f, //[7:4]bright_th start [3:0]bright_th slop -+ 0x6d, 0x8f, //[7:4]dd_limit_start[3:0]dd_limit slop -+ 0x6e, 0x55, //[7:4]ee1 effect start [3:0]slope broad -+ 0x6f, 0x38, //[7:4]ee2 effect start [3:0]slope narrow -+ 0x70, 0x15, //saturation dec slope -+ 0x71, 0x33, //33//[7:4]low limit,[3:0]saturation slope -+ -+ //eeintp_t -+ 0x72, 0xdc, //[7]edge_add_mode [6]new edge mode [5]edge2_mode [4]HP_mode -+ //[3]lp intp en [2]lp edge en [1:0]lp edge mode -+ 0x73, 0x80, //[7]edge_add_mode2 [6]NA [5]only 2direction [4]fixed direction th -+ //[3]only defect map [2]intp_map dir [1]HP_acc [0]only edge map -+ -+ //for high resolution in light scene -+ 0x74, 0x02, //direction th1 -+ 0x75, 0x3f, //direction th2 -+ 0x76, 0x02, //direction diff th h>v+diff ; h>th1 ; v<th2 -+ 0x77, 0x84,//32, //36//[7:4]edge1_effect [3:0]edge2_effect -+ 0x78, 0x88, //[7:4]edge_pos_ratio [3:0]edge neg ratio -+ 0x79, 0x81, //edge1_max,edge1_min -+ 0x7a, 0x81, //edge2_max,edge2_min -+ 0x7b, 0x22, //edge1_th,edge2_th -+ 0x7c, 0xff, //pos_edge_max,neg_edge_max -+ -+ //cct -+ 0x93, 0x48, // <--40 -+ 0x94, 0x02, -+ 0x95, 0x07, -+ 0x96, 0xe0, -+ 0x97, 0x40, -+ 0x98, 0xf0, -+ //ycpt -+ 0xb1, 0x40, //manual cb -+ 0xb2, 0x40, //manual cr -+ 0xb3, 0x40, //40 -+ 0xb6, 0xe0, -+ 0xbd, 0x38, -+ 0xbe, 0x36, // [5:4]gray mode 00:4&8 01:4&12 10:4&20 11:8$16 [3:0] auto_gray -+ //AECT -+ 0xd0, 0xcb, // exp is gc mode -+ 0xd1, 0x10, //every N -+ 0xd2, 0x90, // 7 aec enable 5 clore y mode 4skin weight 3 weight drop mode -+ 0xd3, 0x58, //48 //Y_target and low pixel thd high X4 low X2 -+ 0xd5, 0xf2, //lhig -+ 0xd6, 0x16, // ignore mode -+ 0xdb, 0x92, -+ 0xdc, 0xa5, //fast_margin fast_ratio -+ 0xdf, 0x23, // I_fram D_ratio -+ -+ 0xd9, 0x00, // colore offset in CAL ,now is too dark so set zero -+ 0xda, 0x00, // GB offset -+ 0xe0, 0x09, -+ -+ -+ 0xed, 0x04, //minimum exposure low 8 bits -+ 0xee, 0xa0, //max_post_dg_gain -+ 0xef, 0x40, //max_pre_dg_gain -+ 0x80, 0x03, -+ -+ ////abbt -+ 0x80, 0x03, -+ ////RGBgama_m5 -+ 0x9F, 0x10, -+ 0xA0, 0x20, -+ 0xA1, 0x38, -+ 0xA2, 0x4E, -+ 0xA3, 0x63, -+ 0xA4, 0x76, -+ 0xA5, 0x87, -+ 0xA6, 0xA2, -+ 0xA7, 0xB8, -+ 0xA8, 0xCA, -+ 0xA9, 0xD8, -+ 0xAA, 0xE3, -+ 0xAB, 0xEB, -+ 0xAC, 0xF0, -+ 0xAD, 0xF8, -+ 0xAE, 0xFD, -+ 0xAF, 0xFF, -+ ///wint -+ ///Y_gamma -+ 0xc0, 0x00, //Y_gamma_0 -+ 0xc1, 0x10, //Y_gamma_1 -+ 0xc2, 0x1C, //Y_gamma_2 -+ 0xc3, 0x30, //Y_gamma_3 -+ 0xc4, 0x43, //Y_gamma_4 -+ 0xc5, 0x54, //Y_gamma_5 -+ 0xc6, 0x65, //Y_gamma_6 -+ 0xc7, 0x75, //Y_gamma_7 -+ 0xc8, 0x93, //Y_gamma_8 -+ 0xc9, 0xB0, //Y_gamma_9 -+ 0xca, 0xCB, //Y_gamma_10 -+ 0xcb, 0xE6, //Y_gamma_11 -+ 0xcc, 0xFF, //Y_gamma_12 -+ //ABS -+ 0xf0, 0x02, -+ 0xf1, 0x01, -+ 0xf2, 0x02, //manual stretch K -+ 0xf3, 0x30, //the limit of Y_stretch -+ 0xf7, 0x12, -+ 0xf8, 0x0a, -+ 0xf9, 0x9f, -+ 0xfa, 0x78, -+ -+ 0xb3, 0x40, //contrast -+ 0xb5, 0x08, //brightness -+ 0xd3, 0x5c, -+ -+ 0xb1, 0x50, //sat -+ 0xb2, 0x50, -+ -+ //AWB -+ 0xfe, 0x01, -+ 0x00, 0xf5, //high_low limit -+ 0x02, 0x20, //y2c -+ 0x04, 0x10, -+ 0x05, 0x08, -+ 0x06, 0x20, -+ 0x08, 0x0a, -+ 0x0a, 0xa0, // number limit -+ 0x0b, 0x60, // skip_mode -+ 0x0c, 0x08, -+ 0x0e, 0x44, // width step -+ 0x0f, 0x32, // height step -+ 0x10, 0x41, -+ 0x11, 0x37, // 0x3f -+ 0x12, 0x22, -+ 0x13, 0x19, //13//smooth 2 -+ 0x14, 0x44, //R_5k_gain_base -+ 0x15, 0x44, //B_5k_gain_base -+ 0x16, 0xc2, //c2//sinT -+ 0x17, 0xa8, //ac//a8//a8//a8//cosT -+ 0x18, 0x18, //X1 thd -+ 0x19, 0x50, //X2 thd -+ 0x1a, 0xd8, //e4//d0//Y1 thd -+ 0x1b, 0xf5, //Y2 thd -+ 0x70, 0x40, // A R2G low -+ 0x71, 0x58, // A R2G high -+ 0x72, 0x30, // A B2G low -+ 0x73, 0x48, // A B2G high -+ 0x74, 0x20, // A G low -+ 0x75, 0x60, // A G high -+ 0x77, 0x20, -+ 0x78, 0x32, -+ -+ ///hsp -+ 0x30, 0x03,//[1]HSP_en [0]sa_curve_en -+ 0x31, 0x40, -+ 0x32, 0x10, -+ 0x33, 0xe0, -+ 0x34, 0xe0, -+ 0x35, 0x00, -+ 0x36, 0x80, -+ 0x37, 0x00, -+ 0x38, 0x04,//sat1, at8 -+ 0x39, 0x09, -+ 0x3a, 0x12, -+ 0x3b, 0x1C, -+ 0x3c, 0x28, -+ 0x3d, 0x31, -+ 0x3e, 0x44, -+ 0x3f, 0x57, -+ 0x40, 0x6C, -+ 0x41, 0x81, -+ 0x42, 0x94, -+ 0x43, 0xA7, -+ 0x44, 0xB8, -+ 0x45, 0xD6, -+ 0x46, 0xEE, //sat15,at224 -+ 0x47, 0x0d,//blue_edge_dec_ratio -+ -+ ///out -+ 0xfe, 0x00, -+#endif -+ -+#if 0 -+//using settings from taixin video pen 20110317 -+ 0xfe, 0x00, -+ 0x01, 0x6a, //28M guding 25fps -+ 0x02, 0x70, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0x96, -+ 0xe4, 0x02, -+ 0xe5, 0x58, -+ 0xe6, 0x03, -+ 0xe7, 0x84, -+ 0xe8, 0x07, -+ 0xe9, 0x08, -+ 0xea, 0x0d, -+ 0xeb, 0x7a, -+ -+ 0xec, 0x20, -+ 0x05, 0x00, -+ 0x06, 0x00, -+ 0x07, 0x00, -+ 0x08, 0x00, -+ 0x09, 0x01, -+ 0x0a, 0xe8, -+ 0x0b, 0x02, -+ 0x0c, 0x88, -+ 0x0d, 0x02, -+ 0x0e, 0x04, -+ 0x10, 0x22, -+ 0x11, 0x0d, -+ 0x12, 0x2a, -+ 0x13, 0x00, -+ 0x14, 0x10, //00 -+ -+ 0x15, 0x0a, -+ 0x16, 0x05, -+ 0x17, 0x01, //05 -+ -+ 0x18, 0x44, -+ 0x19, 0x44, -+ 0x1a, 0x2a, //17 -+ -+ 0x1b, 0x00, -+ 0x1c, 0x41, -+ 0x1d, 0xba, -+ 0x1e, 0x11, -+ 0x1f, 0x15, -+ -+ 0x20, 0xff, -+ 0x21, 0xff, -+ 0x22, 0x00, -+ 0x24, 0xa0,///a2, -+ 0x25, 0x0f,//00, -+ -+ 0x26, 0x02,///02,//3f, -+ 0x2f, 0x01, -+ -+ //grab -+ 0x30, 0x27, -+ 0x31, 0x40, -+ 0x32, 0x01, -+ 0x39, 0x04, -+ 0x3a, 0x20, -+ 0x3b, 0x10, -+ 0x3c, 0x00, -+ 0x3d, 0x00, -+ 0x3e, 0x00, -+ 0x3f, 0x00, -+ 0x50, 0x12, -+ 0x53, 0x80, -+ 0x54, 0x80, -+ 0x55, 0x80, -+ 0x56, 0x80, -+ -+ //LSC_t -+ 0x8b, 0x40, -+ 0x8c, 0x40, -+ 0x8d, 0x40, -+ 0x8e, 0x30, -+ 0x8f, 0x30, -+ 0x90, 0x30, -+ 0x91, 0x3c, -+ 0x92, 0x50, -+ 0x5d, 0x12, -+ 0x5e, 0x1a, -+ 0x5f, 0x24, -+ 0x60, 0x07, -+ 0x61, 0x22, -+ 0x62, 0x0c, -+ 0x64, 0x05, -+ 0x66, 0xe6, -+ 0x67, 0x86, -+ 0x68, 0x82, -+ 0x69, 0x20, -+ 0x6a, 0xaf, -+ 0x6b, 0xaa, -+ 0x6c, 0x5f, -+ 0x6d, 0x8f, -+ 0x6e, 0x58, -+ 0x6f, 0x48, -+ 0x70, 0x10, -+ 0x71, 0x31, -+ 0x72, 0xec, -+ 0x73, 0x80, -+ 0x74, 0x05, -+ 0x75, 0x3f, -+ 0x76, 0x05, -+ 0x77, 0x84, -+ 0x78, 0x88, -+ 0x79, 0x81, -+ 0x7a, 0x81, -+ 0x7b, 0x22, -+ 0x7c, 0xf8, -+ 0x85, 0x04,// -+ 0x86, 0x04,// -+ 0x87, 0x05,// -+ 0x88, 0x04,// -+ 0x89, 0x04,// -+ 0x8a, 0x05,// -+ 0x93, 0x44, -+ 0x94, 0xfe, -+ 0x95, 0xfe, -+ 0x96, 0xfe, -+ 0x97, 0x44, -+ 0x98, 0xfe, -+ 0xb1, 0x30, -+ 0xb2, 0x30, -+ 0xb3, 0x40, -+ 0xb6, 0xe8, -+ 0xbd, 0x38, -+ 0xbe, 0x36, -+ //AECT -+ 0xd0, 0xca, -+ 0xd1, 0x21, -+ 0xd2, 0x90, -+ 0xd3, 0x50, -+ 0xd5, 0xf2, -+ 0xd6, 0x18, -+ 0xdb, 0x91, -+ 0xdc, 0x96, -+ 0xdf, 0x33, -+ 0xd9, 0x88, -+ 0xda, 0x88, -+ 0xe0, 0x07, -+ 0xed, 0x04, -+ 0xee, 0xc0, -+ 0xef, 0x60, -+ 0x80, 0x03, -+ -+ //abbt -+ 0x80, 0x03, -+ //RGBgama_m5 -+ 0x9f, 0x10, -+ 0xa0, 0x20, -+ 0xa1, 0x38, -+ 0xa2, 0x4e, -+ 0xa3, 0x63, -+ 0xa4, 0x76, -+ 0xa5, 0x87, -+ 0xa6, 0xa2, -+ 0xa7, 0xb8, -+ 0xa8, 0xca, -+ 0xa9, 0xd8, -+ 0xaa, 0xe3, -+ 0xab, 0xeb, -+ 0xac, 0xf0, -+ 0xad, 0xf8, -+ 0xae, 0xfd, -+ 0xaf, 0xff, -+ 0xbd, 0x38,// -+ 0xbe, 0x36,// -+ -+ 0xc0, 0x00, -+ 0xc1, 0x10, -+ 0xc2, 0x1c, -+ 0xc3, 0x30, -+ 0xc4, 0x43, -+ 0xc5, 0x54, -+ 0xc6, 0x65, -+ 0xc7, 0x75, -+ 0xc8, 0x93, -+ 0xc9, 0xb0, -+ 0xca, 0xcb, -+ 0xcb, 0xe6, -+ 0xcc, 0xff, -+ 0xd3, 0x50,// -+ 0xd4, 0x80,// -+ 0xdb, 0x91,// -+ 0xf0, 0xf3, -+ 0xf1, 0x02, -+ 0xf2, 0x00, -+ 0xf3, 0x30, -+ 0xf4, 0xc0,// -+ 0xf5, 0x40,// -+ 0xf7, 0x04, -+ 0xf8, 0x02, -+ 0xf9, 0x98, -+ 0xfa, 0x70, -+ ///////////////// -+ 0xfe, 0x01, -+ 0x53, 0x83,// -+ 0x54, 0x11,// -+ 0x00, 0xf5, -+ 0x02, 0x18, -+ 0x04, 0x10, -+ 0x05, 0x22, -+ 0x06, 0x40, -+ 0x08, 0x60, -+ 0x0a, 0x90, -+ 0x0b, 0x60, -+ 0x0c, 0x06, -+ 0x0e, 0x49, -+ 0x0f, 0x36, -+ 0x10, 0x42, -+ 0x11, 0x0f, -+ 0x12, 0x42, -+ 0x13, 0x21, -+ 0x14, 0x40, -+ 0x15, 0x40, -+ 0x16, 0xc2, -+ 0x17, 0xa6, -+ 0x18, 0x20, -+ 0x19, 0x4b, -+ 0x1a, 0xb0, -+ 0x1b, 0xea, -+ 0x1c, 0x70,// -+ 0x1d, 0x58,// -+ 0x1e, 0x78,// -+ 0x70, 0x45, -+ 0x71, 0x58, -+ 0x72, 0x30, -+ 0x73, 0x3d, -+ 0x74, 0x20, -+ 0x75, 0x50, -+ 0x76, 0x60,// -+ 0x77, 0x20, -+ 0x78, 0x30, -+ 0x79, 0x20,// -+ 0x30, 0x03, -+ 0x31, 0x40, -+ 0x32, 0x00, -+ 0x33, 0xd6, -+ 0x34, 0xe0, -+ 0x35, 0x6a, -+ 0x36, 0x80, -+ 0x37, 0x60, -+ 0x38, 0x06, -+ 0x39, 0x0b, -+ 0x3a, 0x14, -+ 0x3b, 0x1d, -+ 0x3c, 0x28, -+ 0x3d, 0x31, -+ 0x3e, 0x44, -+ 0x3f, 0x57, -+ 0x40, 0x6c, -+ 0x41, 0x81, -+ 0x42, 0x94, -+ 0x43, 0xa7, -+ 0x44, 0xb8, -+ 0x45, 0xd6, -+ 0x46, 0xee, -+ 0x47, 0x0c, -+ 0xd0, 0x40,// -+ 0xd1, 0x40,// -+ 0xd2, 0x40,// -+#endif -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 VGA_MODE_TAB[] = -+{ -+ 0x26, 0x02, -+ 0x10, 0x26, -+ -+ 0x05, 0x00, // row_start_high -+ 0x06, 0x00, // row_start_low -+ 0x07, 0x00, // col_start_high -+ 0x08, 0x00, // col_start_low -+ 0x09, 0x01, //[8]cis_win_height 488 -+ 0x0a, 0xe8, //[7:0]cis_win_height -+ 0x0b, 0x02, //[9:8]cis_win_width 648 -+ 0x0c, 0x88, //[7:0]cis_win_width -+ -+ 0x91, 0x3c, //[7]singed4 [6:0]row_cneter -+ 0x92, 0x50, //col_center -+ -+ 0xf7, 0x12, //big_win_x0,X4 -+ 0xf8, 0x0a, //big_win_y0 -+ 0xf9, 0x9f, //big_win_x1 -+ 0xfa, 0x78, //big_win_y1 -+ -+ 0xfe, 0x01, -+ //GC0309_Set_SubsampleRatio(GC_1_2_SUBSAMPLE_RATIO); // 1/1 subsample -+ 0x54, 0x11, -+ 0x55, 0x03, -+ 0x56, 0x00, -+ 0x57, 0x00, -+ 0x58, 0x00, -+ 0x59, 0x00, -+ -+ 0x0e, 0x44, -+ 0x0f, 0x32, -+ -+ 0xfe, 0x00, -+ 0x01, 0x6a, //24M guding 25fps -+ 0x02, 0x70, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0x96, -+ 0xe4, 0x02, -+ 0xe5, 0x58, -+ 0xe6, 0x02, -+ 0xe7, 0x58, -+ 0xe8, 0x02, -+ 0xe9, 0x58, -+ 0xea, 0x0e, -+ 0xeb, 0xa6, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CIF_MODE_TAB[] = -+{ -+ //windowing 352x288 -+ 0x26, 0x02, -+ 0x10, 0x26, -+ -+ 0x05, 0x00, //row_start -+ 0x06, 0x60, -+ 0x07, 0x00, //col start -+ 0x08, 0x90, -+ 0x09, 0x01, //win height 296 -+ 0x0A, 0x28, -+ 0x0B, 0x01, //win width 360 -+ 0x0c, 0x68, -+ -+ 0x91, 0x25, //LSC row center -+ 0x92, 0x31, //LSC colum center -+ -+ 0xf7, 0x01, //big_win_x0,x4 -+ 0xf8, 0x01, //big_win_y0 -+ 0xf9, 0x58, //big_win_x1 -+ 0xfa, 0x48, //big_win_y1 -+ -+ 0xfe, 0x01, -+ //GC0308_Set_SubsampleRatio(GC_1_1_SUBSAMPLE_RATIO); // 1/1 subsample -+ 0x54, 0x11, -+ 0x55, 0x03, -+ 0x56, 0x00, -+ 0x57, 0x00, -+ 0x58, 0x00, -+ 0x59, 0x00, -+ -+ 0x0e, 0x2b, -+ 0x0f, 0x23, -+ -+ 0xfe, 0x00, -+ 0x01, 0x22, -+ 0x02, 0xCC, -+ 0x0f, 0x02, -+ 0xe2, 0x00, -+ 0xe3, 0x7D, -+ 0xe4, 0x01, -+ 0xe5, 0xF4, -+ 0xe6, 0x02, -+ 0xe7, 0xEE, -+ 0xe8, 0x05, -+ 0xe9, 0xDC, -+ 0xea, 0x0C, -+ 0xeb, 0x35, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QVGA_MODE_TAB[] = -+{ -+ //1/2 subsample 320x240 -+ 0x26, 0x02, -+ 0x10, 0x26, -+ -+ 0x05, 0x00, //row_start -+ 0x06, 0x00, -+ 0x07, 0x00, //col start -+ 0x08, 0x00, -+ -+ 0x09, 0x01, //win height 488 -+ 0x0A, 0xe8, -+ 0x0B, 0x02, //win width 648 -+ 0x0c, 0x88, -+ -+ 0x91, 0x3c, //LSC row center -+ 0x92, 0x50, //LSC colum center -+ -+ 0xf7, 0x12, //big_win_x0,x4 -+ 0xf8, 0x0a, //big_win_y0 -+ 0xf9, 0x9f, //big_win_x1 -+ 0xfa, 0x78, //big_win_y1 -+ -+ 0xfe, 0x01, -+ //GC0309_Set_SubsampleRatio(GC_1_2_SUBSAMPLE_RATIO); // 1/2 subsample -+ 0x54, 0x22, -+ 0x55, 0x03, -+ 0x56, 0x00, -+ 0x57, 0x00, -+ 0x58, 0x00, -+ 0x59, 0x00, -+ -+ 0x0e, 0x44, -+ 0x0f, 0x32, -+ -+ 0xfe, 0x00, -+ 0x01, 0x6a, -+ 0x02, 0x70, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0x96, -+ 0xe4, 0x02, -+ 0xe5, 0x58, -+ 0xe6, 0x02, -+ 0xe7, 0x58, -+ 0xe8, 0x02, -+ 0xe9, 0x58, -+ 0xea, 0x02, -+ 0xeb, 0x58, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QCIF_MODE_TAB[] = -+{ -+ //windowing 352x288 -> 1/2 subsample 176x144 -+ 0x26, 0x02, -+ 0x10, 0x26, -+ -+ 0x05, 0x00, //row_start -+ 0x06, 0x60, -+ 0x07, 0x00, //col start -+ 0x08, 0x90, -+ 0x09, 0x01, //win height 296 -+ 0x0A, 0x28, -+ 0x0B, 0x01, //win width 360 -+ 0x0c, 0x68, -+ -+ 0x91, 0x25, //LSC row center -+ 0x92, 0x31, //LSC colum center -+ -+ 0xf7, 0x01, //big_win_x0,x4 -+ 0xf8, 0x01, //big_win_y0 -+ 0xf9, 0x58, //big_win_x1 -+ 0xfa, 0x48, //big_win_y1 -+ -+ 0xfe, 0x01, -+ //GC0309_Set_SubsampleRatio(GC_1_2_SUBSAMPLE_RATIO); // 1/2 subsample -+ 0x54, 0x22, -+ 0x55, 0x03, -+ 0x56, 0x00, -+ 0x57, 0x00, -+ 0x58, 0x00, -+ 0x59, 0x00, -+ -+ 0x0e, 0x2b, -+ 0x0f, 0x23, -+ -+ 0xfe, 0x00, -+ 0x01, 0x22, -+ 0x02, 0xCC, -+ 0x0f, 0x02, -+ 0xe2, 0x00, -+ 0xe3, 0x7D, -+ 0xe4, 0x01, -+ 0xe5, 0xF4, -+ 0xe6, 0x02, -+ 0xe7, 0xEE, -+ 0xe8, 0x05, -+ 0xe9, 0xDC, -+ 0xea, 0x0C, -+ 0xeb, 0x35, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QQVGA_MODE_TAB[] = -+{ -+ //1/4 subsample 160x120 -+ 0x26, 0x02, -+ 0x10, 0x26, -+ -+ 0x05, 0x00, //row_start -+ 0x06, 0x00, -+ 0x07, 0x00, //col start -+ 0x08, 0x00, -+ -+ 0x09, 0x01, //win height 488 -+ 0x0A, 0xe8, -+ 0x0B, 0x02, //win width 648 -+ 0x0c, 0x88, -+ -+ 0x91, 0x3c, //LSC row center -+ 0x92, 0x50, //LSC colum center -+ -+ 0xf7, 0x12, //big_win_x0,x4 -+ 0xf8, 0x0a, //big_win_y0 -+ 0xf9, 0x9f, //big_win_x1 -+ 0xfa, 0x78, //big_win_y1 -+ -+ 0xfe, 0x01, -+ //GC0309_Set_SubsampleRatio(GC_1_4_SUBSAMPLE_RATIO); // 1/4 subsample -+ 0x54, 0x44, -+ 0x55, 0x03, -+ 0x56, 0x00, -+ 0x57, 0x00, -+ 0x58, 0x00, -+ 0x59, 0x00, -+ -+ 0x0e, 0x44, -+ 0x0f, 0x32, -+ -+ 0xfe, 0x00, -+ 0x01, 0x6a, -+ 0x02, 0x70, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0x96, -+ 0xe4, 0x02, -+ 0xe5, 0x58, -+ 0xe6, 0x03, -+ 0xe7, 0x84, -+ 0xe8, 0x07, -+ 0xe9, 0x08, -+ 0xea, 0x0d, -+ 0xeb, 0x7a, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 PREV_MODE_TAB[] = -+{ -+ 0x26, 0x02, -+ 0x10, 0x26, -+ -+ 0x05, 0x00, // row_start_high -+ 0x06, 0x00, // row_start_low -+ 0x07, 0x00, // col_start_high -+ 0x08, 0x00, // col_start_low -+ 0x09, 0x01, //[8]cis_win_height 488 -+ 0x0a, 0xe8, //[7:0]cis_win_height -+ 0x0b, 0x02, //[9:8]cis_win_width 648 -+ 0x0c, 0x88, //[7:0]cis_win_width -+ -+ 0x91, 0x3c, //[7]singed4 [6:0]row_cneter -+ 0x92, 0x50, //col_center -+ -+ 0xf7, 0x12, //big_win_x0,x4 -+ 0xf8, 0x0a, //big_win_y0 -+ 0xf9, 0x9f, //big_win_x1 -+ 0xfa, 0x78, //big_win_y1 -+ -+ 0xfe, 0x01, -+ //GC0309_Set_SubsampleRatio(GC_1_2_SUBSAMPLE_RATIO); // 1/1 subsample -+ 0x54, 0x11, -+ 0x55, 0x03, -+ 0x56, 0x00, -+ 0x57, 0x00, -+ 0x58, 0x00, -+ 0x59, 0x00, -+ -+ 0x0e, 0x44, -+ 0x0f, 0x32, -+ -+ 0xfe, 0x00, -+ 0x01, 0x6a, //24M guding 25fps -+ 0x02, 0x70, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0x96, -+ 0xe4, 0x02, -+ 0xe5, 0x58, -+ 0xe6, 0x02, -+ 0xe7, 0x58, -+ 0xe8, 0x02, -+ 0xe9, 0x58, -+ 0xea, 0x0e, -+ 0xeb, 0xa6, -+ END_FLAG, END_FLAG -+}; -+ -+ -+static const T_U8 RECORD_MODE_TAB[] = -+{ -+ 0x26, 0x02, -+ 0x10, 0x26, -+ -+ 0x05, 0x00, // row_start_high -+ 0x06, 0x00, // row_start_low -+ 0x07, 0x00, // col_start_high -+ 0x08, 0x00, // col_start_low -+ 0x09, 0x01, //[8]cis_win_height 488 -+ 0x0a, 0xe8, //[7:0]cis_win_height -+ 0x0b, 0x02, //[9:8]cis_win_width 648 -+ 0x0c, 0x88, //[7:0]cis_win_width -+ -+ 0x91, 0x3c, //[7]singed4 [6:0]row_cneter -+ 0x92, 0x50, //col_center -+ -+ 0xf7, 0x12, //big_win_x0,x4 -+ 0xf8, 0x0a, //big_win_y0 -+ 0xf9, 0x9f, //big_win_x1 -+ 0xfa, 0x78, //big_win_y1 -+ -+ 0xfe, 0x01, -+ //GC0309_Set_SubsampleRatio(GC_1_2_SUBSAMPLE_RATIO); // 1/1 subsample -+ 0x54, 0x11, -+ 0x55, 0x03, -+ 0x56, 0x00, -+ 0x57, 0x00, -+ 0x58, 0x00, -+ 0x59, 0x00, -+ -+ 0x0e, 0x44, -+ 0x0f, 0x32, -+ -+ 0xfe, 0x00, -+ 0x01, 0x6a, //24M guding 25fps -+ 0x02, 0x70, -+ 0x0f, 0x00, -+ 0xe2, 0x00, -+ 0xe3, 0x96, -+ 0xe4, 0x02, -+ 0xe5, 0x58, -+ 0xe6, 0x02, -+ 0xe7, 0x58, -+ 0xe8, 0x02, -+ 0xe9, 0x58, -+ 0xea, 0x0e, -+ 0xeb, 0xa6, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Exposure Table ****************/ -+static const T_U8 EXPOSURE_WHOLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_CENTER_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_MIDDLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Brightness Table ****************/ -+static const T_U8 BRIGHTNESS_0_TAB[] = -+{ -+ //0xb5, 0xd0, -+ //0xd3, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_1_TAB[] = -+{ -+ //0xb5, 0xe0, -+ //0xd3, 0x48, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_2_TAB[] = -+{ -+ //0xb5, 0xf0, -+ //0xd3, 0x50, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_3_TAB[] = -+{ -+ //0xb5, 0x00, -+ //0xd3, 0x58, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_4_TAB[] = -+{ -+ //0xb5, 0x10, -+ //0xd3, 0x60, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_5_TAB[] = -+{ -+ //0xb5, 0x20, -+ //0xd3, 0x68, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_6_TAB[] = -+{ -+ //0xb5, 0x30, -+ //0xd3, 0x70, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Contrast Table ****************/ -+static const T_U8 CONTRAST_1_TAB[] = -+{ -+ //0xb3, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_2_TAB[] = -+{ -+ //0xb3, 0x50, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_3_TAB[] = -+{ -+ //0xb3, 0x60, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_4_TAB[] = -+{ -+ //0xb3, 0x70, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_5_TAB[] = -+{ -+ //0xb3, 0x80, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_6_TAB[] = -+{ -+ //0xb3, 0x90, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_7_TAB[] = -+{ -+ //0xb3, 0xa0, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Saturation Table ****************/ -+static const T_U8 SATURATION_1_TAB[] = -+{ -+ //0xb1, 0x40, -+ //0xb2, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_2_TAB[] = -+{ -+ //0xb1, 0x48, -+ //0xb2, 0x48, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_3_TAB[] = -+{ -+ //0xb1, 0x50, -+ //0xb2, 0x50, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_4_TAB[] = -+{ -+ //0xb1, 0x58, -+ //0xb2, 0x58, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_5_TAB[] = -+{ -+ //0xb1, 0x60, -+ //0xb2, 0x60, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Sharpness Table ****************/ -+static const T_U8 SHARPNESS_0_TAB[] = -+{ -+ 0x77, 0x11, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_1_TAB[] = -+{ -+ 0x77, 0x33, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_2_TAB[] = -+{ -+ 0x77, 0x55, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_3_TAB[] = -+{ -+ 0x77, 0x77, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_4_TAB[] = -+{ -+ 0x77, 0x99, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_5_TAB[] = -+{ -+ 0x77, 0xbb, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_6_TAB[] = -+{ -+ 0x77, 0xdd, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera AWB Table ****************/ -+static const T_U8 AWB_AUTO_TAB[] = -+{ -+ 0x5a, 0x56, -+ 0x5b, 0x40, -+ 0x5c, 0x4a, -+ 0x22, 0x57, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_SUNNY_TAB[] = -+{ -+ 0x22, 0x55, -+ 0x5a, 0x74, -+ 0x5b, 0x52, -+ 0x5c, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_CLOUDY_TAB[] = -+{ -+ 0x22, 0x55, -+ 0x5a, 0x8c, -+ 0x5b, 0x50, -+ 0x5c, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_OFFICE_TAB[] = -+{ -+ 0x22, 0x55, -+ 0x5a, 0x40, -+ 0x5b, 0x42, -+ 0x5c, 0x50, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_HOME_TAB[] = -+{ -+ 0x22, 0x55, -+ 0x5a, 0x48, -+ 0x5b, 0x40, -+ 0x5c, 0x5c, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_NIGHT_TAB[] = -+{ -+ 0x22, 0x55, -+ 0x5a, 0x40, -+ 0x5b, 0x54, -+ 0x5c, 0x70, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Effect Table ****************/ -+static const T_U8 EFFECT_NORMAL_TAB[] = -+{ -+ 0x23, 0x00, -+ 0x2d, 0x0a, -+ 0x20, 0xff, -+ 0xd2, 0x90, -+ 0x73, 0x00, -+ 0x77, 0x54, -+ -+ 0xb3, 0x40, -+ 0xb4, 0x80, -+ 0xba, 0x00, -+ 0xbb, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_SEPIA_TAB[] = -+{ -+ 0x23, 0x02, -+ 0x2d, 0x0a, -+ 0x20, 0xff, -+ 0xd2, 0x90, -+ 0x73, 0x00, -+ -+ 0xb3, 0x40, -+ 0xb4, 0x80, -+ 0xba, 0xd0, -+ 0xbb, 0x28, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_ANTIQUE_TAB[] = -+{ -+ 0x23, 0x01, -+ 0x2d, 0x0a, -+ 0x20, 0xff, -+ 0xd2, 0x90, -+ 0x73, 0x00, -+ -+ 0xb3, 0x40, -+ 0xb4, 0x80, -+ 0xba, 0x00, -+ 0xbb, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BLUISH_TAB[] = -+{ -+ 0x23, 0x02, -+ 0x2d, 0x0a, -+ 0x20, 0xff, -+ 0xd2, 0x90, -+ 0x73, 0x00, -+ -+ 0xb3, 0x40, -+ 0xb4, 0x80, -+ 0xba, 0x50, -+ 0xbb, 0xe0, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_GREENISH_TAB[] = -+{ -+ 0x23, 0x02, -+ 0x2d, 0x0a, -+ 0x20, 0xff, -+ 0xd2, 0x90, -+ 0x77, 0x88, -+ -+ 0xb3, 0x40, -+ 0xb4, 0x80, -+ 0xba, 0xc0, -+ 0xbb, 0xc0, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_NEGATIVE_TAB[] = -+{ -+ 0x23, 0x03, -+ 0x2d, 0x0a, -+ 0x20, 0xff, -+ 0xd2, 0x90, -+ 0x73, 0x00, -+ -+ 0xb3, 0x40, -+ 0xb4, 0x80, -+ 0xba, 0x00, -+ 0xbb, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BW_TAB[] = -+{ -+ 0x23, 0x02, -+ 0x2d, 0x0a, -+ 0x20, 0xbf, -+ 0xd2, 0x10, -+ 0x73, 0x01, -+ -+ 0x51, 0x40, -+ 0x52, 0x40, -+ 0xb3, 0x60, -+ 0xb4, 0x40, -+ 0xba, 0x00, -+ 0xbb, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BWN_TAB[] = -+{ -+ 0x23, 0x02, -+ 0x2d, 0x0a, -+ 0x20, 0xbf, -+ 0xd2, 0x10, -+ 0x73, 0x01, -+ -+ 0x51, 0x40, -+ 0x52, 0x40, -+ 0xb3, 0x98, -+ 0xb4, 0xb0, -+ 0xba, 0x00, -+ 0xbb, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera night/day mode ****************/ -+static const T_U8 DAY_MODE_TAB[] = -+{ -+ 0xec, 0x20, -+ 0x20, 0xff, -+ 0x3c, 0x02, -+ 0x3d, 0x02, -+ 0x3e, 0x02, -+ 0x3f, 0x02, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 NIGHT_MODE_TAB[] = -+{ -+ 0xec, 0x30, -+ 0x20, 0x5f, -+ 0x3c, 0x08, -+ 0x3d, 0x08, -+ 0x3e, 0x08, -+ 0x3f, 0x08, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Mirror Table ****************/ -+static const T_U8 MIRROR_V_TAB[] = -+{ -+ //flip -+ 0xfe, 0x00,//page0 -+ 0x14, 0x12, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 MIRROR_H_TAB[] = -+{ -+ //mirror -+ 0xfe, 0x00,//page0 -+ 0x14, 0x11, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 MIRROR_NORMAL_TAB[] = -+{ -+ //no mirror/flip -+ 0xfe, 0x00,//page0 -+ 0x14, 0x10,//0x13 180㷭ת -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 MIRROR_FLIP_TAB[] = -+{ -+ //flip/mirror -+ 0xfe, 0x00,//page0 -+ 0x14, 0x13, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera anti-flicker mode ****************/ -+static const T_U8 ANTI_FLICKER_DISABLE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 ANTI_FLICKER_50HZ_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 ANTI_FLICKER_60HZ_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 ANTI_FLICKER_AUTO_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+#endif -+#endif -+ -diff --git a/drivers/media/video/plat-anyka/camera_hm1375.c b/drivers/media/video/plat-anyka/camera_hm1375.c -new file mode 100755 -index 00000000..72a9e2a7 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_hm1375.c -@@ -0,0 +1,1051 @@ -+/** -+ * @file camera_hm1375.c -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-09-21 -+ * @version 1.0 -+ * @ref -+ */ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/cam_com_sensor.h> -+#include "camera_hm1375.h" -+#else -+#include "akdefine.h" -+#include "cam_com_sensor.h" -+#include "camera_hm1375.h" -+#include "Gpio_config.h" -+#endif -+ -+#if defined (USE_CAMERA_HM1375) || defined (CONFIG_SENSOR_HM1375) -+ -+#define CAM_EN_LEVEL 0 -+#define CAM_RESET_LEVEL 0 -+ -+#define CAMERA_SCCB_ADDR 0x48 -+ -+#define CAMERA_HM1375_ID 0x0375 -+ -+#define HM1375_CAMERA_MCLK 24 -+ -+static T_CAMERA_TYPE camera_hm1375_type = CAMERA_2M; -+static T_NIGHT_MODE night_mode = CAMERA_DAY_MODE; -+static T_CAMERA_MODE s_hm1375_CurMode = CAMERA_MODE_VGA; -+ -+#if 0 -+static T_VOID camera_setbit(T_U16 reg, T_U8 bit, T_U8 value) -+{ -+ T_U8 tmp; -+ -+ tmp = sccb_read_short(CAMERA_SCCB_ADDR, reg); -+ if (value == 1) -+ { -+ tmp |= 0x1 << bit; -+ } -+ else -+ { -+ tmp &= ~(0x1 << bit); -+ } -+ -+ sccb_write_short(CAMERA_SCCB_ADDR, reg, &tmp, 1); -+} -+#endif -+static T_U32 cam_hm1375_read_id(T_VOID); -+ -+static T_BOOL camera_set_param(const T_U16 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 temp_value; -+ T_U8 data; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ data = tabParameter[i + 1]; -+ sccb_write_short(CAMERA_SCCB_ADDR, tabParameter[i], &data, 1); -+ -+ if ((tabParameter[i] != 0x0000) || (tabParameter[i] != 0x0022) -+ || (tabParameter[i] != 0x0100) || (tabParameter[i] != 0x0101)) -+ { -+ temp_value = sccb_read_short(CAMERA_SCCB_ADDR, tabParameter[i]); -+ if (temp_value != tabParameter[i + 1]) -+ { -+ akprintf(C1, M_DRVSYS, "set parameter error!\n"); -+ akprintf(C1, M_DRVSYS, "reg 0x%x write data is 0x%x, read data is 0x%x!\n", tabParameter[i], tabParameter[i + 1], temp_value); -+ -+ return AK_FALSE; -+ } -+ } -+ } -+ -+ i += 2; -+ } -+ -+ return AK_TRUE; -+} -+ -+static T_VOID camera_setup(const T_U16 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 data; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ data = tabParameter[i + 1]; -+ sccb_write_short(CAMERA_SCCB_ADDR, tabParameter[i], &data, 1); -+ } -+ i += 2; -+ } -+ -+} -+ -+static T_VOID cam_hm1375_open(T_VOID) -+{ -+ gpio_set_pin_dir(GPIO_CAMERA_AVDD, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_CHIP_ENABLE); -+ gpio_set_pin_dir(GPIO_CAMERA_CHIP_ENABLE, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, CAM_EN_LEVEL); -+ mini_delay(10); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_RESET); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, CAM_RESET_LEVEL); -+ mini_delay(10); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, !CAM_RESET_LEVEL); -+ -+ mini_delay(20); -+} -+ -+static T_BOOL cam_hm1375_close(T_VOID) -+{ -+ //sccb software standby mode -+// T_U8 Reg0x3d = 0x48; -+// T_U8 Reg0xc3 = 0x00; -+ -+// sccb_write_short(CAMERA_SCCB_ADDR, 0x3d, &Reg0x3d, 1); -+// sccb_write_short(CAMERA_SCCB_ADDR, 0xc3, &Reg0xc3, 1); -+ -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, !CAM_EN_LEVEL); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, !gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_INPUT); -+ -+ gpio_set_pin_dir(GPIO_I2C_SCL, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SCL, GPIO_LEVEL_LOW); -+ gpio_set_pin_dir(GPIO_I2C_SDA, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SDA, GPIO_LEVEL_LOW); -+ -+ return AK_TRUE; -+} -+ -+static T_U32 cam_hm1375_read_id(T_VOID) -+{ -+ T_U8 value = 0x00; -+ T_U32 id = 0; -+ -+ sccb_init(GPIO_I2C_SCL, GPIO_I2C_SDA); //init sccb first here!! -+ -+ value = sccb_read_short(CAMERA_SCCB_ADDR, 0x0001); -+ id = value << 8; -+ value = sccb_read_short(CAMERA_SCCB_ADDR, 0x0002); -+ id |= value; -+ -+ return id; -+} -+ -+/** -+ * @brief initialize the parameters of camera, should be done after reset and open camera to initialize -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @return T_BOOL -+ * @retval AK_TRUE if success, else AK_FALSE -+ */ -+static T_BOOL cam_hm1375_init(void) -+{ -+ if (!camera_set_param(INIT_TAB)) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ night_mode = CAMERA_DAY_MODE; -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief Set camera mode to specify image quality, SXGA/VGA/CIF etc -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mode mode value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_mode(T_CAMERA_MODE mode) -+{ -+ s_hm1375_CurMode = mode; -+ switch(mode) -+ { -+ case CAMERA_MODE_UXGA: -+ camera_setup(UXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_SXGA: -+ camera_setup(SXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_VGA: -+ camera_setup(VGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_CIF: -+ camera_setup(CIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QVGA: -+ camera_setup(QVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_QCIF: -+ camera_setup(QCIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QQVGA: -+ camera_setup(QQVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_PREV: -+ camera_setup(PREV_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_REC: -+ camera_setup(RECORD_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_720P: -+ camera_setup(RECORD_720P_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ default: -+ s_hm1375_CurMode = CAMERA_MODE_VGA; -+ akprintf(C1, M_DRVSYS, "set camera mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera exposure mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] exposure exposure mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_exposure(T_CAMERA_EXPOSURE exposure) -+{ -+ switch(exposure) -+ { -+ case EXPOSURE_WHOLE: -+ camera_setup(EXPOSURE_WHOLE_TAB); -+ break; -+ case EXPOSURE_CENTER: -+ camera_setup(EXPOSURE_CENTER_TAB); -+ break; -+ case EXPOSURE_MIDDLE: -+ camera_setup(EXPOSURE_MIDDLE_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set exposure parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera brightness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] brightness brightness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_brightness(T_CAMERA_BRIGHTNESS brightness) -+{ -+ switch(brightness) -+ { -+ case CAMERA_BRIGHTNESS_0: -+ camera_setup(BRIGHTNESS_0_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_1: -+ camera_setup(BRIGHTNESS_1_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_2: -+ camera_setup(BRIGHTNESS_2_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_3: -+ camera_setup(BRIGHTNESS_3_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_4: -+ camera_setup(BRIGHTNESS_4_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_5: -+ camera_setup(BRIGHTNESS_5_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_6: -+ camera_setup(BRIGHTNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set brightness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera contrast level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] contrast contrast value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_contrast(T_CAMERA_CONTRAST contrast) -+{ -+ switch(contrast) -+ { -+ case CAMERA_CONTRAST_1: -+ camera_setup(CONTRAST_1_TAB); -+ break; -+ case CAMERA_CONTRAST_2: -+ camera_setup(CONTRAST_2_TAB); -+ break; -+ case CAMERA_CONTRAST_3: -+ camera_setup(CONTRAST_3_TAB); -+ break; -+ case CAMERA_CONTRAST_4: -+ camera_setup(CONTRAST_4_TAB); -+ break; -+ case CAMERA_CONTRAST_5: -+ camera_setup(CONTRAST_5_TAB); -+ break; -+ case CAMERA_CONTRAST_6: -+ camera_setup(CONTRAST_6_TAB); -+ break; -+ case CAMERA_CONTRAST_7: -+ camera_setup(CONTRAST_7_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set contrast parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera saturation level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] saturation saturation value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_saturation(T_CAMERA_SATURATION saturation) -+{ -+ switch(saturation) -+ { -+ case CAMERA_SATURATION_0: -+ camera_setup(SATURATION_0_TAB); -+ break; -+ case CAMERA_SATURATION_1: -+ camera_setup(SATURATION_1_TAB); -+ break; -+ case CAMERA_SATURATION_2: -+ camera_setup(SATURATION_2_TAB); -+ break; -+ case CAMERA_SATURATION_3: -+ camera_setup(SATURATION_3_TAB); -+ break; -+ case CAMERA_SATURATION_4: -+ camera_setup(SATURATION_4_TAB); -+ break; -+ case CAMERA_SATURATION_5: -+ camera_setup(SATURATION_5_TAB); -+ break; -+ case CAMERA_SATURATION_6: -+ camera_setup(SATURATION_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set saturation parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera sharpness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] sharpness sharpness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_sharpness(T_CAMERA_SHARPNESS sharpness) -+{ -+ switch(sharpness) -+ { -+ case CAMERA_SHARPNESS_0: -+ camera_setup(SHARPNESS_0_TAB); -+ break; -+ case CAMERA_SHARPNESS_1: -+ camera_setup(SHARPNESS_1_TAB); -+ break; -+ case CAMERA_SHARPNESS_2: -+ camera_setup(SHARPNESS_2_TAB); -+ break; -+ case CAMERA_SHARPNESS_3: -+ camera_setup(SHARPNESS_3_TAB); -+ break; -+ case CAMERA_SHARPNESS_4: -+ camera_setup(SHARPNESS_4_TAB); -+ break; -+ case CAMERA_SHARPNESS_5: -+ camera_setup(SHARPNESS_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set sharpness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera AWB mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] awb AWB mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_AWB(T_CAMERA_AWB awb) -+{ -+ switch(awb) -+ { -+ case AWB_AUTO: -+ camera_setup(AWB_AUTO_TAB); -+ break; -+ case AWB_SUNNY: -+ camera_setup(AWB_SUNNY_TAB); -+ break; -+ case AWB_CLOUDY: -+ camera_setup(AWB_CLOUDY_TAB); -+ break; -+ case AWB_OFFICE: -+ camera_setup(AWB_OFFICE_TAB); -+ break; -+ case AWB_HOME: -+ camera_setup(AWB_HOME_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set AWB mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera mirror mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mirror mirror mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_mirror(T_CAMERA_MIRROR mirror) -+{ -+ switch(mirror) -+ { -+ case CAMERA_MIRROR_V: -+ break; -+ case CAMERA_MIRROR_H: -+ break; -+ case CAMERA_MIRROR_NORMAL: -+ break; -+ case CAMERA_MIRROR_FLIP: -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set mirror parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera effect mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] effect effect mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_hm1375_set_effect(T_CAMERA_EFFECT effect) -+{ -+ switch(effect) -+ { -+ case CAMERA_EFFECT_NORMAL: -+ camera_setup(EFFECT_NORMAL_TAB); -+ break; -+ case CAMERA_EFFECT_SEPIA: -+ camera_setup(EFFECT_SEPIA_TAB); -+ break; -+ case CAMERA_EFFECT_ANTIQUE: -+ camera_setup(EFFECT_ANTIQUE_TAB); -+ break; -+ case CAMERA_EFFECT_BLUE: -+ camera_setup(EFFECT_BLUISH_TAB); -+ break; -+ case CAMERA_EFFECT_GREEN: -+ camera_setup(EFFECT_GREENISH_TAB); -+ break; -+ case CAMERA_EFFECT_RED: -+ camera_setup(EFFECT_REDDISH_TAB); -+ break; -+ case CAMERA_EFFECT_NEGATIVE: -+ camera_setup(EFFECT_NEGATIVE_TAB); -+ break; -+ case CAMERA_EFFECT_BW: -+ camera_setup(EFFECT_BW_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set camer effect parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief set camera window -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] srcWidth window width -+ * @param[in] srcHeight window height -+ * @return T_S32 -+ * @retval 0 if error mode -+ * @retval 1 if success -+ * @retval -1 if failed -+ */ -+static T_S32 cam_hm1375_set_digital_zoom(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ return 1; -+} -+ -+static T_VOID cam_hm1375_set_night_mode(T_NIGHT_MODE mode) -+{ -+ switch(mode) -+ { -+ case CAMERA_DAY_MODE: -+ camera_setup(DAY_MODE_TAB); -+ night_mode = CAMERA_DAY_MODE; -+ break; -+ case CAMERA_NIGHT_MODE: -+ camera_setup(NIGHT_MODE_TAB); -+ night_mode = CAMERA_NIGHT_MODE; -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set night mode parameter error!\n"); -+ break; -+ } -+} -+ -+static T_VOID cam_hm1375_set_anti_flicker(T_U32 value) -+{ -+ switch(value) { -+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: -+ //camera_setup(ANTI_FLICKER_DISABLE_TAB); -+ akprintf(C1, M_DRVSYS, "Anti-flicker not support 'Disable', Error." -+ " please select other frequency!\n"); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: -+ camera_setup(ANTI_FLICKER_50HZ_TAB); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: -+ camera_setup(ANTI_FLICKER_60HZ_TAB); -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: -+ //camera_setup(ANTI_FLICKER_AUTO_TAB); -+ akprintf(C1, M_DRVSYS, "Anti-flicker not support 'Auto', Error." -+ " please select other frequency!\n"); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set Anti-flicker parameter error!\n"); -+ break; -+ } -+} -+ -+static T_BOOL cam_hm1375_set_to_cap(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_VGA; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 1024)) -+ { -+ Cammode = CAMERA_MODE_SXGA; -+ } -+ else if ((srcWidth <= 1600) && (srcHeight <= 1200)) -+ { -+ Cammode = CAMERA_MODE_UXGA; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "hm1375 unsupport %d & %d mode!\n", srcWidth, srcHeight); -+ return AK_FALSE; -+ } -+ -+ cam_hm1375_set_mode(Cammode); -+ cam_hm1375_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_hm1375_set_to_prev(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_hm1375_set_mode(CAMERA_MODE_PREV); -+ cam_hm1375_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_hm1375_set_to_record(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_REC; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "200W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_hm1375_set_mode(Cammode); -+ cam_hm1375_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_CAMERA_TYPE cam_hm1375_get_type(T_VOID) -+{ -+ return camera_hm1375_type; -+} -+ -+static T_VOID cam_hm1375_set_sensor_param(T_U32 cmd, T_U32 data) -+{ -+ T_U8 value; -+ -+ value = (T_U8)data; -+ sccb_write_short(CAMERA_SCCB_ADDR, (T_U16)cmd, &value, 1); -+} -+ -+static T_CAMERA_FUNCTION_HANDLER hm1375_function_handler = -+{ -+ HM1375_CAMERA_MCLK, -+ cam_hm1375_open, -+ cam_hm1375_close, -+ cam_hm1375_read_id, -+ cam_hm1375_init, -+ cam_hm1375_set_mode, -+ cam_hm1375_set_exposure, -+ cam_hm1375_set_brightness, -+ cam_hm1375_set_contrast, -+ cam_hm1375_set_saturation, -+ cam_hm1375_set_sharpness, -+ cam_hm1375_set_AWB, -+ cam_hm1375_set_mirror, -+ cam_hm1375_set_effect, -+ cam_hm1375_set_digital_zoom, -+ cam_hm1375_set_night_mode, -+ AK_NULL, -+ cam_hm1375_set_anti_flicker, -+ cam_hm1375_set_to_cap, -+ cam_hm1375_set_to_prev, -+ cam_hm1375_set_to_record, -+ cam_hm1375_get_type, -+ cam_hm1375_set_sensor_param -+}; -+ -+#ifndef CONFIG_LINUX_AKSENSOR -+static int camera_hm1375_reg(void) -+{ -+ camera_reg_dev(CAMERA_HM1375_ID, &hm1375_function_handler); -+ return 0; -+} -+ -+#ifdef __CC_ARM -+#pragma arm section rwdata = "__initcall_", zidata = "__initcall_" -+#endif -+module_init(camera_hm1375_reg) -+#ifdef __CC_ARM -+#pragma arm section -+#endif -+ -+#else -+static const char * awb_menu[] = { -+ [AWB_AUTO] = "auto", -+ [AWB_SUNNY] = "sunny", -+ [AWB_CLOUDY] = "cloudy", -+ [AWB_OFFICE] = "office", -+ [AWB_HOME] = "home", -+ [AWB_NIGHT] = "night", -+}; -+ -+static const char * effect_menu[] = { -+ [CAMERA_EFFECT_NORMAL] = "normal", -+ [CAMERA_EFFECT_SEPIA] = "sepia", -+ [CAMERA_EFFECT_ANTIQUE] = "antique", -+ [CAMERA_EFFECT_BLUE] = "blue", -+ [CAMERA_EFFECT_GREEN] = "green", -+ [CAMERA_EFFECT_RED] = "red", -+ [CAMERA_EFFECT_NEGATIVE] = "negative", -+ [CAMERA_EFFECT_BW] = "bw", -+ [CAMERA_EFFECT_BWN] = "bwn", -+ [CAMERA_EFFECT_AQUA] = "aqua", -+ [CAMERA_EFFECT_COOL] = "cool", -+ [CAMERA_EFFECT_WARM] = "warm", -+}; -+ -+static const char * resolution_menu[] = { -+ [0] = "1280x960", -+ [1] = "1280x800", -+ [2] = "1280x720", -+ [3] = "640x480", -+}; -+ -+static const char * hflip_menu[] = { -+ [0] = "normal", -+ [1] = "horizontal flip", -+}; -+ -+static const char * vflip_menu[] = { -+ [0] = "normal", -+ [1] = "vertical flip", -+}; -+ -+static const char * night_menu[] = { -+ [CAMERA_DAY_MODE] = "daylight", -+ [CAMERA_NIGHT_MODE] = "night", -+}; -+ -+static const char * anti_flicker_menu[] = { -+ [V4L2_CID_POWER_LINE_FREQUENCY_DISABLED] = "Disable", -+ [V4L2_CID_POWER_LINE_FREQUENCY_50HZ] = "50Hz", -+ [V4L2_CID_POWER_LINE_FREQUENCY_60HZ] = "60Hz", -+ [V4L2_CID_POWER_LINE_FREQUENCY_AUTO] = "Auto", -+}; -+ -+static int hm1375_s_ctl(struct v4l2_ctrl *ctrl) -+{ -+ int ret = -EINVAL; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ if (hm1375_function_handler.cam_set_AWB_func) { -+ hm1375_function_handler.cam_set_AWB_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_COLORFX: -+ if (hm1375_function_handler.cam_set_effect_func) { -+ hm1375_function_handler.cam_set_effect_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ -+ case V4L2_CID_BRIGHTNESS: -+ if (hm1375_function_handler.cam_set_brightness_func) { -+ hm1375_function_handler.cam_set_brightness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_CONTRAST: -+ if (hm1375_function_handler.cam_set_contrast_func) { -+ hm1375_function_handler.cam_set_contrast_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SATURATION: -+ if (hm1375_function_handler.cam_set_saturation_func) { -+ hm1375_function_handler.cam_set_saturation_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SHARPNESS: -+ if (hm1375_function_handler.cam_set_sharpness_func) { -+ hm1375_function_handler.cam_set_sharpness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_HFLIP: -+ if (hm1375_function_handler.cam_set_mirror_func) { -+ hm1375_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_H : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_VFLIP: -+ if (hm1375_function_handler.cam_set_mirror_func) { -+ hm1375_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_V : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_NIGHTMODE: -+ if (hm1375_function_handler.cam_set_night_mode_func) { -+ hm1375_function_handler.cam_set_night_mode_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_POWER_LINE_FREQUENCY: -+ if (hm1375_function_handler.cam_set_anti_flicker_func) { -+ hm1375_function_handler.cam_set_anti_flicker_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+}; -+ -+static struct v4l2_ctrl_ops hm1375_ctrl_ops = { -+ .s_ctrl = hm1375_s_ctl, -+}; -+ -+static const struct v4l2_ctrl_config hm1375_ctrls[] = { -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_AUTO_WHITE_BALANCE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "AWB", -+ .min = 0, -+ .max = ARRAY_SIZE(awb_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = awb_menu, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_COLORFX, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Effect", -+ .min = 0, -+ .max = ARRAY_SIZE(effect_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = effect_menu, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Horizontal Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(hflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = hflip_menu, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Vetical Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(vflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = vflip_menu, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_PICTURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Resolution", -+ .min = 0, -+ .max = ARRAY_SIZE(resolution_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = resolution_menu, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_NIGHTMODE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Night mode", -+ .min = 0, -+ .max = ARRAY_SIZE(night_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = night_menu, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_BRIGHTNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Brightness", -+ .min = 0, -+ .max = CAMERA_BRIGHTNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .min = 0, -+ .max = CAMERA_CONTRAST_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .min = 0, -+ .max = CAMERA_SATURATION_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_SHARPNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Sharpness", -+ .min = 0, -+ .max = CAMERA_SHARPNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &hm1375_ctrl_ops, -+ .id = V4L2_CID_POWER_LINE_FREQUENCY, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "anti flicker", -+ .min = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, -+ .max = V4L2_CID_POWER_LINE_FREQUENCY_AUTO, -+ .step = 0, -+ .def = V4L2_CID_POWER_LINE_FREQUENCY_50HZ, -+ .flags = 0, -+ .menu_skip_mask = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, -+ .qmenu = anti_flicker_menu, -+ } -+}; -+ -+ -+/* -+ * supported format list -+ */ -+static const struct aksensor_color_format hm1375_formats[] = { -+ { -+ .code = V4L2_MBUS_FMT_YUYV8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_YVYU8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_UYVY8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+}; -+ -+static const struct aksensor_win_size hm1375_win[] = { -+ {.name = "VGA", .width = 640, .height = 480}, -+ {.name = "720P", .width = 1280, .height = 720}, -+ {.name = "800P", .width = 1280, .height = 800}, -+ {.name = "960P", .width = 1280, .height = 960}, -+}; -+ -+static struct sensor_info hm1375_sensor_info = { -+ .sensor_name = "hm1375", -+ .sensor_id = CAMERA_HM1375_ID, -+ .ctrls = hm1375_ctrls, -+ .nr_ctrls = ARRAY_SIZE(hm1375_ctrls), -+ .formats = hm1375_formats, -+ .num_formats = ARRAY_SIZE(hm1375_formats), -+ .resolution = hm1375_win, -+ .num_resolution = ARRAY_SIZE(hm1375_win), -+ .handler = &hm1375_function_handler, -+}; -+ -+static int hm1375_module_init(void) -+{ -+ return register_sensor(&hm1375_sensor_info); -+} -+module_init(hm1375_module_init) -+#endif -+ -+#endif -+ -+ -diff --git a/drivers/media/video/plat-anyka/camera_hm1375.h b/drivers/media/video/plat-anyka/camera_hm1375.h -new file mode 100755 -index 00000000..10e47fc0 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_hm1375.h -@@ -0,0 +1,1537 @@ -+/** -+ * @file camera_hm1375.h -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author wudaochao -+ * @date 2013-04-26 -+ * @version 1.0 -+ * @ref -+ */ -+#ifndef __CAMERA_HM1375_H__ -+#define __CAMERA_HM1375_H__ -+ -+ -+#if defined (USE_CAMERA_HM1375) || defined (CONFIG_SENSOR_HM1375) -+ -+#undef DELAY_FLAG -+#undef END_FLAG -+#define DELAY_FLAG 0xfd // first parameter is 0xfe, then 2nd parameter is delay time count -+#define END_FLAG 0xfe // first parameter is 0xff, then parameter table is over -+ -+static const T_U16 INIT_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 UXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 VGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QVGA_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QCIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QQVGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 PREV_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 RECORD_MODE_TAB[] = -+{ -+ 0x0022, 0x00, -+ 0x000C, 0x04, -+ 0x0006, 0x0F,//��������װ���˵ģ�ҪVFLIP on,Mirror on -+ 0x000A, 0x20, -+ 0x000F, 0x10, -+ 0x0012, 0x01, -+ 0x0013, 0x02, -+ 0x0015, 0x01, -+ 0x0016, 0x00, -+ 0x0018, 0x00, -+ 0x001D, 0x40, -+ //0x0020, 0x10, -+ 0x0020, 0x50,//VSYNC: active low -+ 0x0023, 0x43, -+ 0x0024, 0x20, -+ 0x0025, 0x00, -+ 0x0026, 0x6F, -+ //0x0027, 0x30,//YUYV(YUV422) -+ 0x0027, 0x10, -+ 0x0028, 0x01, -+ 0x002E, 0x0E, -+ 0x0030, 0x00, -+ 0x0034, 0x0E, -+ 0x0035, 0x01, -+ 0x0036, 0x00, -+ 0x0038, 0x02, -+ 0x0039, 0x01, -+ 0x003A, 0x01, -+ 0x003B, 0xFF, -+ 0x003C, 0xFF, -+ 0x003D, 0x40, -+ 0x003F, 0x14, -+ 0x0040, 0x10, -+ 0x0044, 0x07, -+ 0x0045, 0x25, -+ 0x0048, 0x7F, -+ 0x004E, 0xFF, -+ 0x0070, 0x00, -+ 0x0071, 0x4F, -+ 0x0072, 0x00, -+ 0x0073, 0x30, -+ 0x0074, 0x13, -+ 0x0075, 0x40, -+ 0x0076, 0x24, -+ 0x0078, 0x0F, -+ 0x007A, 0x05, -+ 0x007B, 0xF2, -+ 0x007C, 0x10, -+ 0x0080, 0xC9, -+ 0x0081, 0x00, -+ 0x0082, 0x28, -+ 0x0083, 0xB0, -+ 0x0084, 0x70, -+ 0x0086, 0x3E, -+ 0x0087, 0x70, -+ 0x0088, 0x11, -+ 0x0089, 0x3C, -+ 0x008A, 0x87, -+ 0x008D, 0x64, -+ 0x0090, 0x07, -+ 0x0091, 0x09, -+ 0x0092, 0x0C, -+ 0x0093, 0x0C, -+ 0x0094, 0x0C, -+ 0x0095, 0x0C, -+ 0x0096, 0x01, -+ 0x0097, 0x00, -+ 0x0098, 0x04, -+ 0x0099, 0x08, -+ 0x009A, 0x0C, -+ 0x0120, 0x36, -+ 0x0121, 0x81, -+ 0x0122, 0xEB, -+ 0x0123, 0x29, -+ 0x0124, 0x50, -+ 0x0125, 0xDE, -+ 0x0126, 0xB1, -+ 0x013D, 0x0F, -+ 0x013E, 0x0F, -+ 0x013F, 0x0F, -+ 0x0140, 0x14, -+ 0x0141, 0x0A, -+ 0x0142, 0x14, -+ 0x0143, 0x0A, -+ 0x0144, 0x08, -+ 0x0145, 0x04, -+ 0x0146, 0x28, -+ 0x0147, 0x3C, -+ 0x0148, 0x28, -+ 0x0149, 0x3C, -+ 0x014A, 0x96, -+ 0x014B, 0xC8, -+ 0x0150, 0x14, -+ 0x0151, 0x30, -+ 0x0152, 0x54, -+ 0x0153, 0x70, -+ 0x0154, 0x14, -+ 0x0155, 0x30, -+ 0x0156, 0x54, -+ 0x0157, 0x70, -+ 0x0158, 0x14, -+ 0x0159, 0x30, -+ 0x015A, 0x54, -+ 0x015B, 0x70, -+ 0x015C, 0x30, -+ 0x015D, 0x00, -+ 0x01D8, 0x20, -+ 0x01D9, 0x08, -+ 0x01DA, 0x20, -+ 0x01DB, 0x08, -+ 0x01DC, 0x20, -+ 0x01DD, 0x08, -+ 0x01DE, 0x20, -+ 0x01DF, 0x08, -+ 0x01E0, 0x20, -+ 0x01E1, 0x08, -+ 0x01E2, 0xFF, -+ 0x01E3, 0x00, -+ 0x01E4, 0x10, -+ 0x01E5, 0x10, -+ 0x01E6, 0x02, -+ 0x01E7, 0x10, -+ 0x01E8, 0x10, -+ 0x01E9, 0x10, -+ 0x01EA, 0x10, -+ 0x01EC, 0xFA, -+ 0x01EB, 0x10, -+ 0x0220, 0xF0, -+ 0x0221, 0xA0, -+ 0x0222, 0x00, -+ 0x0223, 0x80, -+ 0x0224, 0x80, -+ 0x0225, 0x00, -+ 0x0226, 0x80, -+ 0x0227, 0x80, -+ 0x0228, 0x00, -+ 0x0229, 0x80, -+ 0x022A, 0x80, -+ 0x022B, 0x00, -+ 0x022C, 0x80, -+ 0x022D, 0x12, -+ 0x022E, 0x10, -+ 0x022F, 0x12, -+ 0x0230, 0x10, -+ 0x0231, 0x12, -+ 0x0232, 0x10, -+ 0x0233, 0x12, -+ 0x0234, 0x10, -+ 0x0235, 0x80, -+ 0x0236, 0x02, -+ 0x0237, 0x80, -+ 0x0238, 0x02, -+ 0x0239, 0x80, -+ 0x023A, 0x02, -+ 0x023B, 0x80, -+ 0x023C, 0x02, -+ 0x023D, 0x00, -+ 0x023E, 0x02, -+ 0x023F, 0x00, -+ 0x0240, 0x02, -+ 0x0241, 0x00, -+ 0x0242, 0x02, -+ 0x0243, 0x00, -+ 0x0244, 0x02, -+ 0x0251, 0x10, -+ 0x0280, 0x00, -+ 0x0281, 0x41, -+ 0x0282, 0x00, -+ 0x0283, 0x6D, -+ 0x0284, 0x00, -+ 0x0285, 0xBC, -+ 0x0286, 0x01, -+ 0x0287, 0x45, -+ 0x0288, 0x01, -+ 0x0289, 0x7B, -+ 0x028A, 0x01, -+ 0x028B, 0xAC, -+ 0x028C, 0x01, -+ 0x028D, 0xD2, -+ 0x028E, 0x01, -+ 0x028F, 0xF6, -+ 0x0290, 0x02, -+ 0x0291, 0x16, -+ 0x0292, 0x02, -+ 0x0293, 0x35, -+ 0x0294, 0x02, -+ 0x0295, 0x6E, -+ 0x0296, 0x02, -+ 0x0297, 0xA2, -+ 0x0298, 0x02, -+ 0x0299, 0xFF, -+ 0x029A, 0x03, -+ 0x029B, 0x51, -+ 0x029C, 0x03, -+ 0x029D, 0x9B, -+ 0x029E, 0x00, -+ 0x029F, 0x85, -+ 0x02A0, 0x04, -+ 0x02C0, 0x80, -+ 0x02C1, 0x01, -+ 0x02C2, 0x71, -+ 0x02C3, 0x04, -+ 0x02C4, 0x0F, -+ 0x02C5, 0x04, -+ 0x02C6, 0x3D, -+ 0x02C7, 0x04, -+ 0x02C8, 0x94, -+ 0x02C9, 0x01, -+ 0x02CA, 0x57, -+ 0x02CB, 0x04, -+ 0x02CC, 0x0F, -+ 0x02CD, 0x04, -+ 0x02CE, 0x8F, -+ 0x02CF, 0x04, -+ 0x02D0, 0x9E, -+ 0x02D1, 0x01, -+ 0x02E0, 0x06, -+ 0x02E1, 0xC0, -+ 0x02E2, 0xE0, -+ 0x02F0, 0x48, -+ 0x02F1, 0x01, -+ 0x02F2, 0x32, -+ 0x02F3, 0x04, -+ 0x02F4, 0x16, -+ 0x02F5, 0x04, -+ 0x02F6, 0x52, -+ 0x02F7, 0x04, -+ 0x02F8, 0xAA, -+ 0x02F9, 0x01, -+ 0x02FA, 0x58, -+ 0x02FB, 0x04, -+ 0x02FC, 0x56, -+ 0x02FD, 0x04, -+ 0x02FE, 0xDD, -+ 0x02FF, 0x04, -+ 0x0300, 0x33, -+ 0x0301, 0x02, -+ 0x0324, 0x00, -+ 0x0325, 0x01, -+ 0x0333, 0x86, -+ 0x0334, 0x00, -+ 0x0335, 0x86, -+ 0x0340, 0x40, -+ 0x0341, 0x44, -+ 0x0342, 0x4A, -+ 0x0343, 0x2B, -+ 0x0344, 0x94, -+ 0x0345, 0x3F, -+ 0x0346, 0x8E, -+ 0x0347, 0x51, -+ 0x0348, 0x75, -+ 0x0349, 0x5C, -+ 0x034A, 0x6A, -+ 0x034B, 0x68, -+ 0x034C, 0x5E, -+ 0x0350, 0x7C, -+ 0x0351, 0x78, -+ 0x0352, 0x08, -+ 0x0353, 0x04, -+ 0x0354, 0x80, -+ 0x0355, 0x9A, -+ 0x0356, 0xCC, -+ 0x0357, 0xFF, -+ 0x0358, 0xFF, -+ 0x035A, 0xFF, -+ 0x035B, 0x00, -+ 0x035C, 0x70, -+ 0x035D, 0x80, -+ 0x035F, 0xA0, -+ 0x0488, 0x30, -+ 0x0360, 0xDF, -+ 0x0361, 0x00, -+ 0x0362, 0xFF, -+ 0x0363, 0x03, -+ 0x0364, 0xFF, -+ 0x037B, 0x11, -+ 0x037C, 0x1E, -+ 0x0380, 0xFF, -+ 0x0383, 0x50, -+ 0x038A, 0x64, -+ 0x038B, 0x64, -+ 0x038E, 0x3C, -+ 0x0391, 0x2A, -+ 0x0393, 0x1E, -+ 0x0394, 0x64, -+ 0x0395, 0x23, -+ 0x0398, 0x03, -+ 0x0399, 0x45, -+ 0x039A, 0x06, -+ 0x039B, 0x8B, -+ 0x039C, 0x0D, -+ 0x039D, 0x16, -+ 0x039E, 0x0A, -+ 0x039F, 0x10, -+ 0x03A0, 0x10, -+ 0x03A1, 0xE5, -+ 0x03A2, 0x06, -+ 0x03A4, 0x18, -+ 0x03A5, 0x48, -+ 0x03A6, 0x2D, -+ 0x03A7, 0x78, -+ 0x03AC, 0x5A, -+ 0x03AD, 0x0F, -+ 0x03AE, 0x7F, -+ 0x03AF, 0x04, -+ 0x03B0, 0x35, -+ 0x03B1, 0x14, -+ 0x036F, 0x04, -+ 0x0370, 0x0A, -+ 0x0371, 0x04, -+ 0x0372, 0x10, -+ 0x0373, 0x40, -+ 0x0374, 0x20, -+ 0x0375, 0x04, -+ 0x0376, 0x00, -+ 0x0377, 0x08, -+ 0x0378, 0x08, -+ 0x0379, 0x04, -+ 0x037A, 0x08, -+ 0x0420, 0x00, -+ 0x0421, 0x00, -+ 0x0422, 0x00, -+ 0x0423, 0x84, -+ 0x0430, 0x10, -+ 0x0431, 0x60, -+ 0x0432, 0x10, -+ 0x0433, 0x20, -+ 0x0434, 0x00, -+ 0x0435, 0x30, -+ 0x0436, 0x00, -+ 0x0450, 0xFD, -+ 0x0451, 0xD8, -+ 0x0452, 0xA0, -+ 0x0453, 0x50, -+ 0x0454, 0x00, -+ 0x0459, 0x04, -+ 0x045A, 0x00, -+ 0x045B, 0x30, -+ 0x045C, 0x01, -+ 0x045D, 0x70, -+ 0x0460, 0x00, -+ 0x0461, 0x00, -+ 0x0462, 0x00, -+ 0x0465, 0x16, -+ 0x0466, 0x14, -+ 0x0478, 0x00, -+ 0x0480, 0x60, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x04B0, 0x4C, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ 0x04D0, 0x56, -+ 0x04D6, 0x30, -+ 0x04DD, 0x10, -+ 0x04D9, 0x16, -+ 0x04D3, 0x18, -+ 0x0540, 0x01, -+ 0x0541, 0x06, -+ 0x0542, 0x01, -+ 0x0543, 0x3B, -+ 0x0580, 0x50, -+ 0x0581, 0x30, -+ 0x0582, 0x2D, -+ 0x0583, 0x16, -+ 0x0584, 0x1E, -+ 0x0585, 0x0F, -+ 0x0586, 0x08, -+ 0x0587, 0x10, -+ 0x0590, 0x10, -+ 0x0591, 0x10, -+ 0x0592, 0x05, -+ 0x0593, 0x05, -+ 0x0594, 0x04, -+ 0x0595, 0x06, -+ 0x05B0, 0x04, -+ 0x05B1, 0x00, -+ 0x05E4, 0x02, -+ 0x05E5, 0x00, -+ 0x05E6, 0x81, -+ 0x05E7, 0x02, -+ 0x05E8, 0x09, -+ 0x05E9, 0x00, -+ 0x05EA, 0xE8, -+ 0x05EB, 0x01, -+ 0x0666, 0x02, -+ 0x0667, 0xE0, -+ 0x067F, 0x19, -+ 0x067C, 0x00, -+ 0x067D, 0x00, -+ 0x0682, 0x00, -+ 0x0683, 0x00, -+ 0x0688, 0x00, -+ 0x0689, 0x00, -+ 0x068E, 0x00, -+ 0x068F, 0x00, -+ 0x0695, 0x00, -+ 0x0694, 0x00, -+ 0x0697, 0x19, -+ 0x069B, 0x00, -+ 0x069C, 0x20, -+ 0x0720, 0x00, -+ 0x0725, 0x6A, -+ 0x0726, 0x03, -+ 0x072B, 0x64, -+ 0x072C, 0x64, -+ 0x072D, 0x20, -+ 0x072E, 0x82, -+ 0x072F, 0x08, -+ 0x0800, 0x16, -+ 0x0801, 0x4F, -+ 0x0802, 0x00, -+ 0x0803, 0x68, -+ 0x0804, 0x01, -+ 0x0805, 0x28, -+ 0x0806, 0x10, -+ 0x0808, 0x1D, -+ 0x0809, 0x18, -+ 0x080A, 0x10, -+ 0x080B, 0x07, -+ 0x080D, 0x0F, -+ 0x080E, 0x0F, -+ 0x0810, 0x00, -+ 0x0811, 0x08, -+ 0x0812, 0x20, -+ 0x0857, 0x0A, -+ 0x0858, 0x04, -+ 0x0859, 0x01, -+ 0x085A, 0x04, -+ 0x085B, 0x18, -+ 0x085C, 0x03, -+ 0x085D, 0x7F, -+ 0x085E, 0x02, -+ 0x085F, 0xD0, -+ 0x0860, 0x03, -+ 0x0861, 0x7F, -+ 0x0862, 0x02, -+ 0x0863, 0xD0, -+ 0x0864, 0x02, -+ 0x0865, 0x7F, -+ 0x0866, 0x01, -+ 0x0867, 0x00, -+ 0x0868, 0x40, -+ 0x0869, 0x01, -+ 0x086A, 0x00, -+ 0x086B, 0x40, -+ 0x086C, 0x01, -+ 0x086D, 0x00, -+ 0x086E, 0x40, -+ 0x0870, 0x00, -+ 0x0871, 0x14, -+ 0x0872, 0x01, -+ 0x0873, 0x20, -+ 0x0874, 0x00, -+ 0x0875, 0x14, -+ 0x0876, 0x00, -+ 0x0877, 0xEC, -+ 0x0815, 0x00, -+ 0x0816, 0x4C, -+ 0x0817, 0x00, -+ 0x0818, 0x7B, -+ 0x0819, 0x00, -+ 0x081A, 0xCA, -+ 0x081B, 0x01, -+ 0x081C, 0x3E, -+ 0x081D, 0x01, -+ 0x081E, 0x77, -+ 0x081F, 0x01, -+ 0x0820, 0xAA, -+ 0x0821, 0x01, -+ 0x0822, 0xCE, -+ 0x0823, 0x01, -+ 0x0824, 0xEE, -+ 0x0825, 0x02, -+ 0x0826, 0x16, -+ 0x0827, 0x02, -+ 0x0828, 0x33, -+ 0x0829, 0x02, -+ 0x082A, 0x65, -+ 0x082B, 0x02, -+ 0x082C, 0x91, -+ 0x082D, 0x02, -+ 0x082E, 0xDC, -+ 0x082F, 0x03, -+ 0x0830, 0x28, -+ 0x0831, 0x03, -+ 0x0832, 0x74, -+ 0x0833, 0x03, -+ 0x0834, 0xFF, -+ 0x0882, 0x00, -+ 0x0883, 0x3E, -+ 0x0884, 0x00, -+ 0x0885, 0x70, -+ 0x0886, 0x00, -+ 0x0887, 0xB8, -+ 0x0888, 0x01, -+ 0x0889, 0x28, -+ 0x088A, 0x01, -+ 0x088B, 0x5B, -+ 0x088C, 0x01, -+ 0x088D, 0x8A, -+ 0x088E, 0x01, -+ 0x088F, 0xB1, -+ 0x0890, 0x01, -+ 0x0891, 0xD9, -+ 0x0892, 0x01, -+ 0x0893, 0xEE, -+ 0x0894, 0x02, -+ 0x0895, 0x0F, -+ 0x0896, 0x02, -+ 0x0897, 0x4C, -+ 0x0898, 0x02, -+ 0x0899, 0x74, -+ 0x089A, 0x02, -+ 0x089B, 0xC3, -+ 0x089C, 0x03, -+ 0x089D, 0x0F, -+ 0x089E, 0x03, -+ 0x089F, 0x57, -+ 0x08A0, 0x03, -+ 0x08A1, 0xFF, -+ 0x0100, 0x01, -+ 0x0101, 0x01, -+ 0x0000, 0x01, -+ 0x002C, 0x00, -+ 0x0005, 0x01, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 RECORD_720P_TAB[] = -+{ -+ 0x0022, 0x00, // SFTSRT _Soft Reset -+ 0x000C, 0x04, -+ 0x0006, 0x0B, //��������װ���˵ģ�ҪVFLIP on,Mirror on -+ 0x000A, 0x00, -+ 0x000F, 0x10, -+ 0x0012, 0x01, -+ 0x0013, 0x02, -+ 0x0015, 0x01, -+ 0x0016, 0x00, -+ 0x0018, 0x00, -+ 0x001D, 0x40, -+// 0x0020, 0x10, //VSYNC: active high -+ 0x0020, 0x50, //VSYNC: active low -+ 0x0023, 0x43, -+ 0x0024, 0x20, -+ 0x0025, 0x00, //PCLK=78MHz -+// 0x0025, 0x01, //PCLK=39MHz -+ 0x0026, 0x6C, -+// 0x0027, 0x30, //YUYV(YUV422) -+ 0x0027, 0x10, //UYVY(YUV422) -+ 0x0028, 0x01, -+ 0x0030, 0x00, -+ 0x0034, 0x0E, -+ 0x0035, 0x01, -+ 0x0036, 0x00, -+ 0x0038, 0x02, -+ 0x0039, 0x01, -+ 0x003A, 0x01, -+ 0x003B, 0xFF, -+ 0x003C, 0xFF, -+ 0x003D, 0x40, -+ 0x003F, 0x14, -+ 0x0040, 0x10, -+ 0x0044, 0x07, -+ 0x0045, 0x35, -+ 0x0048, 0x7F, -+ 0x004E, 0xFF, -+ 0x0070, 0x22, -+ 0x0071, 0x3F, -+ 0x0072, 0x22, -+ 0x0073, 0x30, -+ 0x0074, 0x13, -+ 0x0075, 0x40, -+ 0x0076, 0x24, -+ 0x0078, 0x0F, -+ 0x007A, 0x06, -+ 0x007B, 0x14, -+ 0x007C, 0x10, -+ 0x0080, 0xC9, -+ 0x0081, 0x00, -+ 0x0082, 0x28, -+ 0x0083, 0xB0, -+ 0x0084, 0x60, -+ 0x0086, 0x3E, -+ 0x0087, 0x70, -+ 0x0088, 0x11, -+ 0x0089, 0x3C, -+ 0x008A, 0x87, -+ 0x008D, 0x64, -+ 0x0090, 0x07, -+ 0x0091, 0x09, -+ 0x0092, 0x0C, -+ 0x0093, 0x0C, -+ 0x0094, 0x0C, -+ 0x0095, 0x0C, -+ 0x0096, 0x01, -+ 0x0097, 0x00, -+ 0x0098, 0x04, -+ 0x0099, 0x08, -+ 0x009A, 0x0C, -+ 0x0120, 0x36, -+ 0x0121, 0x81, -+ 0x0122, 0xEB, -+ 0x0123, 0x29, -+ 0x0124, 0x50, -+ 0x0125, 0xDE, -+ 0x0126, 0xB1, -+ 0x013D, 0x0F, -+ 0x013E, 0x0F, -+ 0x013F, 0x0F, -+ 0x0140, 0x14, -+ 0x0141, 0x0A, -+ 0x0142, 0x14, -+ 0x0143, 0x0A, -+ 0x0144, 0x08, -+ 0x0145, 0x04, -+ 0x0146, 0x28, -+ 0x0147, 0x3C, -+ 0x0148, 0x28, -+ 0x0149, 0x3C, -+ 0x014A, 0x96, -+ 0x014B, 0xC8, -+ 0x0150, 0x14, -+ 0x0151, 0x30, -+ 0x0152, 0x54, -+ 0x0153, 0x70, -+ 0x0154, 0x14, -+ 0x0155, 0x30, -+ 0x0156, 0x54, -+ 0x0157, 0x70, -+ 0x0158, 0x14, -+ 0x0159, 0x30, -+ 0x015A, 0x54, -+ 0x015B, 0x70, -+ 0x015C, 0x30, -+ 0x015D, 0x00, -+ 0x01D8, 0x20, -+ 0x01D9, 0x08, -+ 0x01DA, 0x20, -+ 0x01DB, 0x08, -+ 0x01DC, 0x20, -+ 0x01DD, 0x08, -+ 0x01DE, 0x50, -+ 0x01E0, 0x50, -+ 0x01E2, 0x50, -+ 0x01E4, 0x10, -+ 0x01E5, 0x10, -+ 0x01E6, 0x02, -+ 0x01E7, 0x10, -+ 0x01E8, 0x10, -+ 0x01E9, 0x10, -+ 0x01EC, 0x28, -+ 0x0220, 0x00, -+ 0x0221, 0xA0, -+ 0x0222, 0x00, -+ 0x0223, 0x80, -+ 0x0224, 0x80, -+ 0x0225, 0x00, -+ 0x0226, 0x80, -+ 0x0227, 0x80, -+ 0x0228, 0x00, -+ 0x0229, 0x80, -+ 0x022A, 0x80, -+ 0x022B, 0x00, -+ 0x022C, 0x80, -+ 0x022D, 0x12, -+ 0x022E, 0x10, -+ 0x022F, 0x12, -+ 0x0230, 0x10, -+ 0x0231, 0x12, -+ 0x0232, 0x10, -+ 0x0233, 0x12, -+ 0x0234, 0x10, -+ 0x0235, 0x88, -+ 0x0236, 0x02, -+ 0x0237, 0x88, -+ 0x0238, 0x02, -+ 0x0239, 0x88, -+ 0x023A, 0x02, -+ 0x023B, 0x88, -+ 0x023C, 0x02, -+ 0x023D, 0x04, -+ 0x023E, 0x02, -+ 0x023F, 0x04, -+ 0x0240, 0x02, -+ 0x0241, 0x04, -+ 0x0242, 0x02, -+ 0x0243, 0x04, -+ 0x0244, 0x02, -+ 0x0251, 0x10, -+ 0x0280, 0x00, -+ 0x0281, 0x41, -+ 0x0282, 0x00, -+ 0x0283, 0x6D, -+ 0x0284, 0x00, -+ 0x0285, 0xBC, -+ 0x0286, 0x01, -+ 0x0287, 0x45, -+ 0x0288, 0x01, -+ 0x0289, 0x7B, -+ 0x028A, 0x01, -+ 0x028B, 0xAC, -+ 0x028C, 0x01, -+ 0x028D, 0xD2, -+ 0x028E, 0x01, -+ 0x028F, 0xF6, -+ 0x0290, 0x02, -+ 0x0291, 0x16, -+ 0x0292, 0x02, -+ 0x0293, 0x35, -+ 0x0294, 0x02, -+ 0x0295, 0x6E, -+ 0x0296, 0x02, -+ 0x0297, 0xA2, -+ 0x0298, 0x02, -+ 0x0299, 0xFF, -+ 0x029A, 0x03, -+ 0x029B, 0x51, -+ 0x029C, 0x03, -+ 0x029D, 0x9B, -+ 0x029E, 0x00, -+ 0x029F, 0x85, -+ 0x02A0, 0x04, -+ 0x02C0, 0x80, -+ 0x02C1, 0x01, -+ 0x02C2, 0x71, -+ 0x02C3, 0x04, -+ 0x02C4, 0x0F, -+ 0x02C5, 0x04, -+ 0x02C6, 0x3D, -+ 0x02C7, 0x04, -+ 0x02C8, 0x94, -+ 0x02C9, 0x01, -+ 0x02CA, 0x57, -+ 0x02CB, 0x04, -+ 0x02CC, 0x0F, -+ 0x02CD, 0x04, -+ 0x02CE, 0x8F, -+ 0x02CF, 0x04, -+ 0x02D0, 0x9E, -+ 0x02D1, 0x01, -+ 0x02E0, 0x06, -+ 0x02E1, 0xC0, -+ 0x02E2, 0xE0, -+ 0x02F0, 0x48, -+ 0x02F1, 0x01, -+ 0x02F2, 0x32, -+ 0x02F3, 0x04, -+ 0x02F4, 0x16, -+ 0x02F5, 0x04, -+ 0x02F6, 0x52, -+ 0x02F7, 0x04, -+ 0x02F8, 0xAA, -+ 0x02F9, 0x01, -+ 0x02FA, 0x58, -+ 0x02FB, 0x04, -+ 0x02FC, 0x56, -+ 0x02FD, 0x04, -+ 0x02FE, 0xDD, -+ 0x02FF, 0x04, -+ 0x0300, 0x33, -+ 0x0301, 0x02, -+ 0x0324, 0x00, -+ 0x0325, 0x01, -+ 0x0333, 0x86, -+ 0x0334, 0x00, -+ 0x0335, 0x86, -+ 0x0340, 0x40, -+ 0x0341, 0x44, -+ 0x0342, 0x4A, -+ 0x0343, 0x2B, -+ 0x0344, 0x94, -+ 0x0345, 0x3F, -+ 0x0346, 0x8E, -+ 0x0347, 0x51, -+ 0x0348, 0x75, -+ 0x0349, 0x5C, -+ 0x034A, 0x6A, -+ 0x034B, 0x68, -+ 0x034C, 0x5E, -+ 0x0350, 0x7C, -+ 0x0351, 0x78, -+ 0x0352, 0x08, -+ 0x0353, 0x04, -+ 0x0354, 0x80, -+ 0x0355, 0x9A, -+ 0x0356, 0xCC, -+ 0x0357, 0xFF, -+ 0x0358, 0xFF, -+ 0x035A, 0xFF, -+ 0x035B, 0x00, -+ 0x035C, 0x70, -+ 0x035D, 0x80, -+ 0x035F, 0xA0, -+ 0x0488, 0x30, -+ 0x0360, 0xDF, -+ 0x0361, 0x00, -+ 0x0362, 0xFF, -+ 0x0363, 0x03, -+ 0x0364, 0xFF, -+ 0x037B, 0x11, -+ 0x037C, 0x1E, -+ 0x0380, 0xFF, -+ 0x0383, 0x50, -+ 0x038A, 0x64, -+ 0x038B, 0x64, -+ 0x038E, 0x3C, -+ 0x0391, 0x2A, -+ 0x0393, 0x1E, -+ 0x0394, 0x64, -+ 0x0395, 0x23, -+ 0x0398, 0x03, -+ 0x0399, 0x45, -+ 0x039A, 0x06, -+ 0x039B, 0x8B, -+ 0x039C, 0x0D, -+ 0x039D, 0x16, -+ 0x039E, 0x0A, -+ 0x039F, 0x10, -+ 0x03A0, 0x10, -+ 0x03A1, 0xE5, -+ 0x03A2, 0x06, -+ 0x03A4, 0x18, -+ 0x03A5, 0x48, -+ 0x03A6, 0x2D, -+ 0x03A7, 0x78, -+ 0x03AC, 0x5A, -+ 0x03AD, 0x0F, -+ 0x03AE, 0x7F, -+ 0x03AF, 0x04, -+ 0x03B0, 0x35, -+ 0x03B1, 0x14, -+ 0x036F, 0x04, -+ 0x0370, 0x0A, -+ 0x0371, 0x04, -+ 0x0372, 0x00, -+ 0x0373, 0x40, -+ 0x0374, 0x20, -+ 0x0375, 0x04, -+ 0x0376, 0x00, -+ 0x0377, 0x08, -+ 0x0378, 0x08, -+ 0x0379, 0x04, -+ 0x037A, 0x08, -+ 0x0420, 0x00, -+ 0x0421, 0x00, -+ 0x0422, 0x00, -+ 0x0423, 0x84, -+ 0x0430, 0x10, -+ 0x0431, 0x60, -+ 0x0432, 0x10, -+ 0x0433, 0x20, -+ 0x0434, 0x00, -+ 0x0435, 0x30, -+ 0x0436, 0x00, -+ 0x0450, 0xFD, -+ 0x0451, 0xD8, -+ 0x0452, 0xA0, -+ 0x0453, 0x50, -+ 0x0454, 0x00, -+ 0x0459, 0x04, -+ 0x045A, 0x00, -+ 0x045B, 0x30, -+ 0x045C, 0x01, -+ 0x045D, 0x70, -+ 0x0460, 0x00, -+ 0x0461, 0x00, -+ 0x0462, 0x00, -+ 0x0465, 0x16, -+ 0x0466, 0x14, -+ 0x0478, 0x00, -+ 0x0480, 0x60, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x04B0, 0x4C, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ 0x04D0, 0x56, -+ 0x04D6, 0x30, -+ 0x04DD, 0x10, -+ 0x04D9, 0x16, -+ 0x04D3, 0x18, -+ 0x0540, 0x00, -+ 0x0541, 0xD0, -+ 0x0542, 0x00, -+ 0x0543, 0xFA, -+ 0x0580, 0x50, -+ 0x0581, 0x30, -+ 0x0582, 0x2D, -+ 0x0583, 0x16, -+ 0x0584, 0x1E, -+ 0x0585, 0x0F, -+ 0x0586, 0x08, -+ 0x0587, 0x10, -+ 0x0590, 0x10, -+ 0x0591, 0x10, -+ 0x0592, 0x05, -+ 0x0593, 0x05, -+ 0x0594, 0x04, -+ 0x0595, 0x06, -+ 0x05B0, 0x04, -+ 0x05B1, 0x00, -+ 0x05E4, 0x08, -+ 0x05E5, 0x00, -+ 0x05E6, 0x07, -+ 0x05E7, 0x05, -+ 0x05E8, 0x0A, -+ 0x05E9, 0x00, -+ 0x05EA, 0xD9, -+ 0x05EB, 0x02, -+ 0x0666, 0x02, -+ 0x0667, 0xE0, -+ 0x067F, 0x19, -+ 0x067C, 0x00, -+ 0x067D, 0x00, -+ 0x0682, 0x00, -+ 0x0683, 0x00, -+ 0x0688, 0x00, -+ 0x0689, 0x00, -+ 0x068E, 0x00, -+ 0x068F, 0x00, -+ 0x0695, 0x00, -+ 0x0694, 0x00, -+ 0x0697, 0x19, -+ 0x069B, 0x00, -+ 0x069C, 0x30, -+ 0x0720, 0x00, -+ 0x0725, 0x6A, -+ 0x0726, 0x03, -+ 0x072B, 0x64, -+ 0x072C, 0x64, -+ 0x072D, 0x20, -+ 0x072E, 0x82, -+ 0x072F, 0x08, -+ 0x0800, 0x16, -+ 0x0801, 0x30, -+ 0x0802, 0x00, -+ 0x0803, 0x68, -+ 0x0804, 0x01, -+ 0x0805, 0x28, -+ 0x0806, 0x10, -+ 0x0808, 0x1D, -+ 0x0809, 0x18, -+ 0x080A, 0x10, -+ 0x080B, 0x07, -+ 0x080D, 0x0F, -+ 0x080E, 0x0F, -+ 0x0810, 0x00, -+ 0x0811, 0x08, -+ 0x0812, 0x20, -+ 0x0857, 0x0A, -+ 0x0858, 0x30, -+ 0x0859, 0x01, -+ 0x085A, 0x03, -+ 0x085B, 0x40, -+ 0x085C, 0x03, -+ 0x085D, 0x7F, -+ 0x085E, 0x02, -+ 0x085F, 0xD0, -+ 0x0860, 0x03, -+ 0x0861, 0x7F, -+ 0x0862, 0x02, -+ 0x0863, 0xD0, -+ 0x0864, 0x00, -+ 0x0865, 0x7F, -+ 0x0866, 0x01, -+ 0x0867, 0x00, -+ 0x0868, 0x40, -+ 0x0869, 0x01, -+ 0x086A, 0x00, -+ 0x086B, 0x40, -+ 0x086C, 0x01, -+ 0x086D, 0x00, -+ 0x086E, 0x40, -+ 0x0870, 0x00, -+ 0x0871, 0x14, -+ 0x0872, 0x01, -+ 0x0873, 0x20, -+ 0x0874, 0x00, -+ 0x0875, 0x14, -+ 0x0876, 0x00, -+ 0x0877, 0xEC, -+ 0x0815, 0x00, -+ 0x0816, 0x4C, -+ 0x0817, 0x00, -+ 0x0818, 0x7B, -+ 0x0819, 0x00, -+ 0x081A, 0xCA, -+ 0x081B, 0x01, -+ 0x081C, 0x3E, -+ 0x081D, 0x01, -+ 0x081E, 0x77, -+ 0x081F, 0x01, -+ 0x0820, 0xAA, -+ 0x0821, 0x01, -+ 0x0822, 0xCE, -+ 0x0823, 0x01, -+ 0x0824, 0xEE, -+ 0x0825, 0x02, -+ 0x0826, 0x16, -+ 0x0827, 0x02, -+ 0x0828, 0x33, -+ 0x0829, 0x02, -+ 0x082A, 0x65, -+ 0x082B, 0x02, -+ 0x082C, 0x91, -+ 0x082D, 0x02, -+ 0x082E, 0xDC, -+ 0x082F, 0x03, -+ 0x0830, 0x28, -+ 0x0831, 0x03, -+ 0x0832, 0x74, -+ 0x0833, 0x03, -+ 0x0834, 0xFF, -+ 0x0882, 0x00, -+ 0x0883, 0x3E, -+ 0x0884, 0x00, -+ 0x0885, 0x70, -+ 0x0886, 0x00, -+ 0x0887, 0xB8, -+ 0x0888, 0x01, -+ 0x0889, 0x28, -+ 0x088A, 0x01, -+ 0x088B, 0x5B, -+ 0x088C, 0x01, -+ 0x088D, 0x8A, -+ 0x088E, 0x01, -+ 0x088F, 0xB1, -+ 0x0890, 0x01, -+ 0x0891, 0xD9, -+ 0x0892, 0x01, -+ 0x0893, 0xEE, -+ 0x0894, 0x02, -+ 0x0895, 0x0F, -+ 0x0896, 0x02, -+ 0x0897, 0x4C, -+ 0x0898, 0x02, -+ 0x0899, 0x74, -+ 0x089A, 0x02, -+ 0x089B, 0xC3, -+ 0x089C, 0x03, -+ 0x089D, 0x0F, -+ 0x089E, 0x03, -+ 0x089F, 0x57, -+ 0x08A0, 0x03, -+ 0x08A1, 0xFF, -+ 0x0100, 0x01, -+ 0x0101, 0x01, -+ 0x0000, 0x01, -+ 0x002C, 0x00, -+ 0x0005, 0x01, -+ END_FLAG, END_FLAG -+}; -+ -+ -+/**************** Camera Exposure Table ****************/ -+static const T_U16 EXPOSURE_WHOLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EXPOSURE_CENTER_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EXPOSURE_MIDDLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Brightness Table ****************/ -+static const T_U16 BRIGHTNESS_0_TAB[] = -+{ -+ 0x04B0, 0x46, -+ 0x04B1, 0x84, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_1_TAB[] = -+{ -+ 0x04B0, 0x4C, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_2_TAB[] = -+{ -+ 0x04B0, 0x5c, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_3_TAB[] = -+{ -+ 0x04B0, 0x7C, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_4_TAB[] = -+{ -+ 0x04B0, 0x9C, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_5_TAB[] = -+{ -+ 0x04B0, 0xAC, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_6_TAB[] = -+{ -+ 0x04B0, 0xCC, -+ 0x04B1, 0x86, -+ 0x04B2, 0x00, -+ 0x04B3, 0x18, -+ 0x04B4, 0x00, -+ 0x04B5, 0x00, -+ 0x04B6, 0x30, -+ 0x04B7, 0x00, -+ 0x04B8, 0x00, -+ 0x04B9, 0x10, -+ 0x04BA, 0x00, -+ 0x04BB, 0x00, -+ 0x04BD, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Contrast Table ****************/ -+static const T_U16 CONTRAST_1_TAB[] = -+{ -+ 0x04D0, 0x56, -+ 0x04D6, 0x30, -+ 0x04DD, 0x10, -+ 0x04D9, 0x16, -+ 0x04D3, 0x18, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_7_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Saturation Table ****************/ -+static const T_U16 SATURATION_0_TAB[] = -+{ -+ 0x0480, 0x30, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x0483, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_1_TAB[] = -+{ -+ 0x0480, 0x40, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x0483, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_2_TAB[] = -+{ -+ 0x0480, 0x50, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x0483, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_3_TAB[] = -+{ -+ 0x0480, 0x60, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x0483, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_4_TAB[] = -+{ -+ 0x0480, 0x70, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x0483, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_5_TAB[] = -+{ -+ 0x0480, 0x80, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x0483, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_6_TAB[] = -+{ -+ 0x0480, 0x90, -+ 0x0481, 0x06, -+ 0x0482, 0x0C, -+ 0x0483, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Sharpness Table ****************/ -+static const T_U16 SHARPNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera AWB Table ****************/ -+static const T_U16 AWB_AUTO_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_SUNNY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_CLOUDY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_OFFICE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_HOME_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Effect Table ****************/ -+static const T_U16 EFFECT_NORMAL_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_SEPIA_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_ANTIQUE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_BLUISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_GREENISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_REDDISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_NEGATIVE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_BW_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera night/day mode ****************/ -+static const T_U16 DAY_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 NIGHT_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera anti-flicker mode ****************/ -+static const T_U16 ANTI_FLICKER_DISABLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 ANTI_FLICKER_50HZ_TAB[] = -+{ -+ 0x0120, 0x36, -+ 0x0542, 0x00, -+ 0x0543, 0xFA, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 ANTI_FLICKER_60HZ_TAB[] = -+{ -+ 0x0120, 0x37, -+ 0x0540, 0x00, -+ 0x0541, 0xD0, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 ANTI_FLICKER_AUTO_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+#endif -+#endif -diff --git a/drivers/media/video/plat-anyka/camera_ov2643.c b/drivers/media/video/plat-anyka/camera_ov2643.c -new file mode 100755 -index 00000000..4938db2f ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov2643.c -@@ -0,0 +1,994 @@ -+/** -+ * @file camera_ov2643.c -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-09-21 -+ * @version 1.0 -+ * @ref -+ */ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/cam_com_sensor.h> -+#include "camera_ov2643.h" -+#else -+#include "akdefine.h" -+#include "cam_com_sensor.h" -+#include "camera_ov2643.h" -+#include "Gpio_config.h" -+#endif -+ -+#if defined (USE_CAMERA_OV2643) || defined (CONFIG_SENSOR_OV2643) -+ -+#define CAM_EN_LEVEL 0 -+#define CAM_RESET_LEVEL 0 -+ -+#define CAMERA_SCCB_ADDR 0x60 -+#define CAMERA_OV2643_ID 0x2643 -+ -+#define OV2643_CAMERA_MCLK 24 -+ -+static T_CAMERA_TYPE camera_ov2643_type = CAMERA_2M; -+static T_NIGHT_MODE night_mode = CAMERA_DAY_MODE; -+static T_CAMERA_MODE s_ov2643_CurMode = CAMERA_MODE_VGA; -+ -+static T_VOID camera_setbit(T_U8 reg, T_U8 bit, T_U8 value) -+{ -+ T_U8 tmp; -+ -+ tmp = sccb_read_data(CAMERA_SCCB_ADDR, reg); -+ if (value == 1) -+ { -+ tmp |= 0x1 << bit; -+ } -+ else -+ { -+ tmp &= ~(0x1 << bit); -+ } -+ -+ sccb_write_data(CAMERA_SCCB_ADDR, reg, &tmp, 1); -+} -+ -+static T_BOOL camera_set_param(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 temp_value; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)(&tabParameter[i + 1]), 1); -+ -+ if (!((tabParameter[i] == 0x12) && (tabParameter[i + 1] & 0x80))) -+ { -+ temp_value = sccb_read_data(CAMERA_SCCB_ADDR, tabParameter[i]); -+ if (temp_value != tabParameter[i + 1]) -+ { -+ akprintf(C1, M_DRVSYS, "set parameter error!\n"); -+ akprintf(C1, M_DRVSYS, "reg 0x%x write data is 0x%x, read data is 0x%x!\n", tabParameter[i], tabParameter[i + 1], temp_value); -+ -+ return AK_FALSE; -+ } -+ } -+ } -+ -+ i += 2; -+ } -+ -+ return AK_TRUE; -+} -+ -+static T_VOID camera_setup(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)&tabParameter[i + 1], 1); -+ } -+ -+ i += 2; -+ } -+} -+ -+static T_VOID cam_ov2643_open(T_VOID) -+{ -+ gpio_set_pin_dir(GPIO_CAMERA_AVDD, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_CHIP_ENABLE); -+ gpio_set_pin_dir(GPIO_CAMERA_CHIP_ENABLE, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, CAM_EN_LEVEL); -+ mini_delay(10); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_RESET); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, CAM_RESET_LEVEL); -+ mini_delay(10); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, !CAM_RESET_LEVEL); -+ -+ mini_delay(20); -+} -+ -+static T_BOOL cam_ov2643_close(T_VOID) -+{ -+ //sccb software standby mode -+ T_U8 Reg0x3d = 0x48; -+ T_U8 Reg0xc3 = 0x00; -+ -+ sccb_write_data(CAMERA_SCCB_ADDR, 0x3d, &Reg0x3d, 1); -+ sccb_write_data(CAMERA_SCCB_ADDR, 0xc3, &Reg0xc3, 1); -+ -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, !CAM_EN_LEVEL); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, !gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_INPUT); -+ -+ gpio_set_pin_dir(GPIO_I2C_SCL, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SCL, GPIO_LEVEL_LOW); -+ gpio_set_pin_dir(GPIO_I2C_SDA, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SDA, GPIO_LEVEL_LOW); -+ -+ return AK_TRUE; -+} -+ -+static T_U32 cam_ov2643_read_id(T_VOID) -+{ -+ T_U8 value = 0x00; -+ T_U32 id = 0; -+ -+ sccb_init(GPIO_I2C_SCL, GPIO_I2C_SDA); //init sccb first here!! -+ -+ value = sccb_read_data(CAMERA_SCCB_ADDR, 0x0a); -+ id = value << 8; -+ value = sccb_read_data(CAMERA_SCCB_ADDR, 0x0b); -+ id |= value; -+ -+ return id; -+} -+ -+/** -+ * @brief initialize the parameters of camera, should be done after reset and open camera to initialize -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @return T_BOOL -+ * @retval AK_TRUE if success, else AK_FALSE -+ */ -+static T_BOOL cam_ov2643_init(void) -+{ -+ if (!camera_set_param(INIT_TAB)) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ night_mode = CAMERA_DAY_MODE; -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief Set camera mode to specify image quality, SXGA/VGA/CIF etc -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mode mode value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_mode(T_CAMERA_MODE mode) -+{ -+ s_ov2643_CurMode = mode; -+ switch(mode) -+ { -+ case CAMERA_MODE_UXGA: -+ camera_setup(UXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_SXGA: -+ camera_setup(SXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_VGA: -+ camera_setup(VGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_CIF: -+ camera_setup(CIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QVGA: -+ camera_setup(QVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_QCIF: -+ camera_setup(QCIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QQVGA: -+ camera_setup(QQVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_PREV: -+ camera_setup(PREV_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_REC: -+ camera_setup(RECORD_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_720P: -+ camera_setup(RECORD_720P_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ default: -+ s_ov2643_CurMode = CAMERA_MODE_VGA; -+ akprintf(C1, M_DRVSYS, "set camera mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera exposure mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] exposure exposure mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_exposure(T_CAMERA_EXPOSURE exposure) -+{ -+ switch(exposure) -+ { -+ case EXPOSURE_WHOLE: -+ camera_setup(EXPOSURE_WHOLE_TAB); -+ break; -+ case EXPOSURE_CENTER: -+ camera_setup(EXPOSURE_CENTER_TAB); -+ break; -+ case EXPOSURE_MIDDLE: -+ camera_setup(EXPOSURE_MIDDLE_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set exposure parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera brightness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] brightness brightness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_brightness(T_CAMERA_BRIGHTNESS brightness) -+{ -+ switch(brightness) -+ { -+ case CAMERA_BRIGHTNESS_0: -+ camera_setup(BRIGHTNESS_0_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_1: -+ camera_setup(BRIGHTNESS_1_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_2: -+ camera_setup(BRIGHTNESS_2_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_3: -+ camera_setup(BRIGHTNESS_3_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_4: -+ camera_setup(BRIGHTNESS_4_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_5: -+ camera_setup(BRIGHTNESS_5_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_6: -+ camera_setup(BRIGHTNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set brightness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera contrast level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] contrast contrast value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_contrast(T_CAMERA_CONTRAST contrast) -+{ -+ switch(contrast) -+ { -+ case CAMERA_CONTRAST_1: -+ camera_setup(CONTRAST_1_TAB); -+ break; -+ case CAMERA_CONTRAST_2: -+ camera_setup(CONTRAST_2_TAB); -+ break; -+ case CAMERA_CONTRAST_3: -+ camera_setup(CONTRAST_3_TAB); -+ break; -+ case CAMERA_CONTRAST_4: -+ camera_setup(CONTRAST_4_TAB); -+ break; -+ case CAMERA_CONTRAST_5: -+ camera_setup(CONTRAST_5_TAB); -+ break; -+ case CAMERA_CONTRAST_6: -+ camera_setup(CONTRAST_6_TAB); -+ break; -+ case CAMERA_CONTRAST_7: -+ camera_setup(CONTRAST_7_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set contrast parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera saturation level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] saturation saturation value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_saturation(T_CAMERA_SATURATION saturation) -+{ -+ switch(saturation) -+ { -+ case CAMERA_SATURATION_1: -+ camera_setup(SATURATION_1_TAB); -+ break; -+ case CAMERA_SATURATION_2: -+ camera_setup(SATURATION_2_TAB); -+ break; -+ case CAMERA_SATURATION_3: -+ camera_setup(SATURATION_3_TAB); -+ break; -+ case CAMERA_SATURATION_4: -+ camera_setup(SATURATION_4_TAB); -+ break; -+ case CAMERA_SATURATION_5: -+ camera_setup(SATURATION_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set saturation parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera sharpness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] sharpness sharpness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_sharpness(T_CAMERA_SHARPNESS sharpness) -+{ -+ switch(sharpness) -+ { -+ case CAMERA_SHARPNESS_0: -+ camera_setup(SHARPNESS_0_TAB); -+ break; -+ case CAMERA_SHARPNESS_1: -+ camera_setup(SHARPNESS_1_TAB); -+ break; -+ case CAMERA_SHARPNESS_2: -+ camera_setup(SHARPNESS_2_TAB); -+ break; -+ case CAMERA_SHARPNESS_3: -+ camera_setup(SHARPNESS_3_TAB); -+ break; -+ case CAMERA_SHARPNESS_4: -+ camera_setup(SHARPNESS_4_TAB); -+ break; -+ case CAMERA_SHARPNESS_5: -+ camera_setup(SHARPNESS_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set sharpness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera AWB mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] awb AWB mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_AWB(T_CAMERA_AWB awb) -+{ -+ switch(awb) -+ { -+ case AWB_AUTO: -+ camera_setup(AWB_AUTO_TAB); -+ break; -+ case AWB_SUNNY: -+ camera_setup(AWB_SUNNY_TAB); -+ break; -+ case AWB_CLOUDY: -+ camera_setup(AWB_CLOUDY_TAB); -+ break; -+ case AWB_OFFICE: -+ camera_setup(AWB_OFFICE_TAB); -+ break; -+ case AWB_HOME: -+ camera_setup(AWB_HOME_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set AWB mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera mirror mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mirror mirror mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_mirror(T_CAMERA_MIRROR mirror) -+{ -+ switch(mirror) -+ { -+ case CAMERA_MIRROR_V: -+ camera_setbit(0x12, 4, 1); -+ camera_setbit(0x12, 5, 0); -+ break; -+ case CAMERA_MIRROR_H: -+ camera_setbit(0x12, 4, 0); -+ camera_setbit(0x12, 5, 1); -+ break; -+ case CAMERA_MIRROR_NORMAL: -+ camera_setbit(0x12, 4, 0); -+ camera_setbit(0x12, 5, 0); -+ break; -+ case CAMERA_MIRROR_FLIP: -+ camera_setbit(0x12, 4, 1); -+ camera_setbit(0x12, 5, 1); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set mirror parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera effect mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] effect effect mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2643_set_effect(T_CAMERA_EFFECT effect) -+{ -+ switch(effect) -+ { -+ case CAMERA_EFFECT_NORMAL: -+ camera_setup(EFFECT_NORMAL_TAB); -+ break; -+ case CAMERA_EFFECT_SEPIA: -+ camera_setup(EFFECT_SEPIA_TAB); -+ break; -+ case CAMERA_EFFECT_ANTIQUE: -+ camera_setup(EFFECT_ANTIQUE_TAB); -+ break; -+ case CAMERA_EFFECT_BLUE: -+ camera_setup(EFFECT_BLUISH_TAB); -+ break; -+ case CAMERA_EFFECT_GREEN: -+ camera_setup(EFFECT_GREENISH_TAB); -+ break; -+ case CAMERA_EFFECT_RED: -+ camera_setup(EFFECT_REDDISH_TAB); -+ break; -+ case CAMERA_EFFECT_NEGATIVE: -+ camera_setup(EFFECT_NEGATIVE_TAB); -+ break; -+ case CAMERA_EFFECT_BW: -+ camera_setup(EFFECT_BW_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set camer effect parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief set camera window -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] srcWidth window width -+ * @param[in] srcHeight window height -+ * @return T_S32 -+ * @retval 0 if error mode -+ * @retval 1 if success -+ * @retval -1 if failed -+ */ -+static T_S32 cam_ov2643_set_digital_zoom(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ return 1; -+} -+ -+static T_VOID cam_ov2643_set_night_mode(T_NIGHT_MODE mode) -+{ -+ switch(mode) -+ { -+ case CAMERA_DAY_MODE: -+ camera_setup(DAY_MODE_TAB); -+ night_mode = CAMERA_DAY_MODE; -+ break; -+ case CAMERA_NIGHT_MODE: -+ camera_setup(NIGHT_MODE_TAB); -+ night_mode = CAMERA_NIGHT_MODE; -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set night mode parameter error!\n"); -+ break; -+ } -+} -+ -+static T_BOOL cam_ov2643_set_to_cap(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_VGA; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 1024)) -+ { -+ Cammode = CAMERA_MODE_SXGA; -+ } -+ else if ((srcWidth <= 1600) && (srcHeight <= 1200)) -+ { -+ Cammode = CAMERA_MODE_UXGA; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "ov2643 unsupport %d & %d mode!\n", srcWidth, srcHeight); -+ return AK_FALSE; -+ } -+ -+ cam_ov2643_set_mode(Cammode); -+ cam_ov2643_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov2643_set_to_prev(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_ov2643_set_mode(CAMERA_MODE_PREV); -+ cam_ov2643_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov2643_set_to_record(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_REC; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "200W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_ov2643_set_mode(Cammode); -+ cam_ov2643_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_CAMERA_TYPE cam_ov2643_get_type(T_VOID) -+{ -+ return camera_ov2643_type; -+} -+ -+static T_VOID cam_ov2643_set_sensor_param(T_U32 cmd, T_U32 data) -+{ -+ T_U8 value; -+ -+ value = (T_U8)data; -+ sccb_write_data(CAMERA_SCCB_ADDR, (T_U8)cmd, &value, 1); -+} -+ -+static T_CAMERA_FUNCTION_HANDLER ov2643_function_handler = -+{ -+ OV2643_CAMERA_MCLK, -+ cam_ov2643_open, -+ cam_ov2643_close, -+ cam_ov2643_read_id, -+ cam_ov2643_init, -+ cam_ov2643_set_mode, -+ cam_ov2643_set_exposure, -+ cam_ov2643_set_brightness, -+ cam_ov2643_set_contrast, -+ cam_ov2643_set_saturation, -+ cam_ov2643_set_sharpness, -+ cam_ov2643_set_AWB, -+ cam_ov2643_set_mirror, -+ cam_ov2643_set_effect, -+ cam_ov2643_set_digital_zoom, -+ cam_ov2643_set_night_mode, -+ AK_NULL, -+ AK_NULL, -+ cam_ov2643_set_to_cap, -+ cam_ov2643_set_to_prev, -+ cam_ov2643_set_to_record, -+ cam_ov2643_get_type, -+ cam_ov2643_set_sensor_param -+}; -+ -+#ifndef CONFIG_LINUX_AKSENSOR -+static int camera_ov2643_reg(void) -+{ -+ camera_reg_dev(CAMERA_OV2643_ID, &ov2643_function_handler); -+ return 0; -+} -+ -+#ifdef __CC_ARM -+#pragma arm section rwdata = "__initcall_", zidata = "__initcall_" -+#endif -+module_init(camera_ov2643_reg) -+#ifdef __CC_ARM -+#pragma arm section -+#endif -+ -+#else -+static const char * awb_menu[] = { -+ [AWB_AUTO] = "auto", -+ [AWB_SUNNY] = "sunny", -+ [AWB_CLOUDY] = "cloudy", -+ [AWB_OFFICE] = "office", -+ [AWB_HOME] = "home", -+ [AWB_NIGHT] = "night", -+}; -+ -+static const char * effect_menu[] = { -+ [CAMERA_EFFECT_NORMAL] = "normal", -+ [CAMERA_EFFECT_SEPIA] = "sepia", -+ [CAMERA_EFFECT_ANTIQUE] = "antique", -+ [CAMERA_EFFECT_BLUE] = "blue", -+ [CAMERA_EFFECT_GREEN] = "green", -+ [CAMERA_EFFECT_RED] = "red", -+ [CAMERA_EFFECT_NEGATIVE] = "negative", -+ [CAMERA_EFFECT_BW] = "bw", -+ [CAMERA_EFFECT_BWN] = "bwn", -+ [CAMERA_EFFECT_AQUA] = "aqua", -+ [CAMERA_EFFECT_COOL] = "cool", -+ [CAMERA_EFFECT_WARM] = "warm", -+}; -+ -+static const char * resolution_menu[] = { -+ [0] = "1600x1200", -+ [1] = "1280x720", -+ [2] = "800x600", -+ [3] = "640x480", -+}; -+ -+static const char * hflip_menu[] = { -+ [0] = "normal", -+ [1] = "horizontal flip", -+}; -+ -+static const char * vflip_menu[] = { -+ [0] = "normal", -+ [1] = "vertical flip", -+}; -+ -+static const char * night_menu[] = { -+ [CAMERA_DAY_MODE] = "daylight", -+ [CAMERA_NIGHT_MODE] = "night", -+}; -+ -+static int ov2643_s_ctl(struct v4l2_ctrl *ctrl) -+{ -+ int ret = -EINVAL; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ if (ov2643_function_handler.cam_set_AWB_func) { -+ ov2643_function_handler.cam_set_AWB_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_COLORFX: -+ if (ov2643_function_handler.cam_set_effect_func) { -+ ov2643_function_handler.cam_set_effect_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ -+ case V4L2_CID_BRIGHTNESS: -+ if (ov2643_function_handler.cam_set_brightness_func) { -+ ov2643_function_handler.cam_set_brightness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_CONTRAST: -+ if (ov2643_function_handler.cam_set_contrast_func) { -+ ov2643_function_handler.cam_set_contrast_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SATURATION: -+ if (ov2643_function_handler.cam_set_saturation_func) { -+ ov2643_function_handler.cam_set_saturation_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SHARPNESS: -+ if (ov2643_function_handler.cam_set_sharpness_func) { -+ ov2643_function_handler.cam_set_sharpness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_HFLIP: -+ if (ov2643_function_handler.cam_set_mirror_func) { -+ ov2643_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_H : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_VFLIP: -+ if (ov2643_function_handler.cam_set_mirror_func) { -+ ov2643_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_V : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_NIGHTMODE: -+ if (ov2643_function_handler.cam_set_night_mode_func) { -+ ov2643_function_handler.cam_set_night_mode_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+}; -+ -+static struct v4l2_ctrl_ops ov2643_ctrl_ops = { -+ .s_ctrl = ov2643_s_ctl, -+}; -+ -+static const struct v4l2_ctrl_config ov2643_ctrls[] = { -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_AUTO_WHITE_BALANCE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "AWB", -+ .min = 0, -+ .max = ARRAY_SIZE(awb_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = awb_menu, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_COLORFX, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Effect", -+ .min = 0, -+ .max = ARRAY_SIZE(effect_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = effect_menu, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Horizontal Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(hflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = hflip_menu, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Vetical Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(vflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = vflip_menu, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_PICTURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Resolution", -+ .min = 0, -+ .max = ARRAY_SIZE(resolution_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = resolution_menu, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_NIGHTMODE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Night mode", -+ .min = 0, -+ .max = ARRAY_SIZE(night_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = night_menu, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_BRIGHTNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Brightness", -+ .min = 0, -+ .max = CAMERA_BRIGHTNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .min = 0, -+ .max = CAMERA_CONTRAST_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .min = 0, -+ .max = CAMERA_SATURATION_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov2643_ctrl_ops, -+ .id = V4L2_CID_SHARPNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Sharpness", -+ .min = 0, -+ .max = CAMERA_SHARPNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ } -+}; -+ -+ -+/* -+ * supported format list -+ */ -+static const struct aksensor_color_format ov2643_formats[] = { -+ { -+ .code = V4L2_MBUS_FMT_YUYV8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_YVYU8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_UYVY8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+}; -+ -+static const struct aksensor_win_size ov2643_win[] = { -+ {.name = "VGA", .width = 640, .height = 480}, -+ {.name = "SVGA", .width = 800, .height = 600}, -+ {.name = "720P", .width = 1280, .height = 720}, -+ {.name = "UXGA", .width = 1600, .height = 1200}, -+}; -+ -+ -+static struct sensor_info ov2643_sensor_info = { -+ .sensor_name = "ov2643", -+ .sensor_id = CAMERA_OV2643_ID, -+ .ctrls = ov2643_ctrls, -+ .nr_ctrls = ARRAY_SIZE(ov2643_ctrls), -+ .formats = ov2643_formats, -+ .num_formats = ARRAY_SIZE(ov2643_formats), -+ .resolution = ov2643_win, -+ .num_resolution = ARRAY_SIZE(ov2643_win), -+ .handler = &ov2643_function_handler, -+}; -+ -+static int ov2643_module_init(void) -+{ -+ return register_sensor(&ov2643_sensor_info); -+} -+module_init(ov2643_module_init) -+#endif -+ -+#endif -+ -+ -diff --git a/drivers/media/video/plat-anyka/camera_ov2643.h b/drivers/media/video/plat-anyka/camera_ov2643.h -new file mode 100755 -index 00000000..4f1f96a8 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov2643.h -@@ -0,0 +1,1216 @@ -+/** -+ * @file camera_ov2643.h -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-10-26 -+ * @version 1.0 -+ * @ref -+ */ -+#ifndef __CAMERA_OV2643_H__ -+#define __CAMERA_OV2643_H__ -+ -+ -+#if defined (USE_CAMERA_OV2643) || defined (CONFIG_SENSOR_OV2643) -+ -+#undef DELAY_FLAG -+#undef END_FLAG -+#define DELAY_FLAG 0xfd // first parameter is 0xfe, then 2nd parameter is delay time count -+#define END_FLAG 0xfe // first parameter is 0xff, then parameter table is over -+ -+static const T_U8 INIT_TAB[] = -+{ -+ //640*480, mclk 24mhz, pclk 72mhz, 30fps -+ 0x12, 0x80, -+ 0xc3, 0x1f, -+ 0xc4, 0xff, -+ 0x3d, 0x48, -+ 0xdd, 0xa5, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x98, -+ 0x22, 0x00, -+ 0x23, 0x06, -+ 0x24, 0x28,//0x280=640 -+ 0x25, 0x04, -+ 0x26, 0x1e,//0x1e0=480 -+ 0x27, 0x04, -+ 0x28, 0x40, -+ -+ //format setting -+ 0x12, 0x09, -+ 0x39, 0xd0, -+ 0xcd, 0x13, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x14, -+ 0x10, 0x0a, -+ 0x11, 0x00, -+ 0x29, 0x07,//dummy pixels -+ 0x2a, 0x93, -+ 0x2b, 0x02,//dummy lines -+ 0x2c, 0x6a, -+ 0x1d, 0x03, -+ 0x1e, 0x00, -+ 0x1f, 0xb9, -+ -+ 0x13, 0xff, -+ 0x14, 0xa7, -+ 0x15, 0x42, -+ 0x3c, 0xa4, -+ 0x18, 0x60, -+ 0x19, 0x50, -+ 0x1a, 0xe2, -+ 0x37, 0xe8, -+ 0x16, 0x90, -+ 0x43, 0x00, -+ 0x40, 0xfb, -+ 0xa9, 0x44, -+ 0x2f, 0xec, -+ 0x35, 0x10, -+ 0x36, 0x10, -+ 0x0c, 0x00, -+ 0x0d, 0x20, -+ 0xd0, 0x93, -+ 0xdc, 0x2b, -+ 0xd9, 0x41, -+ 0xd3, 0x02, -+ 0xde, 0x7c, -+ 0x3d, 0x08, -+ 0x0c, 0x00, -+ 0x18, 0x2c, -+ 0x19, 0x24, -+ 0x1a, 0x71, -+ 0x9b, 0x69, -+ 0x9c, 0x7d, -+ 0x9d, 0x7d, -+ 0x9e, 0x69, -+ 0x35, 0x04, -+ 0x36, 0x04, -+ //gamma -+ 0x65, 0x04, -+ 0x66, 0x07, -+ 0x67, 0x19, -+ 0x68, 0x34, -+ 0x69, 0x4a, -+ 0x6a, 0x5a, -+ 0x6b, 0x67, -+ 0x6c, 0x71, -+ 0x6d, 0x7c, -+ 0x6e, 0x8c, -+ 0x6f, 0x9b, -+ 0x70, 0xa9, -+ 0x71, 0xc0, -+ 0x72, 0xd5, -+ 0x73, 0xe8, -+ 0x74, 0x20, -+ //color matrix -+ 0xab, 0x28, -+ 0xac, 0x48, -+ 0xad, 0x10, -+ 0xae, 0x12, -+ 0xaf, 0x76, -+ 0xb0, 0x88, -+ 0xb1, 0x80, -+ 0xb2, 0x88, -+ 0xb3, 0x08, -+ 0xb4, 0x98, -+ 0xb5, 0x00, -+ //lens shading -+ 0x40, 0xfb, -+ 0x4c, 0x03, -+ 0x4d, 0x40, -+ 0x4e, 0x02, -+ 0x4f, 0x63, -+ 0x50, 0x44, -+ 0x51, 0x20, -+ 0x52, 0x66, -+ 0x53, 0x03, -+ 0x54, 0x34, -+ 0x55, 0x02, -+ 0x56, 0x5c, -+ 0x57, 0x38, -+ 0x58, 0x00, -+ 0x59, 0x66, -+ 0x5a, 0x03, -+ 0x5b, 0x20, -+ 0x5c, 0x02, -+ 0x5d, 0x5c, -+ 0x5e, 0x36, -+ 0x5f, 0x00, -+ 0x60, 0x66, -+ 0x41, 0x1f, -+ 0xb6, 0x02, -+ 0xb9, 0x40, -+ 0xba, 0x28, -+ 0xbf, 0x0c, -+ 0xc0, 0x3e, -+ 0xa3, 0x0a, -+ 0xa4, 0x0f, -+ 0xa5, 0x10, -+ 0xa6, 0x16, -+ 0x9f, 0x0a, -+ 0xa0, 0x0f, -+ 0xa7, 0x0a, -+ 0xa8, 0x0f, -+ 0xa1, 0x18, -+ 0xa2, 0x10, -+ 0xa9, 0x00, -+ 0xaa, 0xa6, -+ //awb -+ 0x75, 0x68, -+ 0x76, 0x11, -+ 0x77, 0x92, -+ 0x78, 0x21, -+ 0x79, 0xe1, -+ 0x7a, 0x02, -+ 0x7c, 0x0e, -+ 0x7d, 0x12, -+ 0x7e, 0x12, -+ 0x7f, 0x54, -+ 0x80, 0x78, -+ 0x81, 0xa2, -+ 0x82, 0x80, -+ 0x83, 0x4e, -+ 0x84, 0x40, -+ 0x85, 0x4c, -+ 0x86, 0x53, -+ 0x87, 0xf8, -+ 0x88, 0x08, -+ 0x89, 0x70, -+ 0x8a, 0xf0, -+ 0x8b, 0xf0, -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 UXGA_MODE_TAB[] = -+{ -+#if 1 -+ //1600*1200, mclk 24mhz, pclk 72mhz, 15fps, with no lcd -+ 0x3d, 0x48, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x25, -+ 0x22, 0x00, -+ 0x23, 0x0c, -+ 0x24, 0x64, //0x640=1600 -+ 0x25, 0x08, -+ 0x26, 0x4b, //0x4b0=1200 -+ 0x27, 0x06, -+ 0x28, 0x42, -+ //format setting -+ 0x12, 0x08, -+ 0x39, 0x10, -+ 0xcd, 0x12, -+ -+ 0x3d, 0x08, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x14, -+ 0x10, 0x0a, -+ 0x11, 0x00, -+ 0x29, 0x07, //dummy pixels -+ 0x2a, 0x93, -+ 0x2b, 0x04, //dummy lines -+ 0x2c, 0xd4, -+ 0x1d, 0x06, //banding -+ 0x1e, 0x00, -+ 0x1f, 0xb9, -+ //other setting -+ 0xde, 0xc4, -+#else -+ //1600*1200, mclk 24mhz, pclk 36mhz, 7.5fps -+ 0x3d, 0x48, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x25, -+ 0x22, 0x00, -+ 0x23, 0x0c, -+ 0x24, 0x64, -+ 0x25, 0x08, -+ 0x26, 0x4b, -+ 0x27, 0x06, -+ 0x28, 0x42, -+ //format setting -+ 0x12, 0x08, -+ 0x39, 0x10, -+ 0xcd, 0x12, -+ -+ 0x3d, 0x08, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x14, -+ 0x10, 0x0a, -+ 0x11, 0x01, -+ 0x29, 0x07, //dummy pixels -+ 0x2a, 0x93, -+ 0x2b, 0x04, //dummy lines -+ 0x2c, 0xd4, -+ 0x1d, 0x0c, //banding -+ 0x1e, 0x00, -+ 0x1f, 0x5d, -+ //other setting -+ 0xde, 0xc4, -+#endif -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SXGA_MODE_TAB[] = -+{ -+ //1280*1024, mclk 24mhz, pclk 36mhz, 15fps -+ 0x3d, 0x48, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x25, -+ 0x22, 0x00, -+ 0x23, 0x0c, -+ 0x24, 0x50, //0x500=1280 -+ 0x25, 0x08, -+ 0x26, 0x40, //0x400=1024 -+ 0x27, 0x06, -+ 0x28, 0x42, -+ //format setting -+ 0x12, 0x08, -+ 0x39, 0x10, -+ 0xcd, 0x12, -+ -+ 0x3d, 0x08, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x14, -+ 0x10, 0x0a, -+ 0x11, 0x00, -+ 0x29, 0x07, //dummy pixels -+ 0x2a, 0x93, -+ 0x2b, 0x04, //dummy lines -+ 0x2c, 0xd4, -+ 0x1d, 0x06, //banding -+ 0x1e, 0x00, -+ 0x1f, 0xb9, -+ -+ //other setting -+ 0xde, 0xc4, -+ END_FLAG, END_FLAG -+}; -+ -+ -+ -+static const T_U8 VGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QVGA_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QCIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QQVGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 PREV_MODE_TAB[] = -+{ -+ //640*480, mclk 24mhz, pclk 72mhz, 30fps -+ 0x3d, 0x48, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x98, -+ 0x22, 0x00, -+ 0x23, 0x06, -+ 0x24, 0x28,//0x280=640 -+ 0x25, 0x04, -+ 0x26, 0x1e,//0x1e0=480 -+ 0x27, 0x04, -+ 0x28, 0x40, -+ //format setting -+ 0x12, 0x09, -+ 0x39, 0xd0, -+ 0xcd, 0x13, -+ 0x3d, 0x08, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x14, -+ 0x10, 0x0a, -+ 0x11, 0x00, -+ 0x29, 0x07,//dummy pixels -+ 0x2a, 0x93, -+ 0x2b, 0x02,//dummy lines -+ 0x2c, 0x6a, -+ 0x1d, 0x03, -+ 0x1e, 0x00, -+ 0x1f, 0xb9, -+ //other setting -+ 0xde, 0x7c, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 RECORD_MODE_TAB[] = -+{ -+ //640*480, mclk 24mhz, pclk 72mhz, 25fps -+ 0x12, 0x80, -+ 0xc3, 0x5F, -+ 0xc4, 0xff, -+ 0x3d, 0x48, -+ 0xdd, 0xa5, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x98, -+ 0x22, 0x00, -+ 0x23, 0x06, -+ 0x24, 0x28,//0x280=640 -+ 0x25, 0x04, -+ 0x26, 0x1e,//0x1e0=480 -+ 0x27, 0x04, -+ 0x28, 0x40, -+ //format setting -+ 0x12, 0x09, -+ 0x39, 0xd0, -+ 0xcd, 0x13, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x14, -+ 0x10, 0x0a, -+ 0x11, 0x00, -+ 0x29, 0x07,//dummy pixels -+ 0x2a, 0x93, -+ 0x2b, 0x02,//dummy lines -+ 0x2c, 0xe6, -+ 0x1d, 0x04, -+ 0x1e, 0x00, -+ 0x1f, 0xb9, -+ -+ 0x13, 0xff, -+ 0x14, 0xa7, -+ 0x15, 0x42, -+ 0x3c, 0xa4, -+ 0x18, 0x60, -+ 0x19, 0x50, -+ 0x1a, 0xe2, -+ 0x37, 0xe8, -+ 0x16, 0x90, -+ 0x43, 0x00, -+ 0x40, 0xfb, -+ 0xa9, 0x44, -+ 0x2f, 0xec, -+ 0x35, 0x10, -+ 0x36, 0x10, -+ 0x0c, 0x00, -+ 0x0d, 0x20, -+ 0xd0, 0x93, -+ 0xdc, 0x2b, -+ 0xd9, 0x41, -+ 0xd3, 0x02, -+ 0xde, 0x7c, -+ 0x3d, 0x08, -+ 0x0c, 0x00, -+ 0x18, 0x34, //3C, //2c, -+ 0x19, 0x2e, //34, //24, -+ 0x1a, 0x71, //82, //71, -+ 0x9b, 0x69, -+ 0x9c, 0x7d, -+ 0x9d, 0x7d, -+ 0x9e, 0x69, -+ 0x35, 0x04, -+ 0x36, 0x04, -+ //gamma -+ 0x65, 0x04, -+ 0x66, 0x07, -+ 0x67, 0x19, -+ 0x68, 0x34, -+ 0x69, 0x4a, -+ 0x6a, 0x5a, -+ 0x6b, 0x67, -+ 0x6c, 0x71, -+ 0x6d, 0x7c, -+ 0x6e, 0x8c, -+ 0x6f, 0x9b, -+ 0x70, 0xa9, -+ 0x71, 0xc0, -+ 0x72, 0xd5, -+ 0x73, 0xe8, -+ 0x74, 0x20, -+ //color matrix -+ 0xab, 0x28, -+ 0xac, 0x48, -+ 0xad, 0x10, -+ 0xae, 0x18, -+ 0xaf, 0x75, -+ 0xb0, 0x8c, -+ 0xb1, 0x8d, -+ 0xb2, 0x8c, -+ 0xb3, 0x00, -+ 0xb4, 0x98, -+ 0xb5, 0x00, -+ //lens shading -+ 0x40, 0xfb, -+ 0x4c, 0x02, -+ 0x4d, 0x90, -+ 0x4e, 0x01, -+ 0x4f, 0x8c, -+ 0x50, 0x55, -+ 0x51, 0x00, -+ 0x52, 0x66, -+ 0x53, 0x02, -+ 0x54, 0x78, -+ 0x55, 0x01, -+ 0x56, 0x70, -+ 0x57, 0x44, -+ 0x58, 0x20, -+ 0x59, 0x66, -+ 0x5a, 0x02, -+ 0x5b, 0x78, -+ 0x5c, 0x01, -+ 0x5d, 0x88, -+ 0x5e, 0x44, -+ 0x5f, 0x00, -+ 0x60, 0x66, -+ -+ 0x41, 0x1f, -+ 0xb6, 0x07, -+ 0xb9, 0x34,//3c saturation -+ 0xba, 0x28, -+ 0xb7, 0x90, -+ 0xb8, 0x08, -+ 0xbf, 0x0c, -+ 0xc0, 0x3e, -+ 0xa3, 0x0a, -+ 0xa4, 0x0f, -+ 0xa5, 0x10, -+ 0xa6, 0x16, -+ 0x9f, 0x0a, -+ 0xa0, 0x0f, -+ 0xa7, 0x0a, -+ 0xa8, 0x0f, -+ 0xa1, 0x18, -+ 0xa2, 0x10, -+ 0xa9, 0x00, -+ 0xaa, 0xa6, -+ //awb -+ 0x75, 0x68, -+ 0x76, 0x11, -+ 0x77, 0x92, -+ 0x78, 0xa1,//21 -+ 0x79, 0xe1, -+ 0x7a, 0x02, -+ 0x7c, 0x0e, -+ 0x7d, 0x12, -+ 0x7e, 0x12, -+ 0x7f, 0x54, -+ 0x80, 0x78, -+ 0x81, 0xa2, -+ 0x82, 0x80, -+ 0x83, 0x4e, -+ 0x84, 0x40, -+ 0x85, 0x4c, -+ 0x86, 0x43, -+ 0x87, 0xf8, -+ 0x88, 0x08, -+ 0x89, 0x70, -+ 0x8a, 0xf0, -+ 0x8b, 0xf0, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 RECORD_720P_TAB[] = -+{ -+#if 1 -+ //mclk 24mhz, pclk 72mhz, 25fps -+ 0x12, 0x80, -+ 0xc3, 0x1f, -+ 0xc4, 0xff, -+ 0x3d, 0x48, -+ 0xdd, 0xa5, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x25, -+ 0x22, 0x00, -+ 0x23, 0x0c, -+ 0x24, 0x50,//0x500=1280 -+ 0x25, 0x08, -+ 0x26, 0x2d,//0x2d0=720 -+ 0x27, 0x04, -+ -+ 0x28, 0x42, -+ //format setting -+ 0x12, 0x48, -+ 0x39, 0x10, -+ 0xcd, 0x12, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x14, -+ 0x10, 0x0a, -+ 0x11, 0x00, -+ 0x29, 0x06,//dummy pixels -+ 0x2a, 0x40, -+ 0x2b, 0x03,//dummy lines -+ 0x2c, 0x84, -+ 0x1d, 0x04, -+ 0x1e, 0x00, -+ 0x1f, 0xe1, -+ -+ 0x13, 0xff, -+ 0x14, 0xa7, -+ 0x15, 0x42, -+ 0x3c, 0xa4, -+ 0x18, 0x60, -+ 0x19, 0x50, -+ 0x1a, 0xe2, -+ 0x37, 0xe8, -+ 0x16, 0x90, -+ 0x43, 0x00, -+ 0x40, 0xfb, -+ 0xa9, 0x44, -+ 0x2f, 0xec, -+ 0x35, 0x10, -+ 0x36, 0x10, -+ 0x0c, 0x00, -+ 0x0d, 0x20, -+ 0xd0, 0x93, -+ 0xdc, 0x2b, -+ 0xd9, 0x41, -+ 0xd3, 0x02, -+ 0x3d, 0x08, -+ 0x0c, 0x00, -+ 0x18, 0x2c, -+ 0x19, 0x24, -+ 0x1a, 0x71, -+ 0x9b, 0x69, -+ 0x9c, 0x7d, -+ 0x9d, 0x7d, -+ 0x9e, 0x69, -+ 0x35, 0x04, -+ 0x36, 0x04, -+ //gamma0x -+ 0x65, 0x04, -+ 0x66, 0x07, -+ 0x67, 0x19, -+ 0x68, 0x34, -+ 0x69, 0x4a, -+ 0x6a, 0x5a, -+ 0x6b, 0x67, -+ 0x6c, 0x71, -+ 0x6d, 0x7c, -+ 0x6e, 0x8c, -+ 0x6f, 0x9b, -+ 0x70, 0xa9, -+ 0x71, 0xc0, -+ 0x72, 0xd5, -+ 0x73, 0xe8, -+ 0x74, 0x20, -+ //color matrix -+ 0xab, 0x28, -+ 0xac, 0x48, -+ 0xad, 0x10, -+ 0xae, 0x18, -+ 0xaf, 0x75, -+ 0xb0, 0x8c, -+ 0xb1, 0x8d, -+ 0xb2, 0x8c, -+ 0xb3, 0x00, -+ 0xb4, 0x98, -+ 0xb5, 0x00, -+ //lens shading -+ 0x40, 0xfb, -+ 0x4c, 0x02, -+ 0x4d, 0x90, -+ 0x4e, 0x01, -+ 0x4f, 0x78, -+ 0x50, 0x54, -+ 0x51, 0x28, -+ 0x52, 0x66, -+ 0x53, 0x02, -+ 0x54, 0x92, -+ 0x55, 0x01, -+ 0x56, 0x70, -+ 0x57, 0x44, -+ 0x58, 0x20, -+ 0x59, 0x66, -+ 0x5a, 0x02, -+ 0x5b, 0x90, -+ 0x5c, 0x01, -+ 0x5d, 0x88, -+ 0x5e, 0x44, -+ 0x5f, 0x00, -+ 0x60, 0x66, -+ -+ 0x41, 0x1f, -+ 0xb6, 0x07, -+ 0xb9, 0x34,//3c saturation -+ 0xba, 0x28, -+ 0xb7, 0x90, -+ 0xb8, 0x08, -+ 0xbf, 0x0c, -+ 0xc0, 0x3e, -+ 0xa3, 0x0a, -+ 0xa4, 0x0f, -+ 0xa5, 0x10, -+ 0xa6, 0x16, -+ 0x9f, 0x0a, -+ 0xa0, 0x0f, -+ 0xa7, 0x0a, -+ 0xa8, 0x0f, -+ 0xa1, 0x18, -+ 0xa2, 0x10, -+ 0xa9, 0x00, -+ 0xaa, 0xa6, -+ //awb -+ 0x75, 0x68, -+ 0x76, 0x11, -+ 0x77, 0x92, -+ 0x78, 0xa1, //21 -+ 0x79, 0xe1, -+ 0x7a, 0x02, -+ 0x7c, 0x0e, -+ 0x7d, 0x12, -+ 0x7e, 0x12, -+ 0x7f, 0x54, -+ 0x80, 0x78, -+ 0x81, 0xa2, -+ 0x82, 0x80, -+ 0x83, 0x4e, -+ 0x84, 0x40, -+ 0x85, 0x4c, -+ 0x86, 0x43, -+ 0x87, 0xf8, -+ 0x88, 0x08, -+ 0x89, 0x70, -+ 0x8a, 0xf0, -+ 0x8b, 0xf0, -+#else -+ //mclk 24mhz, pclk 48mhz, 20fps -+ 0x12, 0x80, -+ 0xc3, 0x5F, -+ 0xc4, 0xff, -+ 0x3d, 0x48, -+ 0xdd, 0xa5, -+ //windows setup -+ 0x20, 0x01, -+ 0x21, 0x25, -+ 0x22, 0x00, -+ 0x23, 0x0c, -+ 0x24, 0x50,//0x500=1280 -+ 0x25, 0x08, -+ 0x26, 0x2d,//0x2d0=720 -+ 0x27, 0x04, -+ 0x28, 0x42, -+ //format setting -+ 0x12, 0x48, -+ 0x39, 0x10, -+ 0xcd, 0x12, -+ //frame setting -+ 0x0e, 0x10, -+ 0x0f, 0x24, -+ 0x10, 0x0a, -+ 0x11, 0x82, -+ 0x29, 0x06,//dummy pixels -+ 0x2a, 0x40, -+ 0x2b, 0x02,//dummy lines -+ 0x2c, 0xee, -+ 0x1d, 0x05, -+ 0x1e, 0x00, -+ 0x1f, 0x96, -+ -+ 0x13, 0xff, -+ 0x14, 0xa7, -+ 0x15, 0x42, -+ 0x3c, 0xa4, -+ 0x18, 0x60, -+ 0x19, 0x50, -+ 0x1a, 0xe2, -+ 0x37, 0xe8, -+ 0x16, 0x90, -+ 0x43, 0x00, -+ 0x40, 0xfb, -+ 0xa9, 0x44, -+ 0x2f, 0xec, -+ 0x35, 0x10, -+ 0x36, 0x10, -+ 0x0c, 0x00, -+ 0x0d, 0x20, -+ 0xd0, 0x93, -+ 0xdc, 0x2b, -+ 0xd9, 0x41, -+ 0xd3, 0x02, -+ 0x3d, 0x08, -+ 0x0c, 0x00, -+ 0x18, 0x2c, -+ 0x19, 0x24, -+ 0x1a, 0x71, -+ 0x9b, 0x69, -+ 0x9c, 0x7d, -+ 0x9d, 0x7d, -+ 0x9e, 0x69, -+ 0x35, 0x04, -+ 0x36, 0x04, -+ //gamma -+ 0x65, 0x04, -+ 0x66, 0x07, -+ 0x67, 0x19, -+ 0x68, 0x34, -+ 0x69, 0x4a, -+ 0x6a, 0x5a, -+ 0x6b, 0x67, -+ 0x6c, 0x71, -+ 0x6d, 0x7c, -+ 0x6e, 0x8c, -+ 0x6f, 0x9b, -+ 0x70, 0xa9, -+ 0x71, 0xc0, -+ 0x72, 0xd5, -+ 0x73, 0xe8, -+ 0x74, 0x20, -+ //color matrix -+ 0xab, 0x28, -+ 0xac, 0x48, -+ 0xad, 0x10, -+ 0xae, 0x18, -+ 0xaf, 0x75, -+ 0xb0, 0x8c, -+ 0xb1, 0x8d, -+ 0xb2, 0x8c, -+ 0xb3, 0x00, -+ 0xb4, 0x98, -+ 0xb5, 0x00, -+ //lens shading -+ 0x40, 0xFB, -+ 0x4c, 0x02, -+ 0x4d, 0x90, -+ 0x4e, 0x01, -+ 0x4f, 0x78, -+ 0x50, 0x54, -+ 0x51, 0x28, -+ 0x52, 0x66, -+ 0x53, 0x02, -+ 0x54, 0x92, -+ 0x55, 0x01, -+ 0x56, 0x70, -+ 0x57, 0x44, -+ 0x58, 0x20, -+ 0x59, 0x66, -+ 0x5a, 0x02, -+ 0x5b, 0x90, -+ 0x5c, 0x01, -+ 0x5d, 0x88, -+ 0x5e, 0x44, -+ 0x5f, 0x00, -+ 0x60, 0x66, -+ -+ 0x41, 0x1f, -+ 0xb6, 0x07, -+ 0xb9, 0x34,//3c saturation -+ 0xba, 0x28, -+ 0xb7, 0x90, -+ 0xb8, 0x08, -+ 0xbf, 0x0c, -+ 0xc0, 0x3e, -+ 0xa3, 0x0a, -+ 0xa4, 0x0f, -+ 0xa5, 0x10, -+ 0xa6, 0x16, -+ 0x9f, 0x0a, -+ 0xa0, 0x0f, -+ 0xa7, 0x0a, -+ 0xa8, 0x0f, -+ 0xa1, 0x18, -+ 0xa2, 0x10, -+ 0xa9, 0x00, -+ 0xaa, 0xa6, -+ //awb -+ 0x75, 0x68, -+ 0x76, 0x11, -+ 0x77, 0x92, -+ 0x78, 0xa1,//21 -+ 0x79, 0xe1, -+ 0x7a, 0x02, -+ 0x7c, 0x0e, -+ 0x7d, 0x12, -+ 0x7e, 0x12, -+ 0x7f, 0x54, -+ 0x80, 0x78, -+ 0x81, 0xa2, -+ 0x82, 0x80, -+ 0x83, 0x4e, -+ 0x84, 0x40, -+ 0x85, 0x4c, -+ 0x86, 0x43, -+ 0x87, 0xf8, -+ 0x88, 0x08, -+ 0x89, 0x70, -+ 0x8a, 0xf0, -+ 0x8b, 0xf0, -+#endif -+ END_FLAG, END_FLAG -+}; -+ -+ -+/**************** Camera Exposure Table ****************/ -+static const T_U8 EXPOSURE_WHOLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_CENTER_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_MIDDLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Brightness Table ****************/ -+static const T_U8 BRIGHTNESS_0_TAB[] = -+{ -+ //Brightness -3 -+ 0xbd, 0x30, -+ 0xbe, 0x08, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_1_TAB[] = -+{ -+ //Brightness -2 -+ 0xbd, 0x20, -+ 0xbe, 0x08, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_2_TAB[] = -+{ -+ //Brightness -1 -+ 0xbd, 0x10, -+ 0xbe, 0x08, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_3_TAB[] = -+{ -+ //Brightness 0 -+ 0xbd, 0x00, -+ 0xbe, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_4_TAB[] = -+{ -+ //Brightness +1 -+ 0xbd, 0x10, -+ 0xbe, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_5_TAB[] = -+{ -+ //Brightness +2 -+ 0xbd, 0x20, -+ 0xbe, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_6_TAB[] = -+{ -+ //Brightness +3 -+ 0xbd, 0x30, -+ 0xbe, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Contrast Table ****************/ -+static const T_U8 CONTRAST_1_TAB[] = -+{ -+ //Contrast -3 -+ 0xbb, 0x14, -+ 0xbc, 0x14, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_2_TAB[] = -+{ -+ //Contrast -2 -+ 0xbb, 0x18, -+ 0xbc, 0x18, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_3_TAB[] = -+{ -+ //Contrast -1 -+ 0xbb, 0x1c, -+ 0xbc, 0x1c, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_4_TAB[] = -+{ -+ //Contrast 0 -+ 0xbb, 0x20, -+ 0xbc, 0x20, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_5_TAB[] = -+{ -+ //Contrast +1 -+ 0xbb, 0x24, -+ 0xbc, 0x24, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_6_TAB[] = -+{ -+ //Contrast +2 -+ 0xbb, 0x28, -+ 0xbc, 0x28, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_7_TAB[] = -+{ -+ //Contrast +3 -+ 0xbb, 0x2c, -+ 0xbc, 0x2c, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Saturation Table ****************/ -+static const T_U8 SATURATION_1_TAB[] = -+{ -+ //Saturation -2(0.5x) -+ 0xb9, 0x20, -+ 0xba, 0x20, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_2_TAB[] = -+{ -+ //Saturation -1(0.75x) -+ 0xb9, 0x30, -+ 0xba, 0x30, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_3_TAB[] = -+{ -+ //Saturation -+ 0xb9, 0x40, -+ 0xba, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_4_TAB[] = -+{ -+ //Saturation +1(1.25x) -+ 0xb9, 0x50, -+ 0xba, 0x50, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_5_TAB[] = -+{ -+ //Saturation +2(1.75x) -+ 0xb9, 0x70, -+ 0xba, 0x70, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Sharpness Table ****************/ -+static const T_U8 SHARPNESS_0_TAB[] = -+{ -+ //Sharpness -2 -+ 0xa1, 0x10, -+ 0xa2, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_1_TAB[] = -+{ -+ //Sharpness -1 -+ 0xa1, 0x14, -+ 0xa2, 0x02, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_2_TAB[] = -+{ -+ //Sharpness default -+ 0xa1, 0x18, -+ 0xa2, 0x04, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_3_TAB[] = -+{ -+ //Sharpness +1 -+ 0xa1, 0x1c, -+ 0xa2, 0x08, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_4_TAB[] = -+{ -+ //Sharpness +2 -+ 0xa1, 0x1f, -+ 0xa2, 0x0c, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_5_TAB[] = -+{ -+ //Sharpness auto -+ 0x9f, 0x0a, -+ 0xa0, 0x0f, -+ 0xa7, 0x0a, -+ 0xa8, 0x0f, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera AWB Table ****************/ -+static const T_U8 AWB_AUTO_TAB[] = -+{ -+ 0x13, 0xff, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_SUNNY_TAB[] = -+{ -+ /*0x13, 0xfb, -+ 0x05, 0x5e, -+ 0x06, 0x41, -+ 0x07, 0x54, -+ 0x08, 0x00, -+ 0x09, 0x00,*/ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_CLOUDY_TAB[] = -+{ -+ /*0x13, 0xfb, -+ 0x05, 0x65, -+ 0x06, 0x41, -+ 0x07, 0x4f, -+ 0x08, 0x00, -+ 0x09, 0x00,*/ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_OFFICE_TAB[] = -+{ -+ /*0x13, 0xfb, -+ 0x05, 0x52, -+ 0x06, 0x41, -+ 0x07, 0x66, -+ 0x08, 0x00, -+ 0x09, 0x00,*/ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_HOME_TAB[] = -+{ -+ /*0x13, 0xfb, -+ 0x05, 0x42, -+ 0x06, 0x3f, -+ 0x07, 0x71, -+ 0x08, 0x00, -+ 0x09, 0x00,*/ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Effect Table ****************/ -+static const T_U8 EFFECT_NORMAL_TAB[] = -+{ -+ //0xb6, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_SEPIA_TAB[] = -+{ -+ //0xb6, 0x18, -+ //0xb9, 0x40, -+ //0xba, 0xa0, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_ANTIQUE_TAB[] = -+{ -+ //0xb6, 0x18, -+ //0xb9, 0x40, -+ //0xba, 0xa0, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BLUISH_TAB[] = -+{ -+ //0xb6, 0x18, -+ //0xb9, 0xa0, -+ //0xba, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_GREENISH_TAB[] = -+{ -+ //0xb6, 0x18, -+ //0xb9, 0x60, -+ //0xba, 0x60, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_REDDISH_TAB[] = -+{ -+ //0xb6, 0x18, -+ //0xb9, 0x80, -+ //0xba, 0xc0, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_NEGATIVE_TAB[] = -+{ -+ //0xb6, 0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BW_TAB[] = -+{ -+ //0xb6, 0x20, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera night/day mode ****************/ -+static const T_U8 DAY_MODE_TAB[] = -+{ -+ //0x14, 0xa0, -+ //0x2e, 0x00, -+ //0x2d, 0x00, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 NIGHT_MODE_TAB[] = -+{ -+ //0x0e, 0xb8, -+ //0x0f, 0x14, -+ //0x14, 0xad, -+ END_FLAG, END_FLAG -+}; -+#endif -+#endif -diff --git a/drivers/media/video/plat-anyka/camera_ov2710.c b/drivers/media/video/plat-anyka/camera_ov2710.c -new file mode 100755 -index 00000000..dd8b73d5 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov2710.c -@@ -0,0 +1,1005 @@ -+/** -+ * @file camera_hm1375.c -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-09-21 -+ * @version 1.0 -+ * @ref -+ */ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/cam_com_sensor.h> -+#include "camera_ov2710.h" -+#else -+#include "akdefine.h" -+#include "cam_com_sensor.h" -+#include "camera_ov2710.h" -+#include "Gpio_config.h" -+#endif -+ -+#if defined (USE_CAMERA_OV2710) || defined (CONFIG_SENSOR_OV2710) -+ -+#define CAM_EN_LEVEL 0 -+#define CAM_RESET_LEVEL 0 -+ -+#define CAMERA_SCCB_ADDR 0x6c -+ -+#define CAMERA_OV2710_ID 0x2710 -+ -+#define OV2710_CAMERA_MCLK 24 -+ -+static T_CAMERA_TYPE camera_ov2710_type = CAMERA_2M; -+static T_NIGHT_MODE night_mode = CAMERA_DAY_MODE; -+static T_CAMERA_MODE s_ov2710_CurMode = CAMERA_MODE_VGA; -+ -+#if 0 -+static T_VOID camera_setbit(T_U16 reg, T_U8 bit, T_U8 value) -+{ -+ T_U8 tmp; -+ -+ tmp = sccb_read_short(CAMERA_SCCB_ADDR, reg); -+ if (value == 1) -+ { -+ tmp |= 0x1 << bit; -+ } -+ else -+ { -+ tmp &= ~(0x1 << bit); -+ } -+ -+ sccb_write_short(CAMERA_SCCB_ADDR, reg, &tmp, 1); -+} -+#endif -+static T_U32 cam_ov2710_read_id(T_VOID); -+ -+static T_BOOL camera_set_param(const T_U16 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 temp_value; -+ T_U8 data; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ data = tabParameter[i + 1]; -+ sccb_write_short(CAMERA_SCCB_ADDR, tabParameter[i], &data, 1); -+ -+ if ((tabParameter[i] != 0x0000) || (tabParameter[i] != 0x0022) -+ || (tabParameter[i] != 0x0100) || (tabParameter[i] != 0x0101)) -+ { -+ temp_value = sccb_read_short(CAMERA_SCCB_ADDR, tabParameter[i]); -+ if (temp_value != tabParameter[i + 1]) -+ { -+ akprintf(C1, M_DRVSYS, "set parameter error!\n"); -+ akprintf(C1, M_DRVSYS, "reg 0x%x write data is 0x%x, read data is 0x%x!\n", tabParameter[i], tabParameter[i + 1], temp_value); -+ -+ return AK_FALSE; -+ } -+ } -+ } -+ -+ i += 2; -+ } -+ -+ return AK_TRUE; -+} -+ -+static T_VOID camera_setup(const T_U16 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 data; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ data = tabParameter[i + 1]; -+ sccb_write_short(CAMERA_SCCB_ADDR, tabParameter[i], &data, 1); -+ -+ //printk("0x%04x, 0x%02x, 0x%02x\n", tabParameter[i], data, sccb_read_short(CAMERA_SCCB_ADDR, tabParameter[i])); -+ } -+ i += 2; -+ } -+ -+} -+ -+static T_VOID cam_ov2710_open(T_VOID) -+{ -+ gpio_set_pin_dir(GPIO_CAMERA_AVDD, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_CHIP_ENABLE); -+ gpio_set_pin_dir(GPIO_CAMERA_CHIP_ENABLE, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, CAM_EN_LEVEL); -+ mini_delay(10); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_RESET); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, CAM_RESET_LEVEL); -+ mini_delay(10); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, !CAM_RESET_LEVEL); -+ -+ mini_delay(20); -+} -+ -+static T_BOOL cam_ov2710_close(T_VOID) -+{ -+ //sccb software standby mode -+// T_U8 Reg0x3d = 0x48; -+// T_U8 Reg0xc3 = 0x00; -+ -+// sccb_write_short(CAMERA_SCCB_ADDR, 0x3d, &Reg0x3d, 1); -+// sccb_write_short(CAMERA_SCCB_ADDR, 0xc3, &Reg0xc3, 1); -+ -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, !CAM_EN_LEVEL); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, !gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_INPUT); -+ -+ gpio_set_pin_dir(GPIO_I2C_SCL, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SCL, GPIO_LEVEL_LOW); -+ gpio_set_pin_dir(GPIO_I2C_SDA, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SDA, GPIO_LEVEL_LOW); -+ -+ return AK_TRUE; -+} -+ -+static T_U32 cam_ov2710_read_id(T_VOID) -+{ -+ T_U8 value = 0x00; -+ T_U32 id = 0; -+ -+ sccb_init(GPIO_I2C_SCL, GPIO_I2C_SDA); //init sccb first here!! -+ -+ value = sccb_read_short(CAMERA_SCCB_ADDR, 0x300a); -+ id = value << 8; -+ value = sccb_read_short(CAMERA_SCCB_ADDR, 0x300b); -+ id |= value; -+ -+ return id; -+} -+ -+/** -+ * @brief initialize the parameters of camera, should be done after reset and open camera to initialize -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @return T_BOOL -+ * @retval AK_TRUE if success, else AK_FALSE -+ */ -+static T_BOOL cam_ov2710_init(void) -+{ -+ if (!camera_set_param(INIT_TAB)) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ night_mode = CAMERA_DAY_MODE; -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief Set camera mode to specify image quality, SXGA/VGA/CIF etc -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mode mode value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_mode(T_CAMERA_MODE mode) -+{ -+ s_ov2710_CurMode = mode; -+ switch(mode) -+ { -+ case CAMERA_MODE_UXGA: -+ camera_setup(UXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_SXGA: -+ camera_setup(SXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_VGA: -+ camera_setup(VGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_CIF: -+ camera_setup(CIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QVGA: -+ camera_setup(QVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_QCIF: -+ camera_setup(QCIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QQVGA: -+ camera_setup(QQVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_PREV: -+ camera_setup(PREV_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_REC: -+ camera_setup(RECORD_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_720P: -+ camera_setup(RECORD_720P_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ default: -+ s_ov2710_CurMode = CAMERA_MODE_VGA; -+ akprintf(C1, M_DRVSYS, "set camera mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera exposure mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] exposure exposure mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_exposure(T_CAMERA_EXPOSURE exposure) -+{ -+ switch(exposure) -+ { -+ case EXPOSURE_WHOLE: -+ camera_setup(EXPOSURE_WHOLE_TAB); -+ break; -+ case EXPOSURE_CENTER: -+ camera_setup(EXPOSURE_CENTER_TAB); -+ break; -+ case EXPOSURE_MIDDLE: -+ camera_setup(EXPOSURE_MIDDLE_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set exposure parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera brightness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] brightness brightness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_brightness(T_CAMERA_BRIGHTNESS brightness) -+{ -+ switch(brightness) -+ { -+ case CAMERA_BRIGHTNESS_0: -+ camera_setup(BRIGHTNESS_0_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_1: -+ camera_setup(BRIGHTNESS_1_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_2: -+ camera_setup(BRIGHTNESS_2_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_3: -+ camera_setup(BRIGHTNESS_3_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_4: -+ camera_setup(BRIGHTNESS_4_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_5: -+ camera_setup(BRIGHTNESS_5_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_6: -+ camera_setup(BRIGHTNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set brightness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera contrast level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] contrast contrast value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_contrast(T_CAMERA_CONTRAST contrast) -+{ -+ switch(contrast) -+ { -+ case CAMERA_CONTRAST_1: -+ camera_setup(CONTRAST_1_TAB); -+ break; -+ case CAMERA_CONTRAST_2: -+ camera_setup(CONTRAST_2_TAB); -+ break; -+ case CAMERA_CONTRAST_3: -+ camera_setup(CONTRAST_3_TAB); -+ break; -+ case CAMERA_CONTRAST_4: -+ camera_setup(CONTRAST_4_TAB); -+ break; -+ case CAMERA_CONTRAST_5: -+ camera_setup(CONTRAST_5_TAB); -+ break; -+ case CAMERA_CONTRAST_6: -+ camera_setup(CONTRAST_6_TAB); -+ break; -+ case CAMERA_CONTRAST_7: -+ camera_setup(CONTRAST_7_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set contrast parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera saturation level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] saturation saturation value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_saturation(T_CAMERA_SATURATION saturation) -+{ -+ switch(saturation) -+ { -+ case CAMERA_SATURATION_1: -+ camera_setup(SATURATION_1_TAB); -+ break; -+ case CAMERA_SATURATION_2: -+ camera_setup(SATURATION_2_TAB); -+ break; -+ case CAMERA_SATURATION_3: -+ camera_setup(SATURATION_3_TAB); -+ break; -+ case CAMERA_SATURATION_4: -+ camera_setup(SATURATION_4_TAB); -+ break; -+ case CAMERA_SATURATION_5: -+ camera_setup(SATURATION_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set saturation parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera sharpness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] sharpness sharpness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_sharpness(T_CAMERA_SHARPNESS sharpness) -+{ -+ switch(sharpness) -+ { -+ case CAMERA_SHARPNESS_0: -+ camera_setup(SHARPNESS_0_TAB); -+ break; -+ case CAMERA_SHARPNESS_1: -+ camera_setup(SHARPNESS_1_TAB); -+ break; -+ case CAMERA_SHARPNESS_2: -+ camera_setup(SHARPNESS_2_TAB); -+ break; -+ case CAMERA_SHARPNESS_3: -+ camera_setup(SHARPNESS_3_TAB); -+ break; -+ case CAMERA_SHARPNESS_4: -+ camera_setup(SHARPNESS_4_TAB); -+ break; -+ case CAMERA_SHARPNESS_5: -+ camera_setup(SHARPNESS_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set sharpness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera AWB mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] awb AWB mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_AWB(T_CAMERA_AWB awb) -+{ -+ switch(awb) -+ { -+ case AWB_AUTO: -+ camera_setup(AWB_AUTO_TAB); -+ break; -+ case AWB_SUNNY: -+ camera_setup(AWB_SUNNY_TAB); -+ break; -+ case AWB_CLOUDY: -+ camera_setup(AWB_CLOUDY_TAB); -+ break; -+ case AWB_OFFICE: -+ camera_setup(AWB_OFFICE_TAB); -+ break; -+ case AWB_HOME: -+ camera_setup(AWB_HOME_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set AWB mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera mirror mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mirror mirror mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_mirror(T_CAMERA_MIRROR mirror) -+{ -+ switch(mirror) -+ { -+ case CAMERA_MIRROR_V: -+ break; -+ case CAMERA_MIRROR_H: -+ break; -+ case CAMERA_MIRROR_NORMAL: -+ break; -+ case CAMERA_MIRROR_FLIP: -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set mirror parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera effect mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] effect effect mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov2710_set_effect(T_CAMERA_EFFECT effect) -+{ -+ switch(effect) -+ { -+ case CAMERA_EFFECT_NORMAL: -+ camera_setup(EFFECT_NORMAL_TAB); -+ break; -+ case CAMERA_EFFECT_SEPIA: -+ camera_setup(EFFECT_SEPIA_TAB); -+ break; -+ case CAMERA_EFFECT_ANTIQUE: -+ camera_setup(EFFECT_ANTIQUE_TAB); -+ break; -+ case CAMERA_EFFECT_BLUE: -+ camera_setup(EFFECT_BLUISH_TAB); -+ break; -+ case CAMERA_EFFECT_GREEN: -+ camera_setup(EFFECT_GREENISH_TAB); -+ break; -+ case CAMERA_EFFECT_RED: -+ camera_setup(EFFECT_REDDISH_TAB); -+ break; -+ case CAMERA_EFFECT_NEGATIVE: -+ camera_setup(EFFECT_NEGATIVE_TAB); -+ break; -+ case CAMERA_EFFECT_BW: -+ camera_setup(EFFECT_BW_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set camer effect parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief set camera window -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] srcWidth window width -+ * @param[in] srcHeight window height -+ * @return T_S32 -+ * @retval 0 if error mode -+ * @retval 1 if success -+ * @retval -1 if failed -+ */ -+static T_S32 cam_ov2710_set_digital_zoom(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ return 1; -+} -+ -+static T_VOID cam_ov2710_set_night_mode(T_NIGHT_MODE mode) -+{ -+ switch(mode) -+ { -+ case CAMERA_DAY_MODE: -+ camera_setup(DAY_MODE_TAB); -+ night_mode = CAMERA_DAY_MODE; -+ break; -+ case CAMERA_NIGHT_MODE: -+ camera_setup(NIGHT_MODE_TAB); -+ night_mode = CAMERA_NIGHT_MODE; -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set night mode parameter error!\n"); -+ break; -+ } -+} -+ -+static T_BOOL cam_ov2710_set_to_cap(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_VGA; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 1024)) -+ { -+ Cammode = CAMERA_MODE_SXGA; -+ } -+ else if ((srcWidth <= 1600) && (srcHeight <= 1200)) -+ { -+ Cammode = CAMERA_MODE_UXGA; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "ov2710 unsupport %d & %d mode!\n", srcWidth, srcHeight); -+ return AK_FALSE; -+ } -+ -+ cam_ov2710_set_mode(Cammode); -+ cam_ov2710_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov2710_set_to_prev(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_ov2710_set_mode(CAMERA_MODE_PREV); -+ cam_ov2710_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov2710_set_to_record(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_REC; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "200W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_ov2710_set_mode(Cammode); -+ cam_ov2710_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_CAMERA_TYPE cam_ov2710_get_type(T_VOID) -+{ -+ return camera_ov2710_type; -+} -+ -+static T_VOID cam_ov2710_set_sensor_param(T_U32 cmd, T_U32 data) -+{ -+ T_U8 value; -+ -+ value = (T_U8)data; -+ sccb_write_short(CAMERA_SCCB_ADDR, (T_U16)cmd, &value, 1); -+} -+ -+static T_CAMERA_FUNCTION_HANDLER ov2710_function_handler = -+{ -+ OV2710_CAMERA_MCLK, -+ cam_ov2710_open, -+ cam_ov2710_close, -+ cam_ov2710_read_id, -+ cam_ov2710_init, -+ cam_ov2710_set_mode, -+ cam_ov2710_set_exposure, -+ cam_ov2710_set_brightness, -+ cam_ov2710_set_contrast, -+ cam_ov2710_set_saturation, -+ cam_ov2710_set_sharpness, -+ cam_ov2710_set_AWB, -+ cam_ov2710_set_mirror, -+ cam_ov2710_set_effect, -+ cam_ov2710_set_digital_zoom, -+ cam_ov2710_set_night_mode, -+ AK_NULL, -+ AK_NULL, -+ cam_ov2710_set_to_cap, -+ cam_ov2710_set_to_prev, -+ cam_ov2710_set_to_record, -+ cam_ov2710_get_type, -+ cam_ov2710_set_sensor_param -+}; -+ -+#ifndef CONFIG_LINUX_AKSENSOR -+static int camera_ov2710_reg(void) -+{ -+ camera_reg_dev(CAMERA_OV2710_ID, &ov2710_function_handler); -+ return 0; -+} -+ -+#ifdef __CC_ARM -+#pragma arm section rwdata = "__initcall_", zidata = "__initcall_" -+#endif -+module_init(camera_ov2710_reg) -+#ifdef __CC_ARM -+#pragma arm section -+#endif -+ -+#else -+static const char * awb_menu[] = { -+ [AWB_AUTO] = "auto", -+ [AWB_SUNNY] = "sunny", -+ [AWB_CLOUDY] = "cloudy", -+ [AWB_OFFICE] = "office", -+ [AWB_HOME] = "home", -+ [AWB_NIGHT] = "night", -+}; -+ -+static const char * effect_menu[] = { -+ [CAMERA_EFFECT_NORMAL] = "normal", -+ [CAMERA_EFFECT_SEPIA] = "sepia", -+ [CAMERA_EFFECT_ANTIQUE] = "antique", -+ [CAMERA_EFFECT_BLUE] = "blue", -+ [CAMERA_EFFECT_GREEN] = "green", -+ [CAMERA_EFFECT_RED] = "red", -+ [CAMERA_EFFECT_NEGATIVE] = "negative", -+ [CAMERA_EFFECT_BW] = "bw", -+ [CAMERA_EFFECT_BWN] = "bwn", -+ [CAMERA_EFFECT_AQUA] = "aqua", -+ [CAMERA_EFFECT_COOL] = "cool", -+ [CAMERA_EFFECT_WARM] = "warm", -+}; -+ -+static const char * resolution_menu[] = { -+ [0] = "1920x1080", -+ [1] = "1280x720", -+ [2] = "640x480", -+ [3] = "320x240", -+}; -+ -+static const char * hflip_menu[] = { -+ [0] = "normal", -+ [1] = "horizontal flip", -+}; -+ -+static const char * vflip_menu[] = { -+ [0] = "normal", -+ [1] = "vertical flip", -+}; -+ -+static const char * night_menu[] = { -+ [CAMERA_DAY_MODE] = "daylight", -+ [CAMERA_NIGHT_MODE] = "night", -+}; -+ -+static int ov2710_s_ctl(struct v4l2_ctrl *ctrl) -+{ -+ int ret = -EINVAL; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ if (ov2710_function_handler.cam_set_AWB_func) { -+ ov2710_function_handler.cam_set_AWB_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_COLORFX: -+ if (ov2710_function_handler.cam_set_effect_func) { -+ ov2710_function_handler.cam_set_effect_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ -+ case V4L2_CID_BRIGHTNESS: -+ if (ov2710_function_handler.cam_set_brightness_func) { -+ ov2710_function_handler.cam_set_brightness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_CONTRAST: -+ if (ov2710_function_handler.cam_set_contrast_func) { -+ ov2710_function_handler.cam_set_contrast_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SATURATION: -+ if (ov2710_function_handler.cam_set_saturation_func) { -+ ov2710_function_handler.cam_set_saturation_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SHARPNESS: -+ if (ov2710_function_handler.cam_set_sharpness_func) { -+ ov2710_function_handler.cam_set_sharpness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_HFLIP: -+ if (ov2710_function_handler.cam_set_mirror_func) { -+ ov2710_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_H : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_VFLIP: -+ if (ov2710_function_handler.cam_set_mirror_func) { -+ ov2710_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_V : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_NIGHTMODE: -+ if (ov2710_function_handler.cam_set_night_mode_func) { -+ ov2710_function_handler.cam_set_night_mode_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+}; -+ -+static struct v4l2_ctrl_ops ov2710_ctrl_ops = { -+ .s_ctrl = ov2710_s_ctl, -+}; -+ -+static const struct v4l2_ctrl_config ov2710_ctrls[] = { -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_AUTO_WHITE_BALANCE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "AWB", -+ .min = 0, -+ .max = ARRAY_SIZE(awb_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = awb_menu, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_COLORFX, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Effect", -+ .min = 0, -+ .max = ARRAY_SIZE(effect_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = effect_menu, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Horizontal Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(hflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = hflip_menu, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Vetical Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(vflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = vflip_menu, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_PICTURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Resolution", -+ .min = 0, -+ .max = ARRAY_SIZE(resolution_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = resolution_menu, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_NIGHTMODE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Night mode", -+ .min = 0, -+ .max = ARRAY_SIZE(night_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = night_menu, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_BRIGHTNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Brightness", -+ .min = 0, -+ .max = CAMERA_BRIGHTNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .min = 0, -+ .max = CAMERA_CONTRAST_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .min = 0, -+ .max = CAMERA_SATURATION_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov2710_ctrl_ops, -+ .id = V4L2_CID_SHARPNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Sharpness", -+ .min = 0, -+ .max = CAMERA_SHARPNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ } -+}; -+ -+ -+/* -+ * supported format list -+ */ -+static const struct aksensor_color_format ov2710_formats[] = { -+ { -+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+}; -+ -+static const struct aksensor_win_size ov2710_win[] = { -+ {.name = "QVGA", .width = 320, .height = 240}, -+ {.name = "VGA", .width = 640, .height = 480}, -+ {.name = "720P", .width = 1280, .height = 720}, -+ {.name = "1080P", .width = 1920, .height = 1080}, -+}; -+ -+ -+static struct sensor_info ov2710_sensor_info = { -+ .sensor_name = "ov2710", -+ .sensor_id = CAMERA_OV2710_ID, -+ .ctrls = ov2710_ctrls, -+ .nr_ctrls = ARRAY_SIZE(ov2710_ctrls), -+ .formats = ov2710_formats, -+ .num_formats = ARRAY_SIZE(ov2710_formats), -+ .resolution = ov2710_win, -+ .num_resolution = ARRAY_SIZE(ov2710_win), -+ .handler = &ov2710_function_handler, -+}; -+ -+static int ov2710_module_init(void) -+{ -+ return register_sensor(&ov2710_sensor_info); -+} -+module_init(ov2710_module_init) -+#endif -+ -+#endif -+ -+ -diff --git a/drivers/media/video/plat-anyka/camera_ov2710.h b/drivers/media/video/plat-anyka/camera_ov2710.h -new file mode 100755 -index 00000000..65646ef5 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov2710.h -@@ -0,0 +1,495 @@ -+/** -+ * @file camera_hm1375.h -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author wudaochao -+ * @date 2013-04-26 -+ * @version 1.0 -+ * @ref -+ */ -+#ifndef __CAMERA_OV2710_H__ -+#define __CAMERA_OV2710_H__ -+ -+ -+#if defined (USE_CAMERA_OV2710) || defined (CONFIG_SENSOR_OV2710) -+ -+#undef DELAY_FLAG -+#undef END_FLAG -+#define DELAY_FLAG 0xfd // first parameter is 0xfe, then 2nd parameter is delay time count -+#define END_FLAG 0xfe // first parameter is 0xff, then parameter table is over -+ -+static const T_U16 INIT_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 UXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 VGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QVGA_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QCIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 QQVGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 PREV_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 RECORD_MODE_TAB[] = -+{ -+ 0x3103, 0x03, -+ 0x3008, 0x82, //reset -+ 0x3017, 0x7f, -+ 0x3018, 0xfc, -+ 0x3706, 0x61, -+ 0x3712, 0x0c, -+ 0x3630, 0x6d, -+ 0x3801, 0xb4, -+ 0x3621, 0x04, -+ 0x3604, 0x60, -+ 0x3603, 0xa7, -+ 0x3631, 0x26, -+ 0x3600, 0x04, -+ 0x3620, 0x37, -+ 0x3623, 0x00, -+ 0x3702, 0x9e, -+ 0x3703, 0x74, -+ 0x3704, 0x10, -+ 0x370d, 0x0f, -+ 0x3713, 0x8b, -+ 0x3714, 0x74, -+ 0x3710, 0x9e, -+ 0x3801, 0xc4, -+ 0x3605, 0x05, -+ 0x3606, 0x12, -+ 0x302d, 0x90, -+ 0x370b, 0x40, -+ 0x3716, 0x31, -+ 0x380d, 0x74, -+ 0x5181, 0x20, -+ 0x518f, 0x00, -+ 0x4301, 0xff, -+ 0x4303, 0x00, -+ 0x3a00, 0x78, -+ 0x300f, 0x88, -+ 0x3011, 0x28, -+ 0x3a1a, 0x06, -+ 0x3a18, 0x00, -+ 0x3a19, 0x7a, -+ 0x3a13, 0x54, -+ 0x382e, 0x0f, -+ 0x381a, 0x1a, -+ //aec -+ 0x3a0f, 0x40, -+ 0x3a10, 0x38, -+ 0x3a1b, 0x48, -+ 0x3a1e, 0x30, -+ 0x3a11, 0x90, -+ 0x3a1f, 0x10, -+ -+ //VGA_binning(640*480) Reference Setting 24M MCLK 30fps -+ //window -+ 0x381c, 0x10, -+ 0x381d, 0x42, -+ 0x381e, 0x3, -+ 0x381f, 0xc8, -+ 0x3820, 0xa, -+ 0x3821, 0x29, -+ 0x3800, 0x2, -+ 0x3801, 0xd6, -+ 0x3802, 0x0, -+ 0x3803, 0x5, -+ 0x3804, 0x2, -+ 0x3805, 0x80, -+ 0x3806, 0x1, -+ 0x3807, 0xe0, -+ 0x3808, 0x2, -+ 0x3809, 0x80, -+ 0x380a, 0x1, -+ 0x380b, 0xe0, -+ 0x380c, 0xa, -+ 0x380d, 0x84, -+ 0x380e, 0x1, -+ 0x380f, 0xf0, -+ 0x3810, 0x8, -+ 0x3811, 0x2, -+ //timing -+ 0x3818, 0xe1, //flip on, mirror on -+ 0x3621, 0xd4, -+ 0x3622, 0x8, -+ 0x370d, 0x4f, -+ 0x401c, 0x4, -+ 0x3012, 0x1, -+ 0x300f, 0x88, -+ 0x3011, 0x28, -+ 0x3010, 0x10, -+ //banding -+ 0x3a0a, 0x12, -+ 0x3a0b, 0x99, -+ 0x3a08, 0xf, -+ 0x3a09, 0x80, -+ 0x3a0d, 0x01, -+ 0x3a0e, 0x00, -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 RECORD_720P_TAB[] = -+{ -+ 0x3103, 0x03, -+ 0x3008, 0x82, //reset -+ 0x3017, 0x7f, -+ 0x3018, 0xfc, -+ 0x3706, 0x61, -+ 0x3712, 0x0c, -+ 0x3630, 0x6d, -+ 0x3801, 0xb4, -+ 0x3621, 0x04, -+ 0x3604, 0x60, -+ 0x3603, 0xa7, -+ 0x3631, 0x26, -+ 0x3600, 0x04, -+ 0x3620, 0x37, -+ 0x3623, 0x00, -+ 0x3702, 0x9e, -+ 0x3703, 0x74, -+ 0x3704, 0x10, -+ 0x370d, 0x0f, -+ 0x3713, 0x8b, -+ 0x3714, 0x74, -+ 0x3710, 0x9e, -+ 0x3801, 0xc4, -+ 0x3605, 0x05, -+ 0x3606, 0x12, -+ 0x302d, 0x90, -+ 0x370b, 0x40, -+ 0x3716, 0x31, -+ 0x380d, 0x74, -+ 0x5181, 0x20, -+ 0x518f, 0x00, -+ 0x4301, 0xff, -+ 0x4303, 0x00, -+ 0x3a00, 0x78, -+ 0x300f, 0x88, -+ 0x3011, 0x28, -+ 0x3a1a, 0x06, -+ 0x3a18, 0x00, -+ 0x3a19, 0x7a, -+ 0x3a13, 0x54, -+ 0x382e, 0x0f, -+ 0x381a, 0x1a, -+ //aec -+ 0x3a0f, 0x40, -+ 0x3a10, 0x38, -+ 0x3a1b, 0x48, -+ 0x3a1e, 0x30, -+ 0x3a11, 0x90, -+ 0x3a1f, 0x10, -+ -+ //720p(1280*720) Reference Setting 24M MCLK 20fps -+ //window -+ 0x381c, 0x10, -+ 0x381d, 0xb8, -+ 0x381e, 0x2, -+ 0x381f, 0xdc, -+ 0x3820, 0xa, -+ 0x3821, 0x29, -+ 0x3800, 0x1, -+ 0x3801, 0xc4, -+ 0x3802, 0x0, -+ 0x3803, 0x09, -+ 0x3804, 0x5, -+ 0x3805, 0x0, -+ 0x3806, 0x2, -+ 0x3807, 0xd0, -+ 0x3808, 0x5, -+ 0x3809, 0x0, -+ 0x380a, 0x2, -+ 0x380b, 0xd0, -+ 0x380c, 0x7, -+ 0x380d, 0x0, -+ 0x380e, 0x2, -+ 0x380f, 0xe8, -+ 0x3810, 0x10, -+ 0x3811, 0x6, -+ //timing -+ 0x3818, 0xe0, //flip on, mirror on -+ 0x3621, 0x14, -+ 0x3622, 0x8, -+ 0x370d, 0xf, -+ 0x401c, 0x8, -+ 0x3012, 0x1, -+ 0x300f, 0x88, -+ 0x3011, 0x28, -+ 0x3010, 0x20, -+ //banding -+ 0x3a0a, 0x9, -+ 0x3a0b, 0x4c, -+ 0x3a08, 0x7, -+ 0x3a09, 0xc0, -+ 0x3a0d, 0x04, -+ 0x3a0e, 0x05, -+ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Exposure Table ****************/ -+static const T_U16 EXPOSURE_WHOLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EXPOSURE_CENTER_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EXPOSURE_MIDDLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Brightness Table ****************/ -+static const T_U16 BRIGHTNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 BRIGHTNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Contrast Table ****************/ -+static const T_U16 CONTRAST_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 CONTRAST_7_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Saturation Table ****************/ -+static const T_U16 SATURATION_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SATURATION_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Sharpness Table ****************/ -+static const T_U16 SHARPNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 SHARPNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera AWB Table ****************/ -+static const T_U16 AWB_AUTO_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_SUNNY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_CLOUDY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_OFFICE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 AWB_HOME_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Effect Table ****************/ -+static const T_U16 EFFECT_NORMAL_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_SEPIA_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_ANTIQUE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_BLUISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_GREENISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_REDDISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_NEGATIVE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 EFFECT_BW_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera night/day mode ****************/ -+static const T_U16 DAY_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U16 NIGHT_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+#endif -+#endif -diff --git a/drivers/media/video/plat-anyka/camera_ov7725.c b/drivers/media/video/plat-anyka/camera_ov7725.c -new file mode 100755 -index 00000000..e6019762 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov7725.c -@@ -0,0 +1,983 @@ -+/** -+ * @file camera_ov7725.c -+ * @brief camera driver file -+ * Copyright (C) 2010 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @version 1.0 -+ * @ref -+ */ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/cam_com_sensor.h> -+#include "camera_ov7725.h" -+#else -+#include "akdefine.h" -+#include "cam_com_sensor.h" -+#include "camera_ov7725.h" -+#include "Gpio_config.h" -+#endif -+ -+#if defined (USE_CAMERA_OV7725) || defined (CONFIG_SENSOR_OV7725) -+ -+#define CAM_EN_LEVEL 0 -+#define CAM_RESET_LEVEL 0 -+ -+#define CAMERA_SCCB_ADDR 0x42 -+#define CAMERA_OV7725_ID 0x7721 -+ -+#define CAMERA_MCLK_DIV 3 //192Mhz/(2*(3+1))=24Mhz -+ -+#define OV7725_CAMERA_MCLK 24 //24, 30fps/60fps; //32, 40fps -+ -+static T_CAMERA_TYPE camera_ov7725_type = CAMERA_P3M; -+static T_NIGHT_MODE night_mode = CAMERA_DAY_MODE; -+static T_CAMERA_MODE s_ov7725_CurMode = CAMERA_MODE_VGA; -+ -+static T_VOID camera_setbit(T_U8 reg, T_U8 bit, T_U8 value) -+{ -+ T_U8 tmp; -+ -+ tmp = sccb_read_data(CAMERA_SCCB_ADDR, reg); -+ if (value == 1) -+ tmp |= 0x1 << bit; -+ else -+ tmp &= ~(0x1 << bit); -+ sccb_write_data(CAMERA_SCCB_ADDR, reg, &tmp, 1); -+} -+ -+static T_BOOL camera_set_param(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 temp_value; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)(&tabParameter[i + 1]), 1); -+ -+ if (!((tabParameter[i] == 0x12) && (tabParameter[i + 1] & 0x80)) -+ && !((tabParameter[i] == 0xc9) && (tabParameter[i + 1] & 0x60))) -+ { -+ temp_value = sccb_read_data(CAMERA_SCCB_ADDR, tabParameter[i]); -+ if (temp_value != tabParameter[i + 1]) -+ { -+ akprintf(C1, M_DRVSYS, "set parameter error!\n"); -+ akprintf(C1, M_DRVSYS, "reg 0x%x write data is 0x%x, read data is 0x%x!\n", tabParameter[i], tabParameter[i + 1], temp_value); -+ -+ return AK_FALSE; -+ } -+ } -+ } -+ i += 2; -+ } -+ -+ return AK_TRUE; -+} -+ -+static T_VOID camera_setup(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)&tabParameter[i + 1], 1); -+ } -+ i += 2; -+ } -+} -+ -+static T_VOID cam_ov7725_open(T_VOID) -+{ -+ gpio_set_pin_dir(GPIO_CAMERA_AVDD, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_CHIP_ENABLE); -+ gpio_set_pin_dir(GPIO_CAMERA_CHIP_ENABLE, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, CAM_EN_LEVEL); -+ mini_delay(10); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_RESET); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, CAM_RESET_LEVEL); -+ mini_delay(10); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, !CAM_RESET_LEVEL); -+ -+ mini_delay(20); -+} -+ -+static T_BOOL cam_ov7725_close(T_VOID) -+{ -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, !CAM_EN_LEVEL); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, !gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_INPUT); -+ -+ gpio_set_pin_dir(GPIO_I2C_SCL, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SCL, GPIO_LEVEL_LOW); -+ gpio_set_pin_dir(GPIO_I2C_SDA, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SDA, GPIO_LEVEL_LOW); -+ -+ return AK_TRUE; -+} -+ -+static T_U32 cam_ov7725_read_id(T_VOID) -+{ -+ T_U8 value = 0x00; -+ T_U32 id = 0; -+ -+ sccb_init(GPIO_I2C_SCL, GPIO_I2C_SDA); //init sccb first here!! -+ -+ value = sccb_read_data(CAMERA_SCCB_ADDR, 0x0a); -+ id = value << 8; -+ value = sccb_read_data(CAMERA_SCCB_ADDR, 0x0b); -+ id |= value; -+ -+ return id; -+} -+ -+/** -+ * @brief initialize the parameters of camera, should be done after reset and open camera to initialize -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @return T_BOOL -+ * @retval AK_TRUE if success, else AK_FALSE -+ */ -+static T_BOOL cam_ov7725_init(void) -+{ -+ if (!camera_set_param(INIT_TAB)) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ night_mode = CAMERA_DAY_MODE; -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief Set camera mode to specify image quality, SXGA/VGA/CIF/ etc -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] mode mode value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_mode(T_CAMERA_MODE mode) -+{ -+ s_ov7725_CurMode = mode; -+ switch(mode) -+ { -+ case CAMERA_MODE_VGA: -+ camera_setup(VGA_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_CIF: -+// camera_setup(CIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QVGA: -+// camera_setup(QVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_QCIF: -+// camera_setup(QCIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QQVGA: -+// camera_setup(QQVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_PREV: //preview mode -+ camera_setup(PREV_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_REC: //record mode -+ camera_setup(RECORD_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ default: -+ s_ov7725_CurMode = CAMERA_MODE_VGA; -+ akprintf(C1, M_DRVSYS, "set camera mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera exposure mode -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] exposure exposure mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_exposure(T_CAMERA_EXPOSURE exposure) -+{ -+ switch(exposure) -+ { -+ case EXPOSURE_WHOLE: -+ camera_setup(EXPOSURE_WHOLE_TAB); -+ break; -+ case EXPOSURE_CENTER: -+ camera_setup(EXPOSURE_CENTER_TAB); -+ break; -+ case EXPOSURE_MIDDLE: -+ camera_setup(EXPOSURE_MIDDLE_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set exposure parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera brightness level -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] brightness brightness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_brightness(T_CAMERA_BRIGHTNESS brightness) -+{ -+ switch(brightness) -+ { -+ case CAMERA_BRIGHTNESS_0: -+ camera_setup(BRIGHTNESS_0_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_1: -+ camera_setup(BRIGHTNESS_1_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_2: -+ camera_setup(BRIGHTNESS_2_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_3: -+ camera_setup(BRIGHTNESS_3_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_4: -+ camera_setup(BRIGHTNESS_4_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_5: -+ camera_setup(BRIGHTNESS_5_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_6: -+ camera_setup(BRIGHTNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set brightness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera contrast level -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] contrast contrast value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_contrast(T_CAMERA_CONTRAST contrast) -+{ -+ switch(contrast) -+ { -+ case CAMERA_CONTRAST_1: -+ camera_setup(CONTRAST_1_TAB); -+ break; -+ case CAMERA_CONTRAST_2: -+ camera_setup(CONTRAST_2_TAB); -+ break; -+ case CAMERA_CONTRAST_3: -+ camera_setup(CONTRAST_3_TAB); -+ break; -+ case CAMERA_CONTRAST_4: -+ camera_setup(CONTRAST_4_TAB); -+ break; -+ case CAMERA_CONTRAST_5: -+ camera_setup(CONTRAST_5_TAB); -+ break; -+ case CAMERA_CONTRAST_6: -+ camera_setup(CONTRAST_6_TAB); -+ break; -+ case CAMERA_CONTRAST_7: -+ camera_setup(CONTRAST_7_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set contrast parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera saturation level -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] saturation saturation value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_saturation(T_CAMERA_SATURATION saturation) -+{ -+ switch(saturation) -+ { -+ case CAMERA_SATURATION_1: -+ camera_setup(SATURATION_1_TAB); -+ break; -+ case CAMERA_SATURATION_2: -+ camera_setup(SATURATION_2_TAB); -+ break; -+ case CAMERA_SATURATION_3: -+ camera_setup(SATURATION_3_TAB); -+ break; -+ case CAMERA_SATURATION_4: -+ camera_setup(SATURATION_4_TAB); -+ break; -+ case CAMERA_SATURATION_5: -+ camera_setup(SATURATION_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set saturation parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera sharpness level -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] sharpness sharpness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_sharpness(T_CAMERA_SHARPNESS sharpness) -+{ -+ switch(sharpness) -+ { -+ case CAMERA_SHARPNESS_0: -+ camera_setup(SHARPNESS_0_TAB); -+ break; -+ case CAMERA_SHARPNESS_1: -+ camera_setup(SHARPNESS_1_TAB); -+ break; -+ case CAMERA_SHARPNESS_2: -+ camera_setup(SHARPNESS_2_TAB); -+ break; -+ case CAMERA_SHARPNESS_3: -+ camera_setup(SHARPNESS_3_TAB); -+ break; -+ case CAMERA_SHARPNESS_4: -+ camera_setup(SHARPNESS_4_TAB); -+ break; -+ case CAMERA_SHARPNESS_5: -+ camera_setup(SHARPNESS_5_TAB); -+ break; -+ case CAMERA_SHARPNESS_6: -+ camera_setup(SHARPNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set sharpness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera AWB mode -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] awb AWB mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_AWB(T_CAMERA_AWB awb) -+{ -+ switch(awb) -+ { -+ case AWB_AUTO: -+ camera_setup(AWB_AUTO_TAB); -+ break; -+ case AWB_SUNNY: -+ camera_setup(AWB_SUNNY_TAB); -+ break; -+ case AWB_CLOUDY: -+ camera_setup(AWB_CLOUDY_TAB); -+ break; -+ case AWB_OFFICE: -+ camera_setup(AWB_OFFICE_TAB); -+ break; -+ case AWB_HOME: -+ camera_setup(AWB_HOME_TAB); -+ break; -+ case AWB_NIGHT: -+ camera_setup(AWB_NIGHT_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set AWB mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera mirror mode -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] mirror mirror mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_mirror(T_CAMERA_MIRROR mirror) -+{ -+ switch(mirror) -+ { -+ case CAMERA_MIRROR_V: -+ camera_setbit(0x1e, 4, 1); -+ camera_setbit(0x1e, 5, 0); -+ break; -+ case CAMERA_MIRROR_H: -+ camera_setbit(0x1e, 4, 0); -+ camera_setbit(0x1e, 5, 1); -+ break; -+ case CAMERA_MIRROR_NORMAL: -+ camera_setbit(0x1e, 4, 0); -+ camera_setbit(0x1e, 5, 0); -+ break; -+ case CAMERA_MIRROR_FLIP: -+ camera_setbit(0x1e, 4, 1); -+ camera_setbit(0x1e, 5, 1); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set mirror parameter error!\n"); -+ break; -+ } -+} -+ -+ -+/** -+ * @brief Set camera effect mode -+ * @author xia_wenting -+ * @date 2010-12-28 -+ * @param[in] effect effect mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov7725_set_effect(T_CAMERA_EFFECT effect) -+{ -+ switch(effect) -+ { -+ case CAMERA_EFFECT_NORMAL: -+ camera_setup(EFFECT_NORMAL_TAB); -+ break; -+ case CAMERA_EFFECT_SEPIA: -+ camera_setup(EFFECT_SEPIA_TAB); -+ break; -+ case CAMERA_EFFECT_ANTIQUE: -+ camera_setup(EFFECT_ANTIQUE_TAB); -+ break; -+ case CAMERA_EFFECT_BLUE: -+ camera_setup(EFFECT_BLUISH_TAB); -+ break; -+ case CAMERA_EFFECT_GREEN: -+ camera_setup(EFFECT_GREENISH_TAB); -+ break; -+ case CAMERA_EFFECT_RED: -+ camera_setup(EFFECT_REDDISH_TAB); -+ break; -+ case CAMERA_EFFECT_NEGATIVE: -+ camera_setup(EFFECT_NEGATIVE_TAB); -+ break; -+ case CAMERA_EFFECT_BW: -+ camera_setup(EFFECT_BW_TAB); -+ break; -+ case CAMERA_EFFECT_BWN: -+ camera_setup(EFFECT_BWN_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set camer effect parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief set camera window -+ * @author -+ * @date 2010-07-30 -+ * @param[in] srcWidth window width -+ * @param[in] srcHeight window height -+ * @return T_S32 -+ * @retval 0 if error mode -+ * @retval 1 if success -+ * @retval -1 if fail -+ */ -+static T_S32 cam_ov7725_set_digital_zoom(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_U16 hrefstart = 0, hrefstop = 0, vrefstart = 0, vrefstop = 0; -+ T_U8 hbit = 0, lstartbit = 0, lstopbit = 0; -+ T_CAMERA_MODE Cammode = s_ov7725_CurMode; -+ T_U8 Camera_window_table[] = -+ { -+ 0x17, 0, -+ 0x18, 0, -+ 0x32, 0, -+ 0x19, 0, -+ 0x1a, 0, -+ 0x03, 0, -+ END_FLAG, END_FLAG -+ }; -+ -+ akprintf(C1, M_DRVSYS, "set window size %d, %d, %d\r\n", Cammode, srcWidth, srcHeight); -+ -+ if(Cammode == CAMERA_MODE_VGA )//VGA_MODE -+ { -+ if((srcWidth == 640) && (srcHeight == 480)) -+ { -+ Camera_window_table[1] = 0x22;//0x13; //0x17; -+ Camera_window_table[3] = 0xa4;//0x01; //0x18 -+ Camera_window_table[5] = 0x00;//0xb6; //0x92; //0x32 from 0x92 to 0xb6 by lujie @061009 -+ Camera_window_table[7] = 0x07; //0x19 -+ Camera_window_table[9] = 0xf0; //0x1a -+ Camera_window_table[11] = 0x00; //0x00; //0x03 //0x00 from 0x0a to 0xb6 by lujie @061009 -+ if (camera_set_param(Camera_window_table) == AK_TRUE) -+ { -+ return 1; -+ } -+ else -+ { -+ return -1; -+ } -+ } -+ else -+ { -+ hrefstart = 158 + (640 - srcWidth) / 2; // by lujie 154 to 156 @061009 -+ hrefstop = hrefstart + srcWidth; -+ -+ vrefstart = 8 + (480 - srcHeight) / 2; -+ vrefstop = vrefstart + srcHeight; -+ } -+ } -+ else if(Cammode == CAMERA_MODE_QVGA )//QVGA_MODE -+ { -+ if((srcWidth == 320) && (srcHeight == 240)) -+ { -+ Camera_window_table[1] = 0x15; //0x17; -+ Camera_window_table[3] = 0x03; //0x18 -+ Camera_window_table[5] = 0x36; //0x32 -+ Camera_window_table[7] = 0x02; //0x19 -+ Camera_window_table[9] = 0x7a; //0x1a -+ Camera_window_table[11]= 0x0a; //0x03 -+ if (camera_set_param(Camera_window_table) == AK_TRUE) -+ { -+ return 1; -+ } -+ else -+ { -+ return -1; -+ } -+ } -+ else -+ { -+ hrefstart = 282 + (320 - srcWidth) / 2;//196 -+ hrefstop = hrefstart + srcWidth; //836 -+ -+ vrefstart = 8 + (240 - srcHeight) / 2 ; -+ vrefstop = vrefstart + srcHeight; -+ } -+ } -+ else if(Cammode == CAMERA_MODE_QQVGA ) //QQVGA_MODE -+ { -+ if((srcWidth == 160) && (srcHeight == 120)) -+ { -+ cam_ov7725_set_mode(CAMERA_MODE_QQVGA); -+ return 1; -+ } -+ hrefstart = 282 + (160 - srcWidth) * 2; -+ hrefstop = hrefstart + srcWidth; -+ -+ vrefstart = 8 + (120 - srcHeight) / 2 ; -+ vrefstop = vrefstart + srcHeight; -+ } -+ else -+ { -+ return 0; -+ } -+ -+ hbit = hrefstart >> 3; //Horizontal Frame start high 8-bit -+ lstartbit = hrefstart & 0x7; //Horizontal Frame start low 3-bit -+ -+ Camera_window_table[1] = hbit; -+ -+ if(Cammode != CAMERA_MODE_VGA && Cammode != CAMERA_MODE_SXGA) -+ { -+ if (hrefstop > 800) -+ { -+ hrefstop -=800; -+ } -+ } -+ hbit = hrefstop >> 3; //Horizontal Frame end high 8-bit -+ lstopbit = hrefstop & 0x7; //Horizontal Frame end low 3-bit -+ -+ Camera_window_table[3] = hbit; -+ -+ Camera_window_table[5] = 0x80 | lstartbit | (lstopbit << 3) ; -+ -+ hbit = vrefstart >> 2; //Vertical Frame start high 8-bit -+ lstartbit = vrefstart & 0x2; //Vertical Frame start low 2-bit -+ -+ Camera_window_table[7] = hbit; -+ -+ hbit = vrefstop >> 2; //Vertical Frame end high 8-bit -+ lstopbit = vrefstop & 0x2; //Vertical Frame end low 2-bit -+ -+ Camera_window_table[9] = hbit; -+ -+ Camera_window_table[11] = 0x0 | lstartbit | (lstopbit << 2); -+ -+ if (camera_set_param(Camera_window_table) == AK_TRUE) -+ { -+ return 1; -+ } -+ else -+ { -+ return -1; -+ } -+} -+ -+static T_VOID cam_ov7725_set_night_mode(T_NIGHT_MODE mode) -+{ -+ switch(mode) -+ { -+ case CAMERA_DAY_MODE: -+ camera_setup(DAY_MODE_TAB); -+ night_mode = CAMERA_DAY_MODE; -+ break; -+ case CAMERA_NIGHT_MODE: -+ camera_setup(NIGHT_MODE_TAB); -+ night_mode = CAMERA_NIGHT_MODE; -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set night mode parameter error!\n"); -+ break; -+ } -+} -+ -+static T_BOOL cam_ov7725_set_to_cap(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_VGA; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "30W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_ov7725_set_mode(Cammode); -+ cam_ov7725_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(200); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov7725_set_to_prev(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_ov7725_set_mode(CAMERA_MODE_PREV); -+ cam_ov7725_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(200); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov7725_set_to_record(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_ov7725_set_mode(CAMERA_MODE_REC); -+ cam_ov7725_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(200); -+ return AK_TRUE; -+} -+ -+static T_CAMERA_TYPE cam_ov7725_get_type(T_VOID) -+{ -+ return camera_ov7725_type; -+} -+ -+static T_VOID cam_ov7725_set_sensor_param(T_U32 cmd, T_U32 data) -+{ -+ T_U8 value; -+ -+ value = (T_U8)data; -+ sccb_write_data(CAMERA_SCCB_ADDR, (T_U8)cmd, &value, 1); -+} -+ -+static T_CAMERA_FUNCTION_HANDLER ov7725_function_handler = -+{ -+ OV7725_CAMERA_MCLK, -+ cam_ov7725_open, -+ cam_ov7725_close, -+ cam_ov7725_read_id, -+ cam_ov7725_init, -+ cam_ov7725_set_mode, -+ cam_ov7725_set_exposure, -+ cam_ov7725_set_brightness, -+ cam_ov7725_set_contrast, -+ cam_ov7725_set_saturation, -+ cam_ov7725_set_sharpness, -+ cam_ov7725_set_AWB, -+ cam_ov7725_set_mirror, -+ cam_ov7725_set_effect, -+ cam_ov7725_set_digital_zoom, -+ cam_ov7725_set_night_mode, -+ AK_NULL, -+ AK_NULL, -+ cam_ov7725_set_to_cap, -+ cam_ov7725_set_to_prev, -+ cam_ov7725_set_to_record, -+ cam_ov7725_get_type, -+ cam_ov7725_set_sensor_param -+}; -+ -+#ifndef CONFIG_LINUX_AKSENSOR -+static int camera_ov7725_reg(void) -+{ -+ camera_reg_dev(CAMERA_OV7725_ID, &ov7725_function_handler); -+ return 0; -+} -+ -+#ifdef __CC_ARM -+#pragma arm section rwdata = "__initcall_", zidata = "__initcall_" -+#endif -+module_init(camera_ov7725_reg) -+#ifdef __CC_ARM -+#pragma arm section -+#endif -+ -+#else -+ -+static const char * resolution_menu[] = { -+ [0] = "640x480", -+}; -+ -+static const char * hflip_menu[] = { -+ [0] = "normal", -+ [1] = "horizontal flip", -+}; -+ -+static const char * vflip_menu[] = { -+ [0] = "normal", -+ [1] = "vertical flip", -+}; -+ -+static const char * night_menu[] = { -+ [CAMERA_DAY_MODE] = "daylight", -+ [CAMERA_NIGHT_MODE] = "night", -+}; -+ -+static int ov7725_s_ctl(struct v4l2_ctrl *ctrl) -+{ -+ int ret = -EINVAL; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_CONTRAST: -+ if (ov7725_function_handler.cam_set_contrast_func) { -+ ov7725_function_handler.cam_set_contrast_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SATURATION: -+ if (ov7725_function_handler.cam_set_saturation_func) { -+ ov7725_function_handler.cam_set_saturation_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_HFLIP: -+ if (ov7725_function_handler.cam_set_mirror_func) { -+ ov7725_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_H : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_VFLIP: -+ if (ov7725_function_handler.cam_set_mirror_func) { -+ ov7725_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_V : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_NIGHTMODE: -+ if (ov7725_function_handler.cam_set_night_mode_func) { -+ ov7725_function_handler.cam_set_night_mode_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+}; -+ -+static struct v4l2_ctrl_ops ov7725_ctrl_ops = { -+ .s_ctrl = ov7725_s_ctl, -+}; -+ -+static const struct v4l2_ctrl_config ov7725_ctrls[] = { -+ { -+ .ops = &ov7725_ctrl_ops, -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Horizontal Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(hflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = hflip_menu, -+ }, -+ { -+ .ops = &ov7725_ctrl_ops, -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Vetical Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(vflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = vflip_menu, -+ }, -+ { -+ .ops = &ov7725_ctrl_ops, -+ .id = V4L2_CID_PICTURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Resolution", -+ .min = 0, -+ .max = ARRAY_SIZE(resolution_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = resolution_menu, -+ }, -+ { -+ .ops = &ov7725_ctrl_ops, -+ .id = V4L2_CID_NIGHTMODE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Night mode", -+ .min = 0, -+ .max = ARRAY_SIZE(night_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = night_menu, -+ }, -+ { -+ .ops = &ov7725_ctrl_ops, -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .min = 0, -+ .max = CAMERA_CONTRAST_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov7725_ctrl_ops, -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .min = 0, -+ .max = CAMERA_SATURATION_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+}; -+ -+ -+/* -+ * supported format list -+ */ -+static const struct aksensor_color_format ov7725_formats[] = { -+ { -+ .code = V4L2_MBUS_FMT_YUYV8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_YVYU8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_UYVY8_2X8, -+ .colorspace = V4L2_COLORSPACE_JPEG, -+ }, -+}; -+ -+static const struct aksensor_win_size ov7725_win[] = { -+ {.name = "VGA", .width = 640, .height = 480}, -+}; -+ -+ -+static struct sensor_info ov7725_sensor_info = { -+ .sensor_name = "ov7725", -+ .sensor_id = CAMERA_OV7725_ID, -+ .ctrls = ov7725_ctrls, -+ .nr_ctrls = ARRAY_SIZE(ov7725_ctrls), -+ .formats = ov7725_formats, -+ .num_formats = ARRAY_SIZE(ov7725_formats), -+ .resolution = ov7725_win, -+ .num_resolution = ARRAY_SIZE(ov7725_win), -+ .handler = &ov7725_function_handler, -+}; -+ -+static int ov7725_module_init(void) -+{ -+ return register_sensor(&ov7725_sensor_info); -+} -+module_init(ov7725_module_init) -+#endif -+ -+#endif -diff --git a/drivers/media/video/plat-anyka/camera_ov7725.h b/drivers/media/video/plat-anyka/camera_ov7725.h -new file mode 100755 -index 00000000..d658cf78 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov7725.h -@@ -0,0 +1,406 @@ -+/** -+ * @file camera_ov7725.h -+ * @brief camera driver file -+ * Copyright (C) 2010 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-04-22 -+ * @version 1.0 -+ * @ref -+ */ -+#ifndef __CAMERA_OV7725_H__ -+#define __CAMERA_OV7725_H__ -+ -+ -+#if defined (USE_CAMERA_OV7725) || defined (CONFIG_SENSOR_OV7725) -+ -+#undef DELAY_FLAG -+#undef END_FLAG -+#define DELAY_FLAG 0xFE // first parameter is 0xfe, then 2nd parameter is delay time count -+#define END_FLAG 0xFF // first parameter is 0xff, then parameter table is over -+ -+ -+static const T_U8 INIT_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 VGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CIF_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QVGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QCIF_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QQVGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 PREV_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 RECORD_MODE_TAB[] = -+{ -+ //MCLK 24MHz, 30fps/60fps; MCLK 32MHz, 40fps -+ 0x12, 0x80, -+ 0x3d, 0x03, -+ -+ 0x17, 0x22, -+ 0x18, 0xa4, -+ 0x32, 0x00, -+ 0x19, 0x07, -+ 0x1a, 0xf0, -+ 0x03, 0x00, -+ -+ 0x29, 0xa0, -+ 0x2c, 0xf0, -+ 0x2a, 0x00, -+ 0x11, 0x01,//01, 30fps/40fps; //00, 60fps -+ 0x33, 0x00,//30fps; 0x66, 25fps, dummy row -+ 0x42, 0x7f, -+ 0x4d, 0x09, -+ 0x63, 0xe0, -+ 0x64, 0xff, -+ 0x65, 0x20, -+ 0x66, 0x00, -+ 0x67, 0x48, -+ 0x13, 0xff, -+ 0x0d, 0x41, -+ 0x0f, 0xc5, -+ 0x14, 0x11,//21, //4x -+ -+ 0x22, 0x97,//97, 30fps/60fps; //ca, 40fps -+ 0x23, 0x02,//02, 30fps; //01, 40fps/60fps -+ 0x24, 0x50,//70,//40, -+ 0x25, 0x40,//60,//30, -+ 0x26, 0xb2,//c3,//a1, -+ -+ 0x2b, 0x00, -+ 0x6b, 0xaa, -+ 0x90, 0x05, -+ 0x91, 0x01, -+ 0x92, 0x03, -+ 0x93, 0x00, -+ 0x94, 0xb0, -+ 0x95, 0x9d, -+ 0x96, 0x13, -+ 0x97, 0x16, -+ 0x98, 0x7b, -+ 0x99, 0x91, -+ 0x9a, 0x1e, -+ 0x9b, 0x08, -+ 0x9c, 0x25,//20, -+ 0x9e, 0x81, -+ 0xa6, 0x04, -+ 0x7e, 0x0c, -+ 0x7f, 0x16, -+ 0x80, 0x2a, -+ 0x81, 0x4e, -+ 0x82, 0x61, -+ 0x83, 0x6f, -+ 0x84, 0x7b, -+ 0x85, 0x86, -+ 0x86, 0x8e, -+ 0x87, 0x97, -+ 0x88, 0xa4, -+ 0x89, 0xaf, -+ 0x8a, 0xc5, -+ 0x8b, 0xd7, -+ 0x8c, 0xe8, -+ 0x8d, 0x20, -+ 0x0c, 0x00, -+ 0x6b, 0x90, -+ 0xa7, 0x70, -+ 0xa8, 0x70, -+ -+ //LC -+ 0x47, 0x90, -+ 0x48, 0x14, -+ 0x4a, 0x00, -+ 0x49, 0x08, //07, //g -+ 0x4b, 0x09, //08, //b -+ 0x4c, 0x0b, //0d, //r -+ 0x46, 0x05, -+ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Exposure Table ****************/ -+static const T_U8 EXPOSURE_WHOLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_CENTER_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_MIDDLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Brightness Table ****************/ -+static const T_U8 BRIGHTNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Contrast Table ****************/ -+static const T_U8 CONTRAST_1_TAB[] = -+{ -+ 0x9c,0x08, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_2_TAB[] = -+{ -+ 0x9c,0x10, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_3_TAB[] = -+{ -+ 0x9c,0x15, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_4_TAB[] = -+{ -+ 0x9c,0x20, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_5_TAB[] = -+{ -+ 0x9c,0x24, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_6_TAB[] = -+{ -+ 0x9c,0x28, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_7_TAB[] = -+{ -+ 0x9c,0x40, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Saturation Table ****************/ -+static const T_U8 SATURATION_1_TAB[] = -+{ -+ 0xa6,0x06, -+ 0xa7,0x10, -+ 0xa8,0x30, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_2_TAB[] = -+{ -+ 0xa6,0x06, -+ 0xa7,0x40, -+ 0xa8,0x40, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_3_TAB[] = -+{ -+ 0xa6,0x04, -+ 0xa7,0x70, -+ 0xa8,0x70, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_4_TAB[] = -+{ -+ 0xa6,0x06, -+ 0xa7,0x80, -+ 0xa8,0x80, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_5_TAB[] = -+{ -+ 0xa6,0x06, -+ 0xa7,0x98, -+ 0xa8,0x98, -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Sharpness Table ****************/ -+static const T_U8 SHARPNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera AWB Table ****************/ -+static const T_U8 AWB_AUTO_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_SUNNY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_CLOUDY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_OFFICE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_HOME_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_NIGHT_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Effect Table ****************/ -+static const T_U8 EFFECT_NORMAL_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_SEPIA_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_ANTIQUE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BLUISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_GREENISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_REDDISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_NEGATIVE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BW_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BWN_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera night/day mode ****************/ -+static const T_U8 DAY_MODE_TAB[] = -+{ -+ 0x0e,0x79, -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 NIGHT_MODE_TAB[] = -+{ -+ 0x0e,0xF9, -+ END_FLAG, END_FLAG -+}; -+ -+#endif -+#endif -diff --git a/drivers/media/video/plat-anyka/camera_ov9712.c b/drivers/media/video/plat-anyka/camera_ov9712.c -new file mode 100755 -index 00000000..23f17522 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov9712.c -@@ -0,0 +1,1000 @@ -+/** -+ * @file camera_ov9712.c -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-09-21 -+ * @version 1.0 -+ * @ref -+ */ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <plat-anyka/aksensor.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/cam_com_sensor.h> -+#include "camera_ov9712.h" -+#else -+#include "akdefine.h" -+#include "cam_com_sensor.h" -+#include "camera_ov9712.h" -+#include "Gpio_config.h" -+#endif -+ -+#if defined (USE_CAMERA_OV9712) || defined (CONFIG_SENSOR_OV9712) -+ -+#define CAM_EN_LEVEL 0 -+#define CAM_RESET_LEVEL 0 -+ -+#define CAMERA_SCCB_ADDR 0x60 -+#define CAMERA_OV9712_ID 0x9711 -+ -+#define OV9712_CAMERA_MCLK 24 -+ -+static T_CAMERA_TYPE camera_ov9712_type = CAMERA_2M; -+static T_NIGHT_MODE night_mode = CAMERA_DAY_MODE; -+static T_CAMERA_MODE s_ov9712_CurMode = CAMERA_MODE_VGA; -+ -+static T_VOID camera_setbit(T_U8 reg, T_U8 bit, T_U8 value) -+{ -+ T_U8 tmp; -+ -+ tmp = sccb_read_data(CAMERA_SCCB_ADDR, reg); -+ if (value == 1) -+ { -+ tmp |= 0x1 << bit; -+ } -+ else -+ { -+ tmp &= ~(0x1 << bit); -+ } -+ -+ sccb_write_data(CAMERA_SCCB_ADDR, reg, &tmp, 1); -+} -+ -+static T_BOOL camera_set_param(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ T_U8 temp_value; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)(&tabParameter[i + 1]), 1); -+ -+ if (!((tabParameter[i] == 0x12) && (tabParameter[i + 1] & 0x80))) -+ { -+ temp_value = sccb_read_data(CAMERA_SCCB_ADDR, tabParameter[i]); -+ if (temp_value != tabParameter[i + 1]) -+ { -+ akprintf(C1, M_DRVSYS, "set parameter error!\n"); -+ akprintf(C1, M_DRVSYS, "reg 0x%x write data is 0x%x, read data is 0x%x!\n", tabParameter[i], tabParameter[i + 1], temp_value); -+ -+ return AK_FALSE; -+ } -+ } -+ } -+ -+ i += 2; -+ } -+ -+ return AK_TRUE; -+} -+ -+static T_VOID camera_setup(const T_U8 tabParameter[]) -+{ -+ int i = 0; -+ -+ while (1) -+ { -+ if ((END_FLAG == tabParameter[i]) && (END_FLAG == tabParameter[i + 1])) -+ { -+ break; -+ } -+ else if (DELAY_FLAG == tabParameter[i]) -+ { -+ mini_delay(tabParameter[i + 1]); -+ } -+ else -+ { -+ sccb_write_data(CAMERA_SCCB_ADDR, tabParameter[i], (T_U8 *)&tabParameter[i + 1], 1); -+ } -+ -+ i += 2; -+ } -+} -+ -+static T_VOID cam_ov9712_open(T_VOID) -+{ -+ gpio_set_pin_dir(GPIO_CAMERA_AVDD, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_CHIP_ENABLE); -+ gpio_set_pin_dir(GPIO_CAMERA_CHIP_ENABLE, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, CAM_EN_LEVEL); -+ mini_delay(10); -+ -+ gpio_set_pin_as_gpio(GPIO_CAMERA_RESET); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, CAM_RESET_LEVEL); -+ mini_delay(10); -+ gpio_set_pin_level(GPIO_CAMERA_RESET, !CAM_RESET_LEVEL); -+ -+ mini_delay(20); -+} -+ -+static T_BOOL cam_ov9712_close(T_VOID) -+{ -+ //sccb software standby mode -+ T_U8 Reg0x3d = 0x48; -+ T_U8 Reg0xc3 = 0x00; -+ -+ sccb_write_data(CAMERA_SCCB_ADDR, 0x3d, &Reg0x3d, 1); -+ sccb_write_data(CAMERA_SCCB_ADDR, 0xc3, &Reg0xc3, 1); -+ -+ gpio_set_pin_level(GPIO_CAMERA_CHIP_ENABLE, !CAM_EN_LEVEL); -+ gpio_set_pin_level(GPIO_CAMERA_AVDD, !gpio_pin_get_ActiveLevel(GPIO_CAMERA_AVDD)); -+ gpio_set_pin_dir(GPIO_CAMERA_RESET, GPIO_DIR_INPUT); -+ -+ gpio_set_pin_dir(GPIO_I2C_SCL, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SCL, GPIO_LEVEL_LOW); -+ gpio_set_pin_dir(GPIO_I2C_SDA, GPIO_DIR_OUTPUT); -+ gpio_set_pin_level(GPIO_I2C_SDA, GPIO_LEVEL_LOW); -+ -+ return AK_TRUE; -+} -+ -+static T_U32 cam_ov9712_read_id(T_VOID) -+{ -+ T_U8 value = 0x00; -+ T_U32 id = 0; -+ -+ sccb_init(GPIO_I2C_SCL, GPIO_I2C_SDA); //init sccb first here!! -+ -+ value = sccb_read_data(CAMERA_SCCB_ADDR, 0x0a); -+ id = value << 8; -+ value = sccb_read_data(CAMERA_SCCB_ADDR, 0x0b); -+ id |= value; -+ -+ return id; -+} -+ -+/** -+ * @brief initialize the parameters of camera, should be done after reset and open camera to initialize -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @return T_BOOL -+ * @retval AK_TRUE if success, else AK_FALSE -+ */ -+static T_BOOL cam_ov9712_init(void) -+{ -+ if (!camera_set_param(INIT_TAB)) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ night_mode = CAMERA_DAY_MODE; -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief Set camera mode to specify image quality, SXGA/VGA/CIF etc -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mode mode value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_mode(T_CAMERA_MODE mode) -+{ -+ s_ov9712_CurMode = mode; -+ -+ switch(mode) -+ { -+ case CAMERA_MODE_UXGA: -+ camera_setup(UXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_SXGA: -+ camera_setup(SXGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_VGA: -+ camera_setup(VGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_CIF: -+ camera_setup(CIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QVGA: -+ camera_setup(QVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_QCIF: -+ camera_setup(QCIF_MODE_TAB); -+ break; -+ case CAMERA_MODE_QQVGA: -+ camera_setup(QQVGA_MODE_TAB); -+ break; -+ case CAMERA_MODE_PREV: -+ camera_setup(PREV_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_REC: -+ camera_setup(RECORD_MODE_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ case CAMERA_MODE_720P: -+ camera_setup(RECORD_720P_TAB); -+ -+ if (CAMERA_NIGHT_MODE == night_mode) -+ { -+ camera_setup(NIGHT_MODE_TAB); -+ } -+ break; -+ default: -+ s_ov9712_CurMode = CAMERA_MODE_VGA; -+ akprintf(C1, M_DRVSYS, "set camera mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera exposure mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] exposure exposure mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_exposure(T_CAMERA_EXPOSURE exposure) -+{ -+ switch(exposure) -+ { -+ case EXPOSURE_WHOLE: -+ camera_setup(EXPOSURE_WHOLE_TAB); -+ break; -+ case EXPOSURE_CENTER: -+ camera_setup(EXPOSURE_CENTER_TAB); -+ break; -+ case EXPOSURE_MIDDLE: -+ camera_setup(EXPOSURE_MIDDLE_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set exposure parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera brightness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] brightness brightness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_brightness(T_CAMERA_BRIGHTNESS brightness) -+{ -+ switch(brightness) -+ { -+ case CAMERA_BRIGHTNESS_0: -+ camera_setup(BRIGHTNESS_0_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_1: -+ camera_setup(BRIGHTNESS_1_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_2: -+ camera_setup(BRIGHTNESS_2_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_3: -+ camera_setup(BRIGHTNESS_3_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_4: -+ camera_setup(BRIGHTNESS_4_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_5: -+ camera_setup(BRIGHTNESS_5_TAB); -+ break; -+ case CAMERA_BRIGHTNESS_6: -+ camera_setup(BRIGHTNESS_6_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set brightness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera contrast level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] contrast contrast value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_contrast(T_CAMERA_CONTRAST contrast) -+{ -+ switch(contrast) -+ { -+ case CAMERA_CONTRAST_1: -+ camera_setup(CONTRAST_1_TAB); -+ break; -+ case CAMERA_CONTRAST_2: -+ camera_setup(CONTRAST_2_TAB); -+ break; -+ case CAMERA_CONTRAST_3: -+ camera_setup(CONTRAST_3_TAB); -+ break; -+ case CAMERA_CONTRAST_4: -+ camera_setup(CONTRAST_4_TAB); -+ break; -+ case CAMERA_CONTRAST_5: -+ camera_setup(CONTRAST_5_TAB); -+ break; -+ case CAMERA_CONTRAST_6: -+ camera_setup(CONTRAST_6_TAB); -+ break; -+ case CAMERA_CONTRAST_7: -+ camera_setup(CONTRAST_7_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set contrast parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera saturation level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] saturation saturation value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_saturation(T_CAMERA_SATURATION saturation) -+{ -+ switch(saturation) -+ { -+ case CAMERA_SATURATION_1: -+ camera_setup(SATURATION_1_TAB); -+ break; -+ case CAMERA_SATURATION_2: -+ camera_setup(SATURATION_2_TAB); -+ break; -+ case CAMERA_SATURATION_3: -+ camera_setup(SATURATION_3_TAB); -+ break; -+ case CAMERA_SATURATION_4: -+ camera_setup(SATURATION_4_TAB); -+ break; -+ case CAMERA_SATURATION_5: -+ camera_setup(SATURATION_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set saturation parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera sharpness level -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] sharpness sharpness value -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_sharpness(T_CAMERA_SHARPNESS sharpness) -+{ -+ switch(sharpness) -+ { -+ case CAMERA_SHARPNESS_0: -+ camera_setup(SHARPNESS_0_TAB); -+ break; -+ case CAMERA_SHARPNESS_1: -+ camera_setup(SHARPNESS_1_TAB); -+ break; -+ case CAMERA_SHARPNESS_2: -+ camera_setup(SHARPNESS_2_TAB); -+ break; -+ case CAMERA_SHARPNESS_3: -+ camera_setup(SHARPNESS_3_TAB); -+ break; -+ case CAMERA_SHARPNESS_4: -+ camera_setup(SHARPNESS_4_TAB); -+ break; -+ case CAMERA_SHARPNESS_5: -+ camera_setup(SHARPNESS_5_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set sharpness parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera AWB mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] awb AWB mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_AWB(T_CAMERA_AWB awb) -+{ -+ switch(awb) -+ { -+ case AWB_AUTO: -+ camera_setup(AWB_AUTO_TAB); -+ break; -+ case AWB_SUNNY: -+ camera_setup(AWB_SUNNY_TAB); -+ break; -+ case AWB_CLOUDY: -+ camera_setup(AWB_CLOUDY_TAB); -+ break; -+ case AWB_OFFICE: -+ camera_setup(AWB_OFFICE_TAB); -+ break; -+ case AWB_HOME: -+ camera_setup(AWB_HOME_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set AWB mode parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera mirror mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] mirror mirror mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_mirror(T_CAMERA_MIRROR mirror) -+{ -+ switch(mirror) -+ { -+ case CAMERA_MIRROR_V: -+ camera_setbit(0x12, 4, 1); -+ camera_setbit(0x12, 5, 0); -+ break; -+ case CAMERA_MIRROR_H: -+ camera_setbit(0x12, 4, 0); -+ camera_setbit(0x12, 5, 1); -+ break; -+ case CAMERA_MIRROR_NORMAL: -+ camera_setbit(0x12, 4, 0); -+ camera_setbit(0x12, 5, 0); -+ break; -+ case CAMERA_MIRROR_FLIP: -+ camera_setbit(0x12, 4, 1); -+ camera_setbit(0x12, 5, 1); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set mirror parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief Set camera effect mode -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] effect effect mode -+ * @return T_VOID -+ * @retval -+ */ -+static T_VOID cam_ov9712_set_effect(T_CAMERA_EFFECT effect) -+{ -+ switch(effect) -+ { -+ case CAMERA_EFFECT_NORMAL: -+ camera_setup(EFFECT_NORMAL_TAB); -+ break; -+ case CAMERA_EFFECT_SEPIA: -+ camera_setup(EFFECT_SEPIA_TAB); -+ break; -+ case CAMERA_EFFECT_ANTIQUE: -+ camera_setup(EFFECT_ANTIQUE_TAB); -+ break; -+ case CAMERA_EFFECT_BLUE: -+ camera_setup(EFFECT_BLUISH_TAB); -+ break; -+ case CAMERA_EFFECT_GREEN: -+ camera_setup(EFFECT_GREENISH_TAB); -+ break; -+ case CAMERA_EFFECT_RED: -+ camera_setup(EFFECT_REDDISH_TAB); -+ break; -+ case CAMERA_EFFECT_NEGATIVE: -+ camera_setup(EFFECT_NEGATIVE_TAB); -+ break; -+ case CAMERA_EFFECT_BW: -+ camera_setup(EFFECT_BW_TAB); -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set camer effect parameter error!\n"); -+ break; -+ } -+} -+ -+/** -+ * @brief set camera window -+ * @author xia_wenting -+ * @date 2011-03-22 -+ * @param[in] srcWidth window width -+ * @param[in] srcHeight window height -+ * @return T_S32 -+ * @retval 0 if error mode -+ * @retval 1 if success -+ * @retval -1 if failed -+ */ -+static T_S32 cam_ov9712_set_digital_zoom(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ return 1; -+} -+ -+static T_VOID cam_ov9712_set_night_mode(T_NIGHT_MODE mode) -+{ -+ switch(mode) -+ { -+ case CAMERA_DAY_MODE: -+ camera_setup(DAY_MODE_TAB); -+ night_mode = CAMERA_DAY_MODE; -+ break; -+ case CAMERA_NIGHT_MODE: -+ camera_setup(NIGHT_MODE_TAB); -+ night_mode = CAMERA_NIGHT_MODE; -+ break; -+ default: -+ akprintf(C1, M_DRVSYS, "set night mode parameter error!\n"); -+ break; -+ } -+} -+ -+static T_BOOL cam_ov9712_set_to_cap(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 160) && (srcHeight <= 120)) -+ { -+ Cammode = CAMERA_MODE_QQVGA; -+ } -+ else if ((srcWidth <= 176) && (srcHeight <= 144)) -+ { -+ Cammode = CAMERA_MODE_QCIF; -+ } -+ else if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 352) && (srcHeight <= 288)) -+ { -+ Cammode = CAMERA_MODE_CIF; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_VGA; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 1024)) -+ { -+ Cammode = CAMERA_MODE_SXGA; -+ } -+ else if ((srcWidth <= 1600) && (srcHeight <= 1200)) -+ { -+ Cammode = CAMERA_MODE_UXGA; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "ov9712 unsupport %d & %d mode!\n", srcWidth, srcHeight); -+ return AK_FALSE; -+ } -+ -+ cam_ov9712_set_mode(Cammode); -+ cam_ov9712_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov9712_set_to_prev(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ cam_ov9712_set_mode(CAMERA_MODE_PREV); -+ cam_ov9712_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_BOOL cam_ov9712_set_to_record(T_U32 srcWidth, T_U32 srcHeight) -+{ -+ T_CAMERA_MODE Cammode; -+ -+ if ((srcWidth <= 320) && (srcHeight <= 240)) -+ { -+ Cammode = CAMERA_MODE_QVGA; -+ } -+ else if ((srcWidth <= 640) && (srcHeight <= 480)) -+ { -+ Cammode = CAMERA_MODE_REC; -+ } -+ else if ((srcWidth <= 1280) && (srcHeight <= 720)) -+ { -+ Cammode = CAMERA_MODE_720P; -+ } -+ else -+ { -+ akprintf(C1, M_DRVSYS, "200W camera dose not support such mode"); -+ return AK_FALSE; -+ } -+ -+ cam_ov9712_set_mode(Cammode); -+ cam_ov9712_set_digital_zoom(srcWidth, srcHeight); -+ mini_delay(300); -+ return AK_TRUE; -+} -+ -+static T_CAMERA_TYPE cam_ov9712_get_type(T_VOID) -+{ -+ return camera_ov9712_type; -+} -+ -+static T_VOID cam_ov9712_set_sensor_param(T_U32 cmd, T_U32 data) -+{ -+ T_U8 value; -+ -+ value = (T_U8)data; -+ sccb_write_data(CAMERA_SCCB_ADDR, (T_U8)cmd, &value, 1); -+} -+ -+static T_CAMERA_FUNCTION_HANDLER ov9712_function_handler = -+{ -+ OV9712_CAMERA_MCLK, -+ cam_ov9712_open, -+ cam_ov9712_close, -+ cam_ov9712_read_id, -+ cam_ov9712_init, -+ cam_ov9712_set_mode, -+ cam_ov9712_set_exposure, -+ cam_ov9712_set_brightness, -+ cam_ov9712_set_contrast, -+ cam_ov9712_set_saturation, -+ cam_ov9712_set_sharpness, -+ cam_ov9712_set_AWB, -+ cam_ov9712_set_mirror, -+ cam_ov9712_set_effect, -+ cam_ov9712_set_digital_zoom, -+ cam_ov9712_set_night_mode, -+ AK_NULL, -+ AK_NULL, -+ cam_ov9712_set_to_cap, -+ cam_ov9712_set_to_prev, -+ cam_ov9712_set_to_record, -+ cam_ov9712_get_type, -+ cam_ov9712_set_sensor_param -+}; -+ -+#ifndef CONFIG_LINUX_AKSENSOR -+static int camera_ov9712_reg(void) -+{ -+ camera_reg_dev(CAMERA_OV9712_ID, &ov9712_function_handler); -+ return 0; -+} -+ -+#ifdef __CC_ARM -+#pragma arm section rwdata = "__initcall_", zidata = "__initcall_" -+#endif -+module_init(camera_ov9712_reg) -+#ifdef __CC_ARM -+#pragma arm section -+#endif -+ -+#else -+static const char * awb_menu[] = { -+ [AWB_AUTO] = "auto", -+ [AWB_SUNNY] = "sunny", -+ [AWB_CLOUDY] = "cloudy", -+ [AWB_OFFICE] = "office", -+ [AWB_HOME] = "home", -+ [AWB_NIGHT] = "night", -+}; -+ -+static const char * effect_menu[] = { -+ [CAMERA_EFFECT_NORMAL] = "normal", -+ [CAMERA_EFFECT_SEPIA] = "sepia", -+ [CAMERA_EFFECT_ANTIQUE] = "antique", -+ [CAMERA_EFFECT_BLUE] = "blue", -+ [CAMERA_EFFECT_GREEN] = "green", -+ [CAMERA_EFFECT_RED] = "red", -+ [CAMERA_EFFECT_NEGATIVE] = "negative", -+ [CAMERA_EFFECT_BW] = "bw", -+ [CAMERA_EFFECT_BWN] = "bwn", -+ [CAMERA_EFFECT_AQUA] = "aqua", -+ [CAMERA_EFFECT_COOL] = "cool", -+ [CAMERA_EFFECT_WARM] = "warm", -+}; -+ -+static const char * resolution_menu[] = { -+ [0] = "1280x720", -+ [1] = "640x480", -+}; -+ -+static const char * hflip_menu[] = { -+ [0] = "normal", -+ [1] = "horizontal flip", -+}; -+ -+static const char * vflip_menu[] = { -+ [0] = "normal", -+ [1] = "vertical flip", -+}; -+ -+static const char * night_menu[] = { -+ [CAMERA_DAY_MODE] = "daylight", -+ [CAMERA_NIGHT_MODE] = "night", -+}; -+ -+static int ov9712_s_ctl(struct v4l2_ctrl *ctrl) -+{ -+ int ret = -EINVAL; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ if (ov9712_function_handler.cam_set_AWB_func) { -+ ov9712_function_handler.cam_set_AWB_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_COLORFX: -+ if (ov9712_function_handler.cam_set_effect_func) { -+ ov9712_function_handler.cam_set_effect_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ -+ case V4L2_CID_BRIGHTNESS: -+ if (ov9712_function_handler.cam_set_brightness_func) { -+ ov9712_function_handler.cam_set_brightness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_CONTRAST: -+ if (ov9712_function_handler.cam_set_contrast_func) { -+ ov9712_function_handler.cam_set_contrast_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SATURATION: -+ if (ov9712_function_handler.cam_set_saturation_func) { -+ ov9712_function_handler.cam_set_saturation_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_SHARPNESS: -+ if (ov9712_function_handler.cam_set_sharpness_func) { -+ ov9712_function_handler.cam_set_sharpness_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_HFLIP: -+ if (ov9712_function_handler.cam_set_mirror_func) { -+ ov9712_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_H : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_VFLIP: -+ if (ov9712_function_handler.cam_set_mirror_func) { -+ ov9712_function_handler.cam_set_mirror_func( -+ ctrl->val ? CAMERA_MIRROR_V : CAMERA_MIRROR_NORMAL); -+ ret = 0; -+ } -+ break; -+ case V4L2_CID_NIGHTMODE: -+ if (ov9712_function_handler.cam_set_night_mode_func) { -+ ov9712_function_handler.cam_set_night_mode_func(ctrl->val); -+ ret = 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+}; -+ -+static struct v4l2_ctrl_ops ov9712_ctrl_ops = { -+ .s_ctrl = ov9712_s_ctl, -+}; -+ -+static const struct v4l2_ctrl_config ov9712_ctrls[] = { -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_AUTO_WHITE_BALANCE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "AWB", -+ .min = 0, -+ .max = ARRAY_SIZE(awb_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = awb_menu, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_COLORFX, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Effect", -+ .min = 0, -+ .max = ARRAY_SIZE(effect_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = effect_menu, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_HFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Horizontal Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(hflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = hflip_menu, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_VFLIP, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Vetical Flip", -+ .min = 0, -+ .max = ARRAY_SIZE(vflip_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = vflip_menu, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_PICTURE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Resolution", -+ .min = 0, -+ .max = ARRAY_SIZE(resolution_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = resolution_menu, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_NIGHTMODE, -+ .type = V4L2_CTRL_TYPE_MENU, -+ .name = "Night mode", -+ .min = 0, -+ .max = ARRAY_SIZE(night_menu) - 1, -+ .step = 0, -+ .def = 0, -+ .flags = 0, -+ .menu_skip_mask = 0, -+ .qmenu = night_menu, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_BRIGHTNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Brightness", -+ .min = 0, -+ .max = CAMERA_BRIGHTNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_CONTRAST, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Contrast", -+ .min = 0, -+ .max = CAMERA_CONTRAST_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_SATURATION, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Saturation", -+ .min = 0, -+ .max = CAMERA_SATURATION_NUM -1, -+ .step = 1, -+ .def = 0, -+ }, -+ { -+ .ops = &ov9712_ctrl_ops, -+ .id = V4L2_CID_SHARPNESS, -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .name = "Sharpness", -+ .min = 0, -+ .max = CAMERA_SHARPNESS_NUM -1, -+ .step = 1, -+ .def = 0, -+ } -+}; -+ -+ -+/* -+ * supported format list -+ */ -+static const struct aksensor_color_format ov9712_formats[] = { -+ { -+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+ { -+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE, -+ .colorspace = V4L2_COLORSPACE_SRGB, -+ }, -+}; -+ -+static const struct aksensor_win_size ov9712_win[] = { -+ {.name = "VGA", .width = 640, .height = 480}, -+ {.name = "720P", .width = 1280, .height = 720}, -+}; -+ -+ -+static struct sensor_info ov9712_sensor_info = { -+ .sensor_name = "ov9712", -+ .sensor_id = CAMERA_OV9712_ID, -+ .ctrls = ov9712_ctrls, -+ .nr_ctrls = ARRAY_SIZE(ov9712_ctrls), -+ .formats = ov9712_formats, -+ .num_formats = ARRAY_SIZE(ov9712_formats), -+ .resolution = ov9712_win, -+ .num_resolution = ARRAY_SIZE(ov9712_win), -+ .handler = &ov9712_function_handler, -+}; -+ -+static int ov9712_module_init(void) -+{ -+ return register_sensor(&ov9712_sensor_info); -+} -+module_init(ov9712_module_init) -+#endif -+ -+#endif -+ -+ -diff --git a/drivers/media/video/plat-anyka/camera_ov9712.h b/drivers/media/video/plat-anyka/camera_ov9712.h -new file mode 100755 -index 00000000..a8711fc2 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/camera_ov9712.h -@@ -0,0 +1,458 @@ -+/** -+ * @file camera_ov9712.h -+ * @brief camera driver file -+ * Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd -+ * @author xia_wenting -+ * @date 2011-10-26 -+ * @version 1.0 -+ * @ref -+ */ -+#ifndef __CAMERA_OV9712_H__ -+#define __CAMERA_OV9712_H__ -+ -+ -+#if defined (USE_CAMERA_OV9712) || defined (CONFIG_SENSOR_OV9712) -+ -+#undef DELAY_FLAG -+#undef END_FLAG -+#define DELAY_FLAG 0xfd // first parameter is 0xfe, then 2nd parameter is delay time count -+#define END_FLAG 0xfe // first parameter is 0xff, then parameter table is over -+ -+static const T_U8 INIT_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 UXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SXGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 VGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QVGA_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QCIF_MODE_TAB[] = -+{ -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 QQVGA_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 PREV_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 RECORD_MODE_TAB[] = -+{ -+ //640*480 Reference Setting 24M MCLK 15fps -+ //Reset -+ 0x12, 0x80, -+ 0x09, 0x10, -+ //Core Settings -+ 0x1e, 0x07, -+ 0x5f, 0x18, -+ 0x69, 0x04, -+ 0x65, 0x2a, -+ 0x68, 0x0a, -+ 0x39, 0x28, -+ 0x4d, 0x90, -+ 0xc1, 0x80, -+ 0x0c, 0x30, -+ 0x6d, 0x02, -+ //DSP -+ 0x96, 0xf1, //DSP options enable -+ 0xbc, 0x68, -+ //Resolution and Format -+ 0x12, 0x00, -+ 0x3b, 0x00, -+ 0x97, 0x80, -+ 0x17, 0x25, -+ 0x18, 0xA2, -+ 0x19, 0x01, -+ 0x1a, 0xCA, -+ 0x03, 0x03, -+ 0x04, 0xc8,//flip on, mirror on -+ 0x32, 0x07, -+ 0x98, 0x40, -+ 0x99, 0xA0, -+ 0x9a, 0x01, -+ 0x57, 0x00, -+ 0x58, 0x78, -+ 0x59, 0x50, -+ 0x4c, 0x13, -+ 0x4b, 0x36, -+ 0x3d, 0x3c, -+ 0x3e, 0x03, -+ 0xbd, 0x50, -+ 0xbe, 0x78, -+ //AWB -+ //Lens Correction -+ //YAVG -+ 0x4e, 0x55, //AVERAGE -+ 0x4f, 0x55, -+ 0x50, 0x55, -+ 0x51, 0x55, -+ 0x24, 0x60, //Exposure windows -+ 0x25, 0x50, -+ 0x26, 0xa1, -+ //Clock -+ 0x5c, 0x59, -+ 0x5d, 0x00, -+ 0x11, 0x01, -+ 0x2a, 0x98, -+ 0x2b, 0x06, -+ 0x2d, 0x00, -+ 0x2e, 0x00, -+ //General -+ 0x13, 0x85, -+ 0x14, 0x40, //Gain Ceiling 8X -+ 0x09, 0x00, -+ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 RECORD_720P_TAB[] = -+{ -+ //Reset -+ 0x12, 0x80, -+ 0x09, 0x10, -+ //Core Settings -+ 0x1e, 0x07, -+ 0x5f, 0x18, -+ 0x69, 0x04, -+ 0x65, 0x2a, -+ 0x68, 0x0a, -+ 0x39, 0x28, -+ 0x4d, 0x90, -+ 0xc1, 0x80, -+ 0x0c, 0x30, -+ 0x6d, 0x02, -+ //DSP -+ 0x96, 0xf9, //0x01 -->manual:0xf9 -+ //0x96, 0xcf, //0x01 -->manual:0xf9 -+ 0xbc, 0x68, -+ //Resolution and Format -+ 0x12, 0x00, -+ 0x3b, 0x00, -+ 0x97, 0x80, -+ 0x17, 0x25, -+ 0x18, 0xA2, -+ 0x19, 0x01, -+ 0x1a, 0xCA, -+ 0x03, 0x01, -+ 0x04, 0xc8, //flip on, mirror on -+ 0x32, 0x07, -+ 0x98, 0x00, -+ 0x99, 0x28, -+ 0x9a, 0x00, -+ 0x57, 0x00, -+ 0x58, 0xB4, -+ 0x59, 0xA0, -+ 0x4c, 0x13, -+ 0x4b, 0x36, -+ 0x3d, 0x3c, -+ 0x3e, 0x03, -+ 0xbd, 0xA0, -+ 0xbe, 0xb4, -+ -+ //YAVG -+ 0x4e, 0x55, -+ 0x4f, 0x55, -+ 0x50, 0x55, -+ 0x51, 0x55, -+ 0x24, 0x60, -+ 0x25, 0x50, -+ 0x26, 0xa1, -+ -+ //Clock -+ 0x5c, 0x52, //0x52-->manual:0x59 -+ 0x5d, 0x00, -+ 0x11, 0x01, -+ 0x2a, 0x98, -+ 0x2b, 0x06, -+ 0x2d, 0x00, -+ 0x2e, 0x00, -+ //General -+// 0x13, 0xa5, //0xa5 -->manual: 0x85 -+// 0x14, 0x40, -+ 0x13, 0xad, -+ 0x14, 0x48, -+ //Banding -+ 0x4a, 0x00, -+ 0x49, 0xfa, -+ 0x22, 0x03, -+ 0x09, 0x00, -+#if 0 -+ //close AE_AWB -+ 0x13, 0x80, -+ 0x16, 0x00, -+ 0x10, 0xf0, -+ 0x00, 0x3f, -+ 0x38, 0x00, -+ 0x01, 0x40, -+ 0x02, 0x40, -+ 0x05, 0x40, -+ 0x06, 0x00, -+ 0x07, 0x00, -+#endif -+ //BLC -+ 0x41, 0x84, -+ -+ END_FLAG, END_FLAG -+}; -+ -+ -+/**************** Camera Exposure Table ****************/ -+static const T_U8 EXPOSURE_WHOLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_CENTER_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EXPOSURE_MIDDLE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Brightness Table ****************/ -+static const T_U8 BRIGHTNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 BRIGHTNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Contrast Table ****************/ -+static const T_U8 CONTRAST_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 CONTRAST_7_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Saturation Table ****************/ -+static const T_U8 SATURATION_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SATURATION_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Sharpness Table ****************/ -+static const T_U8 SHARPNESS_0_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_1_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_2_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_3_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_4_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_5_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 SHARPNESS_6_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera AWB Table ****************/ -+static const T_U8 AWB_AUTO_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_SUNNY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_CLOUDY_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_OFFICE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 AWB_HOME_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera Effect Table ****************/ -+static const T_U8 EFFECT_NORMAL_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_SEPIA_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_ANTIQUE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BLUISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_GREENISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_REDDISH_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_NEGATIVE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 EFFECT_BW_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+/**************** Camera night/day mode ****************/ -+static const T_U8 DAY_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+ -+static const T_U8 NIGHT_MODE_TAB[] = -+{ -+ END_FLAG, END_FLAG -+}; -+#endif -+#endif -diff --git a/drivers/media/video/plat-anyka/wrap_sensor.c b/drivers/media/video/plat-anyka/wrap_sensor.c -new file mode 100755 -index 00000000..37173af4 ---- /dev/null -+++ b/drivers/media/video/plat-anyka/wrap_sensor.c -@@ -0,0 +1,139 @@ -+ -+#include <linux/kernel.h> -+#include <linux/delay.h> -+#include <plat-anyka/wrap_sensor.h> -+#include <plat-anyka/aksensor.h> -+ -+/** -+ * @brief millisecond delay -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] minisecond minisecond delay number -+ * @return T_VOID -+ */ -+T_VOID mini_delay(T_U32 minisecond) -+{ -+ mdelay(minisecond); -+} -+ -+/** -+ * @brief anyka specific printf -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] level forbidden level -+ * @param[in] mStr module string -+ * @param[in] s format string -+ * @return T_S32 -+ * @retval 0 is print ok, -1 is forbidden to print -+ */ -+T_S32 akprintf(T_U8 level, T_pCSTR mStr, T_pCSTR s, ...) -+{ -+ va_list args; -+ T_S32 r; -+ -+ va_start(args, s); -+ r = vprintk(s, args); -+ va_end(args); -+ -+ return r; -+} -+ -+/** -+ * @brief write data to SCCB device -+ * -+ * write size length data to daddr's raddr register -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] daddr SCCB device address -+ * @param[in] raddr register address -+ * @param[in] data write data's point -+ * @param[in] size write data's length -+ * @return T_BOOL return write success or failed -+ * @retval AK_FALSE operate failed -+ * @retval AK_TRUE operate success -+ */ -+T_BOOL sccb_write_data(T_U8 daddr, T_U8 raddr, T_U8 *data, T_U32 size) -+{ -+ int ret = aksensor_i2c_write_byte_data(daddr, raddr, data, size); -+ -+ if (ret != 0) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ return AK_TRUE; -+ } -+} -+ -+/** -+ * @brief read data from SCCB device function -+ * -+ * read data from daddr's raddr register -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] daddr SCCB device address -+ * @param[in] raddr register address -+ * @return T_U8 -+ * @retval read-back data -+ */ -+T_U8 sccb_read_data(T_U8 daddr, T_U8 raddr) -+{ -+ return aksensor_i2c_read_byte_data(daddr, raddr); -+} -+ -+T_BOOL sccb_write_short(T_U8 daddr, T_U16 raddr, T_U8 *data, T_U32 size) -+{ -+ int ret = aksensor_i2c_write_byte_short(daddr, raddr, data, size); -+ -+ if (ret != 0) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ return AK_TRUE; -+ } -+} -+ -+T_U8 sccb_read_short(T_U8 daddr, T_U16 raddr) -+{ -+ return aksensor_i2c_read_byte_short(daddr, raddr); -+} -+ -+T_BOOL sccb_write_word(T_U8 daddr, T_U16 raddr, T_U16 *data, T_U32 size) -+{ -+ int ret = aksensor_i2c_write_word_data(daddr, raddr, data, size); -+ if (ret != 0) -+ { -+ return AK_FALSE; -+ } -+ else -+ { -+ return AK_TRUE; -+ } -+} -+ -+T_U16 sccb_read_word(T_U8 daddr, T_U16 raddr) -+{ -+ return aksensor_i2c_read_word_data(daddr, raddr); -+} -+ -+/*@{*/ -+/** -+ * @brief SCCB interface initialize function -+ * -+ * setup SCCB interface -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] pin_scl the pin assigned to SCL -+ * @param[in] pin_sda the pin assigned to SDA -+ * @return T_VOID -+ */ -+T_VOID sccb_init(T_U32 pin_scl, T_U32 pin_sda) -+{ -+ -+} -+ -+ -+ -diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c -index 5b2ec1fd..22c3e7af 100644 ---- a/drivers/media/video/v4l2-ioctl.c -+++ b/drivers/media/video/v4l2-ioctl.c -@@ -2417,7 +2417,10 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, - err = -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) { - unsigned long n = cmd_input_size(cmd); -- -+ -+ if (cmd == VIDIOC_G_PARM) -+ n+=4; -+ - if (copy_from_user(parg, (void __user *)arg, n)) - goto out; - -diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index c7795096..49705182 100644 ---- a/drivers/misc/Kconfig -+++ b/drivers/misc/Kconfig -@@ -382,6 +382,14 @@ config HMC6352 - This driver provides support for the Honeywell HMC6352 compass, - providing configuration and heading data via sysfs. - -+config SENSORS_AK8975 -+ tristate "AK8975 compass support" -+ default n -+ depends on I2C -+ help -+ If you say yes here you get support for Asahi Kasei's -+ orientation sensor AK8975. -+ - config EP93XX_PWM - tristate "EP93xx PWM support" - depends on ARCH_EP93XX -@@ -425,6 +433,10 @@ config TI_DAC7512 - This driver can also be built as a module. If so, the module - will be called ti_dac7512. - -+config UID_STAT -+ bool "UID based statistics tracking exported to /proc/uid_stat" -+ default n -+ - config VMWARE_BALLOON - tristate "VMware Balloon Driver" - depends on X86 -@@ -498,6 +510,40 @@ config MAX8997_MUIC - Maxim MAX8997 PMIC. - The MAX8997 MUIC is a USB port accessory detector and switch. - -+config WL127X_RFKILL -+ tristate "Bluetooth power control driver for TI wl127x" -+ depends on RFKILL -+ default n -+ ---help--- -+ Creates an rfkill entry in sysfs for power control of Bluetooth -+ TI wl127x chips. -+ -+config AK_SERIAL_NUMBER -+ tristate "Anyka Serial Number Interface" -+ depends on ARCH_AK39 -+ ---help--- -+ If you say yes here you get an sysfs interface to read device serial number -+ on Anyka platform. -+ -+config AK_MOTOR -+ tristate "Anyka Motor Support" -+ default n -+ help -+ If you say yes here you get support for the Anyka Motor device. -+ -+comment "user space generic gpio controller" -+config GPIOS_AKCUSTOM -+ tristate "Generic akgpio custom support" -+ depends on ARCH_AK39 -+ help -+ This enables anyka's generic GPIO for setting support through user space controller. -+ if you want need to enable this, you can control attribute of akgpio, -+ example dir[in/out], out[high/low], pull[up/down], get gpio level, -+ irq polarity[low/high], request gpio irq and delete irq etc. -+ -+ If unsure, say N. -+ -+ - source "drivers/misc/c2port/Kconfig" - source "drivers/misc/eeprom/Kconfig" - source "drivers/misc/cb710/Kconfig" -diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index 3e1d8010..b1b215fc 100644 ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -33,6 +33,7 @@ obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o - obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o - obj-$(CONFIG_DS1682) += ds1682.o - obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o -+obj-$(CONFIG_UID_STAT) += uid_stat.o - obj-$(CONFIG_C2PORT) += c2port/ - obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ - obj-$(CONFIG_HMC6352) += hmc6352.o -@@ -49,3 +50,8 @@ obj-y += carma/ - obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o - obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ - obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o -+obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o -+obj-$(CONFIG_SENSORS_AK8975) += akm8975.o -+obj-$(CONFIG_AK_MOTOR) += ak_motor.o -+obj-$(CONFIG_AK_SERIAL_NUMBER) += ak_sn.o -+obj-$(CONFIG_GPIOS_AKCUSTOM) += akgpios.o -diff --git a/drivers/misc/ak_motor.c b/drivers/misc/ak_motor.c -new file mode 100644 -index 00000000..5d8c9338 ---- /dev/null -+++ b/drivers/misc/ak_motor.c -@@ -0,0 +1,723 @@ -+/* -+ * @file /driver/misc/ak_motor.c -+ * @brief AK On-chip motor driver -+ * Copyright C 2013 Anyka CO.,LTD -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * @author lixinhai -+ * @date 2013-05-11 -+ * @note 2013-05-11 created -+ * @note 2013-05-14 add more comments -+ */ -+ -+#include <linux/fs.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/platform_device.h> -+#include <linux/init.h> -+#include <linux/spinlock.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/errno.h> -+#include <linux/err.h> -+#include <linux/poll.h> -+#include <linux/io.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/wait.h> -+#include <linux/miscdevice.h> -+#include <linux/list.h> -+#include <linux/delay.h> -+#include <linux/types.h> -+#include <mach/gpio.h> -+#include <mach/reset.h> -+#include <mach/clock.h> -+ -+#include <plat-anyka/ak_motor.h> -+ -+#define AK_MOTOR_DEVNAME "ak-motor" -+ -+//#define MOTOR_DEBUG -+ -+#ifdef MOTOR_DEBUG -+#define PDEBUG(fmt, args...) printk(KERN_INFO "ak-motor:" fmt, ##args) -+#else -+#define PDEBUG(fmt, args...) -+#endif -+ -+ -+#define MOTOR_TURN_CLKWISE (0) /*turn by clock wise*/ -+#define MOTOR_TURN_ANTICLKWISE (1) /*turn by anti clock wise*/ -+#define MOTOR_STEP_PERIOD (64) -+#define MOTOR_STEP_ANGLE (360/MOTOR_STEP_PERIOD) -+#define MOTOR_STEP_REMAIN (360%MOTOR_STEP_PERIOD) -+#define MOTOR_DEFAULT_DELAY_MS (2) -+ -+/*motor device list*/ -+static LIST_HEAD(motor_list); -+static DEFINE_MUTEX(list_lock); -+ -+struct ak_motor_runtime -+{ -+ int cw; -+ int angle; -+ int remain_angle; -+ int count; -+ int delay_jiffies; -+ int hit_flags; -+ int running; -+#define MOTOR_STATUS_RUNNING (1) -+#define MOTOR_STATUS_STOPING (2) -+#define MOTOR_STATUS_STOPED (3) -+}; -+ -+struct ak_motor { -+ struct miscdevice miscdev; -+ struct ak_motor_plat_data *pdata; -+ int irq_hit[AK_MOTOR_HIT_NUM]; /*hit feedback irq descriptor code*/ -+ int hit_pin[AK_MOTOR_HIT_NUM]; /*hit feedback irq pin.*/ -+ int trigger_level[AK_MOTOR_HIT_NUM]; /*irq trigger level*/ -+ -+ int irq_hit_type[AK_MOTOR_HIT_NUM]; /*current trigger level*/ -+ int trigger_irq; /*in course of trigger irq index.*/ -+ int phase_pin[AK_MOTOR_PHASE_NUM]; /*phase pin*/ -+ spinlock_t lock; -+ u32 angular_speed; -+ u32 delay; -+ struct timer_list detect_timer; -+ struct timer_list work_timer; -+ -+ struct ak_motor_runtime runtime; -+ struct list_head list; -+ int index; -+ -+ struct ak_motor_dev *curr_dev; -+}; -+ -+ -+struct ak_motor_dev { -+ struct ak_motor *motor; -+ spinlock_t lock; -+ int rd_flags; -+ struct notify_data data; /*notify data to user.*/ -+ int is_open; -+ wait_queue_head_t event; -+}; -+ -+/*clockwise*/ -+static unsigned char ctrl_tbl_cw[] = {0x03, 0x06, 0x0c, 0x09}; -+ -+/*anticlockwise*/ -+static unsigned char ctrl_tbl_acw[] = {0x03, 0x09, 0x0c, 0x06}; -+ -+static void ak_motor_stop(struct ak_motor_dev *motor_dev); -+static int ak_motor_wait_for_stop(struct ak_motor_dev *motor_dev); -+ -+static inline int motor_step_count(int angle) -+{ -+ int count; -+ -+/* -+ int frag; -+ -+ count = angle/MOTOR_STEP_ANGLE; -+ frag = angle%MOTOR_STEP_ANGLE; -+ -+ if((frag*2 >= MOTOR_STEP_ANGLE) || ((count == 0)&& angle)) { -+ count++; -+ } -+*/ -+ count = angle*MOTOR_STEP_ANGLE; -+ count += (angle*MOTOR_STEP_REMAIN)/MOTOR_STEP_PERIOD; -+ return count; -+} -+ -+#define ms_unit (1000) -+static inline int get_delay_by_speed(int speed) -+{ -+ int time; -+ -+ time = (1*ms_unit)/speed; -+ /* time *= MOTOR_STEP_ANGLE; */ -+ time /= MOTOR_STEP_ANGLE; -+ if(time<=0) -+ time= MOTOR_DEFAULT_DELAY_MS; -+ return time; -+} -+ -+ -+/** -+ * * @brief ak motor open -+ * * -+ * * open. -+ * * @author lixinhai -+ * * @date 2013-03-20 -+ * * @param[in] inode pointer. -+ * * @param[in] file pointer. -+ * * @return int return exec success or failed -+ * * @retval returns zero on success -+ * * @retval return a non-zero error code if failed -+ * */ -+static int ak_motor_open(struct inode *inode, struct file *file) -+{ -+ int minor; -+ bool found = false; -+ struct ak_motor *motor; -+ struct ak_motor_dev *motor_dev; -+ -+ PDEBUG("open the motor device.\n"); -+ -+ minor = iminor(file->f_path.dentry->d_inode); -+ list_for_each_entry(motor, &motor_list, list) { -+ if(minor == motor->miscdev.minor) { -+ found = true; -+ break; -+ } -+ } -+ -+ if((found == false) || (motor->curr_dev != NULL)) { -+ printk("ak-motor open fail, device busy now.\n"); -+ return -EBUSY; -+ } -+ -+ motor_dev = kzalloc(sizeof *motor_dev, GFP_KERNEL); -+ if(!motor_dev) { -+ printk("ak-motor: alloc the motor dev err, open fail.\n"); -+ } -+ -+ init_waitqueue_head(&motor_dev->event); -+ motor_dev->motor = motor; -+ motor->curr_dev = motor_dev; -+ motor_dev->data.event = AK_MOTOR_EVENT_UNHIT; -+ motor_dev->is_open = 1; -+ spin_lock_init(&motor_dev->lock); -+ -+ file->private_data = motor_dev; -+ printk("open ak motor device success.\n"); -+ return 0; -+} -+ -+/** -+ * @brief ak motor close -+ * -+ * close. -+ * @author lixinhai -+ * @date 2013-03-20 -+ * @param[in] inode pointer. -+ * @param[in] file pointer. -+ * @return int return exec success or failed -+ * @retval returns zero on success -+ * @retval return a non-zero error code if failed -+ */ -+static int ak_motor_close(struct inode *inode, struct file *file) -+{ -+ int ret; -+ struct ak_motor_dev *motor_dev = file->private_data; -+ struct ak_motor *motor = motor_dev->motor; -+ -+ BUG_ON(motor==NULL); -+ -+ motor_dev->is_open = 0; -+ ak_motor_stop(motor_dev); -+ ret = del_timer_sync(&motor->work_timer); -+ if(ret) { /*timer is pending, need wait for timer stop.*/ -+ ret = ak_motor_wait_for_stop(motor_dev); -+ if(ret) -+ printk("warning: ak motor stop fail.\n"); -+ } -+ -+ motor_dev->motor->curr_dev = NULL; -+ kfree(motor_dev); -+ printk("close ak motor device success.\n"); -+ return 0; -+} -+ -+ -+/** -+ * @brief ak motor read -+ * -+ * read. -+ * @author lixinhai -+ * @date 2013-03-20 -+ * @param[in] file pointer. -+ * @param[in] data buf. -+ * @param[in] data count. -+ * @param[in] data offset. -+ * @return int return read data count. -+ */ -+static ssize_t ak_motor_read(struct file *file, char __user *data, size_t len, loff_t *ofs) -+{ -+ unsigned long flags; -+ int ret = 0; -+ struct ak_motor_dev *motor_dev = file->private_data; -+ -+ PDEBUG("read the motor data, len:%d\n", len); -+ wait_event_interruptible(motor_dev->event, motor_dev->rd_flags != 0); -+ -+ spin_lock_irqsave(&motor_dev->lock, flags); -+ -+ ret = copy_to_user(data, &motor_dev->data, sizeof(struct notify_data)); -+ -+ motor_dev->rd_flags = 0; -+ PDEBUG("copy to user data, ret:%d.\n", ret); -+ spin_unlock_irqrestore(&motor_dev->lock, flags); -+ -+ return ret; -+} -+ -+ -+static unsigned int ak_motor_poll(struct file *file, struct poll_table_struct *wait) -+{ -+ unsigned int mask = 0; -+ struct ak_motor_dev *motor_dev = file->private_data; -+ -+ PDEBUG("motor poll.\n"); -+ -+ poll_wait(file, &motor_dev->event, wait); -+ -+ if(motor_dev->rd_flags != 0) -+ mask |= POLLIN; -+ -+ return mask; -+} -+ -+/** -+ * @brief control the motor turn. -+ * -+ * read. -+ * @author lixinhai -+ * @date 2013-03-20 -+ * @param[in] ak_motor_dev. -+ * @param[in] is clockwise. -+ * @param[in] turn angle.. -+ * @return int return exec success or failed -+ * @retval returns zero on success -+ * @retval return a non-zero error code if failed -+ */ -+static int ak_motor_turn(struct ak_motor_dev *motor_dev, int cw, int angle) -+{ -+ struct ak_motor *motor = motor_dev->motor; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&motor_dev->lock, flags); -+ motor->runtime.cw = cw; -+ motor->runtime.angle = angle; -+ motor->runtime.remain_angle = angle; -+ motor->runtime.count = motor_step_count(angle); -+ motor->runtime.delay_jiffies = (motor->delay*HZ)/1000; -+ motor->runtime.running = MOTOR_STATUS_RUNNING; -+ motor->runtime.hit_flags = 0; -+ -+ PDEBUG("ak motor turn request, %sclockwise, angle is %d.\n", cw ?"":"anti", angle); -+ mod_timer(&motor->work_timer, jiffies); -+ spin_unlock_irqrestore(&motor_dev->lock, flags); -+ return 0; -+} -+ -+static void ak_motor_stop(struct ak_motor_dev *motor_dev) -+{ -+ unsigned long flags; -+ struct ak_motor *motor = motor_dev->motor; -+ -+ spin_lock_irqsave(&motor_dev->lock, flags); -+ motor->runtime.running = MOTOR_STATUS_STOPING; -+ spin_unlock_irqrestore(&motor_dev->lock, flags); -+} -+ -+static int ak_motor_wait_for_stop(struct ak_motor_dev *motor_dev) -+{ -+ int timeout = 200; -+ struct ak_motor *motor = motor_dev->motor; -+ -+ while(timeout--) { -+ if(motor->runtime.running == MOTOR_STATUS_STOPED) -+ return 0; -+ msleep(1); -+ } -+ return 1; -+} -+ -+ -+static long ak_motor_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ int val; -+ int err = 0, ret = 0; -+ struct ak_motor_dev *motor_dev = file->private_data; -+ struct ak_motor *motor = motor_dev->motor; -+ -+ PDEBUG("exec the motor ioctl.\n"); -+ /* Check type and command number */ -+ if (_IOC_TYPE(cmd) != AK_MOTOR_IOC_MAGIC) -+ return -ENOTTY; -+ -+ /* Check access direction once here; don't repeat below. -+ * IOC_DIR is from the user perspective, while access_ok is -+ * from the kernel perspective; so they look reversed. -+ */ -+ if (_IOC_DIR(cmd) & _IOC_READ) -+ err = !access_ok(VERIFY_WRITE, -+ (void __user *)arg, _IOC_SIZE(cmd)); -+ if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) -+ err = !access_ok(VERIFY_READ, -+ (void __user *)arg, _IOC_SIZE(cmd)); -+ if (err) -+ return -EFAULT; -+ -+ switch(cmd) { -+ case AK_MOTOR_SET_ANG_SPEED: -+ __get_user(val, (int __user*)arg); -+ PDEBUG("ak motor set angular speed %d.\n", val); -+ if((val<AK_MOTOR_MIN_SPEED) || val > AK_MOTOR_MAX_SPEED) -+ return -EINVAL; -+ -+ motor->angular_speed = val; -+ motor->delay = get_delay_by_speed(motor->angular_speed); -+ break; -+ case AK_MOTOR_GET_ANG_SPEED: -+ PDEBUG("ak motor get angular speed.\n"); -+ __put_user(motor->angular_speed, (int __user*)arg); -+ break; -+ case AK_MOTOR_TURN_CLKWISE: -+ __get_user(val, (int __user*)arg); -+ PDEBUG("ak motor turn clk wise, angle:%d\n", val); -+ if(val < 0) -+ return -EINVAL; -+ -+ ak_motor_turn(motor_dev, MOTOR_TURN_CLKWISE, val); -+ break; -+ case AK_MOTOR_TURN_ANTICLKWISE: -+ __get_user(val, (int __user*)arg); -+ PDEBUG("ak motor turn anti clkwise, angle:%d\n", val); -+ if(val < 0) -+ return -EINVAL; -+ -+ ak_motor_turn(motor_dev, MOTOR_TURN_ANTICLKWISE, val); -+ break; -+ case AK_MOTOR_GET_HIT_STATUS: -+ val = 0; -+ ret = ak_gpio_getpin(motor->hit_pin[AK_MOTOR_HIT_LEFT]); -+ if(ret == (motor->trigger_level[AK_MOTOR_HIT_LEFT] == IRQ_TYPE_LEVEL_HIGH)) -+ val |= AK_MOTOR_HITTING_LEFT; -+ -+ ret = ak_gpio_getpin(motor->hit_pin[AK_MOTOR_HIT_RIGHT]); -+ if(ret == (motor->trigger_level[AK_MOTOR_HIT_RIGHT] == IRQ_TYPE_LEVEL_HIGH)) -+ val |= AK_MOTOR_HITTING_RIGHT; -+ -+ PDEBUG("ak motor get status, val:%d\n", val); -+ __put_user(val, (int __user*)arg); -+ case AK_MOTOR_TURN_STOP: -+ PDEBUG("ak motor stop request.\n"); -+ ak_motor_stop(motor_dev); -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+static struct file_operations ak_motor_fops = { -+ .owner = THIS_MODULE, -+ .open = ak_motor_open, -+ .release = ak_motor_close, -+ .read = ak_motor_read, -+ .poll = ak_motor_poll, -+ .unlocked_ioctl = ak_motor_ioctl, -+}; -+ -+/*********************************************************************/ -+ -+static void ak_motor_event_notify(struct ak_motor *motor, int num, int event) -+{ -+ struct ak_motor_dev *motor_dev = motor->curr_dev; -+ -+ if(!motor_dev) -+ return; -+ -+ motor_dev->data.hit_num = num; -+ motor_dev->data.event = event; -+ motor_dev->data.remain_angle = motor->runtime.remain_angle; -+ motor_dev->rd_flags = 1; -+ PDEBUG("notify to hit: hit number:%d, event:%d, remain angle:%d.\n", -+ num, event, motor->runtime.remain_angle); -+ -+ if(event == AK_MOTOR_EVENT_HIT) -+ motor->runtime.hit_flags = 1; -+ -+ wake_up_interruptible(&motor_dev->event); -+} -+ -+/** -+ * @brief detect the motor hit the boundary or not. -+ * -+ * @author lixinhai -+ * @date 2013-03-20 -+ * @param[in] timer data pointer. -+ */ -+static void ak_motor_hit_detect(unsigned long data) -+{ -+ int i; -+ int hit_event; -+ unsigned long flags; -+ struct ak_motor *motor = (struct ak_motor*)data; -+ struct ak_motor_dev *motor_dev = motor->curr_dev; -+ -+ PDEBUG("ak motor hit detect.\n"); -+ spin_lock_irqsave(&motor_dev->lock, flags); -+ for(i=0; i<AK_MOTOR_HIT_NUM; i++) { -+ if(motor->trigger_irq == motor->irq_hit[i]) { -+ hit_event = (motor->trigger_level[i] == motor->irq_hit_type[i]) ? -+ AK_MOTOR_EVENT_HIT : AK_MOTOR_EVENT_UNHIT; -+ -+ if(motor->irq_hit_type[i] == IRQ_TYPE_LEVEL_LOW) { -+ motor->irq_hit_type[i] = IRQ_TYPE_LEVEL_HIGH; -+ }else { -+ motor->irq_hit_type[i] = IRQ_TYPE_LEVEL_LOW; -+ } -+ irq_set_irq_type(motor->irq_hit[i], motor->irq_hit_type[i]); -+ enable_irq(motor->irq_hit[i]); -+ ak_motor_event_notify(motor, i, hit_event); -+ break; -+ } -+ } -+ spin_unlock_irqrestore(&motor_dev->lock, flags); -+} -+ -+/** -+ * @brief hitting the boundary interrupt. -+ * -+ * @author lixinhai -+ * @date 2013-03-20 -+ * @param[in] irq description. -+ * @param[in] dev_id. -+ */ -+static irqreturn_t ak_motor_hit_irq(int irq, void *dev_id) -+{ -+ struct ak_motor *motor = dev_id; -+ -+ PDEBUG("receive the motor hit irq.\n"); -+ disable_irq_nosync(irq); -+ motor->trigger_irq = irq; -+ mod_timer(&motor->detect_timer, jiffies + msecs_to_jiffies(50)); -+ -+ return IRQ_HANDLED; -+} -+ -+static void ak_motor_timer_hander(unsigned long data) -+{ -+ unsigned long flags; -+ unsigned char *ctrl_tbl; -+ int i, j, idx; -+ struct ak_motor_dev *motor_dev; -+ int ret = 0; -+ struct ak_motor_runtime *runtime; -+ struct ak_motor *motor = (struct ak_motor*)data; -+ int count; -+ char *err_desc = ""; -+ -+ motor_dev = motor->curr_dev; -+ if(!motor_dev) -+ return; -+ -+ spin_lock_irqsave(&motor_dev->lock, flags); -+ runtime = &motor->runtime; -+ count = motor_step_count(runtime->angle); -+ i = count - runtime->count; -+ ctrl_tbl = runtime->cw ? ctrl_tbl_cw : ctrl_tbl_acw; -+ //printk("[%d:%d]",i, runtime->count); -+/* -+ PDEBUG("ak motor turn: %s, angle:%d, delay:%d, count:%d, runtime count:%d\n", -+ runtime->cw ?"cw":"acw", runtime->angle, motor->delay, count, runtime->count); -+*/ -+ if(unlikely(!motor_dev->is_open)) { -+ err_desc = "not open"; -+ goto out; -+ } -+ -+ if(unlikely(motor->runtime.hit_flags)) { -+ motor->runtime.hit_flags = 0; -+ err_desc = "hitting the boundary"; -+ goto out; -+ } -+ -+ if(unlikely(runtime->running != MOTOR_STATUS_RUNNING)) { -+ ak_motor_event_notify(motor, 0, AK_MOTOR_EVENT_STOP); -+ err_desc = "stop running"; -+ goto out; -+ } -+ -+ idx = i % AK_MOTOR_PHASE_NUM; -+ for(j=0; j<AK_MOTOR_PHASE_NUM; j++) { -+ ak_gpio_setpin(motor->phase_pin[j], !!((1<<j) & ctrl_tbl[idx])); -+ } -+ -+ runtime->remain_angle = runtime->angle - (i*MOTOR_STEP_PERIOD)/360; -+ -+ if(--runtime->count > 0 && -+ runtime->running == MOTOR_STATUS_RUNNING) { -+ ret = mod_timer(&motor->work_timer, jiffies + runtime->delay_jiffies); -+ if(ret) { -+ printk(KERN_ERR "ak motor: mod timer fail.\n"); -+ } -+ } else { -+ runtime->running = MOTOR_STATUS_STOPED; -+ for(j=0; j<AK_MOTOR_PHASE_NUM; j++) { -+ ak_gpio_setpin(motor->phase_pin[j], 0); -+ } -+ ak_motor_event_notify(motor, 0, AK_MOTOR_EVENT_STOP); -+ } -+ -+ spin_unlock_irqrestore(&motor_dev->lock, flags); -+ return; -+out: -+ runtime->running = MOTOR_STATUS_STOPED; -+ spin_unlock_irqrestore(&motor_dev->lock, flags); -+ PDEBUG("ak motor running stop, out reason:%s\n", err_desc); -+ return; -+} -+ -+ -+/** -+ * @brief initilize the motor gpio. -+ * -+ * @author lixinhai -+ * @date 2013-03-20 -+ * @param[in] ak_motor. -+ */ -+static int ak_motor_init_cfg(struct ak_motor *motor) -+{ -+ int i, ret = 0; -+ bool flags = false; -+ struct ak_motor_plat_data *plat = motor->pdata; -+ -+ for(i=0; i<AK_MOTOR_PHASE_NUM; i++) { -+ ak_gpio_set(&plat->gpio_phase[i]); -+ motor->phase_pin[i] = plat->gpio_phase[i].pin; -+ ak_setpin_as_gpio(motor->phase_pin[i]); -+ } -+ -+ for(i=0; i<AK_MOTOR_HIT_NUM; i++) { -+ motor->irq_hit[i] = 0; -+ if(plat->gpio_hit[i].pin >= 0) { -+ motor->hit_pin[i] = plat->gpio_hit[i].pin; -+ ak_gpio_set(&plat->gpio_hit[i]); -+ -+ if(!flags) { -+ setup_timer(&motor->detect_timer, ak_motor_hit_detect, -+ (unsigned long)motor); -+ flags = true; -+ } -+ motor->irq_hit[i] = ak_gpio_to_irq(motor->hit_pin[i]); -+ -+ /*request the hit boundary irq*/ -+ ret = request_irq(motor->irq_hit[i], ak_motor_hit_irq, -+ IRQF_DISABLED|IRQF_TRIGGER_LOW, "motor", motor); -+ if(ret) -+ goto out; -+ -+ printk("ak_motor:request gpio irq ret = %d, irq=%d\n", -+ ret, motor->irq_hit[i]); -+ -+ motor->trigger_level[i] = motor->irq_hit_type[i] = plat->irq_hit_type[i]; -+ } -+ } -+ -+out: -+ return ret; -+} -+ -+static int __devinit ak_motor_probe(struct platform_device *pdev) -+{ -+ int ret; -+ struct ak_motor *motor; -+ struct ak_motor_plat_data *pdata; -+ char name[64]; -+ -+ PDEBUG("ak motor driver probe enter.\n"); -+ pdata = pdev->dev.platform_data; -+ if(!pdata) -+ return -ENODEV; -+ -+ motor = kzalloc(sizeof *motor, GFP_KERNEL); -+ if(!motor) { -+ printk("alloc the motor device fail.\n"); -+ return -ENOMEM; -+ } -+ -+ motor->pdata = pdata; -+ platform_set_drvdata(pdev, motor); -+ -+ sprintf(name, "%s%d", pdev->name, pdev->id); -+ -+ motor->angular_speed = pdata->angular_speed; -+ motor->delay = get_delay_by_speed(motor->angular_speed); -+ motor->miscdev.minor = MISC_DYNAMIC_MINOR; -+ motor->miscdev.name = name; -+ motor->miscdev.fops = &ak_motor_fops; -+ motor->miscdev.mode = S_IRWXO; -+ spin_lock_init(&motor->lock); -+ -+ setup_timer(&motor->work_timer, ak_motor_timer_hander, (unsigned long)motor); -+ -+ ak_motor_init_cfg(motor); -+ list_add_tail(&motor->list, &motor_list); -+ -+ /*register to miscdevice subsystem*/ -+ ret = misc_register(&motor->miscdev); -+ if(ret) { -+ dev_err(&pdev->dev, "register misc device fail.\n"); -+ ret = -ENOENT; -+ goto err_misc_dev; -+ } -+ PDEBUG("minor:%d\n", motor->miscdev.minor); -+ printk("init the ak-motor device success.\n"); -+ return 0; -+ -+err_misc_dev: -+ kfree(motor); -+ -+ return ret; -+} -+ -+static int __devexit ak_motor_remove(struct platform_device *pdev) -+{ -+ struct ak_motor *motor = platform_get_drvdata(pdev); -+ -+ dev_info(&pdev->dev, "remove the ak motor driver.\n"); -+ misc_deregister(&motor->miscdev); -+ -+ kfree(motor); -+ return 0; -+} -+ -+static struct platform_driver ak_motor_driver = { -+ .driver = { -+ .name = "ak-motor", -+ .owner = THIS_MODULE, -+ }, -+ .probe = ak_motor_probe, -+ .remove = __devexit_p(ak_motor_remove), -+}; -+ -+ -+static int __init ak_motor_init(void) -+{ -+ printk("AK Motor Driver (c) 2013 ANYKA\n"); -+ return platform_driver_register(&ak_motor_driver); -+} -+ -+static void __exit ak_motor_exit(void) -+{ -+ platform_driver_unregister(&ak_motor_driver); -+} -+ -+module_init(ak_motor_init); -+module_exit(ak_motor_exit); -+ -+MODULE_AUTHOR("Anyka"); -+MODULE_DESCRIPTION("Anyka Motor Device Driver"); -+MODULE_ALIAS("platform:ak-motor"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/misc/ak_sn.c b/drivers/misc/ak_sn.c -new file mode 100644 -index 00000000..dbd91b0a ---- /dev/null -+++ b/drivers/misc/ak_sn.c -@@ -0,0 +1,69 @@ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/kobject.h> -+#include <linux/sysfs.h> -+ -+#include <mach-anyka/anyka_types.h> -+#include <mach-anyka/fha_asa.h> -+ -+#define SN_FILE_NAME "SERADDR" -+#define SN_MAX_LEN 64 -+ -+static ssize_t sn_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -+{ -+ unsigned char sn[SN_MAX_LEN] = {0}; -+ unsigned char file_len[4] = {0}; -+ -+ if (FHA_asa_read_file(SN_FILE_NAME, file_len, 4) == AK_FALSE) { -+ goto out; -+ } -+ -+ if (FHA_asa_read_file(SN_FILE_NAME, sn, *(unsigned long*)file_len + 4) == AK_FALSE) { -+ memset(sn, 0, SN_MAX_LEN); -+ goto out; -+ } -+out: -+ return sprintf(buf, "%s\n", sn + 4); -+} -+ -+static struct kobj_attribute sn_attribute = -+ __ATTR(sn, 0666, sn_show, NULL); -+ -+static struct attribute *attrs[] = { -+ &sn_attribute.attr, -+ NULL -+}; -+ -+static struct kobject *sn_kobj; -+ -+static int __init serial_number_init(void) -+{ -+ int ret; -+ -+ sn_kobj = kobject_create_and_add("serial_number", kernel_kobj); -+ if (!sn_kobj) { -+ printk("Create serial number kobject failed\n"); -+ return -ENOMEM; -+ } -+ -+ ret = sysfs_create_file(sn_kobj, *attrs); -+ if (ret) { -+ printk("Create serial number sysfs file failed\n"); -+ kobject_put(sn_kobj); -+ } -+ -+ return ret; -+} -+ -+static void __exit serial_number_exit(void) -+{ -+ kobject_put(sn_kobj); -+} -+ -+module_init(serial_number_init); -+module_exit(serial_number_exit); -+ -+MODULE_DESCRIPTION("Anyka Device Serial Number Interface"); -+MODULE_AUTHOR("Anyka"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/misc/akgpios.c b/drivers/misc/akgpios.c -new file mode 100755 -index 00000000..f3985e65 ---- /dev/null -+++ b/drivers/misc/akgpios.c -@@ -0,0 +1,361 @@ -+/* -+ * drivers/gpio/akgpios.c -+ */ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/list.h> -+#include <linux/errno.h> -+#include <linux/fs.h> -+#include <linux/io.h> -+#include <linux/miscdevice.h> -+#include <linux/platform_device.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/semaphore.h> -+#include <asm/uaccess.h> -+#include <plat-anyka/akgpios.h> -+#include <mach/gpio.h> -+ -+ -+//#define AKGPIO_DEDUB -+#define DBG(fmt...) //printk(fmt); -+ -+#define AKGPIO_DEV_NAME "akgpio" -+ -+#define init_MUTEX(sem) sema_init(sem, 1) -+ -+struct akgpio_custom_device { -+ struct gpio_info gpioinfo; -+ int gpio; -+ int used; -+ int irq_flag; -+ struct semaphore sem; -+ int locked; -+}; -+ -+static struct custom_gpio_data *pdata = NULL; -+static struct akgpio_custom_device *akgpios = NULL; -+static int gpio_num; -+ -+ -+#ifdef AKGPIO_DEDUB -+static void print_gpio_set_info(struct gpio_info *gpio) -+{ -+ printk("GPIO[%d], dir[%s] out[%s] pulldown[%s] pullup[%s] int_pol[%s]\n", -+ gpio->pin, -+ (gpio->dir == AK_GPIO_DIR_OUTPUT) ? "out" : "in", -+ (gpio->value == AK_GPIO_OUT_HIGH) ? "high" : -+ (gpio->value == AK_GPIO_OUT_LOW) ? "low" : "no set", -+ (gpio->pulldown == AK_PULLDOWN_ENABLE) ? "enable" : "disable", -+ (gpio->pullup == AK_PULLUP_ENABLE) ? "enable" : "disable", -+ (gpio->int_pol == AK_GPIO_INT_HIGHLEVEL) ? "high" : -+ (gpio->int_pol == AK_GPIO_INT_LOWLEVEL) ? "low" : "no set"); -+} -+ -+static void print_gpios_info(struct akgpio_custom_device *gpioirq, int ngpio) -+{ -+ int i; -+ for (i = 0; i < ngpio; i++) { -+ printk("akgpios[%d].gpio=%d, akgpios[%d].used=%d\n," -+ " akgpios[%d].irq_flag=%d, akgpios[%d].locked=%d\n," -+ " akgpios[%d].gpioinfo=%p, akgpios[%d].sem=%p\n\n", -+ i, gpioirq[i].gpio, i, gpioirq[i].used, i, gpioirq[i].irq_flag, -+ i, gpioirq[i].locked, i, &gpioirq[i].gpioinfo, i, &gpioirq[i].sem); -+ } -+} -+ -+#else -+static void print_gpio_set_info(struct gpio_info *gpio) {} -+static void print_gpios_info(struct akgpio_custom_device *gpioirq, int ngpio){} -+#endif -+ -+static irqreturn_t akgpio_custom_irq(int irq, void *dev_id) -+{ -+ struct akgpio_custom_device *gpioirq = dev_id; -+ struct gpio_info *gpio = &gpioirq->gpioinfo; -+ unsigned int gpio_level; -+ -+ DBG("akgpio irq: irq=%d, gpioirq->gpio=%d\n", irq, gpioirq->gpio); -+ -+ BUG_ON(irq != ak_gpio_to_irq(gpio->pin)); -+ -+ gpio_level = ak_gpio_getpin(gpio->pin); -+ //disalbe gpio_irq when the button down -+ if ((gpio_level && gpio->int_pol) || (!gpio_level && !gpio->int_pol)) -+ ak_gpio_intpol(gpio->pin, !gpio->int_pol); -+ -+ //enable gpiot_irq when the button up -+ if ((!gpio_level && gpio->int_pol) || (gpio_level && !gpio->int_pol)) { -+ ak_gpio_intpol(gpio->pin, gpio->int_pol); -+ -+ /* release semaphore lock */ -+ if (gpioirq->locked) { -+ up(&gpioirq->sem); -+ gpioirq->locked = 0; -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static long akgpio_custom_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ unsigned int *gpio_array = pdata->gpiopin; -+ unsigned int ngpio = pdata->ngpiopin; -+ struct gpio_info gpio; -+ struct gpio_group_info gpios_info; -+ unsigned int irq, gpiopin; -+ int i, ret; -+ -+ switch(cmd) { -+ case GET_GPIO_NUM: -+ /* get gpio num */ -+ if (copy_to_user((void __user *)arg, &ngpio, sizeof(unsigned int))) -+ return -EINVAL; -+ break; -+ case GET_AVAILABLE_GPIO: -+ /* get unused gpio num, and report user space */ -+ if (copy_to_user((void __user *)arg, gpio_array, ngpio*sizeof(unsigned int))) -+ return -EINVAL; -+ break; -+ -+ case SET_GPIO_FUNC: -+ /* set gpio attribute, include dir(in/out), out(low/high), pull(up/down) */ -+ if (copy_from_user(&gpio, (void __user *)arg, sizeof(struct gpio_info))) -+ return -EINVAL; -+ -+ ak_gpio_set(&gpio); -+ break; -+ -+ case SET_GPIO_LEVEL: -+ /* set gpio level when the pin as output */ -+ if (copy_from_user(&gpio, (void __user *)arg, sizeof(struct gpio_info))) -+ return -EINVAL; -+ -+ ak_gpio_setpin(gpio.pin, gpio.value); -+ break; -+ -+ case SET_GROUP_GPIO_LEVEL: -+ /* set gpio level when the pin as output */ -+ if (copy_from_user(&gpios_info, (void __user *)arg, sizeof(struct gpio_group_info))) -+ return -EINVAL; -+ -+ for(i = 0; i < gpios_info.gpio_num; i++) { -+ ak_gpio_setpin(gpios_info.gpio[i].pin, gpios_info.gpio[i].value); -+ } -+ break; -+ -+ case GET_GPIO_VALUE: -+ /* read gpio value when the pin is input */ -+ if (copy_from_user(&gpio, (void __user *)arg, sizeof(struct gpio_info))) -+ return -EINVAL; -+ -+ gpio.value = ak_gpio_getpin(gpio.pin); -+ if(copy_to_user((void __user *)arg, &gpio, sizeof(struct gpio_info))) -+ return -EINVAL; -+ break; -+ -+ case SET_GPIO_IRQ: -+ { -+ /* set gpio irq func */ -+ struct akgpio_custom_device *gpioirq = NULL; -+ if (copy_from_user(&gpio, (void __user *)arg, sizeof(struct gpio_info))) -+ return -EINVAL; -+ -+ for (i = 0; i < ngpio; i++) { -+ gpioirq = &akgpios[i]; -+ if ((gpioirq->used)&&(gpioirq->gpio == gpio.pin)) { -+ /* gpio irq had set, return for */ -+ break; -+ } else if (!gpioirq->used) { -+ gpioirq->used = 1; -+ gpioirq->gpio = gpio.pin; -+ down(&gpioirq->sem); -+ break; -+ } -+ } -+ -+ for (i = 0; i < ngpio; i++) { -+ gpioirq = &akgpios[i]; -+ if ((gpioirq->used)&&(gpioirq->gpio == gpio.pin)) { -+ memcpy(&gpioirq->gpioinfo, &gpio, sizeof(struct gpio_info)); -+ -+ print_gpio_set_info(&gpio); -+ ak_gpio_set(&gpio); -+ -+ if (!gpioirq->irq_flag) { -+ irq = ak_gpio_to_irq(gpio.pin); -+ DBG("akgpio: gpio[%d], irq[%d]\n", gpio.pin, irq); -+ ret = request_irq(irq, akgpio_custom_irq, -+ ((gpio.int_pol == AK_GPIO_INT_HIGHLEVEL)?(IRQF_TRIGGER_HIGH):(IRQF_TRIGGER_LOW)), -+ "akgpio", gpioirq); -+ if (ret) { -+ printk("Request irq failed. ret=%d\n", ret); -+ return -EINVAL; -+ } -+ gpioirq->irq_flag = 1; -+ } -+ break; -+ } -+ } -+ } -+ break; -+ -+ case LISTEN_GPIO_IRQ: -+ /* wait irq occurs */ -+ gpiopin = (unsigned int)arg; -+ for (i = 0; i < ngpio; i++) { -+ struct akgpio_custom_device *gpioirq = &akgpios[i]; -+ if ((gpioirq->used)&&(gpioirq->gpio == gpiopin)) { -+ gpioirq->locked = 1; -+ down(&gpioirq->sem); -+ /* blocking, wait irq occurs, then continue */ -+ break; -+ } -+ -+ if (i == ngpio) { -+ printk("listen gpio irq: first request irq, then do this.\n"); -+ return -EINVAL; -+ } -+ } -+ break; -+ -+ case DELETE_GPIO_IRQ: -+ /* delete gpio irq that specific */ -+ gpiopin = (unsigned int)arg; -+ for (i = 0; i < ngpio; i++) { -+ struct akgpio_custom_device *gpioirq = &akgpios[i]; -+ if ((gpioirq->used)&&(gpioirq->gpio == gpiopin)) { -+ irq = ak_gpio_to_irq(gpiopin); -+ free_irq(irq, gpioirq); -+ gpioirq->irq_flag = 0; -+ break; -+ } -+ -+ if (i == ngpio) { -+ printk("delete gpio irq: first request irq, then do this.\n"); -+ return -EINVAL; -+ } -+ } -+ break; -+ -+ default: -+ printk("akgpio: the ioctl is unknow.\n"); -+ break; -+ } -+ -+ //print_gpios_info(akgpios, ngpio); -+ return 0; -+} -+ -+static int akgpio_custom_open(struct inode *node, struct file *file) -+{ -+ /* do nothing, return correct */ -+ printk(KERN_INFO "open akgpio device success.\n"); -+ return 0; -+} -+ -+static int akgpio_custom_release(struct inode *node, struct file *file) -+{ -+ /* do nothing */ -+ return 0; -+} -+ -+static const struct file_operations akgpio_ops = { -+ .owner = THIS_MODULE, -+ .open = akgpio_custom_open, -+ .release = akgpio_custom_release, -+ .unlocked_ioctl = akgpio_custom_ioctl, -+}; -+ -+static struct miscdevice akgpio_dev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = AKGPIO_DEV_NAME, -+ .fops = &akgpio_ops, -+ .mode = S_IRWXO, -+}; -+ -+static int akgpio_custom_probe(struct platform_device *pdev) -+{ -+ int i; -+ struct akgpio_custom_device *gpioirq = NULL; -+ -+ /* get platform data of akgpio */ -+ pdata = pdev->dev.platform_data; -+ if ((pdata == NULL)||((pdata)&&(pdata->ngpiopin == 0))) -+ return -ENODEV; -+ -+ /* register misc device */ -+ if (misc_register(&akgpio_dev)) { -+ printk(KERN_ERR "akgpio: Unable register misc device.\n"); -+ return -ENODEV; -+ } -+ -+ gpio_num = pdata->ngpiopin; -+ -+ akgpios = kzalloc(gpio_num * sizeof(struct akgpio_custom_device), GFP_KERNEL); -+ if (akgpios == NULL) -+ return -ENOMEM; -+ gpioirq = akgpios; -+ -+ for (i = 0; i < gpio_num; i++) { -+ gpioirq[i].gpio = -1; -+ gpioirq[i].used = 0; -+ gpioirq[i].irq_flag = 0; -+ init_MUTEX(&gpioirq[i].sem); -+ gpioirq[i].locked = 0; -+ } -+ -+ printk("akgpio driver initialize.\n"); -+ print_gpios_info(gpioirq, gpio_num); -+ return 0; -+} -+ -+static int akgpio_custom_remove(struct platform_device *pdev) -+{ -+ /* release platform data for akgpio */ -+ int i; -+ struct akgpio_custom_device *gpioirq = akgpios; -+ -+ pdata = NULL; -+ misc_deregister(&akgpio_dev); -+ -+ for (i = 0; i < gpio_num; i++) { -+ gpioirq[i].gpio = -1; -+ gpioirq[i].used = 0; -+ gpioirq[i].irq_flag = 0; -+ gpioirq[i].locked = 0; -+ } -+ -+ return 0; -+} -+ -+static struct platform_driver akgpio_custom_driver = { -+ .probe = akgpio_custom_probe, -+ .remove = __devexit_p(akgpio_custom_remove), -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = AKGPIO_DEV_NAME, -+ }, -+}; -+ -+static int __init akgpio_custom_init(void) -+{ -+ return platform_driver_register(&akgpio_custom_driver); -+} -+ -+static void __exit akgpio_custom_exit(void) -+{ -+ platform_driver_unregister(&akgpio_custom_driver); -+} -+ -+module_init(akgpio_custom_init); -+module_exit(akgpio_custom_exit); -+ -+MODULE_AUTHOR("Anyka Microelectronic Ltd."); -+MODULE_DESCRIPTION("Anyka gpio apply for user space control"); -+MODULE_ALIAS("Anyka GPIO Apply"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/misc/akm8975.c b/drivers/misc/akm8975.c -new file mode 100644 -index 00000000..830d2897 ---- /dev/null -+++ b/drivers/misc/akm8975.c -@@ -0,0 +1,732 @@ -+/* drivers/misc/akm8975.c - akm8975 compass driver -+ * -+ * Copyright (C) 2007-2008 HTC Corporation. -+ * Author: Hou-Kun Chen <houkun.chen@gmail.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+/* -+ * Revised by AKM 2009/04/02 -+ * Revised by Motorola 2010/05/27 -+ * -+ */ -+ -+#include <linux/interrupt.h> -+#include <linux/i2c.h> -+#include <linux/slab.h> -+#include <linux/irq.h> -+#include <linux/miscdevice.h> -+#include <linux/gpio.h> -+#include <linux/uaccess.h> -+#include <linux/delay.h> -+#include <linux/input.h> -+#include <linux/workqueue.h> -+#include <linux/freezer.h> -+#include <linux/akm8975.h> -+#include <linux/earlysuspend.h> -+ -+#define AK8975DRV_CALL_DBG 0 -+#if AK8975DRV_CALL_DBG -+#define FUNCDBG(msg) pr_err("%s:%s\n", __func__, msg); -+#else -+#define FUNCDBG(msg) -+#endif -+ -+#define AK8975DRV_DATA_DBG 0 -+#define MAX_FAILURE_COUNT 10 -+ -+struct akm8975_data { -+ struct i2c_client *this_client; -+ struct akm8975_platform_data *pdata; -+ struct input_dev *input_dev; -+ struct work_struct work; -+ struct mutex flags_lock; -+#ifdef CONFIG_HAS_EARLYSUSPEND -+ struct early_suspend early_suspend; -+#endif -+}; -+ -+/* -+* Because misc devices can not carry a pointer from driver register to -+* open, we keep this global. This limits the driver to a single instance. -+*/ -+struct akm8975_data *akmd_data; -+ -+static DECLARE_WAIT_QUEUE_HEAD(open_wq); -+ -+static atomic_t open_flag; -+ -+static short m_flag; -+static short a_flag; -+static short t_flag; -+static short mv_flag; -+ -+static short akmd_delay; -+ -+static ssize_t akm8975_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ return sprintf(buf, "%u\n", i2c_smbus_read_byte_data(client, -+ AK8975_REG_CNTL)); -+} -+static ssize_t akm8975_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ unsigned long val; -+ strict_strtoul(buf, 10, &val); -+ if (val > 0xff) -+ return -EINVAL; -+ i2c_smbus_write_byte_data(client, AK8975_REG_CNTL, val); -+ return count; -+} -+static DEVICE_ATTR(akm_ms1, S_IWUSR | S_IRUGO, akm8975_show, akm8975_store); -+ -+static int akm8975_i2c_rxdata(struct akm8975_data *akm, char *buf, int length) -+{ -+ struct i2c_msg msgs[] = { -+ { -+ .addr = akm->this_client->addr, -+ .flags = 0, -+ .len = 1, -+ .buf = buf, -+ }, -+ { -+ .addr = akm->this_client->addr, -+ .flags = I2C_M_RD, -+ .len = length, -+ .buf = buf, -+ }, -+ }; -+ -+ FUNCDBG("called"); -+ -+ if (i2c_transfer(akm->this_client->adapter, msgs, 2) < 0) { -+ pr_err("akm8975_i2c_rxdata: transfer error\n"); -+ return EIO; -+ } else -+ return 0; -+} -+ -+static int akm8975_i2c_txdata(struct akm8975_data *akm, char *buf, int length) -+{ -+ struct i2c_msg msgs[] = { -+ { -+ .addr = akm->this_client->addr, -+ .flags = 0, -+ .len = length, -+ .buf = buf, -+ }, -+ }; -+ -+ FUNCDBG("called"); -+ -+ if (i2c_transfer(akm->this_client->adapter, msgs, 1) < 0) { -+ pr_err("akm8975_i2c_txdata: transfer error\n"); -+ return -EIO; -+ } else -+ return 0; -+} -+ -+static void akm8975_ecs_report_value(struct akm8975_data *akm, short *rbuf) -+{ -+ struct akm8975_data *data = i2c_get_clientdata(akm->this_client); -+ -+ FUNCDBG("called"); -+ -+#if AK8975DRV_DATA_DBG -+ pr_info("akm8975_ecs_report_value: yaw = %d, pitch = %d, roll = %d\n", -+ rbuf[0], rbuf[1], rbuf[2]); -+ pr_info("tmp = %d, m_stat= %d, g_stat=%d\n", rbuf[3], rbuf[4], rbuf[5]); -+ pr_info("Acceleration: x = %d LSB, y = %d LSB, z = %d LSB\n", -+ rbuf[6], rbuf[7], rbuf[8]); -+ pr_info("Magnetic: x = %d LSB, y = %d LSB, z = %d LSB\n\n", -+ rbuf[9], rbuf[10], rbuf[11]); -+#endif -+ mutex_lock(&akm->flags_lock); -+ /* Report magnetic sensor information */ -+ if (m_flag) { -+ input_report_abs(data->input_dev, ABS_RX, rbuf[0]); -+ input_report_abs(data->input_dev, ABS_RY, rbuf[1]); -+ input_report_abs(data->input_dev, ABS_RZ, rbuf[2]); -+ input_report_abs(data->input_dev, ABS_RUDDER, rbuf[4]); -+ } -+ -+ /* Report acceleration sensor information */ -+ if (a_flag) { -+ input_report_abs(data->input_dev, ABS_X, rbuf[6]); -+ input_report_abs(data->input_dev, ABS_Y, rbuf[7]); -+ input_report_abs(data->input_dev, ABS_Z, rbuf[8]); -+ input_report_abs(data->input_dev, ABS_WHEEL, rbuf[5]); -+ } -+ -+ /* Report temperature information */ -+ if (t_flag) -+ input_report_abs(data->input_dev, ABS_THROTTLE, rbuf[3]); -+ -+ if (mv_flag) { -+ input_report_abs(data->input_dev, ABS_HAT0X, rbuf[9]); -+ input_report_abs(data->input_dev, ABS_HAT0Y, rbuf[10]); -+ input_report_abs(data->input_dev, ABS_BRAKE, rbuf[11]); -+ } -+ mutex_unlock(&akm->flags_lock); -+ -+ input_sync(data->input_dev); -+} -+ -+static void akm8975_ecs_close_done(struct akm8975_data *akm) -+{ -+ FUNCDBG("called"); -+ mutex_lock(&akm->flags_lock); -+ m_flag = 1; -+ a_flag = 1; -+ t_flag = 1; -+ mv_flag = 1; -+ mutex_unlock(&akm->flags_lock); -+} -+ -+static int akm_aot_open(struct inode *inode, struct file *file) -+{ -+ int ret = -1; -+ -+ FUNCDBG("called"); -+ if (atomic_cmpxchg(&open_flag, 0, 1) == 0) { -+ wake_up(&open_wq); -+ ret = 0; -+ } -+ -+ ret = nonseekable_open(inode, file); -+ if (ret) -+ return ret; -+ -+ file->private_data = akmd_data; -+ -+ return ret; -+} -+ -+static int akm_aot_release(struct inode *inode, struct file *file) -+{ -+ FUNCDBG("called"); -+ atomic_set(&open_flag, 0); -+ wake_up(&open_wq); -+ return 0; -+} -+ -+static int akm_aot_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ void __user *argp = (void __user *) arg; -+ short flag; -+ struct akm8975_data *akm = file->private_data; -+ -+ FUNCDBG("called"); -+ -+ switch (cmd) { -+ case ECS_IOCTL_APP_SET_MFLAG: -+ case ECS_IOCTL_APP_SET_AFLAG: -+ case ECS_IOCTL_APP_SET_MVFLAG: -+ if (copy_from_user(&flag, argp, sizeof(flag))) -+ return -EFAULT; -+ if (flag < 0 || flag > 1) -+ return -EINVAL; -+ break; -+ case ECS_IOCTL_APP_SET_DELAY: -+ if (copy_from_user(&flag, argp, sizeof(flag))) -+ return -EFAULT; -+ break; -+ default: -+ break; -+ } -+ -+ mutex_lock(&akm->flags_lock); -+ switch (cmd) { -+ case ECS_IOCTL_APP_SET_MFLAG: -+ m_flag = flag; -+ break; -+ case ECS_IOCTL_APP_GET_MFLAG: -+ flag = m_flag; -+ break; -+ case ECS_IOCTL_APP_SET_AFLAG: -+ a_flag = flag; -+ break; -+ case ECS_IOCTL_APP_GET_AFLAG: -+ flag = a_flag; -+ break; -+ case ECS_IOCTL_APP_SET_MVFLAG: -+ mv_flag = flag; -+ break; -+ case ECS_IOCTL_APP_GET_MVFLAG: -+ flag = mv_flag; -+ break; -+ case ECS_IOCTL_APP_SET_DELAY: -+ akmd_delay = flag; -+ break; -+ case ECS_IOCTL_APP_GET_DELAY: -+ flag = akmd_delay; -+ break; -+ default: -+ return -ENOTTY; -+ } -+ mutex_unlock(&akm->flags_lock); -+ -+ switch (cmd) { -+ case ECS_IOCTL_APP_GET_MFLAG: -+ case ECS_IOCTL_APP_GET_AFLAG: -+ case ECS_IOCTL_APP_GET_MVFLAG: -+ case ECS_IOCTL_APP_GET_DELAY: -+ if (copy_to_user(argp, &flag, sizeof(flag))) -+ return -EFAULT; -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int akmd_open(struct inode *inode, struct file *file) -+{ -+ int err = 0; -+ -+ FUNCDBG("called"); -+ err = nonseekable_open(inode, file); -+ if (err) -+ return err; -+ -+ file->private_data = akmd_data; -+ return 0; -+} -+ -+static int akmd_release(struct inode *inode, struct file *file) -+{ -+ struct akm8975_data *akm = file->private_data; -+ -+ FUNCDBG("called"); -+ akm8975_ecs_close_done(akm); -+ return 0; -+} -+ -+static int akmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ void __user *argp = (void __user *) arg; -+ -+ char rwbuf[16]; -+ int ret = -1; -+ int status; -+ short value[12]; -+ short delay; -+ struct akm8975_data *akm = file->private_data; -+ -+ FUNCDBG("called"); -+ -+ switch (cmd) { -+ case ECS_IOCTL_READ: -+ case ECS_IOCTL_WRITE: -+ if (copy_from_user(&rwbuf, argp, sizeof(rwbuf))) -+ return -EFAULT; -+ break; -+ -+ case ECS_IOCTL_SET_YPR: -+ if (copy_from_user(&value, argp, sizeof(value))) -+ return -EFAULT; -+ break; -+ -+ default: -+ break; -+ } -+ -+ switch (cmd) { -+ case ECS_IOCTL_READ: -+ if (rwbuf[0] < 1) -+ return -EINVAL; -+ -+ ret = akm8975_i2c_rxdata(akm, &rwbuf[1], rwbuf[0]); -+ if (ret < 0) -+ return ret; -+ break; -+ -+ case ECS_IOCTL_WRITE: -+ if (rwbuf[0] < 2) -+ return -EINVAL; -+ -+ ret = akm8975_i2c_txdata(akm, &rwbuf[1], rwbuf[0]); -+ if (ret < 0) -+ return ret; -+ break; -+ case ECS_IOCTL_SET_YPR: -+ akm8975_ecs_report_value(akm, value); -+ break; -+ -+ case ECS_IOCTL_GET_OPEN_STATUS: -+ wait_event_interruptible(open_wq, -+ (atomic_read(&open_flag) != 0)); -+ status = atomic_read(&open_flag); -+ break; -+ case ECS_IOCTL_GET_CLOSE_STATUS: -+ wait_event_interruptible(open_wq, -+ (atomic_read(&open_flag) == 0)); -+ status = atomic_read(&open_flag); -+ break; -+ -+ case ECS_IOCTL_GET_DELAY: -+ delay = akmd_delay; -+ break; -+ -+ default: -+ FUNCDBG("Unknown cmd\n"); -+ return -ENOTTY; -+ } -+ -+ switch (cmd) { -+ case ECS_IOCTL_READ: -+ if (copy_to_user(argp, &rwbuf, sizeof(rwbuf))) -+ return -EFAULT; -+ break; -+ case ECS_IOCTL_GET_OPEN_STATUS: -+ case ECS_IOCTL_GET_CLOSE_STATUS: -+ if (copy_to_user(argp, &status, sizeof(status))) -+ return -EFAULT; -+ break; -+ case ECS_IOCTL_GET_DELAY: -+ if (copy_to_user(argp, &delay, sizeof(delay))) -+ return -EFAULT; -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+/* needed to clear the int. pin */ -+static void akm_work_func(struct work_struct *work) -+{ -+ struct akm8975_data *akm = -+ container_of(work, struct akm8975_data, work); -+ -+ FUNCDBG("called"); -+ enable_irq(akm->this_client->irq); -+} -+ -+static irqreturn_t akm8975_interrupt(int irq, void *dev_id) -+{ -+ struct akm8975_data *akm = dev_id; -+ FUNCDBG("called"); -+ -+ disable_irq_nosync(akm->this_client->irq); -+ schedule_work(&akm->work); -+ return IRQ_HANDLED; -+} -+ -+static int akm8975_power_off(struct akm8975_data *akm) -+{ -+#if AK8975DRV_CALL_DBG -+ pr_info("%s\n", __func__); -+#endif -+ if (akm->pdata->power_off) -+ akm->pdata->power_off(); -+ -+ return 0; -+} -+ -+static int akm8975_power_on(struct akm8975_data *akm) -+{ -+ int err; -+ -+#if AK8975DRV_CALL_DBG -+ pr_info("%s\n", __func__); -+#endif -+ if (akm->pdata->power_on) { -+ err = akm->pdata->power_on(); -+ if (err < 0) -+ return err; -+ } -+ return 0; -+} -+ -+static int akm8975_suspend(struct i2c_client *client, pm_message_t mesg) -+{ -+ struct akm8975_data *akm = i2c_get_clientdata(client); -+ -+#if AK8975DRV_CALL_DBG -+ pr_info("%s\n", __func__); -+#endif -+ /* TO DO: might need more work after power mgmt -+ is enabled */ -+ return akm8975_power_off(akm); -+} -+ -+static int akm8975_resume(struct i2c_client *client) -+{ -+ struct akm8975_data *akm = i2c_get_clientdata(client); -+ -+#if AK8975DRV_CALL_DBG -+ pr_info("%s\n", __func__); -+#endif -+ /* TO DO: might need more work after power mgmt -+ is enabled */ -+ return akm8975_power_on(akm); -+} -+ -+#ifdef CONFIG_HAS_EARLYSUSPEND -+static void akm8975_early_suspend(struct early_suspend *handler) -+{ -+ struct akm8975_data *akm; -+ akm = container_of(handler, struct akm8975_data, early_suspend); -+ -+#if AK8975DRV_CALL_DBG -+ pr_info("%s\n", __func__); -+#endif -+ akm8975_suspend(akm->this_client, PMSG_SUSPEND); -+} -+ -+static void akm8975_early_resume(struct early_suspend *handler) -+{ -+ struct akm8975_data *akm; -+ akm = container_of(handler, struct akm8975_data, early_suspend); -+ -+#if AK8975DRV_CALL_DBG -+ pr_info("%s\n", __func__); -+#endif -+ akm8975_resume(akm->this_client); -+} -+#endif -+ -+ -+static int akm8975_init_client(struct i2c_client *client) -+{ -+ struct akm8975_data *data; -+ int ret; -+ -+ data = i2c_get_clientdata(client); -+ -+ ret = request_irq(client->irq, akm8975_interrupt, IRQF_TRIGGER_RISING, -+ "akm8975", data); -+ -+ if (ret < 0) { -+ pr_err("akm8975_init_client: request irq failed\n"); -+ goto err; -+ } -+ -+ init_waitqueue_head(&open_wq); -+ -+ mutex_lock(&data->flags_lock); -+ m_flag = 1; -+ a_flag = 1; -+ t_flag = 1; -+ mv_flag = 1; -+ mutex_unlock(&data->flags_lock); -+ -+ return 0; -+err: -+ return ret; -+} -+ -+static const struct file_operations akmd_fops = { -+ .owner = THIS_MODULE, -+ .open = akmd_open, -+ .release = akmd_release, -+ .ioctl = akmd_ioctl, -+}; -+ -+static const struct file_operations akm_aot_fops = { -+ .owner = THIS_MODULE, -+ .open = akm_aot_open, -+ .release = akm_aot_release, -+ .ioctl = akm_aot_ioctl, -+}; -+ -+static struct miscdevice akm_aot_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "akm8975_aot", -+ .fops = &akm_aot_fops, -+}; -+ -+static struct miscdevice akmd_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "akm8975_dev", -+ .fops = &akmd_fops, -+}; -+ -+int akm8975_probe(struct i2c_client *client, -+ const struct i2c_device_id *devid) -+{ -+ struct akm8975_data *akm; -+ int err; -+ FUNCDBG("called"); -+ -+ if (client->dev.platform_data == NULL) { -+ dev_err(&client->dev, "platform data is NULL. exiting.\n"); -+ err = -ENODEV; -+ goto exit_platform_data_null; -+ } -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { -+ dev_err(&client->dev, "platform data is NULL. exiting.\n"); -+ err = -ENODEV; -+ goto exit_check_functionality_failed; -+ } -+ -+ akm = kzalloc(sizeof(struct akm8975_data), GFP_KERNEL); -+ if (!akm) { -+ dev_err(&client->dev, -+ "failed to allocate memory for module data\n"); -+ err = -ENOMEM; -+ goto exit_alloc_data_failed; -+ } -+ -+ akm->pdata = client->dev.platform_data; -+ -+ mutex_init(&akm->flags_lock); -+ INIT_WORK(&akm->work, akm_work_func); -+ i2c_set_clientdata(client, akm); -+ -+ err = akm8975_power_on(akm); -+ if (err < 0) -+ goto exit_power_on_failed; -+ -+ akm8975_init_client(client); -+ akm->this_client = client; -+ akmd_data = akm; -+ -+ akm->input_dev = input_allocate_device(); -+ if (!akm->input_dev) { -+ err = -ENOMEM; -+ dev_err(&akm->this_client->dev, -+ "input device allocate failed\n"); -+ goto exit_input_dev_alloc_failed; -+ } -+ -+ set_bit(EV_ABS, akm->input_dev->evbit); -+ -+ /* yaw */ -+ input_set_abs_params(akm->input_dev, ABS_RX, 0, 23040, 0, 0); -+ /* pitch */ -+ input_set_abs_params(akm->input_dev, ABS_RY, -11520, 11520, 0, 0); -+ /* roll */ -+ input_set_abs_params(akm->input_dev, ABS_RZ, -5760, 5760, 0, 0); -+ /* x-axis acceleration */ -+ input_set_abs_params(akm->input_dev, ABS_X, -5760, 5760, 0, 0); -+ /* y-axis acceleration */ -+ input_set_abs_params(akm->input_dev, ABS_Y, -5760, 5760, 0, 0); -+ /* z-axis acceleration */ -+ input_set_abs_params(akm->input_dev, ABS_Z, -5760, 5760, 0, 0); -+ /* temparature */ -+ input_set_abs_params(akm->input_dev, ABS_THROTTLE, -30, 85, 0, 0); -+ /* status of magnetic sensor */ -+ input_set_abs_params(akm->input_dev, ABS_RUDDER, 0, 3, 0, 0); -+ /* status of acceleration sensor */ -+ input_set_abs_params(akm->input_dev, ABS_WHEEL, 0, 3, 0, 0); -+ /* x-axis of raw magnetic vector */ -+ input_set_abs_params(akm->input_dev, ABS_HAT0X, -20480, 20479, 0, 0); -+ /* y-axis of raw magnetic vector */ -+ input_set_abs_params(akm->input_dev, ABS_HAT0Y, -20480, 20479, 0, 0); -+ /* z-axis of raw magnetic vector */ -+ input_set_abs_params(akm->input_dev, ABS_BRAKE, -20480, 20479, 0, 0); -+ -+ akm->input_dev->name = "compass"; -+ -+ err = input_register_device(akm->input_dev); -+ if (err) { -+ pr_err("akm8975_probe: Unable to register input device: %s\n", -+ akm->input_dev->name); -+ goto exit_input_register_device_failed; -+ } -+ -+ err = misc_register(&akmd_device); -+ if (err) { -+ pr_err("akm8975_probe: akmd_device register failed\n"); -+ goto exit_misc_device_register_failed; -+ } -+ -+ err = misc_register(&akm_aot_device); -+ if (err) { -+ pr_err("akm8975_probe: akm_aot_device register failed\n"); -+ goto exit_misc_device_register_failed; -+ } -+ -+ err = device_create_file(&client->dev, &dev_attr_akm_ms1); -+ -+#ifdef CONFIG_HAS_EARLYSUSPEND -+ akm->early_suspend.suspend = akm8975_early_suspend; -+ akm->early_suspend.resume = akm8975_early_resume; -+ register_early_suspend(&akm->early_suspend); -+#endif -+ return 0; -+ -+exit_misc_device_register_failed: -+exit_input_register_device_failed: -+ input_free_device(akm->input_dev); -+exit_input_dev_alloc_failed: -+ akm8975_power_off(akm); -+exit_power_on_failed: -+ kfree(akm); -+exit_alloc_data_failed: -+exit_check_functionality_failed: -+exit_platform_data_null: -+ return err; -+} -+ -+static int __devexit akm8975_remove(struct i2c_client *client) -+{ -+ struct akm8975_data *akm = i2c_get_clientdata(client); -+ FUNCDBG("called"); -+ free_irq(client->irq, NULL); -+ input_unregister_device(akm->input_dev); -+ misc_deregister(&akmd_device); -+ misc_deregister(&akm_aot_device); -+ akm8975_power_off(akm); -+ kfree(akm); -+ return 0; -+} -+ -+static const struct i2c_device_id akm8975_id[] = { -+ { "akm8975", 0 }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(i2c, akm8975_id); -+ -+static struct i2c_driver akm8975_driver = { -+ .probe = akm8975_probe, -+ .remove = akm8975_remove, -+#ifndef CONFIG_HAS_EARLYSUSPEND -+ .resume = akm8975_resume, -+ .suspend = akm8975_suspend, -+#endif -+ .id_table = akm8975_id, -+ .driver = { -+ .name = "akm8975", -+ }, -+}; -+ -+static int __init akm8975_init(void) -+{ -+ pr_info("AK8975 compass driver: init\n"); -+ FUNCDBG("AK8975 compass driver: init\n"); -+ return i2c_add_driver(&akm8975_driver); -+} -+ -+static void __exit akm8975_exit(void) -+{ -+ FUNCDBG("AK8975 compass driver: exit\n"); -+ i2c_del_driver(&akm8975_driver); -+} -+ -+module_init(akm8975_init); -+module_exit(akm8975_exit); -+ -+MODULE_AUTHOR("Hou-Kun Chen <hk_chen@htc.com>"); -+MODULE_DESCRIPTION("AK8975 compass driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/misc/uid_stat.c b/drivers/misc/uid_stat.c -new file mode 100644 -index 00000000..2141124a ---- /dev/null -+++ b/drivers/misc/uid_stat.c -@@ -0,0 +1,156 @@ -+/* drivers/misc/uid_stat.c -+ * -+ * Copyright (C) 2008 - 2009 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <asm/atomic.h> -+ -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/list.h> -+#include <linux/proc_fs.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/stat.h> -+#include <linux/uid_stat.h> -+#include <net/activity_stats.h> -+ -+static DEFINE_SPINLOCK(uid_lock); -+static LIST_HEAD(uid_list); -+static struct proc_dir_entry *parent; -+ -+struct uid_stat { -+ struct list_head link; -+ uid_t uid; -+ atomic_t tcp_rcv; -+ atomic_t tcp_snd; -+}; -+ -+static struct uid_stat *find_uid_stat(uid_t uid) { -+ unsigned long flags; -+ struct uid_stat *entry; -+ -+ spin_lock_irqsave(&uid_lock, flags); -+ list_for_each_entry(entry, &uid_list, link) { -+ if (entry->uid == uid) { -+ spin_unlock_irqrestore(&uid_lock, flags); -+ return entry; -+ } -+ } -+ spin_unlock_irqrestore(&uid_lock, flags); -+ return NULL; -+} -+ -+static int tcp_snd_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len; -+ unsigned int bytes; -+ char *p = page; -+ struct uid_stat *uid_entry = (struct uid_stat *) data; -+ if (!data) -+ return 0; -+ -+ bytes = (unsigned int) (atomic_read(&uid_entry->tcp_snd) + INT_MIN); -+ p += sprintf(p, "%u\n", bytes); -+ len = (p - page) - off; -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ return len; -+} -+ -+static int tcp_rcv_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len; -+ unsigned int bytes; -+ char *p = page; -+ struct uid_stat *uid_entry = (struct uid_stat *) data; -+ if (!data) -+ return 0; -+ -+ bytes = (unsigned int) (atomic_read(&uid_entry->tcp_rcv) + INT_MIN); -+ p += sprintf(p, "%u\n", bytes); -+ len = (p - page) - off; -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ return len; -+} -+ -+/* Create a new entry for tracking the specified uid. */ -+static struct uid_stat *create_stat(uid_t uid) { -+ unsigned long flags; -+ char uid_s[32]; -+ struct uid_stat *new_uid; -+ struct proc_dir_entry *entry; -+ -+ /* Create the uid stat struct and append it to the list. */ -+ if ((new_uid = kmalloc(sizeof(struct uid_stat), GFP_KERNEL)) == NULL) -+ return NULL; -+ -+ new_uid->uid = uid; -+ /* Counters start at INT_MIN, so we can track 4GB of network traffic. */ -+ atomic_set(&new_uid->tcp_rcv, INT_MIN); -+ atomic_set(&new_uid->tcp_snd, INT_MIN); -+ -+ spin_lock_irqsave(&uid_lock, flags); -+ list_add_tail(&new_uid->link, &uid_list); -+ spin_unlock_irqrestore(&uid_lock, flags); -+ -+ sprintf(uid_s, "%d", uid); -+ entry = proc_mkdir(uid_s, parent); -+ -+ /* Keep reference to uid_stat so we know what uid to read stats from. */ -+ create_proc_read_entry("tcp_snd", S_IRUGO, entry , tcp_snd_read_proc, -+ (void *) new_uid); -+ -+ create_proc_read_entry("tcp_rcv", S_IRUGO, entry, tcp_rcv_read_proc, -+ (void *) new_uid); -+ -+ return new_uid; -+} -+ -+int uid_stat_tcp_snd(uid_t uid, int size) { -+ struct uid_stat *entry; -+ activity_stats_update(); -+ if ((entry = find_uid_stat(uid)) == NULL && -+ ((entry = create_stat(uid)) == NULL)) { -+ return -1; -+ } -+ atomic_add(size, &entry->tcp_snd); -+ return 0; -+} -+ -+int uid_stat_tcp_rcv(uid_t uid, int size) { -+ struct uid_stat *entry; -+ activity_stats_update(); -+ if ((entry = find_uid_stat(uid)) == NULL && -+ ((entry = create_stat(uid)) == NULL)) { -+ return -1; -+ } -+ atomic_add(size, &entry->tcp_rcv); -+ return 0; -+} -+ -+static int __init uid_stat_init(void) -+{ -+ parent = proc_mkdir("uid_stat", NULL); -+ if (!parent) { -+ pr_err("uid_stat: failed to create proc entry\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+__initcall(uid_stat_init); -diff --git a/drivers/misc/wl127x-rfkill.c b/drivers/misc/wl127x-rfkill.c -new file mode 100644 -index 00000000..f5b95152 ---- /dev/null -+++ b/drivers/misc/wl127x-rfkill.c -@@ -0,0 +1,121 @@ -+/* -+ * Bluetooth TI wl127x rfkill power control via GPIO -+ * -+ * Copyright (C) 2009 Motorola, Inc. -+ * Copyright (C) 2008 Texas Instruments -+ * Initial code: Pavan Savoy <pavan.savoy@gmail.com> (wl127x_power.c) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/gpio.h> -+#include <linux/rfkill.h> -+#include <linux/platform_device.h> -+#include <linux/wl127x-rfkill.h> -+ -+static int wl127x_rfkill_set_power(void *data, enum rfkill_state state) -+{ -+ int nshutdown_gpio = (int) data; -+ -+ switch (state) { -+ case RFKILL_STATE_UNBLOCKED: -+ gpio_set_value(nshutdown_gpio, 1); -+ break; -+ case RFKILL_STATE_SOFT_BLOCKED: -+ gpio_set_value(nshutdown_gpio, 0); -+ break; -+ default: -+ printk(KERN_ERR "invalid bluetooth rfkill state %d\n", state); -+ } -+ return 0; -+} -+ -+static int wl127x_rfkill_probe(struct platform_device *pdev) -+{ -+ int rc = 0; -+ struct wl127x_rfkill_platform_data *pdata = pdev->dev.platform_data; -+ enum rfkill_state default_state = RFKILL_STATE_SOFT_BLOCKED; /* off */ -+ -+ rc = gpio_request(pdata->nshutdown_gpio, "wl127x_nshutdown_gpio"); -+ if (unlikely(rc)) -+ return rc; -+ -+ rc = gpio_direction_output(pdata->nshutdown_gpio, 0); -+ if (unlikely(rc)) -+ return rc; -+ -+ rfkill_set_default(RFKILL_TYPE_BLUETOOTH, default_state); -+ wl127x_rfkill_set_power(NULL, default_state); -+ -+ pdata->rfkill = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH); -+ if (unlikely(!pdata->rfkill)) -+ return -ENOMEM; -+ -+ pdata->rfkill->name = "wl127x"; -+ pdata->rfkill->state = default_state; -+ /* userspace cannot take exclusive control */ -+ pdata->rfkill->user_claim_unsupported = 1; -+ pdata->rfkill->user_claim = 0; -+ pdata->rfkill->data = (void *) pdata->nshutdown_gpio; -+ pdata->rfkill->toggle_radio = wl127x_rfkill_set_power; -+ -+ rc = rfkill_register(pdata->rfkill); -+ -+ if (unlikely(rc)) -+ rfkill_free(pdata->rfkill); -+ -+ return 0; -+} -+ -+static int wl127x_rfkill_remove(struct platform_device *pdev) -+{ -+ struct wl127x_rfkill_platform_data *pdata = pdev->dev.platform_data; -+ -+ rfkill_unregister(pdata->rfkill); -+ rfkill_free(pdata->rfkill); -+ gpio_free(pdata->nshutdown_gpio); -+ -+ return 0; -+} -+ -+static struct platform_driver wl127x_rfkill_platform_driver = { -+ .probe = wl127x_rfkill_probe, -+ .remove = wl127x_rfkill_remove, -+ .driver = { -+ .name = "wl127x-rfkill", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init wl127x_rfkill_init(void) -+{ -+ return platform_driver_register(&wl127x_rfkill_platform_driver); -+} -+ -+static void __exit wl127x_rfkill_exit(void) -+{ -+ platform_driver_unregister(&wl127x_rfkill_platform_driver); -+} -+ -+module_init(wl127x_rfkill_init); -+module_exit(wl127x_rfkill_exit); -+ -+MODULE_ALIAS("platform:wl127x"); -+MODULE_DESCRIPTION("wl127x-rfkill"); -+MODULE_AUTHOR("Motorola"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig -index 3b1f783b..c9905355 100644 ---- a/drivers/mmc/card/Kconfig -+++ b/drivers/mmc/card/Kconfig -@@ -50,6 +50,15 @@ config MMC_BLOCK_BOUNCE - - If unsure, say Y here. - -+config MMC_BLOCK_DEFERRED_RESUME -+ bool "Deferr MMC layer resume until I/O is requested" -+ depends on MMC_BLOCK -+ default n -+ help -+ Say Y here to enable deferred MMC resume until I/O -+ is requested. This will reduce overall resume latency and -+ save power when theres an SD card inserted but not being used. -+ - config SDIO_UART - tristate "SDIO UART/GPS class support" - help -@@ -67,3 +76,11 @@ config MMC_TEST - - This driver is only of interest to those developing or - testing a host driver. Most people should say N here. -+ -+config SDIO_WIFI -+ tristate "SDIO WIFI support" -+ depends on MMC_ANYKA -+ default n -+ help -+ SDIO function driver for SDIO cards that implements the WIFI -+ module. -diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile -index c73b406a..c6c2f22f 100644 ---- a/drivers/mmc/card/Makefile -+++ b/drivers/mmc/card/Makefile -@@ -7,4 +7,5 @@ mmc_block-objs := block.o queue.o - obj-$(CONFIG_MMC_TEST) += mmc_test.o - - obj-$(CONFIG_SDIO_UART) += sdio_uart.o -+obj-$(CONFIG_SDIO_WIFI) += sdio_wifi.o - -diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c -index 833ff16f..117b98a6 100644 ---- a/drivers/mmc/card/block.c -+++ b/drivers/mmc/card/block.c -@@ -143,11 +143,7 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) - - static inline int mmc_get_devidx(struct gendisk *disk) - { -- int devmaj = MAJOR(disk_devt(disk)); -- int devidx = MINOR(disk_devt(disk)) / perdev_minors; -- -- if (!devmaj) -- devidx = disk->first_minor / perdev_minors; -+ int devidx = disk->first_minor / perdev_minors; - return devidx; - } - -@@ -660,18 +656,22 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error, - req->rq_disk->disk_name, "timed out", name, status); - - /* If the status cmd initially failed, retry the r/w cmd */ -- if (!status_valid) -+ if (!status_valid) { -+ pr_err("%s: status not valid, retrying timeout\n", req->rq_disk->disk_name); - return ERR_RETRY; -- -+ } - /* - * If it was a r/w cmd crc error, or illegal command - * (eg, issued in wrong state) then retry - we should - * have corrected the state problem above. - */ -- if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) -+ if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) { -+ pr_err("%s: command error, retrying timeout\n", req->rq_disk->disk_name); - return ERR_RETRY; -+ } - - /* Otherwise abort the command */ -+ pr_err("%s: not retrying timeout\n", req->rq_disk->disk_name); - return ERR_ABORT; - - default: -@@ -1405,12 +1405,22 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) - return 0; - } - -+static int -+mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card); -+ - static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) - { - int ret; - struct mmc_blk_data *md = mq->data; - struct mmc_card *card = md->queue.card; - -+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME -+ if (mmc_bus_needs_resume(card->host)) { -+ mmc_resume_bus(card->host); -+ mmc_blk_set_blksize(md, card); -+ } -+#endif -+ - if (req && !mq->mqrq_prev->req) - /* claim host only for the first request */ - mmc_claim_host(card->host); -@@ -1523,6 +1533,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, - md->disk->queue = md->queue.queue; - md->disk->driverfs_dev = parent; - set_disk_ro(md->disk, md->read_only || default_ro); -+ md->disk->flags = GENHD_FL_EXT_DEVT; - - /* - * As discussed on lkml, GENHD_FL_REMOVABLE should: -@@ -1820,6 +1831,9 @@ static int mmc_blk_probe(struct mmc_card *card) - mmc_set_drvdata(card, md); - mmc_fixup_device(card, blk_fixups); - -+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME -+ mmc_set_bus_resume_policy(card->host, 1); -+#endif - if (mmc_add_disk(md)) - goto out; - -@@ -1845,6 +1859,9 @@ static void mmc_blk_remove(struct mmc_card *card) - mmc_release_host(card->host); - mmc_blk_remove_req(md); - mmc_set_drvdata(card, NULL); -+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME -+ mmc_set_bus_resume_policy(card->host, 0); -+#endif - } - - #ifdef CONFIG_PM -diff --git a/drivers/mmc/card/sdio_wifi.c b/drivers/mmc/card/sdio_wifi.c -new file mode 100644 -index 00000000..82ef05b6 ---- /dev/null -+++ b/drivers/mmc/card/sdio_wifi.c -@@ -0,0 +1,103 @@ -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <plat-anyka/wifi.h> -+#include <linux/delay.h> -+ -+#define WIFI_DEV_ENABLE 1 -+ -+ -+static int __devinit akplat_wifi_probe(struct platform_device *pdev) -+{ -+ int ret; -+ struct akwifi_platform_data *pdata = pdev->dev.platform_data; -+ -+ printk("%s entered.\n", __func__); -+ if(!pdata) -+ { -+ ret = -EINVAL; -+ return ret; -+ } -+ -+ /* akwifi power on */ -+ if (pdata->gpio_on.pin > 0) { -+ pdata->gpio_init(&pdata->gpio_on); -+ -+ msleep(pdata->power_on_delay); -+ printk("wifi power on\n"); -+ -+ } -+// data->power_off(); -+// data->power_on(); -+ return 0; -+} -+ -+static int __devexit akplat_wifi_remove(struct platform_device *pdev) -+{ -+ struct akwifi_platform_data *pdata = pdev->dev.platform_data; -+ -+ printk("%s entered.\n", __func__); -+ -+ if (pdata->gpio_off.pin > 0) { -+ pdata->gpio_init(&pdata->gpio_off); -+ -+ msleep(pdata->power_off_delay); -+ printk("wifi power off\n"); -+ } -+ -+// data->power_off(); -+ return 0; -+} -+ -+static int akplat_wifi_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+// struct wifi_power_platform_data *data = pdev->dev.platform_data; -+ -+ printk("%s entered.\n", __func__); -+ -+ //data->power_off(); -+ -+ return 0; -+} -+ -+static int akplat_wifi_resume(struct platform_device *pdev) -+{ -+// struct wifi_power_platform_data *data = pdev->dev.platform_data; -+ -+ printk("%s entered.\n", __func__); -+ -+ //data->power_on(); -+ -+ return 0; -+} -+ -+struct platform_device_id sdio_wifi_ids[] ={ -+ { -+ .name = "sdio_wifi_ar6302", -+ .driver_data = 0, -+ }, { }, -+}; -+ -+static struct platform_driver akplat_wifi_driver = { -+ .driver = { -+ .name = "anyka-wifi", -+ }, -+// .id_table = sdio_wifi_ids, -+ .probe = akplat_wifi_probe, -+ .remove = akplat_wifi_remove, -+ .suspend = akplat_wifi_suspend, -+ .resume = akplat_wifi_resume, -+}; -+ -+ -+static int __init sdio_wifi_init(void) -+{ -+ return platform_driver_register(&akplat_wifi_driver); -+} -+ -+static void __exit sdio_wifi_exit(void) -+{ -+ platform_driver_unregister(&akplat_wifi_driver); -+} -+ -+module_init(sdio_wifi_init); -+module_exit(sdio_wifi_exit); -diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig -index ef103871..85c2e1ac 100644 ---- a/drivers/mmc/core/Kconfig -+++ b/drivers/mmc/core/Kconfig -@@ -27,3 +27,20 @@ config MMC_CLKGATE - support handling this in order for it to be of any use. - - If unsure, say N. -+ -+config MMC_EMBEDDED_SDIO -+ boolean "MMC embedded SDIO device support (EXPERIMENTAL)" -+ depends on EXPERIMENTAL -+ help -+ If you say Y here, support will be added for embedded SDIO -+ devices which do not contain the necessary enumeration -+ support in hardware to be properly detected. -+ -+config MMC_PARANOID_SD_INIT -+ bool "Enable paranoid SD card initialization (EXPERIMENTAL)" -+ depends on EXPERIMENTAL -+ help -+ If you say Y here, the MMC layer will be extra paranoid -+ about re-trying SD init requests. This can be a useful -+ work-around for buggy controllers and hardware. Enable -+ if you are experiencing issues with SD detection. -diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c -index ba821fe7..27c49568 100644 ---- a/drivers/mmc/core/core.c -+++ b/drivers/mmc/core/core.c -@@ -26,6 +26,7 @@ - #include <linux/suspend.h> - #include <linux/fault-inject.h> - #include <linux/random.h> -+#include <linux/wakelock.h> - - #include <linux/mmc/card.h> - #include <linux/mmc/host.h> -@@ -140,13 +141,25 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) - cmd->retries = 0; - } - -- if (err && cmd->retries && !mmc_card_removed(host->card)) { -- /* -- * Request starter must handle retries - see -- * mmc_wait_for_req_done(). -- */ -- if (mrq->done) -- mrq->done(mrq); -+ if ((err && cmd->retries && !mmc_card_removed(host->card)) -+ ||(mrq->data && mrq->data->error && mrq->data->retries)) { -+ if (err && cmd->retries) { -+ pr_debug("%s: req failed (CMD%u): %d, retrying...\n", -+ mmc_hostname(host), cmd->opcode, err); -+ -+ cmd->retries--; -+ cmd->error = 0; -+ host->ops->request(host, mrq); -+ } else { -+ printk("%s: data(%s) req failed (CMD%u): %d, retrying(%d)...\n", -+ mmc_hostname(host), -+ (mrq->data->flags & MMC_DATA_READ) ? "read" : "write", -+ cmd->opcode, mrq->data->error, mrq->data->retries); -+ -+ mrq->data->retries--; -+ mrq->data->error = 0; -+ host->ops->request(host, mrq); -+ } - } else { - mmc_should_fail_request(host, mrq); - -@@ -232,6 +245,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) - - mrq->cmd->data = mrq->data; - mrq->data->error = 0; -+ mrq->data->retries = 3; - mrq->data->mrq = mrq; - if (mrq->stop) { - mrq->data->stop = mrq->stop; -@@ -1285,6 +1299,36 @@ static inline void mmc_bus_put(struct mmc_host *host) - spin_unlock_irqrestore(&host->lock, flags); - } - -+int mmc_resume_bus(struct mmc_host *host) -+{ -+ unsigned long flags; -+ -+ if (!mmc_bus_needs_resume(host)) -+ return -EINVAL; -+ -+ printk("%s: Starting deferred resume\n", mmc_hostname(host)); -+ spin_lock_irqsave(&host->lock, flags); -+ host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME; -+ host->rescan_disable = 0; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ mmc_bus_get(host); -+ if (host->bus_ops && !host->bus_dead) { -+ mmc_power_up(host); -+ BUG_ON(!host->bus_ops->resume); -+ host->bus_ops->resume(host); -+ } -+ -+ if (host->bus_ops->detect && !host->bus_dead) -+ host->bus_ops->detect(host); -+ -+ mmc_bus_put(host); -+ printk("%s: Deferred resume completed\n", mmc_hostname(host)); -+ return 0; -+} -+ -+EXPORT_SYMBOL(mmc_resume_bus); -+ - /* - * Assign a mmc bus handler to a host. Only one bus handler may control a - * host at any given time. -@@ -1350,6 +1394,8 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) - spin_unlock_irqrestore(&host->lock, flags); - #endif - host->detect_change = 1; -+ -+ wake_lock(&host->detect_wake_lock); - mmc_schedule_delayed_work(&host->detect, delay); - } - -@@ -2005,10 +2051,11 @@ EXPORT_SYMBOL(mmc_detect_card_removed); - - void mmc_rescan(struct work_struct *work) - { -- static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; -+ static const unsigned freqs[] = {300000, 200000, 100000 }; - struct mmc_host *host = - container_of(work, struct mmc_host, detect.work); - int i; -+ bool extend_wakelock = false; - - if (host->rescan_disable) - return; -@@ -2025,6 +2072,12 @@ void mmc_rescan(struct work_struct *work) - - host->detect_change = 0; - -+ /* If the card was removed the bus will be marked -+ * as dead - extend the wakelock so userspace -+ * can respond */ -+ if (host->bus_dead) -+ extend_wakelock = 1; -+ - /* - * Let mmc_bus_put() free the bus/bus_ops if we've found that - * the card is no longer present. -@@ -2049,16 +2102,24 @@ void mmc_rescan(struct work_struct *work) - - mmc_claim_host(host); - for (i = 0; i < ARRAY_SIZE(freqs); i++) { -- if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) -+ if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) { -+ extend_wakelock = true; - break; -+ } - if (freqs[i] <= host->f_min) - break; - } - mmc_release_host(host); - - out: -- if (host->caps & MMC_CAP_NEEDS_POLL) -+ if (extend_wakelock) -+ wake_lock_timeout(&host->detect_wake_lock, HZ / 2); -+ else -+ wake_unlock(&host->detect_wake_lock); -+ if (host->caps & MMC_CAP_NEEDS_POLL) { -+ wake_lock(&host->detect_wake_lock); - mmc_schedule_delayed_work(&host->detect, HZ); -+ } - } - - void mmc_start_host(struct mmc_host *host) -@@ -2076,7 +2137,8 @@ void mmc_stop_host(struct mmc_host *host) - spin_unlock_irqrestore(&host->lock, flags); - #endif - -- cancel_delayed_work_sync(&host->detect); -+ if (cancel_delayed_work_sync(&host->detect)) -+ wake_unlock(&host->detect_wake_lock); - mmc_flush_scheduled_work(); - - /* clear pm flags now and let card drivers set them as needed */ -@@ -2272,7 +2334,11 @@ int mmc_suspend_host(struct mmc_host *host) - { - int err = 0; - -- cancel_delayed_work(&host->detect); -+ if (mmc_bus_needs_resume(host)) -+ return 0; -+ -+ if (cancel_delayed_work(&host->detect)) -+ wake_unlock(&host->detect_wake_lock); - mmc_flush_scheduled_work(); - - err = mmc_cache_ctrl(host, 0); -@@ -2322,6 +2388,12 @@ int mmc_resume_host(struct mmc_host *host) - int err = 0; - - mmc_bus_get(host); -+ if (mmc_bus_manual_resume(host)) { -+ host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME; -+ mmc_bus_put(host); -+ return 0; -+ } -+ - if (host->bus_ops && !host->bus_dead) { - if (!mmc_card_keep_power(host)) { - mmc_power_up(host); -@@ -2372,10 +2444,15 @@ int mmc_pm_notify(struct notifier_block *notify_block, - case PM_SUSPEND_PREPARE: - - spin_lock_irqsave(&host->lock, flags); -+ if (mmc_bus_needs_resume(host)) { -+ spin_unlock_irqrestore(&host->lock, flags); -+ break; -+ } - host->rescan_disable = 1; - host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; - spin_unlock_irqrestore(&host->lock, flags); -- cancel_delayed_work_sync(&host->detect); -+ if (cancel_delayed_work_sync(&host->detect)) -+ wake_unlock(&host->detect_wake_lock); - - if (!host->bus_ops || host->bus_ops->suspend) - break; -@@ -2396,6 +2473,10 @@ int mmc_pm_notify(struct notifier_block *notify_block, - case PM_POST_RESTORE: - - spin_lock_irqsave(&host->lock, flags); -+ if (mmc_bus_manual_resume(host)) { -+ spin_unlock_irqrestore(&host->lock, flags); -+ break; -+ } - host->rescan_disable = 0; - host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG; - spin_unlock_irqrestore(&host->lock, flags); -@@ -2407,6 +2488,22 @@ int mmc_pm_notify(struct notifier_block *notify_block, - } - #endif - -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+void mmc_set_embedded_sdio_data(struct mmc_host *host, -+ struct sdio_cis *cis, -+ struct sdio_cccr *cccr, -+ struct sdio_embedded_func *funcs, -+ int num_funcs) -+{ -+ host->embedded_sdio_data.cis = cis; -+ host->embedded_sdio_data.cccr = cccr; -+ host->embedded_sdio_data.funcs = funcs; -+ host->embedded_sdio_data.num_funcs = num_funcs; -+} -+ -+EXPORT_SYMBOL(mmc_set_embedded_sdio_data); -+#endif -+ - static int __init mmc_init(void) - { - int ret; -diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c -index 91c84c7a..dd7b1203 100644 ---- a/drivers/mmc/core/host.c -+++ b/drivers/mmc/core/host.c -@@ -329,6 +329,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) - - spin_lock_init(&host->lock); - init_waitqueue_head(&host->wq); -+ wake_lock_init(&host->detect_wake_lock, WAKE_LOCK_SUSPEND, -+ kasprintf(GFP_KERNEL, "%s_detect", mmc_hostname(host))); - INIT_DELAYED_WORK(&host->detect, mmc_rescan); - #ifdef CONFIG_PM - host->pm_notify.notifier_call = mmc_pm_notify; -@@ -381,7 +383,8 @@ int mmc_add_host(struct mmc_host *host) - mmc_host_clk_sysfs_init(host); - - mmc_start_host(host); -- register_pm_notifier(&host->pm_notify); -+ if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) -+ register_pm_notifier(&host->pm_notify); - - return 0; - } -@@ -398,7 +401,9 @@ EXPORT_SYMBOL(mmc_add_host); - */ - void mmc_remove_host(struct mmc_host *host) - { -- unregister_pm_notifier(&host->pm_notify); -+ if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) -+ unregister_pm_notifier(&host->pm_notify); -+ - mmc_stop_host(host); - - #ifdef CONFIG_DEBUG_FS -@@ -425,6 +430,7 @@ void mmc_free_host(struct mmc_host *host) - spin_lock(&mmc_host_lock); - idr_remove(&mmc_host_idr, host->index); - spin_unlock(&mmc_host_lock); -+ wake_lock_destroy(&host->detect_wake_lock); - - put_device(&host->class_dev); - } -diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c -index c272c686..7c76a455 100644 ---- a/drivers/mmc/core/sd.c -+++ b/drivers/mmc/core/sd.c -@@ -806,6 +806,9 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, - bool reinit) - { - int err; -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ int retries; -+#endif - - if (!reinit) { - /* -@@ -832,7 +835,26 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, - /* - * Fetch switch information from card. - */ -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ for (retries = 1; retries <= 3; retries++) { -+ err = mmc_read_switch(card); -+ if (!err) { -+ if (retries > 1) { -+ printk(KERN_WARNING -+ "%s: recovered\n", -+ mmc_hostname(host)); -+ } -+ break; -+ } else { -+ printk(KERN_WARNING -+ "%s: read switch failed (attempt %d)\n", -+ mmc_hostname(host), retries); -+ } -+ } -+#else - err = mmc_read_switch(card); -+#endif -+ - if (err) - return err; - } -@@ -1046,18 +1068,36 @@ static int mmc_sd_alive(struct mmc_host *host) - */ - static void mmc_sd_detect(struct mmc_host *host) - { -- int err; -+ int err = 0; -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ int retries = 5; -+#endif - - BUG_ON(!host); - BUG_ON(!host->card); -- -+ - mmc_claim_host(host); - - /* - * Just check if our card has been removed. - */ -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ while(retries) { -+ err = mmc_send_status(host->card, NULL); -+ if (err) { -+ retries--; -+ udelay(5); -+ continue; -+ } -+ break; -+ } -+ if (!retries) { -+ printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n", -+ __func__, mmc_hostname(host), err); -+ } -+#else - err = _mmc_detect_card_removed(host); -- -+#endif - mmc_release_host(host); - - if (err) { -@@ -1096,12 +1136,31 @@ static int mmc_sd_suspend(struct mmc_host *host) - static int mmc_sd_resume(struct mmc_host *host) - { - int err; -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ int retries; -+#endif - - BUG_ON(!host); - BUG_ON(!host->card); - - mmc_claim_host(host); -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ retries = 5; -+ while (retries) { -+ err = mmc_sd_init_card(host, host->ocr, host->card); -+ -+ if (err) { -+ printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n", -+ mmc_hostname(host), err, retries); -+ mdelay(5); -+ retries--; -+ continue; -+ } -+ break; -+ } -+#else - err = mmc_sd_init_card(host, host->ocr, host->card); -+#endif - mmc_release_host(host); - - return err; -@@ -1155,6 +1214,9 @@ int mmc_attach_sd(struct mmc_host *host) - { - int err; - u32 ocr; -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ int retries; -+#endif - - BUG_ON(!host); - WARN_ON(!host->claimed); -@@ -1217,9 +1279,27 @@ int mmc_attach_sd(struct mmc_host *host) - /* - * Detect and init the card. - */ -+#ifdef CONFIG_MMC_PARANOID_SD_INIT -+ retries = 5; -+ while (retries) { -+ err = mmc_sd_init_card(host, host->ocr, NULL); -+ if (err) { -+ retries--; -+ continue; -+ } -+ break; -+ } -+ -+ if (!retries) { -+ printk(KERN_ERR "%s: mmc_sd_init_card() failure (err = %d)\n", -+ mmc_hostname(host), err); -+ goto err; -+ } -+#else - err = mmc_sd_init_card(host, host->ocr, NULL); - if (err) - goto err; -+#endif - - mmc_release_host(host); - err = mmc_add_card(host->card); -diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c -index 13d0e953..341b4c0f 100644 ---- a/drivers/mmc/core/sdio.c -+++ b/drivers/mmc/core/sdio.c -@@ -10,6 +10,7 @@ - */ - - #include <linux/err.h> -+#include <linux/module.h> - #include <linux/pm_runtime.h> - - #include <linux/mmc/host.h> -@@ -28,6 +29,10 @@ - #include "sdio_ops.h" - #include "sdio_cis.h" - -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+#include <linux/mmc/sdio_ids.h> -+#endif -+ - static int sdio_read_fbr(struct sdio_func *func) - { - int ret; -@@ -713,19 +718,35 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, - goto finish; - } - -- /* -- * Read the common registers. -- */ -- err = sdio_read_cccr(card, ocr); -- if (err) -- goto remove; -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ if (host->embedded_sdio_data.cccr) -+ memcpy(&card->cccr, host->embedded_sdio_data.cccr, sizeof(struct sdio_cccr)); -+ else { -+#endif -+ /* -+ * Read the common registers. -+ */ -+ err = sdio_read_cccr(card, ocr); -+ if (err) -+ goto remove; -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ } -+#endif - -- /* -- * Read the common CIS tuples. -- */ -- err = sdio_read_common_cis(card); -- if (err) -- goto remove; -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ if (host->embedded_sdio_data.cis) -+ memcpy(&card->cis, host->embedded_sdio_data.cis, sizeof(struct sdio_cis)); -+ else { -+#endif -+ /* -+ * Read the common CIS tuples. -+ */ -+ err = sdio_read_common_cis(card); -+ if (err) -+ goto remove; -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ } -+#endif - - if (oldcard) { - int same = (card->cis.vendor == oldcard->cis.vendor && -@@ -1124,14 +1145,36 @@ int mmc_attach_sdio(struct mmc_host *host) - funcs = (ocr & 0x70000000) >> 28; - card->sdio_funcs = 0; - -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ if (host->embedded_sdio_data.funcs) -+ card->sdio_funcs = funcs = host->embedded_sdio_data.num_funcs; -+#endif -+ - /* - * Initialize (but don't add) all present functions. - */ - for (i = 0; i < funcs; i++, card->sdio_funcs++) { -- err = sdio_init_func(host->card, i + 1); -- if (err) -- goto remove; -- -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ if (host->embedded_sdio_data.funcs) { -+ struct sdio_func *tmp; -+ -+ tmp = sdio_alloc_func(host->card); -+ if (IS_ERR(tmp)) -+ goto remove; -+ tmp->num = (i + 1); -+ card->sdio_func[i] = tmp; -+ tmp->class = host->embedded_sdio_data.funcs[i].f_class; -+ tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize; -+ tmp->vendor = card->cis.vendor; -+ tmp->device = card->cis.device; -+ } else { -+#endif -+ err = sdio_init_func(host->card, i + 1); -+ if (err) -+ goto remove; -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ } -+#endif - /* - * Enable Runtime PM for this func (if supported) - */ -@@ -1179,3 +1222,39 @@ err: - return err; - } - -+int sdio_reset_comm(struct mmc_card *card) -+{ -+ struct mmc_host *host = card->host; -+ u32 ocr; -+ int err; -+ -+ printk("%s():\n", __func__); -+ mmc_claim_host(host); -+ -+ mmc_go_idle(host); -+ -+ mmc_set_clock(host, host->f_min); -+ -+ err = mmc_send_io_op_cond(host, 0, &ocr); -+ if (err) -+ goto err; -+ -+ host->ocr = mmc_select_voltage(host, ocr); -+ if (!host->ocr) { -+ err = -EINVAL; -+ goto err; -+ } -+ -+ err = mmc_sdio_init_card(host, host->ocr, card, 0); -+ if (err) -+ goto err; -+ -+ mmc_release_host(host); -+ return 0; -+err: -+ printk("%s: Error resetting SDIO communications (%d)\n", -+ mmc_hostname(host), err); -+ mmc_release_host(host); -+ return err; -+} -+EXPORT_SYMBOL(sdio_reset_comm); -diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c -index 236842ec..56d020e2 100644 ---- a/drivers/mmc/core/sdio_bus.c -+++ b/drivers/mmc/core/sdio_bus.c -@@ -24,6 +24,10 @@ - #include "sdio_cis.h" - #include "sdio_bus.h" - -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+#include <linux/mmc/host.h> -+#endif -+ - /* show configuration fields */ - #define sdio_config_attr(field, format_string) \ - static ssize_t \ -@@ -263,7 +267,14 @@ static void sdio_release_func(struct device *dev) - { - struct sdio_func *func = dev_to_sdio_func(dev); - -- sdio_free_func_cis(func); -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ /* -+ * If this device is embedded then we never allocated -+ * cis tables for this func -+ */ -+ if (!func->card->host->embedded_sdio_data.funcs) -+#endif -+ sdio_free_func_cis(func); - - if (func->info) - kfree(func->info); -diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c -old mode 100644 -new mode 100755 -index 8f6f5ac1..01fa6e86 ---- a/drivers/mmc/core/sdio_io.c -+++ b/drivers/mmc/core/sdio_io.c -@@ -387,6 +387,39 @@ u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret) - } - EXPORT_SYMBOL_GPL(sdio_readb); - -+/** -+ * sdio_readb_ext - read a single byte from a SDIO function -+ * @func: SDIO function to access -+ * @addr: address to read -+ * @err_ret: optional status value from transfer -+ * @in: value to add to argument -+ * -+ * Reads a single byte from the address space of a given SDIO -+ * function. If there is a problem reading the address, 0xff -+ * is returned and @err_ret will contain the error code. -+ */ -+unsigned char sdio_readb_ext(struct sdio_func *func, unsigned int addr, -+ int *err_ret, unsigned in) -+{ -+ int ret; -+ unsigned char val; -+ -+ BUG_ON(!func); -+ -+ if (err_ret) -+ *err_ret = 0; -+ -+ ret = mmc_io_rw_direct(func->card, 0, func->num, addr, (u8)in, &val); -+ if (ret) { -+ if (err_ret) -+ *err_ret = ret; -+ return 0xFF; -+ } -+ -+ return val; -+} -+EXPORT_SYMBOL_GPL(sdio_readb_ext); -+ - /** - * sdio_writeb - write a single byte to a SDIO function - * @func: SDIO function to access -diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 2bc06e73..99146344 100644 ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig -@@ -619,3 +619,13 @@ config MMC_USHC - - Note: These controllers only support SDIO cards and do not - support MMC or SD memory cards. -+ -+config MMC_ANYKA -+ bool "ANYKA MMC/SD/SDIO Card Interface support" -+ depends on ARCH_AK39 -+ help -+ This selects a driver for the MCI interface found in ANYKA's CPUs. -+ If you have a board based on one of those and a MMC/SD -+ slot, say Y here. If unsure, say N. -+ -+ -diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index 3e7e26d0..7160d24c 100644 ---- a/drivers/mmc/host/Makefile -+++ b/drivers/mmc/host/Makefile -@@ -53,6 +53,7 @@ obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o - obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o - obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o - obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o -+obj-$(CONFIG_MMC_ANYKA) +=akmci.o - - ifeq ($(CONFIG_CB710_DEBUG),y) - CFLAGS-cb710-mmc += -DDEBUG -diff --git a/drivers/mmc/host/akmci.c b/drivers/mmc/host/akmci.c -new file mode 100644 -index 00000000..f5b895e8 ---- /dev/null -+++ b/drivers/mmc/host/akmci.c -@@ -0,0 +1,1408 @@ -+/* -+ * linux/drivers/mmc/host/plat-anyka/akmci.c - Anyka MMC/SD/SDIO driver -+ * -+ * Copyright (C) 2010 Anyka, Ltd, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/ioport.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <linux/err.h> -+#include <linux/highmem.h> -+#include <linux/log2.h> -+#include <linux/mmc/host.h> -+#include <linux/clk.h> -+#include <linux/cpufreq.h> -+#include <linux/scatterlist.h> -+#include <linux/irq.h> -+#include <linux/gpio.h> -+#include <linux/dma-mapping.h> -+#include <linux/notifier.h> -+ -+#include <asm/cacheflush.h> -+#include <asm/div64.h> -+#include <asm/io.h> -+#include <asm/sizes.h> -+#include <plat/l2.h> -+ -+#include <plat-anyka/adkey.h> -+#include <plat-anyka/drv_module_lock.h> -+#include <mach/gpio.h> -+#include <mach/clock.h> -+#include <mach/reset.h> -+#include <plat-anyka/akmci.h> -+ -+#define DRIVER_NAME "akmci" -+//#define DRIVER_NAME "ak-mci" -+ -+#undef PDEBUG -+ -+#define ___hdbg___() //printk("akmci:----func:%s---line:%d----\n", __func__, __LINE__); -+#define DDREGS(host) //dbg_dumpregs(host, __func__, __LINE__) -+#define DDDATA(h, d, s) //dbg_dumpdata(h, d, s) -+#define HDBG(fmt, args...) //printk(fmt, ##args) -+ -+//#define MCI_DBG -+ -+#ifdef MCI_DBG -+#ifdef __KERNEL__ -+#define PDEBUG(fmt, args...) printk(KERN_INFO "akmci:" fmt, ##args) -+#else -+#define PDEBUG(fmt, args...) fprintf(stderr, "%s %d:" fmt,__FILE__, __LINE__, ## args) -+#endif -+#else -+#define PDEBUG(fmt, args...) -+#endif -+ -+ -+static inline void dbg_dumpregs(struct akmci_host *host, -+ const char *prefix, int eflags) -+{ -+ u32 clkcon, cmdarg, cmd, cmdrsp, rsp1, rsp2, rsp3, rsp4; -+ u32 dtimer, datlen, datcon, datcnt, stat, imask, dmamode, cpumode; -+ -+ clkcon = readl(host->base + MCI_CLK_REG); -+ cmdarg = readl(host->base + MCI_ARGUMENT_REG); -+ cmd = readl(host->base + MCI_COMMAND_REG); -+ cmdrsp = readl(host->base + MCI_RESPCMD_REG); -+ -+ rsp1 = readl(host->base + MCI_RESPONSE0_REG); -+ rsp2 = readl(host->base + MCI_RESPONSE1_REG); -+ rsp3 = readl(host->base + MCI_RESPONSE2_REG); -+ rsp4 = readl(host->base + MCI_RESPONSE3_REG); -+ -+ dtimer = readl(host->base + MCI_DATATIMER_REG); -+ datlen = readl(host->base + MCI_DATALENGTH_REG); -+ datcon = readl(host->base + MCI_DATACTRL_REG); -+ datcnt = readl(host->base + MCI_DATACNT_REG); -+ -+ stat = 0; //readl(host->base + MCI_STATUS_REG); -+ imask = readl(host->base + MCI_MASK_REG); -+ dmamode = readl(host->base + MCI_DMACTRL_REG); -+ cpumode = readl(host->base + MCI_FIFO_REG); -+ -+ PDEBUG("current prefix: %s (%d)\n", prefix, eflags); -+ -+ PDEBUG("clkcon:[%08x], cmdarg:[%08x], cmd:[%08x], cmdrsp:[%08x].\n", -+ clkcon, cmdarg, cmd, cmdrsp); -+ PDEBUG("rsp1:[%08x], rsp2:[%08x], rsp3:[%08x], rsp4:[%08x]\n", -+ rsp1, rsp2, rsp3, rsp4); -+ PDEBUG("dtimer:[%08x], datlen:[%08x], datcon:[%08x], datcnt:[%08x]\n", -+ dtimer, datlen, datcon, datcnt); -+ PDEBUG("stat:[%08x], imask:[%08x], dmamode:[%08x], cpumode:[%08x]\n", -+ stat, imask, dmamode, cpumode); -+} -+ -+static inline void dbg_dumpdata(struct akmci_host *host, -+ void *data, int size) -+{ -+ int ii; -+ int dsize = (size +3)/4; -+ u32 *dptr = data; -+ -+ printk("xfer data (size:%d):", size); -+ -+ for(ii = 0; ii < dsize; ii++) { -+ if((ii%10) == 0) -+ printk("\n"); -+ -+ printk("%08x ", *(dptr + ii)); -+ } -+ printk("\n"); -+} -+ -+/** -+ * the data transfer mode description. -+*/ -+static char* xfer_mode_desc[] = { -+ "unknown", -+ "l2dma", -+ "l2pio", -+ "inner pio", -+ }; -+ -+/** -+ * the sd/mmc/sdio card detect mode description. -+*/ -+static char* detect_mode_desc[] = { -+ "plugin alway", -+ "GPIO detect", -+ "AD detect", -+ }; -+ -+ -+static void akmci_drv_lock(struct akmci_host *host) -+{ -+ if(host->mci_mode == MCI_MODE_MMC_SD) { -+ ak_drv_module_protect(DRV_MODULE_SDMMC); -+ } -+} -+static void akmci_drv_unlock(struct akmci_host *host) -+{ -+ if(host->mci_mode == MCI_MODE_MMC_SD) { -+ ak_drv_module_unprotect(DRV_MODULE_SDMMC); -+ } -+} -+ -+static void akmci_init_sharepin(struct akmci_host *host) -+{ -+ if(host->mci_mode == MCI_MODE_MMC_SD) { -+ if(ak_drv_module_lock(DRV_MODULE_SDMMC) < 0) -+ ak_group_config(ePIN_AS_MCI); -+ ak_drv_module_unlock(DRV_MODULE_SDMMC); -+ } else { -+ if(ak_drv_module_lock(DRV_MODULE_SDIO) < 0) -+ ak_group_config(ePIN_AS_SDIO); -+ ak_drv_module_unlock(DRV_MODULE_SDIO); -+ } -+} -+ -+ -+#define MCI_L2_ADDR(host) \ -+ ((host->mci_mode == MCI_MODE_MMC_SD) ? ADDR_MMC_SD : ADDR_SDIO) -+ -+/** -+* akmci_xfer_mode - judgement the mci transfer mode. -+* ret: AKMCI_XFER_L2DMA: use for l2 dma mode -+* AKMCI_XFER_L2PIO: use for l2 fifo mode. -+* AKMCI_XFER_INNERPIO: use for inner fifo mode. -+*/ -+static inline int akmci_xfer_mode(struct akmci_host *host) -+{ -+ return host->xfer_mode; -+} -+ -+static inline int enable_imask(struct akmci_host *host, u32 imask) -+{ -+ u32 newmask; -+ -+ newmask = readl(host->base + MCI_MASK_REG); -+ newmask |= imask; -+ writel(newmask, host->base + MCI_MASK_REG); -+ -+ return newmask; -+} -+ -+static inline int disable_imask(struct akmci_host *host, u32 imask) -+{ -+ u32 newmask; -+ -+ newmask = readl(host->base + MCI_MASK_REG); -+ newmask &= ~imask; -+ writel(newmask, host->base + MCI_MASK_REG); -+ -+ return newmask; -+} -+ -+static inline void clear_imask(struct akmci_host *host) -+{ -+ u32 mask = readl(host->base + MCI_MASK_REG); -+ -+ /* preserve the SDIO IRQ mask state */ -+ mask &= MCI_SDIOINTMASK; -+ writel(mask, host->base + MCI_MASK_REG); -+} -+ -+static void akmci_reset(struct akmci_host *host) -+{ -+ if(host->mci_mode == MCI_MODE_MMC_SD) { -+ ak_soft_reset(AK_SRESET_MMCSD); -+ } else { -+ ak_soft_reset(AK_SRESET_SDIO); -+ } -+} -+ -+/** -+ * @brief transmitting data. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *host information of data transmitted, including data buf pointer, data len . -+ * @return void. -+*/ -+static void akmci_l2xfer(struct akmci_host *host) -+{ -+ int sg_remain; -+ u32 xferlen; -+ u8 dir; -+ u32 *tempbuf = NULL; -+ dma_addr_t phyaddr = 0; -+ -+ if (host->data->flags & MMC_DATA_WRITE) { -+ dir = MEM2BUF; -+ } else { -+ dir = BUF2MEM; -+ } -+ -+ sg_remain = host->sg_ptr->length - host->sg_off; -+ if (sg_remain <= 0) -+ { -+ host->sg_ptr = sg_next(host->sg_ptr); -+ if (host->sg_ptr == NULL) -+ return; -+ -+ host->sg_off = 0; -+ sg_remain = host->sg_ptr->length - host->sg_off; -+ } -+ -+#ifdef CONFIG_MMC_BLOCK_BOUNCE -+ xferlen = sg_remain; -+#else -+ xferlen = (sg_remain > host->data->blksz) ? host->data->blksz : sg_remain; -+#endif -+ -+ if ((akmci_xfer_mode(host) == AKMCI_XFER_L2DMA) && -+ xferlen >= L2_DMA_ALIGN) -+ { -+ PDEBUG("akmci transfer data: DMA mode.\n"); -+ phyaddr = sg_dma_address(host->sg_ptr) + host->sg_off; -+ l2_combuf_dma(phyaddr, host->l2buf_id, xferlen, dir, AK_FALSE); -+ } else { -+ PDEBUG("akmci transfer data: CPU mode.\n"); -+ tempbuf = sg_virt(host->sg_ptr) + host->sg_off; -+ l2_combuf_cpu((unsigned long)tempbuf, host->l2buf_id, xferlen, dir); -+ } -+ -+ host->sg_off += xferlen; -+ host->data_xfered += xferlen; -+ host->size -= xferlen; -+ -+ /* debug info if data transfer error */ -+ if(host->data_err_flag > 0) { -+ printk("mci_xfer transfered: xferptr = 0x%p, xfer_offset=%d, xfer_bytes=%d\n", -+ sg_virt(host->sg_ptr)+host->sg_off, host->sg_off, host->data_xfered); -+ } -+} -+ -+ -+void akmci_init_sg(struct akmci_host *host, struct mmc_data *data) -+{ -+ /* -+ * Ideally, we want the higher levels to pass us a scatter list. -+ */ -+ host->sg_len = data->sg_len; -+ host->sg_ptr = data->sg; -+ host->sg_off = 0; -+} -+ -+int akmci_next_sg(struct akmci_host *host) -+{ -+ host->sg_ptr++; -+ host->sg_off = 0; -+ return --host->sg_len; -+} -+ -+/** -+ * @brief stop data, close interrupt. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *host get the base address of resgister. -+ * @return void. -+ */ -+static void akmci_stop_data(struct akmci_host *host) -+{ -+ writel(0, host->base + MCI_DMACTRL_REG); -+ writel(0, host->base + MCI_DATACTRL_REG); -+ -+ /* disable mci data irq */ -+ disable_imask(host, MCI_DATAIRQMASKS|MCI_FIFOFULLMASK|MCI_FIFOEMPTYMASK); -+ -+ if(akmci_xfer_mode(host) ==AKMCI_XFER_L2DMA) { -+ if (host->data->flags & MMC_DATA_WRITE) { -+ dma_sync_sg_for_cpu(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_TO_DEVICE); -+ dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_TO_DEVICE); -+ } else { -+ dma_sync_sg_for_cpu(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_FROM_DEVICE); -+ dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, DMA_FROM_DEVICE); -+ } -+ } -+ -+ host->sg_ptr = NULL; -+ host->sg_len = 0; -+ host->sg_off = 0; -+ -+ host->data = NULL; -+} -+ -+/** -+ * @brief finish a request,release resource. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *host information of sd controller. -+ * @param [in] *mrq information of request. -+ * @return void. -+ */ -+static void akmci_request_end(struct akmci_host *host, struct mmc_request *mrq) -+{ -+ int not_retry = 0; -+ -+ writel(0, host->base + MCI_COMMAND_REG); -+ -+ BUG_ON(host->data); -+ host->mrq = NULL; -+ host->cmd = NULL; -+ -+ if(host->data_err_flag > 0) { -+ akmci_reset(host); -+ -+ writel(MCI_ENABLE|MCI_FAIL_TRIGGER, host->base + MCI_CLK_REG); -+ writel(readl(host->base + MCI_CLK_REG)|host->clkreg, host->base + MCI_CLK_REG); -+ mdelay(10); -+ } -+ -+ if(host->l2buf_id != BUF_NULL) { -+ l2_free(MCI_L2_ADDR(host)); -+ host->l2buf_id = BUF_NULL; -+ } -+ -+ if (mrq->data) -+ mrq->data->bytes_xfered = host->data_xfered; -+ -+ /* -+ * Need to drop the host lock here; mmc_request_done may call -+ * back into the driver... -+ */ -+ spin_unlock(&host->lock); -+ -+ not_retry = (!mrq->cmd->error) || ((mrq->cmd->error && (mrq->cmd->retries == 0))); -+ -+ mmc_request_done(host->mmc, mrq); -+ PDEBUG("finalize the mci request.\n"); -+ -+ /*if request fail,then mmc_request_done send request again, -+ * ak_mci_send_request not down nand_lock in interrupt,so not to up nand_lock. -+ */ -+ if (not_retry) { -+ akmci_drv_unlock(host); -+ } -+ -+#ifdef CONFIG_CPU_FREQ -+ /*if request fail,then mmc_request_done send request again, ak_mci_send_request -+ * not down freq_lock in interrupt,so not to unlock freq_lock. -+ */ -+ if (not_retry) { -+ up(&host->freq_lock); -+ } -+#endif -+ -+ spin_lock(&host->lock); -+} -+ -+#define BOTH_DIR (MMC_DATA_WRITE | MMC_DATA_READ) -+ -+/** -+ * @brief config sd controller, start transmitting data. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *host information of sd controller. -+ * @param [in] *data information of data transmitted. -+ * @return void. -+ */ -+static void akmci_start_data(struct akmci_host *host, struct mmc_data *data) -+{ -+ unsigned int datactrl, dmacon; -+ -+ PDEBUG("%s: blksz %04x blks %04x flags %08x\n", -+ __func__, data->blksz, data->blocks, data->flags); -+ BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); -+ -+ host->data = data; -+ host->size = data->blksz * data->blocks; -+ host->data_xfered = 0; -+ -+ akmci_init_sg(host, data); -+ -+ if(akmci_xfer_mode(host) == AKMCI_XFER_L2DMA) { -+ /* set dma addr */ -+ if (data->flags & MMC_DATA_WRITE) -+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, DMA_TO_DEVICE); -+ else -+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, DMA_FROM_DEVICE); -+ } -+ -+ writel(TRANS_DATA_TIMEOUT, host->base + MCI_DATATIMER_REG); -+ writel(host->size, host->base + MCI_DATALENGTH_REG); -+ -+ if(akmci_xfer_mode(host) != AKMCI_XFER_INNERPIO) { -+ /*dma mode register*/ -+ dmacon = MCI_DMA_BUFEN | MCI_DMA_SIZE(MCI_L2FIFO_SIZE/4); -+ -+ if(akmci_xfer_mode(host) == AKMCI_XFER_L2DMA) { -+ dmacon |= MCI_DMA_EN; -+ } -+ writel(dmacon, host->base + MCI_DMACTRL_REG); -+ } -+ -+ /* enable mci data irq */ -+ enable_imask(host, MCI_DATAIRQMASKS); -+ -+ datactrl = MCI_DPSM_ENABLE; -+ -+ switch (host->bus_width) { -+ case MMC_BUS_WIDTH_8: -+ datactrl |= MCI_DPSM_BUSMODE(2); -+ break; -+ case MMC_BUS_WIDTH_4: -+ datactrl |= MCI_DPSM_BUSMODE(1); -+ break; -+ case MMC_BUS_WIDTH_1: -+ default: -+ datactrl |= MCI_DPSM_BUSMODE(0); -+ break; -+ } -+ -+ if (data->flags & MMC_DATA_STREAM) { -+ PDEBUG("STREAM Data\n"); -+ datactrl |= MCI_DPSM_STREAM; -+ } else { -+ PDEBUG("BLOCK Data: %u x %u\n", data->blksz, data->blocks); -+ datactrl |= MCI_DPSM_BLOCKSIZE(data->blksz); -+ datactrl &= ~MCI_DPSM_STREAM; -+ } -+ -+ if (data->flags & MMC_DATA_READ) -+ datactrl |= MCI_DPSM_DIRECTION; -+ else if (data->flags & MMC_DATA_WRITE) -+ datactrl &= ~MCI_DPSM_DIRECTION; -+ -+ /* configurate data controller register */ -+ writel(datactrl, host->base + MCI_DATACTRL_REG); -+ -+ PDEBUG("ENABLE DATA IRQ, datactrl: 0x%08x, timeout: 0x%08x, len: %u\n", -+ datactrl, readl(host->base + MCI_DATATIMER_REG), host->size); -+ -+ if((akmci_xfer_mode(host) != AKMCI_XFER_INNERPIO) && -+ data->flags & MMC_DATA_WRITE) -+ akmci_l2xfer(host); -+} -+ -+/** -+ * @brief config sd controller, start sending command. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *host information of sd controller. -+ * @param [in] *cmd information of cmd sended. -+ * @return void. -+ */ -+static void akmci_start_command(struct akmci_host *host, struct mmc_command *cmd) -+{ -+ unsigned int ccon; -+ -+ PDEBUG("mci send cmd: op %i arg 0x%08x flags 0x%08x.%s data.\n", -+ cmd->opcode, cmd->arg, cmd->flags, cmd->data ? "contain":"no"); -+ -+ writel(cmd->arg, host->base + MCI_ARGUMENT_REG); -+ /* enable mci cmd irq */ -+ enable_imask(host, MCI_CMDIRQMASKS); -+ -+ -+ ccon = MCI_CPSM_CMD(cmd->opcode) | MCI_CPSM_ENABLE; -+ if (cmd->flags & MMC_RSP_PRESENT) { -+ ccon |= MCI_CPSM_RESPONSE; -+ if (cmd->flags & MMC_RSP_136) -+ ccon |= MCI_CPSM_LONGRSP; -+ } -+ -+ if (cmd->data) -+ ccon |= MCI_CPSM_WITHDATA; -+ -+ host->cmd = cmd; -+ -+ /* configurate cmd controller register */ -+ writel(ccon, host->base + MCI_COMMAND_REG); -+} -+ -+ -+static void print_mci_data_err(struct mmc_data *data, -+ unsigned int status, const char *err) -+{ -+ if (data->flags & MMC_DATA_READ) { -+ printk("akmci: data(read) status=%d %s\n", status, err); -+ } else if (data->flags & MMC_DATA_WRITE) { -+ printk("akmci: data(write) status=%d %s\n", status, err); -+ } -+} -+ -+/** -+ * @brief data handle in sdio interrupt. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *host information of sd controller. -+ * @param [in] *data information of data transmitting. -+ * @return void. -+ */ -+static void akmci_data_irq(struct akmci_host *host, struct mmc_data *data, -+ unsigned int status) -+{ -+ if(status & MCI_DATABLOCKEND) { -+ if((akmci_xfer_mode(host) == AKMCI_XFER_L2DMA) || -+ (akmci_xfer_mode(host) == AKMCI_XFER_L2PIO)) { -+ //wait L2 dma finish, if need frac dma,start frac dma -+ if((akmci_xfer_mode(host) == AKMCI_XFER_L2DMA) && -+ (AK_FALSE == l2_combuf_wait_dma_finish(host->l2buf_id))) -+ return; -+ -+ if (data->flags & MMC_DATA_WRITE) -+ l2_clr_status(host->l2buf_id); -+ -+ if (host->size > 0) { -+ akmci_l2xfer(host); -+ } -+ } -+ } -+ -+ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT)) { -+ if (status & MCI_DATACRCFAIL) { -+ data->error = -EILSEQ; -+ print_mci_data_err(data, status, "illeage byte sequence"); -+ } else if (status & MCI_DATATIMEOUT) { -+ data->error = -ETIMEDOUT; -+ print_mci_data_err(data, status, "transfer timeout"); -+ } -+ -+ status |= MCI_DATAEND; -+ host->data_err_flag = 1; -+ -+ printk("akmci need transfer: data->sg = 0x%p, data->sg_len=%d(sg)," -+ " data->sg->length=%d, remain data = %d\n", -+ data->sg, data->sg_len, data->sg->length, -+ __raw_readl(host->base + 0x30)); -+ -+ /* -+ * We hit an error condition. Ensure that any data -+ * partially written to a page is properly coherent. -+ */ -+ if (host->sg_len && data->flags & MMC_DATA_READ) -+ flush_dcache_page(sg_page(host->sg_ptr)); -+ } -+ -+ if (status & MCI_DATAEND) { -+ if ((data->retries > 0) && data->error) { -+ printk("data->error = %d, data->retries = %d\n", -+ data->error, data->retries); -+ -+ /* support retry if error */ -+ akmci_stop_data(host); -+ akmci_request_end(host, data->mrq); -+ } else { -+ -+ //wait L2 dma finish, if need frac dma,start frac dma -+ if((akmci_xfer_mode(host) == AKMCI_XFER_L2DMA) && -+ (AK_FALSE == l2_combuf_wait_dma_finish(host->l2buf_id))) -+ return; -+ -+ host->data_err_flag = 0; -+ akmci_stop_data(host); -+ -+ if (!data->stop) -+ akmci_request_end(host, data->mrq); -+ else -+ akmci_start_command(host, data->stop); -+ } -+ } -+} -+ -+/** -+ * @brief cmd handle in sd interrupt. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *host information of sd controller. -+ * @param [in] *cmd information of cmd sended. -+ *@param [in] *status the status of sd controller. -+ * @return void. -+ */ -+static void akmci_cmd_irq(struct akmci_host *host, struct mmc_command *cmd, -+ unsigned int status) -+{ -+ host->cmd = NULL; -+ -+ cmd->resp[0] = readl(host->base + MCI_RESPONSE0_REG); -+ cmd->resp[1] = readl(host->base + MCI_RESPONSE1_REG); -+ cmd->resp[2] = readl(host->base + MCI_RESPONSE2_REG); -+ cmd->resp[3] = readl(host->base + MCI_RESPONSE3_REG); -+ -+ PDEBUG("resp[0]=0x%x, [1]=0x%x, resp[2]=0x%x, [3]=0x%x\n", -+ cmd->resp[0],cmd->resp[1],cmd->resp[2],cmd->resp[3]); -+ -+ if (status & MCI_RESPTIMEOUT) { -+ cmd->error = -ETIMEDOUT; -+ PDEBUG("CMD: send timeout\n"); -+ } else if (status & MCI_RESPCRCFAIL && cmd->flags & MMC_RSP_CRC) { -+ cmd->error = -EILSEQ; -+ PDEBUG("CMD: illegal byte sequence\n"); -+ } -+ -+ /* disable mci cmd irq */ -+ disable_imask(host, MCI_CMDIRQMASKS); -+ -+ if (!cmd->data || cmd->error) { -+ if (host->data) -+ akmci_stop_data(host); -+ akmci_request_end(host, cmd->mrq); -+ } else if (!(cmd->data->flags & MMC_DATA_READ)) { -+ /* transfer data from host to sd card */ -+ akmci_start_data(host, cmd->data); -+ } -+} -+ -+/* -+ * Handle completion of command and data transfers. -+ */ -+static irqreturn_t akmci_irq(int irq, void *dev_id) -+{ -+ struct akmci_host *host = dev_id; -+ u32 stat_mask; -+ u32 status; -+ int ret = 0; -+ -+ spin_lock(&host->lock); -+ -+ status = readl(host->base + MCI_STATUS_REG); -+ if (status & MCI_SDIOINT) { -+ /*must disable sdio irq ,than read status to clear the sdio status, -+ * else sdio irq will come again. -+ */ -+ mmc_signal_sdio_irq(host->mmc); -+ status |= readl(host->base + MCI_STATUS_REG); -+ } -+ -+ stat_mask = MCI_RESPCRCFAIL|MCI_RESPTIMEOUT|MCI_CMDSENT|MCI_RESPEND; -+ if ((status & stat_mask) && host->cmd) -+ akmci_cmd_irq(host, host->cmd, status); -+ -+ stat_mask = MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_DATAEND| -+ MCI_DATABLOCKEND|MCI_STARTBIT_ERR; -+ -+ if ((status & stat_mask) && host->data) -+ akmci_data_irq(host, host->data, status); -+ -+ ret = 1; -+ spin_unlock(&host->lock); -+ -+ return IRQ_RETVAL(ret); -+ -+} -+ -+ -+static void akmci_send_request(struct mmc_host *mmc) -+{ -+ struct akmci_host *host = mmc_priv(mmc); -+ struct mmc_request *mrq = host->mrq; -+ unsigned long flags; -+ -+#ifdef CONFIG_CPU_FREQ -+ /* need not to acquire the freq_lock in interrupt. */ -+ if (!in_interrupt()) -+ down(&host->freq_lock); -+#endif -+ -+ /* need not to acquire the nand_lock in interrupt. */ -+ if (!in_interrupt()) { -+ akmci_drv_lock(host); -+ } -+ -+ if(mrq->data || mrq->cmd->data) { -+ host->l2buf_id = l2_alloc(MCI_L2_ADDR(host)); -+ if (BUF_NULL == host->l2buf_id) { -+ printk("L2 buffer malloc fail!\n"); -+ BUG(); -+ } -+ } -+ -+ spin_lock_irqsave(&host->lock, flags); -+ -+ if (mrq->data && (mrq->data->flags & MMC_DATA_READ)) -+ akmci_start_data(host, mrq->data); -+ -+ akmci_start_command(host, mrq->cmd); -+ -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+ -+/** -+ * @brief detect sdio card's level type . -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] data getting the information of sd host. -+ * @return void. -+ */ -+static void akmci_detect_change(unsigned long data) -+{ -+ struct akmci_host *host = (struct akmci_host *)data; -+ -+ PDEBUG("card detect change.\n"); -+ -+ mmc_detect_change(host->mmc, 0); -+ -+ if (host->irq_cd_type == IRQ_TYPE_LEVEL_LOW) { -+ host->irq_cd_type = IRQ_TYPE_LEVEL_HIGH; -+ } else { -+ host->irq_cd_type = IRQ_TYPE_LEVEL_LOW; -+ } -+ irq_set_irq_type(host->irq_cd, host->irq_cd_type); -+ enable_irq(host->irq_cd); -+} -+ -+static irqreturn_t akmci_card_detect_irq(int irq, void *dev) -+{ -+ struct akmci_host *host = dev; -+ -+ disable_irq_nosync(irq); -+ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(400)); -+ -+ return IRQ_HANDLED; -+} -+ -+ -+/** -+ * @brief detect the sdio card whether or not is in. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *mmc information of host ,getting the sdio detect gpio. -+ * @return int. -+ * @retal 1 sdio card is in ;0 sdio card is not in -+ */ -+static int set_mci_plugin(struct notifier_block *nb, -+ unsigned long val, void *data) -+{ -+ struct akmci_host *host = container_of(nb, struct akmci_host, detect_nb); -+ -+ if(host->mci_mode == MCI_MODE_MMC_SD) { -+ if (val == ADDETECT_MMC_PLUGIN) -+ host->plugin_flag = 1; -+ else if (val == ADDETECT_MMC_PLUGOUT) -+ host->plugin_flag = 0; -+ } else { -+ if (val == ADDETECT_SDIO_PLUGIN) -+ host->plugin_flag = 1; -+ else if (val == ADDETECT_SDIO_PLUGOUT) -+ host->plugin_flag = 0; -+ } -+ -+ mmc_detect_change(host->mmc, 50); -+ return 0; -+} -+ -+static int akmci_enable(struct mmc_host *mmc) -+{ -+ PDEBUG("akmci_enable:host is claimed.\n"); -+ //akmci_drv_lock(host); -+ return 0; -+} -+ -+static int akmci_disable(struct mmc_host *mmc) -+{ -+ PDEBUG("akmci_disable:host is released.\n"); -+ //akmci_drv_unlock(host); -+ return 0; -+} -+ -+static int akmci_card_present(struct mmc_host *mmc) -+{ -+ struct akmci_host *host = mmc_priv(mmc); -+ -+ if(host->detect_mode == AKMCI_DETECT_MODE_AD) -+ { -+ return host->plugin_flag; -+ } -+ else if(host->detect_mode == AKMCI_DETECT_MODE_GPIO) -+ { -+ if (host->gpio_cd == -ENOSYS) -+ return -ENOSYS; -+ -+ if(host->gpio_cd >= 0) -+ return (ak_gpio_getpin(host->gpio_cd) == 0); -+ else -+ return 1; -+ } -+ else -+ { -+ return 1; //plugin alway. -+ } -+} -+ -+static void akmci_request(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct akmci_host *host = mmc_priv(mmc); -+ -+ host->mrq = mrq; -+ host->data_err_flag = 0; -+ -+ PDEBUG("start the mci request.\n"); -+ -+ if(akmci_card_present(mmc) == 0) { -+ printk("%s: no medium present.\n", __func__); -+ host->mrq->cmd->error = -ENOMEDIUM; -+ mmc_request_done(mmc, mrq); -+ } else { -+ akmci_send_request(mmc); -+ } -+} -+ -+static void akmci_set_clk(struct akmci_host *host, struct mmc_ios *ios) -+{ -+ u32 clk, div; -+ u32 clk_div_h, clk_div_l; -+ -+ if (ios->clock == 0) { -+ clk = readl(host->base + MCI_CLK_REG); -+ clk &= ~MCI_CLK_ENABLE; -+ writel(clk, host->base + MCI_CLK_REG); -+ -+ host->bus_clock = 0; -+ } else { -+ clk = readl(host->base + MCI_CLK_REG); -+ clk |= MCI_CLK_ENABLE;//|MCI_CLK_PWRSAVE; -+ clk &= ~0xffff; /* clear clk div */ -+ -+ div = host->asic_clk/ios->clock; -+ -+ if (host->asic_clk % ios->clock) -+ div += 1; -+ -+ div -= 2; -+ clk_div_h = div/2; -+ clk_div_l = div - clk_div_h; -+ -+ clk |= MMC_CLK_DIVL(clk_div_l) | MMC_CLK_DIVH(clk_div_h); -+ writel(clk, host->base + MCI_CLK_REG); -+ -+ host->bus_clock = host->asic_clk / ((clk_div_h+1)*(clk_div_l + 1)); -+ -+ PDEBUG("mmc clock is %lu Mhz. asic_clock is %ld MHz(div:l=%d, h=%d).\n", -+ ios->clock/MHz, host->asic_clk/MHz, clk_div_l, clk_div_h); -+ } -+ -+ host->clkreg = clk; -+} -+ -+ -+static void akmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct akmci_host *host = mmc_priv(mmc); -+ -+ switch(ios->power_mode) { -+ case MMC_POWER_ON: -+ PDEBUG("mci power on.\n"); -+ break; -+ case MMC_POWER_UP: -+ PDEBUG("mci power up.\n"); -+ break; -+ case MMC_POWER_OFF: -+ PDEBUG("mci power off.\n"); -+ break; -+ default: -+ break; -+ } -+ -+ host->bus_mode = ios->bus_mode; -+ host->bus_width = ios->bus_width; -+ -+ if(ios->clock != host->bus_clock) { -+ akmci_set_clk(host, ios); -+ } -+} -+ -+/** -+ * @brief detect the sdio card writing protection. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *mmc information of host ,getting the sdio detect gpio. -+ * @return int. -+ * @retal 1 sdio card writing protected ;0 sdio card writing is not protected -+ */ -+static int akmci_get_ro(struct mmc_host *mmc) -+{ -+ struct akmci_host *host = mmc_priv(mmc); -+ -+ if (host->gpio_wp == -ENOSYS) -+ return -ENOSYS; -+ -+ return (ak_gpio_getpin(host->gpio_wp) == 0); -+} -+ -+/** -+ * @brief enable or disable sdio interrupt, mmc host not use.. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *mmc information of sd controller. -+ * @param [in] enable 1: enable; 0: disable. -+ * @return void. -+ */ -+static void akmci_enable_sdio_irq(struct mmc_host *mmc, int enable) -+{ -+ unsigned reg1,reg2; -+ unsigned long flags; -+ struct akmci_host *host = mmc_priv(mmc); -+ -+ BUG_ON(host->mci_mode == MCI_MODE_MMC_SD); -+ -+ PDEBUG("%s the sdio interrupt.\n", enable ? "enable" : "disable"); -+ spin_lock_irqsave(&host->lock, flags); -+ -+ reg1 = readl(host->base + MCI_MASK_REG); -+ reg2 = readl(host->base + SDIO_INTRCTR_REG); -+ -+ if (enable) { -+ reg1 |= SDIO_INTR_ENABLE; -+ reg2 |= SDIO_INTR_CTR_ENABLE; -+ } else { -+ reg1 &= ~SDIO_INTR_ENABLE; -+ reg2 &= ~SDIO_INTR_CTR_ENABLE; -+ } -+ -+ writel(reg2, host->base + SDIO_INTRCTR_REG); -+ writel(reg1, host->base + MCI_MASK_REG); -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+/** -+ * register the function of sd/sdio driver. -+ * -+ */ -+static struct mmc_host_ops akmci_ops = { -+ .enable = akmci_enable, -+ .disable = akmci_disable, -+ .request = akmci_request, -+ .set_ios = akmci_set_ios, -+ .get_ro = akmci_get_ro, -+ .get_cd = akmci_card_present, -+ .enable_sdio_irq = akmci_enable_sdio_irq, -+}; -+ -+ -+static int akmci_init_mmc_host(struct akmci_host *host) -+{ -+ struct mmc_host *mmc = host->mmc; -+ struct ak_mci_platform_data *plat = host->plat; -+ -+ mmc->ops = &akmci_ops; -+ -+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -+ mmc->caps = MMC_CAP_4_BIT_DATA; -+ -+ if(host->mci_mode == MCI_MODE_SDIO) -+ mmc->caps |= MMC_CAP_SDIO_IRQ; -+ -+ if(plat->cap_highspeed) -+ mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; -+ -+// mmc->caps |= MMC_CAP_NEEDS_POLL; -+ mmc->f_min = host->asic_clk / (255+1 + 255+1); -+ mmc->f_max = host->asic_clk / (0+1 + 0+1); -+ mmc->f_max = (mmc->f_max < plat->max_speed_hz) ? -+ mmc->f_max : plat->max_speed_hz; -+ -+#ifdef CONFIG_MMC_BLOCK_BOUNCE -+ /* use block bounce buffer. */ -+ mmc->max_segs = 1; -+#else -+ /* We can do SGIO */ -+ mmc->max_segs = MAX_MCI_REQ_SIZE/MAX_MCI_BLOCK_SIZE; -+#endif -+ -+ /* -+ * Since we only have a 16-bit data length register, we must -+ * ensure that we don't exceed 2^16-1 bytes in a single request. -+ */ -+ mmc->max_req_size = MAX_MCI_REQ_SIZE; -+ -+ /* -+ * Set the maximum segment size. Since we aren't doing DMA -+ * (yet) we are only limited by the data length register. -+ */ -+ mmc->max_seg_size = mmc->max_req_size; -+ -+ mmc->max_blk_size = MAX_MCI_BLOCK_SIZE; -+ -+ /*No limit on the number of blocks transferred.*/ -+ mmc->max_blk_count = mmc->max_req_size / MAX_MCI_BLOCK_SIZE; -+ return 0; -+} -+ -+static void akmci_init_host_cfg(struct akmci_host *host) -+{ -+ akmci_init_sharepin(host); -+ /*enable the mci clock*/ -+ writel(MCI_ENABLE|MCI_FAIL_TRIGGER, host->base + MCI_CLK_REG); -+ -+ clear_imask(host); -+} -+ -+ -+#if defined(CONFIG_CPU_FREQ) -+ -+static int akmci_cpufreq_transition(struct notifier_block *nb, -+ unsigned long val, void *data) -+{ -+ struct akmci_host *host; -+ struct mmc_host *mmc; -+ unsigned long newclk; -+ unsigned long flags; -+ struct cpufreq_freqs *freqs = (struct cpufreq_freqs *)data; -+ host = container_of(nb, struct ak_mci_host, freq_transition); -+ -+ PDEBUG("%s(): in_interrupt()=%ld\n", __func__, in_interrupt()); -+ PDEBUG("ak_get_asic_clk = %ld\n",ak_get_asic_clk()); -+ PDEBUG("freqs->new_cpufreq.asic_clk = %d\n", -+ freqs->new_cpufreq.asic_clk); -+ -+ mmc = host->mmc; -+ newclk = freqs->new_cpufreq.asic_clk; -+ if ((val == CPUFREQ_PRECHANGE && newclk > host->asic_clock) -+ || (val == CPUFREQ_POSTCHANGE && newclk < host->asic_clock)) -+ { -+ -+ if (mmc->ios.power_mode != MMC_POWER_OFF && -+ mmc->ios.clock != 0) -+ { -+ PDEBUG("%s(): preempt_count()=%d\n", __func__, preempt_count()); -+ -+ down(&host->freq_lock); -+ -+ spin_lock_irqsave(&mmc->lock, flags); -+ -+ host->asic_clock = newclk; -+ PDEBUG("MCI_CLK_REG1 = %d\n",readl(host->base + MCI_CLK_REG)); -+ aksdio_set_clk(host, &mmc->ios); -+ PDEBUG("MCI_CLK_REG2 = %d\n",readl(host->base + MCI_CLK_REG)); -+ -+ spin_unlock_irqrestore(&mmc->lock, flags); -+ -+ up(&host->freq_lock); -+ } -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+ -+static inline int akmci_cpufreq_register(struct akmci_host *host) -+{ -+ // use for requst and cpufreq -+ sema_init(&host->freq_lock, 1); -+ -+ host->freq_transition.notifier_call = akmci_cpufreq_transition; -+ -+ return cpufreq_register_notifier(&host->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+static inline void akmci_cpufreq_deregister(struct akmci_host *host) -+{ -+ cpufreq_unregister_notifier(&host->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+#else -+static inline int akmci_cpufreq_register(struct akmci_host *host) -+{ -+ return 0; -+} -+ -+static inline void akmci_cpufreq_deregister(struct akmci_host *host) -+{ -+} -+#endif -+ -+ -+/** -+ * @brief sdio driver probe and init. -+ * -+ * @author Hanyang -+ * @date 2011-05-10 -+ * @param [in] *pdev information of platform device ,getting the sd driver resource . -+ * @return int. -+ * @retval -EINVAL no platform data , fail; -+ * @retval -EBUSY requset mem fail; -+ * @retval -ENOMEM alloc mem fail; -+ */ -+static int __devinit akmci_probe(struct platform_device *pdev) -+{ -+ struct akmci_host *host; -+ struct mmc_host *mmc; -+ int ret; -+ struct ak_mci_platform_data *plat; -+ -+ plat = pdev->dev.platform_data; -+ if(!plat) { -+ printk("not found mci platform data."); -+ ret = -EINVAL; -+ goto probe_out; -+ } -+ -+ mmc = mmc_alloc_host(sizeof(struct akmci_host), &pdev->dev); -+ if (!mmc) { -+ ret = -ENOMEM; -+ goto probe_out; -+ } -+ -+ host = mmc_priv(mmc); -+ host->mmc = mmc; -+ host->pdev = pdev; -+ -+ spin_lock_init(&host->lock); -+ -+ host->plat = plat; -+ host->mci_mode = plat->mci_mode; -+ host->data_err_flag = 0; -+ host->l2buf_id = BUF_NULL; -+ -+ host->gpio_wp = -ENOSYS; -+ host->gpio_cd = -ENOSYS; -+ host->detect_mode = plat->detect_mode; -+ host->xfer_mode = plat->xfer_mode; -+ -+ akmci_reset(host); -+ -+ host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if(!host->mem) { -+ ret = -ENOENT; -+ goto probe_free_host; -+ } -+ -+ host->mem = request_mem_region(host->mem->start, -+ resource_size(host->mem), pdev->name); -+ -+ if (!host->mem) { -+ dev_err(&pdev->dev, "failed to request io memory region.\n"); -+ ret = -ENOENT; -+ goto probe_free_host; -+ } -+ -+ host->base = ioremap(host->mem->start, resource_size(host->mem)); -+ if (!host->base) { -+ dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); -+ ret = -EINVAL; -+ goto probe_free_mem_region; -+ } -+ -+ host->irq_mci = platform_get_irq(pdev, 0); -+ if(host->irq_mci == 0) { -+ dev_err(&pdev->dev, "failed to get interrupt resouce.\n"); -+ ret = -EINVAL; -+ goto probe_iounmap; -+ } -+ -+ if (request_irq(host->irq_mci, akmci_irq, IRQF_DISABLED, pdev->name, host)) { -+ dev_err(&pdev->dev, "failed to request mci interrupt.\n"); -+ ret = -ENOENT; -+ goto probe_iounmap; -+ } -+ -+ /* We get spurious interrupts even when we have set the IMSK -+ * register to ignore everything, so use disable_irq() to make -+ * ensure we don't lock the system with un-serviceable requests. */ -+ //disable_irq(host->irq_mci); -+ -+ host->clk = clk_get(&pdev->dev, (host->mci_mode == MCI_MODE_MMC_SD)? "mci" : "sdio"); -+ if (IS_ERR(host->clk)) { -+ dev_err(&pdev->dev, "failed to find clock source.\n"); -+ ret = PTR_ERR(host->clk); -+ host->clk = NULL; -+ goto probe_free_irq; -+ } -+ -+ ret = clk_enable(host->clk); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to enable clock source.\n"); -+ goto clk_free; -+ } -+ -+ host->asic_clk = clk_get_rate(host->clk); -+ -+ ret = akmci_init_mmc_host(host); -+ if(ret) { -+ dev_err(&pdev->dev, "failed to init mmc host.\n"); -+ goto clk_disable; -+ } -+ -+ akmci_init_host_cfg(host); -+ -+ if(host->detect_mode == AKMCI_DETECT_MODE_GPIO) { -+ if(plat->gpio_cd.pin >= 0) { -+ host->gpio_cd = plat->gpio_cd.pin; -+ plat->gpio_init(&plat->gpio_cd); -+ -+ setup_timer(&host->detect_timer, akmci_detect_change, -+ (unsigned long)host); -+ -+ host->irq_cd = ak_gpio_to_irq(host->gpio_cd); -+ ret = request_irq(host->irq_cd, akmci_card_detect_irq, -+ IRQF_DISABLED|IRQF_TRIGGER_LOW, pdev->name, host); -+ -+ dev_info(&pdev->dev, "pdev->name:%s request gpio irq ret = %d, irq=%d\n", -+ pdev->name, ret, host->irq_cd); -+ if (ret) -+ goto clk_disable; -+ -+ host->irq_cd_type = plat->irq_cd_type; -+ } -+ } -+ else if(host->detect_mode == AKMCI_DETECT_MODE_AD) { -+ memset(&host->detect_nb, 0, sizeof(host->detect_nb)); -+ host->detect_nb.notifier_call = set_mci_plugin; -+ addetect_register_client(&host->detect_nb); -+ } -+ -+ if (plat->gpio_wp.pin >= 0) { -+ host->gpio_wp = plat->gpio_wp.pin; -+ plat->gpio_init(&plat->gpio_wp); -+ } -+ -+ ret = akmci_cpufreq_register(host); -+ if (ret) { -+ goto detect_irq_free; -+ } -+ -+ platform_set_drvdata(pdev, mmc); -+ -+ ret = mmc_add_host(mmc); -+ if (ret) { -+ goto probe_cpufreq_free; -+ } -+ -+ dev_info(&pdev->dev, "Mci Interface driver.%s." -+ " using %s, %s IRQ. detect mode:%s.\n", -+ mmc_hostname(mmc), xfer_mode_desc[akmci_xfer_mode(host)], -+ mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw", -+ detect_mode_desc[host->detect_mode]); -+ -+ return 0; -+ -+probe_cpufreq_free: -+ -+detect_irq_free: -+ free_irq(host->irq_cd, host); -+ -+clk_disable: -+ clk_disable(host->clk); -+ -+clk_free: -+ clk_put(host->clk); -+ -+probe_free_irq: -+ free_irq(host->irq_mci, host); -+ -+probe_iounmap: -+ iounmap(host->base); -+ -+probe_free_mem_region: -+ release_mem_region(host->mem->start, resource_size(host->mem)); -+ -+probe_free_host: -+ mmc_free_host(host->mmc); -+ -+probe_out: -+ return ret; -+} -+ -+static int __devexit akmci_remove(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc; -+ struct akmci_host *host; -+ -+ mmc = platform_get_drvdata(pdev); -+ host = mmc_priv(mmc); -+ -+ mmc_remove_host(mmc); -+ -+ akmci_cpufreq_deregister(host); -+ -+ if(host->detect_mode == AKMCI_DETECT_MODE_AD) -+ addetect_unregister_client(&host->detect_nb); -+ -+ clk_disable(host->clk); -+ clk_put(host->clk); -+ -+ free_irq(host->irq_cd, host); -+ free_irq(host->irq_mci, host); -+ -+ iounmap(host->base); -+ release_mem_region(host->mem->start, resource_size(host->mem)); -+ -+ mmc_free_host(host->mmc); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int akmci_suspend(struct device *dev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); -+ -+ return mmc_suspend_host(mmc); -+} -+ -+static int akmci_resume(struct device *dev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); -+ -+ return mmc_resume_host(mmc); -+} -+ -+static struct dev_pm_ops akmci_pm = { -+ .suspend = akmci_suspend, -+ .resume = akmci_resume -+}; -+ -+#define akmci_pm_ops &akmci_pm -+#else -+#define akmci_pm_ops NULL -+#endif -+ -+struct platform_device_id ak_mci_ids[] ={ -+ {.name = "ak_mci", .driver_data = MCI_MODE_MMC_SD,}, -+ {.name = "ak_sdio", .driver_data = MCI_MODE_SDIO,}, -+}; -+ -+static struct platform_driver akmci_driver = { -+ .probe = akmci_probe, -+ .remove = __devexit_p(akmci_remove), -+ .id_table = ak_mci_ids, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .pm = akmci_pm_ops, -+ }, -+ -+}; -+ -+static int __init akmci_init(void) -+{ -+ printk("AK MCI Driver (c) 2010 ANYKA\n"); -+ return platform_driver_register(&akmci_driver); -+} -+ -+static void __exit akmci_exit(void) -+{ -+ return platform_driver_unregister(&akmci_driver); -+} -+ -+ -+module_init(akmci_init); -+module_exit(akmci_exit); -+ -+MODULE_DESCRIPTION("Anyka MCI Interface driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Anyka"); -+ -diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index 1fe0ca9c..4b970ade 100644 ---- a/drivers/mmc/host/sdhci.c -+++ b/drivers/mmc/host/sdhci.c -@@ -680,11 +680,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) - break; - } - -- if (count >= 0xF) { -- pr_warning("%s: Too large timeout requested for CMD%d!\n", -- mmc_hostname(host->mmc), cmd->opcode); -+ if (count >= 0xF) - count = 0xE; -- } - - return count; - } -diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile -index f9013542..0dd5e1a7 100644 ---- a/drivers/mtd/Makefile -+++ b/drivers/mtd/Makefile -@@ -5,6 +5,7 @@ - # Core functionality. - obj-$(CONFIG_MTD) += mtd.o - mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o -+mtd-y += akfha_char.o - - obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o -diff --git a/drivers/mtd/akfha_char.c b/drivers/mtd/akfha_char.c -new file mode 100755 -index 00000000..0c426a59 ---- /dev/null -+++ b/drivers/mtd/akfha_char.c -@@ -0,0 +1,546 @@ -+/** -+ * @filename akfha_char.c -+ * @brief AK fha char device driver -+ * Copyright (C) 2010 Anyka (Guangzhou) Software Technology Co., LTD -+ * @author zhangshenglin -+ * @date 2012-12-7 -+ * @version 1.0 -+ * @ -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/fs.h> -+#include <linux/errno.h> -+#include <linux/mm.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/cdev.h> -+#include <linux/string.h> -+#include <linux/delay.h> -+#include <asm/uaccess.h> -+#include <linux/mtd/partitions.h> -+#include <linux/gpio.h> -+#include <mtd/mtd-abi.h> -+#include <mach-anyka/nand_list.h> -+#include <mach-anyka/fha.h> -+#ifdef CONFIG_MTD_NAND_ANYKA -+#include <plat-anyka/wrap_nand.h> -+#include <plat-anyka/anyka_cpu.h> -+#include <plat-anyka/nand.h> -+#endif -+ -+#include <mach/gpio.h> -+#include <mach/clock.h> -+#include <linux/platform_device.h> -+ -+ -+#define FHA_CHAR_MAJOR 168 -+#define AK_FHA_UPDATE_BOOT_BEGIN 0xb1 -+#define AK_FHA_UPDATE_BOOT 0xb2 -+#define AK_FHA_UPDATE_BIN_BEGIN 0xb3 -+#define AK_FHA_UPDATE_BIN 0xb4 -+#define MAX_BUF_LEN 64*1024 -+extern int ak_fha_init_for_update(int n); -+extern T_U32 ak_fha_read_callback(T_U32 chip_num, T_U32 page_num, T_U8 *data, -+ T_U32 data_len, T_U8 *oob, T_U32 oob_len, T_U32 eDataType); -+ -+typedef struct -+{ -+ long filelen; -+ char filename[256];//the bin name in flash -+}T_BinInfo; -+ -+typedef struct -+{ -+ long buflen; -+ char buff[MAX_BUF_LEN]; -+ long ddrparcnt; -+ unsigned int ddrpar[64][2]; -+}T_BufInfo; -+static T_BufInfo* pBufInfo = NULL; -+ -+typedef struct -+{ -+ char Disk_Name; //盘符名 -+ char bOpenZone; // -+ char ProtectType; // -+ char ZoneType; // -+ unsigned int Size; -+ unsigned int EnlargeSize; // set this value if enlarge capacity,otherwise set 0 -+ unsigned int HideStartBlock; //hide disk start -+ unsigned int FSType; -+ unsigned int resv[1]; -+}__attribute__((packed)) T_PARTION_INFO; -+ -+#define MAX_PARTS_COUNT 26 -+static unsigned char* spipart_info = NULL; -+#define SPI_PAGESIZE 256 -+static int akfha_char_open(struct inode *inode, struct file *filp); -+static int akfha_char_close(struct inode *inode, struct file *filp); -+static long akfha_char_ioctl(/*struct inode *inode, */struct file *filp, unsigned int cmd, unsigned long arg); -+ -+static struct akfha_char_dev -+{ -+ struct cdev c_dev; -+}fha_c_dev; -+ -+static int fha_c_major = FHA_CHAR_MAJOR; -+ -+static const struct file_operations akfha_char_fops = -+{ -+ .owner = THIS_MODULE, -+ .open = akfha_char_open, -+ .release = akfha_char_close, -+ .unlocked_ioctl = akfha_char_ioctl, -+}; -+ -+static int akfha_char_open(struct inode *inode, struct file *filp) -+{ -+ pBufInfo = kmalloc(sizeof(T_BufInfo), GFP_KERNEL); -+ if(pBufInfo == NULL) -+ { -+ printk("malloc buf error\n"); -+ return -1; -+ } -+ filp->private_data = &fha_c_dev; -+ ak_fha_init_for_update(1); -+ return 0; -+} -+ -+static int akfha_char_close(struct inode *inode, struct file *filp) -+{ -+ if(pBufInfo) -+ { -+ kfree(pBufInfo); -+ pBufInfo = NULL; -+ } -+ if(spipart_info != NULL) -+ { -+ if(AK_FALSE == FHA_set_fs_part(spipart_info, 256)) -+ { -+ printk("FHA_set_fs_part error\n"); -+ } -+ kfree(spipart_info); -+ spipart_info = NULL; -+ } -+ -+ FHA_close(); -+ return 0; -+} -+ -+static int fhachar_UpdateBootBegin(unsigned long arg) -+{ -+ return 0; -+} -+static int fhachar_UpdateBoot(unsigned long arg) -+{ -+ int ret = 0; -+ //int size; -+ //unsigned long partition_count = 0; -+ struct partitions* parts = NULL; -+ unsigned long *ori_mbyte = NULL; -+ unsigned char *part_info = NULL; -+ //int i = 0; -+ -+ T_U8* page0 = NULL; -+ T_U8* pData = NULL; -+ -+ T_U8 ecc[4]; -+ T_U8 pagedata[512]; -+ long newBootLen; -+ int pagesize; -+ -+#ifdef CONFIG_MTD_NAND_ANYKA -+ /* get the old part_info */ -+ size = sizeof(partition_count) + sizeof(*parts) * MAX_PARTS_COUNT + -+ sizeof(*ori_mbyte) * MAX_PARTS_COUNT; -+ part_info = kmalloc(size, GFP_KERNEL); -+ if (part_info == NULL) { -+ printk("malloc part_info error\n"); -+ ret = -1; -+ goto go_out; -+ } -+ -+ if (AK_FALSE == FHA_get_fs_part(part_info, size)){ -+ ret = -1; -+ goto go_out; -+ } -+ -+ partition_count = *(unsigned long *)(part_info); -+ -+ parts = kmalloc(partition_count * sizeof(*parts), GFP_KERNEL); -+ ori_mbyte = kmalloc(partition_count * sizeof(*ori_mbyte), GFP_KERNEL); -+ -+ memcpy(parts, part_info + sizeof(partition_count), partition_count * sizeof(*parts)); -+ memcpy(ori_mbyte, part_info + sizeof(partition_count) + partition_count * sizeof(*parts), -+ partition_count * sizeof(*ori_mbyte)); -+ /* end get the old part_info */ -+#endif -+ -+ if(copy_from_user(pBufInfo, (T_BufInfo*)arg, sizeof(T_BufInfo)) != 0) -+ { -+ ret = -1; -+ goto go_out; -+ } -+ -+ memset(pagedata, 0, 512); -+ -+#ifdef CONFIG_MTD_NAND_ANYKA -+ ak_fha_read_callback(0, 0, pagedata, 512, ecc, 4, FHA_DATA_BOOT); -+ -+ pagesize = pagedata[0xc] * 512;//BOOT页大小 -+#else -+ pagesize = SPI_PAGESIZE;//pagedata[0xc] * 512;//BOOT页大小 -+#endif -+ page0 = (T_U8*)kmalloc(pagesize, GFP_KERNEL); -+ if(page0 == NULL) -+ { -+ ret = -1; -+ goto go_out; -+ } -+ memset(page0, 0, pagesize); -+ -+#ifdef CONFIG_MTD_NAND_ANYKA -+ ak_fha_read_callback(0, 0, page0, pagesize, ecc, 4, FHA_DATA_BOOT); -+ -+ page0[0xd] = pBufInfo->buflen / pagesize + 2;//修改nandboot所占的页数 -+#else -+ ak_fha_read_callback(0, 0, page0, 1, ecc, 4, FHA_DATA_BOOT); -+ ak_fha_read_callback(0, 1, pagedata, 1, ecc, 4, FHA_DATA_BOOT); -+ *((unsigned int*)(page0+0x0c)) = pBufInfo->buflen; -+#endif -+ //ddr param -+ if(pBufInfo->ddrparcnt > 0 && pBufInfo->ddrparcnt < 53) -+ { -+#ifdef CONFIG_MTD_NAND_ANYKA -+ for(i = 0x2c; i < 472 - sizeof(T_NAND_PHY_INFO) - 4; i ++) -+ { -+ if(page0[i] == 'N' && page0[i + 1] == 'A' && page0[i + 2] == 'N' && page0[i + 3] == 'D') -+ { -+ printk("NAND found\n"); -+ break; -+ } -+ } -+ -+ if(i == 472 - sizeof(T_NAND_PHY_INFO) - 4) -+ { -+ ret = -1; -+ goto go_out; -+ } -+ -+ memmove(page0 + 0x2c + pBufInfo->ddrparcnt * 8, page0 + i, sizeof(T_NAND_PHY_INFO)+ 4); -+ -+ memcpy(page0 + 0x2c, pBufInfo->ddrpar, pBufInfo->ddrparcnt * sizeof(unsigned int) * 2); -+#endif -+ } -+ newBootLen = pBufInfo->buflen; -+ if(newBootLen < 0) -+ { -+ ret = -1; -+ goto go_out; -+ } -+ -+#ifdef CONFIG_MTD_NAND_ANYKA -+ newBootLen += pagesize; -+#endif -+ //printk("New Boot len:%ld\n", newBootLen); -+ -+ pData = (T_U8*)kmalloc(newBootLen, GFP_KERNEL); -+ if(pData == NULL) -+ { -+ printk("malloc error\n"); -+ ret = -1; -+ goto go_out; -+ } -+ -+#ifndef CONFIG_MTD_NAND_ANYKA -+ memcpy(pData, pBufInfo->buff, pBufInfo->buflen); -+#endif -+ memcpy(pData, page0, pagesize); -+#ifndef CONFIG_MTD_NAND_ANYKA -+ memcpy(pData+pagesize, pagedata, pagesize); -+#endif -+ -+//ddr param -+ if(pBufInfo->ddrparcnt > 0 && pBufInfo->ddrparcnt < 53) -+ { -+#ifndef CONFIG_MTD_NAND_ANYKA -+ memcpy(pData + 0x18, pBufInfo->ddrpar, pBufInfo->ddrparcnt * sizeof(unsigned int) * 2); -+#endif -+ } -+ -+#ifdef CONFIG_MTD_NAND_ANYKA -+ memcpy(pData+pagesize, pBufInfo->buff, pBufInfo->buflen); -+ -+ ak_fha_read_callback(0, 1, pagedata, 512, ecc, 4, FHA_DATA_BOOT); -+ memcpy(pData + pagesize, pagedata, 208); -+#endif -+#ifdef CONFIG_MTD_NAND_ANYKA -+ if (FHA_FAIL == FHA_set_fs_part(part_info, sizeof(int) -+ + partition_count * sizeof(parts[0]) + partition_count * sizeof(ori_mbyte[0]))) -+ { -+ ret = -1; -+ goto go_out; -+ } -+#endif -+ if(FHA_write_boot_begin(newBootLen) == AK_TRUE) -+ { -+ printk("write boot begin ok\n"); -+ } -+ else -+ { -+ printk("write boot begin error\n"); -+ ret = -1; -+ goto go_out; -+ } -+ -+ if(FHA_write_boot(pData, newBootLen) == AK_TRUE) -+ { -+ printk("write boot ok\n"); -+ } -+ else -+ { -+ printk("write boot error\n"); -+ ret = -1; -+ goto go_out; -+ } -+ -+go_out: -+ if(page0) -+ { -+ kfree(page0); -+ page0 = NULL; -+ } -+ if(pData) -+ { -+ kfree(pData); -+ pData = NULL; -+ } -+ if(parts) -+ { -+ kfree(parts); -+ parts = NULL; -+ } -+ -+ if(part_info) -+ { -+ kfree(part_info); -+ part_info = NULL; -+ } -+ if(ori_mbyte) -+ { -+ kfree(ori_mbyte); -+ ori_mbyte = NULL; -+ } -+ -+ printk("*********************end to update nandboot:ret=%d\n", ret); -+ return ret; -+} -+static int fhachar_UpdateBinBegin(unsigned long arg) -+{ -+ T_BinInfo binInfo; -+ T_FHA_BIN_PARAM binParam; -+ memset(&binParam, 0, sizeof(binParam)); -+ printk("e00000\n"); -+ if(copy_from_user(&binInfo, (T_BinInfo*)arg, sizeof(T_BinInfo)) != 0) -+ { -+ printk("e11111\n"); -+ return -1; -+ } -+ strcpy(binParam.file_name, binInfo.filename); -+ if(FHA_read_bin_begin(&binParam) == FHA_FAIL) -+ { -+ printk("e22222\n"); -+ return -1; -+ } -+ -+ binParam.data_length = binInfo.filelen; -+ if(FHA_write_bin_begin(&binParam) == FHA_FAIL) -+ { -+ printk("e33333\n"); -+ return -1; -+ } -+ printk("e444444\n"); -+ return 0; -+} -+ -+static int fhachar_UpdateBin(unsigned long arg) -+{ -+ if(copy_from_user(pBufInfo, (T_BufInfo*)arg, sizeof(T_BufInfo)) != 0) -+ { -+ return -1; -+ } -+ -+#ifndef CONFIG_MTD_NAND_ANYKA -+ if(spipart_info == NULL) -+ { -+ spipart_info = kmalloc(SPI_PAGESIZE, GFP_KERNEL); -+ if(AK_FALSE == FHA_get_fs_part(spipart_info, SPI_PAGESIZE)) -+ { -+ printk("fha get fs part error\n"); -+ } -+ } -+#endif -+ if(FHA_write_bin(pBufInfo->buff, pBufInfo->buflen) != FHA_SUCCESS) -+ { -+ return -1; -+ } -+ return 0; -+} -+/** -+ * @brief :Command Control interface for burntool . -+ * -+ * @author zhangshenglin -+ * @date 2012-12-07 -+ * @param inode[in] nand char device inode. -+ * @param filp[in] nand char file id. -+ * @param cmd[in] burntool command. -+ * @param arg[in] parameter from user. -+ * @return int -+ * @retval 1: fail 0: success -+ */ -+static long akfha_char_ioctl(/*struct inode *inode, */struct file *filp, -+ unsigned int cmd, unsigned long arg) -+{ -+ int ret = 0; -+ switch(cmd) -+ { -+ case AK_FHA_UPDATE_BOOT_BEGIN: -+ { -+ ret = fhachar_UpdateBootBegin(arg); -+ break; -+ } -+ case AK_FHA_UPDATE_BOOT: -+ { -+ ret = fhachar_UpdateBoot(arg); -+ break; -+ } -+ case AK_FHA_UPDATE_BIN_BEGIN: -+ { -+ ret = fhachar_UpdateBinBegin(arg); -+ break; -+ } -+ case AK_FHA_UPDATE_BIN: -+ { -+ ret = fhachar_UpdateBin(arg); -+ break; -+ } -+ default: -+ { -+ return -EINVAL; -+ } -+ -+ } -+ return ret; -+} -+ -+static struct class *fha_class; -+ -+static void fha_setup_cdev(void) -+{ -+ int err = 0; -+ dev_t devno = MKDEV(fha_c_major, 0); -+ -+ cdev_init(&(fha_c_dev.c_dev), &akfha_char_fops); -+ fha_c_dev.c_dev.owner = THIS_MODULE; -+ fha_c_dev.c_dev.ops = &akfha_char_fops; -+ err = cdev_add(&(fha_c_dev.c_dev), devno, 1); -+ if(err) -+ { -+ printk(KERN_NOTICE "Error %d adding anyka akfha char dev\n", err); -+ } -+ -+ //automatic mknod device node -+ fha_class = class_create(THIS_MODULE, "akfha_class"); -+ device_create(fha_class, NULL, devno, &fha_c_dev, "akfha_char"); -+} -+static int akfha_char_probe(struct platform_device *pdev) -+{ -+ int result = 0; -+ //int existent_chips; -+ //int nr_sets; -+ dev_t devno; -+ -+#ifdef CONFIG_MTD_NAND_ANYKA -+ struct ak_platform_nand_multice *plat = pdev->dev.platform_data; -+ struct ak_nand_set *sets; -+ sets = (plat != NULL) ? plat->sets : NULL; -+ nr_sets = (plat != NULL) ? plat->nr_sets : 1; -+ ak_nand_clock(AK_TRUE); -+#ifndef CONFIG_MTD_DOWNLOAD_MODE -+ existent_chips = ak_nand_CE_set(sets->max_chips, sets->nr_chips, &sets->ce2_gpio, &sets->ce3_gpio); -+ if (!existent_chips) { -+ printk("Can not find one chip\n"); -+ return -1; -+ } -+ -+ if(FHA_FAIL == ak_fha_init(sets->nr_chips)) -+ { -+ printk(KERN_INFO "%s, %d init fha lib error return!!!\n", __func__, __LINE__); -+ return -1; -+ } -+#endif -+#endif -+ devno = MKDEV(fha_c_major, 0); -+ if(fha_c_major) -+ { -+ result = register_chrdev_region(devno, 1, "anyka fha char dev"); -+ } -+ else -+ { -+ result = alloc_chrdev_region(&devno, 0, 1, "anyka fha char dev"); -+ } -+ if(result < 0) -+ { -+ return result; -+ } -+ fha_setup_cdev(); -+ -+ printk(KERN_INFO "akfha Char Device Initialize Successed!\n"); -+ return 0; -+} -+static int akfha_char_remove(struct platform_device *pdev) -+{ -+ dev_t devno = MKDEV(fha_c_major, 0); -+ -+ //destroy device node -+ device_destroy(fha_class, devno); -+ class_destroy(fha_class); -+ -+ //delete char device -+ cdev_del(&(fha_c_dev.c_dev)); -+ unregister_chrdev_region(devno, 1); -+ -+ return 0; -+} -+ -+/* device driver for platform bus bits */ -+static struct platform_driver akfha_char_driver = { -+ .probe = akfha_char_probe, -+ .remove = akfha_char_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "ak-fhachar", -+ .pm = NULL, -+ }, -+}; -+static int __init akfha_char_init(void) -+{ -+ printk("*********akfha_char init\n"); -+ return platform_driver_register(&akfha_char_driver); -+} -+ -+static void __exit akfha_char_exit(void) -+{ -+ platform_driver_unregister(&akfha_char_driver); -+ printk("*******akfha_char_exit"); -+} -+ -+subsys_initcall(akfha_char_init); -+module_exit(akfha_char_exit); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("ZhangShenglin"); -+MODULE_DESCRIPTION("Direct character-device access to fha devices"); -+ -diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig -index 4cdb2af7..de263fbe 100644 ---- a/drivers/mtd/devices/Kconfig -+++ b/drivers/mtd/devices/Kconfig -@@ -334,4 +334,15 @@ config MTD_DOCPROBE_55AA - LinuxBIOS or if you need to recover a DiskOnChip Millennium on which - you have managed to wipe the first block. - -+config MTD_AK_SPIFLASH -+ tristate "Support Anyka SPI Flash chips(Most chips)" -+ depends on SPI_MASTER -+ help -+ Anyka driver enables access to most SPI flash chips, used for -+ program and data storage. -+ -+ Set up your spi devices with the right board-specific platform data, -+ if you want to specify device partitioning or to use a device which -+ doesn't support the JEDEC ID instruction. -+ - endmenu -diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile -index a4dd1d82..748ba408 100644 ---- a/drivers/mtd/devices/Makefile -+++ b/drivers/mtd/devices/Makefile -@@ -19,5 +19,7 @@ obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o - obj-$(CONFIG_MTD_M25P80) += m25p80.o - obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o - obj-$(CONFIG_MTD_SST25L) += sst25l.o -+obj-$(CONFIG_MTD_AK_SPIFLASH) += ak_spiflash.o -+ -+CFLAGS_docg3.o += -I$(src) - --CFLAGS_docg3.o += -I$(src) -\ No newline at end of file -diff --git a/drivers/mtd/devices/ak_spiflash.c b/drivers/mtd/devices/ak_spiflash.c -new file mode 100644 -index 00000000..ce0a53c7 ---- /dev/null -+++ b/drivers/mtd/devices/ak_spiflash.c -@@ -0,0 +1,1795 @@ -+ /** -+ * @file /driver/mtd/devices/ak_SPIFlash.c -+ * @brief SPI Flash driver for Anyka AK37 platform. -+ * Copyright C 2012 Anyka CO.,LTD -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * @author She Shaohua -+ * @date 2012-03-23 -+ * @note 2011-03-20 created -+ * @note 2011-03-23 Debug OK. -+ */ -+ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/device.h> -+#include <linux/interrupt.h> -+#include <linux/mutex.h> -+#include <linux/math64.h> -+#include <linux/sched.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/partitions.h> -+ -+#include <linux/spi/spi.h> -+#include <linux/spi/flash.h> -+#include <linux/delay.h> -+#include <mach-anyka/fha.h> -+#include <mach-anyka/anyka_types.h> -+#include <linux/mm.h> -+ -+ -+//#define SPIFLASH_DEBUG -+#undef PDEBUG -+#ifdef SPIFLASH_DEBUG -+#define PDEBUG(fmt, args...) printk( KERN_INFO fmt,## args) -+#define DEBUG(n, args...) printk(KERN_INFO args) -+#else -+#define PDEBUG(fmt, args...) -+#define DEBUG(n, args...) -+#endif -+ -+#define FLASH_BUF_SIZE (32*1024*1024) -+#define FLASH_PAGESIZE 256 -+ -+#define SPI_FLASH_READ 1 -+#define SPI_FLASH_WRITE 2 -+ -+#define CONFIG_SPIFLASH_USE_FAST_READ 1 -+ -+/*mtd layer allocate memory use for 'vmalloc' interface, need to convert.*/ -+//#define SPIFLASH_USE_MTD_BLOCK_LAYER -+ -+#define OPCODE_WREN 0x06 /* Write Enable */ -+#define OPCODE_WRDI 0x04 /* Write Disable */ -+#define OPCODE_RDSR1 0x05 /* Read Status Register1 */ -+#define OPCODE_RDSR2 0x35 /* Read Status Register2 */ -+#define OPCODE_WRSR 0x01 /* Write Status Register */ -+ -+#define OPCODE_NORM_READ 0x03 /* Read Data Bytes */ -+#define OPCODE_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ -+#define OPCODE_FAST_D_READ 0x3b /* Read Data Bytes at Dual output */ -+#define OPCODE_FAST_Q_READ 0x6b /* Read Data Bytes at Quad output */ -+#define OPCODE_FAST_D_IO 0xbb /* Read Data Bytes at Dual i/o */ -+#define OPCODE_FAST_Q_IO 0xeb /* Read Data Bytes at Quad i/o */ -+ -+#define OPCODE_PP 0x02 /* Page Program */ -+#define OPCODE_PP_DUAL 0x12 /* Dual Page Program*/ -+#define OPCODE_PP_QUAD 0x32 /* Quad Page Program*/ -+#define OPCODE_2IO_PP 0x18 /* 2I/O Page Program (tmp)*/ -+#define OPCODE_4IO_PP 0x38 /* 4I/O Page Program*/ -+ -+#define OPCODE_BE_4K 0x20 /* Sector (4K) Erase */ -+#define OPCODE_BE_32K 0x52 /* Block (32K) Erase */ -+#define OPCODE_BE_64K 0xd8 /* Block (64K) Erase */ -+#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ -+#define OPCODE_CHIP_ERASE 0xc7 /* Chip Erase */ -+#define OPCODE_RDID 0x9f /* Read JEDEC ID */ -+#define OPCODE_DP 0xb9 /* Deep Power-down */ -+#define OPCODE_RES 0xab /* Release from DP, and Read Signature */ -+ -+ -+#define SPI_STATUS_REG1 1 -+#define SPI_STATUS_REG2 2 -+ -+ -+/* Used for SST flashes only. */ -+#define OPCODE_BP 0x02 /* Byte program */ -+#define OPCODE_WRDI 0x04 /* Write disable */ -+#define OPCODE_AAI_WP 0xad /* Auto address increment word program */ -+ -+ -+/* Define max times to check status register before we give up. */ -+#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* 40s max chip erase */ -+ -+#define CMD_SIZE (1) -+#define ADDR_SIZE (3) -+#define CMD_ADDR_SIZE (CMD_SIZE + ADDR_SIZE) -+#define MAX_DUMMY_SIZE (4) -+ -+#define MTD_PART_NAME_LEN (4) -+ -+#ifdef CONFIG_SPIFLASH_USE_FAST_READ -+#define OPCODE_READ OPCODE_FAST_READ -+#define FAST_READ_DUMMY_BYTE 1 -+#else -+#define OPCODE_READ OPCODE_NORM_READ -+#define FAST_READ_DUMMY_BYTE 0 -+#endif -+ -+#define ALIGN_DOWN(a, b) (((a) / (b)) * (b)) -+ -+/****************************************************************************/ -+struct partitions -+{ -+ char name[MTD_PART_NAME_LEN]; -+ unsigned long long size; -+ unsigned long long offset; -+ unsigned int mask_flags; -+}__attribute__((packed)); -+ -+typedef struct -+{ -+ T_U32 BinPageStart; /*bin data start addr*/ -+ T_U32 PageSize; /*spi page size*/ -+ T_U32 PagesPerBlock;/*page per block*/ -+ T_U32 BinInfoStart; -+ T_U32 FSPartStart; -+} -+T_SPI_BURN_INIT_INFO; -+ -+ -+/* -+ * SPI device driver setup and teardown -+ */ -+struct flash_info { -+ char *name; -+ -+ /* JEDEC id zero means "no ID" (most older chips); otherwise it has -+ * a high byte of zero plus three data bytes: the manufacturer id, -+ * then a two byte device id. -+ */ -+ u32 jedec_id; -+ u16 ext_id; -+ -+ /* The size listed here is what works with OPCODE_SE, which isn't -+ * necessarily called a "sector" by the vendor. -+ */ -+ unsigned sector_size; -+ u16 n_sectors; -+ -+ /** -+ * chip character bits: -+ * bit 0: under_protect flag, the serial flash under protection or not when power on -+ * bit 1: fast read flag, the serial flash support fast read or not(command 0Bh) -+ * bit 2: AAI flag, the serial flash support auto address increment word programming -+ * bit 3: support dual write or no -+ * bit 4: support dual read or no -+ * bit 5: support quad write or no -+ * bit 6: support quad read or no -+ * bit 7: the second status command (35h) flag,if use 4-wire(quad) mode,the bit must be is enable -+ */ -+ u16 flags; -+#define SFLAG_UNDER_PROTECT (1<<0) -+#define SFLAG_FAST_READ (1<<1) -+#define SFLAG_AAAI (1<<2) -+#define SFLAG_COM_STATUS2 (1<<3) -+ -+#define SFLAG_DUAL_IO_READ (1<<4) -+#define SFLAG_DUAL_READ (1<<5) -+#define SFLAG_QUAD_IO_READ (1<<6) -+#define SFLAG_QUAD_READ (1<<7) -+ -+#define SFLAG_DUAL_IO_WRITE (1<<8) -+#define SFLAG_DUAL_WRITE (1<<9) -+#define SFLAG_QUAD_IO_WRITE (1<<10) -+#define SFLAG_QUAD_WRITE (1<<11) -+ -+#define SFLAG_SECT_4K (1<<12) -+ -+}; -+ -+/** -+ *because of some spi flash is difference of status register difinition. -+ *this structure use mapping the status reg function and corresponding. -+*/ -+struct flash_status_reg -+{ -+ u32 jedec_id; -+ u16 ext_id; -+ unsigned b_wip:4; /*write in progress*/ -+ unsigned b_wel:4; /*wrute ebabke latch*/ -+ unsigned b_bp0:4; /*block protected 0*/ -+ unsigned b_bp1:4; /*block protected 1*/ -+ unsigned b_bp2:4; /*block protected 2*/ -+ unsigned b_bp3:4; /*block protected 3*/ -+ unsigned b_bp4:4; /*block protected 4*/ -+ unsigned b_srp0:4; /*status register protect 0*/ -+ -+ unsigned b_srp1:4; /*status register protect 1*/ -+ unsigned b_qe:4; /*quad enable*/ -+ unsigned b_lb:4; /*write protect control and status to the security reg.*/ -+/* -+ unsigned b_reserved0:4; -+ unsigned b_reserved1:4; -+ unsigned b_reserved2:4; -+*/ -+ unsigned b_cmp:4; /*conjunction bp0-bp4 bit*/ -+ unsigned b_sus:4; /*exec an erase/program suspend command*/ -+}; -+ -+struct ak_spiflash { -+ struct spi_device *spi; -+ struct mutex lock; -+ struct flash_info info; -+ struct mtd_info mtd; -+ unsigned partitioned:1; -+ -+ u8 bus_width; -+ unsigned char *buf; -+ u8 command[CMD_ADDR_SIZE + MAX_DUMMY_SIZE]; -+ u8 dummy_len; -+ -+ u8 erase_opcode; -+ u8 tx_opcode; -+ u8 rx_opcode; -+ u8 txd_bus_width; -+ u8 rxd_bus_width; -+ -+ u8 txa_bus_width; -+ u8 rxa_bus_width; -+ struct flash_status_reg stat_reg; -+}; -+ -+static struct mtd_info *ak_mtd_info; -+ -+ -+static inline struct ak_spiflash *mtd_to_spiflash(struct mtd_info *mtd) -+{ -+ return container_of(mtd, struct ak_spiflash, mtd); -+} -+ -+#ifdef SPIFLASH_USE_MTD_BLOCK_LAYER -+/** -+* @brief: because of the _read() function call by mtd block layer, the buffer be -+* allocate by vmalloc() in mtd layer, spi driver layer may use this buffer that -+* intents of use for DMA transfer, so, add this function to transition buffer. -+* call this function at before real read/write data. -+* -+* @author lixinhai -+* @date 2013-04-10 -+* @param[in] flash spiflash handle. -+* @param[in] buffer. -+* @param[in] buffer len -+* @param[in] read/write -+* @retval return the transition buffer -+*/ -+static void *flash_buf_bounce_pre(struct ak_spiflash *flash, -+ void *buf, u32 len, int dir) -+{ -+ if(!is_vmalloc_addr(buf)) { -+ return buf; -+ } -+ -+ if(dir == SPI_FLASH_WRITE) { -+ memcpy(flash->buf, buf, len); -+ } -+ return flash->buf; -+} -+ -+/** -+* @brief: because of the _read() function call by mtd block layer, the buffer be -+* allocate by vmalloc() in mtd layer, spi driver layer may use this buffer that -+* intents of use for DMA transfer, so, add this function to transition buffer. -+* call this function at after real read/write data -+* -+* @author lixinhai -+* @date 2013-04-10 -+* @param[in] flash spiflash handle. -+* @param[in] buffer. -+* @param[in] buffer len -+* @param[in] read/write -+* @retval return the transition buffer -+*/ -+static void flash_buf_bounce_post(struct ak_spiflash *flash, -+ void *buf, u32 len, int dir) -+{ -+ if(!is_vmalloc_addr(buf)) { -+ return; -+ } -+ -+ if(dir == SPI_FLASH_READ) { -+ memcpy(buf, flash->buf, len); -+ } -+} -+#else -+static inline void *flash_buf_bounce_pre(struct ak_spiflash *flash, -+ void *buf, u32 len, int dir) -+{ -+ return buf; -+} -+ -+static inline void flash_buf_bounce_post(struct ak_spiflash *flash, -+ void *buf, u32 len, int dir) -+{ -+} -+ -+#endif -+ -+/* -+ * Internal helper functions -+ */ -+ -+/** -+* @brief Read the status register. -+* -+* returning its value in the location -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] spiflash handle. -+* @return int Return the status register value. -+*/ -+static int read_sr(struct ak_spiflash *flash) -+{ -+ ssize_t retval; -+ u8 code; -+ u16 status; -+ u8 status1, status2; -+ -+ code = OPCODE_RDSR1; -+ -+ if((retval = spi_write_then_read(flash->spi, &code, 1, &status1, 1))<0) -+ return retval; -+ -+ if(flash->info.flags & SFLAG_COM_STATUS2){ -+ code = OPCODE_RDSR2; -+ if((retval = spi_write_then_read(flash->spi, &code, 1, &status2, 1))<0) -+ return retval; -+ -+ status = (status1 | (status2 << 8)); -+ } else -+ status = status1 & 0xff; -+ -+ return status; -+} -+ -+ -+/** -+* @brief Write status register -+* -+* Write status register 1 byte. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] flash spiflash handle. -+* @param[in] val register value to be write. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a negative error code if failed -+*/ -+static int write_sr(struct ak_spiflash *flash, u16 val) -+{ -+ int wr_cnt; -+ -+ flash->command[0] = OPCODE_WRSR; -+ flash->command[1] = val & 0xff; -+ flash->command[2] = (val>>8) &0xff; -+ -+ if (flash->info.flags & SFLAG_COM_STATUS2) { -+ wr_cnt = 3; -+ } else { -+ wr_cnt = 2; -+ } -+ -+ return spi_write(flash->spi, flash->command, wr_cnt); -+} -+ -+ -+/** -+* @brief Set write enable latch. -+* -+* Set write enable latch with Write Enable command. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] flash spiflash handle. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a negative error code if failed -+*/ -+static inline int write_enable(struct ak_spiflash *flash) -+{ -+ u8 code = OPCODE_WREN; -+ -+ return spi_write_then_read(flash->spi, &code, 1, NULL, 0); -+} -+ -+ -+/** -+* @brief Set write disble -+* -+* Set write disble instruction to the chip. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] flash spiflash handle. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a negative error code if failed -+*/ -+static inline int write_disable(struct ak_spiflash *flash) -+{ -+ u8 code = OPCODE_WRDI; -+ -+ return spi_write_then_read(flash->spi, &code, 1, NULL, 0); -+} -+ -+/** -+* @brief Wait for SPI flash ready. -+* -+* Service routine to read status register until ready, or timeout occurs. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] flash spiflash handle. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int wait_till_ready(struct ak_spiflash *flash) -+{ -+ unsigned long deadline; -+ int sr; -+ struct flash_status_reg *fsr = &flash->stat_reg; -+ -+ deadline = jiffies + MAX_READY_WAIT_JIFFIES; -+ -+ do { -+ if ((sr = read_sr(flash)) < 0) -+ break; -+ else if (!(sr & (1<<fsr->b_wip))) -+ return 0; -+ -+ cond_resched(); -+ -+ } while (!time_after_eq(jiffies, deadline)); -+ -+ return 1; -+} -+ -+static int quad_mode_enable(struct ak_spiflash *flash) -+{ -+ int ret; -+ u16 regval; -+ struct flash_status_reg *fsr = &flash->stat_reg; -+ -+ ret = wait_till_ready(flash); -+ if (ret) -+ return -EBUSY; -+ -+ write_enable(flash); -+ -+ regval = read_sr(flash); -+ regval |= 1<<fsr->b_qe; -+ write_sr(flash, regval); -+ -+ write_disable(flash); -+ return 0; -+} -+ -+static int quad_mode_disable(struct ak_spiflash *flash) -+{ -+ int ret; -+ u16 regval; -+ struct flash_status_reg *fsr = &flash->stat_reg; -+ -+ ret = wait_till_ready(flash); -+ if (ret) -+ return -EBUSY; -+ -+ write_enable(flash); -+ -+ regval = read_sr(flash); -+ regval &= ~(1<<fsr->b_qe); -+ write_sr(flash, regval); -+ -+ write_disable(flash); -+ return 0; -+} -+ -+/** -+* @brief Erase chip -+* -+* Erase the whole flash memory. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] flash spiflash handle. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int erase_chip(struct ak_spiflash *flash) -+{ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n", -+ dev_name(&flash->spi->dev), __func__, -+ (long long)(flash->mtd.size >> 10)); -+ -+ /* Wait until finished previous write command. */ -+ if (wait_till_ready(flash)) -+ return -EBUSY; -+ -+ /* Send write enable, then erase commands. */ -+ write_enable(flash); -+ -+ /* Set up command buffer. */ -+ flash->command[0] = OPCODE_CHIP_ERASE; -+ -+ spi_write(flash->spi, flash->command, 1); -+ -+ return 0; -+} -+ -+ -+ -+/** -+* @brief Erase sector -+* -+* Erase a sector specialed by user. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] flash spiflash handle. -+* @param[in] offset which is any address within the sector which should be erased. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int erase_sector(struct ak_spiflash *flash, u32 offset) -+{ -+ DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", -+ dev_name(&flash->spi->dev), __func__, -+ flash->mtd.erasesize / 1024, offset); -+ -+ /* Wait until finished previous write command. */ -+ if (wait_till_ready(flash)) -+ return -EBUSY; -+ -+ /* Send write enable, then erase commands. */ -+ write_enable(flash); -+ -+ /* Set up command buffer. */ -+ flash->command[0] = flash->erase_opcode; -+ flash->command[1] = offset >> 16; -+ flash->command[2] = offset >> 8; -+ flash->command[3] = offset; -+ -+ spi_write(flash->spi, flash->command, CMD_ADDR_SIZE); -+ -+ return 0; -+} -+ -+/****************************************************************************/ -+ -+/* -+ * MTD implementation -+ */ -+ -+ -+/** -+* @brief MTD Erase -+* -+* Erase an address range on the flash chip. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd mtd info handle. -+* @param[in] instr erase info. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int ak_spiflash_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct ak_spiflash *flash = mtd_to_spiflash(mtd); -+ u32 addr,len; -+ uint32_t rem; -+ -+ PDEBUG("ak_spiflash_erase\n"); -+ //printk(": instr->len=%lld, mtd->erasesize=%ld, addr=%lld\n", instr->len,mtd->erasesize,(long long)instr->addr); -+ -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n", -+ dev_name(&flash->spi->dev), __func__, "at", -+ (long long)instr->addr, (long long)instr->len); -+ -+ /* sanity checks */ -+ if (instr->addr + instr->len > mtd->size) -+ { -+ printk(KERN_ERR "ak_spiflash_erase:instr->addr[0x%llx] + instr->len[%lld] > mtd->size[%lld]\n", -+ instr->addr, instr->len, mtd->size ); -+ return -EINVAL; -+ } -+ div_u64_rem(instr->len, mtd->erasesize, &rem); -+ if (rem != 0) -+ { -+ printk(KERN_ERR "ak_spiflash_erase:rem!=0 [%u]\n", rem ); -+ return -EINVAL; -+ } -+ -+ addr = instr->addr; -+ len = instr->len; -+ -+ mutex_lock(&flash->lock); -+ -+ /* whole-chip erase? */ -+ if (len == mtd->size) { -+ if (erase_chip(flash)) { -+ instr->state = MTD_ERASE_FAILED; -+ mutex_unlock(&flash->lock); -+ return -EIO; -+ } -+ -+ /* REVISIT in some cases we could speed up erasing large regions -+ * by using OPCODE_SE instead of OPCODE_BE_4K. We may have set up -+ * to use "small sector erase", but that's not always optimal. -+ */ -+ -+ /* "sector"-at-a-time erase */ -+ } else { -+ while (len) { -+ if (erase_sector(flash, addr)) { -+ instr->state = MTD_ERASE_FAILED; -+ mutex_unlock(&flash->lock); -+ return -EIO; -+ } -+ -+ addr += mtd->erasesize; -+ len -= mtd->erasesize; -+ } -+ } -+ -+ mutex_unlock(&flash->lock); -+ -+ instr->state = MTD_ERASE_DONE; -+ mtd_erase_callback(instr); -+ -+ return 0; -+} -+ -+ -+static int init_spiflash_rw_info(struct ak_spiflash *flash) -+{ -+ /**default param.*/ -+ flash->rx_opcode = OPCODE_READ; -+ flash->rxd_bus_width = XFER_1DATAWIRE; -+ flash->rxa_bus_width = XFER_1DATAWIRE; -+ flash->tx_opcode = OPCODE_PP; -+ flash->txd_bus_width = XFER_1DATAWIRE; -+ flash->txa_bus_width = XFER_1DATAWIRE; -+ flash->dummy_len = 1; -+ -+ if(flash->bus_width & FLASH_BUS_WIDTH_2WIRE){ -+ if(flash->info.flags & SFLAG_DUAL_READ) { -+ flash->rx_opcode = OPCODE_FAST_D_READ; -+ flash->rxd_bus_width = XFER_2DATAWIRE; -+ flash->rxa_bus_width = XFER_1DATAWIRE; -+ flash->dummy_len = 1; -+ } else if (flash->info.flags & SFLAG_DUAL_IO_READ) { -+ flash->rx_opcode = OPCODE_FAST_D_IO; -+ flash->rxd_bus_width = XFER_2DATAWIRE; -+ flash->rxa_bus_width = XFER_2DATAWIRE; -+ flash->dummy_len = 1; -+ } -+ -+ if(flash->info.flags & SFLAG_DUAL_WRITE) { -+ flash->tx_opcode = OPCODE_PP_DUAL; -+ flash->txd_bus_width = XFER_2DATAWIRE; -+ flash->txa_bus_width = XFER_1DATAWIRE; -+ } else if(flash->info.flags & SFLAG_DUAL_IO_WRITE) { -+ flash->tx_opcode = OPCODE_2IO_PP; -+ flash->txd_bus_width = XFER_2DATAWIRE; -+ flash->txa_bus_width = XFER_2DATAWIRE; -+ } -+ } -+ -+ if(flash->bus_width & FLASH_BUS_WIDTH_4WIRE){ -+ if(flash->info.flags & SFLAG_QUAD_READ) { -+ flash->rx_opcode = OPCODE_FAST_Q_READ; -+ flash->rxd_bus_width = XFER_4DATAWIRE; -+ flash->rxa_bus_width = XFER_1DATAWIRE; -+ flash->dummy_len = 1; -+ }else if(flash->info.flags & SFLAG_QUAD_IO_READ){ -+ flash->rx_opcode = OPCODE_FAST_Q_IO; -+ flash->rxd_bus_width = XFER_4DATAWIRE; -+ flash->rxa_bus_width = XFER_4DATAWIRE; -+ flash->dummy_len = 3; -+ } -+ -+ if(flash->info.flags & SFLAG_QUAD_WRITE) { -+ flash->tx_opcode = OPCODE_PP_QUAD; -+ flash->txd_bus_width = XFER_4DATAWIRE; -+ flash->txa_bus_width = XFER_1DATAWIRE; -+ }else if(flash->info.flags & SFLAG_QUAD_IO_WRITE) { -+ flash->tx_opcode = OPCODE_4IO_PP; -+ flash->txd_bus_width = XFER_4DATAWIRE; -+ flash->txa_bus_width = XFER_4DATAWIRE; -+ } -+ -+ } -+ return 0; -+} -+ -+static int ak_spiflash_cfg_quad_mode(struct ak_spiflash *flash) -+{ -+ int ret = 0; -+ -+ if((flash->bus_width & FLASH_BUS_WIDTH_4WIRE) && -+ (flash->info.flags & (SFLAG_QUAD_WRITE|SFLAG_QUAD_IO_WRITE| -+ SFLAG_DUAL_READ|SFLAG_DUAL_IO_READ))) { -+ ret = quad_mode_enable(flash); -+ if(ret) -+ flash->bus_width &= ~FLASH_BUS_WIDTH_4WIRE; -+ } -+ else -+ quad_mode_disable(flash); -+ -+ return ret; -+} -+ -+ -+#define FILL_CMD(c, val) do{c[0] = (val);}while(0) -+#define FILL_ADDR(c, val) do{ \ -+ c[CMD_SIZE] = (val) >> 16; \ -+ c[CMD_SIZE+1] = (val) >> 8; \ -+ c[CMD_SIZE+2] = (val); \ -+ }while(0) -+ -+#define FILL_DUMMY_DATA(c, val) do{ \ -+ c[CMD_ADDR_SIZE] = val >> 16; \ -+ c[CMD_ADDR_SIZE+1] = 0; \ -+ c[CMD_ADDR_SIZE+2] = 0; \ -+ c[CMD_ADDR_SIZE+3] = 0; \ -+ }while(0) -+ -+ -+static int spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ struct ak_spiflash *flash = mtd_to_spiflash(mtd); -+ struct spi_transfer t[3]; -+ struct spi_message m; -+ void *bounce_buf; -+ -+ spi_message_init(&m); -+ memset(t, 0, (sizeof t)); -+ -+ mutex_lock(&flash->lock); -+ -+ bounce_buf = flash_buf_bounce_pre(flash, buf, len, SPI_FLASH_READ); -+ -+ t[0].tx_buf = flash->command; -+ t[0].len = CMD_SIZE; -+ spi_message_add_tail(&t[0], &m); -+ -+ t[1].tx_buf = &flash->command[CMD_SIZE]; -+ t[1].len = ADDR_SIZE + flash->dummy_len; -+ t[1].xfer_mode = flash->rxa_bus_width; -+ spi_message_add_tail(&t[1], &m); -+ -+ t[2].rx_buf = bounce_buf; -+ t[2].len = len; -+ t[2].cs_change = 1; -+ t[2].xfer_mode = flash->rxd_bus_width; -+ -+ spi_message_add_tail(&t[2], &m); -+ -+ /* Byte count starts at zero. */ -+ if (retlen) -+ *retlen = 0; -+ -+ /* Wait till previous write/erase is done. */ -+ if (wait_till_ready(flash)) { -+ /* REVISIT status return?? */ -+ mutex_unlock(&flash->lock); -+ return -EBUSY; -+ } -+ -+ /* Set up the write data buffer. */ -+ FILL_CMD(flash->command, flash->rx_opcode); -+ FILL_ADDR(flash->command, from); -+ FILL_DUMMY_DATA(flash->command, 0x00); -+ -+ spi_sync(flash->spi, &m); -+ -+ *retlen = m.actual_length - CMD_ADDR_SIZE - flash->dummy_len; -+ -+ flash_buf_bounce_post(flash, buf, len, SPI_FLASH_READ); -+ -+ mutex_unlock(&flash->lock); -+ -+ return 0; -+} -+ -+ -+static int ak_spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ int ret = 0; -+ size_t rlen = 0; -+ u32 xfer_len; -+ u32 offset = 0; -+ u32 count = len; -+ -+ while(count > 0) { -+ xfer_len = (count > FLASH_BUF_SIZE) ? FLASH_BUF_SIZE : count; -+ -+ if(xfer_len > FLASH_PAGESIZE) -+ xfer_len = ALIGN_DOWN(xfer_len, FLASH_PAGESIZE); -+ -+ ret = spiflash_read(mtd, from + offset, xfer_len, &rlen, buf + offset); -+ if(unlikely(ret)) { -+ ret = -EBUSY; -+ goto out; -+ } -+ -+ *retlen += rlen; -+ count -= rlen; -+ offset += rlen; -+ } -+out: -+ return ret; -+} -+ -+ -+/** -+* @brief MTD write -+* -+* Write an address range to the flash chip. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd mtd info handle. -+* @param[in] to write start address. -+* @param[in] len write length. -+* @param[out] retlen write length at actually. -+* @param[out] buf the pointer to write data. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int ak_spiflash_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct ak_spiflash *flash = mtd_to_spiflash(mtd); -+ u32 page_offset, page_size; -+ struct spi_transfer t[3]; -+ struct spi_message m; -+ void *bounce_buf; -+ -+ DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", -+ dev_name(&flash->spi->dev), __func__, "to", -+ (u32)to, len); -+ -+ if (retlen) -+ *retlen = 0; -+ -+ /* sanity checks */ -+ if (!len) -+ return(0); -+ -+ if (to + len > mtd->size) -+ return -EINVAL; -+ -+ spi_message_init(&m); -+ memset(t, 0, (sizeof t)); -+ -+ mutex_lock(&flash->lock); -+ bounce_buf = flash_buf_bounce_pre(flash, (void*)buf, len, SPI_FLASH_WRITE); -+ -+ t[0].tx_buf = flash->command; -+ t[0].len = CMD_SIZE; -+ spi_message_add_tail(&t[0], &m); -+ -+ t[1].tx_buf = &flash->command[CMD_SIZE]; -+ t[1].len = ADDR_SIZE; -+ t[1].xfer_mode = flash->txa_bus_width; -+ spi_message_add_tail(&t[1], &m); -+ -+ t[2].tx_buf = bounce_buf; -+ t[2].cs_change = 1; -+ t[2].xfer_mode = flash->txd_bus_width; -+ -+ spi_message_add_tail(&t[2], &m); -+ -+ //memcpy(flash->buf, buf, len); -+ -+ /* Wait until finished previous write command. */ -+ if (wait_till_ready(flash)) { -+ mutex_unlock(&flash->lock); -+ return 1; -+ } -+ -+ write_enable(flash); -+ -+ /* Set up the opcode in the write buffer. */ -+ FILL_CMD(flash->command, flash->tx_opcode); -+ FILL_ADDR(flash->command, to); -+ -+ /* what page do we start with? */ -+ page_offset = to % FLASH_PAGESIZE; -+ -+ /* do all the bytes fit onto one page? */ -+ if (page_offset + len <= FLASH_PAGESIZE) { -+ t[2].len = len; -+ -+ spi_sync(flash->spi, &m); -+ -+ *retlen = m.actual_length - CMD_ADDR_SIZE; -+ } else { -+ u32 i; -+ -+ /* the size of data remaining on the first page */ -+ page_size = FLASH_PAGESIZE - page_offset; -+ -+ t[2].len = page_size; -+ spi_sync(flash->spi, &m); -+ -+ *retlen = m.actual_length - CMD_ADDR_SIZE; -+ -+ /* write everything in PAGESIZE chunks */ -+ for (i = page_size; i < len; i += page_size) { -+ page_size = len - i; -+ if (page_size > FLASH_PAGESIZE) -+ page_size = FLASH_PAGESIZE; -+ -+ /* write the next page to flash */ -+ FILL_ADDR(flash->command, to+i); -+ -+ t[2].tx_buf = buf + i; -+ t[2].len = page_size; -+ -+ wait_till_ready(flash); -+ -+ write_enable(flash); -+ -+ spi_sync(flash->spi, &m); -+ -+ if (retlen) -+ *retlen += m.actual_length - CMD_ADDR_SIZE; -+ } -+ } -+ -+ PDEBUG("ak_spiflash_write: retlen=%ld\n", *retlen); -+ flash_buf_bounce_post(flash, (void*)buf, len, SPI_FLASH_WRITE); -+ -+ mutex_unlock(&flash->lock); -+ -+ return 0; -+} -+ -+/** -+* @brief MTD get device ID -+* -+* get the device ID of the spi flash chip. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd mtd info handle. -+* @return int return device ID of the spi flash chip. -+*/ -+static int ak_spiflash_get_devid(struct mtd_info *mtd) -+{ -+ struct ak_spiflash *flash = mtd_to_spiflash(mtd); -+ int ret; -+ u8 code = OPCODE_RDID; -+ u8 id[5]; -+ u32 jedec; -+ -+ /* Wait until finished previous write command. */ -+ if (wait_till_ready(flash)) -+ return -EBUSY; -+ -+ /* JEDEC also defines an optional "extended device information" -+ * string for after vendor-specific data, after the three bytes -+ * we use here. Supporting some chips might require using it. -+ */ -+ ret = spi_write_then_read(flash->spi, &code, 1, id, 3); -+ if (ret < 0) { -+ DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d ak_spiflash_get_devid\n", -+ dev_name(&flash->spi->dev), ret); -+ return AK_FALSE; -+ } -+ -+ jedec = id[0] | (id[1]<<8) | (id[2]<<16); -+ printk("spi flash ID: 0x%08x\n", jedec); -+ -+ return jedec; -+} -+ -+ -+ /** -+ * @brief MTD write only for SST spi flash. -+ * -+ * Write an address range to the flash chip. -+ * @author SheShaohua -+ * @date 2012-03-20 -+ * @param[in] mtd mtd info handle. -+ * @param[in] to write start address. -+ * @param[in] len write length. -+ * @param[out] retlen write length at actually. -+ * @param[out] buf the pointer to write data. -+ * @return int return write success or failed -+ * @retval returns zero on success -+ * @retval return a non-zero error code if failed -+ */ -+static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct ak_spiflash *flash = mtd_to_spiflash(mtd); -+ struct spi_transfer t[2]; -+ struct spi_message m; -+ size_t actual; -+ int cmd_sz, ret; -+ -+ if (retlen) -+ *retlen = 0; -+ -+ /* sanity checks */ -+ if (!len) -+ return 0; -+ -+ if (to + len > flash->mtd.size) -+ return -EINVAL; -+ -+ spi_message_init(&m); -+ memset(t, 0, (sizeof t)); -+ -+ t[0].tx_buf = flash->command; -+ t[0].len = CMD_ADDR_SIZE; -+ spi_message_add_tail(&t[0], &m); -+ -+ t[1].tx_buf = buf; -+ spi_message_add_tail(&t[1], &m); -+ -+ mutex_lock(&flash->lock); -+ -+ /* Wait until finished previous write command. */ -+ ret = wait_till_ready(flash); -+ if (ret) -+ goto time_out; -+ -+ write_enable(flash); -+ -+ actual = to % 2; -+ /* Start write from odd address. */ -+ if (actual) { -+ flash->command[0] = OPCODE_BP; -+ flash->command[1] = to >> 16; -+ flash->command[2] = to >> 8; -+ flash->command[3] = to; -+ -+ /* write one byte. */ -+ t[1].len = 1; -+ spi_sync(flash->spi, &m); -+ ret = wait_till_ready(flash); -+ if (ret) -+ goto time_out; -+ *retlen += m.actual_length - CMD_ADDR_SIZE; -+ } -+ to += actual; -+ -+ flash->command[0] = OPCODE_AAI_WP; -+ flash->command[1] = to >> 16; -+ flash->command[2] = to >> 8; -+ flash->command[3] = to; -+ -+ /* Write out most of the data here. */ -+ cmd_sz = CMD_ADDR_SIZE; -+ for (; actual < len - 1; actual += 2) { -+ t[0].len = cmd_sz; -+ /* write two bytes. */ -+ t[1].len = 2; -+ t[1].tx_buf = buf + actual; -+ -+ spi_sync(flash->spi, &m); -+ ret = wait_till_ready(flash); -+ if (ret) -+ goto time_out; -+ *retlen += m.actual_length - cmd_sz; -+ cmd_sz = 1; -+ to += 2; -+ } -+ write_disable(flash); -+ ret = wait_till_ready(flash); -+ if (ret) -+ goto time_out; -+ -+ /* Write out trailing byte if it exists. */ -+ if (actual != len) { -+ write_enable(flash); -+ flash->command[0] = OPCODE_BP; -+ flash->command[1] = to >> 16; -+ flash->command[2] = to >> 8; -+ flash->command[3] = to; -+ t[0].len = CMD_ADDR_SIZE; -+ t[1].len = 1; -+ t[1].tx_buf = buf + actual; -+ -+ spi_sync(flash->spi, &m); -+ ret = wait_till_ready(flash); -+ if (ret) -+ goto time_out; -+ *retlen += m.actual_length - CMD_ADDR_SIZE; -+ write_disable(flash); -+ } -+ -+time_out: -+ mutex_unlock(&flash->lock); -+ return ret; -+} -+ -+/****************************************************************************/ -+ -+static struct flash_status_reg __devinitdata status_reg_list[] = { -+ /*spiflash mx25l12805d*/ -+ { -+ .jedec_id = 0xc22018, .ext_id = 0, -+ .b_wip = 0, .b_wel = 1, .b_bp0 = 2, .b_bp1 = 3, -+ .b_bp2 = 4, .b_bp3 = 5, .b_qe = 6, .b_srp0 = 7, -+ }, -+ /*normal status reg define*/ -+ { -+ .jedec_id = 0, .ext_id = 0, -+ .b_wip = 0, .b_wel = 1, .b_bp0 = 2, .b_bp1 = 3, -+ .b_bp2 = 4, .b_bp3 = 5, .b_bp4 = 6, .b_srp0 = 7, -+ -+ .b_srp1 = 8,.b_qe = 9, .b_lb = 10, .b_cmp = 14, -+ .b_sus = 15, -+ }, -+}; -+ -+ -+ -+/* NOTE: double check command sets and memory organization when you add -+ * more flash chips. This current list focusses on newer chips, which -+ * have been converging on command sets which including JEDEC ID. -+ */ -+static struct flash_info __devinitdata ak_spiflash_supportlist [] = { -+ -+ /* Atmel -- some are (confusingly) marketed as "DataFlash" */ -+ { "at25fs010", 0x1f6601, 0, 32 * 1024, 4, SFLAG_SECT_4K, }, -+ { "at25fs040", 0x1f6604, 0, 64 * 1024, 8, SFLAG_SECT_4K, }, -+ -+ { "at25df041a", 0x1f4401, 0, 64 * 1024, 8, SFLAG_SECT_4K, }, -+ { "at25df641", 0x1f4800, 0, 64 * 1024, 128, SFLAG_SECT_4K, }, -+ -+ { "at26f004", 0x1f0400, 0, 64 * 1024, 8, SFLAG_SECT_4K, }, -+ { "at26df081a", 0x1f4501, 0, 64 * 1024, 16, SFLAG_SECT_4K, }, -+ { "at26df161a", 0x1f4601, 0, 64 * 1024, 32, SFLAG_SECT_4K, }, -+ { "at26df321", 0x1f4701, 0, 64 * 1024, 64, SFLAG_SECT_4K, }, -+ -+ /* Macronix */ -+ { "mx25l3205d", 0xc22016, 0, 64 * 1024, 64, SFLAG_SECT_4K | SFLAG_DUAL_READ}, -+ { "mx25l6405d", 0xc22017, 0, 64 * 1024, 128, SFLAG_SECT_4K | SFLAG_DUAL_READ}, -+ { "mx25l12805d", 0xc22018, 0, 64 * 1024, 256, SFLAG_SECT_4K | SFLAG_DUAL_IO_READ | SFLAG_QUAD_IO_READ | SFLAG_QUAD_IO_WRITE}, -+ { "mx25l12855e", 0xc22618, 0, 64 * 1024, 256, SFLAG_SECT_4K | SFLAG_DUAL_READ}, -+ -+ /* Spansion -- single (large) sector size only, at least -+ * for the chips listed here (without boot sectors). -+ */ -+ { "s25sl004a", 0x010212, 0, 64 * 1024, 8, }, -+ { "s25sl008a", 0x010213, 0, 64 * 1024, 16, }, -+ { "s25sl016a", 0x010214, 0, 64 * 1024, 32, }, -+ { "s25sl032a", 0x010215, 0, 64 * 1024, 64, }, -+ { "s25sl064a", 0x010216, 0, 64 * 1024, 128, }, -+ { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, }, -+ { "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, }, -+ { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, }, -+ { "s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, }, -+ -+ /* SST -- large erase sizes are "overlays", "sectors" are 4K */ -+ { "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SFLAG_SECT_4K, }, -+ { "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SFLAG_SECT_4K, }, -+ { "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SFLAG_SECT_4K, }, -+ { "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SFLAG_SECT_4K, }, -+ { "sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SFLAG_SECT_4K, }, -+ { "sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SFLAG_SECT_4K, }, -+ { "sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SFLAG_SECT_4K, }, -+ { "sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SFLAG_SECT_4K, }, -+ -+ /* ST Microelectronics -- newer production may have feature updates */ -+ { "m25p05", 0x202010, 0, 32 * 1024, 2, }, -+ { "m25p10", 0x202011, 0, 32 * 1024, 4, }, -+ { "m25p20", 0x202012, 0, 64 * 1024, 4, }, -+ { "m25p40", 0x202013, 0, 64 * 1024, 8, }, -+ { "m25p80", 0, 0, 64 * 1024, 16, }, -+ { "m25p16", 0x202015, 0, 64 * 1024, 32, }, -+ { "m25p32", 0x202016, 0, 64 * 1024, 64, }, -+ { "m25p64", 0x202017, 0, 64 * 1024, 128, }, -+ { "m25p128", 0x202018, 0, 256 * 1024, 64, }, -+ -+ { "m45pe10", 0x204011, 0, 64 * 1024, 2, }, -+ { "m45pe80", 0x204014, 0, 64 * 1024, 16, }, -+ { "m45pe16", 0x204015, 0, 64 * 1024, 32, }, -+ -+ { "m25pe80", 0x208014, 0, 64 * 1024, 16, }, -+ { "m25pe16", 0x208015, 0, 64 * 1024, 32, SFLAG_SECT_4K, }, -+ -+ /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ -+ { "w25x10", 0xef3011, 0, 64 * 1024, 2, SFLAG_SECT_4K, }, -+ { "w25x20", 0xef3012, 0, 64 * 1024, 4, SFLAG_SECT_4K, }, -+ { "w25x40", 0xef3013, 0, 64 * 1024, 8, SFLAG_SECT_4K, }, -+ { "w25x80", 0xef3014, 0, 64 * 1024, 16, SFLAG_SECT_4K, }, -+ { "w25x16", 0xef3015, 0, 64 * 1024, 32, SFLAG_SECT_4K, }, -+ { "w25x32", 0xef3016, 0, 64 * 1024, 64, SFLAG_SECT_4K, }, -+ { "w25x64", 0xef3017, 0, 64 * 1024, 128, SFLAG_SECT_4K, }, -+ -+ { "w25q32", 0xef4016, 0, 32 * 1024, 128, SFLAG_SECT_4K|SFLAG_COM_STATUS2|SFLAG_DUAL_READ|SFLAG_QUAD_READ|SFLAG_QUAD_WRITE, }, -+ { "w25q64", 0xef4017, 0, 64 * 1024, 128, SFLAG_SECT_4K|SFLAG_COM_STATUS2|SFLAG_DUAL_READ|SFLAG_QUAD_READ|SFLAG_QUAD_WRITE, }, -+ { "w25q128", 0xef4018, 0, 64 * 1024, 128, SFLAG_SECT_4K|SFLAG_COM_STATUS2|SFLAG_DUAL_READ|SFLAG_QUAD_READ|SFLAG_QUAD_WRITE, }, -+ -+ /* GigaDevice -- w25x "blocks" are 64K, "sectors" are 4KiB */ -+ { "gd25q64", 0xc84017, 0, 64 * 1024, 128, SFLAG_SECT_4K|SFLAG_COM_STATUS2|SFLAG_DUAL_READ|SFLAG_QUAD_READ|SFLAG_DUAL_IO_READ|SFLAG_QUAD_IO_READ|SFLAG_QUAD_WRITE , }, -+ { "gd25q128", 0xc84018, 0, 64 * 1024, 128, SFLAG_SECT_4K|SFLAG_COM_STATUS2|SFLAG_DUAL_READ|SFLAG_QUAD_READ|SFLAG_DUAL_IO_READ|SFLAG_QUAD_IO_READ|SFLAG_QUAD_WRITE ,}, -+}; -+ -+T_U32 ak_fha_erase_callback(T_U32 chip_num, T_U32 startpage) -+{ -+ struct erase_info einfo; -+ memset(&einfo, 0, sizeof(struct erase_info)); -+ einfo.addr = startpage * FLASH_PAGESIZE; -+ einfo.len = ak_mtd_info->erasesize; -+ einfo.mtd = ak_mtd_info; -+ -+ if(ak_spiflash_erase(ak_mtd_info, &einfo) == 0) -+ { -+ return FHA_SUCCESS; -+ } -+ else -+ { -+ printk("***erase failed\n"); -+ return FHA_FAIL; -+ } -+} -+ -+T_U32 ak_fha_write_callback(T_U32 chip_num, T_U32 page_num, const T_U8 *data, -+ T_U32 data_len, T_U8 *oob, T_U32 oob_len, T_U32 eDataType) -+{ -+ int ret; -+ ssize_t retlen; -+ loff_t to = page_num * FLASH_PAGESIZE; -+ ret = ak_spiflash_write(ak_mtd_info, to, data_len * FLASH_PAGESIZE, &retlen, data); -+ if(ret) -+ { -+ printk("%s:%d\n", __func__, __LINE__); -+ return FHA_FAIL; -+ } -+ return FHA_SUCCESS; -+} -+ -+T_U32 ak_fha_read_callback(T_U32 chip_num, T_U32 page_num, T_U8 *data, -+ T_U32 data_len, T_U8 *oob, T_U32 oob_len, T_U32 eDataType) -+{ -+ int ret; -+ ssize_t retlen; -+ loff_t from = page_num * FLASH_PAGESIZE; -+ -+ ret = ak_spiflash_read(ak_mtd_info, from, data_len * FLASH_PAGESIZE, &retlen, data); -+ if (ret) { -+ printk("%s:%d\n", __func__, __LINE__); -+ return FHA_FAIL; -+ } -+ -+ return FHA_SUCCESS; -+} -+ -+static T_VOID *fha_ram_alloc(T_U32 size) -+{ -+ return kmalloc(size, GFP_KERNEL); -+} -+ -+static T_VOID *fha_ram_free(void *point) -+{ -+ kfree(point); -+ return NULL; -+} -+ -+static T_S32 fha_print(T_pCSTR fmt, ...) -+{ -+ va_list args; -+ int r; -+ -+ va_start(args, fmt); -+ vprintk("FHA:",args); -+ r = vprintk(fmt, args); -+ va_end(args); -+ -+ return r; -+} -+ -+int ak_fha_init(void) -+{ -+ int ret = 0; -+ T_PFHA_INIT_INFO pInit_info = NULL; -+ T_PFHA_LIB_CALLBACK pCallback = NULL; -+ T_SPI_BURN_INIT_INFO spi_info; -+ -+ pInit_info = kmalloc(sizeof(T_FHA_INIT_INFO), GFP_KERNEL); -+ if (!pInit_info) { -+ printk("allocate memory for pInit_info failed\n"); -+ return -ENOMEM; -+ } -+ -+ pInit_info->nChipCnt = 0; -+ pInit_info->nBlockStep = 1; -+ pInit_info->eAKChip = FHA_CHIP_SET_TYPE; -+ pInit_info->ePlatform = PLAT_LINUX; -+ pInit_info->eMedium = MEDIUM_SPIFLASH; -+ pInit_info->eMode = MODE_UPDATE; -+ -+ pCallback = kmalloc(sizeof(T_FHA_LIB_CALLBACK), GFP_KERNEL); -+ if (!pCallback) { -+ printk("allocate memory for pCallback failed\n"); -+ ret = -ENOMEM; -+ goto err_out; -+ } -+ -+ pCallback->Erase = ak_fha_erase_callback; -+ pCallback->Write = (FHA_Write)ak_fha_write_callback; -+ pCallback->Read = (FHA_Read)ak_fha_read_callback; -+ pCallback->RamAlloc = fha_ram_alloc; -+ pCallback->RamFree = fha_ram_free; -+ pCallback->MemCmp = (FHA_MemCmp)memcmp; -+ pCallback->MemSet = (FHA_MemSet)memset; -+ pCallback->MemCpy = (FHA_MemCpy)memcpy; -+ pCallback->Printf = (FHA_Printf)fha_print; -+ -+ /* Yea, PagePerBlock=16 in producer_all, -+ * when SPI flash didn`t suport 4k sector erase, -+ * all will dead, Why can be forbear of this big BUG ? */ -+ spi_info.BinPageStart = 64; -+ spi_info.PageSize = 256; -+ spi_info.PagesPerBlock = ak_mtd_info->erasesize / 256; -+ -+ ret = FHA_mount(pInit_info, pCallback, &spi_info); -+ if (ret == FHA_FAIL) { -+ printk("FHA_mount failed\n"); -+ ret = -EINVAL; -+ } else { -+ ret = 0; -+ } -+ -+ kfree(pCallback); -+err_out: -+ kfree(pInit_info); -+ return ret; -+} -+ -+int ak_fha_init_for_update(int n) -+{ -+ int ret = 0; -+ T_PFHA_INIT_INFO pInit_info = NULL; -+ T_PFHA_LIB_CALLBACK pCallback = NULL; -+ T_SPI_BURN_INIT_INFO spi_info; -+ -+ pInit_info = kmalloc(sizeof(T_FHA_INIT_INFO), GFP_KERNEL); -+ if (!pInit_info) { -+ printk("allocate memory for pInit_info failed\n"); -+ return -ENOMEM; -+ } -+ -+ pInit_info->nChipCnt = 0; -+ pInit_info->nBlockStep = 1; -+ pInit_info->eAKChip = FHA_CHIP_SET_TYPE; -+ pInit_info->ePlatform = PLAT_LINUX; -+ pInit_info->eMedium = MEDIUM_SPIFLASH; -+ pInit_info->eMode = MODE_NEWBURN; -+ -+ pCallback = kmalloc(sizeof(T_FHA_LIB_CALLBACK), GFP_KERNEL); -+ if (!pCallback) { -+ printk("allocate memory for pCallback failed\n"); -+ ret = -ENOMEM; -+ goto err_out; -+ } -+ -+ pCallback->Erase = ak_fha_erase_callback; -+ pCallback->Write = (FHA_Write)ak_fha_write_callback; -+ pCallback->Read = (FHA_Read)ak_fha_read_callback; -+ pCallback->RamAlloc = fha_ram_alloc; -+ pCallback->RamFree = fha_ram_free; -+ pCallback->MemCmp = (FHA_MemCmp)memcmp; -+ pCallback->MemSet = (FHA_MemSet)memset; -+ pCallback->MemCpy = (FHA_MemCpy)memcpy; -+ pCallback->Printf = (FHA_Printf)fha_print; -+ -+ /* Yea, PagePerBlock=16 in producer_all, -+ * when SPI flash didn`t suport 4k sector erase, -+ * all will dead, Why can be forbear of this big BUG ? */ -+ spi_info.BinPageStart = 64; -+ spi_info.PageSize = 256; -+ spi_info.PagesPerBlock = ak_mtd_info->erasesize / 256; -+ -+ ret = FHA_burn_init(pInit_info, pCallback, &spi_info); -+ if (ret == FHA_FAIL) { -+ printk("FHA_mount failed\n"); -+ ret = -EINVAL; -+ } else { -+ ret = 0; -+ } -+ -+ kfree(pCallback); -+err_out: -+ kfree(pInit_info); -+ return ret; -+} -+ -+static int ak_mount_partitions(struct spi_device *spi) -+{ -+ int i, ret; -+ unsigned long nr_parts; -+ unsigned char *buf; -+ struct partitions *parts = NULL; -+ struct mtd_partition *mtd_part; -+ struct mtd_part_parser_data ppdata; -+ -+ ret = ak_fha_init(); -+ if (ret) { -+ printk("Init FHA lib failed\n"); -+ goto err_out; -+ } -+ -+ buf = kzalloc(FLASH_PAGESIZE, GFP_KERNEL); -+ if (!buf) { -+ printk("allocate memory for page buffer failed\n"); -+ ret = -ENOMEM; -+ goto err_out; -+ } -+ -+ ret = FHA_get_fs_part(buf, FLASH_PAGESIZE); -+ if (ret == FHA_FAIL) { -+ printk("get partition info failed\n"); -+ ret = !ret; -+ goto no_parts; -+ } -+ -+ nr_parts = *(unsigned long *)buf; -+ /* if no partiton to mount, the buf will be all 0xFF but not constant. -+ * So, it is not safe here. */ -+ printk("nr_parts=0x%lx\n", nr_parts); -+ if (nr_parts <= 0 || nr_parts > 5) { -+ printk("partition count invalid\n"); -+ ret = -EINVAL; -+ goto no_parts; -+ } -+ -+ mtd_part = kzalloc(sizeof(struct mtd_partition) * nr_parts, GFP_KERNEL); -+ if (!mtd_part) { -+ printk("allocate memory for mtd_partition failed\n"); -+ ret = -ENOMEM; -+ goto no_parts; -+ } -+ -+ parts = (struct partitions *)(&buf[sizeof(unsigned long)]); -+ for (i = 0; i < nr_parts; i++) { -+ mtd_part[i].name = kzalloc(MTD_PART_NAME_LEN, GFP_KERNEL); -+ memcpy(mtd_part[i].name, parts[i].name, MTD_PART_NAME_LEN); -+ mtd_part[i].size = parts[i].size; -+ mtd_part[i].offset = parts[i].offset; -+ mtd_part[i].mask_flags = parts[i].mask_flags; -+ printk("mtd_part[%d]:\nname = %s\nsize = 0x%llx\noffset = 0x%llx\nmask_flags = 0x%x\n\n", -+ i, mtd_part[i].name, mtd_part[i].size, mtd_part[i].offset, mtd_part[i].mask_flags); -+ } -+ ppdata.of_node = spi->dev.of_node; -+ -+ ret = mtd_device_parse_register(ak_mtd_info, NULL, &ppdata, -+ (const struct mtd_partition *)mtd_part, nr_parts); -+ if (ret) { -+ printk("add mtd partition failed\n"); -+ goto no_parts; -+ } -+ -+no_parts: -+ kfree(buf); -+err_out: -+ return ret; -+} -+ -+/** -+* @brief jedec probe -+* -+* Read the device ID and identify that it was supported or not. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd spi device handle. -+* @return int return the device info. -+*/ -+static struct flash_info *__devinit jedec_probe(struct spi_device *spi) -+{ -+ int tmp; -+ u8 code = OPCODE_RDID; -+ u8 id[5]; -+ u32 jedec; -+ u16 ext_jedec = 0; -+ struct flash_info *info; -+ -+ /* JEDEC also defines an optional "extended device information" -+ * string for after vendor-specific data, after the three bytes -+ * we use here. Supporting some chips might require using it. -+ */ -+ tmp = spi_write_then_read(spi, &code, 1, id, 3); -+ if (tmp < 0) { -+ DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", -+ dev_name(&spi->dev), tmp); -+ return NULL; -+ } -+ jedec = id[0]; -+ jedec = jedec << 8; -+ jedec |= id[1]; -+ jedec = jedec << 8; -+ jedec |= id[2]; -+ -+ printk("akspi flash ID: 0x%08x\n", jedec); -+ -+ //ext_jedec = id[3] << 8 | id[4]; -+ for (tmp = 0, info = ak_spiflash_supportlist; -+ tmp < ARRAY_SIZE(ak_spiflash_supportlist); -+ tmp++, info++) { -+ if (info->jedec_id == jedec) { -+ if (info->ext_id != 0 && info->ext_id != ext_jedec) -+ continue; -+ return info; -+ } -+ } -+ dev_err(&spi->dev, "jedec_probe() unrecognized JEDEC id %06x\n", jedec); -+ return NULL; -+} -+ -+static int ak_spiflash_init_stat_reg(struct ak_spiflash *flash) -+{ -+ int i; -+ struct flash_status_reg *sr; -+ struct flash_info *info = &flash->info; -+ -+ for(i=0, sr=status_reg_list; i<ARRAY_SIZE(status_reg_list); i++, sr++) { -+ if (sr->jedec_id == info->jedec_id) { -+ if (info->ext_id != 0 && info->ext_id != sr->ext_id) -+ continue; -+ flash->stat_reg = *sr; -+ return 0; -+ } -+ } -+ -+ flash->stat_reg = status_reg_list[i-1]; -+ return 0; -+} -+ -+ -+ -+/** -+* @brief spi flash probe -+* -+* Initial the spi flash device driver to kernel. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd spi device handle. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int __devinit ak_spiflash_probe(struct spi_device *spi) -+{ -+ struct flash_platform_data *data; -+ struct ak_spiflash *flash; -+ struct flash_info *info; -+ unsigned i, ret = 0; -+ -+ printk("ak spiflash probe enter.\n"); -+ /* Platform data helps sort out which chip type we have, as -+ * well as how this board partitions it. If we don't have -+ * a chip ID, try the JEDEC id commands; they'll work for most -+ * newer chips, even if we don't recognize the particular chip. -+ */ -+ data = spi->dev.platform_data; -+ if (data && data->type) { -+ for (i = 0, info = ak_spiflash_supportlist; -+ i < ARRAY_SIZE(ak_spiflash_supportlist); -+ i++, info++) { -+ if (strcmp(data->type, info->name) == 0) -+ break; -+ } -+ -+ /* unrecognized chip? */ -+ if (i == ARRAY_SIZE(ak_spiflash_supportlist)) { -+ DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n", -+ dev_name(&spi->dev), data->type); -+ info = NULL; -+ -+ /* recognized; is that chip really what's there? */ -+ } else if (info->jedec_id) { -+ struct flash_info *chip = jedec_probe(spi); -+ -+ if (!chip || chip != info) { -+ dev_warn(&spi->dev, "found %s, expected %s\n", -+ chip ? chip->name : "UNKNOWN", -+ info->name); -+ info = NULL; -+ } -+ } -+ } else -+ info = jedec_probe(spi); -+ -+ if (!info) -+ return -ENODEV; -+ -+ flash = kzalloc(sizeof *flash, GFP_KERNEL); -+ if (!flash) -+ return -ENOMEM; -+ -+#ifdef SPIFLASH_USE_MTD_BLOCK_LAYER -+ /*pre-allocation buffer use for spi flash data transfer.*/ -+ flash->buf = kzalloc(FLASH_BUF_SIZE, GFP_KERNEL); -+ if (!flash->buf) { -+ printk("Allocate buf for spi page failed\n"); -+ kfree(flash); -+ return -ENOMEM; -+ } -+#endif -+ -+ ak_mtd_info = &flash->mtd; -+ -+ flash->spi = spi; -+ flash->info = *info; -+ mutex_init(&flash->lock); -+ dev_set_drvdata(&spi->dev, flash); -+ -+ flash->bus_width = data->bus_width; -+ -+ /* -+ * Atmel serial flash tend to power up -+ * with the software protection bits set -+ */ -+ -+ if (info->jedec_id >> 16 == 0x1f) { -+ write_enable(flash); -+ write_sr(flash, 0); -+ } -+ -+ if (data && data->name) -+ flash->mtd.name = data->name; -+ else -+ flash->mtd.name = dev_name(&spi->dev); -+ -+ flash->mtd.type = MTD_NORFLASH; -+ flash->mtd.writesize = FLASH_PAGESIZE; -+ flash->mtd.flags = MTD_WRITEABLE; -+ flash->mtd.size = info->sector_size * info->n_sectors; -+ flash->mtd._erase = ak_spiflash_erase; -+ flash->mtd._read = ak_spiflash_read; -+ flash->mtd.get_device_id = ak_spiflash_get_devid; -+ printk("%s, info->sector_size = %d, info->n_sectors = %d\n", info->name, info->sector_size, info->n_sectors); -+ //printk("flash->mtd.size = %x, %ld\n", flash->mtd.size, flash->mtd.size); -+ -+ /* sst flash chips use AAI word program */ -+ if (info->jedec_id >> 16 == 0xbf) -+ flash->mtd._write = sst_write; -+ else -+ flash->mtd._write = ak_spiflash_write; -+ -+ /* prefer "small sector" erase if possible */ -+ if (info->flags & SFLAG_SECT_4K) { -+ flash->erase_opcode = OPCODE_BE_4K; -+ flash->mtd.erasesize = 4096; -+ } else { -+ flash->erase_opcode = OPCODE_SE; -+ flash->mtd.erasesize = info->sector_size; -+ } -+ -+ ak_spiflash_init_stat_reg(flash); -+ ak_spiflash_cfg_quad_mode(flash); -+ init_spiflash_rw_info(flash); -+ -+ flash->mtd.dev.parent = &spi->dev; -+ -+ dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name, -+ (long long)flash->mtd.size >> 10); -+ -+ DEBUG(MTD_DEBUG_LEVEL0, -+ "mtd .name = %s, .size = 0x%llx (%lldMiB) " -+ ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", -+ flash->mtd.name, -+ (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), -+ flash->mtd.erasesize, flash->mtd.erasesize / 1024, -+ flash->mtd.numeraseregions); -+ -+ if (flash->mtd.numeraseregions) -+ for (i = 0; i < flash->mtd.numeraseregions; i++) -+ DEBUG(MTD_DEBUG_LEVEL0, -+ "mtd.eraseregions[%d] = { .offset = 0x%llx, " -+ ".erasesize = 0x%.8x (%uKiB), " -+ ".numblocks = %d }\n", -+ i, (long long)flash->mtd.eraseregions[i].offset, -+ flash->mtd.eraseregions[i].erasesize, -+ flash->mtd.eraseregions[i].erasesize / 1024, -+ flash->mtd.eraseregions[i].numblocks); -+ -+ -+ /* partitions should match sector boundaries; and it may be good to -+ * use readonly partitions for writeprotected sectors (BP2..BP0). -+ */ -+ ret = mtd_device_parse_register(ak_mtd_info, NULL, NULL, NULL, 0); -+ if (ret) { -+ printk("Add root MTD device failed\n"); -+ kfree(flash->buf); -+ kfree(flash); -+ return -EINVAL; -+ } -+ ret = ak_mount_partitions(spi); -+ if (ret) -+ printk("Add MTD partitions failed\n"); -+ -+ printk("Init AK SPI Flash finish.\n"); -+ -+ return 0; -+} -+ -+/** -+* @brief spi flash remove -+* -+* Remove the spi flash device driver from kernel. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd spi device handle. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int __devexit ak_spiflash_remove(struct spi_device *spi) -+{ -+ struct ak_spiflash *flash = dev_get_drvdata(&spi->dev); -+ int status; -+ -+ status = mtd_device_unregister(&flash->mtd); -+ -+ if (status == 0) { -+ kfree(flash->buf); -+ kfree(flash); -+ } -+ return 0; -+} -+ -+ -+static struct spi_driver ak_spiflash_driver = { -+ .driver = { -+ .name = "ak-spiflash", -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ .probe = ak_spiflash_probe, -+ .remove = __devexit_p(ak_spiflash_remove), -+ -+ /* REVISIT: many of these chips have deep power-down modes, which -+ * should clearly be entered on suspend() to minimize power use. -+ * And also when they're otherwise idle... -+ */ -+}; -+ -+/** -+* @brief spi flash device init -+* -+* Moudle initial. -+* @author SheShaohua -+* @date 2012-03-20 -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int __init ak_spiflash_init(void) -+{ -+ printk("Start to init Anyka SPI Flash...\n"); -+ return spi_register_driver(&ak_spiflash_driver); -+} -+ -+ -+/** -+* @brief spi flash device exit -+* -+* Moudle exit. -+* @author SheShaohua -+* @date 2012-03-20 -+* @return None -+*/ -+static void __exit ak_spiflash_exit(void) -+{ -+ spi_unregister_driver(&ak_spiflash_driver); -+} -+ -+ -+module_init(ak_spiflash_init); -+module_exit(ak_spiflash_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("She Shaohua"); -+MODULE_DESCRIPTION("MTD SPI driver for Anyka spiflash chips"); -diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c -index f2f482be..4efca411 100644 ---- a/drivers/mtd/mtdchar.c -+++ b/drivers/mtd/mtdchar.c -@@ -35,11 +35,50 @@ - #include <linux/mtd/mtd.h> - #include <linux/mtd/partitions.h> - #include <linux/mtd/map.h> -- -+#include <plat-anyka/anyka_types.h> - #include <asm/uaccess.h> - - static DEFINE_MUTEX(mtd_mutex); - -+/* Add ioctl data structure for spi flash burn tool. -+*/ -+#define FLASH_PAGESIZE 256 -+#define FLASH_ERASESIZE 4096 -+ -+#define AK_SPIFLASH_PHY_ERASE 0x80 -+#define AK_SPIFLASH_PHY_READ 0x81 -+#define AK_SPIFLASH_PHY_WRITE 0x82 -+#define AK_SPIFLASH_GET_CHIP_ID 0x83 -+#define AK_SPIFLASH_READ_BYTES 0x84 -+ -+#define LEFT_ALIGN(a,b) ((a/b)*b) -+#define RIGHT_ALIGN(a, b) (((a+b-1)/b)*b) -+ -+struct rw_para -+{ -+ T_U32 chip_num; -+ T_U32 page_num; -+ T_U8 *data; -+ T_U32 data_len; -+ T_U8 *oob; //not used in spi flash, only reserve for nand. -+ T_U32 oob_len; //not used in spi flash, only reserve for nand. -+ T_U32 eDataType; -+}; -+ -+/* erase block info */ -+struct erase_para -+{ -+ T_U32 chip_num; //which chip the block is in -+ T_U32 startpage; // the block's first page number -+}; -+ -+struct get_id_para -+{ -+ T_U32 chip_num; -+ T_U32 *spiflash_id; -+}; -+ -+ - /* - * Data structure to hold the pointer to the mtd device as well - * as mode information of various use cases. -@@ -620,6 +659,236 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd, - return ret; - } - -+ -+/** -+* @brief MTD char earse -+* -+* Erase a sector specified by input paramerter. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd mtd info handle. -+* @param[in] arg erase info. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int erase_SPIFlash_page(struct mtd_info *mtd, unsigned long arg) -+{ -+ struct erase_info instr_info; -+ struct erase_para e_para; -+ unsigned long len; -+ int ret; -+ -+ ret = copy_from_user(&e_para, (struct erase_para *)arg, sizeof(struct erase_para)); -+ if(ret) -+ return -EFAULT; -+ //printk("Erase sector: %ld \n", e_para.startpage/16); -+ -+ memset(&instr_info, 0, sizeof(struct erase_info)); -+ instr_info.addr = e_para.startpage * FLASH_PAGESIZE; -+ instr_info.len = len = FLASH_ERASESIZE; -+ instr_info.mtd = mtd; -+ -+ //printk("Addr: %lld, len: %lld, start to erase...\n", instr_info.addr, instr_info.len); -+ -+ mtd_erase(mtd, &instr_info); -+ -+ return 0; -+} -+ -+ -+static int read_spiflash_bytes(struct mtd_info *mtd, unsigned long arg) -+{ -+ struct rw_para r_para; -+ unsigned long baseaddr, len, retlen; -+ unsigned char *buf; -+ int ret; -+ -+ ret = copy_from_user(&r_para, (struct rw_para *)arg, sizeof(struct rw_para)); -+ if(ret) -+ return -EFAULT; -+ -+ baseaddr = r_para.page_num; -+ len = r_para.data_len; -+ buf = (unsigned char *)kmalloc(len, GFP_KERNEL); -+ if( buf == NULL ) -+ { -+ printk(KERN_ERR "%s, kmalloc buf fail!\n", __func__); -+ return -1; -+ } -+ -+ mtd_read(mtd, baseaddr, len, (size_t*)&retlen, buf); -+ -+ ret = copy_to_user(((struct rw_para *)arg)->data, buf, retlen); -+ if(ret) { -+ ret = -EFAULT; -+ goto rd_fail; -+ } -+ -+rd_fail: -+ kfree(buf); -+ -+ return 0; -+} -+ -+ -+/** -+* @brief MTD char read -+* -+* Read data from spi flash. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd mtd info handle. -+* @param[in] arg read address and length info. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int read_SPIFlash_page(struct mtd_info *mtd, unsigned long arg) -+{ -+ struct rw_para r_para; -+ unsigned long baseaddr, addr, len, retlen, pageCount; -+ unsigned char *buf; -+ int ret; -+ -+ ret = copy_from_user(&r_para, (struct rw_para *)arg, sizeof(struct rw_para)); -+ if(ret) -+ return -EFAULT; -+ -+ //printk("Read page: %ld, len: %ld\n", r_para.page_num, r_para.data_len); -+ -+ baseaddr = r_para.page_num * FLASH_PAGESIZE; -+ pageCount = r_para.data_len; -+ len = r_para.data_len * FLASH_PAGESIZE; -+ buf = (unsigned char *)kmalloc(len, GFP_KERNEL); -+ if( buf == NULL ) -+ { -+ printk(KERN_ERR "%s, kmalloc buf fail!\n", __func__); -+ return -1; -+ } -+ -+ addr = baseaddr; -+ mtd_read(mtd, addr, len, (size_t*)&retlen, buf); -+ -+ ret = copy_to_user(((struct rw_para *)arg)->data, buf, retlen); -+ if(ret) { -+ ret = -EFAULT; -+ goto rd_fail; -+ } -+ -+rd_fail: -+ kfree(buf); -+ -+ return 0; -+} -+ -+ -+/** -+* @brief MTD char write -+* -+* write data to spi flash. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd mtd info handle. -+* @param[in] arg write related info. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int write_SPIFlash_page(struct mtd_info *mtd, unsigned long arg) -+{ -+ struct rw_para w_para; -+ unsigned long baseAddr, addr, total_len, len, remainCount, retlen, pageCount; -+ unsigned char *buff, *pbuf; -+ u32 i; -+ int ret; -+ -+ ret = copy_from_user(&w_para, (struct rw_para *)arg, sizeof(struct rw_para)); -+ if(ret) -+ return -EFAULT; -+ -+// printk("Write page: %ld ~ %ld\n", w_para.page_num, (w_para.page_num + w_para.data_len - 1) ); -+ -+ baseAddr = w_para.page_num * FLASH_PAGESIZE; -+ pageCount = w_para.data_len; -+ total_len = w_para.data_len * FLASH_PAGESIZE; -+ buff = (unsigned char *)kmalloc(total_len, GFP_KERNEL); -+ if( buff == NULL ) -+ { -+ printk(KERN_ERR "%s, kmalloc buf fail!\n", __func__); -+ return -1; -+ } -+ -+ ret = copy_from_user(buff, w_para.data, total_len); -+ if(ret) { -+ ret = -EFAULT; -+ goto wr_fail; -+ } -+ -+ -+ remainCount = total_len; -+ addr = baseAddr; -+ pbuf = buff; -+ for(i=0; i<pageCount; i++) -+ { -+ if( remainCount > FLASH_PAGESIZE ) -+ { -+ len = FLASH_PAGESIZE; -+ } -+ else -+ { -+ len = remainCount; -+ } -+ -+ addr = baseAddr + (i * FLASH_PAGESIZE); -+ pbuf = buff + (i * FLASH_PAGESIZE); -+ mtd_write(mtd, addr, len, (size_t*)&retlen, pbuf); -+ remainCount -= FLASH_PAGESIZE; -+ } -+ -+wr_fail: -+ kfree(buff); -+ -+ return 0; -+} -+ -+ -+/** -+* @brief Get Device ID -+* -+* Get Device ID of spi flash. -+* @author SheShaohua -+* @date 2012-03-20 -+* @param[in] mtd mtd info handle. -+* @param[out] arg return device ID. -+* @return int return write success or failed -+* @retval returns zero on success -+* @retval return a non-zero error code if failed -+*/ -+static int get_SPIFlash_ID(struct mtd_info *mtd, unsigned long arg) -+{ -+ int ret; -+ u32 spi_id = 0; -+ -+ if(mtd->get_device_id) -+ { -+ spi_id = mtd->get_device_id(mtd); -+ if( spi_id == AK_FALSE) -+ { -+ printk(KERN_ERR "%s, get_device_id fail!\n", __func__); -+ return -1; -+ } -+ } -+ -+ ret = copy_to_user(((struct get_id_para *)arg)->spiflash_id, &spi_id, sizeof(u32)); -+ if(ret) -+ return -EFAULT; -+ -+ printk("get_SPIFlash_ID: 0x%08x\n", spi_id); -+ return 0; -+} -+ -+ - static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) - { - struct mtd_file_info *mfi = file->private_data; -@@ -641,7 +910,51 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) - return -EFAULT; - } - -- switch (cmd) { -+ switch (cmd) { -+ case AK_SPIFLASH_PHY_READ: -+ ret = read_SPIFlash_page( mtd, arg ); -+ if( ret != 0 ) -+ { -+ printk(KERN_ERR "AK_SPIFLASH_PHY_READ failed:ret=%d\n", ret); -+ return -EFAULT; -+ } -+ break; -+ -+ case AK_SPIFLASH_PHY_WRITE: -+ ret = write_SPIFlash_page( mtd, arg ); -+ if( ret != 0 ) -+ { -+ printk(KERN_ERR "AK_SPIFLASH_PHY_WRITE failed:ret=%d\n", ret); -+ return -EFAULT; -+ } -+ break; -+ -+ case AK_SPIFLASH_PHY_ERASE: -+ ret = erase_SPIFlash_page( mtd, arg ); -+ if( ret != 0 ) -+ { -+ printk(KERN_ERR "AK_SPIFLASH_PHY_ERASE failed:ret=%d\n", ret); -+ return -EFAULT; -+ } -+ break; -+ -+ case AK_SPIFLASH_GET_CHIP_ID: -+ ret = get_SPIFlash_ID( mtd, arg ); -+ if( ret != 0 ) -+ { -+ printk(KERN_ERR "AK_SPIFLASH_GET_CHIP_ID failed:ret=%d\n", ret); -+ return -EFAULT; -+ } -+ break; -+ case AK_SPIFLASH_READ_BYTES: -+ ret = read_spiflash_bytes(mtd, arg); -+ if( ret != 0 ) -+ { -+ printk(KERN_ERR "AK_SPIFLASH_READ_BYTES failed:ret=%d\n", ret); -+ return -EFAULT; -+ } -+ break; -+ - case MEMGETREGIONCOUNT: - if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) - return -EFAULT; -diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig -index 7d17ceca..884f99ca 100644 ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -1,3 +1,10 @@ -+config MTD_NAND_IDS -+ tristate "Include chip ids for known NAND devices." -+ depends on MTD -+ help -+ Useful for NAND drivers that do not use the NAND subsystem but -+ still like to take advantage of the known chip information. -+ - config MTD_NAND_ECC - tristate - -@@ -115,9 +122,6 @@ config MTD_NAND_OMAP2 - Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 - platforms. - --config MTD_NAND_IDS -- tristate -- - config MTD_NAND_RICOH - tristate "Ricoh xD card reader" - default n -diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig -index c63a64cb..a8d24dde 100644 ---- a/drivers/net/ethernet/Kconfig -+++ b/drivers/net/ethernet/Kconfig -@@ -176,5 +176,5 @@ source "drivers/net/ethernet/tundra/Kconfig" - source "drivers/net/ethernet/via/Kconfig" - source "drivers/net/ethernet/xilinx/Kconfig" - source "drivers/net/ethernet/xircom/Kconfig" -- -+source "drivers/net/ethernet/ak-ethernet/Kconfig" - endif # ETHERNET -diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile -index 9676a510..2c46e882 100644 ---- a/drivers/net/ethernet/Makefile -+++ b/drivers/net/ethernet/Makefile -@@ -75,3 +75,4 @@ obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundra/ - obj-$(CONFIG_NET_VENDOR_VIA) += via/ - obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ - obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ -+obj-$(CONFIG_AK_ETHERNET) += ak-ethernet/ -diff --git a/drivers/net/ethernet/ak-ethernet/Ethernethw.h b/drivers/net/ethernet/ak-ethernet/Ethernethw.h -new file mode 100755 -index 00000000..2fa00197 ---- /dev/null -+++ b/drivers/net/ethernet/ak-ethernet/Ethernethw.h -@@ -0,0 +1,731 @@ -+#ifndef _MAC_REG_DEFINE_H_ -+#define _MAC_REG_DEFINE_H_ -+#define MAC_REG_BASE 0x60000000 -+ -+#define REG_MASTER_CTRL ( 0x1400) /* WORD reg */ -+ #define MASTER_CTRL_MAC_SOFT_RST_OFF 0 /* hw sc */ -+ #define MASTER_CTRL_MAC_SOFT_RST_BITS 1 -+ #define MASTER_CTRL_PCIE_SOFT_RST_OFF 1 /* hw sc */ -+ #define MASTER_CTRL_PCIE_SOFT_RST_BITS 1 -+ #define MASTER_CTRL_PCIE_TEST_MOD_OFF 2 -+ #define MASTER_CTRL_PCIE_TEST_MOD_BITS 2 -+ #define MASTER_CTRL_BERT_START_OFF 4 -+ #define MASTER_CTRL_BERT_START_BITS 1 -+ #define MASTER_CTRL_OOB_DIS_OFF 6 -+ #define MASTER_CTRL_OOB_DIS_BITS 1 -+ #define MASTER_CTRL_SA_TIMER_EN_OFF 7 -+ #define MASTER_CTRL_SA_TIMER_EN_BITS 1 -+ #define MASTER_CTRL_MANUAL_TIME_EN_OFF 8 -+ #define MASTER_CTRL_MANUAL_TIMER_EN_BITS 1 -+ #define MASTER_CTRL_MANUAL_INT_OFF 9 -+ #define MASTER_CTRL_MANUAL_INT_BITS 1 -+ #define MASTER_CTRL_IRQ_MODRT_EN_OFF 10 /* tx if 2 timer */ -+ #define MASTER_CTRL_IRQ_MODRT_EN_BITS 1 -+ #define MASTER_CTRL_IRQ_MODRT_RXEN_OFF 11 /* rx if 2 timer */ -+ #define MASTER_CTRL_IRQ_MODRT_RXEN_BITS 1 -+ #define MASTER_CTRL_PCLK_SEL_DIS_OFF 12 /* ps may set it */ -+ #define MASTER_CTRL_PCLK_SEL_DIS_BITS 1 -+ #define MASTER_CTRL_CLKSW_MODE_OFF 13 -+ #define MASTER_CTRL_CLKSW_MODE_BITS 1 -+ #define MASTER_CTRL_INT_RCLR_EN_OFF 14 -+ #define MASTER_CTRL_INT_CLCR_EN_BITS 1 -+ #define MASTER_CTRL_OTP_SEL_OFF 31 -+ #define MASTER_CTRL_OTP_SEL_BITS 1 -+ -+#define REG_DEV_REV_NUM (0x1402) /* BYTE reg */ -+#define REG_DEV_ID_NUM (0x1403) /* BYTE reg */ -+ -+#define REG_MANUAL_TIMER_INIT (0x1404) /* DWORD reg */ -+ -+#define REG_IRQ_MODRT_INIT (0x1408) /* WORD reg */ -+#define REG_IRQ_MODRT_RX_INIT (0x140A) /* WORD reg */ -+ -+#define REG_PHY_CTRL (0x140C) /* DWORD reg */ -+ #define PHY_CTRL_EXIT_RST_OFF 0 -+ #define PHY_CTRL_EXIT_RST_BITS 1 -+ #define PHY_CTRL_RTL_MOD_OFF 1 -+ #define PHY_CTRL_RTL_MOD_BITS 1 -+ #define PHY_CTRL_LED_MOD_OFF 2 -+ #define PHY_CTRL_LED_MOD_BITS 1 -+ #define PHY_CTRL_ANEG_NOW_OFF 3 -+ #define PHY_CTRL_ANEG_NOW_BITS 1 -+ #define PHY_CTRL_REV_ANEG_OFF 4 -+ #define PHY_CTRL_REV_ANEG_BITS 1 -+ #define PHY_CTRL_GATE25M_EN_OFF 5 -+ #define PHY_CTRL_GATE25M_EN_BITS 1 -+ #define PHY_CTRL_LPW_EXIT_OFF 6 -+ #define PHY_CTRL_LPW_EXIT_BITS 1 -+ #define PHY_CTRL_PHY_IDDQ_OFF 7 -+ #define PHY_CTRL_PHY_IDDQ_BITS 1 -+ #define PHY_CTRL_PHY_IDDQ_DIS_OFF 8 -+ #define PHY_CTRL_PHY_IDDQ_DIS_BITS 1 -+ #define PHY_CTRL_GIGA_DIS_OFF 9 -+ #define PHY_CTRL_GIGA_DIS_BITS 1 -+ #define PHY_CTRL_HIB_EN_HW_OFF 10 -+ #define PHY_CTRL_HIB_EN_HW_BITS 1 -+ #define PHY_CTRL_HIB_PULSE_HW_OFF 11 -+ #define PHY_CTRL_HIB_PULSE_HW_BITS 1 -+ #define PHY_CTRL_SEL_ANA_RST_OFF 12 -+ #define PHY_CTRL_SEL_ANA_RST_BITS 1 -+ #define PHY_CTRL_PHY_PLL_ON_OFF 13 -+ #define PHY_CTRL_PHY_PLL_ON_BITS 1 -+ #define PHY_CTRL_POWERDOWN_HW_OFF 14 -+ #define PHY_CTRL_POWERDOWN_HW_BITS 1 -+ #define PHY_CTRL_PHY_PLL_BYPASS_OFF 15 -+ #define PHY_CTRL_PHY_PLL_BYPASS_BITS 1 -+ -+#ifdef EN_HIB -+ #define PHY_CTRL_DEFAULT (\ -+ FLAG(PHY_CTRL_SEL_ANA_RST_OFF) |\ -+ FLAG(PHY_CTRL_HIB_EN_HW_OFF) |\ -+ FLAG(PHY_CTRL_HIB_PULSE_HW_OFF) ) -+#else -+ #define PHY_CTRL_DEFAULT (\ -+ FLAG(PHY_CTRL_SEL_ANA_RST_OFF) |\ -+ FLAG(PHY_CTRL_HIB_PULSE_HW_OFF) ) -+#endif/*EN_HIB*/ -+ -+ #define PHY_CTRL_POWER_SAVING (\ -+ FLAG(PHY_CTRL_SEL_ANA_RST_OFF) |\ -+ FLAG(PHY_CTRL_HIB_EN_HW_OFF) |\ -+ FLAG(PHY_CTRL_HIB_PULSE_HW_OFF) |\ -+ FLAG(PHY_CTRL_POWERDOWN_HW_OFF) |\ -+ FLAG(PHY_CTRL_PHY_IDDQ_OFF) ) -+ -+ -+#define REG_IDLE_STATUS (0x1410) /* BYTE reg */ -+ #define IDLE_STATUS_RXMAC_OFF 0 -+ #define IDLE_STATUS_RXMAC_BITS 1 -+ #define IDLE_STATUS_TXMAC_OFF 1 -+ #define IDLE_STATUS_TXMAC_BITS 1 -+ #define IDLE_STATUS_RXQ_OFF 2 -+ #define IDLE_STATUS_RXQ_BITS 1 -+ #define IDLE_STATUS_TXQ_OFF 3 -+ #define IDLE_STATUS_TXQ_BITS 1 -+ -+#define REG_MDIO_CTRL (0x1414) /* DWORD reg */ -+ #define MDIO_CTRL_DATA(val) (val&0xFFFF) -+ #define MDIO_CTRL_REG_ADDR(val) ((val&0x1f) << 16) -+ #define MDIO_CTRL_REG_ADDR_BITS 5 -+ #define MDIO_CTRL_WRITE (0<<21) -+ #define MDIO_CTRL_READ (1<<21)/*read:0, write:1*/ -+ #define MDIO_CTRL_RW_OFF 21 -+ #define MDIO_CTRL_RW_BITS 1 -+ #define MDIO_CTRL_SUP_PREAMBLE (1<<22) -+ #define MDIO_CTRL_SUP_PREAMBLE_BITS 1 -+ #define MDIO_CTRL_START (1<<23) -+ #define MDIO_CTRL_START_BITS 1 /* sc */ -+ #define MDIO_CTRL_CLK_SEL_OFF 24 -+ #define MDIO_CTRL_CLK_SEL_BITS 3 -+ #define MDIO_CTRL_BUSY_OFF 27 -+ #define MDIO_CTRL_BUSY_BITS 1 -+ #define MDIO_CTRL_AP_EN_OFF 28 -+ #define MDIO_CTRL_AP_EN_BITS 1 -+ #define MDIO_CLK_25_4 0 -+ #define MDIO_CLK_25_6 2 -+ #define MDIO_CLK_25_8 3 -+ #define MDIO_CLK_25_10 4 -+ #define MDIO_CLK_25_14 5 -+ #define MDIO_CLK_25_20 6 -+ #define MDIO_CLK_25_28 7 -+ #define MDIO_MAX_AC_TIMER 100 /* 1 ms */ -+ #define MDIO_CTRL_POST_READ_OFF 29 -+ #define MDIO_CTRL_POST_READ_BITS 1 -+ #define MDIO_CTRL_MODE_OFF 30 -+ #define MDIO_CTRL_MODE_BITS 1 -+ #define MDIO_CTRL_MODE_OLD 0 -+ #define MDIO_CTRL_MODE_EXTENSION 1 -+ -+ -+#define REG_PHY_STATUS (0x1418) /* DWORD reg */ -+ #define PHY_STATUS_PHY_STATUS_OFF 0 -+ #define PHY_STATUS_PHY_STATUS_BITS 16 -+ #define PHY_STATUS_OE_PWSTRP_OFF 16 -+ #define PHY_STATUS_OE_PWSTRP_BITS 11 -+ #define PHY_STATUS_LPW_STATUS_OFF 31 -+ #define PHY_STATUS_LPW_STATUS_BITS 1 -+ -+#define REG_BIST0_CTRL (0x141C) /* DWORD reg */ -+ #define BIST0_CTRL_NOW_OFF 0 -+ #define BIST0_CTRL_NOW_BITS 1 -+ #define BIST0_CTRL_SRAM_FAIL_OFF 1 -+ #define BIST0_CTRL_SRAM_FAIL_BITS 1 -+ #define BIST0_CTRL_FUSE_FLAG_OFF 2 -+ #define BIST0_CTRL_FUSE_FLAG_BITS 1 -+ #define BIST0_CTRL_FUSE_PAT_OFF 4 -+ #define BIST0_CTRL_FUSE_PAT_BITS 3 -+ #define BIST0_CTRL_FUSE_STEP_OFF 8 -+ #define BIST0_CTRL_FUSE_SETP_BITS 4 -+ #define BIST0_CTRL_FUSE_ROW_OFF 12 -+ #define BIST0_CTRL_FUSE_ROW_BITS 12 -+ #define BIST0_CTRL_FUSE_COL_OFF 24 -+ #define BIST0_CTRL_FUSE_COL_BITS 6 -+ -+#define REG_BIST1_CTRL (0x1420) /* DWORD reg */ -+ #define BIST1_CTRL_NOW_OFF 0 -+ #define BIST1_CTRL_NOW_BITS 1 -+ #define BIST1_CTRL_SRAM_FAIL_OFF 1 -+ #define BIST1_CTRL_SRAM_FAIL_BITS 1 -+ #define BIST1_CTRL_FUSE_FLAG_OFF 2 -+ #define BIST1_CTRL_FUSE_FLAG_BITS 1 -+ #define BIST1_CTRL_FUSE_PAT_OFF 4 -+ #define BIST1_CTRL_FUSE_PAT_BITS 3 -+ #define BIST1_CTRL_FUSE_STEP_OFF 8 -+ #define BIST1_CTRL_FUSE_SETP_BITS 4 -+ #define BIST1_CTRL_FUSE_ROW_OFF 12 -+ #define BIST1_CTRL_FUSE_ROW_BITS 7 -+ #define BIST1_CTRL_FUSE_COL_OFF 24 -+ #define BIST1_CTRL_FUSE_COL_BITS 5 -+ -+#define REG_SERDES_CTRL_STS (0x1424) -+#define SERDES_CTRL_STS_SELFB_PLL_SEL_OFF 14 -+#define SERDES_CTRL_STS_SELFB_PLL_SEL_BITS 2 -+#define SERDES_OVCLK_18_25 0 -+#define SERDES_OVCLK_12_18 1 -+#define SERDES_OVCLK_0_4 2 -+#define SERDES_OVCLK_4_12 3 -+#define SERDES_MAC_CLK_SLOWDOWN_OFF 17 -+#define SERDES_MAC_CLK_SLOWDOWN_BITS 1 -+#define SERDES_PHY_CLK_SLOWDOWN_OFF 18 -+#define SERDES_PHY_CLK_SLOWDOWN_BITS 1 -+ -+ -+#define REG_LED_CTRL (0x1428) /* DWORD reg */ -+ #define LED_CTRL_DC_CTRL_OFF 0 -+ #define LED_CTRL_DC_CTRL_BITS 2 -+ #define LED_CTRL_D3_MODE_CTRL_OFF 2 -+ #define LED_CTRL_D3_MODE_CTRL_BITS 2 -+ #define LED_CTRL_0_PAT_MAP_OFF 4 -+ #define LED_CTRL_0_PAT_MAP_BITS 2 -+ #define LED_CTRL_1_PAT_MAP_OFF 6 -+ #define LED_CTRL_1_PAT_MAP_BITS 2 -+ #define LED_CTRL_2_PAT_MAP_OFF 8 -+ #define LED_CTRL_2_PAT_MAP_BITS 2 -+ -+#define REG_LED_PAT0 (0x142C) /* WORD reg */ -+#define REG_LED_PAT1 (0x142E) /* WORD reg */ -+#define REG_LED_PAT2 (0x1430) /* WORD reg */ -+ -+#define REG_SYS_ALIVE (0x1434) -+ #define SYS_ALIVE_FLAG_OFF 0 -+ #define SYS_ALIVE_FLAG_BITS 1 -+ -+#define REG_LPI_TD (0x143C) -+ -+#define REG_LPI_CTRL (0x1440) -+ #define LPI_CTRL_EN_OFF 0 -+ #define LPI_CTRL_EN_BITS 1 -+ #define LPI_CTRL_CTRL_OFF 1 -+ #define LPI_CTRL_CTRL_BITS 1 -+ #define LPI_CTRL_GMII_OFF 2 -+ #define LPI_CTRL_GMII_BITS 1 -+ #define LPI_CTRL_CHK_STATE_OFF 3 -+ #define LPI_CTRL_CHK_STATE_BITS 1 -+ #define LPI_CTRL_CHK_RX_OFF 4 -+ #define LPI_CTRL_CHK_RX_BITS 1 -+ -+#define REG_LPI_TW (0x1444) -+ -+ -+#define REG_MDIO_EXT_CTRL (0x1448) -+ #define MDIO_EXT_CTRL_REG_ADDR_OFF 0 -+ #define MDIO_EXT_CTRL_REG_ADDR_BITS 16 -+ #define MDIO_EXT_CTRL_DEVADDR_OFF 16 -+ #define MDIO_EXT_CTRL_DEVADDR_BITS 5 -+ #define MDIO_EXT_CTRL_PTADDR_OFF 21 -+ #define MDIO_EXT_CTRL_PTADDR_BITS 5 -+ -+#define REG_MAC_CTRL (0x1480) /* DWORD reg */ -+ #define MAC_CTRL_TXEN_OFF 0 -+ #define MAC_CTRL_TXEN_BITS 1 -+ #define MAC_CTRL_RXEN_OFF 1 -+ #define MAC_CTRL_RXEN_BITS 1 -+ #define MAC_CTRL_TXFC_OFF 2 -+ #define MAC_CTRL_TXFC_BITS 1 -+ #define MAC_CTRL_RXFC_OFF 3 -+ #define MAC_CTRL_RXFC_BITS 1 -+ #define MAC_CTRL_LOOPBACK_OFF 4 -+ #define MAC_CTRL_LOOPBACK_BITS 1 -+ #define MAC_CTRL_FULLD_OFF 5 -+ #define MAC_CTRL_FULLD_BITS 1 -+ #define MAC_CTRL_CRCE_OFF 6 -+ #define MAC_CTRL_CRCE_BITS 1 -+ #define MAC_CTRL_PCRCE_OFF 7 -+ #define MAC_CTRL_PCRCE_BITS 1 -+ #define MAC_CTRL_FLCHK_OFF 8 -+ #define MAC_CTRL_FLCHK_BITS 1 -+ #define MAC_CTRL_HUGEN_OFF 9 -+ #define MAC_CTRL_HUGEN_BITS 1 -+ #define MAC_CTRL_PRLEN_OFF 10 -+ #define MAC_CTRL_PRLEN_BITS 4 -+ #define MAC_CTRL_PRLEN_DEF 7 -+ #define MAC_CTRL_VLAN_STRIP_OFF 14 -+ #define MAC_CTRL_VLAN_STRIP_BITS 1 -+ #define MAC_CTRL_PROM_MODE_OFF 15 -+ #define MAC_CTRL_PROM_MODE_BITS 1 -+ #define MAC_CTRL_TPAUSE_OFF 16 -+ #define MAC_CTRL_TPAUSE_BITS 1 -+ #define MAC_CTRL_SSTCT_OFF 17 -+ #define MAC_CTRL_SSTCT_BITS 1 -+ #define MAC_CTRL_SRTFN_OFF 18 -+ #define MAC_CTRL_SRTFN_BITS 1 -+ #define MAC_CTRL_SIMR_OFF 19 -+ #define MAC_CTRL_SIMR_BITS 1 -+ #define MAC_CTRL_SPEED_OFF 20 -+ #define MAC_CTRL_SPEED_BITS 2 -+ #define MAC_CTRL_SPEED_10_100 1 -+ #define MAC_CTRL_SPEED_1000 2 -+ #define MAC_CTRL_MBOF_OFF 22 -+ #define MAC_CTRL_MBOF_BITS 1 -+ #define MAC_CTRL_HUGE_OFF 23 -+ #define MAC_CTRL_HUGE_BITS 1 -+ #define MAC_CTRL_RX_XSUM_EN_OFF 24 -+ #define MAC_CTRL_RX_XSUM_EN_BITS 1 -+ #define MAC_CTRL_MUTI_ALL_OFF 25 -+ #define MAC_CTRL_MUTI_ALL_BITS 1 -+ #define MAC_CTRL_BROAD_EN_OFF 26 -+ #define MAC_CTRL_BROAD_EN_BITS 1 -+ #define MAC_CTRL_DEBUG_MODE_OFF 27 -+ #define MAC_CTRL_DEBUG_MODE_BITS 1 -+ #define MAC_CTRL_SINGLE_PAUSE_OFF 28 -+ #define MAC_CTRL_SINGLE_PAUSE_BITS 1 -+ #define MAC_CTRL_HASH_ALG_MODE_OFF 29 -+ #define MAC_CTRL_HASH_ALG_MODE_BITS 1 -+ #define MAC_CTRL_HASH_ALG_CRC32 1 -+ #define MAC_CTRL_HASH_ALG_CRC16 0 -+ #define MAC_CTRL_SPEED_MODE_OFF 30 -+ #define MAC_CTRL_SPEED_MODE_BITS 1 -+ #define MAC_CTRL_SPEED_MODE_PHY 0 -+ #define MAC_CTRL_SPEED_MODE_SW 1 -+ -+ -+#define REG_MAC_STA_ADDR (0x1488) /* QWORD reg */ -+/* [1488]=0x749dc320, [148c]=0x00000013, mac-addr:00-13-74-9d-c3-20 */ -+ -+#define REG_RX_HASH_TABLE (0x1490) /* QWORD reg */ -+ -+#define REG_MTU (0x149C) /* WORD reg */ -+ -+#define REG_WOL_CTRL (0x14A0) /* DWORD reg */ -+ #define WOL_CTRL_PATTERN_EN_OFF 0 -+ #define WOL_CTRL_PATTERN_EN_BITS 1 -+ #define WOL_CTRL_PATTERN_PME_EN_OFF 1 -+ #define WOL_CTRL_PATTERN_PME_EN_BITS 1 -+ #define WOL_CTRL_MAGIC_EN_OFF 2 -+ #define WOL_CTRL_MAGIC_EN_BITS 1 -+ #define WOL_CTRL_MAGIC_PME_EN_OFF 3 -+ #define WOL_CTRL_MAGIC_PME_EN_BITS 1 -+ #define WOL_CTRL_LINKCHG_EN_OFF 4 -+ #define WOL_CTRL_LINKCHG_EN_BITS 1 -+ #define WOL_CTRL_LINKCHG_PME_EN_OFF 5 -+ #define WOL_CTRL_LINKCHG_PME_EN_BITS 1 -+ #define WOL_CTRL_PATTERN_ST_OFF 8 -+ #define WOL_CTRL_PATTERN_ST_BITS 1 -+ #define WOL_CTRL_MAGIC_ST_OFF 9 -+ #define WOL_CTRL_MAGIC_ST_BITS 1 -+ #define WOL_CTRL_LINKCHG_ST_OFF 10 -+ #define WOL_CTRL_LINKCHG_ST_BITS 1 -+ #define WOL_CTRL_CLK_SWH_EN_OFF 15 -+ #define WOL_CTRL_CLK_SWH_EN_BITS 1 -+ #define WOL_CTRL_PT0_EN_OFF 16 -+ #define WOL_CTRL_PT0_EN_BITS 1 -+ #define WOL_CTRL_PT1_EN_OFF 17 -+ #define WOL_CTRL_PT1_EN_BITS 1 -+ #define WOL_CTRL_PT2_EN_OFF 18 -+ #define WOL_CTRL_PT2_EN_BITS 1 -+ #define WOL_CTRL_PT3_EN_OFF 19 -+ #define WOL_CTRL_PT3_EN_BITS 1 -+ #define WOL_CTRL_PT4_EN_OFF 20 -+ #define WOL_CTRL_PT4_EN_BITS 1 -+ #define WOL_CTRL_PT5_EN_OFF 21 -+ #define WOL_CTRL_PT5_EN_BITS 1 -+ #define WOL_CTRL_PT6_EN_OFF 22 -+ #define WOL_CTRL_PT6_EN_BITS 1 -+ #define WOL_CTRL_PT0_MATCH_OFF 24 -+ #define WOL_CTRL_PT0_MATCH_BITS 1 -+ #define WOL_CTRL_PT1_MATCH_OFF 25 -+ #define WOL_CTRL_PT1_MATCH_BITS 1 -+ #define WOL_CTRL_PT2_MATCH_OFF 26 -+ #define WOL_CTRL_PT2_MATCH_BITS 1 -+ #define WOL_CTRL_PT3_MATCH_OFF 27 -+ #define WOL_CTRL_PT3_MATCH_BITS 1 -+ #define WOL_CTRL_PT4_MATCH_OFF 28 -+ #define WOL_CTRL_PT4_MATCH_BITS 1 -+ #define WOL_CTRL_PT5_MATCH_OFF 29 -+ #define WOL_CTRL_PT5_MATCH_BITS 1 -+ #define WOL_CTRL_PT6_MATCH_OFF 30 -+ #define WOL_CTRL_PT6_MATCH_BITS 1 -+ -+#define REG_WOL_PT0_LEN (0x14A4) /* BYTE reg */ -+#define REG_WOL_PT1_LEN 0x14A5 /* BYTE reg */ -+#define REG_WOL_PT2_LEN 0x14A6 /* BYTE reg */ -+#define REG_WOL_PT3_LEN 0x14A7 /* BYTE reg */ -+#define REG_WOL_PT4_LEN 0x14A8 /* BYTE reg */ -+#define REG_WOL_PT5_LEN 0x14A9 /* BYTE reg */ -+#define REG_WOL_PT6_LEN 0x14AA /* BYTE reg */ -+ -+#define REG_SRAM_RFD0 (0x1500) /* DWORD reg */ -+ #define SRAM_RFD0_HDRADDR_OFF 0 -+ #define SRAM_RFD0_HDRADDR_BITS 12 -+ #define SRAM_RFD0_TALADDR_OFF 16 -+ #define SRAM_RFD0_TALADDR_BITS 12 -+ -+#define REG_SRAM_RFD1 (0x1504) /* DWORD reg */ -+ #define SRAM_RFD1_HDRADDR_OFF 0 -+ #define SRAM_RFD1_HDRADDR_BITS 12 -+ #define SRAM_RFD1_TALADDR_OFF 16 -+ #define SRAM_RFD1_TALADDR_BITS 12 -+ -+#define REG_SRAM_RFD2 (0x1508) /* DWORD reg */ -+ #define SRAM_RFD2_HDRADDR_OFF 0 -+ #define SRAM_RFD2_HDRADDR_BITS 12 -+ #define SRAM_RFD2_TALADDR_OFF 16 -+ #define SRAM_RFD2_TALADDR_BITS 12 -+ -+#define REG_SRAM_RFD3 (0x150C) /* DWORD reg */ -+ #define SRAM_RFD3_HDRADDR_OFF 0 -+ #define SRAM_RFD3_HDRADDR_BITS 12 -+ #define SRAM_RFD3_TALADDR_OFF 16 -+ #define SRAM_RFD3_TALADDR_BITS 12 -+ -+#define REG_SRAM_RFD_NICLEN (0x1510) /* DWORD reg */ -+ -+#define REG_SRAM_TRD 0x1518 /* DWORD reg */ -+ #define SRAM_TRD_HDRADDR_OFF 0 -+ #define SRAM_TRD_HDRADDR_BITS 12 -+ #define SRAM_TRD_TALADDR_OFF 16 -+ #define SRAM_TRD_TALADDR_BITS 12 -+ -+#define REG_SRAM_TRD_NICLEN (0x151C) /* DWORD reg */ -+ -+#define REG_SRAM_RXF (0x1520) /* DWORD reg */ -+ #define SRAM_RXF_HDRADDR_OFF 0 -+ #define SRAM_RXF_HDRADDR_BITS 12 -+ #define SRAM_RXF_TALADDR_OFF 16 -+ #define SRAM_RXF_TALADDR_BITS 12 -+ -+#define REG_SRAM_RXF_NICLEN (0x1524) /* DWORD reg */ -+ -+#define REG_SRAM_TXF (0x1528) /* DWORD reg */ -+ #define SRAM_TXF_HDRADDR_OFF 0 -+ #define SRAM_TXF_HDRADDR_BITS 12 -+ #define SRAM_TXF_TALADDR_OFF 16 -+ #define SRAM_TXF_TALADDR_BITS 12 -+ -+#define REG_SRAM_TXF_NICLEN (0x152C) /* DWORD reg */ -+ -+#define REG_SRAM_TCP_HDRADDR (0x1530) /* WORD reg */ -+ -+#define REG_SRAM_PAT_HDRADDR (0x1532) /* WORD reg */ -+ -+#define REG_SRAM_LOAD_PTR (0x1534) /* BYTE reg, sc */ -+ #define SRAM_LOAD_PTR_OFF 0 -+ #define SRAM_LOAD_PTR_BITS 1 -+ -+ -+#define REG_RX_BASE_ADDR_HI (0x1540) /* DWORD reg */ -+ -+#define REG_TX_BASE_ADDR_HI (0x1544) /* DWORD reg */ -+ -+#define REG_SMB_BASE_ADDR_HI (0x1548) /* DWORD reg */ -+#define REG_SMB_BASE_ADDR_LO (0x154C) /* DWORD reg */ -+ -+#define REG_RFD0_HDRADDR_LO (0x1550) /* DWORD reg */ -+#define REG_RFD1_HDRADDR_LO (0x1554) /* DWORD reg */ -+#define REG_RFD2_HDRADDR_LO (0x1558) /* DWORD reg */ -+#define REG_RFD3_HDRADDR_LO (0x155C) /* DWORD reg */ -+#define REG_RFD_RING_SIZE (0x1560) /* DWORD reg */ -+#define REG_RFD_BUFFER_SIZE (0x1564) /* DWORD reg */ -+ -+#define REG_RRD0_HDRADDR_LO (0x1568) /* DWORD reg */ -+#define REG_RRD1_HDRADDR_LO (0x156C) /* DWORD reg */ -+#define REG_RRD2_HDRADDR_LO (0x1570) /* DWORD reg */ -+#define REG_RRD3_HDRADDR_LO (0x1574) /* DWORD reg */ -+#define REG_RRD_RING_SIZE (0x1578) /* DWORD reg */ -+ -+#define REG_HTPD_HDRADDR_LO (0x157C) /* DWORD reg */ -+#define REG_NTPD_HDRADDR_LO (0x1580) /* DWORD reg */ -+#define REG_TPD_RING_SIZE (0x1584) /* DWORD reg */ -+ -+#define REG_CMB_BASE_ADDR_LO (0x1588) /* DWORD reg */ -+ -+#define REG_RSS_KEY0 (0x14B0) /* DWORD reg */ -+#define REG_RSS_KEY1 (0x14B4) /* DWORD reg */ -+#define REG_RSS_KEY2 (0x14B8) /* DWORD reg */ -+#define REG_RSS_KEY3 (0x14BC) /* DWORD reg */ -+#define REG_RSS_KEY4 (0x14C0) /* DWORD reg */ -+#define REG_RSS_KEY5 (0x14C4) /* DWORD reg */ -+#define REG_RSS_KEY6 (0x14C8) /* DWORD reg */ -+#define REG_RSS_KEY7 (0x14CC) /* DWORD reg */ -+#define REG_RSS_KEY8 (0x14D0) /* DWORD reg */ -+#define REG_RSS_KEY9 (0x14D4) /* DWORD reg */ -+ -+#define REG_RSS_IDT_TABLE0 (0x14E0) /* DWORD reg */ -+#define REG_RSS_IDT_TABLE1 (0x14E4) /* DWORD reg */ -+#define REG_RSS_IDT_TABLE2 (0x14E8) /* DWORD reg */ -+#define REG_RSS_IDT_TABLE3 (0x14EC) /* DWORD reg */ -+#define REG_RSS_IDT_TABLE4 (0x14F0) /* DWORD reg */ -+#define REG_RSS_IDT_TABLE5 (0x14F4) /* DWORD reg */ -+#define REG_RSS_IDT_TABLE6 (0x14F8) /* DWORD reg */ -+#define REG_RSS_IDT_TABLE7 (0x14FC) /* DWORD reg */ -+ -+#define REG_RSS_HASH_VAL (0x15B0) /* DWORD reg */ -+#define REG_RSS_HASH_FLAG (0x15B4) /* DOWRD reg */ -+ -+#define REG_RSS_BASE_CPU_NUMBER (0x15B8) /* DWORD reg */ -+ -+#define REG_TXQ_CTRL (0x1590) /* DWORD reg */ -+ #define TXQ_CTRL_NUM_TPD_BURST_OFF 0 -+ #define TXQ_CTRL_NUM_TPD_BURST_BITS 4 -+ #define TXQ_CTRL_NUM_TPD_BURST_DEF 5 -+ #define TXQ_CTRL_IP_OPT_SP_OFF 4 -+ #define TXQ_CTRL_IP_OPT_SP_BITS 1 -+ #define TXQ_CTRL_EN_OFF 5 -+ #define TXQ_CTRL_EN_BITS 1 -+ #define TXQ_CTRL_MODE_OFF 6 -+ #define TXQ_CTRL_MODE_BITS 1 -+ #define TXQ_CTRL_MODE_ENH 1 -+ #define TXQ_CTRL_EN_SNAP_LSO_OFF 7 -+ #define TXQ_CTRL_EN_SNAP_LSO_BITS 1 -+ #define TXQ_CTRL_NUM_TXF_BURST_OFF 16 -+ #define TXQ_CTRL_NUM_TXF_BURST_BITS 16 -+ -+ -+#define REG_TXQ_JUMBO_TSO_THRESHOLD (0x1594) /* DWORD reg */ -+ -+#define REG_TXQ_TXF_BURST_L1 (0x1598) /* DWORD reg */ -+ #define TXQ_TXF_BURST_L1_LWM_OFF 0 -+ #define TXQ_TXF_BURST_L1_LWM_BITS 12 -+ #define TXQ_TXF_BURST_L1_HWM_OFF 16 -+ #define TXQ_TXF_BURST_L1_HWM_BITS 12 -+ #define TXQ_TXF_BURST_L1_EN_OFF 31 -+ #define TXQ_TXF_BURST_L1_EN_BITS 1 -+ -+ -+#define REG_THRUPUT_MON_CTRL (0x159C) /* DWORD reg */ -+ #define THRUPUT_MON_CTRL_RATE_OFF 0 -+ #define THRUPUT_MON_CTRL_RATE_BITS 2 -+ -+ #define THRUPUT_MON_CTRL_EN_OFF 7 -+ #define THRUPUT_MON_CTRL_EN_BITS 1 -+ -+#define REG_RXQ_CTRL (0x15A0) /* DWORD reg */ -+ #define RXQ_CTRL_ASPM_THRUPUT_LIM_OFF 0 -+ #define RXQ_CTRL_ASPM_THRUPUT_LIM_BITS 2 -+ #define RXQ_CTRL_ASPM_THRUPUT_LIM_NO 0 -+ #define RXQ_CTRL_ASPM_THRUPUT_LIM_1MB 1 -+ #define RXQ_CTRL_ASPM_THRUPUT_LIM_10MB 2 -+ #define RXQ_CTRL_ASPM_THRUPUT_LIM_100MB 3 -+ #define RXQ_CTRL_Q1_EN_OFF 4 -+ #define RXQ_CTRL_Q1_EN_BITS 1 -+ #define RXQ_CTRL_Q2_EN_OFF 5 -+ #define RXQ_CTRL_Q2_EN_BITS 1 -+ #define RXQ_CTRL_Q3_EN_OFF 6 -+ #define RXQ_CTRL_Q3_EN_BITS 1 -+ #define RXQ_CTRL_IPV6_XSUM_EN_OFF 7 -+ #define RXQ_CTRL_IPV6_XSUM_EN_BITS 1 -+ #define RXQ_CTRL_RSS_HASH_BITS_OFF 8 -+ #define RXQ_CTRL_RSS_HASH_BITS_BITS 8 -+ #define RXQ_CTRL_RSS_HASH_TYPE_IPV4_OFF 16 -+ #define RXQ_CTRL_RSS_HASH_TYPE_IPV4_TCP_OFF 17 -+ #define RXQ_CTRL_RSS_HASH_TYPE_IPV6_OFF 18 -+ #define RXQ_CTRL_RSS_HASH_TYPE_IPV6_TCP_OFF 19 -+ #define RXQ_CTRL_NUM_RFD_PREF_OFF 20 -+ #define RXQ_CTRL_NUM_RFD_PREF_BITS 6 -+ #define RXQ_CTRL_NUM_RFD_PREF_DEF 8 -+ #define RXQ_CTRL_RSS_MODE_OFF 26 -+ #define RXQ_CTRL_RSS_MODE_BITS 2 -+ #define RXQ_CTRL_RSS_MODE_DIS 0 -+ #define RXQ_CTRL_RSS_MODE_SQSI 1 -+ #define RXQ_CTRL_RSS_MODE_MQSI 2 -+ #define RXQ_CTRL_RSS_MODE_MQMI 3 -+ #define RXQ_CTRL_NIP_QUEUE_SEL_OFF 28 -+ #define RXQ_CTRL_NIP_QUEUE_SEL_BITS 1 -+ #define RXQ_CTRL_RSS_HASH_EN_OFF 29 -+ #define RXQ_CTRL_RSS_HASH_EN_BITS 1 -+ #define RXQ_CTRL_CUT_THRU_OFF 30 -+ #define RXQ_CTRL_CUT_THRU_BITS 1 -+ #define RXQ_CTRL_EN_OFF 31 -+ #define RXQ_CTRL_EN_BITS 1 -+ -+#define REG_RFD_PREF_CTRL (0x15A4) -+ #define RFD_PREF_CTRL_UP_TH_OFF 0 -+ #define RFD_PREF_CTRL_UP_TH_BITS 6 -+ #define RFD_PREF_CTRL_UP_TH_DEF 16 -+ #define RFD_PREF_CTRL_LOW_TH_OFF 6 -+ #define RFD_PREF_CTRL_LOW_TH_BITS 6 -+ #define RFD_PREF_CTRL_LOW_TH_DEF 8 -+ -+ -+#define REG_FC_RXF_HI (0x15A8) /* WORD reg */ -+#define REG_FC_RXF_LO 0x15AA /* WORD reg */ -+ -+#define REG_RXD_CTRL (0x15AC) /* DWORD reg */ -+ #define RXD_CTRL_THRESHOLD_OFF 0 -+ #define RXD_CTRL_THRESHOLD_BITS 12 -+ #define RXD_CTRL_TIMER_OFF 16 -+ #define RXD_CTRL_TIMER_BITS 16 -+ -+ -+#define REG_DMA_CTRL (0x15C0) /* DWORD reg */ -+ #define DMA_CTRL_ORDER_MODE_OFF 0 -+ #define DMA_CTRL_ORDER_MODE_BITS 3 -+ #define DMA_CTRL_ORDER_MODE_IN 1 -+ #define DMA_CTRL_ORDER_MODE_ENH 2 -+ #define DMA_CTRL_ORDER_MODE_OUT 4 -+ #define DMA_CTRL_RCB_VAL_OFF 3 -+ #define DMA_CTRL_RCB_VAL_BITS 1 -+ #define DMA_CTRL_REGRDBLEN_OFF 4 -+ #define DMA_CTRL_REGRDBLEN_BITS 3 -+ #define DMA_CTRL_REGWRBLEN_OFF 7 -+ #define DMA_CTRL_REGWRBLEN_BITS 3 -+ #define DMA_CTRL_DMAR_REQ_PRI_OFF 10 -+ #define DMA_CTRL_DMAR_REQ_PRI_BITS 1 -+ #define DMA_CTRL_DMAR_DLY_CNT_OFF 11 -+ #define DMA_CTRL_DMAR_DLY_CNT_BITS 5 -+ #define DMA_CTRL_DMAR_DLY_CNT_DEF 15 -+ #define DMA_CTRL_DMAW_DLY_CNT_OFF 16 -+ #define DMA_CTRL_DMAW_DLY_CNT_BITS 4 -+ #define DMA_CTRL_DMAW_DLY_CNT_DEF 4 -+ #define DMA_CTRL_CMB_EN_OFF 20 -+ #define DMA_CTRL_CMB_EN_BITS 1 -+ #define DMA_CTRL_SMB_DMA_SP_OFF 21 /* enable SMB DMA */ -+ #define DMA_CTRL_SMB_DMA_SP_BITS 1 -+ #define DMA_CTRL_CMB_NOW_OFF 22 -+ #define DMA_CTRL_CMB_NOW_BITS 1 -+ #define DMA_CTRL_SMB_DIS_OFF 24 -+ #define DMA_CTRL_SMB_DIS_BITS 1 -+ #define DMA_CTRL_SMB_NOW_OFF 31 -+ #define DMA_CTRL_SMB_NOW_BITS 1 -+ -+#define REG_SMB_DIS (0x15C3) /* BYTE reg */ -+ -+#define REG_SMB_TIMER (0x15C4 ) /* DWORD reg */ -+ -+#define REG_CMB_TPD_THRESHOLD (0x15C8) /* WORD reg */ -+#define REG_CMB_TIMER (0x15CC) /* WORD reg */ -+ -+#define REG_RFD0_PROD_INDEX (0x15E0) /* WORD reg */ -+#define REG_RFD1_PROD_INDEX (0x15E4) /* WORD reg */ -+#define REG_RFD2_PROD_INDEX (0x15E8) /* WORD reg */ -+#define REG_RFD3_PROD_INDEX (0x15EC) /* WORD reg */ -+ -+#define REG_HTPD_PROD_INDEX (0x15F0) /* WORD reg */ -+#define REG_NTPD_PROD_INDEX (0x15F2) /* WORD reg */ -+#define REG_HTPD_CONS_INDEX (0x15F4) /* WORD reg, ro */ -+#define REG_NTPD_CONS_INDEX (0x15F6) /* WORD reg, ro */ -+ -+#define REG_RFD0_CONS_INDEX (0x15F8) /* WORD reg, ro */ -+#define REG_RFD1_CONS_INDEX (0x15FA) /* WORD reg, ro */ -+#define REG_RFD2_CONS_INDEX (0x15FC) /* WORD reg, ro */ -+#define REG_RFD3_CONS_INDEX (0x15FE) /* WORD reg, ro */ -+ -+ -+#define REG_ISR (0x1600) /* DWORD reg */ -+ #define ISR_SMB_OFF 0 -+ -+ #define ISR_TIMER_OFF 1 -+ -+ #define ISR_SW_MANUAL_OFF 2 -+ #define ISR_SW_MANUAL_BITS 1 -+ #define ISR_RXF_OV_OFF (1<<3) -+ #define ISR_RXF_OV_BITS 1 -+ #define ISR_RFD0_UR_OFF (1<<4) -+ #define ISR_RFD0_UR_BITS 1 -+ #define ISR_RFD1_UR_OFF 5 -+ #define ISR_RFD1_UR_BITS 1 -+ #define ISR_RFD2_UR_OFF 6 -+ #define ISR_RFD2_UR_BITS 1 -+ #define ISR_RFD3_UR_OFF 7 -+ #define ISR_RFD3_UR_BITS 1 -+ #define ISR_TXF_UR_OFF 8 -+ #define ISR_TXF_UR_BITS 1 -+ #define ISR_DMAR_OFF (1<<9) -+ #define ISR_DMAR_BITS 1 -+ #define ISR_DMAW_OFF (1<<10) -+ #define ISR_DMAW_BITS 1 -+ #define ISR_TX_CREDIT_OFF 11 -+ #define ISR_TX_CREDIT_BITS 1 -+ #define ISR_GPHY_OFF (1<<12) -+ #define ISR_GPHY_BITS 1 -+ #define ISR_GPHY_LPW_OFF (1<<13) -+ #define ISR_GPHY_LPW_BITS 1 -+ #define ISR_TXQ_OFF (1<<14) -+ #define ISR_TXQ_BITS 1 -+ #define ISR_TX_PKT_OFF (1<<15) -+ #define ISR_TX_PKT_BITS 1 -+ #define ISR_RX0_PKT_OFF (1<<16) -+ #define ISR_RX0_PKT_BITS 1 -+ #define ISR_RX1_PKT_OFF 17 -+ #define ISR_RX1_PKT_BITS 1 -+ #define ISR_RX2_PKT_OFF 18 -+ #define ISR_RX2_PKT_BITS 1 -+ #define ISR_RX3_PKT_OFF 19 -+ #define ISR_RX3_PKT_BITS 1 -+ #define ISR_MAC_RX_OFF 20 -+ #define ISR_MAC_RX_BITS 1 -+ #define ISR_MAC_TX_OFF 21 -+ #define ISR_MAC_TX_BITS 1 -+ #define ISR_PCIE_UR_OFF 22 -+ #define ISR_PCIE_UR_BITS 1 -+ #define ISR_PCIE_FERR_OFF 23 -+ #define ISR_PCIE_FERR_BITS 1 -+ #define ISR_PCIE_NFERR_OFF 24 -+ #define ISR_PCIE_NFERR_BITS 1 -+ #define ISR_PCIE_CERR_OFF 25 -+ #define ISR_PCIE_CERR_BITS 1 -+ #define ISR_PCIE_LINKDOWN_OFF 26 -+ #define ISR_PCIE_LINKDOWN_BITS 1 -+ #define ISR_DIS_OFF 31 -+ #define ISR_DIS_BITS 1 -+ -+#define REG_IMR (0x1604) /* DWORD reg */ -+ -+ -+#define INT_FATAL_MASK (\ -+ FLAG(ISR_DMAR_OFF) |\ -+ FLAG(ISR_DMAW_OFF) |\ -+ FLAG(ISR_PCIE_FERR_OFF) |\ -+ FLAG(ISR_PCIE_LINKDOWN_OFF) ) -+ -+ -+#define INT_TX_MASK (\ -+ FLAG(ISR_MAC_TX_OFF) |\ -+ FLAG(ISR_TX_PKT_OFF) |\ -+ FLAG(ISR_TXF_UR_OFF) ) -+ -+#define INT_RX_MASK (\ -+ FLAG(ISR_RXF_OV_OFF) |\ -+ /* FLAG(ISR_RFD0_UR_OFF) |*/\ -+ FLAG(ISR_RFD1_UR_OFF) |\ -+ FLAG(ISR_RFD2_UR_OFF) |\ -+ FLAG(ISR_RFD3_UR_OFF) |\ -+ FLAG(ISR_RX0_PKT_OFF) |\ -+ FLAG(ISR_RX1_PKT_OFF) |\ -+ FLAG(ISR_RX2_PKT_OFF) |\ -+ FLAG(ISR_RX3_PKT_OFF) |\ -+ FLAG(ISR_MAC_RX_OFF) ) -+ -+#define INT_MASK (\ -+ INT_RX_MASK |\ -+ INT_TX_MASK |\ -+ INT_FATAL_MASK |\ -+ FLAG(ISR_SMB_OFF) |\ -+ FLAG(ISR_SW_MANUAL_OFF) |\ -+ FLAG(ISR_GPHY_OFF) |\ -+ FLAG(ISR_GPHY_LPW_OFF) ) -+ -+ -+ -+ -+#define REG_INT_RETRIG_TIMER (0x1608) /* WORD reg */ -+ -+#define REG_HDS_CTRL (0x160C) /* DWORD reg */ -+ #define HDS_CTRL_EN_OFF 0 -+ #define HDS_CTRL_EN_BITS 1 -+ #define HDS_CTRL_BACKFILLSIZE_OFF 8 -+ #define HDS_CTRL_BACKFILLSIZE_BITS 12 -+ #define HDS_CTRL_MAX_HDRSIZE_OFF 20 -+ #define HDS_CTRL_MAX_HDRSIZE_BITS 12 -+ -+#endif -diff --git a/drivers/net/ethernet/ak-ethernet/Kconfig b/drivers/net/ethernet/ak-ethernet/Kconfig -new file mode 100755 -index 00000000..84962124 ---- /dev/null -+++ b/drivers/net/ethernet/ak-ethernet/Kconfig -@@ -0,0 +1,6 @@ -+config AK_ETHERNET -+ tristate "Anyka Ethernet support" -+ depends on ARCH_AK39 -+ help -+ Anyka Ethernet device support -+ -diff --git a/drivers/net/ethernet/ak-ethernet/Makefile b/drivers/net/ethernet/ak-ethernet/Makefile -new file mode 100755 -index 00000000..f6c1f519 ---- /dev/null -+++ b/drivers/net/ethernet/ak-ethernet/Makefile -@@ -0,0 +1,5 @@ -+ -+ -+obj-$(CONFIG_AK_ETHERNET) += ak_ethernet.o -+ -+ -diff --git a/drivers/net/ethernet/ak-ethernet/ak_ethernet.c b/drivers/net/ethernet/ak-ethernet/ak_ethernet.c -new file mode 100755 -index 00000000..9244f71b ---- /dev/null -+++ b/drivers/net/ethernet/ak-ethernet/ak_ethernet.c -@@ -0,0 +1,1657 @@ -+/* -+ * Anyka MAC Fast Ethernet driver for Linux. -+ * Features -+ * Copyright (C) 2010 ANYKA -+ * AUTHOR Tang Anyang -+ * AUTHOR Zhang Jingyuan -+ * 10-11-01 09:08:08 -+ */ -+ -+#include <linux/module.h> -+#include <linux/ioport.h> -+#include <linux/netdevice.h> -+#include <linux/etherdevice.h> -+#include <linux/init.h> -+#include <linux/skbuff.h> -+#include <linux/spinlock.h> -+#include <linux/crc32.h> -+#include <linux/delay.h> -+#include <linux/platform_device.h> -+#include <linux/irq.h> -+#include <linux/kernel.h> -+#include <linux/clk.h> -+#include <linux/ctype.h> -+#include <linux/interrupt.h> -+ -+#include <asm/delay.h> -+#include <asm/irq.h> -+#include <asm/io.h> -+ -+#include <mach/map.h> -+#include <mach/gpio.h> -+#include <mach-anyka/mac.h> -+#include <mach/clock.h> -+//#include <mach/l2cache.h> -+#include <plat-anyka/anyka_types.h> -+#include <plat-anyka/fha_asa.h> -+ -+#define MACNAME "ak98_mac" -+#define DRV_VERSION "1.0" -+#define TPD_RING_SIZE 0x50 -+#define RFD_RING_SIZE 0x50 -+#define RRD_RING_SIZE 0x50 -+#define MAC_FILE_NAME "MACADDR" -+#define CTOI(c) (isdigit(c) ? (c - '0') : (c - 'A' + 10)) -+ -+#include "eth_ops.h" -+#include "Ethernethw.h" -+#include "phyhw.h" -+ -+#if 0 -+#define dbg(fmt, arg...) printk( "%s(%d): " fmt "\n", __func__, __LINE__, ##arg) -+#else -+#define dbg(fmt, arg...) {} -+#endif -+ -+/* rrd format */ -+typedef struct _RrdDescr_s { -+ -+ unsigned short xsum; /* */ -+ -+ unsigned short nor :4 ; /* number of RFD */ -+ unsigned short si :12 ; /* start index of rfd-ring */ -+ -+ unsigned short hash; /* rss(MSFT) hash value */ -+ -+ unsigned short hash1; -+ -+ unsigned short vidh :4 ; /* vlan-id high part */ -+ unsigned short cfi :1 ; /* vlan-cfi */ -+ unsigned short pri :3 ; /* vlan-priority */ -+ unsigned short vidl :8 ; /* vlan-id low part */ -+ unsigned char hdr_len; /* Header Length of Header-Data Split. unsigned short unit */ -+ unsigned char hds_typ :2 ; /* Header-Data Split Type, -+ 00:no split, -+ 01:split at upper layer protocol header -+ 10:split at upper layer payload */ -+ unsigned char rss_cpu :2 ; /* CPU number used by RSS */ -+ unsigned char hash_t6 :1 ; /* TCP(IPv6) flag for RSS hash algrithm */ -+ unsigned char hash_i6 :1 ; /* IPv6 flag for RSS hash algrithm */ -+ unsigned char hash_t4 :1 ; /* TCP(IPv4) flag for RSS hash algrithm */ -+ unsigned char hash_i4 :1 ; /* IPv4 flag for RSS hash algrithm */ -+ -+ unsigned short frm_len :14 ; /* frame length of the packet */ -+ unsigned short l4f :1 ; /* L4(TCP/UDP) checksum failed */ -+ unsigned short ipf :1 ; /* IP checksum failed */ -+ unsigned short vtag :1 ; /* vlan tag */ -+ unsigned short pid :3 ; /* protocol id, -+ 000: non-ip packet -+ 001: ipv4(only) -+ 011: tcp/ipv4 -+ 101: udp/ipv4 -+ 010: tcp/ipv6 -+ 100: udp/ipv6 -+ 110: ipv6(only) */ -+ unsigned short res :1 ; /* received error summary */ -+ unsigned short crc :1 ; /* crc error */ -+ unsigned short fae :1 ; /* frame alignment error */ -+ unsigned short trunc :1 ; /* truncated packet, larger than MTU */ -+ unsigned short runt :1 ; /* runt packet */ -+ unsigned short icmp :1 ; /* incomplete packet, due to insufficient rx-descriptor */ -+ unsigned short bar :1 ; /* broadcast address received */ -+ unsigned short mar :1 ; /* multicast address received */ -+ unsigned short typ :1 ; /* type of packet (ethernet_ii(1) or snap(0)) */ -+ unsigned short resv1 :2 ; /* reserved, must be 0 */ -+ unsigned short updt :1 ; /* update by hardware. after hw fulfill the buffer, this bit -+ should be 1 */ -+} RrdDescr_t, *PRrdDescr_t; -+ -+unsigned char *pMacBase = NULL; -+//unsigned char *pSystemBase; -+unsigned char *psysbase; -+unsigned long g_tpdconsumerindex = 0; -+unsigned long g_rfdconsumerindex = 0; -+unsigned long g_rrdconsumerindex = 0; -+bool g_update = false; -+ -+//unsigned long rfdaddress = 0; -+unsigned long tpdaddress = 0; /* physical address for tpd */ -+unsigned long tpdaddressVa = 0; /* virtual address for tpd */ -+void *tpdbufaddressVa = NULL; /* virtual address for tpd buffer */ -+dma_addr_t tpdbufaddressPa = 0; /* physical address for tpd buffer */ -+unsigned long rrdaddressVa = 0; /* virtual address for rrd */ -+ -+void *rfd_sequenceva = NULL; /* virtual address for rfd */ -+dma_addr_t rfd_sequence; /* physical address for rfd */ -+void *RingbufVa = NULL; /* virtual address for ring buf */ -+dma_addr_t RingbufPa; /* physical address for ring buf */ -+ -+void *rfdbaseva = NULL; -+dma_addr_t rfdbasepa; -+ -+static void ak_mac_hash_table(struct net_device *ndev); -+ -+/* close the 2x when cpu clk is bigger than 340 */ -+unsigned long _2xswitchflag = 0; -+#if 0 -+static inline void cpu_clk_2x_switch(void) -+{ -+ -+ if (ak98_get_cpu_clk() / MHz > 340) -+ { -+ printk("CPU Core > 340 MHz"); -+ _2xswitchflag = 1; -+ } -+ else { -+ printk("CPU Core <= 340 MHz"); -+ _2xswitchflag = 0; -+ } -+} -+ -+static inline void close_2x(void) -+{ -+ if (_2xswitchflag) { -+ REG32(psysbase + 0x04) &= ~(0x1 << 15); -+ } -+} -+static inline void open_2x(void) -+{ -+ if (_2xswitchflag) { -+ REG32(psysbase + 0x04) |= (0x1 << 15); -+ } -+} -+#endif -+ -+ -+/* Structure/enum declaration ------------------------------- */ -+typedef struct mac_info { -+ void __iomem *io_addr; /* Register I/O base address */ -+ u16 irq; /* IRQ */ -+ -+ u16 tx_pkt_cnt; -+ u16 queue_pkt_len; -+ u16 queue_start_addr; -+ u16 queue_ip_summed; -+ u16 dbug_cnt; -+ u8 io_mode; /* 0:word, 2:byte */ -+ u8 phy_addr; -+ u8 imr_all; -+ -+ unsigned int flags; -+ unsigned int in_suspend :1; -+ -+ void (*inblk)(void __iomem *port, void *data, int length); -+ void (*outblk)(void __iomem *port, void *data, int length); -+ void (*dumpblk)(void __iomem *port, int length); -+ -+ struct device *dev; /* parent device */ -+ -+ struct resource *addr_res; /* resources found */ -+ struct resource *addr_req; /* resources requested */ -+ struct resource *irq_res; -+ -+ struct mutex addr_lock; /* phy and eeprom access lock */ -+ -+ struct delayed_work phy_poll; -+ struct net_device *ndev; -+ -+ spinlock_t lock; -+ -+ u32 msg_enable; -+ -+ int rx_csum; -+ int can_csum; -+ int ip_summed; -+ int phy_id; -+ struct clk *clk; -+ -+ struct work_struct link_chg_task; -+} mac_info_t; -+ -+void MacDelay(unsigned long us) -+{ -+ unsigned long i =0; -+ for (i=0; i< 10*us*1000; i++) -+ ; -+} -+ -+/** * @brief Read Phy Register -+* Read Phy Register from MII Interface -+* @author Tang Anyang -+* @date 2010-11-16 -+* @param unsigned long RegAddr: Phy Register address -+* @retval unsigned long: the value of Phy Register. -+*/ -+unsigned long MIIRead(unsigned long RegAddr) -+{ -+ unsigned int Val; -+ unsigned short Index; -+ unsigned short phyVal; -+ unsigned int macbug; -+ -+ Val = -+ MDIO_CTRL_REG_ADDR(RegAddr) | -+ MDIO_CTRL_START| -+ MDIO_CTRL_READ; -+ -+ REG32(pMacBase + REG_MDIO_CTRL)= Val; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ for (Index=0; Index <MDIO_MAX_AC_TIMER; Index++) -+ { -+ Val = REG32(pMacBase + REG_MDIO_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ if (0 == (Val&FLAG(MDIO_CTRL_BUSY_OFF))) -+ { -+ phyVal = (unsigned short) Val; -+ goto mr_exit; -+ } -+ MacDelay(10); -+ } -+ -+ phyVal = 0; -+ -+mr_exit: -+ return phyVal; -+} -+ -+/** * @brief Wrtie Phy Register -+* Write dedicated value to Phy Register from MII Interface -+* @author Tang Anyang -+* @date 2010-11-16 -+* @param unsigned long RegAddr: Phy Register address -+* @param unsigned long phyVal: dedicated value. -+*/ -+void MIIWrite(unsigned long RegAddr, unsigned long phyVal) -+{ -+ unsigned int Val; -+ unsigned short Index; -+ unsigned int macbug; -+ -+ REG32(pMacBase + REG_MDIO_CTRL)= 0; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ MacDelay(30); -+ for(Index = 0; Index < MDIO_MAX_AC_TIMER; Index++) -+ { -+ Val = REG32(pMacBase + REG_MDIO_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ if (0 == (Val & FLAG(MDIO_CTRL_BUSY_OFF))) -+ { -+ break; -+ } -+ MacDelay(10); -+ } -+ -+ Val = -+ MDIO_CTRL_DATA(phyVal) | -+ MDIO_CTRL_REG_ADDR(RegAddr) |MDIO_CTRL_WRITE| -+ MDIO_CTRL_START; -+ -+ REG32(pMacBase + REG_MDIO_CTRL)= Val; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ for (Index=0; Index <MDIO_MAX_AC_TIMER; Index++) -+ { -+ Val = REG32(pMacBase + REG_MDIO_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ if (0 == (Val&FLAG(MDIO_CTRL_BUSY_OFF))) -+ { -+ -+ return; -+ } -+ MacDelay(10); -+ } -+} -+ -+unsigned int HwStopMAC(void) -+{ -+ unsigned int Val; -+ unsigned short Index; -+ unsigned int macbug; -+ -+ Val = REG32(pMacBase + REG_RXQ_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ BIT_CLEAR(Val, RXQ_CTRL_EN_OFF); -+ BIT_CLEAR(Val, RXQ_CTRL_Q1_EN_OFF); -+ BIT_CLEAR(Val, RXQ_CTRL_Q2_EN_OFF); -+ BIT_CLEAR(Val, RXQ_CTRL_Q3_EN_OFF); -+ REG32(pMacBase + REG_RXQ_CTRL) = Val; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ Val = REG32(pMacBase + REG_TXQ_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ BIT_CLEAR(Val, TXQ_CTRL_EN_OFF); -+ REG32(pMacBase + REG_TXQ_CTRL) = Val; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // waiting for rxq/txq be idle -+ for (Index=0; Index<50; Index++) -+ { -+ Val = REG32(pMacBase + REG_IDLE_STATUS); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ if (BIT_TEST(Val, IDLE_STATUS_RXQ_OFF) || -+ BIT_TEST(Val, IDLE_STATUS_TXQ_OFF)) -+ { -+ MacDelay(20); -+ } -+ else -+ break; -+ } -+ -+ // stop mac tx/rx -+ Val = REG32(pMacBase + REG_MAC_CTRL); -+ -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ BIT_CLEAR(Val, MAC_CTRL_RXEN_OFF); -+ BIT_CLEAR(Val, MAC_CTRL_TXEN_OFF); -+ REG32(pMacBase + REG_MAC_CTRL) = Val; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ MacDelay(10); -+ -+ for (Index=0; Index<50; Index++) // -+ { -+ Val = REG32(pMacBase + REG_IDLE_STATUS); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ if (0 == (unsigned char)Val) -+ return true; -+ -+ MacDelay(20); -+ } -+ -+ return false; -+} -+ -+void MacRest(void) -+{ -+ unsigned long Val =0; -+ unsigned long Index; -+ unsigned int macbug; -+ -+ // clear to unmask the corresponding INTs -+ REG32(pMacBase + REG_IMR)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ // disable interrupt -+ REG32(pMacBase + REG_ISR)=FLAG(ISR_DIS_OFF); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ HwStopMAC(); -+ -+ // reset whole-MAC safely -+ Val = REG32(pMacBase + REG_MASTER_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ BIT_SET(Val, MASTER_CTRL_MAC_SOFT_RST_OFF); -+ REG32(pMacBase + REG_MASTER_CTRL)= Val; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ MacDelay(50); -+ -+ for (Index=0; Index<50; Index++) // wait atmost 1ms -+ { -+ Val = REG32(pMacBase + REG_IDLE_STATUS); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ if (0 == (unsigned char)Val) -+ { -+ return ; -+ } -+ MacDelay(20); -+ } -+ -+ return; -+} -+ -+/* alloc buffer for ringbuf ,rfd, tpd */ -+bool InitEthernetMemory(void) -+{ -+ int i; -+ unsigned long *tempp; -+ -+ if (RingbufVa == NULL) -+ RingbufVa = dma_alloc_coherent(NULL, TPD_RING_SIZE * 16 + RRD_RING_SIZE * 16, &RingbufPa, GFP_KERNEL); -+ if(RingbufVa == NULL) -+ { -+ dbg("Alloc Memory for RingBuf Failed!"); -+ return false; -+ } -+ if (rfd_sequenceva == NULL) -+ rfd_sequenceva = dma_alloc_coherent(NULL, RFD_RING_SIZE * 8, &rfd_sequence, GFP_KERNEL); -+ if (rfd_sequenceva == NULL) -+ { -+ dbg("Alloc rfd sequence buffer failed!"); -+ return false; -+ } -+ -+ if (tpdbufaddressVa == NULL) -+ tpdbufaddressVa = dma_alloc_coherent(NULL, TPD_RING_SIZE * 1520, &tpdbufaddressPa, GFP_KERNEL); -+ if(tpdbufaddressVa == NULL) -+ { -+ dbg("Alloc tpd sequence buffer failed!"); -+ return false; -+ } -+ if (rfdbaseva == NULL) -+ rfdbaseva = dma_alloc_coherent(NULL, RFD_RING_SIZE * 1520, &rfdbasepa, GFP_KERNEL); -+ if(rfdbaseva == NULL) -+ { -+ dbg("Alloc rfd buffer failed!"); -+ return false; -+ } -+ -+ tempp = rfd_sequenceva; -+ for(i = 0; i < TPD_RING_SIZE; i++) -+ { -+ *tempp = rfdbasepa + i*1520; -+ tempp++; -+ -+ *tempp =0x00; -+ tempp++; -+ } -+ -+ return true; -+} -+ -+static void mac_phy_reset(struct ak_mac_data *pdata) -+{ -+ /* first set phy level low */ -+ pdata->gpio_init(&pdata->phy_rst_gpio); -+ mdelay(10); -+ /* second set gpio as input and be in powersave */ -+ ak_gpio_cfgpin(pdata->phy_rst_gpio.pin, !pdata->phy_rst_gpio.dir); -+ mdelay(1); -+} -+ -+static int mac_init_hw(struct ak_mac_data *pdata) -+{ -+ ak_group_config(ePIN_AS_MAC); -+ -+ if (pdata != NULL) { -+ /* init mac power on */ -+ if (pdata->pwr_gpio.pin > 0) -+ pdata->gpio_init(&pdata->pwr_gpio); -+ -+ /* init the gpio for phy */ -+ if (pdata->phy_rst_gpio.pin > 0) -+ mac_phy_reset(pdata); -+ } -+ return 0; -+} -+ -+/* init the mac and the phy */ -+bool init_hw(struct net_device *ndev) -+{ -+ unsigned long Val = 0; -+ unsigned long IntModerate = 100;//500000/5000; -+ -+ unsigned int mac_addL; -+ unsigned int mac_addH; -+ -+ unsigned long rrdaddress; -+ unsigned int macbug; -+ -+ struct mac_info *db = netdev_priv(ndev); -+ -+ // initial mac hw support -+ mac_init_hw(db->dev->platform_data); -+ -+ g_tpdconsumerindex = 0; -+ g_rfdconsumerindex = 0; -+ g_rrdconsumerindex = 0; -+ Val = REG32(pMacBase + 0x140c); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ Val |= (5<< 19); -+ REG32(pMacBase + 0x140c)= Val; -+ -+ -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+#if 0 -+ MIIWrite(MII_BMCR,0x8000); -+ -+ mdelay(50); -+ -+ dbg("PHYSID1:0x%lx, PHYSID2:0x%lx", MIIRead(MII_PHYSID1), MIIRead(MII_PHYSID2)); -+ -+ -+ -+ while(MIIRead(MII_BMCR)&0x8000) -+ { -+ dbg("BMCR:0x%lx", MIIRead(MII_BMCR)); -+ } -+#endif -+ mdelay(200); -+ dbg("BMCR:0x%lx", MIIRead(MII_BMCR)); -+ dbg("PHYSID1:0x%lx, PHYSID2:0x%lx\r\n", MIIRead(MII_PHYSID1), MIIRead(MII_PHYSID2)); -+ dbg("PHYSID1:0x%lx, PHYSID2:0x%lx\r\n", MIIRead(MII_PHYSID1), MIIRead(MII_PHYSID2)); -+ dbg("PHYSID1:0x%lx, PHYSID2:0x%lx\r\n", MIIRead(MII_PHYSID1), MIIRead(MII_PHYSID2)); -+ dbg("PHYSID1:0x%lx, PHYSID2:0x%lx\r\n", MIIRead(MII_PHYSID1), MIIRead(MII_PHYSID2)); -+ dbg("PHYSID1:0x%lx, PHYSID2:0x%lx\r\n", MIIRead(MII_PHYSID1), MIIRead(MII_PHYSID2)); -+ -+ db->phy_id = MIIRead(MII_PHYSID1); -+ printk("===PHY ID:0x%x===\r\n", db->phy_id); -+ if(db->phy_id == 0x22) -+ { -+ MIIWrite(MII_BMCR, MIIRead(MII_BMCR) | 0x1000); -+ } -+ else -+ { -+ MIIWrite(MII_BMCR, MIIRead(MII_BMCR) | 0x1100); -+ -+ } -+ dbg("BMCR:0x%lx", MIIRead(MII_BMCR)); -+ dbg("GIGA_PSSR:0x%lx", MIIRead(MII_GIGA_PSSR)); -+ -+ /* set mac-address */ -+ mac_addL = ndev->dev_addr[5] | (ndev->dev_addr[4] << 8) -+ | (ndev->dev_addr[3] << 16) | (ndev->dev_addr[2] << 24); -+ mac_addH = ndev->dev_addr[1] | (ndev->dev_addr[0] << 8); -+ -+ REG32(pMacBase + REG_MAC_STA_ADDR)= mac_addL; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_MAC_STA_ADDR+4)= mac_addH; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // clear the Multicast HASH table -+ REG32(pMacBase + REG_RX_HASH_TABLE) = 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RX_HASH_TABLE+4)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // clear any WOL setting/status / -+ Val = REG32(pMacBase + REG_WOL_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_WOL_CTRL)=0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ tpdaddressVa = (unsigned long)RingbufVa; -+ // tx/rx/smb Ring BaseMem -+ REG32(pMacBase + REG_NTPD_HDRADDR_LO) = RingbufPa;//NTPD_HDRADDR_LO -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_HTPD_HDRADDR_LO)= RingbufPa;//HTPD_HDRADDR_LO -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_TX_BASE_ADDR_HI) = 0x00;//TX_BASE_ADDR_HI -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_TPD_RING_SIZE)= TPD_RING_SIZE;//TPD_RING_SIZE -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ REG32(pMacBase + REG_RX_BASE_ADDR_HI)= 0x00;//RX_BASE_ADDR_HI -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ REG32(pMacBase + REG_RFD0_HDRADDR_LO) = rfd_sequence;//RFD0_HDRADDR_LO -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ REG32(pMacBase + REG_RFD1_HDRADDR_LO)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RFD2_HDRADDR_LO)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RFD3_HDRADDR_LO)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RFD_RING_SIZE)= RFD_RING_SIZE;//RFD_RING_SIZE -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RFD_BUFFER_SIZE)= 0x600;//RFD_BUFFER_SIZE -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ rrdaddress = RingbufPa + TPD_RING_SIZE * 16; -+ rrdaddressVa = (unsigned long)RingbufVa + TPD_RING_SIZE * 16; -+ -+ REG32(pMacBase + REG_RRD0_HDRADDR_LO)= rrdaddress; // RRD0_HDRADDR_LO -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RRD1_HDRADDR_LO)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RRD2_HDRADDR_LO)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RRD3_HDRADDR_LO)= 0x00; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RRD_RING_SIZE)= RRD_RING_SIZE;//REG_RRD_RING_SIZE -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ -+ REG32(pMacBase + REG_TXQ_TXF_BURST_L1)= 0;// TX watermark, to enter l1 state. -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RXD_CTRL)= 0; // RXD threshold. -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // load all base/mem ptr -+ REG32(pMacBase + REG_SRAM_LOAD_PTR)= FLAG(SRAM_LOAD_PTR_OFF); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // set Interrupt Moderator Timer (max interrupt per sec) -+ // we use seperate time for rx/tx -+ REG16(pMacBase + REG_IRQ_MODRT_INIT)= IntModerate * 2; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG16(pMacBase + REG_IRQ_MODRT_RX_INIT)= IntModerate; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // set Interrupt Clear Timer -+ // HW will enable self to assert interrupt event to system after -+ // waiting x-time for software to notify it accept interrupt. -+ -+ REG32(pMacBase + REG_INT_RETRIG_TIMER)= 10000;// 20ms -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // Enable Read-Clear Interrupt Mechanism -+ Val = FLAG(MASTER_CTRL_INT_RCLR_EN_OFF); -+ BIT_SET(Val, MASTER_CTRL_SA_TIMER_EN_OFF); -+ REG32(pMacBase + REG_MASTER_CTRL)= Val; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ REG32(pMacBase + REG_FC_RXF_HI)= 0x03300400; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_TXQ_JUMBO_TSO_THRESHOLD)= 0xbf; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // set MTU -+ REG32(pMacBase + REG_MTU)= 1540; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // set DMA -+ //mac_set_reg(REG_DMA_CTRL, 0x347ed1);//DMA Engine Control -+ //mac_set_reg(REG_DMA_CTRL, 0x47C20);//DMA Engine Control -+ //REG32(pMacBase + REG_DMA_CTRL)= 0x47C10; -+ REG32(pMacBase + REG_DMA_CTRL)= 0x47C14; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // set TXQ -+ REG32(pMacBase + REG_TXQ_CTRL)= 0x01000025; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // set RXQ -+ //mac_set_reg(0x600015a0, 0xc08f10f0); -+ REG32(pMacBase + REG_RXQ_CTRL)= 0xC0800000; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ // rfd producer index -+ REG32(pMacBase + REG_RFD0_PROD_INDEX)= RFD_RING_SIZE - 1; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ //set MAC control -+ //REG32(pMacBase + REG_MAC_CTRL)= 0x0e10dcef;//MAC control register -+ REG32(pMacBase + REG_MAC_CTRL)= 0x06105cef;//MAC control register -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ REG32(pMacBase + REG_IMR)= 0x1d608;//Interrupt Mask -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ if(db->phy_id == 0x22) -+ { -+ MIIWrite(0x1B, 0x0500); -+ MIIWrite(0x1F, 0x8300); -+ } -+ else -+ { -+ MIIWrite(MII_IER, 0x0c00); -+ } -+ -+ ak_mac_hash_table(ndev); -+ -+ return true; -+} -+ -+/** * @brief Initialize Mac -+* Initialize MAC and PHY -+* @author Tang Anyang -+* @date 2010-11-16 -+* @param unsigned char * MacAddress: -+*/ -+bool MacInit(struct net_device *ndev) -+{ -+ //struct mac_info *db; -+ volatile unsigned long count; -+ -+ -+ int i=0; -+ //db = netdev_priv(ndev); -+ //close_2x(); -+ -+ -+ -+ //to enable the 25MHz oscillator -+ //TODO: Need to be changed to new clock API -+ REG32(psysbase + 0x74) &= ~(3 << 2); -+ REG32(psysbase + 0x74) |= (1 << 2); -+ REG32(psysbase + 0x80) |= (1 << 2); -+ //REG32(psysbase + 0x14) |= (1 << 18); -+ //REG32(psysbase + 0x1c) |= (1 << 13); -+ REG32(psysbase + 0x14) |= (1 << 16|1 << 18); -+ REG32(psysbase + 0x1c) &= ~(1 << 13); -+ for(i=0;i<6;i++) -+ { -+ REG32(psysbase + 0x14) |= (1 << 20); -+ REG32(psysbase + 0x14) &= ~(1 << 20); -+ } -+/* -+ -+ reg_value = REG32(psysbase + 0x18); -+ //��x0800,0014�Ĵ����ġ�18��λ����Ϊ1��opclkѡ�����opclk divider��ʱ�Ӷ�����MAC_CLK, 25MHz -+ -+ //���÷�Ƶϵ�� -+ //reg_value &= (0x3F); -+ reg_value = (0x17); -+ REG32(psysbase + 0x18)= reg_value; -+ -+ //enable the adjustment of OPCLK divider. -+ REG32(psysbase + 0x18) |= (1 << 9); -+ //��ʱ�ӿ��� -+ // REG32(psysbase + 0x18) |= (1 << 8); -+ -+ REG32(psysbase + 0x18) |= (1 << 8); -+ -+ -+ REG32(psysbase + 0x14) &= ~(1 << 14); -+ -+ //unreset MAC module -+ count = 10000; -+ while(count--); -+ REG32(psysbase + 0x20) &= ~(1 << 13); -+ count = 10000; -+ */ -+ count = 10; -+ while(count--); -+ -+ //to enable the 25MHz oscillator -+ //REG32(psysbase + 0x14) |= (1 << 16); -+ -+ count = 10; -+ //reset MAC module -+ while(count--); -+ REG32(psysbase + 0x20) |= (1 << 13); -+ count = 10; -+ -+ while(count--); -+ -+ //unreset MAC module -+ REG32(psysbase + 0x20) &= ~(1 << 13); -+ count = 10; -+ -+ while(count--); -+ -+ if (false == InitEthernetMemory()) -+ return false; -+ -+ if (false == init_hw(ndev)) -+ return false; -+ -+// open_2x(); -+ -+ return true; -+} -+ -+void Macexit(struct net_device *ndev) -+{ -+ if (rfd_sequenceva) { -+ dma_free_coherent(NULL, RFD_RING_SIZE * 4, rfd_sequenceva, rfd_sequence); -+ rfd_sequenceva = NULL; -+ rfd_sequence = 0; -+ } -+ -+ if (tpdbufaddressVa) { -+ dma_free_coherent(NULL, TPD_RING_SIZE * 1520, tpdbufaddressVa, tpdbufaddressPa); -+ tpdbufaddressVa = NULL; -+ tpdbufaddressPa = 0; -+ } -+ -+ if (rfdbaseva) { -+ dma_free_coherent(NULL, RFD_RING_SIZE * 1520, rfdbaseva, rfdbasepa); -+ rfdbaseva = NULL; -+ rfdbasepa = 0; -+ } -+ -+ if (RingbufVa) { -+ dma_free_coherent(NULL, TPD_RING_SIZE * 16 + RRD_RING_SIZE * 16, RingbufVa, RingbufPa); -+ RingbufVa = NULL; -+ RingbufPa = 0; -+ } -+} -+ -+unsigned long GetPacketCount(void) -+{ -+ unsigned long ulNewRfdConsIdx = 0; -+ unsigned int macbug; -+ -+ ulNewRfdConsIdx = REG32(pMacBase + REG_RFD0_CONS_INDEX); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ dbg("ulNewRfdConsIdx:0x%lx, g_rfdconsumerindex:%lx", ulNewRfdConsIdx, g_rfdconsumerindex); -+ -+ return ulNewRfdConsIdx - g_rfdconsumerindex; -+} -+ -+long ReceivePacket(struct net_device *ndev) -+{ -+ PRrdDescr_t prrd; -+ short length; -+ static unsigned long g_wait_count = 0; -+ unsigned char *sendbuffer; -+ struct sk_buff *skb; -+ unsigned int macbug; -+ -+ //l2cache_invalidate(); -+ -+ prrd = (PRrdDescr_t)(rrdaddressVa + g_rfdconsumerindex*16); -+ length = prrd->frm_len; -+ dbg("g_rfdconsumerindex:%lx, length:%x, updt:%d", -+ g_rfdconsumerindex, length, prrd->updt); -+ -+ if (length == 0) -+ { -+ if (prrd->nor == 0) -+ { -+ if (g_update) -+ { -+ g_rrdconsumerindex = g_rfdconsumerindex; -+ g_update = false; -+ } -+ } -+ length = 0; -+ -+ g_rfdconsumerindex++; -+ g_rfdconsumerindex %= RFD_RING_SIZE; -+ -+ return length; -+ } -+ -+ if (prrd->updt == 0) -+ -+ { -+ g_wait_count++; -+ -+ if (g_wait_count < 5) -+ { -+ length = -1; -+ -+ return length; -+ } -+ } -+ g_wait_count = 0; -+ prrd->updt = 0; -+ prrd->frm_len = 0; -+ -+ sendbuffer = (unsigned char *)(rfdbaseva + (g_rfdconsumerindex)*1520); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ skb = dev_alloc_skb(length + 2); -+ skb_reserve(skb, 2); -+ skb->dev = ndev; -+ memcpy(skb_put(skb, length), sendbuffer, length); -+ skb->protocol = eth_type_trans(skb, ndev); -+ -+ netif_rx(skb); -+ -+ ndev->last_rx = jiffies; -+ ndev->stats.rx_packets++; -+ ndev->stats.rx_bytes += length; -+ -+ REG32(pMacBase + REG_RFD0_PROD_INDEX) = g_rfdconsumerindex; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ g_rfdconsumerindex++; -+ g_rfdconsumerindex %= RFD_RING_SIZE; -+ -+ return length; -+} -+ -+void SendPacket(unsigned char *sendbuffer, unsigned long length) -+{ -+ int tpdvalue = 0x80000000; -+ unsigned char *RingbufVa; -+ unsigned long tpdbufv; -+ unsigned int macbug; -+ -+ RingbufVa = (unsigned char *)(tpdbufaddressVa+g_tpdconsumerindex*1520); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ memcpy(RingbufVa, sendbuffer, length); -+ -+ tpdbufv = tpdaddressVa + g_tpdconsumerindex*16; -+ -+ REG32(tpdbufv)= (unsigned long)0x3aa00000+length; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ dbg("Send 0x%lx", length); -+ -+ tpdbufv += 4; -+ REG32(tpdbufv)= tpdvalue; -+ -+ tpdbufv += 4; -+ -+ //close_2x(); -+ REG32(tpdbufv)= tpdbufaddressPa + g_tpdconsumerindex*1520; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ tpdbufv += 4; -+ -+ g_tpdconsumerindex++; -+ -+ g_tpdconsumerindex %= TPD_RING_SIZE; -+ REG32(pMacBase + REG_HTPD_PROD_INDEX) = g_tpdconsumerindex; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ //open_2x(); -+ -+ return; -+} -+ -+/* ak_mac_release_board -+ * -+ * release a board, and any mapped resources -+ */ -+ -+static void -+ak_mac_release_board(struct platform_device *pdev, struct mac_info *db) -+{ -+ /* unmap our resources */ -+ -+ iounmap(db->io_addr); -+ -+ /* release the resources */ -+ -+ release_resource(db->addr_req); -+ kfree(db->addr_req); -+} -+ -+/* -+ * Set AK98 MAC address -+ */ -+static int set_mac_address(struct net_device *ndev, void *p) -+{ -+ struct sockaddr *addr = p; -+ unsigned int macbug; -+ -+ if (netif_running(ndev)) -+ return -EBUSY; -+ if (!is_valid_ether_addr(addr->sa_data)) -+ return -EADDRNOTAVAIL; -+ -+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); -+ -+ /* set the Ethernet address */ -+ REG32(pMacBase + REG_MAC_STA_ADDR) = ndev->dev_addr[0] | (ndev->dev_addr[1] << 8) -+ | (ndev->dev_addr[2] << 16) | (ndev->dev_addr[3] << 24); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_MAC_STA_ADDR + 4) = ndev->dev_addr[4] | (ndev->dev_addr[5] << 8); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ return 0; -+} -+ -+/* -+ * atl1c_hash_mc_addr -+ * purpose -+ * set hash value for a multicast address -+ * hash calcu processing : -+ * 1. calcu 32bit CRC for multicast address -+ * 2. reverse crc with MSB to LSB -+ */ -+u32 ak_mac_hash_mc_addr(u8 *mc_addr) -+{ -+ u32 crc32; -+ u32 value = 0; -+ int i; -+ -+ crc32 = ether_crc_le(6, mc_addr); -+ for (i = 0; i < 32; i++) -+ value |= (((crc32 >> i) & 1) << (31 - i)); -+ -+ return value; -+} -+ -+/* -+ * Sets the bit in the multicast table corresponding to the hash value. -+ * hw - Struct containing variables accessed by shared code -+ * hash_value - Multicast address hash value -+ */ -+void ak_mac_hash_set(u32 hash_value) -+{ -+ u32 hash_bit, hash_reg; -+ u32 mta; -+ unsigned int macbug; -+ -+ /* -+ * The HASH Table is a register array of 2 32-bit registers. -+ * It is treated like an array of 64 bits. We want to set -+ * bit BitArray[hash_value]. So we figure out what register -+ * the bit is in, read it, OR in the new bit, then write -+ * back the new value. The register is determined by the -+ * upper bit of the hash value and the bit within that -+ * register are determined by the lower 5 bits of the value. -+ */ -+ hash_reg = (hash_value >> 31) & 0x1; -+ hash_bit = (hash_value >> 26) & 0x1F; -+ -+ if (hash_reg == 0) -+ mta = REG32(pMacBase + REG_RX_HASH_TABLE); -+ else -+ mta = REG32(pMacBase + REG_RX_HASH_TABLE + 4); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ mta |= (1 << hash_bit); -+ if (hash_reg == 0) -+ REG32(pMacBase + REG_RX_HASH_TABLE) = mta; -+ else -+ REG32(pMacBase + REG_RX_HASH_TABLE + 4) = mta; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+} -+ -+/* -+ * Set AK98 MAC multicast address -+ */ -+ #if 1 -+static void -+ak_mac_hash_table(struct net_device *ndev) -+{ -+// struct dev_mc_list *mc_ptr; -+ u32 mac_ctrl_data; -+// u32 hash_value; -+ unsigned int macbug; -+ -+ -+ /* Check for Promiscuous and All Multicast modes */ -+ mac_ctrl_data = REG32(pMacBase + REG_MAC_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ if (ndev->flags & IFF_PROMISC) { -+ mac_ctrl_data |= FLAG(MAC_CTRL_PROM_MODE_OFF); -+ } else if (ndev->flags & IFF_ALLMULTI) { -+ mac_ctrl_data |= FLAG(MAC_CTRL_MUTI_ALL_OFF); -+ mac_ctrl_data &= ~(FLAG(MAC_CTRL_PROM_MODE_OFF)); -+ } else { -+ mac_ctrl_data &= ~(FLAG(MAC_CTRL_MUTI_ALL_OFF) | FLAG(MAC_CTRL_PROM_MODE_OFF)); -+ } -+ -+ REG32(pMacBase + REG_MAC_CTRL) = mac_ctrl_data; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ /* clear the old settings from the multicast hash table */ -+ REG32(pMacBase + REG_RX_HASH_TABLE) = 0; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ REG32(pMacBase + REG_RX_HASH_TABLE + 4) = 0;; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ /* comoute mc addresses' hash value ,and put it into hash table */ -+ //for (mc_ptr = ndev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { -+ // hash_value = ak_mac_hash_mc_addr(mc_ptr->dmi_addr); -+ // ak_mac_hash_set(hash_value);// -+ //} -+} -+#endif -+/* Our watchdog timed out. Called by the networking layer */ -+static void ak_mac_timeout(struct net_device *ndev) -+{ -+ /* Initialize AK98 MAC */ -+ if (MacInit(ndev) == false) { -+ printk("Mac reset fail\n"); -+ return; -+ } -+ -+ /* wake up the send queue */ -+ netif_wake_queue(ndev); -+} -+ -+/* -+ * Hardware start transmission. -+ * Send a packet to media from the upper layer. -+ */ -+static int -+ak_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) -+{ -+ unsigned long flags; -+ int len; -+ char *data, shortpkt[ETH_ZLEN]; -+ mac_info_t *db = netdev_priv(ndev); -+ -+ /* keep the upload from being interrupted, since we -+ * ask the chip to start transmitting before the -+ * whole packet has been completely uploaded. */ -+ spin_lock_irqsave(&db->lock, flags); -+ data = skb->data; -+ len = skb->len; -+ if (len < ETH_ZLEN) { -+ memset(shortpkt, 0, ETH_ZLEN); -+ memcpy(shortpkt, skb->data, skb->len); -+ len = ETH_ZLEN; -+ data = shortpkt; -+ } -+ netif_stop_queue(ndev); -+ -+ SendPacket(data, len); -+ spin_unlock_irqrestore(&db->lock, flags); -+ ndev->stats.tx_bytes += skb->len; -+ ndev->trans_start = jiffies; -+ dev_kfree_skb(skb); -+ -+ return NETDEV_TX_OK; -+} -+ -+int receive(struct net_device *ndev) -+{ -+ int length = 0; -+ -+ g_rfdconsumerindex = g_rrdconsumerindex; -+ g_update = true; -+ -+ while (GetPacketCount()) -+ { -+ length = ReceivePacket(ndev); -+ if (length == 0) -+ break; -+ else if (length == -1) -+ continue; -+ } -+ if(g_update) -+ g_rrdconsumerindex = g_rfdconsumerindex; -+ -+ return length; -+} -+ -+/* -+ * check whether the mac is connect, -+ * if connect, judge the full-duplex or half-duplex -+ * and set mac control register -+ */ -+int ak_mac_check_link(mac_info_t *db) -+{ -+ unsigned long status; -+ unsigned long ctrl_reg; -+ unsigned int macbug; -+ -+ ctrl_reg = REG32(pMacBase + REG_MAC_CTRL); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ status = MIIRead(MII_BMSR); -+ status = MIIRead(MII_BMSR); -+ dbg("==BMSR: 0x%lx===", status); -+ -+ if(status == 0xFFFF) -+ { -+ netif_carrier_off(db->ndev); -+ return 0; -+ } -+ -+ if ((status & BMSR_LINK_STATUS) == 0) { -+ netif_carrier_off(db->ndev); -+ printk("%s: link down\n", db->ndev->name); -+ } else { -+ -+ if ((status & 0x20) == 0) { -+ printk("auto negotiation is not resolved\n"); -+ return -1; -+ } -+ else if (status & 0x4000) { -+ -+ printk("%s: link up, full duplex, 100Mb\n", db->ndev->name); -+ } -+ else if(status & 0x2000) -+ { -+ -+ printk("%s: link up, half duplex, 100Mb\n", db->ndev->name); -+ } -+ else if(status & 0x1000) -+ { -+ -+ printk("%s: link up, full duplex, 10Mb\n", db->ndev->name); -+ } -+ else -+ { -+ -+ printk("%s: link up, half duplex, 10Mb\n", db->ndev->name); -+ } -+ -+ -+ -+ netif_carrier_on(db->ndev); -+ -+ -+ -+ } -+ return 0; -+} -+ -+void ak_mac_link_chg_task(struct work_struct *work) -+{ -+ mac_info_t *db = container_of(work, struct mac_info, link_chg_task); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&db->lock, flags); -+ ak_mac_check_link(db); -+ spin_unlock_irqrestore(&db->lock, flags); -+} -+ -+static irqreturn_t ak_mac_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *ndev = dev_id; -+ mac_info_t *db = netdev_priv(ndev); -+ unsigned long flags; -+ unsigned long IntStatus = 0; -+ unsigned int macbug; -+ /* holders of db->lock must always block IRQs */ -+ spin_lock_irqsave(&db->lock, flags); -+ -+ //close_2x(); -+ IntStatus = REG32(pMacBase + REG_ISR); -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ -+ dbg("IntStatus %lx", IntStatus); -+ -+ if(IntStatus & ISR_GPHY_OFF) { -+ if(db->phy_id==0x22) -+ { -+ MIIRead(0x1B); -+ } -+ else -+ { -+ MIIRead(MII_ISR); -+ } -+ //if(dwPHYIntStatus & (ISR_LINK_DOWN | ISR_LINK_UP)) { -+ schedule_work(&db->link_chg_task); -+ //} -+ REG32(pMacBase + REG_ISR) = ISR_GPHY_OFF; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ } -+ if(IntStatus & ISR_GPHY_LPW_OFF) { -+ unsigned long dwPHYIntStatus = MIIRead(MII_ISR); -+ if(dwPHYIntStatus & ISR_LINK_UP) { -+ //SetNetLinkStatus(TRUE); -+ netif_carrier_on(ndev); -+ dbg("%s: low power state link up", ndev->name); -+ } -+ if(dwPHYIntStatus & ISR_LINK_DOWN) { -+ //SetNetLinkStatus(FALSE); -+ netif_carrier_off(ndev); -+ dbg("%s: low power state link down", ndev->name); -+ } -+ } -+ -+ if(IntStatus & ISR_TX_PKT_OFF) { -+ REG32(pMacBase + REG_ISR) = ISR_TX_PKT_OFF; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ dbg("send complete!%lx", g_tpdconsumerindex); -+ ndev->stats.tx_packets++; -+ netif_wake_queue(ndev); -+ } -+ if(IntStatus & ISR_RX0_PKT_OFF) { -+ receive(ndev); -+ REG32(pMacBase + REG_ISR) = ISR_RX0_PKT_OFF; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ } -+ if(IntStatus & ISR_RXF_OV_OFF) { -+ receive(ndev); -+ REG32(pMacBase + REG_ISR) = ISR_RXF_OV_OFF; -+ macbug = REG32(AK_VA_L2CTRL+0xFF0); -+ } -+ if(IntStatus & ISR_DMAW_OFF) -+ { -+ printk("DMAW operation timeout"); -+ init_hw(ndev); -+ netif_wake_queue(ndev); -+ } -+ if(IntStatus & ISR_DMAR_OFF) -+ { -+ printk("DMAR operation timeout"); -+ init_hw(ndev); -+ netif_wake_queue(ndev); -+ } -+ if(IntStatus & ISR_TXQ_OFF) -+ { -+ printk("TXQ operation timeout"); -+ init_hw(ndev); -+ netif_wake_queue(ndev); -+ } -+ -+ //open_2x(); -+ -+ spin_unlock_irqrestore(&db->lock, flags); -+ -+ return IRQ_HANDLED; -+} -+ -+#ifdef CONFIG_NET_POLL_CONTROLLER -+/* -+ *Used by netconsole -+ */ -+static void ak_mac_poll_controller(struct net_device *ndev) -+{ -+ disable_irq(ndev->irq); -+ ak_mac_interrupt(ndev->irq, ndev); -+ enable_irq(ndev->irq); -+} -+#endif -+ -+/* -+ * Open the interface. -+ * The interface is opened whenever "ifconfig" actives it. -+ */ -+static int -+ak_mac_open(struct net_device *ndev) -+{ -+ mac_info_t *db = netdev_priv(ndev); -+ -+ /* enable clk */ -+// clk_enable(db->clk); -+ -+ /* Initialize AK98 MAC */ -+ if (MacInit(ndev) == false) { -+ printk("mac init fail\n"); -+ return -ENOMEM; -+ } else -+ printk("mac init success!\n"); -+ -+ if (request_irq(ndev->irq, &ak_mac_interrupt, 0, ndev->name, ndev)) -+ return -EAGAIN; -+ -+ schedule_work(&db->link_chg_task); -+ -+ netif_start_queue(ndev); -+ -+ return 0; -+} -+ -+/* -+ * Stop the interface. -+ * The interface is stopped when it is brought. -+ */ -+static int -+ak_mac_stop(struct net_device *ndev) -+{ -+// mac_info_t *db = netdev_priv(ndev); -+ -+ netif_stop_queue(ndev); -+ netif_carrier_off(ndev); -+ -+ /* free interrupt */ -+ free_irq(ndev->irq, ndev); -+ -+ /* reset mac and close phy */ -+ //close_2x(); -+ MacRest(); -+ MIIWrite(MII_BMCR, MIIRead(MII_BMCR) | 0x800); -+ //open_2x(); -+ -+ /* close clk */ -+ //clk_disable(db->clk); -+ -+ return 0; -+} -+ -+/* Get the current statistics. This may be called with the card open or -+ closed. */ -+static struct net_device_stats * -+ak_mac_get_stats(struct net_device *ndev) -+{ -+ //struct mac_info_t *db = netdev_priv(ndev); -+ //unsigned long flags; -+ -+ //spin_lock_irqsave(&lp->lock, flags); -+ /* Update the statistics from the device registers. */ -+ //db->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); -+ //db->stats.collisions += (readreg(dev, PP_TxCol) >> 6); -+ //spin_unlock_irqrestore(&lp->lock, flags); -+ -+ return &ndev->stats; -+} -+ -+static const struct net_device_ops ak_mac_netdev_ops = { -+ .ndo_open = ak_mac_open, -+ .ndo_stop = ak_mac_stop, -+ .ndo_start_xmit = ak_mac_start_xmit, -+ .ndo_tx_timeout = ak_mac_timeout, -+ .ndo_set_rx_mode = ak_mac_hash_table, -+ .ndo_change_mtu = eth_change_mtu, -+ .ndo_validate_addr = eth_validate_addr, -+ .ndo_set_mac_address = set_mac_address, -+#ifdef CONFIG_NET_POLL_CONTROLLER -+ .ndo_poll_controller = ak_mac_poll_controller, -+#endif -+ .ndo_get_stats = ak_mac_get_stats, -+}; -+ -+static int get_mac_addr(struct ak_mac_data *pdata) -+{ -+ int i; -+ unsigned char mac_addr[32] = {0}; -+ unsigned char file_len[4] = {0}; -+ -+ if (FHA_asa_read_file(MAC_FILE_NAME, file_len, 4) == AK_FALSE) { -+ goto out; -+ } -+ -+ if (FHA_asa_read_file(MAC_FILE_NAME, mac_addr, *(unsigned long*)file_len + 4) == AK_FALSE) { -+ goto out; -+ } -+ -+ for (i = 0; i < MAC_ADDR_STRING_LEN; i++) { -+ if ((i % 3 != 2)) { -+ mac_addr[i + 4] = toupper(mac_addr[i + 4]); -+ if (!(isdigit(mac_addr[i + 4]) || (mac_addr[i + 4] <= 'F' && mac_addr[i + 4] >= 'A'))) -+ goto out; -+ } -+ else if (mac_addr[i + 4] != ':') -+ goto out; -+ } -+ -+ for (i = 0; i < MAC_ADDR_LEN; i++) -+ pdata->dev_addr[i] = CTOI(mac_addr[i * 3 + 4]) * 16 + CTOI(mac_addr[i * 3 + 5]); -+ -+ return 0; -+out: -+ -+ printk("Failed to read MAC addres in medium storage, use default mac\n"); -+ return -1; -+} -+ -+ -+/* -+ * Search AK98 MAC, allocate space and register it -+ */ -+static int __devinit ak_mac_probe(struct platform_device *pdev) -+{ -+ struct ak_mac_data *pdata = pdev->dev.platform_data; -+ struct mac_info *db; /* Point a board information structure */ -+ struct net_device *ndev; -+ int ret = 0; -+ int iosize; -+ -+ //cpu_clk_2x_switch(); -+ -+ /* Init network device */ -+ ndev = alloc_etherdev(sizeof(struct mac_info)); -+ if (!ndev) { -+ dev_err(&pdev->dev, "could not allocate device.\n"); -+ return -ENOMEM; -+ } -+ -+ SET_NETDEV_DEV(ndev, &pdev->dev); -+ -+ dev_dbg(&pdev->dev, "ak_mac_probe()\n"); -+ -+ /* setup board info structure */ -+ db = netdev_priv(ndev); -+ -+ db->dev = &pdev->dev; -+ db->ndev = ndev; -+ -+ /* get the register and irq resource */ -+ db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -+ -+ if (db->addr_res == NULL || db->irq_res == NULL) { -+ dev_err(db->dev, "insufficient resources\n"); -+ ret = -ENOENT; -+ goto out; -+ } -+ -+ iosize = resource_size(db->addr_res); -+ db->addr_req = request_mem_region(db->addr_res->start, iosize, -+ pdev->name); -+ -+ if (db->addr_req == NULL) { -+ dev_err(db->dev, "cannot claim address reg area\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ db->io_addr = ioremap(db->addr_res->start, iosize); -+ -+ if (db->io_addr == NULL) { -+ dev_err(db->dev, "failed to ioremap address reg\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+#if 0 -+ /* get mac clock */ -+ db->clk = clk_get(db->dev, "mac_clk"); -+ if (IS_ERR(db->clk)) { -+ dbg("clocks missing"); -+ ret = -ENODEV; -+ goto out; -+ } -+ spin_lock_init(&db->lock); -+#endif -+ /* fill in parameters for net-dev structure */ -+ ndev->base_addr = (unsigned long)db->io_addr; -+ ndev->irq = db->irq_res->start; -+ -+ /* driver system function */ -+ ether_setup(ndev); -+ -+ ndev->netdev_ops = &ak_mac_netdev_ops; -+ ndev->watchdog_timeo = msecs_to_jiffies(5000); -+ -+ /* get Ethernet address from flash area */ -+ if ((get_mac_addr(pdata) < 0)||(!is_valid_ether_addr(pdata->dev_addr))) { -+ -+ dev_warn(db->dev, "%s, Invalid Ethernet address. " -+ "Generate software assigned\n\trandom Ethernet address.\n", ndev->name); -+ -+ /* Generate software assigned random Ethernet address */ -+ random_ether_addr(pdata->dev_addr); -+ if (!is_valid_ether_addr(pdata->dev_addr)) -+ dev_warn(db->dev, "%s: Invalid Ethernet address. Please " -+ "set using ifconfig\n", ndev->name); -+ } -+ -+ memcpy(ndev->dev_addr, pdata->dev_addr, 6); -+ -+ pMacBase = db->io_addr; -+ -+ psysbase = AK_VA_SYSCTRL; -+ if(psysbase == NULL) -+ { -+ dbg("sysbase alloc error!"); -+ } -+ -+ platform_set_drvdata(pdev, ndev); -+ INIT_WORK(&db->link_chg_task, ak_mac_link_chg_task); -+ ret = register_netdev(ndev); -+ -+ if (ret == 0) -+ printk(KERN_INFO "%s: ak98_mac at %p IRQ %d MAC: %pM\n", -+ ndev->name, db->io_addr, ndev->irq, ndev->dev_addr); -+ -+ return 0; -+out: -+ dev_err(db->dev, "not found (%d).\n", ret); -+ -+ ak_mac_release_board(pdev, db); -+ free_netdev(ndev); -+ -+ return ret; -+} -+ -+static int -+ak_mac_drv_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct net_device *ndev = platform_get_drvdata(pdev); -+ mac_info_t *db = netdev_priv(ndev); -+ -+ if (ndev) { -+ db = netdev_priv(ndev); -+ db->in_suspend = 1; -+ -+ if (netif_running(ndev)) { -+ netif_device_detach(ndev); -+ -+ //close_2x(); -+ MacRest(); -+ MIIWrite(MII_BMCR, MIIRead(MII_BMCR) | 0x800); -+ //MIIWrite(0x29, MIIRead(0x29) | 0x8000); -+ // open_2x(); -+ -+ // clk_disable(db->clk); -+ } -+ } -+ return 0; -+} -+ -+static int -+ak_mac_drv_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct net_device *ndev = platform_get_drvdata(pdev); -+ mac_info_t *db = netdev_priv(ndev); -+ -+ if (ndev) { -+ if (netif_running(ndev)) { -+ //clk_enable(db->clk); -+ -+ /* Initialize AK98 MAC */ -+ if (MacInit(ndev) == false) { -+ printk("mac init fail\n"); -+ return -ENOMEM; -+ } else -+ printk("mac init success!\n"); -+ -+ schedule_work(&db->link_chg_task); -+ netif_device_attach(ndev); -+ } -+ } -+ return 0; -+} -+ -+static struct dev_pm_ops ak_mac_drv_pm_ops = { -+ .suspend = ak_mac_drv_suspend, -+ .resume = ak_mac_drv_resume, -+}; -+ -+static int __devexit ak_mac_drv_remove(struct platform_device *pdev) -+{ -+ struct net_device *ndev = platform_get_drvdata(pdev); -+ struct ak_mac_data *pdata = pdev->dev.platform_data; -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ unregister_netdev(ndev); -+ ak_mac_release_board(pdev, (mac_info_t *) netdev_priv(ndev)); -+ Macexit(ndev); -+ free_netdev(ndev); /* free device structure */ -+ -+ //mac power off -+ if (pdata != NULL) -+ ak_gpio_setpin(pdata->pwr_gpio.pin, !pdata->pwr_gpio.value); -+ -+ dev_dbg(&pdev->dev, "released and freed device\n"); -+ return 0; -+} -+ -+static struct platform_driver ak_mac_driver = { -+ .driver = { -+ .name = "ak_ethernet", -+ .owner = THIS_MODULE, -+ .pm = &ak_mac_drv_pm_ops, -+ }, -+ .probe = ak_mac_probe, -+ .remove = __devexit_p(ak_mac_drv_remove), -+}; -+ -+static int __init ak_mac_init(void) -+{ -+ printk(KERN_INFO "%s Ethernet Driver, V%s\n", MACNAME, DRV_VERSION); -+ -+ return platform_driver_register(&ak_mac_driver); -+} -+ -+static void __exit ak_mac_cleanup(void) -+{ -+ platform_driver_unregister(&ak_mac_driver); -+} -+ -+module_init(ak_mac_init); -+module_exit(ak_mac_cleanup); -+ -+MODULE_AUTHOR("Tang Anyang, Zhang Jingyuan (C) ANYKA"); -+MODULE_DESCRIPTION("Anyka MAC driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ak-ethernet"); -diff --git a/drivers/net/ethernet/ak-ethernet/eth_ops.h b/drivers/net/ethernet/ak-ethernet/eth_ops.h -new file mode 100644 -index 00000000..de632b34 ---- /dev/null -+++ b/drivers/net/ethernet/ak-ethernet/eth_ops.h -@@ -0,0 +1,8 @@ -+#ifndef _ETHERNET_OPERATION_H_ -+#define _ETHERNET_OPERATION_H_ -+ -+#define FLAG(_off) ((unsigned int)1 << (_off)) -+#define BIT_SET(_val, _off) ( (_val) |= FLAG(_off) ) //set the bit -+#define BIT_CLEAR(_val, _off) ( (_val) &= ~FLAG(_off) ) // clear the bit -+#define BIT_TEST(_val, _off) (0 != ( (_val) & FLAG(_off) ) ) //test the bit -+#endif -diff --git a/drivers/net/ethernet/ak-ethernet/phyhw.h b/drivers/net/ethernet/ak-ethernet/phyhw.h -new file mode 100755 -index 00000000..a4caf42c ---- /dev/null -+++ b/drivers/net/ethernet/ak-ethernet/phyhw.h -@@ -0,0 +1,140 @@ -+#ifndef _ANYKA_PHY_REG_H_ -+#define _ANYKA_PHY_REG_H_ -+/********************* PHY regs definition ***************************/ -+#define LC_10H 0x01 -+#define LC_10F 0x02 -+#define LC_100H 0x04 -+#define LC_100F 0x08 -+#define LC_1000F 0x10 -+#define LC_ALL (LC_10H|LC_10F|LC_100H|LC_100F|LC_1000F) -+ -+/* PHY Control Register */ -+#define MII_BMCR 0x00 -+ #define BMCR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ -+ #define BMCR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ -+ #define BMCR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ -+ #define BMCR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ -+ #define BMCR_ISOLATE 0x0400 /* Isolate PHY from MII */ -+ #define BMCR_POWER_DOWN 0x0800 /* Power down */ -+ #define BMCR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ -+ #define BMCR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ -+ #define BMCR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ -+ #define BMCR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ -+ #define BMCR_SPEED_MASK 0x2040 -+ #define BMCR_SPEED_1000 0x0040 -+ #define BMCR_SPEED_100 0x2000 -+ #define BMCR_SPEED_10 0x0000 -+ -+/* PHY Status Register */ -+#define MII_BMSR 0x01 -+ #define BMMSR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -+ #define BMSR_JABBER_DETECT 0x0002 /* Jabber Detected */ -+ #define BMSR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -+ #define BMSR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -+ #define BMSR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -+ #define BMSR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -+ #define BMSR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -+ #define BMSR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -+ #define BMSR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -+ #define BMSR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -+ #define BMSR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -+ #define BMSR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -+ #define BMSR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -+ #define BMMII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -+ #define BMMII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ -+ -+#define MII_PHYSID1 0x02 -+#define MII_PHYSID2 0x03 -+#define L1D_MPW_PHYID1 0xD01C /* V7 */ -+#define L1D_MPW_PHYID2 0xD01D /* V1-V6 */ -+#define L1D_MPW_PHYID3 0xD01E /* V8 */ -+ -+ -+/* Autoneg Advertisement Register */ -+#define MII_ADVERTISE 0x04 -+ #define ADVERTISE_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ -+ #define ADVERTISE_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ -+ #define ADVERTISE_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ -+ #define ADVERTISE_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ -+ #define ADVERTISE_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ -+ #define ADVERTISE_100T4_CAPS 0x0200 /* 100T4 Capable */ -+ #define ADVERTISE_PAUSE 0x0400 /* Pause operation desired */ -+ #define ADVERTISE_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ -+ #define ADVERTISE_REMOTE_FAULT 0x2000 /* Remote Fault detected */ -+ #define ADVERTISE_NEXT_PAGE 0x8000 /* Next Page ability supported */ -+ #define ADVERTISE_SPEED_MASK 0x01E0 -+ #define ADVERTISE_DEFAULT_CAP 0x0DE0 -+ -+/* Link partner ability register */ -+#define MII_LPA 0x05 -+ #define LPA_SLCT 0x001 /* Same as advertise selector */ -+ #define LPA_10HALF 0x002 /* Can do 10mbps half-duplex */ -+ #define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ -+ #define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ -+ #define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ -+ #define LPA_100BASE4 0x0200 /* 100BASE-T4 */ -+ #define LPA_PAUSE 0x0400 /* PAUSE */ -+ #define LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */ -+ #define LPA_RFAULT 0x2000 /* Link partner faulted */ -+ #define LPA_LPACK 0x4000 /* Link partner acked us */ -+ #define LPA_NPAGE 0x8000 /* Next page bit */ -+ -+/* 1000BASE-T Control Register */ -+#define MII_GIGA_CR 0x09 -+ #define GIGA_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ -+ #define GIGA_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ -+ #define GIGA_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ -+ /* 0=DTE device */ -+ #define GIGA_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ -+ /* 0=Configure PHY as Slave */ -+ #define GIGA_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ -+ /* 0=Automatic Master/Slave config */ -+ #define GIGA_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ -+ #define GIGA_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ -+ #define GIGA_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ -+ #define GIGA_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ -+ #define GIGA_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ -+ #define GIGA_CR_1000T_SPEED_MASK 0x0300 -+ #define GIGA_CR_1000T_DEFAULT_CAP 0x0300 -+ -+/* 1000BASE-T Status Register */ -+#define MII_GIGA_SR 0x0A -+ -+/* PHY Specific Status Register */ -+#define MII_GIGA_PSSR 0x11 -+ #define GIGA_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ -+ #define GIGA_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ -+ #define GIGA_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ -+ #define GIGA_PSSR_10MBS 0x0000 /* 00=10Mbs */ -+ #define GIGA_PSSR_100MBS 0x4000 /* 01=100Mbs */ -+ #define GIGA_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ -+ -+/* PHY Interrupt Enable Register */ -+#define MII_IER 0x12 -+ #define IER_LINK_UP 0x0400 -+ #define IER_LINK_DOWN 0x0800 -+ -+/* PHY Interrupt Status Register */ -+#define MII_ISR 0x13 -+ #define ISR_LINK_UP 0x0400 -+ #define ISR_LINK_DOWN 0x0800 -+ -+/* Cable-Detect-Test Control Register */ -+#define MII_CDTC 0x16 -+ #define CDTC_EN 1 /* sc */ -+ #define CDTC_PAIR_OFFSET 8 -+ #define CDTC_PAIR_MASK 3 -+ -+ -+/* Cable-Detect-Test Status Register */ -+#define MII_CDTS 0x1C -+ #define CDTS_STATUS_OFFSET 8 -+ #define CDTS_STATUS_MASK 3 -+ #define CDTS_STATUS_NORMAL 0 -+ #define CDTS_STATUS_SHORT 1 -+ #define CDTS_STATUS_OPEN 2 -+ #define CDTS_STATUS_INVALID 3 -+ -+#define MII_DBG_ADDR 0x1D -+#define MII_DBG_DATA 0x1E -+#endif -\ No newline at end of file -diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig -index 872df3ef..7936ae4c 100644 ---- a/drivers/net/ppp/Kconfig -+++ b/drivers/net/ppp/Kconfig -@@ -148,6 +148,23 @@ config PPPOL2TP - used by ISPs and enterprises to tunnel PPP traffic over UDP - tunnels. L2TP is replacing PPTP for VPN uses. - -+config PPPOLAC -+ tristate "PPP on L2TP Access Concentrator" -+ depends on PPP && INET -+ help -+ L2TP (RFC 2661) is a tunneling protocol widely used in virtual private -+ networks. This driver handles L2TP data packets between a UDP socket -+ and a PPP channel, but only permits one session per socket. Thus it is -+ fairly simple and suited for clients. -+ -+config PPPOPNS -+ tristate "PPP on PPTP Network Server" -+ depends on PPP && INET -+ help -+ PPTP (RFC 2637) is a tunneling protocol widely used in virtual private -+ networks. This driver handles PPTP data packets between a RAW socket -+ and a PPP channel. It is fairly simple and easy to use. -+ - config PPP_ASYNC - tristate "PPP support for async serial ports" - depends on PPP -diff --git a/drivers/net/ppp/Makefile b/drivers/net/ppp/Makefile -index a6b6297b..d283d03c 100644 ---- a/drivers/net/ppp/Makefile -+++ b/drivers/net/ppp/Makefile -@@ -11,3 +11,5 @@ obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o - obj-$(CONFIG_PPPOE) += pppox.o pppoe.o - obj-$(CONFIG_PPPOL2TP) += pppox.o - obj-$(CONFIG_PPTP) += pppox.o pptp.o -+obj-$(CONFIG_PPPOLAC) += pppox.o pppolac.o -+obj-$(CONFIG_PPPOPNS) += pppox.o pppopns.o -diff --git a/drivers/net/ppp/pppolac.c b/drivers/net/ppp/pppolac.c -new file mode 100644 -index 00000000..a5d3d634 ---- /dev/null -+++ b/drivers/net/ppp/pppolac.c -@@ -0,0 +1,449 @@ -+/* drivers/net/pppolac.c -+ * -+ * Driver for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661) -+ * -+ * Copyright (C) 2009 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+/* This driver handles L2TP data packets between a UDP socket and a PPP channel. -+ * The socket must keep connected, and only one session per socket is permitted. -+ * Sequencing of outgoing packets is controlled by LNS. Incoming packets with -+ * sequences are reordered within a sliding window of one second. Currently -+ * reordering only happens when a packet is received. It is done for simplicity -+ * since no additional locks or threads are required. This driver only works on -+ * IPv4 due to the lack of UDP encapsulation support in IPv6. */ -+ -+#include <linux/module.h> -+#include <linux/jiffies.h> -+#include <linux/workqueue.h> -+#include <linux/skbuff.h> -+#include <linux/file.h> -+#include <linux/netdevice.h> -+#include <linux/net.h> -+#include <linux/udp.h> -+#include <linux/ppp_defs.h> -+#include <linux/if_ppp.h> -+#include <linux/if_pppox.h> -+#include <linux/ppp_channel.h> -+#include <net/tcp_states.h> -+#include <asm/uaccess.h> -+ -+#define L2TP_CONTROL_BIT 0x80 -+#define L2TP_LENGTH_BIT 0x40 -+#define L2TP_SEQUENCE_BIT 0x08 -+#define L2TP_OFFSET_BIT 0x02 -+#define L2TP_VERSION 0x02 -+#define L2TP_VERSION_MASK 0x0F -+ -+#define PPP_ADDR 0xFF -+#define PPP_CTRL 0x03 -+ -+union unaligned { -+ __u32 u32; -+} __attribute__((packed)); -+ -+static inline union unaligned *unaligned(void *ptr) -+{ -+ return (union unaligned *)ptr; -+} -+ -+struct meta { -+ __u32 sequence; -+ __u32 timestamp; -+}; -+ -+static inline struct meta *skb_meta(struct sk_buff *skb) -+{ -+ return (struct meta *)skb->cb; -+} -+ -+/******************************************************************************/ -+ -+static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb) -+{ -+ struct sock *sk = (struct sock *)sk_udp->sk_user_data; -+ struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac; -+ struct meta *meta = skb_meta(skb); -+ __u32 now = jiffies; -+ __u8 bits; -+ __u8 *ptr; -+ -+ /* Drop the packet if L2TP header is missing. */ -+ if (skb->len < sizeof(struct udphdr) + 6) -+ goto drop; -+ -+ /* Put it back if it is a control packet. */ -+ if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT) -+ return opt->backlog_rcv(sk_udp, skb); -+ -+ /* Skip UDP header. */ -+ skb_pull(skb, sizeof(struct udphdr)); -+ -+ /* Check the version. */ -+ if ((skb->data[1] & L2TP_VERSION_MASK) != L2TP_VERSION) -+ goto drop; -+ bits = skb->data[0]; -+ ptr = &skb->data[2]; -+ -+ /* Check the length if it is present. */ -+ if (bits & L2TP_LENGTH_BIT) { -+ if ((ptr[0] << 8 | ptr[1]) != skb->len) -+ goto drop; -+ ptr += 2; -+ } -+ -+ /* Skip all fields including optional ones. */ -+ if (!skb_pull(skb, 6 + (bits & L2TP_SEQUENCE_BIT ? 4 : 0) + -+ (bits & L2TP_LENGTH_BIT ? 2 : 0) + -+ (bits & L2TP_OFFSET_BIT ? 2 : 0))) -+ goto drop; -+ -+ /* Skip the offset padding if it is present. */ -+ if (bits & L2TP_OFFSET_BIT && -+ !skb_pull(skb, skb->data[-2] << 8 | skb->data[-1])) -+ goto drop; -+ -+ /* Check the tunnel and the session. */ -+ if (unaligned(ptr)->u32 != opt->local) -+ goto drop; -+ -+ /* Check the sequence if it is present. */ -+ if (bits & L2TP_SEQUENCE_BIT) { -+ meta->sequence = ptr[4] << 8 | ptr[5]; -+ if ((__s16)(meta->sequence - opt->recv_sequence) < 0) -+ goto drop; -+ } -+ -+ /* Skip PPP address and control if they are present. */ -+ if (skb->len >= 2 && skb->data[0] == PPP_ADDR && -+ skb->data[1] == PPP_CTRL) -+ skb_pull(skb, 2); -+ -+ /* Fix PPP protocol if it is compressed. */ -+ if (skb->len >= 1 && skb->data[0] & 1) -+ skb_push(skb, 1)[0] = 0; -+ -+ /* Drop the packet if PPP protocol is missing. */ -+ if (skb->len < 2) -+ goto drop; -+ -+ /* Perform reordering if sequencing is enabled. */ -+ atomic_set(&opt->sequencing, bits & L2TP_SEQUENCE_BIT); -+ if (bits & L2TP_SEQUENCE_BIT) { -+ struct sk_buff *skb1; -+ -+ /* Insert the packet into receive queue in order. */ -+ skb_set_owner_r(skb, sk); -+ skb_queue_walk(&sk->sk_receive_queue, skb1) { -+ struct meta *meta1 = skb_meta(skb1); -+ __s16 order = meta->sequence - meta1->sequence; -+ if (order == 0) -+ goto drop; -+ if (order < 0) { -+ meta->timestamp = meta1->timestamp; -+ skb_insert(skb1, skb, &sk->sk_receive_queue); -+ skb = NULL; -+ break; -+ } -+ } -+ if (skb) { -+ meta->timestamp = now; -+ skb_queue_tail(&sk->sk_receive_queue, skb); -+ } -+ -+ /* Remove packets from receive queue as long as -+ * 1. the receive buffer is full, -+ * 2. they are queued longer than one second, or -+ * 3. there are no missing packets before them. */ -+ skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) { -+ meta = skb_meta(skb); -+ if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && -+ now - meta->timestamp < HZ && -+ meta->sequence != opt->recv_sequence) -+ break; -+ skb_unlink(skb, &sk->sk_receive_queue); -+ opt->recv_sequence = (__u16)(meta->sequence + 1); -+ skb_orphan(skb); -+ ppp_input(&pppox_sk(sk)->chan, skb); -+ } -+ return NET_RX_SUCCESS; -+ } -+ -+ /* Flush receive queue if sequencing is disabled. */ -+ skb_queue_purge(&sk->sk_receive_queue); -+ skb_orphan(skb); -+ ppp_input(&pppox_sk(sk)->chan, skb); -+ return NET_RX_SUCCESS; -+drop: -+ kfree_skb(skb); -+ return NET_RX_DROP; -+} -+ -+static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb) -+{ -+ sock_hold(sk_udp); -+ sk_receive_skb(sk_udp, skb, 0); -+ return 0; -+} -+ -+static struct sk_buff_head delivery_queue; -+ -+static void pppolac_xmit_core(struct work_struct *delivery_work) -+{ -+ mm_segment_t old_fs = get_fs(); -+ struct sk_buff *skb; -+ -+ set_fs(KERNEL_DS); -+ while ((skb = skb_dequeue(&delivery_queue))) { -+ struct sock *sk_udp = skb->sk; -+ struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; -+ struct msghdr msg = { -+ .msg_iov = (struct iovec *)&iov, -+ .msg_iovlen = 1, -+ .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT, -+ }; -+ sk_udp->sk_prot->sendmsg(NULL, sk_udp, &msg, skb->len); -+ kfree_skb(skb); -+ } -+ set_fs(old_fs); -+} -+ -+static DECLARE_WORK(delivery_work, pppolac_xmit_core); -+ -+static int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb) -+{ -+ struct sock *sk_udp = (struct sock *)chan->private; -+ struct pppolac_opt *opt = &pppox_sk(sk_udp->sk_user_data)->proto.lac; -+ -+ /* Install PPP address and control. */ -+ skb_push(skb, 2); -+ skb->data[0] = PPP_ADDR; -+ skb->data[1] = PPP_CTRL; -+ -+ /* Install L2TP header. */ -+ if (atomic_read(&opt->sequencing)) { -+ skb_push(skb, 10); -+ skb->data[0] = L2TP_SEQUENCE_BIT; -+ skb->data[6] = opt->xmit_sequence >> 8; -+ skb->data[7] = opt->xmit_sequence; -+ skb->data[8] = 0; -+ skb->data[9] = 0; -+ opt->xmit_sequence++; -+ } else { -+ skb_push(skb, 6); -+ skb->data[0] = 0; -+ } -+ skb->data[1] = L2TP_VERSION; -+ unaligned(&skb->data[2])->u32 = opt->remote; -+ -+ /* Now send the packet via the delivery queue. */ -+ skb_set_owner_w(skb, sk_udp); -+ skb_queue_tail(&delivery_queue, skb); -+ schedule_work(&delivery_work); -+ return 1; -+} -+ -+/******************************************************************************/ -+ -+static struct ppp_channel_ops pppolac_channel_ops = { -+ .start_xmit = pppolac_xmit, -+}; -+ -+static int pppolac_connect(struct socket *sock, struct sockaddr *useraddr, -+ int addrlen, int flags) -+{ -+ struct sock *sk = sock->sk; -+ struct pppox_sock *po = pppox_sk(sk); -+ struct sockaddr_pppolac *addr = (struct sockaddr_pppolac *)useraddr; -+ struct socket *sock_udp = NULL; -+ struct sock *sk_udp; -+ int error; -+ -+ if (addrlen != sizeof(struct sockaddr_pppolac) || -+ !addr->local.tunnel || !addr->local.session || -+ !addr->remote.tunnel || !addr->remote.session) { -+ return -EINVAL; -+ } -+ -+ lock_sock(sk); -+ error = -EALREADY; -+ if (sk->sk_state != PPPOX_NONE) -+ goto out; -+ -+ sock_udp = sockfd_lookup(addr->udp_socket, &error); -+ if (!sock_udp) -+ goto out; -+ sk_udp = sock_udp->sk; -+ lock_sock(sk_udp); -+ -+ /* Remove this check when IPv6 supports UDP encapsulation. */ -+ error = -EAFNOSUPPORT; -+ if (sk_udp->sk_family != AF_INET) -+ goto out; -+ error = -EPROTONOSUPPORT; -+ if (sk_udp->sk_protocol != IPPROTO_UDP) -+ goto out; -+ error = -EDESTADDRREQ; -+ if (sk_udp->sk_state != TCP_ESTABLISHED) -+ goto out; -+ error = -EBUSY; -+ if (udp_sk(sk_udp)->encap_type || sk_udp->sk_user_data) -+ goto out; -+ if (!sk_udp->sk_bound_dev_if) { -+ struct dst_entry *dst = sk_dst_get(sk_udp); -+ error = -ENODEV; -+ if (!dst) -+ goto out; -+ sk_udp->sk_bound_dev_if = dst->dev->ifindex; -+ dst_release(dst); -+ } -+ -+ po->chan.hdrlen = 12; -+ po->chan.private = sk_udp; -+ po->chan.ops = &pppolac_channel_ops; -+ po->chan.mtu = PPP_MRU - 80; -+ po->proto.lac.local = unaligned(&addr->local)->u32; -+ po->proto.lac.remote = unaligned(&addr->remote)->u32; -+ atomic_set(&po->proto.lac.sequencing, 1); -+ po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv; -+ -+ error = ppp_register_channel(&po->chan); -+ if (error) -+ goto out; -+ -+ sk->sk_state = PPPOX_CONNECTED; -+ udp_sk(sk_udp)->encap_type = UDP_ENCAP_L2TPINUDP; -+ udp_sk(sk_udp)->encap_rcv = pppolac_recv; -+ sk_udp->sk_backlog_rcv = pppolac_recv_core; -+ sk_udp->sk_user_data = sk; -+out: -+ if (sock_udp) { -+ release_sock(sk_udp); -+ if (error) -+ sockfd_put(sock_udp); -+ } -+ release_sock(sk); -+ return error; -+} -+ -+static int pppolac_release(struct socket *sock) -+{ -+ struct sock *sk = sock->sk; -+ -+ if (!sk) -+ return 0; -+ -+ lock_sock(sk); -+ if (sock_flag(sk, SOCK_DEAD)) { -+ release_sock(sk); -+ return -EBADF; -+ } -+ -+ if (sk->sk_state != PPPOX_NONE) { -+ struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private; -+ lock_sock(sk_udp); -+ skb_queue_purge(&sk->sk_receive_queue); -+ pppox_unbind_sock(sk); -+ udp_sk(sk_udp)->encap_type = 0; -+ udp_sk(sk_udp)->encap_rcv = NULL; -+ sk_udp->sk_backlog_rcv = pppox_sk(sk)->proto.lac.backlog_rcv; -+ sk_udp->sk_user_data = NULL; -+ release_sock(sk_udp); -+ sockfd_put(sk_udp->sk_socket); -+ } -+ -+ sock_orphan(sk); -+ sock->sk = NULL; -+ release_sock(sk); -+ sock_put(sk); -+ return 0; -+} -+ -+/******************************************************************************/ -+ -+static struct proto pppolac_proto = { -+ .name = "PPPOLAC", -+ .owner = THIS_MODULE, -+ .obj_size = sizeof(struct pppox_sock), -+}; -+ -+static struct proto_ops pppolac_proto_ops = { -+ .family = PF_PPPOX, -+ .owner = THIS_MODULE, -+ .release = pppolac_release, -+ .bind = sock_no_bind, -+ .connect = pppolac_connect, -+ .socketpair = sock_no_socketpair, -+ .accept = sock_no_accept, -+ .getname = sock_no_getname, -+ .poll = sock_no_poll, -+ .ioctl = pppox_ioctl, -+ .listen = sock_no_listen, -+ .shutdown = sock_no_shutdown, -+ .setsockopt = sock_no_setsockopt, -+ .getsockopt = sock_no_getsockopt, -+ .sendmsg = sock_no_sendmsg, -+ .recvmsg = sock_no_recvmsg, -+ .mmap = sock_no_mmap, -+}; -+ -+static int pppolac_create(struct net *net, struct socket *sock) -+{ -+ struct sock *sk; -+ -+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppolac_proto); -+ if (!sk) -+ return -ENOMEM; -+ -+ sock_init_data(sock, sk); -+ sock->state = SS_UNCONNECTED; -+ sock->ops = &pppolac_proto_ops; -+ sk->sk_protocol = PX_PROTO_OLAC; -+ sk->sk_state = PPPOX_NONE; -+ return 0; -+} -+ -+/******************************************************************************/ -+ -+static struct pppox_proto pppolac_pppox_proto = { -+ .create = pppolac_create, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init pppolac_init(void) -+{ -+ int error; -+ -+ error = proto_register(&pppolac_proto, 0); -+ if (error) -+ return error; -+ -+ error = register_pppox_proto(PX_PROTO_OLAC, &pppolac_pppox_proto); -+ if (error) -+ proto_unregister(&pppolac_proto); -+ else -+ skb_queue_head_init(&delivery_queue); -+ return error; -+} -+ -+static void __exit pppolac_exit(void) -+{ -+ unregister_pppox_proto(PX_PROTO_OLAC); -+ proto_unregister(&pppolac_proto); -+} -+ -+module_init(pppolac_init); -+module_exit(pppolac_exit); -+ -+MODULE_DESCRIPTION("PPP on L2TP Access Concentrator (PPPoLAC)"); -+MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/net/ppp/pppopns.c b/drivers/net/ppp/pppopns.c -new file mode 100644 -index 00000000..6016d29c ---- /dev/null -+++ b/drivers/net/ppp/pppopns.c -@@ -0,0 +1,428 @@ -+/* drivers/net/pppopns.c -+ * -+ * Driver for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637) -+ * -+ * Copyright (C) 2009 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+/* This driver handles PPTP data packets between a RAW socket and a PPP channel. -+ * The socket is created in the kernel space and connected to the same address -+ * of the control socket. Outgoing packets are always sent with sequences but -+ * without acknowledgements. Incoming packets with sequences are reordered -+ * within a sliding window of one second. Currently reordering only happens when -+ * a packet is received. It is done for simplicity since no additional locks or -+ * threads are required. This driver should work on both IPv4 and IPv6. */ -+ -+#include <linux/module.h> -+#include <linux/jiffies.h> -+#include <linux/workqueue.h> -+#include <linux/skbuff.h> -+#include <linux/file.h> -+#include <linux/netdevice.h> -+#include <linux/net.h> -+#include <linux/ppp_defs.h> -+#include <linux/if.h> -+#include <linux/if_ppp.h> -+#include <linux/if_pppox.h> -+#include <linux/ppp_channel.h> -+#include <asm/uaccess.h> -+ -+#define GRE_HEADER_SIZE 8 -+ -+#define PPTP_GRE_BITS htons(0x2001) -+#define PPTP_GRE_BITS_MASK htons(0xEF7F) -+#define PPTP_GRE_SEQ_BIT htons(0x1000) -+#define PPTP_GRE_ACK_BIT htons(0x0080) -+#define PPTP_GRE_TYPE htons(0x880B) -+ -+#define PPP_ADDR 0xFF -+#define PPP_CTRL 0x03 -+ -+struct header { -+ __u16 bits; -+ __u16 type; -+ __u16 length; -+ __u16 call; -+ __u32 sequence; -+} __attribute__((packed)); -+ -+struct meta { -+ __u32 sequence; -+ __u32 timestamp; -+}; -+ -+static inline struct meta *skb_meta(struct sk_buff *skb) -+{ -+ return (struct meta *)skb->cb; -+} -+ -+/******************************************************************************/ -+ -+static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb) -+{ -+ struct sock *sk = (struct sock *)sk_raw->sk_user_data; -+ struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns; -+ struct meta *meta = skb_meta(skb); -+ __u32 now = jiffies; -+ struct header *hdr; -+ -+ /* Skip transport header */ -+ skb_pull(skb, skb_transport_header(skb) - skb->data); -+ -+ /* Drop the packet if GRE header is missing. */ -+ if (skb->len < GRE_HEADER_SIZE) -+ goto drop; -+ hdr = (struct header *)skb->data; -+ -+ /* Check the header. */ -+ if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local || -+ (hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS) -+ goto drop; -+ -+ /* Skip all fields including optional ones. */ -+ if (!skb_pull(skb, GRE_HEADER_SIZE + -+ (hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) + -+ (hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0))) -+ goto drop; -+ -+ /* Check the length. */ -+ if (skb->len != ntohs(hdr->length)) -+ goto drop; -+ -+ /* Check the sequence if it is present. */ -+ if (hdr->bits & PPTP_GRE_SEQ_BIT) { -+ meta->sequence = ntohl(hdr->sequence); -+ if ((__s32)(meta->sequence - opt->recv_sequence) < 0) -+ goto drop; -+ } -+ -+ /* Skip PPP address and control if they are present. */ -+ if (skb->len >= 2 && skb->data[0] == PPP_ADDR && -+ skb->data[1] == PPP_CTRL) -+ skb_pull(skb, 2); -+ -+ /* Fix PPP protocol if it is compressed. */ -+ if (skb->len >= 1 && skb->data[0] & 1) -+ skb_push(skb, 1)[0] = 0; -+ -+ /* Drop the packet if PPP protocol is missing. */ -+ if (skb->len < 2) -+ goto drop; -+ -+ /* Perform reordering if sequencing is enabled. */ -+ if (hdr->bits & PPTP_GRE_SEQ_BIT) { -+ struct sk_buff *skb1; -+ -+ /* Insert the packet into receive queue in order. */ -+ skb_set_owner_r(skb, sk); -+ skb_queue_walk(&sk->sk_receive_queue, skb1) { -+ struct meta *meta1 = skb_meta(skb1); -+ __s32 order = meta->sequence - meta1->sequence; -+ if (order == 0) -+ goto drop; -+ if (order < 0) { -+ meta->timestamp = meta1->timestamp; -+ skb_insert(skb1, skb, &sk->sk_receive_queue); -+ skb = NULL; -+ break; -+ } -+ } -+ if (skb) { -+ meta->timestamp = now; -+ skb_queue_tail(&sk->sk_receive_queue, skb); -+ } -+ -+ /* Remove packets from receive queue as long as -+ * 1. the receive buffer is full, -+ * 2. they are queued longer than one second, or -+ * 3. there are no missing packets before them. */ -+ skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) { -+ meta = skb_meta(skb); -+ if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && -+ now - meta->timestamp < HZ && -+ meta->sequence != opt->recv_sequence) -+ break; -+ skb_unlink(skb, &sk->sk_receive_queue); -+ opt->recv_sequence = meta->sequence + 1; -+ skb_orphan(skb); -+ ppp_input(&pppox_sk(sk)->chan, skb); -+ } -+ return NET_RX_SUCCESS; -+ } -+ -+ /* Flush receive queue if sequencing is disabled. */ -+ skb_queue_purge(&sk->sk_receive_queue); -+ skb_orphan(skb); -+ ppp_input(&pppox_sk(sk)->chan, skb); -+ return NET_RX_SUCCESS; -+drop: -+ kfree_skb(skb); -+ return NET_RX_DROP; -+} -+ -+static void pppopns_recv(struct sock *sk_raw, int length) -+{ -+ struct sk_buff *skb; -+ while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) { -+ sock_hold(sk_raw); -+ sk_receive_skb(sk_raw, skb, 0); -+ } -+} -+ -+static struct sk_buff_head delivery_queue; -+ -+static void pppopns_xmit_core(struct work_struct *delivery_work) -+{ -+ mm_segment_t old_fs = get_fs(); -+ struct sk_buff *skb; -+ -+ set_fs(KERNEL_DS); -+ while ((skb = skb_dequeue(&delivery_queue))) { -+ struct sock *sk_raw = skb->sk; -+ struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len}; -+ struct msghdr msg = { -+ .msg_iov = (struct iovec *)&iov, -+ .msg_iovlen = 1, -+ .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT, -+ }; -+ sk_raw->sk_prot->sendmsg(NULL, sk_raw, &msg, skb->len); -+ kfree_skb(skb); -+ } -+ set_fs(old_fs); -+} -+ -+static DECLARE_WORK(delivery_work, pppopns_xmit_core); -+ -+static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb) -+{ -+ struct sock *sk_raw = (struct sock *)chan->private; -+ struct pppopns_opt *opt = &pppox_sk(sk_raw->sk_user_data)->proto.pns; -+ struct header *hdr; -+ __u16 length; -+ -+ /* Install PPP address and control. */ -+ skb_push(skb, 2); -+ skb->data[0] = PPP_ADDR; -+ skb->data[1] = PPP_CTRL; -+ length = skb->len; -+ -+ /* Install PPTP GRE header. */ -+ hdr = (struct header *)skb_push(skb, 12); -+ hdr->bits = PPTP_GRE_BITS | PPTP_GRE_SEQ_BIT; -+ hdr->type = PPTP_GRE_TYPE; -+ hdr->length = htons(length); -+ hdr->call = opt->remote; -+ hdr->sequence = htonl(opt->xmit_sequence); -+ opt->xmit_sequence++; -+ -+ /* Now send the packet via the delivery queue. */ -+ skb_set_owner_w(skb, sk_raw); -+ skb_queue_tail(&delivery_queue, skb); -+ schedule_work(&delivery_work); -+ return 1; -+} -+ -+/******************************************************************************/ -+ -+static struct ppp_channel_ops pppopns_channel_ops = { -+ .start_xmit = pppopns_xmit, -+}; -+ -+static int pppopns_connect(struct socket *sock, struct sockaddr *useraddr, -+ int addrlen, int flags) -+{ -+ struct sock *sk = sock->sk; -+ struct pppox_sock *po = pppox_sk(sk); -+ struct sockaddr_pppopns *addr = (struct sockaddr_pppopns *)useraddr; -+ struct sockaddr_storage ss; -+ struct socket *sock_tcp = NULL; -+ struct socket *sock_raw = NULL; -+ struct sock *sk_tcp; -+ struct sock *sk_raw; -+ int error; -+ -+ if (addrlen != sizeof(struct sockaddr_pppopns)) -+ return -EINVAL; -+ -+ lock_sock(sk); -+ error = -EALREADY; -+ if (sk->sk_state != PPPOX_NONE) -+ goto out; -+ -+ sock_tcp = sockfd_lookup(addr->tcp_socket, &error); -+ if (!sock_tcp) -+ goto out; -+ sk_tcp = sock_tcp->sk; -+ error = -EPROTONOSUPPORT; -+ if (sk_tcp->sk_protocol != IPPROTO_TCP) -+ goto out; -+ addrlen = sizeof(struct sockaddr_storage); -+ error = kernel_getpeername(sock_tcp, (struct sockaddr *)&ss, &addrlen); -+ if (error) -+ goto out; -+ if (!sk_tcp->sk_bound_dev_if) { -+ struct dst_entry *dst = sk_dst_get(sk_tcp); -+ error = -ENODEV; -+ if (!dst) -+ goto out; -+ sk_tcp->sk_bound_dev_if = dst->dev->ifindex; -+ dst_release(dst); -+ } -+ -+ error = sock_create(ss.ss_family, SOCK_RAW, IPPROTO_GRE, &sock_raw); -+ if (error) -+ goto out; -+ sk_raw = sock_raw->sk; -+ sk_raw->sk_bound_dev_if = sk_tcp->sk_bound_dev_if; -+ error = kernel_connect(sock_raw, (struct sockaddr *)&ss, addrlen, 0); -+ if (error) -+ goto out; -+ -+ po->chan.hdrlen = 14; -+ po->chan.private = sk_raw; -+ po->chan.ops = &pppopns_channel_ops; -+ po->chan.mtu = PPP_MRU - 80; -+ po->proto.pns.local = addr->local; -+ po->proto.pns.remote = addr->remote; -+ po->proto.pns.data_ready = sk_raw->sk_data_ready; -+ po->proto.pns.backlog_rcv = sk_raw->sk_backlog_rcv; -+ -+ error = ppp_register_channel(&po->chan); -+ if (error) -+ goto out; -+ -+ sk->sk_state = PPPOX_CONNECTED; -+ lock_sock(sk_raw); -+ sk_raw->sk_data_ready = pppopns_recv; -+ sk_raw->sk_backlog_rcv = pppopns_recv_core; -+ sk_raw->sk_user_data = sk; -+ release_sock(sk_raw); -+out: -+ if (sock_tcp) -+ sockfd_put(sock_tcp); -+ if (error && sock_raw) -+ sock_release(sock_raw); -+ release_sock(sk); -+ return error; -+} -+ -+static int pppopns_release(struct socket *sock) -+{ -+ struct sock *sk = sock->sk; -+ -+ if (!sk) -+ return 0; -+ -+ lock_sock(sk); -+ if (sock_flag(sk, SOCK_DEAD)) { -+ release_sock(sk); -+ return -EBADF; -+ } -+ -+ if (sk->sk_state != PPPOX_NONE) { -+ struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private; -+ lock_sock(sk_raw); -+ skb_queue_purge(&sk->sk_receive_queue); -+ pppox_unbind_sock(sk); -+ sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready; -+ sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv; -+ sk_raw->sk_user_data = NULL; -+ release_sock(sk_raw); -+ sock_release(sk_raw->sk_socket); -+ } -+ -+ sock_orphan(sk); -+ sock->sk = NULL; -+ release_sock(sk); -+ sock_put(sk); -+ return 0; -+} -+ -+/******************************************************************************/ -+ -+static struct proto pppopns_proto = { -+ .name = "PPPOPNS", -+ .owner = THIS_MODULE, -+ .obj_size = sizeof(struct pppox_sock), -+}; -+ -+static struct proto_ops pppopns_proto_ops = { -+ .family = PF_PPPOX, -+ .owner = THIS_MODULE, -+ .release = pppopns_release, -+ .bind = sock_no_bind, -+ .connect = pppopns_connect, -+ .socketpair = sock_no_socketpair, -+ .accept = sock_no_accept, -+ .getname = sock_no_getname, -+ .poll = sock_no_poll, -+ .ioctl = pppox_ioctl, -+ .listen = sock_no_listen, -+ .shutdown = sock_no_shutdown, -+ .setsockopt = sock_no_setsockopt, -+ .getsockopt = sock_no_getsockopt, -+ .sendmsg = sock_no_sendmsg, -+ .recvmsg = sock_no_recvmsg, -+ .mmap = sock_no_mmap, -+}; -+ -+static int pppopns_create(struct net *net, struct socket *sock) -+{ -+ struct sock *sk; -+ -+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppopns_proto); -+ if (!sk) -+ return -ENOMEM; -+ -+ sock_init_data(sock, sk); -+ sock->state = SS_UNCONNECTED; -+ sock->ops = &pppopns_proto_ops; -+ sk->sk_protocol = PX_PROTO_OPNS; -+ sk->sk_state = PPPOX_NONE; -+ return 0; -+} -+ -+/******************************************************************************/ -+ -+static struct pppox_proto pppopns_pppox_proto = { -+ .create = pppopns_create, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init pppopns_init(void) -+{ -+ int error; -+ -+ error = proto_register(&pppopns_proto, 0); -+ if (error) -+ return error; -+ -+ error = register_pppox_proto(PX_PROTO_OPNS, &pppopns_pppox_proto); -+ if (error) -+ proto_unregister(&pppopns_proto); -+ else -+ skb_queue_head_init(&delivery_queue); -+ return error; -+} -+ -+static void __exit pppopns_exit(void) -+{ -+ unregister_pppox_proto(PX_PROTO_OPNS); -+ proto_unregister(&pppopns_proto); -+} -+ -+module_init(pppopns_init); -+module_exit(pppopns_exit); -+ -+MODULE_DESCRIPTION("PPP on PPTP Network Server (PPPoPNS)"); -+MODULE_AUTHOR("Chia-chi Yeh <chiachi@android.com>"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/net/tun.c b/drivers/net/tun.c -index 147b6284..279d860e 100644 ---- a/drivers/net/tun.c -+++ b/drivers/net/tun.c -@@ -1254,6 +1254,12 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, - int vnet_hdr_sz; - int ret; - -+#ifdef CONFIG_ANDROID_PARANOID_NETWORK -+ if (cmd != TUNGETIFF && !capable(CAP_NET_ADMIN)) { -+ return -EPERM; -+ } -+#endif -+ - if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) { - if (copy_from_user(&ifr, argp, ifreq_len)) - return -EFAULT; -diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig -index abd3b71c..d9252ff7 100644 ---- a/drivers/net/wireless/Kconfig -+++ b/drivers/net/wireless/Kconfig -@@ -268,9 +268,15 @@ config MWL8K - To compile this driver as a module, choose M here: the module - will be called mwl8k. If unsure, say N. - -+config WIFI_CONTROL_FUNC -+ bool "Enable WiFi control function abstraction" -+ help -+ Enables Power/Reset/Carddetect function abstraction -+ - source "drivers/net/wireless/ath/Kconfig" - source "drivers/net/wireless/b43/Kconfig" - source "drivers/net/wireless/b43legacy/Kconfig" -+source "drivers/net/wireless/bcmdhd/Kconfig" - source "drivers/net/wireless/brcm80211/Kconfig" - source "drivers/net/wireless/hostap/Kconfig" - source "drivers/net/wireless/ipw2x00/Kconfig" -diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile -index 98db7619..8db066f3 100644 ---- a/drivers/net/wireless/Makefile -+++ b/drivers/net/wireless/Makefile -@@ -59,5 +59,7 @@ obj-$(CONFIG_IWM) += iwmc3200wifi/ - - obj-$(CONFIG_MWIFIEX) += mwifiex/ - -+obj-$(CONFIG_BCMDHD) += bcmdhd/ -+ - obj-$(CONFIG_BRCMFMAC) += brcm80211/ - obj-$(CONFIG_BRCMSMAC) += brcm80211/ -diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig -new file mode 100644 -index 00000000..231ae187 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/Kconfig -@@ -0,0 +1,47 @@ -+config BCMDHD -+ tristate "Broadcom 4329/30 wireless cards support" -+ depends on MMC -+ ---help--- -+ This module adds support for wireless adapters based on -+ Broadcom 4329/30 chipset. -+ -+ This driver uses the kernel's wireless extensions subsystem. -+ -+ If you choose to build a module, it'll be called dhd. Say M if -+ unsure. -+ -+config BCMDHD_FW_PATH -+ depends on BCMDHD -+ string "Firmware path" -+ default "/system/etc/firmware/fw_bcmdhd.bin" -+ ---help--- -+ Path to the firmware file. -+ -+config BCMDHD_NVRAM_PATH -+ depends on BCMDHD -+ string "NVRAM path" -+ default "/system/etc/wifi/bcmdhd.cal" -+ ---help--- -+ Path to the calibration file. -+ -+config BCMDHD_WEXT -+ bool "Enable WEXT support" -+ depends on BCMDHD && CFG80211 = n -+ select WIRELESS_EXT -+ select WEXT_PRIV -+ help -+ Enables WEXT support -+ -+config DHD_USE_STATIC_BUF -+ bool "Enable memory preallocation" -+ depends on BCMDHD -+ default n -+ ---help--- -+ Use memory preallocated in platform -+ -+config DHD_USE_SCHED_SCAN -+ bool "Use CFG80211 sched scan" -+ depends on BCMDHD && CFG80211 -+ default n -+ ---help--- -+ Use CFG80211 sched scan -diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile -new file mode 100644 -index 00000000..85149537 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/Makefile -@@ -0,0 +1,45 @@ -+# bcmdhd for 43241 -+# -+ -+DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -+ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ -+ -DDHDTHREAD -DDHD_DEBUG -DSDTEST -DBDC -DTOE \ -+ -DDHD_BCMEVENTS -DSHOW_EVENTS -DPROP_TXSTATUS -DBCMDBG \ -+ -DCUSTOMER_HW2 -DOOB_INTR_ONLY -DHW_OOB \ -+ -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ -+ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ -+ -DKEEP_ALIVE -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ -+ -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ -+ -DDHD_USE_IDLECOUNT -DSET_RANDOM_MAC_SOFTAP -DROAM_ENABLE -DVSDB \ -+ -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -DSDIO_CRC_ERROR_FIX \ -+ -DESCAN_RESULT_PATCH -DHT40_GO -DPASS_ARP_PACKET -DSUPPORT_PM2_ONLY \ -+ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \ -+ -DCUSTOM_SDIO_F2_BLKSIZE=128 \ -+ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include -+ -+DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ -+ dhd_linux_sched.o dhd_sdio.o bcmwifi_channels.o bcmevent.o hndpmu.o \ -+ bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \ -+ bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o -+ -+obj-$(CONFIG_BCMDHD) += bcmdhd.o -+bcmdhd-objs += $(DHDOFILES) -+ifneq ($(CONFIG_WIRELESS_EXT),) -+bcmdhd-objs += wl_iw.o -+DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW -+endif -+ifneq ($(CONFIG_CFG80211),) -+bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o -+DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF -+DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 -+DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 -+DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 -+DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 -+endif -+ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) -+DHDCFLAGS += -DWL_SCHED_SCAN -+endif -+EXTRA_CFLAGS = $(DHDCFLAGS) -+ifeq ($(CONFIG_BCMDHD),m) -+EXTRA_LDFLAGS += --strip-debug -+endif -diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c -new file mode 100644 -index 00000000..3ca17259 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/aiutils.c -@@ -0,0 +1,846 @@ -+/* -+ * Misc utility routines for accessing chip-specific features -+ * of the SiliconBackplane-based Broadcom chips. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: aiutils.c 347614 2012-07-27 10:24:51Z $ -+ */ -+#include <bcm_cfg.h> -+#include <typedefs.h> -+#include <bcmdefs.h> -+#include <osl.h> -+#include <bcmutils.h> -+#include <siutils.h> -+#include <hndsoc.h> -+#include <sbchipc.h> -+#include <pcicfg.h> -+ -+#include "siutils_priv.h" -+ -+#define BCM47162_DMP() (0) -+#define BCM5357_DMP() (0) -+#define remap_coreid(sih, coreid) (coreid) -+#define remap_corerev(sih, corerev) (corerev) -+ -+ -+ -+static uint32 -+get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) -+{ -+ uint32 ent; -+ uint inv = 0, nom = 0; -+ -+ while (TRUE) { -+ ent = R_REG(si_osh(sih), *eromptr); -+ (*eromptr)++; -+ -+ if (mask == 0) -+ break; -+ -+ if ((ent & ER_VALID) == 0) { -+ inv++; -+ continue; -+ } -+ -+ if (ent == (ER_END | ER_VALID)) -+ break; -+ -+ if ((ent & mask) == match) -+ break; -+ -+ nom++; -+ } -+ -+ SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); -+ if (inv + nom) { -+ SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); -+ } -+ return ent; -+} -+ -+static uint32 -+get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, -+ uint32 *sizel, uint32 *sizeh) -+{ -+ uint32 asd, sz, szd; -+ -+ asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); -+ if (((asd & ER_TAG1) != ER_ADD) || -+ (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || -+ ((asd & AD_ST_MASK) != st)) { -+ -+ (*eromptr)--; -+ return 0; -+ } -+ *addrl = asd & AD_ADDR_MASK; -+ if (asd & AD_AG32) -+ *addrh = get_erom_ent(sih, eromptr, 0, 0); -+ else -+ *addrh = 0; -+ *sizeh = 0; -+ sz = asd & AD_SZ_MASK; -+ if (sz == AD_SZ_SZD) { -+ szd = get_erom_ent(sih, eromptr, 0, 0); -+ *sizel = szd & SD_SZ_MASK; -+ if (szd & SD_SG32) -+ *sizeh = get_erom_ent(sih, eromptr, 0, 0); -+ } else -+ *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); -+ -+ SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", -+ sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); -+ -+ return asd; -+} -+ -+static void -+ai_hwfixup(si_info_t *sii) -+{ -+} -+ -+ -+ -+void -+ai_scan(si_t *sih, void *regs, uint devid) -+{ -+ si_info_t *sii = SI_INFO(sih); -+ chipcregs_t *cc = (chipcregs_t *)regs; -+ uint32 erombase, *eromptr, *eromlim; -+ -+ erombase = R_REG(sii->osh, &cc->eromptr); -+ -+ switch (BUSTYPE(sih->bustype)) { -+ case SI_BUS: -+ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); -+ break; -+ -+ case PCI_BUS: -+ -+ sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); -+ -+ -+ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); -+ eromptr = regs; -+ break; -+ -+ case SPI_BUS: -+ case SDIO_BUS: -+ eromptr = (uint32 *)(uintptr)erombase; -+ break; -+ -+ case PCMCIA_BUS: -+ default: -+ SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); -+ ASSERT(0); -+ return; -+ } -+ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); -+ -+ SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", -+ regs, erombase, eromptr, eromlim)); -+ while (eromptr < eromlim) { -+ uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; -+ uint32 mpd, asd, addrl, addrh, sizel, sizeh; -+ uint i, j, idx; -+ bool br; -+ -+ br = FALSE; -+ -+ -+ cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); -+ if (cia == (ER_END | ER_VALID)) { -+ SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); -+ ai_hwfixup(sii); -+ return; -+ } -+ -+ cib = get_erom_ent(sih, &eromptr, 0, 0); -+ -+ if ((cib & ER_TAG) != ER_CI) { -+ SI_ERROR(("CIA not followed by CIB\n")); -+ goto error; -+ } -+ -+ cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; -+ mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; -+ crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; -+ nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; -+ nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; -+ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; -+ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; -+ -+#ifdef BCMDBG_SI -+ SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " -+ "nsw = %d, nmp = %d & nsp = %d\n", -+ mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp)); -+#else -+ BCM_REFERENCE(crev); -+#endif -+ -+ if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) -+ continue; -+ if ((nmw + nsw == 0)) { -+ -+ if (cid == OOB_ROUTER_CORE_ID) { -+ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, -+ &addrl, &addrh, &sizel, &sizeh); -+ if (asd != 0) { -+ sii->oob_router = addrl; -+ } -+ } -+ if (cid != GMAC_COMMON_4706_CORE_ID) -+ continue; -+ } -+ -+ idx = sii->numcores; -+ -+ sii->cia[idx] = cia; -+ sii->cib[idx] = cib; -+ sii->coreid[idx] = remap_coreid(sih, cid); -+ -+ for (i = 0; i < nmp; i++) { -+ mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); -+ if ((mpd & ER_TAG) != ER_MP) { -+ SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); -+ goto error; -+ } -+ SI_VMSG((" Master port %d, mp: %d id: %d\n", i, -+ (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, -+ (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); -+ } -+ -+ -+ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); -+ if (asd == 0) { -+ do { -+ -+ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, -+ &sizel, &sizeh); -+ if (asd != 0) -+ br = TRUE; -+ else { -+ if (br == TRUE) { -+ break; -+ } -+ else if ((addrh != 0) || (sizeh != 0) || -+ (sizel != SI_CORE_SIZE)) { -+ SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" -+ "0x%x\n", addrh, sizeh, sizel)); -+ SI_ERROR(("First Slave ASD for" -+ "core 0x%04x malformed " -+ "(0x%08x)\n", cid, asd)); -+ goto error; -+ } -+ } -+ } while (1); -+ } -+ sii->coresba[idx] = addrl; -+ sii->coresba_size[idx] = sizel; -+ -+ j = 1; -+ do { -+ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, -+ &sizel, &sizeh); -+ if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { -+ sii->coresba2[idx] = addrl; -+ sii->coresba2_size[idx] = sizel; -+ } -+ j++; -+ } while (asd != 0); -+ -+ -+ for (i = 1; i < nsp; i++) { -+ j = 0; -+ do { -+ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, -+ &sizel, &sizeh); -+ -+ if (asd == 0) -+ break; -+ j++; -+ } while (1); -+ if (j == 0) { -+ SI_ERROR((" SP %d has no address descriptors\n", i)); -+ goto error; -+ } -+ } -+ -+ -+ for (i = 0; i < nmw; i++) { -+ asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, -+ &sizel, &sizeh); -+ if (asd == 0) { -+ SI_ERROR(("Missing descriptor for MW %d\n", i)); -+ goto error; -+ } -+ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { -+ SI_ERROR(("Master wrapper %d is not 4KB\n", i)); -+ goto error; -+ } -+ if (i == 0) -+ sii->wrapba[idx] = addrl; -+ } -+ -+ -+ for (i = 0; i < nsw; i++) { -+ uint fwp = (nsp == 1) ? 0 : 1; -+ asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, -+ &sizel, &sizeh); -+ if (asd == 0) { -+ SI_ERROR(("Missing descriptor for SW %d\n", i)); -+ goto error; -+ } -+ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { -+ SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); -+ goto error; -+ } -+ if ((nmw == 0) && (i == 0)) -+ sii->wrapba[idx] = addrl; -+ } -+ -+ -+ -+ if (br) -+ continue; -+ -+ -+ sii->numcores++; -+ } -+ -+ SI_ERROR(("Reached end of erom without finding END")); -+ -+error: -+ sii->numcores = 0; -+ return; -+} -+ -+ -+void * -+ai_setcoreidx(si_t *sih, uint coreidx) -+{ -+ si_info_t *sii = SI_INFO(sih); -+ uint32 addr, wrap; -+ void *regs; -+ -+ if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) -+ return (NULL); -+ -+ addr = sii->coresba[coreidx]; -+ wrap = sii->wrapba[coreidx]; -+ -+ -+ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); -+ -+ switch (BUSTYPE(sih->bustype)) { -+ case SI_BUS: -+ -+ if (!sii->regs[coreidx]) { -+ sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE); -+ ASSERT(GOODREGS(sii->regs[coreidx])); -+ } -+ sii->curmap = regs = sii->regs[coreidx]; -+ if (!sii->wrappers[coreidx]) { -+ sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); -+ ASSERT(GOODREGS(sii->wrappers[coreidx])); -+ } -+ sii->curwrap = sii->wrappers[coreidx]; -+ break; -+ -+ -+ case SPI_BUS: -+ case SDIO_BUS: -+ sii->curmap = regs = (void *)((uintptr)addr); -+ sii->curwrap = (void *)((uintptr)wrap); -+ break; -+ -+ case PCMCIA_BUS: -+ default: -+ ASSERT(0); -+ regs = NULL; -+ break; -+ } -+ -+ sii->curmap = regs; -+ sii->curidx = coreidx; -+ -+ return regs; -+} -+ -+void -+ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) -+{ -+ si_info_t *sii = SI_INFO(sih); -+ chipcregs_t *cc = NULL; -+ uint32 erombase, *eromptr, *eromlim; -+ uint i, j, cidx; -+ uint32 cia, cib, nmp, nsp; -+ uint32 asd, addrl, addrh, sizel, sizeh; -+ -+ for (i = 0; i < sii->numcores; i++) { -+ if (sii->coreid[i] == CC_CORE_ID) { -+ cc = (chipcregs_t *)sii->regs[i]; -+ break; -+ } -+ } -+ if (cc == NULL) -+ goto error; -+ -+ erombase = R_REG(sii->osh, &cc->eromptr); -+ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); -+ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); -+ -+ cidx = sii->curidx; -+ cia = sii->cia[cidx]; -+ cib = sii->cib[cidx]; -+ -+ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; -+ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; -+ -+ -+ while (eromptr < eromlim) { -+ if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && -+ (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { -+ break; -+ } -+ } -+ -+ -+ for (i = 0; i < nmp; i++) -+ get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); -+ -+ -+ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); -+ if (asd == 0) { -+ -+ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, -+ &sizel, &sizeh); -+ } -+ -+ j = 1; -+ do { -+ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, -+ &sizel, &sizeh); -+ j++; -+ } while (asd != 0); -+ -+ -+ for (i = 1; i < nsp; i++) { -+ j = 0; -+ do { -+ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, -+ &sizel, &sizeh); -+ if (asd == 0) -+ break; -+ -+ if (!asidx--) { -+ *addr = addrl; -+ *size = sizel; -+ return; -+ } -+ j++; -+ } while (1); -+ -+ if (j == 0) { -+ SI_ERROR((" SP %d has no address descriptors\n", i)); -+ break; -+ } -+ } -+ -+error: -+ *size = 0; -+ return; -+} -+ -+ -+int -+ai_numaddrspaces(si_t *sih) -+{ -+ return 2; -+} -+ -+ -+uint32 -+ai_addrspace(si_t *sih, uint asidx) -+{ -+ si_info_t *sii; -+ uint cidx; -+ -+ sii = SI_INFO(sih); -+ cidx = sii->curidx; -+ -+ if (asidx == 0) -+ return sii->coresba[cidx]; -+ else if (asidx == 1) -+ return sii->coresba2[cidx]; -+ else { -+ SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", -+ __FUNCTION__, asidx)); -+ return 0; -+ } -+} -+ -+ -+uint32 -+ai_addrspacesize(si_t *sih, uint asidx) -+{ -+ si_info_t *sii; -+ uint cidx; -+ -+ sii = SI_INFO(sih); -+ cidx = sii->curidx; -+ -+ if (asidx == 0) -+ return sii->coresba_size[cidx]; -+ else if (asidx == 1) -+ return sii->coresba2_size[cidx]; -+ else { -+ SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", -+ __FUNCTION__, asidx)); -+ return 0; -+ } -+} -+ -+uint -+ai_flag(si_t *sih) -+{ -+ si_info_t *sii; -+ aidmp_t *ai; -+ -+ sii = SI_INFO(sih); -+ if (BCM47162_DMP()) { -+ SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__)); -+ return sii->curidx; -+ } -+ if (BCM5357_DMP()) { -+ SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); -+ return sii->curidx; -+ } -+ ai = sii->curwrap; -+ -+ return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); -+} -+ -+void -+ai_setint(si_t *sih, int siflag) -+{ -+} -+ -+uint -+ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) -+{ -+ si_info_t *sii = SI_INFO(sih); -+ uint32 *map = (uint32 *) sii->curwrap; -+ -+ if (mask || val) { -+ uint32 w = R_REG(sii->osh, map+(offset/4)); -+ w &= ~mask; -+ w |= val; -+ W_REG(sii->osh, map+(offset/4), val); -+ } -+ -+ return (R_REG(sii->osh, map+(offset/4))); -+} -+ -+uint -+ai_corevendor(si_t *sih) -+{ -+ si_info_t *sii; -+ uint32 cia; -+ -+ sii = SI_INFO(sih); -+ cia = sii->cia[sii->curidx]; -+ return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); -+} -+ -+uint -+ai_corerev(si_t *sih) -+{ -+ si_info_t *sii; -+ uint32 cib; -+ -+ sii = SI_INFO(sih); -+ cib = sii->cib[sii->curidx]; -+ return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); -+} -+ -+bool -+ai_iscoreup(si_t *sih) -+{ -+ si_info_t *sii; -+ aidmp_t *ai; -+ -+ sii = SI_INFO(sih); -+ ai = sii->curwrap; -+ -+ return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && -+ ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); -+} -+ -+ -+uint -+ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -+{ -+ uint origidx = 0; -+ uint32 *r = NULL; -+ uint w; -+ uint intr_val = 0; -+ bool fast = FALSE; -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ ASSERT(GOODIDX(coreidx)); -+ ASSERT(regoff < SI_CORE_SIZE); -+ ASSERT((val & ~mask) == 0); -+ -+ if (coreidx >= SI_MAXCORES) -+ return 0; -+ -+ if (BUSTYPE(sih->bustype) == SI_BUS) { -+ -+ fast = TRUE; -+ -+ if (!sii->regs[coreidx]) { -+ sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], -+ SI_CORE_SIZE); -+ ASSERT(GOODREGS(sii->regs[coreidx])); -+ } -+ r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); -+ } else if (BUSTYPE(sih->bustype) == PCI_BUS) { -+ -+ -+ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { -+ -+ -+ fast = TRUE; -+ r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); -+ } else if (sii->pub.buscoreidx == coreidx) { -+ -+ fast = TRUE; -+ if (SI_FAST(sii)) -+ r = (uint32 *)((char *)sii->curmap + -+ PCI_16KB0_PCIREGS_OFFSET + regoff); -+ else -+ r = (uint32 *)((char *)sii->curmap + -+ ((regoff >= SBCONFIGOFF) ? -+ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + -+ regoff); -+ } -+ } -+ -+ if (!fast) { -+ INTR_OFF(sii, intr_val); -+ -+ -+ origidx = si_coreidx(&sii->pub); -+ -+ -+ r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff); -+ } -+ ASSERT(r != NULL); -+ -+ -+ if (mask || val) { -+ w = (R_REG(sii->osh, r) & ~mask) | val; -+ W_REG(sii->osh, r, w); -+ } -+ -+ -+ w = R_REG(sii->osh, r); -+ -+ if (!fast) { -+ -+ if (origidx != coreidx) -+ ai_setcoreidx(&sii->pub, origidx); -+ -+ INTR_RESTORE(sii, intr_val); -+ } -+ -+ return (w); -+} -+ -+void -+ai_core_disable(si_t *sih, uint32 bits) -+{ -+ si_info_t *sii; -+ volatile uint32 dummy; -+ uint32 status; -+ aidmp_t *ai; -+ -+ sii = SI_INFO(sih); -+ -+ ASSERT(GOODREGS(sii->curwrap)); -+ ai = sii->curwrap; -+ -+ -+ if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) -+ return; -+ -+ -+ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); -+ -+ -+ if (status != 0) { -+ -+ -+ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); -+ -+ -+ } -+ -+ W_REG(sii->osh, &ai->ioctrl, bits); -+ dummy = R_REG(sii->osh, &ai->ioctrl); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(10); -+ -+ W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); -+ dummy = R_REG(sii->osh, &ai->resetctrl); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+} -+ -+ -+void -+ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -+{ -+ si_info_t *sii; -+ aidmp_t *ai; -+ volatile uint32 dummy; -+ -+ sii = SI_INFO(sih); -+ ASSERT(GOODREGS(sii->curwrap)); -+ ai = sii->curwrap; -+ -+ -+ ai_core_disable(sih, (bits | resetbits)); -+ -+ -+ W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); -+ dummy = R_REG(sii->osh, &ai->ioctrl); -+ BCM_REFERENCE(dummy); -+ -+ W_REG(sii->osh, &ai->resetctrl, 0); -+ dummy = R_REG(sii->osh, &ai->resetctrl); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+ -+ W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); -+ dummy = R_REG(sii->osh, &ai->ioctrl); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+} -+ -+void -+ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -+{ -+ si_info_t *sii; -+ aidmp_t *ai; -+ uint32 w; -+ -+ sii = SI_INFO(sih); -+ -+ if (BCM47162_DMP()) { -+ SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", -+ __FUNCTION__)); -+ return; -+ } -+ if (BCM5357_DMP()) { -+ SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", -+ __FUNCTION__)); -+ return; -+ } -+ -+ ASSERT(GOODREGS(sii->curwrap)); -+ ai = sii->curwrap; -+ -+ ASSERT((val & ~mask) == 0); -+ -+ if (mask || val) { -+ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); -+ W_REG(sii->osh, &ai->ioctrl, w); -+ } -+} -+ -+uint32 -+ai_core_cflags(si_t *sih, uint32 mask, uint32 val) -+{ -+ si_info_t *sii; -+ aidmp_t *ai; -+ uint32 w; -+ -+ sii = SI_INFO(sih); -+ if (BCM47162_DMP()) { -+ SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0", -+ __FUNCTION__)); -+ return 0; -+ } -+ if (BCM5357_DMP()) { -+ SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", -+ __FUNCTION__)); -+ return 0; -+ } -+ -+ ASSERT(GOODREGS(sii->curwrap)); -+ ai = sii->curwrap; -+ -+ ASSERT((val & ~mask) == 0); -+ -+ if (mask || val) { -+ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); -+ W_REG(sii->osh, &ai->ioctrl, w); -+ } -+ -+ return R_REG(sii->osh, &ai->ioctrl); -+} -+ -+uint32 -+ai_core_sflags(si_t *sih, uint32 mask, uint32 val) -+{ -+ si_info_t *sii; -+ aidmp_t *ai; -+ uint32 w; -+ -+ sii = SI_INFO(sih); -+ if (BCM47162_DMP()) { -+ SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", -+ __FUNCTION__)); -+ return 0; -+ } -+ if (BCM5357_DMP()) { -+ SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", -+ __FUNCTION__)); -+ return 0; -+ } -+ -+ ASSERT(GOODREGS(sii->curwrap)); -+ ai = sii->curwrap; -+ -+ ASSERT((val & ~mask) == 0); -+ ASSERT((mask & ~SISF_CORE_BITS) == 0); -+ -+ if (mask || val) { -+ w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); -+ W_REG(sii->osh, &ai->iostatus, w); -+ } -+ -+ return R_REG(sii->osh, &ai->iostatus); -+} -diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c -new file mode 100644 -index 00000000..35859488 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/bcmevent.c -@@ -0,0 +1,147 @@ -+/* -+ * bcmevent read-only data shared by kernel or app layers -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * $Id: bcmevent.c 370587 2012-11-22 09:32:38Z $ -+ */ -+ -+#include <typedefs.h> -+#include <bcmutils.h> -+#include <proto/ethernet.h> -+#include <proto/bcmeth.h> -+#include <proto/bcmevent.h> -+ -+#if WLC_E_LAST != 107 -+#error "You need to add an entry to bcmevent_names[] for the new event" -+#endif -+ -+const bcmevent_name_t bcmevent_names[] = { -+ { WLC_E_SET_SSID, "SET_SSID" }, -+ { WLC_E_JOIN, "JOIN" }, -+ { WLC_E_START, "START" }, -+ { WLC_E_AUTH, "AUTH" }, -+ { WLC_E_AUTH_IND, "AUTH_IND" }, -+ { WLC_E_DEAUTH, "DEAUTH" }, -+ { WLC_E_DEAUTH_IND, "DEAUTH_IND" }, -+ { WLC_E_ASSOC, "ASSOC" }, -+ { WLC_E_ASSOC_IND, "ASSOC_IND" }, -+ { WLC_E_REASSOC, "REASSOC" }, -+ { WLC_E_REASSOC_IND, "REASSOC_IND" }, -+ { WLC_E_DISASSOC, "DISASSOC" }, -+ { WLC_E_DISASSOC_IND, "DISASSOC_IND" }, -+ { WLC_E_QUIET_START, "START_QUIET" }, -+ { WLC_E_QUIET_END, "END_QUIET" }, -+ { WLC_E_BEACON_RX, "BEACON_RX" }, -+ { WLC_E_LINK, "LINK" }, -+ { WLC_E_MIC_ERROR, "MIC_ERROR" }, -+ { WLC_E_NDIS_LINK, "NDIS_LINK" }, -+ { WLC_E_ROAM, "ROAM" }, -+ { WLC_E_TXFAIL, "TXFAIL" }, -+ { WLC_E_PMKID_CACHE, "PMKID_CACHE" }, -+ { WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF" }, -+ { WLC_E_PRUNE, "PRUNE" }, -+ { WLC_E_AUTOAUTH, "AUTOAUTH" }, -+ { WLC_E_EAPOL_MSG, "EAPOL_MSG" }, -+ { WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE" }, -+ { WLC_E_ADDTS_IND, "ADDTS_IND" }, -+ { WLC_E_DELTS_IND, "DELTS_IND" }, -+ { WLC_E_BCNSENT_IND, "BCNSENT_IND" }, -+ { WLC_E_BCNRX_MSG, "BCNRX_MSG" }, -+ { WLC_E_BCNLOST_MSG, "BCNLOST_IND" }, -+ { WLC_E_ROAM_PREP, "ROAM_PREP" }, -+ { WLC_E_PFN_NET_FOUND, "PFNFOUND_IND" }, -+ { WLC_E_PFN_NET_LOST, "PFNLOST_IND" }, -+#if defined(IBSS_PEER_DISCOVERY_EVENT) -+ { WLC_E_IBSS_ASSOC, "IBSS_ASSOC" }, -+#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ -+ { WLC_E_RADIO, "RADIO" }, -+ { WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG" }, -+ { WLC_E_PROBREQ_MSG, "PROBE_REQ_MSG" }, -+ { WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" }, -+ { WLC_E_PSK_SUP, "PSK_SUP" }, -+ { WLC_E_COUNTRY_CODE_CHANGED, "CNTRYCODE_IND" }, -+ { WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" }, -+ { WLC_E_ICV_ERROR, "ICV_ERROR" }, -+ { WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" }, -+ { WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" }, -+ { WLC_E_TRACE, "TRACE" }, -+#ifdef WLBTAMP -+ { WLC_E_BTA_HCI_EVENT, "BTA_HCI_EVENT" }, -+#endif -+ { WLC_E_IF, "IF" }, -+#ifdef WLP2P -+ { WLC_E_P2P_DISC_LISTEN_COMPLETE, "WLC_E_P2P_DISC_LISTEN_COMPLETE" }, -+#endif -+ { WLC_E_RSSI, "RSSI" }, -+ { WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE" }, -+ { WLC_E_EXTLOG_MSG, "EXTERNAL LOG MESSAGE" }, -+#ifdef WIFI_ACT_FRAME -+ { WLC_E_ACTION_FRAME, "ACTION_FRAME" }, -+ { WLC_E_ACTION_FRAME_RX, "ACTION_FRAME_RX" }, -+ { WLC_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" }, -+#endif -+#if 0 && (NDISVER >= 0x0620) -+ { WLC_E_PRE_ASSOC_IND, "ASSOC_RECV" }, -+ { WLC_E_PRE_REASSOC_IND, "REASSOC_RECV" }, -+ { WLC_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" }, -+ { WLC_E_AP_STARTED, "AP_STARTED" }, -+ { WLC_E_DFS_AP_STOP, "DFS_AP_STOP" }, -+ { WLC_E_DFS_AP_RESUME, "DFS_AP_RESUME" }, -+ { WLC_E_ASSOC_IND_NDIS, "ASSOC_IND_NDIS"}, -+ { WLC_E_REASSOC_IND_NDIS, "REASSOC_IND_NDIS"}, -+ { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, -+ { WLC_E_AUTH_REQ, "WLC_E_AUTH_REQ" }, -+#endif -+ { WLC_E_ESCAN_RESULT, "WLC_E_ESCAN_RESULT" }, -+ { WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "WLC_E_AF_OFF_CHAN_COMPLETE" }, -+#ifdef WLP2P -+ { WLC_E_PROBRESP_MSG, "PROBE_RESP_MSG" }, -+ { WLC_E_P2P_PROBREQ_MSG, "P2P PROBE_REQ_MSG" }, -+#endif -+#ifdef PROP_TXSTATUS -+ { WLC_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP" }, -+#endif -+ { WLC_E_WAKE_EVENT, "WAKE_EVENT" }, -+ { WLC_E_DCS_REQUEST, "DCS_REQUEST" }, -+ { WLC_E_RM_COMPLETE, "RM_COMPLETE" }, -+#ifdef WLMEDIA_HTSF -+ { WLC_E_HTSFSYNC, "HTSF_SYNC_EVENT" }, -+#endif -+ { WLC_E_OVERLAY_REQ, "OVERLAY_REQ_EVENT" }, -+ { WLC_E_CSA_COMPLETE_IND, "WLC_E_CSA_COMPLETE_IND"}, -+ { WLC_E_EXCESS_PM_WAKE_EVENT, "EXCESS_PM_WAKE_EVENT" }, -+ { WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" }, -+ { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" }, -+#ifdef SOFTAP -+ { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }, -+#endif -+ { WLC_E_ASSOC_REQ_IE, "ASSOC_REQ_IE" }, -+ { WLC_E_ASSOC_RESP_IE, "ASSOC_RESP_IE" }, -+ { WLC_E_ACTION_FRAME_RX_NDIS, "WLC_E_ACTION_FRAME_RX_NDIS" }, -+#ifdef WLTDLS -+ { WLC_E_TDLS_PEER_EVENT, "TDLS_PEER_EVENT" }, -+#endif /* WLTDLS */ -+ { WLC_E_SERVICE_FOUND, "SERVICE_FOUND" }, -+ { WLC_E_P2PO_ADD_DEVICE, "P2PO_DEV_FOUND" }, -+ { WLC_E_P2PO_DEL_DEVICE, "P2PO_DEV_LOST" }, -+}; -+ -+const int bcmevent_names_size = ARRAYSIZE(bcmevent_names); -diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c -new file mode 100644 -index 00000000..b05e2956 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/bcmsdh.c -@@ -0,0 +1,756 @@ -+/* -+ * BCMSDH interface glue -+ * implement bcmsdh API for SDIOH driver -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdh.c 347614 2012-07-27 10:24:51Z $ -+ */ -+ -+/** -+ * @file bcmsdh.c -+ */ -+ -+/* ****************** BCMSDH Interface Functions *************************** */ -+ -+#include <typedefs.h> -+#include <bcmdevs.h> -+#include <bcmendian.h> -+#include <bcmutils.h> -+#include <hndsoc.h> -+#include <siutils.h> -+#include <osl.h> -+ -+#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */ -+#include <bcmsdbus.h> /* common SDIO/controller interface */ -+#include <sbsdio.h> /* SDIO device core hardware definitions. */ -+ -+#include <sdio.h> /* SDIO Device and Protocol Specs */ -+ -+#define SDIOH_API_ACCESS_RETRY_LIMIT 2 -+const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; -+ -+/** -+ * BCMSDH API context -+ */ -+struct bcmsdh_info -+{ -+ bool init_success; /* underlying driver successfully attached */ -+ void *sdioh; /* handler for sdioh */ -+ uint32 vendevid; /* Target Vendor and Device ID on SD bus */ -+ osl_t *osh; -+ bool regfail; /* Save status of last reg_read/reg_write call */ -+ uint32 sbwad; /* Save backplane window address */ -+}; -+/* local copy of bcm sd handler */ -+bcmsdh_info_t * l_bcmsdh = NULL; -+ -+#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -+extern int -+sdioh_enable_hw_oob_intr(void *sdioh, bool enable); -+ -+void -+bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) -+{ -+ sdioh_enable_hw_oob_intr(sdh->sdioh, enable); -+} -+#endif -+ -+/* Attach BCMSDH layer to SDIO Host Controller Driver -+ * -+ * @param osh OSL Handle. -+ * @param cfghdl Configuration Handle. -+ * @param regsva Virtual address of controller registers. -+ * @param irq Interrupt number of SDIO controller. -+ * -+ * @return bcmsdh_info_t Handle to BCMSDH context. -+ */ -+bcmsdh_info_t * -+bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq) -+{ -+ bcmsdh_info_t *bcmsdh; -+ -+ if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { -+ BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); -+ return NULL; -+ } -+ bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); -+ -+ /* save the handler locally */ -+ l_bcmsdh = bcmsdh; -+ -+ if (!(bcmsdh->sdioh = sdioh_attach(osh, cfghdl, irq))) { -+ bcmsdh_detach(osh, bcmsdh); -+ return NULL; -+ } -+ -+ bcmsdh->osh = osh; -+ bcmsdh->init_success = TRUE; -+ -+ *regsva = (uint32 *)SI_ENUM_BASE; -+ -+ /* Report the BAR, to fix if needed */ -+ bcmsdh->sbwad = SI_ENUM_BASE; -+ return bcmsdh; -+} -+ -+int -+bcmsdh_detach(osl_t *osh, void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ if (bcmsdh != NULL) { -+ if (bcmsdh->sdioh) { -+ sdioh_detach(osh, bcmsdh->sdioh); -+ bcmsdh->sdioh = NULL; -+ } -+ MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); -+ } -+ -+ l_bcmsdh = NULL; -+ return 0; -+} -+ -+int -+bcmsdh_iovar_op(void *sdh, const char *name, -+ void *params, int plen, void *arg, int len, bool set) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); -+} -+ -+bool -+bcmsdh_intr_query(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ bool on; -+ -+ ASSERT(bcmsdh); -+ status = sdioh_interrupt_query(bcmsdh->sdioh, &on); -+ if (SDIOH_API_SUCCESS(status)) -+ return FALSE; -+ else -+ return on; -+} -+ -+int -+bcmsdh_intr_enable(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ ASSERT(bcmsdh); -+ -+ status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -+} -+ -+int -+bcmsdh_intr_disable(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ ASSERT(bcmsdh); -+ -+ status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -+} -+ -+int -+bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ ASSERT(bcmsdh); -+ -+ status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -+} -+ -+int -+bcmsdh_intr_dereg(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ ASSERT(bcmsdh); -+ -+ status = sdioh_interrupt_deregister(bcmsdh->sdioh); -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -+} -+ -+#if defined(DHD_DEBUG) -+bool -+bcmsdh_intr_pending(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ ASSERT(sdh); -+ return sdioh_interrupt_pending(bcmsdh->sdioh); -+} -+#endif -+ -+ -+int -+bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) -+{ -+ ASSERT(sdh); -+ -+ /* don't support yet */ -+ return BCME_UNSUPPORTED; -+} -+ -+/** -+ * Read from SDIO Configuration Space -+ * @param sdh SDIO Host context. -+ * @param func_num Function number to read from. -+ * @param addr Address to read from. -+ * @param err Error return. -+ * @return value read from SDIO configuration space. -+ */ -+uint8 -+bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT -+ int32 retry = 0; -+#endif -+ uint8 data = 0; -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ ASSERT(bcmsdh->init_success); -+ -+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT -+ do { -+ if (retry) /* wait for 1 ms till bus get settled down */ -+ OSL_DELAY(1000); -+#endif -+ status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT -+ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -+#endif -+ if (err) -+ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); -+ -+ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, -+ fnc_num, addr, data)); -+ -+ return data; -+} -+ -+void -+bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT -+ int32 retry = 0; -+#endif -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ ASSERT(bcmsdh->init_success); -+ -+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT -+ do { -+ if (retry) /* wait for 1 ms till bus get settled down */ -+ OSL_DELAY(1000); -+#endif -+ status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); -+#ifdef SDIOH_API_ACCESS_RETRY_LIMIT -+ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); -+#endif -+ if (err) -+ *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; -+ -+ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, -+ fnc_num, addr, data)); -+} -+ -+uint32 -+bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ uint32 data = 0; -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ ASSERT(bcmsdh->init_success); -+ -+ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, -+ addr, &data, 4); -+ -+ if (err) -+ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); -+ -+ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, -+ fnc_num, addr, data)); -+ -+ return data; -+} -+ -+void -+bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ ASSERT(bcmsdh->init_success); -+ -+ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, -+ addr, &data, 4); -+ -+ if (err) -+ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); -+ -+ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, -+ addr, data)); -+} -+ -+ -+int -+bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ -+ uint8 *tmp_buf, *tmp_ptr; -+ uint8 *ptr; -+ bool ascii = func & ~0xf; -+ func &= 0x7; -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ ASSERT(bcmsdh->init_success); -+ ASSERT(cis); -+ ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); -+ -+ status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); -+ -+ if (ascii) { -+ /* Move binary bits to tmp and format them into the provided buffer. */ -+ if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { -+ BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); -+ return BCME_NOMEM; -+ } -+ bcopy(cis, tmp_buf, length); -+ for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { -+ ptr += snprintf((char*)ptr, (cis + length - ptr - 4), -+ "%.2x ", *tmp_ptr & 0xff); -+ if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) -+ ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); -+ } -+ MFREE(bcmsdh->osh, tmp_buf, length); -+ } -+ -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -+} -+ -+ -+int -+bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) -+{ -+ int err = 0; -+ uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ if (bar0 != bcmsdh->sbwad || force_set) { -+ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, -+ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); -+ if (!err) -+ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, -+ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); -+ if (!err) -+ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, -+ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); -+ -+ if (!err) -+ bcmsdh->sbwad = bar0; -+ else -+ /* invalidate cached window var */ -+ bcmsdh->sbwad = 0; -+ -+ } -+ -+ return err; -+} -+ -+uint32 -+bcmsdh_reg_read(void *sdh, uint32 addr, uint size) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ uint32 word = 0; -+ -+ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr)); -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ ASSERT(bcmsdh->init_success); -+ -+ if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) -+ return 0xFFFFFFFF; -+ -+ addr &= SBSDIO_SB_OFT_ADDR_MASK; -+ if (size == 4) -+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; -+ -+ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, -+ SDIOH_READ, SDIO_FUNC_1, addr, &word, size); -+ -+ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); -+ -+ BCMSDH_INFO(("uint32data = 0x%x\n", word)); -+ -+ /* if ok, return appropriately masked word */ -+ if (SDIOH_API_SUCCESS(status)) { -+ switch (size) { -+ case sizeof(uint8): -+ return (word & 0xff); -+ case sizeof(uint16): -+ return (word & 0xffff); -+ case sizeof(uint32): -+ return word; -+ default: -+ bcmsdh->regfail = TRUE; -+ -+ } -+ } -+ -+ /* otherwise, bad sdio access or invalid size */ -+ BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size)); -+ return 0xFFFFFFFF; -+} -+ -+uint32 -+bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ int err = 0; -+ -+ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", -+ __FUNCTION__, addr, size*8, data)); -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ ASSERT(bcmsdh->init_success); -+ -+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) -+ return err; -+ -+ addr &= SBSDIO_SB_OFT_ADDR_MASK; -+ if (size == 4) -+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; -+ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, -+ addr, &data, size); -+ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); -+ -+ if (SDIOH_API_SUCCESS(status)) -+ return 0; -+ -+ BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", -+ __FUNCTION__, data, addr, size)); -+ return 0xFFFFFFFF; -+} -+ -+bool -+bcmsdh_regfail(void *sdh) -+{ -+ return ((bcmsdh_info_t *)sdh)->regfail; -+} -+ -+int -+bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, -+ uint8 *buf, uint nbytes, void *pkt, -+ bcmsdh_cmplt_fn_t complete_fn, void *handle) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ uint incr_fix; -+ uint width; -+ int err = 0; -+ -+ ASSERT(bcmsdh); -+ ASSERT(bcmsdh->init_success); -+ -+ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", -+ __FUNCTION__, fn, addr, nbytes)); -+ -+ /* Async not implemented yet */ -+ ASSERT(!(flags & SDIO_REQ_ASYNC)); -+ if (flags & SDIO_REQ_ASYNC) -+ return BCME_UNSUPPORTED; -+ -+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) -+ return err; -+ -+ addr &= SBSDIO_SB_OFT_ADDR_MASK; -+ -+ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; -+ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; -+ if (width == 4) -+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; -+ -+ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, -+ SDIOH_READ, fn, addr, width, nbytes, buf, pkt); -+ -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); -+} -+ -+int -+bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, -+ uint8 *buf, uint nbytes, void *pkt, -+ bcmsdh_cmplt_fn_t complete_fn, void *handle) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ uint incr_fix; -+ uint width; -+ int err = 0; -+ -+ ASSERT(bcmsdh); -+ ASSERT(bcmsdh->init_success); -+ -+ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", -+ __FUNCTION__, fn, addr, nbytes)); -+ -+ /* Async not implemented yet */ -+ ASSERT(!(flags & SDIO_REQ_ASYNC)); -+ if (flags & SDIO_REQ_ASYNC) -+ return BCME_UNSUPPORTED; -+ -+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) -+ return err; -+ -+ addr &= SBSDIO_SB_OFT_ADDR_MASK; -+ -+ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; -+ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; -+ if (width == 4) -+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; -+ -+ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, -+ SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); -+ -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -+} -+ -+int -+bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ SDIOH_API_RC status; -+ -+ ASSERT(bcmsdh); -+ ASSERT(bcmsdh->init_success); -+ ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); -+ -+ addr &= SBSDIO_SB_OFT_ADDR_MASK; -+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; -+ -+ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, -+ (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, -+ addr, 4, nbytes, buf, NULL); -+ -+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); -+} -+ -+int -+bcmsdh_abort(void *sdh, uint fn) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ return sdioh_abort(bcmsdh->sdioh, fn); -+} -+ -+int -+bcmsdh_start(void *sdh, int stage) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ return sdioh_start(bcmsdh->sdioh, stage); -+} -+ -+int -+bcmsdh_stop(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ return sdioh_stop(bcmsdh->sdioh); -+} -+ -+int -+bcmsdh_waitlockfree(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ return sdioh_waitlockfree(bcmsdh->sdioh); -+} -+ -+ -+int -+bcmsdh_query_device(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; -+ return (bcmsdh->vendevid); -+} -+ -+uint -+bcmsdh_query_iofnum(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ return (sdioh_query_iofnum(bcmsdh->sdioh)); -+} -+ -+int -+bcmsdh_reset(bcmsdh_info_t *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ return sdioh_sdio_reset(bcmsdh->sdioh); -+} -+ -+void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) -+{ -+ ASSERT(sdh); -+ return sdh->sdioh; -+} -+ -+/* Function to pass device-status bits to DHD. */ -+uint32 -+bcmsdh_get_dstatus(void *sdh) -+{ -+ return 0; -+} -+uint32 -+bcmsdh_cur_sbwad(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ -+ if (!bcmsdh) -+ bcmsdh = l_bcmsdh; -+ -+ return (bcmsdh->sbwad); -+} -+ -+void -+bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) -+{ -+ return; -+} -+ -+ -+int -+bcmsdh_sleep(void *sdh, bool enab) -+{ -+#ifdef SDIOH_SLEEP_ENABLED -+ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; -+ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); -+ -+ return sdioh_sleep(sd, enab); -+#else -+ return BCME_UNSUPPORTED; -+#endif -+} -+ -+int -+bcmsdh_gpio_init(void *sdh) -+{ -+ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; -+ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); -+ -+ return sdioh_gpio_init(sd); -+} -+ -+bool -+bcmsdh_gpioin(void *sdh, uint32 gpio) -+{ -+ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; -+ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); -+ -+ return sdioh_gpioin(sd, gpio); -+} -+ -+int -+bcmsdh_gpioouten(void *sdh, uint32 gpio) -+{ -+ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; -+ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); -+ -+ return sdioh_gpioouten(sd, gpio); -+} -+ -+int -+bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) -+{ -+ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; -+ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); -+ -+ return sdioh_gpioout(sd, gpio, enab); -+} -+ -+#ifdef BCMSDIOH_TXGLOM -+void -+bcmsdh_glom_post(void *sdh, uint8 *frame, uint len) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ sdioh_glom_post(bcmsdh->sdioh, frame, len); -+} -+ -+void -+bcmsdh_glom_clear(void *sdh) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ sdioh_glom_clear(bcmsdh->sdioh); -+} -+ -+uint -+bcmsdh_set_mode(void *sdh, uint mode) -+{ -+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; -+ return (sdioh_set_mode(bcmsdh->sdioh, mode)); -+} -+ -+bool -+bcmsdh_glom_enabled(void) -+{ -+ return (sdioh_glom_enabled()); -+} -+#endif /* BCMSDIOH_TXGLOM */ -diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c -new file mode 100644 -index 00000000..96a126ec ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c -@@ -0,0 +1,750 @@ -+/* -+ * SDIO access interface for drivers - linux specific (pci only) -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdh_linux.c 347638 2012-07-27 11:39:03Z $ -+ */ -+ -+/** -+ * @file bcmsdh_linux.c -+ */ -+ -+#define __UNDEF_NO_VERSION__ -+ -+#include <typedefs.h> -+#include <linuxver.h> -+ -+#include <linux/pci.h> -+#include <linux/completion.h> -+ -+#include <osl.h> -+#include <pcicfg.h> -+#include <bcmdefs.h> -+#include <bcmdevs.h> -+ -+#if defined(OOB_INTR_ONLY) -+#include <linux/irq.h> -+extern void dhdsdio_isr(void * args); -+#include <bcmutils.h> -+#include <dngl_stats.h> -+#include <dhd.h> -+#endif /* defined(OOB_INTR_ONLY) */ -+ -+ -+/** -+ * SDIO Host Controller info -+ */ -+typedef struct bcmsdh_hc bcmsdh_hc_t; -+ -+struct bcmsdh_hc { -+ bcmsdh_hc_t *next; -+#ifdef BCMPLATFORM_BUS -+ struct device *dev; /* platform device handle */ -+#else -+ struct pci_dev *dev; /* pci device handle */ -+#endif /* BCMPLATFORM_BUS */ -+ osl_t *osh; -+ void *regs; /* SDIO Host Controller address */ -+ bcmsdh_info_t *sdh; /* SDIO Host Controller handle */ -+ void *ch; -+ unsigned int oob_irq; -+ unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ -+ bool oob_irq_registered; -+ bool oob_irq_enable_flag; -+#if defined(OOB_INTR_ONLY) -+ spinlock_t irq_lock; -+#endif /* defined(OOB_INTR_ONLY) */ -+}; -+static bcmsdh_hc_t *sdhcinfo = NULL; -+ -+/* driver info, initialized when bcmsdh_register is called */ -+static bcmsdh_driver_t drvinfo = {NULL, NULL}; -+ -+/* debugging macros */ -+#define SDLX_MSG(x) -+ -+/** -+ * Checks to see if vendor and device IDs match a supported SDIO Host Controller. -+ */ -+bool -+bcmsdh_chipmatch(uint16 vendor, uint16 device) -+{ -+ /* Add other vendors and devices as required */ -+ -+#ifdef BCMSDIOH_STD -+ /* Check for Arasan host controller */ -+ if (vendor == VENDOR_SI_IMAGE) { -+ return (TRUE); -+ } -+ /* Check for BRCM 27XX Standard host controller */ -+ if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { -+ return (TRUE); -+ } -+ /* Check for BRCM Standard host controller */ -+ if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { -+ return (TRUE); -+ } -+ /* Check for TI PCIxx21 Standard host controller */ -+ if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { -+ return (TRUE); -+ } -+ if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { -+ return (TRUE); -+ } -+ /* Ricoh R5C822 Standard SDIO Host */ -+ if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { -+ return (TRUE); -+ } -+ /* JMicron Standard SDIO Host */ -+ if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { -+ return (TRUE); -+ } -+ -+#endif /* BCMSDIOH_STD */ -+#ifdef BCMSDIOH_SPI -+ /* This is the PciSpiHost. */ -+ if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { -+ printf("Found PCI SPI Host Controller\n"); -+ return (TRUE); -+ } -+ -+#endif /* BCMSDIOH_SPI */ -+ -+ return (FALSE); -+} -+ -+#if defined(BCMPLATFORM_BUS) -+#if defined(BCMLXSDMMC) -+/* forward declarations */ -+int bcmsdh_probe(struct device *dev); -+int bcmsdh_remove(struct device *dev); -+ -+EXPORT_SYMBOL(bcmsdh_probe); -+EXPORT_SYMBOL(bcmsdh_remove); -+ -+#else -+/* forward declarations */ -+static int __devinit bcmsdh_probe(struct device *dev); -+static int __devexit bcmsdh_remove(struct device *dev); -+#endif /* defined(BCMLXSDMMC) */ -+ -+#if !defined(BCMLXSDMMC) -+static -+#endif /* !defined(BCMLXSDMMC) */ -+int bcmsdh_probe(struct device *dev) -+{ -+ osl_t *osh = NULL; -+ bcmsdh_hc_t *sdhc = NULL; -+ ulong regs = 0; -+ bcmsdh_info_t *sdh = NULL; -+#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) -+ struct platform_device *pdev; -+ struct resource *r; -+#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) */ -+ int irq = 0; -+ uint32 vendevid; -+ unsigned long irq_flags = 0; -+ -+#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) -+ pdev = to_platform_device(dev); -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irq = platform_get_irq(pdev, 0); -+ if (!r || irq == NO_IRQ) -+ return -ENXIO; -+#endif /* !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS) */ -+ -+#if defined(OOB_INTR_ONLY) -+#ifdef HW_OOB -+ irq_flags = -+ IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; -+#else -+ irq_flags = IRQF_TRIGGER_FALLING; -+#endif /* HW_OOB */ -+ -+ /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ -+ irq = dhd_customer_oob_irq_map(&irq_flags); -+ if (irq < 0) { -+ SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__)); -+ return 1; -+ } -+#endif /* defined(OOB_INTR_ONLY) */ -+ /* allocate SDIO Host Controller state info */ -+ if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) { -+ SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+ if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) { -+ SDLX_MSG(("%s: out of memory, allocated %d bytes\n", -+ __FUNCTION__, -+ MALLOCED(osh))); -+ goto err; -+ } -+ bzero(sdhc, sizeof(bcmsdh_hc_t)); -+ sdhc->osh = osh; -+ -+ sdhc->dev = (void *)dev; -+ -+#if defined(BCMLXSDMMC) -+ if (!(sdh = bcmsdh_attach(osh, (void *)0, -+ (void **)®s, irq))) { -+ SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+#else -+ if (!(sdh = bcmsdh_attach(osh, (void *)r->start, -+ (void **)®s, irq))) { -+ SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+#endif /* defined(BCMLXSDMMC) */ -+ sdhc->sdh = sdh; -+ sdhc->oob_irq = irq; -+ sdhc->oob_flags = irq_flags; -+ sdhc->oob_irq_registered = FALSE; /* to make sure.. */ -+ sdhc->oob_irq_enable_flag = FALSE; -+#if defined(OOB_INTR_ONLY) -+ spin_lock_init(&sdhc->irq_lock); -+#endif /* defined(BCMLXSDMMC) */ -+ -+ /* chain SDIO Host Controller info together */ -+ sdhc->next = sdhcinfo; -+ sdhcinfo = sdhc; -+ -+ /* Read the vendor/device ID from the CIS */ -+ vendevid = bcmsdh_query_device(sdh); -+ /* try to attach to the target device */ -+ if (!(sdhc->ch = drvinfo.attach((vendevid >> 16), -+ (vendevid & 0xFFFF), 0, 0, 0, 0, -+ (void *)regs, NULL, sdh))) { -+ SDLX_MSG(("%s: device attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ return 0; -+ -+ /* error handling */ -+err: -+ if (sdhc) { -+ if (sdhc->sdh) -+ bcmsdh_detach(sdhc->osh, sdhc->sdh); -+ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); -+ } -+ if (osh) -+ osl_detach(osh); -+ return -ENODEV; -+} -+ -+#if !defined(BCMLXSDMMC) -+static -+#endif /* !defined(BCMLXSDMMC) */ -+int bcmsdh_remove(struct device *dev) -+{ -+ bcmsdh_hc_t *sdhc, *prev; -+ osl_t *osh; -+ -+ sdhc = sdhcinfo; -+ drvinfo.detach(sdhc->ch); -+ bcmsdh_detach(sdhc->osh, sdhc->sdh); -+ -+ /* find the SDIO Host Controller state for this pdev and take it out from the list */ -+ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { -+ if (sdhc->dev == (void *)dev) { -+ if (prev) -+ prev->next = sdhc->next; -+ else -+ sdhcinfo = NULL; -+ break; -+ } -+ prev = sdhc; -+ } -+ if (!sdhc) { -+ SDLX_MSG(("%s: failed\n", __FUNCTION__)); -+ return 0; -+ } -+ -+ /* release SDIO Host Controller info */ -+ osh = sdhc->osh; -+ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); -+ osl_detach(osh); -+ -+#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) -+ dev_set_drvdata(dev, NULL); -+#endif /* !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) */ -+ -+ return 0; -+} -+ -+#else /* BCMPLATFORM_BUS */ -+ -+#if !defined(BCMLXSDMMC) -+/* forward declarations for PCI probe and remove functions. */ -+static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -+static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev); -+ -+/** -+ * pci id table -+ */ -+static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = { -+ { vendor: PCI_ANY_ID, -+ device: PCI_ANY_ID, -+ subvendor: PCI_ANY_ID, -+ subdevice: PCI_ANY_ID, -+ class: 0, -+ class_mask: 0, -+ driver_data: 0, -+ }, -+ { 0, } -+}; -+MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid); -+ -+/** -+ * SDIO Host Controller pci driver info -+ */ -+static struct pci_driver bcmsdh_pci_driver = { -+ node: {}, -+ name: "bcmsdh", -+ id_table: bcmsdh_pci_devid, -+ probe: bcmsdh_pci_probe, -+ remove: bcmsdh_pci_remove, -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -+ save_state: NULL, -+#endif -+ suspend: NULL, -+ resume: NULL, -+ }; -+ -+ -+extern uint sd_pci_slot; /* Force detection to a particular PCI */ -+ /* slot only . Allows for having multiple */ -+ /* WL devices at once in a PC */ -+ /* Only one instance of dhd will be */ -+ /* usable at a time */ -+ /* Upper word is bus number, */ -+ /* lower word is slot number */ -+ /* Default value of 0xffffffff turns this */ -+ /* off */ -+module_param(sd_pci_slot, uint, 0); -+ -+ -+/** -+ * Detect supported SDIO Host Controller and attach if found. -+ * -+ * Determine if the device described by pdev is a supported SDIO Host -+ * Controller. If so, attach to it and attach to the target device. -+ */ -+static int __devinit -+bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ osl_t *osh = NULL; -+ bcmsdh_hc_t *sdhc = NULL; -+ ulong regs; -+ bcmsdh_info_t *sdh = NULL; -+ int rc; -+ -+ if (sd_pci_slot != 0xFFFFffff) { -+ if (pdev->bus->number != (sd_pci_slot>>16) || -+ PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) { -+ SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n", -+ __FUNCTION__, -+ bcmsdh_chipmatch(pdev->vendor, pdev->device) -+ ?"Found compatible SDIOHC" -+ :"Probing unknown device", -+ pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, -+ pdev->device)); -+ return -ENODEV; -+ } -+ SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n", -+ __FUNCTION__, -+ bcmsdh_chipmatch(pdev->vendor, pdev->device) -+ ?"Using compatible SDIOHC" -+ :"WARNING, forced use of unkown device", -+ pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device)); -+ } -+ -+ if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) || -+ (pdev->device == PCIXX21_FLASHMEDIA0_ID))) { -+ uint32 config_reg; -+ -+ SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__)); -+ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { -+ SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4); -+ -+ /* -+ * Set MMC_SD_DIS bit in FlashMedia Controller. -+ * Disbling the SD/MMC Controller in the FlashMedia Controller -+ * allows the Standard SD Host Controller to take over control -+ * of the SD Slot. -+ */ -+ config_reg |= 0x02; -+ OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg); -+ osl_detach(osh); -+ } -+ /* match this pci device with what we support */ -+ /* we can't solely rely on this to believe it is our SDIO Host Controller! */ -+ if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) { -+ return -ENODEV; -+ } -+ -+ /* this is a pci device we might support */ -+ SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n", -+ __FUNCTION__, -+ pdev->bus->number, PCI_SLOT(pdev->devfn), -+ PCI_FUNC(pdev->devfn), pdev->irq)); -+ -+ /* use bcmsdh_query_device() to get the vendor ID of the target device so -+ * it will eventually appear in the Broadcom string on the console -+ */ -+ -+ /* allocate SDIO Host Controller state info */ -+ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { -+ SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+ if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) { -+ SDLX_MSG(("%s: out of memory, allocated %d bytes\n", -+ __FUNCTION__, -+ MALLOCED(osh))); -+ goto err; -+ } -+ bzero(sdhc, sizeof(bcmsdh_hc_t)); -+ sdhc->osh = osh; -+ -+ sdhc->dev = pdev; -+ -+ /* map to address where host can access */ -+ pci_set_master(pdev); -+ rc = pci_enable_device(pdev); -+ if (rc) { -+ SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__)); -+ goto err; -+ } -+ if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0), -+ (void **)®s, pdev->irq))) { -+ SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ sdhc->sdh = sdh; -+ -+ /* try to attach to the target device */ -+ if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */ -+ bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0, -+ (void *)regs, NULL, sdh))) { -+ SDLX_MSG(("%s: device attach failed\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ /* chain SDIO Host Controller info together */ -+ sdhc->next = sdhcinfo; -+ sdhcinfo = sdhc; -+ -+ return 0; -+ -+ /* error handling */ -+err: -+ if (sdhc) { -+ if (sdhc->sdh) -+ bcmsdh_detach(sdhc->osh, sdhc->sdh); -+ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); -+ } -+ if (osh) -+ osl_detach(osh); -+ return -ENODEV; -+} -+ -+ -+/** -+ * Detach from target devices and SDIO Host Controller -+ */ -+static void __devexit -+bcmsdh_pci_remove(struct pci_dev *pdev) -+{ -+ bcmsdh_hc_t *sdhc, *prev; -+ osl_t *osh; -+ -+ /* find the SDIO Host Controller state for this pdev and take it out from the list */ -+ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { -+ if (sdhc->dev == pdev) { -+ if (prev) -+ prev->next = sdhc->next; -+ else -+ sdhcinfo = NULL; -+ break; -+ } -+ prev = sdhc; -+ } -+ if (!sdhc) -+ return; -+ -+ drvinfo.detach(sdhc->ch); -+ -+ bcmsdh_detach(sdhc->osh, sdhc->sdh); -+ -+ /* release SDIO Host Controller info */ -+ osh = sdhc->osh; -+ MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); -+ osl_detach(osh); -+} -+#endif /* BCMLXSDMMC */ -+#endif /* BCMPLATFORM_BUS */ -+ -+extern int sdio_function_init(void); -+ -+extern int sdio_func_reg_notify(void* semaphore); -+extern void sdio_func_unreg_notify(void); -+ -+#if defined(BCMLXSDMMC) -+int bcmsdh_reg_sdio_notify(void* semaphore) -+{ -+ return sdio_func_reg_notify(semaphore); -+} -+ -+void bcmsdh_unreg_sdio_notify(void) -+{ -+ sdio_func_unreg_notify(); -+} -+#endif /* defined(BCMLXSDMMC) */ -+ -+int -+bcmsdh_register(bcmsdh_driver_t *driver) -+{ -+ int error = 0; -+ -+ drvinfo = *driver; -+ -+#if defined(BCMPLATFORM_BUS) -+ SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n")); -+ error = sdio_function_init(); -+ return error; -+#endif /* defined(BCMPLATFORM_BUS) */ -+ -+#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -+ if (!(error = pci_module_init(&bcmsdh_pci_driver))) -+ return 0; -+#else -+ if (!(error = pci_register_driver(&bcmsdh_pci_driver))) -+ return 0; -+#endif -+ -+ SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error)); -+#endif /* BCMPLATFORM_BUS */ -+ -+ return error; -+} -+ -+extern void sdio_function_cleanup(void); -+ -+void -+bcmsdh_unregister(void) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -+ if (bcmsdh_pci_driver.node.next) -+#endif -+ -+#if defined(BCMLXSDMMC) -+ sdio_function_cleanup(); -+#endif /* BCMLXSDMMC */ -+ -+#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) -+ pci_unregister_driver(&bcmsdh_pci_driver); -+#endif /* BCMPLATFORM_BUS */ -+} -+ -+#if defined(OOB_INTR_ONLY) -+void bcmsdh_oob_intr_set(bool enable) -+{ -+ static bool curstate = 1; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sdhcinfo->irq_lock, flags); -+ if (curstate != enable) { -+ if (enable) -+ enable_irq(sdhcinfo->oob_irq); -+ else -+ disable_irq_nosync(sdhcinfo->oob_irq); -+ curstate = enable; -+ } -+ spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags); -+} -+ -+static irqreturn_t wlan_oob_irq(int irq, void *dev_id) -+{ -+ dhd_pub_t *dhdp; -+ -+ dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev); -+ -+ bcmsdh_oob_intr_set(0); -+ -+ if (dhdp == NULL) { -+ SDLX_MSG(("Out of band GPIO interrupt fired way too early\n")); -+ return IRQ_HANDLED; -+ } -+ -+ dhdsdio_isr((void *)dhdp->bus); -+ -+ return IRQ_HANDLED; -+} -+ -+int bcmsdh_register_oob_intr(void * dhdp) -+{ -+ int error = 0; -+ -+ SDLX_MSG(("%s Enter \n", __FUNCTION__)); -+ -+ /* IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */ -+ -+ dev_set_drvdata(sdhcinfo->dev, dhdp); -+ -+ if (!sdhcinfo->oob_irq_registered) { -+ SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__, -+ (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags)); -+ /* Refer to customer Host IRQ docs about proper irqflags definition */ -+ error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags, -+ "bcmsdh_sdmmc", NULL); -+ if (error) -+ return -ENODEV; -+ -+ error = enable_irq_wake(sdhcinfo->oob_irq); -+ if (error) -+ SDLX_MSG(("%s enable_irq_wake error=%d \n", __FUNCTION__, error)); -+ sdhcinfo->oob_irq_registered = TRUE; -+ sdhcinfo->oob_irq_enable_flag = TRUE; -+ } -+ -+ return 0; -+} -+ -+void bcmsdh_set_irq(int flag) -+{ -+ if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) { -+ SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag)); -+ sdhcinfo->oob_irq_enable_flag = flag; -+ if (flag) { -+ enable_irq(sdhcinfo->oob_irq); -+ enable_irq_wake(sdhcinfo->oob_irq); -+ } else { -+ disable_irq_wake(sdhcinfo->oob_irq); -+ disable_irq(sdhcinfo->oob_irq); -+ } -+ } -+} -+ -+void bcmsdh_unregister_oob_intr(void) -+{ -+ SDLX_MSG(("%s: Enter\n", __FUNCTION__)); -+ -+ if (sdhcinfo->oob_irq_registered == TRUE) { -+ bcmsdh_set_irq(FALSE); -+ free_irq(sdhcinfo->oob_irq, NULL); -+ sdhcinfo->oob_irq_registered = FALSE; -+ } -+} -+#endif /* defined(OOB_INTR_ONLY) */ -+ -+#if defined(BCMLXSDMMC) -+void *bcmsdh_get_drvdata(void) -+{ -+ if (!sdhcinfo) -+ return NULL; -+ return dev_get_drvdata(sdhcinfo->dev); -+} -+#endif -+ -+/* Module parameters specific to each host-controller driver */ -+ -+extern uint sd_msglevel; /* Debug message level */ -+module_param(sd_msglevel, uint, 0); -+ -+extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ -+module_param(sd_power, uint, 0); -+ -+extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ -+module_param(sd_clock, uint, 0); -+ -+extern uint sd_divisor; /* Divisor (-1 means external clock) */ -+module_param(sd_divisor, uint, 0); -+ -+extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ -+module_param(sd_sdmode, uint, 0); -+ -+extern uint sd_hiok; /* Ok to use hi-speed mode */ -+module_param(sd_hiok, uint, 0); -+ -+extern uint sd_f2_blocksize; -+module_param(sd_f2_blocksize, int, 0); -+ -+#ifdef BCMSDIOH_STD -+extern int sd_uhsimode; -+module_param(sd_uhsimode, int, 0); -+#endif -+ -+#ifdef BCMSDIOH_TXGLOM -+extern uint sd_txglom; -+module_param(sd_txglom, uint, 0); -+#endif -+ -+#ifdef BCMSDH_MODULE -+EXPORT_SYMBOL(bcmsdh_attach); -+EXPORT_SYMBOL(bcmsdh_detach); -+EXPORT_SYMBOL(bcmsdh_intr_query); -+EXPORT_SYMBOL(bcmsdh_intr_enable); -+EXPORT_SYMBOL(bcmsdh_intr_disable); -+EXPORT_SYMBOL(bcmsdh_intr_reg); -+EXPORT_SYMBOL(bcmsdh_intr_dereg); -+ -+#if defined(DHD_DEBUG) -+EXPORT_SYMBOL(bcmsdh_intr_pending); -+#endif -+ -+EXPORT_SYMBOL(bcmsdh_devremove_reg); -+EXPORT_SYMBOL(bcmsdh_cfg_read); -+EXPORT_SYMBOL(bcmsdh_cfg_write); -+EXPORT_SYMBOL(bcmsdh_cis_read); -+EXPORT_SYMBOL(bcmsdh_reg_read); -+EXPORT_SYMBOL(bcmsdh_reg_write); -+EXPORT_SYMBOL(bcmsdh_regfail); -+EXPORT_SYMBOL(bcmsdh_send_buf); -+EXPORT_SYMBOL(bcmsdh_recv_buf); -+ -+EXPORT_SYMBOL(bcmsdh_rwdata); -+EXPORT_SYMBOL(bcmsdh_abort); -+EXPORT_SYMBOL(bcmsdh_query_device); -+EXPORT_SYMBOL(bcmsdh_query_iofnum); -+EXPORT_SYMBOL(bcmsdh_iovar_op); -+EXPORT_SYMBOL(bcmsdh_register); -+EXPORT_SYMBOL(bcmsdh_unregister); -+EXPORT_SYMBOL(bcmsdh_chipmatch); -+EXPORT_SYMBOL(bcmsdh_reset); -+EXPORT_SYMBOL(bcmsdh_waitlockfree); -+ -+EXPORT_SYMBOL(bcmsdh_get_dstatus); -+EXPORT_SYMBOL(bcmsdh_cfg_read_word); -+EXPORT_SYMBOL(bcmsdh_cfg_write_word); -+EXPORT_SYMBOL(bcmsdh_cur_sbwad); -+EXPORT_SYMBOL(bcmsdh_chipinfo); -+ -+#endif /* BCMSDH_MODULE */ -diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c -new file mode 100644 -index 00000000..046bd028 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c -@@ -0,0 +1,1504 @@ -+/* -+ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdh_sdmmc.c 379078 2013-01-16 00:41:36Z $ -+ */ -+#include <typedefs.h> -+ -+#include <bcmdevs.h> -+#include <bcmendian.h> -+#include <bcmutils.h> -+#include <osl.h> -+#include <sdio.h> /* SDIO Device and Protocol Specs */ -+#include <sdioh.h> /* Standard SDIO Host Controller Specification */ -+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ -+#include <sdiovar.h> /* ioctl/iovars */ -+ -+#include <linux/mmc/core.h> -+#include <linux/mmc/card.h> -+#include <linux/mmc/sdio_func.h> -+#include <linux/mmc/sdio_ids.h> -+ -+#include <dngl_stats.h> -+#include <dhd.h> -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -+#include <linux/suspend.h> -+extern volatile bool dhd_mmc_suspend; -+#endif -+#include "bcmsdh_sdmmc.h" -+ -+#ifndef BCMSDH_MODULE -+extern int sdio_function_init(void); -+extern void sdio_function_cleanup(void); -+#endif /* BCMSDH_MODULE */ -+ -+#if !defined(OOB_INTR_ONLY) -+static void IRQHandler(struct sdio_func *func); -+static void IRQHandlerF2(struct sdio_func *func); -+#endif /* !defined(OOB_INTR_ONLY) */ -+static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); -+extern int sdio_reset_comm(struct mmc_card *card); -+ -+extern PBCMSDH_SDMMC_INSTANCE gInstance; -+ -+#define DEFAULT_SDIO_F2_BLKSIZE 512 -+#ifndef CUSTOM_SDIO_F2_BLKSIZE -+#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE -+#endif -+ -+uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ -+uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; -+uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ -+ -+uint sd_power = 1; /* Default to SD Slot powered ON */ -+uint sd_clock = 1; /* Default to SD Clock turned ON */ -+uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ -+uint sd_msglevel = 0x01; -+uint sd_use_dma = TRUE; -+DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); -+DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); -+DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); -+DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); -+ -+#define DMA_ALIGN_MASK 0x03 -+#define MMC_SDIO_ABORT_RETRY_LIMIT 5 -+ -+int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); -+ -+static int -+sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) -+{ -+ int err_ret; -+ uint32 fbraddr; -+ uint8 func; -+ -+ sd_trace(("%s\n", __FUNCTION__)); -+ -+ /* Get the Card's common CIS address */ -+ sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); -+ sd->func_cis_ptr[0] = sd->com_cis_ptr; -+ sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); -+ -+ /* Get the Card's function CIS (for each function) */ -+ for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; -+ func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { -+ sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); -+ sd_info(("%s: Function %d CIS Ptr = 0x%x\n", -+ __FUNCTION__, func, sd->func_cis_ptr[func])); -+ } -+ -+ sd->func_cis_ptr[0] = sd->com_cis_ptr; -+ sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); -+ -+ /* Enable Function 1 */ -+ sdio_claim_host(gInstance->func[1]); -+ err_ret = sdio_enable_func(gInstance->func[1]); -+ sdio_release_host(gInstance->func[1]); -+ if (err_ret) { -+ sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret)); -+ } -+ -+ return FALSE; -+} -+ -+/* -+ * Public entry points & extern's -+ */ -+extern sdioh_info_t * -+sdioh_attach(osl_t *osh, void *bar0, uint irq) -+{ -+ sdioh_info_t *sd; -+ int err_ret; -+ -+ sd_trace(("%s\n", __FUNCTION__)); -+ -+ if (gInstance == NULL) { -+ sd_err(("%s: SDIO Device not present\n", __FUNCTION__)); -+ return NULL; -+ } -+ -+ if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { -+ sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); -+ return NULL; -+ } -+ bzero((char *)sd, sizeof(sdioh_info_t)); -+ sd->osh = osh; -+ if (sdioh_sdmmc_osinit(sd) != 0) { -+ sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__)); -+ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); -+ return NULL; -+ } -+ -+ sd->num_funcs = 2; -+ sd->sd_blockmode = TRUE; -+ sd->use_client_ints = TRUE; -+ sd->client_block_size[0] = 64; -+ sd->use_rxchain = FALSE; -+ -+ gInstance->sd = sd; -+ -+ /* Claim host controller */ -+ if (gInstance->func[1]) { -+ sdio_claim_host(gInstance->func[1]); -+ -+ sd->client_block_size[1] = 64; -+ err_ret = sdio_set_block_size(gInstance->func[1], 64); -+ if (err_ret) { -+ sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); -+ } -+ -+ /* Release host controller F1 */ -+ sdio_release_host(gInstance->func[1]); -+ } else { -+ sd_err(("%s:gInstance->func[1] is null\n", __FUNCTION__)); -+ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); -+ return NULL; -+ } -+ -+ if (gInstance->func[2]) { -+ /* Claim host controller F2 */ -+ sdio_claim_host(gInstance->func[2]); -+ -+ sd->client_block_size[2] = sd_f2_blocksize; -+ err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize); -+ if (err_ret) { -+ sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n", -+ sd_f2_blocksize)); -+ } -+ -+ /* Release host controller F2 */ -+ sdio_release_host(gInstance->func[2]); -+ } else { -+ sd_err(("%s:gInstance->func[2] is null\n", __FUNCTION__)); -+ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); -+ return NULL; -+ } -+ -+ sdioh_sdmmc_card_enablefuncs(sd); -+ -+ sd_trace(("%s: Done\n", __FUNCTION__)); -+ return sd; -+} -+ -+ -+extern SDIOH_API_RC -+sdioh_detach(osl_t *osh, sdioh_info_t *sd) -+{ -+ sd_trace(("%s\n", __FUNCTION__)); -+ -+ if (sd) { -+ -+ /* Disable Function 2 */ -+ sdio_claim_host(gInstance->func[2]); -+ sdio_disable_func(gInstance->func[2]); -+ sdio_release_host(gInstance->func[2]); -+ -+ /* Disable Function 1 */ -+ if (gInstance->func[1]) { -+ sdio_claim_host(gInstance->func[1]); -+ sdio_disable_func(gInstance->func[1]); -+ sdio_release_host(gInstance->func[1]); -+ } -+ -+ gInstance->func[1] = NULL; -+ gInstance->func[2] = NULL; -+ -+ /* deregister irq */ -+ sdioh_sdmmc_osfree(sd); -+ -+ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); -+ } -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -+ -+extern SDIOH_API_RC -+sdioh_enable_func_intr(void) -+{ -+ uint8 reg; -+ int err; -+ -+ if (gInstance->func[0]) { -+ sdio_claim_host(gInstance->func[0]); -+ -+ reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); -+ if (err) { -+ sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); -+ sdio_release_host(gInstance->func[0]); -+ return SDIOH_API_RC_FAIL; -+ } -+ -+ /* Enable F1 and F2 interrupts, clear master enable */ -+ reg &= ~INTR_CTL_MASTER_EN; -+ reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); -+ sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); -+ sdio_release_host(gInstance->func[0]); -+ -+ if (err) { -+ sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); -+ return SDIOH_API_RC_FAIL; -+ } -+ } -+ -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+extern SDIOH_API_RC -+sdioh_disable_func_intr(void) -+{ -+ uint8 reg; -+ int err; -+ -+ if (gInstance->func[0]) { -+ sdio_claim_host(gInstance->func[0]); -+ reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err); -+ if (err) { -+ sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); -+ sdio_release_host(gInstance->func[0]); -+ return SDIOH_API_RC_FAIL; -+ } -+ -+ reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); -+ /* Disable master interrupt with the last function interrupt */ -+ if (!(reg & 0xFE)) -+ reg = 0; -+ sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err); -+ -+ sdio_release_host(gInstance->func[0]); -+ if (err) { -+ sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); -+ return SDIOH_API_RC_FAIL; -+ } -+ } -+ return SDIOH_API_RC_SUCCESS; -+} -+#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ -+ -+/* Configure callback to client when we recieve client interrupt */ -+extern SDIOH_API_RC -+sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -+{ -+ sd_trace(("%s: Entering\n", __FUNCTION__)); -+ if (fn == NULL) { -+ sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); -+ return SDIOH_API_RC_FAIL; -+ } -+#if !defined(OOB_INTR_ONLY) -+ sd->intr_handler = fn; -+ sd->intr_handler_arg = argh; -+ sd->intr_handler_valid = TRUE; -+ -+ /* register and unmask irq */ -+ if (gInstance->func[2]) { -+ sdio_claim_host(gInstance->func[2]); -+ sdio_claim_irq(gInstance->func[2], IRQHandlerF2); -+ sdio_release_host(gInstance->func[2]); -+ } -+ -+ if (gInstance->func[1]) { -+ sdio_claim_host(gInstance->func[1]); -+ sdio_claim_irq(gInstance->func[1], IRQHandler); -+ sdio_release_host(gInstance->func[1]); -+ } -+#elif defined(HW_OOB) -+ sdioh_enable_func_intr(); -+#endif /* !defined(OOB_INTR_ONLY) */ -+ -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+extern SDIOH_API_RC -+sdioh_interrupt_deregister(sdioh_info_t *sd) -+{ -+ sd_trace(("%s: Entering\n", __FUNCTION__)); -+ -+#if !defined(OOB_INTR_ONLY) -+ if (gInstance->func[1]) { -+ /* register and unmask irq */ -+ sdio_claim_host(gInstance->func[1]); -+ sdio_release_irq(gInstance->func[1]); -+ sdio_release_host(gInstance->func[1]); -+ } -+ -+ if (gInstance->func[2]) { -+ /* Claim host controller F2 */ -+ sdio_claim_host(gInstance->func[2]); -+ sdio_release_irq(gInstance->func[2]); -+ /* Release host controller F2 */ -+ sdio_release_host(gInstance->func[2]); -+ } -+ -+ sd->intr_handler_valid = FALSE; -+ sd->intr_handler = NULL; -+ sd->intr_handler_arg = NULL; -+#elif defined(HW_OOB) -+ sdioh_disable_func_intr(); -+#endif /* !defined(OOB_INTR_ONLY) */ -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+extern SDIOH_API_RC -+sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -+{ -+ sd_trace(("%s: Entering\n", __FUNCTION__)); -+ *onoff = sd->client_intr_enabled; -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+#if defined(DHD_DEBUG) -+extern bool -+sdioh_interrupt_pending(sdioh_info_t *sd) -+{ -+ return (0); -+} -+#endif -+ -+uint -+sdioh_query_iofnum(sdioh_info_t *sd) -+{ -+ return sd->num_funcs; -+} -+ -+/* IOVar table */ -+enum { -+ IOV_MSGLEVEL = 1, -+ IOV_BLOCKMODE, -+ IOV_BLOCKSIZE, -+ IOV_DMA, -+ IOV_USEINTS, -+ IOV_NUMINTS, -+ IOV_NUMLOCALINTS, -+ IOV_HOSTREG, -+ IOV_DEVREG, -+ IOV_DIVISOR, -+ IOV_SDMODE, -+ IOV_HISPEED, -+ IOV_HCIREGS, -+ IOV_POWER, -+ IOV_CLOCK, -+ IOV_RXCHAIN -+}; -+ -+const bcm_iovar_t sdioh_iovars[] = { -+ {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, -+ {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, -+ {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ -+ {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, -+ {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, -+ {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, -+ {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, -+ {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, -+ {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, -+ {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, -+ {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, -+ {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, -+ {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, -+ {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 }, -+ {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 }, -+ {NULL, 0, 0, 0, 0 } -+}; -+ -+int -+sdioh_iovar_op(sdioh_info_t *si, const char *name, -+ void *params, int plen, void *arg, int len, bool set) -+{ -+ const bcm_iovar_t *vi = NULL; -+ int bcmerror = 0; -+ int val_size; -+ int32 int_val = 0; -+ bool bool_val; -+ uint32 actionid; -+ -+ ASSERT(name); -+ ASSERT(len >= 0); -+ -+ /* Get must have return space; Set does not take qualifiers */ -+ ASSERT(set || (arg && len)); -+ ASSERT(!set || (!params && !plen)); -+ -+ sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); -+ -+ if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { -+ bcmerror = BCME_UNSUPPORTED; -+ goto exit; -+ } -+ -+ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) -+ goto exit; -+ -+ /* Set up params so get and set can share the convenience variables */ -+ if (params == NULL) { -+ params = arg; -+ plen = len; -+ } -+ -+ if (vi->type == IOVT_VOID) -+ val_size = 0; -+ else if (vi->type == IOVT_BUFFER) -+ val_size = len; -+ else -+ val_size = sizeof(int); -+ -+ if (plen >= (int)sizeof(int_val)) -+ bcopy(params, &int_val, sizeof(int_val)); -+ -+ bool_val = (int_val != 0) ? TRUE : FALSE; -+ BCM_REFERENCE(bool_val); -+ -+ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); -+ switch (actionid) { -+ case IOV_GVAL(IOV_MSGLEVEL): -+ int_val = (int32)sd_msglevel; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_MSGLEVEL): -+ sd_msglevel = int_val; -+ break; -+ -+ case IOV_GVAL(IOV_BLOCKMODE): -+ int_val = (int32)si->sd_blockmode; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_BLOCKMODE): -+ si->sd_blockmode = (bool)int_val; -+ /* Haven't figured out how to make non-block mode with DMA */ -+ break; -+ -+ case IOV_GVAL(IOV_BLOCKSIZE): -+ if ((uint32)int_val > si->num_funcs) { -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ int_val = (int32)si->client_block_size[int_val]; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_BLOCKSIZE): -+ { -+ uint func = ((uint32)int_val >> 16); -+ uint blksize = (uint16)int_val; -+ uint maxsize; -+ -+ if (func > si->num_funcs) { -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ -+ switch (func) { -+ case 0: maxsize = 32; break; -+ case 1: maxsize = BLOCK_SIZE_4318; break; -+ case 2: maxsize = BLOCK_SIZE_4328; break; -+ default: maxsize = 0; -+ } -+ if (blksize > maxsize) { -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ if (!blksize) { -+ blksize = maxsize; -+ } -+ -+ /* Now set it */ -+ si->client_block_size[func] = blksize; -+ -+ break; -+ } -+ -+ case IOV_GVAL(IOV_RXCHAIN): -+ int_val = (int32)si->use_rxchain; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_GVAL(IOV_DMA): -+ int_val = (int32)si->sd_use_dma; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_DMA): -+ si->sd_use_dma = (bool)int_val; -+ break; -+ -+ case IOV_GVAL(IOV_USEINTS): -+ int_val = (int32)si->use_client_ints; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_USEINTS): -+ si->use_client_ints = (bool)int_val; -+ if (si->use_client_ints) -+ si->intmask |= CLIENT_INTR; -+ else -+ si->intmask &= ~CLIENT_INTR; -+ -+ break; -+ -+ case IOV_GVAL(IOV_DIVISOR): -+ int_val = (uint32)sd_divisor; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_DIVISOR): -+ sd_divisor = int_val; -+ break; -+ -+ case IOV_GVAL(IOV_POWER): -+ int_val = (uint32)sd_power; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_POWER): -+ sd_power = int_val; -+ break; -+ -+ case IOV_GVAL(IOV_CLOCK): -+ int_val = (uint32)sd_clock; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_CLOCK): -+ sd_clock = int_val; -+ break; -+ -+ case IOV_GVAL(IOV_SDMODE): -+ int_val = (uint32)sd_sdmode; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_SDMODE): -+ sd_sdmode = int_val; -+ break; -+ -+ case IOV_GVAL(IOV_HISPEED): -+ int_val = (uint32)sd_hiok; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_HISPEED): -+ sd_hiok = int_val; -+ break; -+ -+ case IOV_GVAL(IOV_NUMINTS): -+ int_val = (int32)si->intrcount; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_GVAL(IOV_NUMLOCALINTS): -+ int_val = (int32)0; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_GVAL(IOV_HOSTREG): -+ { -+ sdreg_t *sd_ptr = (sdreg_t *)params; -+ -+ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { -+ sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ -+ sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__, -+ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), -+ sd_ptr->offset)); -+ if (sd_ptr->offset & 1) -+ int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */ -+ else if (sd_ptr->offset & 2) -+ int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */ -+ else -+ int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */ -+ -+ bcopy(&int_val, arg, sizeof(int_val)); -+ break; -+ } -+ -+ case IOV_SVAL(IOV_HOSTREG): -+ { -+ sdreg_t *sd_ptr = (sdreg_t *)params; -+ -+ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) { -+ sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset)); -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ -+ sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value, -+ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32), -+ sd_ptr->offset)); -+ break; -+ } -+ -+ case IOV_GVAL(IOV_DEVREG): -+ { -+ sdreg_t *sd_ptr = (sdreg_t *)params; -+ uint8 data = 0; -+ -+ if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { -+ bcmerror = BCME_SDIO_ERROR; -+ break; -+ } -+ -+ int_val = (int)data; -+ bcopy(&int_val, arg, sizeof(int_val)); -+ break; -+ } -+ -+ case IOV_SVAL(IOV_DEVREG): -+ { -+ sdreg_t *sd_ptr = (sdreg_t *)params; -+ uint8 data = (uint8)sd_ptr->value; -+ -+ if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { -+ bcmerror = BCME_SDIO_ERROR; -+ break; -+ } -+ break; -+ } -+ -+ default: -+ bcmerror = BCME_UNSUPPORTED; -+ break; -+ } -+exit: -+ -+ return bcmerror; -+} -+ -+#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -+ -+SDIOH_API_RC -+sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) -+{ -+ SDIOH_API_RC status; -+ uint8 data; -+ -+ if (enable) -+ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; -+ else -+ data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ -+ -+ status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); -+ return status; -+} -+#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ -+ -+extern SDIOH_API_RC -+sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -+{ -+ SDIOH_API_RC status; -+ /* No lock needed since sdioh_request_byte does locking */ -+ status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); -+ return status; -+} -+ -+extern SDIOH_API_RC -+sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -+{ -+ /* No lock needed since sdioh_request_byte does locking */ -+ SDIOH_API_RC status; -+ status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); -+ return status; -+} -+ -+static int -+sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) -+{ -+ /* read 24 bits and return valid 17 bit addr */ -+ int i; -+ uint32 scratch, regdata; -+ uint8 *ptr = (uint8 *)&scratch; -+ for (i = 0; i < 3; i++) { -+ if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) -+ sd_err(("%s: Can't read!\n", __FUNCTION__)); -+ -+ *ptr++ = (uint8) regdata; -+ regaddr++; -+ } -+ -+ /* Only the lower 17-bits are valid */ -+ scratch = ltoh32(scratch); -+ scratch &= 0x0001FFFF; -+ return (scratch); -+} -+ -+extern SDIOH_API_RC -+sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -+{ -+ uint32 count; -+ int offset; -+ uint32 foo; -+ uint8 *cis = cisd; -+ -+ sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); -+ -+ if (!sd->func_cis_ptr[func]) { -+ bzero(cis, length); -+ sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); -+ return SDIOH_API_RC_FAIL; -+ } -+ -+ sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); -+ -+ for (count = 0; count < length; count++) { -+ offset = sd->func_cis_ptr[func] + count; -+ if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { -+ sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); -+ return SDIOH_API_RC_FAIL; -+ } -+ -+ *cis = (uint8)(foo & 0xff); -+ cis++; -+ } -+ -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+extern SDIOH_API_RC -+sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -+{ -+ int err_ret; -+#if defined(MMC_SDIO_ABORT) -+ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -+#endif -+ sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); -+ -+ DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); -+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); -+ if(rw) { /* CMD52 Write */ -+ if (func == 0) { -+ /* Can only directly write to some F0 registers. Handle F2 enable -+ * as a special case. -+ */ -+ if (regaddr == SDIOD_CCCR_IOEN) { -+ if (gInstance->func[2]) { -+ sdio_claim_host(gInstance->func[2]); -+ if (*byte & SDIO_FUNC_ENABLE_2) { -+ /* Enable Function 2 */ -+ err_ret = sdio_enable_func(gInstance->func[2]); -+ if (err_ret) { -+ sd_err(("bcmsdh_sdmmc: enable F2 failed:%d", -+ err_ret)); -+ } -+ } else { -+ /* Disable Function 2 */ -+ err_ret = sdio_disable_func(gInstance->func[2]); -+ if (err_ret) { -+ sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d", -+ err_ret)); -+ } -+ } -+ sdio_release_host(gInstance->func[2]); -+ } -+ } -+#if defined(MMC_SDIO_ABORT) -+ /* to allow abort command through F1 */ -+ else if (regaddr == SDIOD_CCCR_IOABORT) { -+ while (sdio_abort_retry--) { -+ if (gInstance->func[func]) { -+ sdio_claim_host(gInstance->func[func]); -+ /* -+ * this sdio_f0_writeb() can be replaced with -+ * another api depending upon MMC driver change. -+ * As of this time, this is temporaray one -+ */ -+ sdio_writeb(gInstance->func[func], -+ *byte, regaddr, &err_ret); -+ sdio_release_host(gInstance->func[func]); -+ } -+ if (!err_ret) -+ break; -+ } -+ } -+#endif /* MMC_SDIO_ABORT */ -+ else if (regaddr < 0xF0) { -+ sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); -+ } else { -+ /* Claim host controller, perform F0 write, and release */ -+ if (gInstance->func[func]) { -+ sdio_claim_host(gInstance->func[func]); -+ sdio_f0_writeb(gInstance->func[func], -+ *byte, regaddr, &err_ret); -+ sdio_release_host(gInstance->func[func]); -+ } -+ } -+ } else { -+ /* Claim host controller, perform Fn write, and release */ -+ if (gInstance->func[func]) { -+ sdio_claim_host(gInstance->func[func]); -+ sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret); -+ sdio_release_host(gInstance->func[func]); -+ } -+ } -+ } else { /* CMD52 Read */ -+ /* Claim host controller, perform Fn read, and release */ -+ if (gInstance->func[func]) { -+ sdio_claim_host(gInstance->func[func]); -+ if (func == 0) { -+ *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret); -+ } else { -+ *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret); -+ } -+ sdio_release_host(gInstance->func[func]); -+ } -+ } -+ -+ if (err_ret) { -+ sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", -+ rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); -+ } -+ -+ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -+} -+ -+extern SDIOH_API_RC -+sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, -+ uint32 *word, uint nbytes) -+{ -+ int err_ret = SDIOH_API_RC_FAIL; -+#if defined(MMC_SDIO_ABORT) -+ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -+#endif -+ -+ if (func == 0) { -+ sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); -+ return SDIOH_API_RC_FAIL; -+ } -+ -+ sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", -+ __FUNCTION__, cmd_type, rw, func, addr, nbytes)); -+ -+ DHD_PM_RESUME_WAIT(sdioh_request_word_wait); -+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); -+ /* Claim host controller */ -+ sdio_claim_host(gInstance->func[func]); -+ -+ if(rw) { /* CMD53 Write */ -+ if (nbytes == 4) { -+ sdio_writel(gInstance->func[func], *word, addr, &err_ret); -+ } else if (nbytes == 2) { -+ sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret); -+ } else { -+ sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); -+ } -+ } else { /* CMD52 Read */ -+ if (nbytes == 4) { -+ *word = sdio_readl(gInstance->func[func], addr, &err_ret); -+ } else if (nbytes == 2) { -+ *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF; -+ } else { -+ sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); -+ } -+ } -+ -+ /* Release host controller */ -+ sdio_release_host(gInstance->func[func]); -+ -+ if (err_ret) { -+#if defined(MMC_SDIO_ABORT) -+ /* Any error on CMD53 transaction should abort that function using function 0. */ -+ while (sdio_abort_retry--) { -+ if (gInstance->func[0]) { -+ sdio_claim_host(gInstance->func[0]); -+ /* -+ * this sdio_f0_writeb() can be replaced with another api -+ * depending upon MMC driver change. -+ * As of this time, this is temporaray one -+ */ -+ sdio_writeb(gInstance->func[0], -+ func, SDIOD_CCCR_IOABORT, &err_ret); -+ sdio_release_host(gInstance->func[0]); -+ } -+ if (!err_ret) -+ break; -+ } -+ if (err_ret) -+#endif /* MMC_SDIO_ABORT */ -+ { -+ sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n", -+ rw ? "Write" : "Read", err_ret)); -+ } -+ } -+ -+ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -+} -+ -+static SDIOH_API_RC -+sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, -+ uint addr, void *pkt) -+{ -+ bool fifo = (fix_inc == SDIOH_DATA_FIX); -+ uint32 SGCount = 0; -+ int err_ret = 0; -+ void *pnext, *pprev; -+ uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; -+ uint blk_num; -+ int blk_size; -+ struct mmc_request mmc_req; -+ struct mmc_command mmc_cmd; -+ struct mmc_data mmc_dat; -+ -+ sd_trace(("%s: Enter\n", __FUNCTION__)); -+ -+ ASSERT(pkt); -+ DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); -+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); -+ -+ ttl_len = xfred_len = 0; -+ /* at least 4 bytes alignment of skb buff is guaranteed */ -+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) -+ ttl_len += PKTLEN(sd->osh, pnext); -+ -+ blk_size = sd->client_block_size[func]; -+ if (!sd->use_rxchain || ttl_len <= blk_size) { -+ blk_num = 0; -+ dma_len = 0; -+ } else { -+ blk_num = ttl_len / blk_size; -+ dma_len = blk_num * blk_size; -+ } -+ lft_len = ttl_len - dma_len; -+ -+ sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n", -+ __FUNCTION__, write ? "W" : "R", -+ ttl_len, func, addr, blk_num, lft_len)); -+ -+ if (0 != dma_len) { -+ memset(&mmc_req, 0, sizeof(struct mmc_request)); -+ memset(&mmc_cmd, 0, sizeof(struct mmc_command)); -+ memset(&mmc_dat, 0, sizeof(struct mmc_data)); -+ -+ /* Set up DMA descriptors */ -+ pprev = pkt; -+ for (pnext = pkt; -+ pnext && dma_len; -+ pnext = PKTNEXT(sd->osh, pnext)) { -+ pkt_len = PKTLEN(sd->osh, pnext); -+ -+ if (dma_len > pkt_len) -+ dma_len -= pkt_len; -+ else { -+ pkt_len = xfred_len = dma_len; -+ dma_len = 0; -+ pkt = pnext; -+ } -+ -+ sg_set_buf(&sd->sg_list[SGCount++], -+ (uint8*)PKTDATA(sd->osh, pnext), -+ pkt_len); -+ -+ if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) { -+ sd_err(("%s: sg list entries exceed limit\n", -+ __FUNCTION__)); -+ return (SDIOH_API_RC_FAIL); -+ } -+ } -+ -+ mmc_dat.sg = sd->sg_list; -+ mmc_dat.sg_len = SGCount; -+ mmc_dat.blksz = blk_size; -+ mmc_dat.blocks = blk_num; -+ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; -+ -+ mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ -+ mmc_cmd.arg = write ? 1<<31 : 0; -+ mmc_cmd.arg |= (func & 0x7) << 28; -+ mmc_cmd.arg |= 1<<27; -+ mmc_cmd.arg |= fifo ? 0 : 1<<26; -+ mmc_cmd.arg |= (addr & 0x1FFFF) << 9; -+ mmc_cmd.arg |= blk_num & 0x1FF; -+ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; -+ -+ mmc_req.cmd = &mmc_cmd; -+ mmc_req.data = &mmc_dat; -+ -+ sdio_claim_host(gInstance->func[func]); -+ mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card); -+ mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req); -+ sdio_release_host(gInstance->func[func]); -+ -+ err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; -+ if (0 != err_ret) { -+ sd_err(("%s:CMD53 %s failed with code %d\n", -+ __FUNCTION__, -+ write ? "write" : "read", -+ err_ret)); -+ sd_err(("%s:Disabling rxchain and fire it with PIO\n", -+ __FUNCTION__)); -+ sd->use_rxchain = FALSE; -+ pkt = pprev; -+ lft_len = ttl_len; -+ } else if (!fifo) { -+ addr = addr + ttl_len - lft_len - dma_len; -+ } -+ } -+ -+ /* PIO mode */ -+ if (0 != lft_len) { -+ /* Claim host controller */ -+ sdio_claim_host(gInstance->func[func]); -+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { -+ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + -+ xfred_len; -+ pkt_len = PKTLEN(sd->osh, pnext); -+ if (0 != xfred_len) { -+ pkt_len -= xfred_len; -+ xfred_len = 0; -+ } -+ -+ /* Align Patch -+ * read or small packet(ex:BDC header) skip 32 byte align -+ * otherwise, padding DHD_SDALIGN for performance -+ */ -+ if (write == 0 || pkt_len < 32) -+ pkt_len = (pkt_len + 3) & 0xFFFFFFFC; -+ else if (pkt_len % blk_size) -+ pkt_len += blk_size - (pkt_len % blk_size); -+ -+#ifdef CONFIG_MMC_MSM7X00A -+ if ((pkt_len % 64) == 32) { -+ sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); -+ pkt_len += 32; -+ } -+#endif /* CONFIG_MMC_MSM7X00A */ -+ -+ if ((write) && (!fifo)) -+ err_ret = sdio_memcpy_toio( -+ gInstance->func[func], -+ addr, buf, pkt_len); -+ else if (write) -+ err_ret = sdio_memcpy_toio( -+ gInstance->func[func], -+ addr, buf, pkt_len); -+ else if (fifo) -+ err_ret = sdio_readsb( -+ gInstance->func[func], -+ buf, addr, pkt_len); -+ else -+ err_ret = sdio_memcpy_fromio( -+ gInstance->func[func], -+ buf, addr, pkt_len); -+ -+ if (err_ret) -+ sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n", -+ __FUNCTION__, -+ (write) ? "TX" : "RX", -+ pnext, SGCount, addr, pkt_len, err_ret)); -+ else -+ sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", -+ __FUNCTION__, -+ (write) ? "TX" : "RX", -+ pnext, SGCount, addr, pkt_len)); -+ -+ if (!fifo) -+ addr += pkt_len; -+ SGCount ++; -+ } -+ sdio_release_host(gInstance->func[func]); -+ } -+ -+ sd_trace(("%s: Exit\n", __FUNCTION__)); -+ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -+} -+ -+ -+/* -+ * This function takes a buffer or packet, and fixes everything up so that in the -+ * end, a DMA-able packet is created. -+ * -+ * A buffer does not have an associated packet pointer, and may or may not be aligned. -+ * A packet may consist of a single packet, or a packet chain. If it is a packet chain, -+ * then all the packets in the chain must be properly aligned. If the packet data is not -+ * aligned, then there may only be one packet, and in this case, it is copied to a new -+ * aligned packet. -+ * -+ */ -+extern SDIOH_API_RC -+sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, -+ uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) -+{ -+ SDIOH_API_RC Status; -+ void *mypkt = NULL; -+ -+ sd_trace(("%s: Enter\n", __FUNCTION__)); -+ -+ DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); -+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); -+ /* Case 1: we don't have a packet. */ -+ if (pkt == NULL) { -+ sd_data(("%s: Creating new %s Packet, len=%d\n", -+ __FUNCTION__, write ? "TX" : "RX", buflen_u)); -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) { -+#else -+ if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) { -+#endif /* CONFIG_DHD_USE_STATIC_BUF */ -+ sd_err(("%s: PKTGET failed: len %d\n", -+ __FUNCTION__, buflen_u)); -+ return SDIOH_API_RC_FAIL; -+ } -+ -+ /* For a write, copy the buffer data into the packet. */ -+ if (write) { -+ bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u); -+ } -+ -+ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); -+ -+ /* For a read, copy the packet data back to the buffer. */ -+ if (!write) { -+ bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u); -+ } -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); -+#else -+ PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); -+#endif /* CONFIG_DHD_USE_STATIC_BUF */ -+ } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { -+ /* Case 2: We have a packet, but it is unaligned. */ -+ -+ /* In this case, we cannot have a chain. */ -+ ASSERT(PKTNEXT(sd->osh, pkt) == NULL); -+ -+ sd_data(("%s: Creating aligned %s Packet, len=%d\n", -+ __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt))); -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { -+#else -+ if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { -+#endif /* CONFIG_DHD_USE_STATIC_BUF */ -+ sd_err(("%s: PKTGET failed: len %d\n", -+ __FUNCTION__, PKTLEN(sd->osh, pkt))); -+ return SDIOH_API_RC_FAIL; -+ } -+ -+ /* For a write, copy the buffer data into the packet. */ -+ if (write) { -+ bcopy(PKTDATA(sd->osh, pkt), -+ PKTDATA(sd->osh, mypkt), -+ PKTLEN(sd->osh, pkt)); -+ } -+ -+ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt); -+ -+ /* For a read, copy the packet data back to the buffer. */ -+ if (!write) { -+ bcopy(PKTDATA(sd->osh, mypkt), -+ PKTDATA(sd->osh, pkt), -+ PKTLEN(sd->osh, mypkt)); -+ } -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); -+#else -+ PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); -+#endif /* CONFIG_DHD_USE_STATIC_BUF */ -+ } else { /* case 3: We have a packet and it is aligned. */ -+ sd_data(("%s: Aligned %s Packet, direct DMA\n", -+ __FUNCTION__, write ? "Tx" : "Rx")); -+ Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt); -+ } -+ -+ return (Status); -+} -+ -+/* this function performs "abort" for both of host & device */ -+extern int -+sdioh_abort(sdioh_info_t *sd, uint func) -+{ -+#if defined(MMC_SDIO_ABORT) -+ char t_func = (char) func; -+#endif /* defined(MMC_SDIO_ABORT) */ -+ sd_trace(("%s: Enter\n", __FUNCTION__)); -+ -+#if defined(MMC_SDIO_ABORT) -+ /* issue abort cmd52 command through F1 */ -+ sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); -+#endif /* defined(MMC_SDIO_ABORT) */ -+ -+ sd_trace(("%s: Exit\n", __FUNCTION__)); -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+/* Reset and re-initialize the device */ -+int sdioh_sdio_reset(sdioh_info_t *si) -+{ -+ sd_trace(("%s: Enter\n", __FUNCTION__)); -+ sd_trace(("%s: Exit\n", __FUNCTION__)); -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+/* Disable device interrupt */ -+void -+sdioh_sdmmc_devintr_off(sdioh_info_t *sd) -+{ -+ sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); -+ sd->intmask &= ~CLIENT_INTR; -+} -+ -+/* Enable device interrupt */ -+void -+sdioh_sdmmc_devintr_on(sdioh_info_t *sd) -+{ -+ sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); -+ sd->intmask |= CLIENT_INTR; -+} -+ -+/* Read client card reg */ -+int -+sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -+{ -+ -+ if ((func == 0) || (regsize == 1)) { -+ uint8 temp = 0; -+ -+ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); -+ *data = temp; -+ *data &= 0xff; -+ sd_data(("%s: byte read data=0x%02x\n", -+ __FUNCTION__, *data)); -+ } else { -+ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize); -+ if (regsize == 2) -+ *data &= 0xffff; -+ -+ sd_data(("%s: word read data=0x%08x\n", -+ __FUNCTION__, *data)); -+ } -+ -+ return SUCCESS; -+} -+ -+#if !defined(OOB_INTR_ONLY) -+/* bcmsdh_sdmmc interrupt handler */ -+static void IRQHandler(struct sdio_func *func) -+{ -+ sdioh_info_t *sd; -+ -+ sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n")); -+ sd = gInstance->sd; -+ -+ ASSERT(sd != NULL); -+ sdio_release_host(gInstance->func[0]); -+ -+ if (sd->use_client_ints) { -+ sd->intrcount++; -+ ASSERT(sd->intr_handler); -+ ASSERT(sd->intr_handler_arg); -+ (sd->intr_handler)(sd->intr_handler_arg); -+ } else { -+ sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); -+ -+ sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", -+ __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); -+ } -+ -+ sdio_claim_host(gInstance->func[0]); -+} -+ -+/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ -+static void IRQHandlerF2(struct sdio_func *func) -+{ -+ sdioh_info_t *sd; -+ -+ sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); -+ -+ sd = gInstance->sd; -+ -+ ASSERT(sd != NULL); -+ BCM_REFERENCE(sd); -+} -+#endif /* !defined(OOB_INTR_ONLY) */ -+ -+#ifdef NOTUSED -+/* Write client card reg */ -+static int -+sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -+{ -+ -+ if ((func == 0) || (regsize == 1)) { -+ uint8 temp; -+ -+ temp = data & 0xff; -+ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); -+ sd_data(("%s: byte write data=0x%02x\n", -+ __FUNCTION__, data)); -+ } else { -+ if (regsize == 2) -+ data &= 0xffff; -+ -+ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); -+ -+ sd_data(("%s: word write data=0x%08x\n", -+ __FUNCTION__, data)); -+ } -+ -+ return SUCCESS; -+} -+#endif /* NOTUSED */ -+ -+int -+sdioh_start(sdioh_info_t *si, int stage) -+{ -+ int ret; -+ sdioh_info_t *sd = gInstance->sd; -+ -+ if (!sd) return (0); -+ -+ /* Need to do this stages as we can't enable the interrupt till -+ downloading of the firmware is complete, other wise polling -+ sdio access will come in way -+ */ -+ if (gInstance->func[0]) { -+ if (stage == 0) { -+ /* Since the power to the chip is killed, we will have -+ re enumerate the device again. Set the block size -+ and enable the fucntion 1 for in preparation for -+ downloading the code -+ */ -+ /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux -+ 2.6.27. The implementation prior to that is buggy, and needs broadcom's -+ patch for it -+ */ -+ if ((ret = sdio_reset_comm(gInstance->func[0]->card))) { -+ sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); -+ return ret; -+ } -+ else { -+ sd->num_funcs = 2; -+ sd->sd_blockmode = TRUE; -+ sd->use_client_ints = TRUE; -+ sd->client_block_size[0] = 64; -+ -+ if (gInstance->func[1]) { -+ /* Claim host controller */ -+ sdio_claim_host(gInstance->func[1]); -+ -+ sd->client_block_size[1] = 64; -+ if (sdio_set_block_size(gInstance->func[1], 64)) { -+ sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n")); -+ } -+ -+ /* Release host controller F1 */ -+ sdio_release_host(gInstance->func[1]); -+ } -+ -+ if (gInstance->func[2]) { -+ /* Claim host controller F2 */ -+ sdio_claim_host(gInstance->func[2]); -+ -+ sd->client_block_size[2] = sd_f2_blocksize; -+ if (sdio_set_block_size(gInstance->func[2], -+ sd_f2_blocksize)) { -+ sd_err(("bcmsdh_sdmmc: Failed to set F2 " -+ "blocksize to %d\n", sd_f2_blocksize)); -+ } -+ -+ /* Release host controller F2 */ -+ sdio_release_host(gInstance->func[2]); -+ } -+ -+ sdioh_sdmmc_card_enablefuncs(sd); -+ } -+ } else { -+#if !defined(OOB_INTR_ONLY) -+ sdio_claim_host(gInstance->func[0]); -+ if (gInstance->func[2]) -+ sdio_claim_irq(gInstance->func[2], IRQHandlerF2); -+ if (gInstance->func[1]) -+ sdio_claim_irq(gInstance->func[1], IRQHandler); -+ sdio_release_host(gInstance->func[0]); -+#else /* defined(OOB_INTR_ONLY) */ -+#if defined(HW_OOB) -+ sdioh_enable_func_intr(); -+#endif -+ bcmsdh_oob_intr_set(TRUE); -+#endif /* !defined(OOB_INTR_ONLY) */ -+ } -+ } -+ else -+ sd_err(("%s Failed\n", __FUNCTION__)); -+ -+ return (0); -+} -+ -+int -+sdioh_stop(sdioh_info_t *si) -+{ -+ /* MSM7201A Android sdio stack has bug with interrupt -+ So internaly within SDIO stack they are polling -+ which cause issue when device is turned off. So -+ unregister interrupt with SDIO stack to stop the -+ polling -+ */ -+ if (gInstance->func[0]) { -+#if !defined(OOB_INTR_ONLY) -+ sdio_claim_host(gInstance->func[0]); -+ if (gInstance->func[1]) -+ sdio_release_irq(gInstance->func[1]); -+ if (gInstance->func[2]) -+ sdio_release_irq(gInstance->func[2]); -+ sdio_release_host(gInstance->func[0]); -+#else /* defined(OOB_INTR_ONLY) */ -+#if defined(HW_OOB) -+ sdioh_disable_func_intr(); -+#endif -+ bcmsdh_oob_intr_set(FALSE); -+#endif /* !defined(OOB_INTR_ONLY) */ -+ } -+ else -+ sd_err(("%s Failed\n", __FUNCTION__)); -+ return (0); -+} -+ -+int -+sdioh_waitlockfree(sdioh_info_t *sd) -+{ -+ return (1); -+} -+ -+ -+SDIOH_API_RC -+sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -+{ -+ return SDIOH_API_RC_FAIL; -+} -+ -+SDIOH_API_RC -+sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -+{ -+ return SDIOH_API_RC_FAIL; -+} -+ -+bool -+sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -+{ -+ return FALSE; -+} -+ -+SDIOH_API_RC -+sdioh_gpio_init(sdioh_info_t *sd) -+{ -+ return SDIOH_API_RC_FAIL; -+} -diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c -new file mode 100644 -index 00000000..e9136401 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c -@@ -0,0 +1,425 @@ -+/* -+ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdh_sdmmc_linux.c 381548 2013-01-28 17:25:38Z $ -+ */ -+ -+#include <typedefs.h> -+#include <bcmutils.h> -+#include <sdio.h> /* SDIO Device and Protocol Specs */ -+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ -+#include <sdiovar.h> /* to get msglevel bit values */ -+ -+#include <linux/sched.h> /* request_irq() */ -+ -+#include <linux/mmc/core.h> -+#include <linux/mmc/card.h> -+#include <linux/mmc/sdio_func.h> -+#include <linux/mmc/sdio_ids.h> -+ -+#if !defined(SDIO_VENDOR_ID_BROADCOM) -+#define SDIO_VENDOR_ID_BROADCOM 0x02d0 -+#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */ -+ -+#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000 -+ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) -+#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) -+#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) -+#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) -+#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) -+#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) -+#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) -+#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ -+#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) -+#define SDIO_DEVICE_ID_BROADCOM_43239 43239 -+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ -+ -+ -+#include <bcmsdh_sdmmc.h> -+ -+#include <dhd_dbg.h> -+ -+#ifdef WL_CFG80211 -+extern void wl_cfg80211_set_parent_dev(void *dev); -+#endif -+ -+extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); -+extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); -+extern int dhd_os_check_wakelock(void *dhdp); -+extern int dhd_os_check_if_up(void *dhdp); -+extern void *bcmsdh_get_drvdata(void); -+ -+int sdio_function_init(void); -+void sdio_function_cleanup(void); -+ -+#define DESCRIPTION "bcmsdh_sdmmc Driver" -+#define AUTHOR "Broadcom Corporation" -+ -+/* module param defaults */ -+static int clockoverride = 0; -+ -+module_param(clockoverride, int, 0644); -+MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); -+ -+PBCMSDH_SDMMC_INSTANCE gInstance; -+ -+/* Maximum number of bcmsdh_sdmmc devices supported by driver */ -+#define BCMSDH_SDMMC_MAX_DEVICES 1 -+ -+extern int bcmsdh_probe(struct device *dev); -+extern int bcmsdh_remove(struct device *dev); -+extern volatile bool dhd_mmc_suspend; -+ -+static int bcmsdh_sdmmc_probe(struct sdio_func *func, -+ const struct sdio_device_id *id) -+{ -+ int ret = 0; -+ static struct sdio_func sdio_func_0; -+ -+ if (func) { -+ sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); -+ sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class)); -+ sd_trace(("sdio_vendor: 0x%04x\n", func->vendor)); -+ sd_trace(("sdio_device: 0x%04x\n", func->device)); -+ sd_trace(("Function#: 0x%04x\n", func->num)); -+ -+ if (func->num == 1) { -+ sdio_func_0.num = 0; -+ sdio_func_0.card = func->card; -+ gInstance->func[0] = &sdio_func_0; -+ if(func->device == 0x4) { /* 4318 */ -+ gInstance->func[2] = NULL; -+ sd_trace(("NIC found, calling bcmsdh_probe...\n")); -+ ret = bcmsdh_probe(&func->dev); -+ } -+ } -+ -+ gInstance->func[func->num] = func; -+ -+ if (func->num == 2) { -+ #ifdef WL_CFG80211 -+ wl_cfg80211_set_parent_dev(&func->dev); -+ #endif -+ sd_trace(("F2 found, calling bcmsdh_probe...\n")); -+ ret = bcmsdh_probe(&func->dev); -+ if (ret < 0 && gInstance) -+ gInstance->func[2] = NULL; -+ } -+ } else { -+ ret = -ENODEV; -+ } -+ -+ return ret; -+} -+ -+static void bcmsdh_sdmmc_remove(struct sdio_func *func) -+{ -+ if (func) { -+ sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); -+ sd_info(("sdio_bcmsdh: func->class=%x\n", func->class)); -+ sd_info(("sdio_vendor: 0x%04x\n", func->vendor)); -+ sd_info(("sdio_device: 0x%04x\n", func->device)); -+ sd_info(("Function#: 0x%04x\n", func->num)); -+ -+ if (gInstance->func[2]) { -+ sd_trace(("F2 found, calling bcmsdh_remove...\n")); -+ bcmsdh_remove(&func->dev); -+ gInstance->func[2] = NULL; -+ } -+ if (func->num == 1) { -+ sdio_claim_host(func); -+ sdio_disable_func(func); -+ sdio_release_host(func); -+ gInstance->func[1] = NULL; -+ } -+ } -+} -+ -+/* devices we support, null terminated */ -+static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, -+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, -+ { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, -+ { /* end: all zeroes */ }, -+}; -+ -+MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); -+ -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) -+static int bcmsdh_sdmmc_suspend(struct device *pdev) -+{ -+ struct sdio_func *func = dev_to_sdio_func(pdev); -+ mmc_pm_flag_t sdio_flags; -+ int ret; -+ -+ if (func->num != 2) -+ return 0; -+ -+ sd_trace_hw4(("%s Enter\n", __FUNCTION__)); -+ -+ if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) -+ return -EBUSY; -+ -+ sdio_flags = sdio_get_host_pm_caps(func); -+ -+ if (!(sdio_flags & MMC_PM_KEEP_POWER)) { -+ sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); -+ return -EINVAL; -+ } -+ -+ /* keep power while host suspended */ -+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); -+ if (ret) { -+ sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); -+ return ret; -+ } -+ -+#if defined(OOB_INTR_ONLY) -+ bcmsdh_oob_intr_set(0); -+#endif /* defined(OOB_INTR_ONLY) */ -+ dhd_mmc_suspend = TRUE; -+ smp_mb(); -+ -+ return 0; -+} -+ -+static int bcmsdh_sdmmc_resume(struct device *pdev) -+{ -+#if defined(OOB_INTR_ONLY) -+ struct sdio_func *func = dev_to_sdio_func(pdev); -+#endif /* defined(OOB_INTR_ONLY) */ -+ sd_trace_hw4(("%s Enter\n", __FUNCTION__)); -+ -+ dhd_mmc_suspend = FALSE; -+#if defined(OOB_INTR_ONLY) -+ if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) -+ bcmsdh_oob_intr_set(1); -+#endif /* (OOB_INTR_ONLY) */ -+ smp_mb(); -+ return 0; -+} -+ -+static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { -+ .suspend = bcmsdh_sdmmc_suspend, -+ .resume = bcmsdh_sdmmc_resume, -+}; -+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ -+ -+#if defined(BCMLXSDMMC) -+static struct semaphore *notify_semaphore = NULL; -+ -+static int dummy_probe(struct sdio_func *func, -+ const struct sdio_device_id *id) -+{ -+ if (notify_semaphore) -+ up(notify_semaphore); -+ return 0; -+} -+ -+static void dummy_remove(struct sdio_func *func) -+{ -+} -+ -+static struct sdio_driver dummy_sdmmc_driver = { -+ .probe = dummy_probe, -+ .remove = dummy_remove, -+ .name = "dummy_sdmmc", -+ .id_table = bcmsdh_sdmmc_ids, -+ }; -+ -+int sdio_func_reg_notify(void* semaphore) -+{ -+ notify_semaphore = semaphore; -+ return sdio_register_driver(&dummy_sdmmc_driver); -+} -+ -+void sdio_func_unreg_notify(void) -+{ -+ sdio_unregister_driver(&dummy_sdmmc_driver); -+} -+ -+#endif /* defined(BCMLXSDMMC) */ -+ -+static struct sdio_driver bcmsdh_sdmmc_driver = { -+ .probe = bcmsdh_sdmmc_probe, -+ .remove = bcmsdh_sdmmc_remove, -+ .name = "bcmsdh_sdmmc", -+ .id_table = bcmsdh_sdmmc_ids, -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) -+ .drv = { -+ .pm = &bcmsdh_sdmmc_pm_ops, -+ }, -+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ -+ }; -+ -+struct sdos_info { -+ sdioh_info_t *sd; -+ spinlock_t lock; -+}; -+ -+ -+int -+sdioh_sdmmc_osinit(sdioh_info_t *sd) -+{ -+ struct sdos_info *sdos; -+ -+ if (!sd) -+ return BCME_BADARG; -+ -+ sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); -+ sd->sdos_info = (void*)sdos; -+ if (sdos == NULL) -+ return BCME_NOMEM; -+ -+ sdos->sd = sd; -+ spin_lock_init(&sdos->lock); -+ return BCME_OK; -+} -+ -+void -+sdioh_sdmmc_osfree(sdioh_info_t *sd) -+{ -+ struct sdos_info *sdos; -+ ASSERT(sd && sd->sdos_info); -+ -+ sdos = (struct sdos_info *)sd->sdos_info; -+ MFREE(sd->osh, sdos, sizeof(struct sdos_info)); -+} -+ -+/* Interrupt enable/disable */ -+SDIOH_API_RC -+sdioh_interrupt_set(sdioh_info_t *sd, bool enable) -+{ -+ ulong flags; -+ struct sdos_info *sdos; -+ -+ if (!sd) -+ return BCME_BADARG; -+ -+ sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); -+ -+ sdos = (struct sdos_info *)sd->sdos_info; -+ ASSERT(sdos); -+ -+#if !defined(OOB_INTR_ONLY) -+ if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { -+ sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); -+ return SDIOH_API_RC_FAIL; -+ } -+#endif /* !defined(OOB_INTR_ONLY) */ -+ -+ /* Ensure atomicity for enable/disable calls */ -+ spin_lock_irqsave(&sdos->lock, flags); -+ -+ sd->client_intr_enabled = enable; -+ if (enable) { -+ sdioh_sdmmc_devintr_on(sd); -+ } else { -+ sdioh_sdmmc_devintr_off(sd); -+ } -+ -+ spin_unlock_irqrestore(&sdos->lock, flags); -+ -+ return SDIOH_API_RC_SUCCESS; -+} -+ -+ -+#ifdef BCMSDH_MODULE -+static int __init -+bcmsdh_module_init(void) -+{ -+ int error = 0; -+ error = sdio_function_init(); -+ return error; -+} -+ -+static void __exit -+bcmsdh_module_cleanup(void) -+{ -+ sdio_function_cleanup(); -+} -+ -+module_init(bcmsdh_module_init); -+module_exit(bcmsdh_module_cleanup); -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION(DESCRIPTION); -+MODULE_AUTHOR(AUTHOR); -+ -+#endif /* BCMSDH_MODULE */ -+/* -+ * module init -+*/ -+int sdio_function_init(void) -+{ -+ int error = 0; -+ sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); -+ -+ gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL); -+ if (!gInstance) -+ return -ENOMEM; -+ -+ error = sdio_register_driver(&bcmsdh_sdmmc_driver); -+ if (error && gInstance) { -+ kfree(gInstance); -+ gInstance = 0; -+ } -+ -+ return error; -+} -+ -+/* -+ * module cleanup -+*/ -+extern int bcmsdh_remove(struct device *dev); -+void sdio_function_cleanup(void) -+{ -+ sd_trace(("%s Enter\n", __FUNCTION__)); -+ -+ -+ sdio_unregister_driver(&bcmsdh_sdmmc_driver); -+ -+ if (gInstance) -+ kfree(gInstance); -+} -diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c -new file mode 100644 -index 00000000..05405aba ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/bcmutils.c -@@ -0,0 +1,2090 @@ -+/* -+ * Driver O/S-independent utility routines -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * $Id: bcmutils.c 312855 2012-02-04 02:01:18Z $ -+ */ -+ -+#include <bcm_cfg.h> -+#include <typedefs.h> -+#include <bcmdefs.h> -+#include <stdarg.h> -+#ifdef BCMDRIVER -+ -+#include <osl.h> -+#include <bcmutils.h> -+ -+#else /* !BCMDRIVER */ -+ -+#include <stdio.h> -+#include <string.h> -+#include <bcmutils.h> -+ -+#if defined(BCMEXTSUP) -+#include <bcm_osl.h> -+#endif -+ -+ -+#endif /* !BCMDRIVER */ -+ -+#include <bcmendian.h> -+#include <bcmdevs.h> -+#include <proto/ethernet.h> -+#include <proto/vlan.h> -+#include <proto/bcmip.h> -+#include <proto/802.1d.h> -+#include <proto/802.11.h> -+void *_bcmutils_dummy_fn = NULL; -+ -+ -+#ifdef BCMDRIVER -+ -+ -+ -+/* copy a pkt buffer chain into a buffer */ -+uint -+pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) -+{ -+ uint n, ret = 0; -+ -+ if (len < 0) -+ len = 4096; /* "infinite" */ -+ -+ /* skip 'offset' bytes */ -+ for (; p && offset; p = PKTNEXT(osh, p)) { -+ if (offset < (uint)PKTLEN(osh, p)) -+ break; -+ offset -= PKTLEN(osh, p); -+ } -+ -+ if (!p) -+ return 0; -+ -+ /* copy the data */ -+ for (; p && len; p = PKTNEXT(osh, p)) { -+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); -+ bcopy(PKTDATA(osh, p) + offset, buf, n); -+ buf += n; -+ len -= n; -+ ret += n; -+ offset = 0; -+ } -+ -+ return ret; -+} -+ -+/* copy a buffer into a pkt buffer chain */ -+uint -+pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) -+{ -+ uint n, ret = 0; -+ -+ /* skip 'offset' bytes */ -+ for (; p && offset; p = PKTNEXT(osh, p)) { -+ if (offset < (uint)PKTLEN(osh, p)) -+ break; -+ offset -= PKTLEN(osh, p); -+ } -+ -+ if (!p) -+ return 0; -+ -+ /* copy the data */ -+ for (; p && len; p = PKTNEXT(osh, p)) { -+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); -+ bcopy(buf, PKTDATA(osh, p) + offset, n); -+ buf += n; -+ len -= n; -+ ret += n; -+ offset = 0; -+ } -+ -+ return ret; -+} -+ -+ -+ -+/* return total length of buffer chain */ -+uint BCMFASTPATH -+pkttotlen(osl_t *osh, void *p) -+{ -+ uint total; -+ int len; -+ -+ total = 0; -+ for (; p; p = PKTNEXT(osh, p)) { -+ len = PKTLEN(osh, p); -+ total += len; -+ } -+ -+ return (total); -+} -+ -+/* return the last buffer of chained pkt */ -+void * -+pktlast(osl_t *osh, void *p) -+{ -+ for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) -+ ; -+ -+ return (p); -+} -+ -+/* count segments of a chained packet */ -+uint BCMFASTPATH -+pktsegcnt(osl_t *osh, void *p) -+{ -+ uint cnt; -+ -+ for (cnt = 0; p; p = PKTNEXT(osh, p)) -+ cnt++; -+ -+ return cnt; -+} -+ -+ -+/* count segments of a chained packet */ -+uint BCMFASTPATH -+pktsegcnt_war(osl_t *osh, void *p) -+{ -+ uint cnt; -+ uint8 *pktdata; -+ uint len, remain, align64; -+ -+ for (cnt = 0; p; p = PKTNEXT(osh, p)) { -+ cnt++; -+ len = PKTLEN(osh, p); -+ if (len > 128) { -+ pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ -+ /* Check for page boundary straddle (2048B) */ -+ if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) -+ cnt++; -+ -+ align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ -+ align64 = (64 - align64) & 0x3f; -+ len -= align64; /* bytes from aligned 64B to end */ -+ /* if aligned to 128B, check for MOD 128 between 1 to 4B */ -+ remain = len % 128; -+ if (remain > 0 && remain <= 4) -+ cnt++; /* add extra seg */ -+ } -+ } -+ -+ return cnt; -+} -+ -+uint8 * BCMFASTPATH -+pktoffset(osl_t *osh, void *p, uint offset) -+{ -+ uint total = pkttotlen(osh, p); -+ uint pkt_off = 0, len = 0; -+ uint8 *pdata = (uint8 *) PKTDATA(osh, p); -+ -+ if (offset > total) -+ return NULL; -+ -+ for (; p; p = PKTNEXT(osh, p)) { -+ pdata = (uint8 *) PKTDATA(osh, p); -+ pkt_off = offset - len; -+ len += PKTLEN(osh, p); -+ if (len > offset) -+ break; -+ } -+ return (uint8*) (pdata+pkt_off); -+} -+ -+/* -+ * osl multiple-precedence packet queue -+ * hi_prec is always >= the number of the highest non-empty precedence -+ */ -+void * BCMFASTPATH -+pktq_penq(struct pktq *pq, int prec, void *p) -+{ -+ struct pktq_prec *q; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ -+ -+ ASSERT(!pktq_full(pq)); -+ ASSERT(!pktq_pfull(pq, prec)); -+ -+ q = &pq->q[prec]; -+ -+ if (q->head) -+ PKTSETLINK(q->tail, p); -+ else -+ q->head = p; -+ -+ q->tail = p; -+ q->len++; -+ -+ pq->len++; -+ -+ if (pq->hi_prec < prec) -+ pq->hi_prec = (uint8)prec; -+ -+ return p; -+} -+ -+void * BCMFASTPATH -+pktq_penq_head(struct pktq *pq, int prec, void *p) -+{ -+ struct pktq_prec *q; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ -+ -+ ASSERT(!pktq_full(pq)); -+ ASSERT(!pktq_pfull(pq, prec)); -+ -+ q = &pq->q[prec]; -+ -+ if (q->head == NULL) -+ q->tail = p; -+ -+ PKTSETLINK(p, q->head); -+ q->head = p; -+ q->len++; -+ -+ pq->len++; -+ -+ if (pq->hi_prec < prec) -+ pq->hi_prec = (uint8)prec; -+ -+ return p; -+} -+ -+void * BCMFASTPATH -+pktq_pdeq(struct pktq *pq, int prec) -+{ -+ struct pktq_prec *q; -+ void *p; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ if ((q->head = PKTLINK(p)) == NULL) -+ q->tail = NULL; -+ -+ q->len--; -+ -+ pq->len--; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+void * BCMFASTPATH -+pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) -+{ -+ struct pktq_prec *q; -+ void *p; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ q = &pq->q[prec]; -+ -+ if (prev_p == NULL) -+ return NULL; -+ -+ if ((p = PKTLINK(prev_p)) == NULL) -+ return NULL; -+ -+ q->len--; -+ -+ pq->len--; -+ -+ PKTSETLINK(prev_p, PKTLINK(p)); -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+void * BCMFASTPATH -+pktq_pdeq_tail(struct pktq *pq, int prec) -+{ -+ struct pktq_prec *q; -+ void *p, *prev; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ for (prev = NULL; p != q->tail; p = PKTLINK(p)) -+ prev = p; -+ -+ if (prev) -+ PKTSETLINK(prev, NULL); -+ else -+ q->head = NULL; -+ -+ q->tail = prev; -+ q->len--; -+ -+ pq->len--; -+ -+ return p; -+} -+ -+void -+pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg) -+{ -+ struct pktq_prec *q; -+ void *p, *prev = NULL; -+ -+ q = &pq->q[prec]; -+ p = q->head; -+ while (p) { -+ if (fn == NULL || (*fn)(p, arg)) { -+ bool head = (p == q->head); -+ if (head) -+ q->head = PKTLINK(p); -+ else -+ PKTSETLINK(prev, PKTLINK(p)); -+ PKTSETLINK(p, NULL); -+ PKTFREE(osh, p, dir); -+ q->len--; -+ pq->len--; -+ p = (head ? q->head : PKTLINK(prev)); -+ } else { -+ prev = p; -+ p = PKTLINK(p); -+ } -+ } -+ -+ if (q->head == NULL) { -+ ASSERT(q->len == 0); -+ q->tail = NULL; -+ } -+} -+ -+bool BCMFASTPATH -+pktq_pdel(struct pktq *pq, void *pktbuf, int prec) -+{ -+ struct pktq_prec *q; -+ void *p; -+ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ if (!pktbuf) -+ return FALSE; -+ -+ q = &pq->q[prec]; -+ -+ if (q->head == pktbuf) { -+ if ((q->head = PKTLINK(pktbuf)) == NULL) -+ q->tail = NULL; -+ } else { -+ for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) -+ ; -+ if (p == NULL) -+ return FALSE; -+ -+ PKTSETLINK(p, PKTLINK(pktbuf)); -+ if (q->tail == pktbuf) -+ q->tail = p; -+ } -+ -+ q->len--; -+ pq->len--; -+ PKTSETLINK(pktbuf, NULL); -+ return TRUE; -+} -+ -+void -+pktq_init(struct pktq *pq, int num_prec, int max_len) -+{ -+ int prec; -+ -+ ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); -+ -+ /* pq is variable size; only zero out what's requested */ -+ bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); -+ -+ pq->num_prec = (uint16)num_prec; -+ -+ pq->max = (uint16)max_len; -+ -+ for (prec = 0; prec < num_prec; prec++) -+ pq->q[prec].max = pq->max; -+} -+ -+void -+pktq_set_max_plen(struct pktq *pq, int prec, int max_len) -+{ -+ ASSERT(prec >= 0 && prec < pq->num_prec); -+ -+ if (prec < pq->num_prec) -+ pq->q[prec].max = (uint16)max_len; -+} -+ -+void * BCMFASTPATH -+pktq_deq(struct pktq *pq, int *prec_out) -+{ -+ struct pktq_prec *q; -+ void *p; -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) -+ pq->hi_prec--; -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ if ((q->head = PKTLINK(p)) == NULL) -+ q->tail = NULL; -+ -+ q->len--; -+ -+ pq->len--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+void * BCMFASTPATH -+pktq_deq_tail(struct pktq *pq, int *prec_out) -+{ -+ struct pktq_prec *q; -+ void *p, *prev; -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ for (prec = 0; prec < pq->hi_prec; prec++) -+ if (pq->q[prec].head) -+ break; -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ for (prev = NULL; p != q->tail; p = PKTLINK(p)) -+ prev = p; -+ -+ if (prev) -+ PKTSETLINK(prev, NULL); -+ else -+ q->head = NULL; -+ -+ q->tail = prev; -+ q->len--; -+ -+ pq->len--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+void * -+pktq_peek(struct pktq *pq, int *prec_out) -+{ -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) -+ pq->hi_prec--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ return (pq->q[prec].head); -+} -+ -+void * -+pktq_peek_tail(struct pktq *pq, int *prec_out) -+{ -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ for (prec = 0; prec < pq->hi_prec; prec++) -+ if (pq->q[prec].head) -+ break; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ return (pq->q[prec].tail); -+} -+ -+void -+pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg) -+{ -+ int prec; -+ -+ /* Optimize flush, if pktq len = 0, just return. -+ * pktq len of 0 means pktq's prec q's are all empty. -+ */ -+ if (pq->len == 0) { -+ return; -+ } -+ -+ for (prec = 0; prec < pq->num_prec; prec++) -+ pktq_pflush(osh, pq, prec, dir, fn, arg); -+ if (fn == NULL) -+ ASSERT(pq->len == 0); -+} -+ -+/* Return sum of lengths of a specific set of precedences */ -+int -+pktq_mlen(struct pktq *pq, uint prec_bmp) -+{ -+ int prec, len; -+ -+ len = 0; -+ -+ for (prec = 0; prec <= pq->hi_prec; prec++) -+ if (prec_bmp & (1 << prec)) -+ len += pq->q[prec].len; -+ -+ return len; -+} -+ -+/* Priority peek from a specific set of precedences */ -+void * BCMFASTPATH -+pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) -+{ -+ struct pktq_prec *q; -+ void *p; -+ int prec; -+ -+ if (pq->len == 0) -+ { -+ return NULL; -+ } -+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) -+ pq->hi_prec--; -+ -+ while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) -+ if (prec-- == 0) -+ return NULL; -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ return p; -+} -+/* Priority dequeue from a specific set of precedences */ -+void * BCMFASTPATH -+pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) -+{ -+ struct pktq_prec *q; -+ void *p; -+ int prec; -+ -+ if (pq->len == 0) -+ return NULL; -+ -+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) -+ pq->hi_prec--; -+ -+ while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) -+ if (prec-- == 0) -+ return NULL; -+ -+ q = &pq->q[prec]; -+ -+ if ((p = q->head) == NULL) -+ return NULL; -+ -+ if ((q->head = PKTLINK(p)) == NULL) -+ q->tail = NULL; -+ -+ q->len--; -+ -+ if (prec_out) -+ *prec_out = prec; -+ -+ pq->len--; -+ -+ PKTSETLINK(p, NULL); -+ -+ return p; -+} -+ -+#endif /* BCMDRIVER */ -+ -+const unsigned char bcm_ctype[] = { -+ -+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ -+ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, -+ _BCM_C, /* 8-15 */ -+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ -+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ -+ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ -+ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ -+ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ -+ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ -+ _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, -+ _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ -+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ -+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ -+ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ -+ _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, -+ _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ -+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ -+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ -+ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ -+ _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, -+ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ -+ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, -+ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ -+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, -+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ -+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, -+ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ -+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, -+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ -+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, -+ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ -+}; -+ -+ulong -+bcm_strtoul(const char *cp, char **endp, uint base) -+{ -+ ulong result, last_result = 0, value; -+ bool minus; -+ -+ minus = FALSE; -+ -+ while (bcm_isspace(*cp)) -+ cp++; -+ -+ if (cp[0] == '+') -+ cp++; -+ else if (cp[0] == '-') { -+ minus = TRUE; -+ cp++; -+ } -+ -+ if (base == 0) { -+ if (cp[0] == '0') { -+ if ((cp[1] == 'x') || (cp[1] == 'X')) { -+ base = 16; -+ cp = &cp[2]; -+ } else { -+ base = 8; -+ cp = &cp[1]; -+ } -+ } else -+ base = 10; -+ } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { -+ cp = &cp[2]; -+ } -+ -+ result = 0; -+ -+ while (bcm_isxdigit(*cp) && -+ (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { -+ result = result*base + value; -+ /* Detected overflow */ -+ if (result < last_result && !minus) -+ return (ulong)-1; -+ last_result = result; -+ cp++; -+ } -+ -+ if (minus) -+ result = (ulong)(-(long)result); -+ -+ if (endp) -+ *endp = DISCARD_QUAL(cp, char); -+ -+ return (result); -+} -+ -+int -+bcm_atoi(const char *s) -+{ -+ return (int)bcm_strtoul(s, NULL, 10); -+} -+ -+/* return pointer to location of substring 'needle' in 'haystack' */ -+char * -+bcmstrstr(const char *haystack, const char *needle) -+{ -+ int len, nlen; -+ int i; -+ -+ if ((haystack == NULL) || (needle == NULL)) -+ return DISCARD_QUAL(haystack, char); -+ -+ nlen = strlen(needle); -+ len = strlen(haystack) - nlen + 1; -+ -+ for (i = 0; i < len; i++) -+ if (memcmp(needle, &haystack[i], nlen) == 0) -+ return DISCARD_QUAL(&haystack[i], char); -+ return (NULL); -+} -+ -+char * -+bcmstrcat(char *dest, const char *src) -+{ -+ char *p; -+ -+ p = dest + strlen(dest); -+ -+ while ((*p++ = *src++) != '\0') -+ ; -+ -+ return (dest); -+} -+ -+char * -+bcmstrncat(char *dest, const char *src, uint size) -+{ -+ char *endp; -+ char *p; -+ -+ p = dest + strlen(dest); -+ endp = p + size; -+ -+ while (p != endp && (*p++ = *src++) != '\0') -+ ; -+ -+ return (dest); -+} -+ -+ -+/**************************************************************************** -+* Function: bcmstrtok -+* -+* Purpose: -+* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), -+* but allows strToken() to be used by different strings or callers at the same -+* time. Each call modifies '*string' by substituting a NULL character for the -+* first delimiter that is encountered, and updates 'string' to point to the char -+* after the delimiter. Leading delimiters are skipped. -+* -+* Parameters: -+* string (mod) Ptr to string ptr, updated by token. -+* delimiters (in) Set of delimiter characters. -+* tokdelim (out) Character that delimits the returned token. (May -+* be set to NULL if token delimiter is not required). -+* -+* Returns: Pointer to the next token found. NULL when no more tokens are found. -+***************************************************************************** -+*/ -+char * -+bcmstrtok(char **string, const char *delimiters, char *tokdelim) -+{ -+ unsigned char *str; -+ unsigned long map[8]; -+ int count; -+ char *nextoken; -+ -+ if (tokdelim != NULL) { -+ /* Prime the token delimiter */ -+ *tokdelim = '\0'; -+ } -+ -+ /* Clear control map */ -+ for (count = 0; count < 8; count++) { -+ map[count] = 0; -+ } -+ -+ /* Set bits in delimiter table */ -+ do { -+ map[*delimiters >> 5] |= (1 << (*delimiters & 31)); -+ } -+ while (*delimiters++); -+ -+ str = (unsigned char*)*string; -+ -+ /* Find beginning of token (skip over leading delimiters). Note that -+ * there is no token iff this loop sets str to point to the terminal -+ * null (*str == '\0') -+ */ -+ while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { -+ str++; -+ } -+ -+ nextoken = (char*)str; -+ -+ /* Find the end of the token. If it is not the end of the string, -+ * put a null there. -+ */ -+ for (; *str; str++) { -+ if (map[*str >> 5] & (1 << (*str & 31))) { -+ if (tokdelim != NULL) { -+ *tokdelim = *str; -+ } -+ -+ *str++ = '\0'; -+ break; -+ } -+ } -+ -+ *string = (char*)str; -+ -+ /* Determine if a token has been found. */ -+ if (nextoken == (char *) str) { -+ return NULL; -+ } -+ else { -+ return nextoken; -+ } -+} -+ -+ -+#define xToLower(C) \ -+ ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) -+ -+ -+/**************************************************************************** -+* Function: bcmstricmp -+* -+* Purpose: Compare to strings case insensitively. -+* -+* Parameters: s1 (in) First string to compare. -+* s2 (in) Second string to compare. -+* -+* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -+* t1 > t2, when ignoring case sensitivity. -+***************************************************************************** -+*/ -+int -+bcmstricmp(const char *s1, const char *s2) -+{ -+ char dc, sc; -+ -+ while (*s2 && *s1) { -+ dc = xToLower(*s1); -+ sc = xToLower(*s2); -+ if (dc < sc) return -1; -+ if (dc > sc) return 1; -+ s1++; -+ s2++; -+ } -+ -+ if (*s1 && !*s2) return 1; -+ if (!*s1 && *s2) return -1; -+ return 0; -+} -+ -+ -+/**************************************************************************** -+* Function: bcmstrnicmp -+* -+* Purpose: Compare to strings case insensitively, upto a max of 'cnt' -+* characters. -+* -+* Parameters: s1 (in) First string to compare. -+* s2 (in) Second string to compare. -+* cnt (in) Max characters to compare. -+* -+* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -+* t1 > t2, when ignoring case sensitivity. -+***************************************************************************** -+*/ -+int -+bcmstrnicmp(const char* s1, const char* s2, int cnt) -+{ -+ char dc, sc; -+ -+ while (*s2 && *s1 && cnt) { -+ dc = xToLower(*s1); -+ sc = xToLower(*s2); -+ if (dc < sc) return -1; -+ if (dc > sc) return 1; -+ s1++; -+ s2++; -+ cnt--; -+ } -+ -+ if (!cnt) return 0; -+ if (*s1 && !*s2) return 1; -+ if (!*s1 && *s2) return -1; -+ return 0; -+} -+ -+/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ -+int -+bcm_ether_atoe(const char *p, struct ether_addr *ea) -+{ -+ int i = 0; -+ char *ep; -+ -+ for (;;) { -+ ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); -+ p = ep; -+ if (!*p++ || i == 6) -+ break; -+ } -+ -+ return (i == 6); -+} -+ -+ -+#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) -+/* registry routine buffer preparation utility functions: -+ * parameter order is like strncpy, but returns count -+ * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) -+ */ -+ulong -+wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) -+{ -+ ulong copyct = 1; -+ ushort i; -+ -+ if (abuflen == 0) -+ return 0; -+ -+ /* wbuflen is in bytes */ -+ wbuflen /= sizeof(ushort); -+ -+ for (i = 0; i < wbuflen; ++i) { -+ if (--abuflen == 0) -+ break; -+ *abuf++ = (char) *wbuf++; -+ ++copyct; -+ } -+ *abuf = '\0'; -+ -+ return copyct; -+} -+#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ -+ -+char * -+bcm_ether_ntoa(const struct ether_addr *ea, char *buf) -+{ -+ static const char hex[] = -+ { -+ '0', '1', '2', '3', '4', '5', '6', '7', -+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' -+ }; -+ const uint8 *octet = ea->octet; -+ char *p = buf; -+ int i; -+ -+ for (i = 0; i < 6; i++, octet++) { -+ *p++ = hex[(*octet >> 4) & 0xf]; -+ *p++ = hex[*octet & 0xf]; -+ *p++ = ':'; -+ } -+ -+ *(p-1) = '\0'; -+ -+ return (buf); -+} -+ -+char * -+bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) -+{ -+ snprintf(buf, 16, "%d.%d.%d.%d", -+ ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); -+ return (buf); -+} -+ -+#ifdef BCMDRIVER -+ -+void -+bcm_mdelay(uint ms) -+{ -+ uint i; -+ -+ for (i = 0; i < ms; i++) { -+ OSL_DELAY(1000); -+ } -+} -+ -+ -+ -+ -+ -+#if defined(DHD_DEBUG) -+/* pretty hex print a pkt buffer chain */ -+void -+prpkt(const char *msg, osl_t *osh, void *p0) -+{ -+ void *p; -+ -+ if (msg && (msg[0] != '\0')) -+ printf("%s:\n", msg); -+ -+ for (p = p0; p; p = PKTNEXT(osh, p)) -+ prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); -+} -+#endif -+ -+/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. -+ * Also updates the inplace vlan tag if requested. -+ * For debugging, it returns an indication of what it did. -+ */ -+uint BCMFASTPATH -+pktsetprio(void *pkt, bool update_vtag) -+{ -+ struct ether_header *eh; -+ struct ethervlan_header *evh; -+ uint8 *pktdata; -+ int priority = 0; -+ int rc = 0; -+ -+ pktdata = (uint8 *)PKTDATA(NULL, pkt); -+ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); -+ -+ eh = (struct ether_header *) pktdata; -+ -+ if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) { -+ uint16 vlan_tag; -+ int vlan_prio, dscp_prio = 0; -+ -+ evh = (struct ethervlan_header *)eh; -+ -+ vlan_tag = ntoh16(evh->vlan_tag); -+ vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; -+ -+ if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { -+ uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); -+ uint8 tos_tc = IP_TOS46(ip_body); -+ dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); -+ } -+ -+ /* DSCP priority gets precedence over 802.1P (vlan tag) */ -+ if (dscp_prio != 0) { -+ priority = dscp_prio; -+ rc |= PKTPRIO_VDSCP; -+ } else { -+ priority = vlan_prio; -+ rc |= PKTPRIO_VLAN; -+ } -+ /* -+ * If the DSCP priority is not the same as the VLAN priority, -+ * then overwrite the priority field in the vlan tag, with the -+ * DSCP priority value. This is required for Linux APs because -+ * the VLAN driver on Linux, overwrites the skb->priority field -+ * with the priority value in the vlan tag -+ */ -+ if (update_vtag && (priority != vlan_prio)) { -+ vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); -+ vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; -+ evh->vlan_tag = hton16(vlan_tag); -+ rc |= PKTPRIO_UPD; -+ } -+ } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { -+ uint8 *ip_body = pktdata + sizeof(struct ether_header); -+ uint8 tos_tc = IP_TOS46(ip_body); -+ priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); -+ rc |= PKTPRIO_DSCP; -+ } -+ -+ ASSERT(priority >= 0 && priority <= MAXPRIO); -+ PKTSETPRIO(pkt, priority); -+ return (rc | priority); -+} -+ -+ -+static char bcm_undeferrstr[32]; -+static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; -+ -+/* Convert the error codes into related error strings */ -+const char * -+bcmerrorstr(int bcmerror) -+{ -+ /* check if someone added a bcmerror code but forgot to add errorstring */ -+ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); -+ -+ if (bcmerror > 0 || bcmerror < BCME_LAST) { -+ snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); -+ return bcm_undeferrstr; -+ } -+ -+ ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); -+ -+ return bcmerrorstrtable[-bcmerror]; -+} -+ -+ -+ -+/* iovar table lookup */ -+const bcm_iovar_t* -+bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) -+{ -+ const bcm_iovar_t *vi; -+ const char *lookup_name; -+ -+ /* skip any ':' delimited option prefixes */ -+ lookup_name = strrchr(name, ':'); -+ if (lookup_name != NULL) -+ lookup_name++; -+ else -+ lookup_name = name; -+ -+ ASSERT(table != NULL); -+ -+ for (vi = table; vi->name; vi++) { -+ if (!strcmp(vi->name, lookup_name)) -+ return vi; -+ } -+ /* ran to end of table */ -+ -+ return NULL; /* var name not found */ -+} -+ -+int -+bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) -+{ -+ int bcmerror = 0; -+ -+ /* length check on io buf */ -+ switch (vi->type) { -+ case IOVT_BOOL: -+ case IOVT_INT8: -+ case IOVT_INT16: -+ case IOVT_INT32: -+ case IOVT_UINT8: -+ case IOVT_UINT16: -+ case IOVT_UINT32: -+ /* all integers are int32 sized args at the ioctl interface */ -+ if (len < (int)sizeof(int)) { -+ bcmerror = BCME_BUFTOOSHORT; -+ } -+ break; -+ -+ case IOVT_BUFFER: -+ /* buffer must meet minimum length requirement */ -+ if (len < vi->minlen) { -+ bcmerror = BCME_BUFTOOSHORT; -+ } -+ break; -+ -+ case IOVT_VOID: -+ if (!set) { -+ /* Cannot return nil... */ -+ bcmerror = BCME_UNSUPPORTED; -+ } else if (len) { -+ /* Set is an action w/o parameters */ -+ bcmerror = BCME_BUFTOOLONG; -+ } -+ break; -+ -+ default: -+ /* unknown type for length check in iovar info */ -+ ASSERT(0); -+ bcmerror = BCME_UNSUPPORTED; -+ } -+ -+ return bcmerror; -+} -+ -+#endif /* BCMDRIVER */ -+ -+ -+/******************************************************************************* -+ * crc8 -+ * -+ * Computes a crc8 over the input data using the polynomial: -+ * -+ * x^8 + x^7 +x^6 + x^4 + x^2 + 1 -+ * -+ * The caller provides the initial value (either CRC8_INIT_VALUE -+ * or the previous returned value) to allow for processing of -+ * discontiguous blocks of data. When generating the CRC the -+ * caller is responsible for complementing the final return value -+ * and inserting it into the byte stream. When checking, a final -+ * return value of CRC8_GOOD_VALUE indicates a valid CRC. -+ * -+ * Reference: Dallas Semiconductor Application Note 27 -+ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", -+ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., -+ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt -+ * -+ * **************************************************************************** -+ */ -+ -+static const uint8 crc8_table[256] = { -+ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, -+ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, -+ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, -+ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, -+ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, -+ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, -+ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, -+ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, -+ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, -+ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, -+ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, -+ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, -+ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, -+ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, -+ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, -+ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, -+ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, -+ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, -+ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, -+ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, -+ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, -+ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, -+ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, -+ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, -+ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, -+ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, -+ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, -+ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, -+ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, -+ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, -+ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, -+ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F -+}; -+ -+#define CRC_INNER_LOOP(n, c, x) \ -+ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] -+ -+uint8 -+hndcrc8( -+ uint8 *pdata, /* pointer to array of data to process */ -+ uint nbytes, /* number of input data bytes to process */ -+ uint8 crc /* either CRC8_INIT_VALUE or previous return value */ -+) -+{ -+ /* hard code the crc loop instead of using CRC_INNER_LOOP macro -+ * to avoid the undefined and unnecessary (uint8 >> 8) operation. -+ */ -+ while (nbytes-- > 0) -+ crc = crc8_table[(crc ^ *pdata++) & 0xff]; -+ -+ return crc; -+} -+ -+/******************************************************************************* -+ * crc16 -+ * -+ * Computes a crc16 over the input data using the polynomial: -+ * -+ * x^16 + x^12 +x^5 + 1 -+ * -+ * The caller provides the initial value (either CRC16_INIT_VALUE -+ * or the previous returned value) to allow for processing of -+ * discontiguous blocks of data. When generating the CRC the -+ * caller is responsible for complementing the final return value -+ * and inserting it into the byte stream. When checking, a final -+ * return value of CRC16_GOOD_VALUE indicates a valid CRC. -+ * -+ * Reference: Dallas Semiconductor Application Note 27 -+ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", -+ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., -+ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt -+ * -+ * **************************************************************************** -+ */ -+ -+static const uint16 crc16_table[256] = { -+ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, -+ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, -+ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, -+ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, -+ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, -+ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, -+ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, -+ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, -+ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, -+ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, -+ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, -+ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, -+ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, -+ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, -+ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, -+ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, -+ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, -+ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, -+ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, -+ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, -+ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, -+ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, -+ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, -+ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, -+ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, -+ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, -+ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, -+ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, -+ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, -+ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, -+ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, -+ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 -+}; -+ -+uint16 -+hndcrc16( -+ uint8 *pdata, /* pointer to array of data to process */ -+ uint nbytes, /* number of input data bytes to process */ -+ uint16 crc /* either CRC16_INIT_VALUE or previous return value */ -+) -+{ -+ while (nbytes-- > 0) -+ CRC_INNER_LOOP(16, crc, *pdata++); -+ return crc; -+} -+ -+static const uint32 crc32_table[256] = { -+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, -+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, -+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, -+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, -+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, -+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, -+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, -+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, -+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, -+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, -+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, -+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, -+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, -+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, -+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, -+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, -+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, -+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, -+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, -+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, -+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, -+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, -+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, -+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, -+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, -+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, -+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, -+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, -+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, -+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, -+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, -+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, -+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, -+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, -+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, -+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, -+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, -+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, -+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, -+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, -+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, -+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, -+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, -+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, -+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, -+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, -+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, -+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, -+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, -+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, -+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, -+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, -+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, -+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, -+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, -+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, -+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, -+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, -+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, -+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, -+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, -+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, -+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, -+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -+}; -+ -+/* -+ * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if -+ * accumulating over multiple pieces. -+ */ -+uint32 -+hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) -+{ -+ uint8 *pend; -+ pend = pdata + nbytes; -+ while (pdata < pend) -+ CRC_INNER_LOOP(32, crc, *pdata++); -+ -+ return crc; -+} -+ -+#ifdef notdef -+#define CLEN 1499 /* CRC Length */ -+#define CBUFSIZ (CLEN+4) -+#define CNBUFS 5 /* # of bufs */ -+ -+void -+testcrc32(void) -+{ -+ uint j, k, l; -+ uint8 *buf; -+ uint len[CNBUFS]; -+ uint32 crcr; -+ uint32 crc32tv[CNBUFS] = -+ {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; -+ -+ ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); -+ -+ /* step through all possible alignments */ -+ for (l = 0; l <= 4; l++) { -+ for (j = 0; j < CNBUFS; j++) { -+ len[j] = CLEN; -+ for (k = 0; k < len[j]; k++) -+ *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; -+ } -+ -+ for (j = 0; j < CNBUFS; j++) { -+ crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); -+ ASSERT(crcr == crc32tv[j]); -+ } -+ } -+ -+ MFREE(buf, CBUFSIZ*CNBUFS); -+ return; -+} -+#endif /* notdef */ -+ -+/* -+ * Advance from the current 1-byte tag/1-byte length/variable-length value -+ * triple, to the next, returning a pointer to the next. -+ * If the current or next TLV is invalid (does not fit in given buffer length), -+ * NULL is returned. -+ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented -+ * by the TLV parameter's length if it is valid. -+ */ -+bcm_tlv_t * -+bcm_next_tlv(bcm_tlv_t *elt, int *buflen) -+{ -+ int len; -+ -+ /* validate current elt */ -+ if (!bcm_valid_tlv(elt, *buflen)) -+ return NULL; -+ -+ /* advance to next elt */ -+ len = elt->len; -+ elt = (bcm_tlv_t*)(elt->data + len); -+ *buflen -= (TLV_HDR_LEN + len); -+ -+ /* validate next elt */ -+ if (!bcm_valid_tlv(elt, *buflen)) -+ return NULL; -+ -+ return elt; -+} -+ -+/* -+ * Traverse a string of 1-byte tag/1-byte length/variable-length value -+ * triples, returning a pointer to the substring whose first element -+ * matches tag -+ */ -+bcm_tlv_t * -+bcm_parse_tlvs(void *buf, int buflen, uint key) -+{ -+ bcm_tlv_t *elt; -+ int totlen; -+ -+ elt = (bcm_tlv_t*)buf; -+ totlen = buflen; -+ -+ /* find tagged parameter */ -+ while (totlen >= TLV_HDR_LEN) { -+ int len = elt->len; -+ -+ /* validate remaining totlen */ -+ if ((elt->id == key) && -+ (totlen >= (len + TLV_HDR_LEN))) -+ return (elt); -+ -+ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); -+ totlen -= (len + TLV_HDR_LEN); -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Traverse a string of 1-byte tag/1-byte length/variable-length value -+ * triples, returning a pointer to the substring whose first element -+ * matches tag. Stop parsing when we see an element whose ID is greater -+ * than the target key. -+ */ -+bcm_tlv_t * -+bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) -+{ -+ bcm_tlv_t *elt; -+ int totlen; -+ -+ elt = (bcm_tlv_t*)buf; -+ totlen = buflen; -+ -+ /* find tagged parameter */ -+ while (totlen >= TLV_HDR_LEN) { -+ uint id = elt->id; -+ int len = elt->len; -+ -+ /* Punt if we start seeing IDs > than target key */ -+ if (id > key) -+ return (NULL); -+ -+ /* validate remaining totlen */ -+ if ((id == key) && -+ (totlen >= (len + TLV_HDR_LEN))) -+ return (elt); -+ -+ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); -+ totlen -= (len + TLV_HDR_LEN); -+ } -+ return NULL; -+} -+ -+#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ -+ defined(DHD_DEBUG) -+int -+bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) -+{ -+ int i; -+ char* p = buf; -+ char hexstr[16]; -+ int slen = 0, nlen = 0; -+ uint32 bit; -+ const char* name; -+ -+ if (len < 2 || !buf) -+ return 0; -+ -+ buf[0] = '\0'; -+ -+ for (i = 0; flags != 0; i++) { -+ bit = bd[i].bit; -+ name = bd[i].name; -+ if (bit == 0 && flags != 0) { -+ /* print any unnamed bits */ -+ snprintf(hexstr, 16, "0x%X", flags); -+ name = hexstr; -+ flags = 0; /* exit loop */ -+ } else if ((flags & bit) == 0) -+ continue; -+ flags &= ~bit; -+ nlen = strlen(name); -+ slen += nlen; -+ /* count btwn flag space */ -+ if (flags != 0) -+ slen += 1; -+ /* need NULL char as well */ -+ if (len <= slen) -+ break; -+ /* copy NULL char but don't count it */ -+ strncpy(p, name, nlen + 1); -+ p += nlen; -+ /* copy btwn flag space and NULL char */ -+ if (flags != 0) -+ p += snprintf(p, 2, " "); -+ } -+ -+ /* indicate the str was too short */ -+ if (flags != 0) { -+ if (len < 2) -+ p -= 2 - len; /* overwrite last char */ -+ p += snprintf(p, 2, ">"); -+ } -+ -+ return (int)(p - buf); -+} -+ -+/* print bytes formatted as hex to a string. return the resulting string length */ -+int -+bcm_format_hex(char *str, const void *bytes, int len) -+{ -+ int i; -+ char *p = str; -+ const uint8 *src = (const uint8*)bytes; -+ -+ for (i = 0; i < len; i++) { -+ p += snprintf(p, 3, "%02X", *src); -+ src++; -+ } -+ return (int)(p - str); -+} -+#endif -+ -+/* pretty hex print a contiguous buffer */ -+void -+prhex(const char *msg, uchar *buf, uint nbytes) -+{ -+ char line[128], *p; -+ int len = sizeof(line); -+ int nchar; -+ uint i; -+ -+ if (msg && (msg[0] != '\0')) -+ printf("%s:\n", msg); -+ -+ p = line; -+ for (i = 0; i < nbytes; i++) { -+ if (i % 16 == 0) { -+ nchar = snprintf(p, len, " %04d: ", i); /* line prefix */ -+ p += nchar; -+ len -= nchar; -+ } -+ if (len > 0) { -+ nchar = snprintf(p, len, "%02x ", buf[i]); -+ p += nchar; -+ len -= nchar; -+ } -+ -+ if (i % 16 == 15) { -+ printf("%s\n", line); /* flush line */ -+ p = line; -+ len = sizeof(line); -+ } -+ } -+ -+ /* flush last partial line */ -+ if (p != line) -+ printf("%s\n", line); -+} -+ -+static const char *crypto_algo_names[] = { -+ "NONE", -+ "WEP1", -+ "TKIP", -+ "WEP128", -+ "AES_CCM", -+ "AES_OCB_MSDU", -+ "AES_OCB_MPDU", -+ "NALG" -+ "UNDEF", -+ "UNDEF", -+ "UNDEF", -+ "UNDEF" -+}; -+ -+const char * -+bcm_crypto_algo_name(uint algo) -+{ -+ return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; -+} -+ -+ -+char * -+bcm_chipname(uint chipid, char *buf, uint len) -+{ -+ const char *fmt; -+ -+ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; -+ snprintf(buf, len, fmt, chipid); -+ return buf; -+} -+ -+/* Produce a human-readable string for boardrev */ -+char * -+bcm_brev_str(uint32 brev, char *buf) -+{ -+ if (brev < 0x100) -+ snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); -+ else -+ snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); -+ -+ return (buf); -+} -+ -+#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ -+ -+/* dump large strings to console */ -+void -+printbig(char *buf) -+{ -+ uint len, max_len; -+ char c; -+ -+ len = strlen(buf); -+ -+ max_len = BUFSIZE_TODUMP_ATONCE; -+ -+ while (len > max_len) { -+ c = buf[max_len]; -+ buf[max_len] = '\0'; -+ printf("%s", buf); -+ buf[max_len] = c; -+ -+ buf += max_len; -+ len -= max_len; -+ } -+ /* print the remaining string */ -+ printf("%s\n", buf); -+ return; -+} -+ -+/* routine to dump fields in a fileddesc structure */ -+uint -+bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, -+ char *buf, uint32 bufsize) -+{ -+ uint filled_len; -+ int len; -+ struct fielddesc *cur_ptr; -+ -+ filled_len = 0; -+ cur_ptr = fielddesc_array; -+ -+ while (bufsize > 1) { -+ if (cur_ptr->nameandfmt == NULL) -+ break; -+ len = snprintf(buf, bufsize, cur_ptr->nameandfmt, -+ read_rtn(arg0, arg1, cur_ptr->offset)); -+ /* check for snprintf overflow or error */ -+ if (len < 0 || (uint32)len >= bufsize) -+ len = bufsize - 1; -+ buf += len; -+ bufsize -= len; -+ filled_len += len; -+ cur_ptr++; -+ } -+ return filled_len; -+} -+ -+uint -+bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) -+{ -+ uint len; -+ -+ len = strlen(name) + 1; -+ -+ if ((len + datalen) > buflen) -+ return 0; -+ -+ strncpy(buf, name, buflen); -+ -+ /* append data onto the end of the name string */ -+ memcpy(&buf[len], data, datalen); -+ len += datalen; -+ -+ return len; -+} -+ -+/* Quarter dBm units to mW -+ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 -+ * Table is offset so the last entry is largest mW value that fits in -+ * a uint16. -+ */ -+ -+#define QDBM_OFFSET 153 /* Offset for first entry */ -+#define QDBM_TABLE_LEN 40 /* Table size */ -+ -+/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. -+ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 -+ */ -+#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ -+ -+/* Largest mW value that will round down to the last table entry, -+ * QDBM_OFFSET + QDBM_TABLE_LEN-1. -+ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. -+ */ -+#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ -+ -+static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { -+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ -+/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, -+/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, -+/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, -+/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, -+/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 -+}; -+ -+uint16 -+bcm_qdbm_to_mw(uint8 qdbm) -+{ -+ uint factor = 1; -+ int idx = qdbm - QDBM_OFFSET; -+ -+ if (idx >= QDBM_TABLE_LEN) { -+ /* clamp to max uint16 mW value */ -+ return 0xFFFF; -+ } -+ -+ /* scale the qdBm index up to the range of the table 0-40 -+ * where an offset of 40 qdBm equals a factor of 10 mW. -+ */ -+ while (idx < 0) { -+ idx += 40; -+ factor *= 10; -+ } -+ -+ /* return the mW value scaled down to the correct factor of 10, -+ * adding in factor/2 to get proper rounding. -+ */ -+ return ((nqdBm_to_mW_map[idx] + factor/2) / factor); -+} -+ -+uint8 -+bcm_mw_to_qdbm(uint16 mw) -+{ -+ uint8 qdbm; -+ int offset; -+ uint mw_uint = mw; -+ uint boundary; -+ -+ /* handle boundary case */ -+ if (mw_uint <= 1) -+ return 0; -+ -+ offset = QDBM_OFFSET; -+ -+ /* move mw into the range of the table */ -+ while (mw_uint < QDBM_TABLE_LOW_BOUND) { -+ mw_uint *= 10; -+ offset -= 40; -+ } -+ -+ for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { -+ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - -+ nqdBm_to_mW_map[qdbm])/2; -+ if (mw_uint < boundary) break; -+ } -+ -+ qdbm += (uint8)offset; -+ -+ return (qdbm); -+} -+ -+ -+uint -+bcm_bitcount(uint8 *bitmap, uint length) -+{ -+ uint bitcount = 0, i; -+ uint8 tmp; -+ for (i = 0; i < length; i++) { -+ tmp = bitmap[i]; -+ while (tmp) { -+ bitcount++; -+ tmp &= (tmp - 1); -+ } -+ } -+ return bitcount; -+} -+ -+#ifdef BCMDRIVER -+ -+/* Initialization of bcmstrbuf structure */ -+void -+bcm_binit(struct bcmstrbuf *b, char *buf, uint size) -+{ -+ b->origsize = b->size = size; -+ b->origbuf = b->buf = buf; -+} -+ -+/* Buffer sprintf wrapper to guard against buffer overflow */ -+int -+bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) -+{ -+ va_list ap; -+ int r; -+ -+ va_start(ap, fmt); -+ -+ r = vsnprintf(b->buf, b->size, fmt, ap); -+ -+ /* Non Ansi C99 compliant returns -1, -+ * Ansi compliant return r >= b->size, -+ * bcmstdlib returns 0, handle all -+ */ -+ /* r == 0 is also the case when strlen(fmt) is zero. -+ * typically the case when "" is passed as argument. -+ */ -+ if ((r == -1) || (r >= (int)b->size)) { -+ b->size = 0; -+ } else { -+ b->size -= r; -+ b->buf += r; -+ } -+ -+ va_end(ap); -+ -+ return r; -+} -+ -+void -+bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len) -+{ -+ int i; -+ -+ if (msg != NULL && msg[0] != '\0') -+ bcm_bprintf(b, "%s", msg); -+ for (i = 0; i < len; i ++) -+ bcm_bprintf(b, "%02X", buf[i]); -+ if (newline) -+ bcm_bprintf(b, "\n"); -+} -+ -+void -+bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) -+{ -+ int i; -+ -+ for (i = 0; i < num_bytes; i++) { -+ num[i] += amount; -+ if (num[i] >= amount) -+ break; -+ amount = 1; -+ } -+} -+ -+int -+bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) -+{ -+ int i; -+ -+ for (i = nbytes - 1; i >= 0; i--) { -+ if (arg1[i] != arg2[i]) -+ return (arg1[i] - arg2[i]); -+ } -+ return 0; -+} -+ -+void -+bcm_print_bytes(const char *name, const uchar *data, int len) -+{ -+ int i; -+ int per_line = 0; -+ -+ printf("%s: %d \n", name ? name : "", len); -+ for (i = 0; i < len; i++) { -+ printf("%02x ", *data++); -+ per_line++; -+ if (per_line == 16) { -+ per_line = 0; -+ printf("\n"); -+ } -+ } -+ printf("\n"); -+} -+#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ -+ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) -+#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) -+ -+int -+bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) -+{ -+ uint i, c; -+ char *p = buf; -+ char *endp = buf + SSID_FMT_BUF_LEN; -+ -+ if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; -+ -+ for (i = 0; i < ssid_len; i++) { -+ c = (uint)ssid[i]; -+ if (c == '\\') { -+ *p++ = '\\'; -+ *p++ = '\\'; -+ } else if (bcm_isprint((uchar)c)) { -+ *p++ = (char)c; -+ } else { -+ p += snprintf(p, (endp - p), "\\x%02X", c); -+ } -+ } -+ *p = '\0'; -+ ASSERT(p < endp); -+ -+ return (int)(p - buf); -+} -+#endif -+ -+#endif /* BCMDRIVER */ -+ -+/* -+ * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL. -+ * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0 -+ * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. -+ * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. -+*/ -+ -+unsigned int -+process_nvram_vars(char *varbuf, unsigned int len) -+{ -+ char *dp; -+ bool findNewline; -+ int column; -+ unsigned int buf_len, n; -+ unsigned int pad = 0; -+ -+ dp = varbuf; -+ -+ findNewline = FALSE; -+ column = 0; -+ -+ for (n = 0; n < len; n++) { -+ if (varbuf[n] == '\r') -+ continue; -+ if (findNewline && varbuf[n] != '\n') -+ continue; -+ findNewline = FALSE; -+ if (varbuf[n] == '#') { -+ findNewline = TRUE; -+ continue; -+ } -+ if (varbuf[n] == '\n') { -+ if (column == 0) -+ continue; -+ *dp++ = 0; -+ column = 0; -+ continue; -+ } -+ *dp++ = varbuf[n]; -+ column++; -+ } -+ buf_len = (unsigned int)(dp - varbuf); -+ if (buf_len % 4) { -+ pad = 4 - buf_len % 4; -+ if (pad && (buf_len + pad <= len)) { -+ buf_len += pad; -+ } -+ } -+ -+ while (dp < varbuf + n) -+ *dp++ = 0; -+ -+ return buf_len; -+} -diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c -new file mode 100644 -index 00000000..6b5b0a3a ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c -@@ -0,0 +1,1179 @@ -+/* -+ * Misc utility routines used by kernel or app-level. -+ * Contents are wifi-specific, used by any kernel or app-level -+ * software that might want wifi things as it grows. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ -+ */ -+ -+#include <bcm_cfg.h> -+#include <typedefs.h> -+ -+#ifdef BCMDRIVER -+#include <osl.h> -+#include <bcmutils.h> -+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -+#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -+#else -+#include <stdio.h> -+#include <stdlib.h> -+#include <ctype.h> -+#ifndef ASSERT -+#define ASSERT(exp) -+#endif -+#endif /* BCMDRIVER */ -+ -+#ifdef _bcmwifi_c_ -+/* temporary for transitional compatibility */ -+#include <bcmwifi.h> -+#else -+#include <bcmwifi_channels.h> -+#endif -+ -+#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) -+#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ -+#endif -+ -+#ifndef D11AC_IOTYPES -+ -+/* Definitions for legacy Chanspec type */ -+ -+/* Chanspec ASCII representation: -+ * <channel><band><bandwidth><ctl-sideband> -+ * digit [AB] [N] [UL] -+ * -+ * <channel>: channel number of the 10MHz or 20MHz channel, -+ * or control sideband channel of 40MHz channel. -+ * <band>: A for 5GHz, B for 2.4GHz -+ * <bandwidth>: N for 10MHz, nothing for 20MHz or 40MHz -+ * (ctl-sideband spec implies 40MHz) -+ * <ctl-sideband>: U for upper, L for lower -+ * -+ * <band> may be omitted on input, and will be assumed to be -+ * 2.4GHz if channel number <= 14. -+ * -+ * Examples: -+ * 8 -> 2.4GHz channel 8, 20MHz -+ * 8b -> 2.4GHz channel 8, 20MHz -+ * 8l -> 2.4GHz channel 8, 40MHz, lower ctl sideband -+ * 8a -> 5GHz channel 8 (low 5 GHz band), 20MHz -+ * 36 -> 5GHz channel 36, 20MHz -+ * 36l -> 5GHz channel 36, 40MHz, lower ctl sideband -+ * 40u -> 5GHz channel 40, 40MHz, upper ctl sideband -+ * 180n -> channel 180, 10MHz -+ */ -+ -+ -+/* given a chanspec and a string buffer, format the chanspec as a -+ * string, and return the original pointer a. -+ * Min buffer length must be CHANSPEC_STR_LEN. -+ * On error return NULL -+ */ -+char * -+wf_chspec_ntoa(chanspec_t chspec, char *buf) -+{ -+ const char *band, *bw, *sb; -+ uint channel; -+ -+ band = ""; -+ bw = ""; -+ sb = ""; -+ channel = CHSPEC_CHANNEL(chspec); -+ /* check for non-default band spec */ -+ if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) || -+ (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL)) -+ band = (CHSPEC_IS2G(chspec)) ? "b" : "a"; -+ if (CHSPEC_IS40(chspec)) { -+ if (CHSPEC_SB_UPPER(chspec)) { -+ sb = "u"; -+ channel += CH_10MHZ_APART; -+ } else { -+ sb = "l"; -+ channel -= CH_10MHZ_APART; -+ } -+ } else if (CHSPEC_IS10(chspec)) { -+ bw = "n"; -+ } -+ -+ /* Outputs a max of 6 chars including '\0' */ -+ snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb); -+ return (buf); -+} -+ -+/* given a chanspec string, convert to a chanspec. -+ * On error return 0 -+ */ -+chanspec_t -+wf_chspec_aton(const char *a) -+{ -+ char *endp = NULL; -+ uint channel, band, bw, ctl_sb; -+ char c; -+ -+ channel = strtoul(a, &endp, 10); -+ -+ /* check for no digits parsed */ -+ if (endp == a) -+ return 0; -+ -+ if (channel > MAXCHANNEL) -+ return 0; -+ -+ band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); -+ bw = WL_CHANSPEC_BW_20; -+ ctl_sb = WL_CHANSPEC_CTL_SB_NONE; -+ -+ a = endp; -+ -+ c = tolower(a[0]); -+ if (c == '\0') -+ goto done; -+ -+ /* parse the optional ['A' | 'B'] band spec */ -+ if (c == 'a' || c == 'b') { -+ band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G; -+ a++; -+ c = tolower(a[0]); -+ if (c == '\0') -+ goto done; -+ } -+ -+ /* parse bandwidth 'N' (10MHz) or 40MHz ctl sideband ['L' | 'U'] */ -+ if (c == 'n') { -+ bw = WL_CHANSPEC_BW_10; -+ } else if (c == 'l') { -+ bw = WL_CHANSPEC_BW_40; -+ ctl_sb = WL_CHANSPEC_CTL_SB_LOWER; -+ /* adjust channel to center of 40MHz band */ -+ if (channel <= (MAXCHANNEL - CH_20MHZ_APART)) -+ channel += CH_10MHZ_APART; -+ else -+ return 0; -+ } else if (c == 'u') { -+ bw = WL_CHANSPEC_BW_40; -+ ctl_sb = WL_CHANSPEC_CTL_SB_UPPER; -+ /* adjust channel to center of 40MHz band */ -+ if (channel > CH_20MHZ_APART) -+ channel -= CH_10MHZ_APART; -+ else -+ return 0; -+ } else { -+ return 0; -+ } -+ -+done: -+ return (channel | band | bw | ctl_sb); -+} -+ -+/* -+ * Verify the chanspec is using a legal set of parameters, i.e. that the -+ * chanspec specified a band, bw, ctl_sb and channel and that the -+ * combination could be legal given any set of circumstances. -+ * RETURNS: TRUE is the chanspec is malformed, false if it looks good. -+ */ -+bool -+wf_chspec_malformed(chanspec_t chanspec) -+{ -+ /* must be 2G or 5G band */ -+ if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec)) -+ return TRUE; -+ /* must be 20 or 40 bandwidth */ -+ if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec)) -+ return TRUE; -+ -+ /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */ -+ if (CHSPEC_IS20(chanspec)) { -+ if (!CHSPEC_SB_NONE(chanspec)) -+ return TRUE; -+ } else { -+ if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+/* -+ * This function returns the channel number that control traffic is being sent on, for legacy -+ * channels this is just the channel number, for 40MHZ channels it is the upper or lower 20MHZ -+ * sideband depending on the chanspec selected -+ */ -+uint8 -+wf_chspec_ctlchan(chanspec_t chspec) -+{ -+ uint8 ctl_chan; -+ -+ /* Is there a sideband ? */ -+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { -+ return CHSPEC_CHANNEL(chspec); -+ } else { -+ /* we only support 40MHZ with sidebands */ -+ ASSERT(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_40); -+ /* chanspec channel holds the centre frequency, use that and the -+ * side band information to reconstruct the control channel number -+ */ -+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { -+ /* control chan is the upper 20 MHZ SB of the 40MHZ channel */ -+ ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); -+ } else { -+ ASSERT(CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_LOWER); -+ /* control chan is the lower 20 MHZ SB of the 40MHZ channel */ -+ ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); -+ } -+ } -+ -+ return ctl_chan; -+} -+ -+chanspec_t -+wf_chspec_ctlchspec(chanspec_t chspec) -+{ -+ chanspec_t ctl_chspec = 0; -+ uint8 channel; -+ -+ ASSERT(!wf_chspec_malformed(chspec)); -+ -+ /* Is there a sideband ? */ -+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { -+ return chspec; -+ } else { -+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { -+ channel = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); -+ } else { -+ channel = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); -+ } -+ ctl_chspec = channel | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; -+ ctl_chspec |= CHSPEC_BAND(chspec); -+ } -+ return ctl_chspec; -+} -+ -+#else /* D11AC_IOTYPES */ -+ -+/* Definitions for D11AC capable Chanspec type */ -+ -+/* Chanspec ASCII representation with 802.11ac capability: -+ * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]] -+ * -+ * <band>: -+ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. -+ * Default value is 2g if channel <= 14, otherwise 5g. -+ * <channel>: -+ * channel number of the 5MHz, 10MHz, 20MHz channel, -+ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. -+ * <bandwidth>: -+ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. -+ * <primary-sideband>: -+ * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. -+ * -+ * For 2.4GHz band 40MHz channels, the same primary channel may be the -+ * upper sideband for one 40MHz channel, and the lower sideband for an -+ * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel -+ * is being specified. -+ * -+ * For 40MHz in the 5GHz band and all channel bandwidths greater than -+ * 40MHz, the U/L specificaion is not allowed since the channels are -+ * non-overlapping and the primary sub-band is derived from its -+ * position in the wide bandwidth channel. -+ * -+ * <1st80Channel>: -+ * <2nd80Channel>: -+ * Required for 80+80, otherwise not allowed. -+ * Specifies the center channel of the first and second 80MHz band. -+ * -+ * In its simplest form, it is a 20MHz channel number, with the implied band -+ * of 2.4GHz if channel number <= 14, and 5GHz otherwise. -+ * -+ * To allow for backward compatibility with scripts, the old form for -+ * 40MHz channels is also allowed: <channel><ctl-sideband> -+ * -+ * <channel>: -+ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz -+ * <ctl-sideband>: -+ * "U" for upper, "L" for lower (or lower case "u" "l") -+ * -+ * 5 GHz Examples: -+ * Chanspec BW Center Ch Channel Range Primary Ch -+ * 5g8 20MHz 8 - - -+ * 52 20MHz 52 - - -+ * 52/40 40MHz 54 52-56 52 -+ * 56/40 40MHz 54 52-56 56 -+ * 52/80 80MHz 58 52-64 52 -+ * 56/80 80MHz 58 52-64 56 -+ * 60/80 80MHz 58 52-64 60 -+ * 64/80 80MHz 58 52-64 64 -+ * 52/160 160MHz 50 36-64 52 -+ * 36/160 160MGz 50 36-64 36 -+ * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 -+ * -+ * 2 GHz Examples: -+ * Chanspec BW Center Ch Channel Range Primary Ch -+ * 2g8 20MHz 8 - - -+ * 8 20MHz 8 - - -+ * 6 20MHz 6 - - -+ * 6/40l 40MHz 8 6-10 6 -+ * 6l 40MHz 8 6-10 6 -+ * 6/40u 40MHz 4 2-6 6 -+ * 6u 40MHz 4 2-6 6 -+ */ -+ -+/* bandwidth ASCII string */ -+static const char *wf_chspec_bw_str[] = -+{ -+ "5", -+ "10", -+ "20", -+ "40", -+ "80", -+ "160", -+ "80+80", -+ "na" -+}; -+ -+static const uint8 wf_chspec_bw_mhz[] = -+{5, 10, 20, 40, 80, 160, 160}; -+ -+#define WF_NUM_BW \ -+ (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) -+ -+/* 40MHz channels in 5GHz band */ -+static const uint8 wf_5g_40m_chans[] = -+{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; -+#define WF_NUM_5G_40M_CHANS \ -+ (sizeof(wf_5g_40m_chans)/sizeof(uint8)) -+ -+/* 80MHz channels in 5GHz band */ -+static const uint8 wf_5g_80m_chans[] = -+{42, 58, 106, 122, 138, 155}; -+#define WF_NUM_5G_80M_CHANS \ -+ (sizeof(wf_5g_80m_chans)/sizeof(uint8)) -+ -+/* 160MHz channels in 5GHz band */ -+static const uint8 wf_5g_160m_chans[] = -+{50, 114}; -+#define WF_NUM_5G_160M_CHANS \ -+ (sizeof(wf_5g_160m_chans)/sizeof(uint8)) -+ -+ -+/* convert bandwidth from chanspec to MHz */ -+static uint -+bw_chspec_to_mhz(chanspec_t chspec) -+{ -+ uint bw; -+ -+ bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; -+ return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); -+} -+ -+/* bw in MHz, return the channel count from the center channel to the -+ * the channel at the edge of the band -+ */ -+static uint8 -+center_chan_to_edge(uint bw) -+{ -+ /* edge channels separated by BW - 10MHz on each side -+ * delta from cf to edge is half of that, -+ * MHz to channel num conversion is 5MHz/channel -+ */ -+ return (uint8)(((bw - 20) / 2) / 5); -+} -+ -+/* return channel number of the low edge of the band -+ * given the center channel and BW -+ */ -+static uint8 -+channel_low_edge(uint center_ch, uint bw) -+{ -+ return (uint8)(center_ch - center_chan_to_edge(bw)); -+} -+ -+/* return side band number given center channel and control channel -+ * return -1 on error -+ */ -+static int -+channel_to_sb(uint center_ch, uint ctl_ch, uint bw) -+{ -+ uint lowest = channel_low_edge(center_ch, bw); -+ uint sb; -+ -+ if ((ctl_ch - lowest) % 4) { -+ /* bad ctl channel, not mult 4 */ -+ return -1; -+ } -+ -+ sb = ((ctl_ch - lowest) / 4); -+ -+ /* sb must be a index to a 20MHz channel in range */ -+ if (sb >= (bw / 20)) { -+ /* ctl_ch must have been too high for the center_ch */ -+ return -1; -+ } -+ -+ return sb; -+} -+ -+/* return control channel given center channel and side band */ -+static uint8 -+channel_to_ctl_chan(uint center_ch, uint bw, uint sb) -+{ -+ return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); -+} -+ -+/* return index of 80MHz channel from channel number -+ * return -1 on error -+ */ -+static int -+channel_80mhz_to_id(uint ch) -+{ -+ uint i; -+ for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { -+ if (ch == wf_5g_80m_chans[i]) -+ return i; -+ } -+ -+ return -1; -+} -+ -+/* given a chanspec and a string buffer, format the chanspec as a -+ * string, and return the original pointer a. -+ * Min buffer length must be CHANSPEC_STR_LEN. -+ * On error return NULL -+ */ -+char * -+wf_chspec_ntoa(chanspec_t chspec, char *buf) -+{ -+ const char *band; -+ uint ctl_chan; -+ -+ if (wf_chspec_malformed(chspec)) -+ return NULL; -+ -+ band = ""; -+ -+ /* check for non-default band spec */ -+ if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || -+ (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) -+ band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; -+ -+ /* ctl channel */ -+ ctl_chan = wf_chspec_ctlchan(chspec); -+ -+ /* bandwidth and ctl sideband */ -+ if (CHSPEC_IS20(chspec)) { -+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); -+ } else if (!CHSPEC_IS8080(chspec)) { -+ const char *bw; -+ const char *sb = ""; -+ -+ bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; -+ -+#ifdef CHANSPEC_NEW_40MHZ_FORMAT -+ /* ctl sideband string if needed for 2g 40MHz */ -+ if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { -+ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; -+ } -+ -+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); -+#else -+ /* ctl sideband string instead of BW for 40MHz */ -+ if (CHSPEC_IS40(chspec)) { -+ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; -+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); -+ } else { -+ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); -+ } -+#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ -+ -+ } else { -+ /* 80+80 */ -+ uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; -+ uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; -+ -+ /* convert to channel number */ -+ chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; -+ chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; -+ -+ /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ -+ snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); -+ } -+ -+ return (buf); -+} -+ -+static int -+read_uint(const char **p, unsigned int *num) -+{ -+ unsigned long val; -+ char *endp = NULL; -+ -+ val = strtoul(*p, &endp, 10); -+ /* if endp is the initial pointer value, then a number was not read */ -+ if (endp == *p) -+ return 0; -+ -+ /* advance the buffer pointer to the end of the integer string */ -+ *p = endp; -+ /* return the parsed integer */ -+ *num = (unsigned int)val; -+ -+ return 1; -+} -+ -+/* given a chanspec string, convert to a chanspec. -+ * On error return 0 -+ */ -+chanspec_t -+wf_chspec_aton(const char *a) -+{ -+ chanspec_t chspec; -+ uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; -+ uint num, ctl_ch; -+ uint ch1, ch2; -+ char c, sb_ul = '\0'; -+ int i; -+ -+ bw = 20; -+ chspec_sb = 0; -+ chspec_ch = ch1 = ch2 = 0; -+ -+ /* parse channel num or band */ -+ if (!read_uint(&a, &num)) -+ return 0; -+ -+ /* if we are looking at a 'g', then the first number was a band */ -+ c = tolower(a[0]); -+ if (c == 'g') { -+ a ++; /* consume the char */ -+ -+ /* band must be "2" or "5" */ -+ if (num == 2) -+ chspec_band = WL_CHANSPEC_BAND_2G; -+ else if (num == 5) -+ chspec_band = WL_CHANSPEC_BAND_5G; -+ else -+ return 0; -+ -+ /* read the channel number */ -+ if (!read_uint(&a, &ctl_ch)) -+ return 0; -+ -+ c = tolower(a[0]); -+ } -+ else { -+ /* first number is channel, use default for band */ -+ ctl_ch = num; -+ chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? -+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); -+ } -+ -+ if (c == '\0') { -+ /* default BW of 20MHz */ -+ chspec_bw = WL_CHANSPEC_BW_20; -+ goto done_read; -+ } -+ -+ a ++; /* consume the 'u','l', or '/' */ -+ -+ /* check 'u'/'l' */ -+ if (c == 'u' || c == 'l') { -+ sb_ul = c; -+ chspec_bw = WL_CHANSPEC_BW_40; -+ goto done_read; -+ } -+ -+ /* next letter must be '/' */ -+ if (c != '/') -+ return 0; -+ -+ /* read bandwidth */ -+ if (!read_uint(&a, &bw)) -+ return 0; -+ -+ /* convert to chspec value */ -+ if (bw == 20) { -+ chspec_bw = WL_CHANSPEC_BW_20; -+ } else if (bw == 40) { -+ chspec_bw = WL_CHANSPEC_BW_40; -+ } else if (bw == 80) { -+ chspec_bw = WL_CHANSPEC_BW_80; -+ } else if (bw == 160) { -+ chspec_bw = WL_CHANSPEC_BW_160; -+ } else { -+ return 0; -+ } -+ -+ /* So far we have <band>g<chan>/<bw> -+ * Can now be followed by u/l if bw = 40, -+ * or '+80' if bw = 80, to make '80+80' bw. -+ */ -+ -+ c = tolower(a[0]); -+ -+ /* if we have a 2g/40 channel, we should have a l/u spec now */ -+ if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { -+ if (c == 'u' || c == 'l') { -+ a ++; /* consume the u/l char */ -+ sb_ul = c; -+ goto done_read; -+ } -+ } -+ -+ /* check for 80+80 */ -+ if (c == '+') { -+ /* 80+80 */ -+ static const char *plus80 = "80/"; -+ -+ /* must be looking at '+80/' -+ * check and consume this string. -+ */ -+ chspec_bw = WL_CHANSPEC_BW_8080; -+ -+ a ++; /* consume the char '+' */ -+ -+ /* consume the '80/' string */ -+ for (i = 0; i < 3; i++) { -+ if (*a++ != *plus80++) { -+ return 0; -+ } -+ } -+ -+ /* read primary 80MHz channel */ -+ if (!read_uint(&a, &ch1)) -+ return 0; -+ -+ /* must followed by '-' */ -+ if (a[0] != '-') -+ return 0; -+ a ++; /* consume the char */ -+ -+ /* read secondary 80MHz channel */ -+ if (!read_uint(&a, &ch2)) -+ return 0; -+ } -+ -+done_read: -+ /* skip trailing white space */ -+ while (a[0] == ' ') { -+ a ++; -+ } -+ -+ /* must be end of string */ -+ if (a[0] != '\0') -+ return 0; -+ -+ /* Now have all the chanspec string parts read; -+ * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. -+ * chspec_band and chspec_bw are chanspec values. -+ * Need to convert ctl_ch, sb_ul, and ch1,ch2 into -+ * a center channel (or two) and sideband. -+ */ -+ -+ /* if a sb u/l string was given, just use that, -+ * guaranteed to be bw = 40 by sting parse. -+ */ -+ if (sb_ul != '\0') { -+ if (sb_ul == 'l') { -+ chspec_ch = UPPER_20_SB(ctl_ch); -+ chspec_sb = WL_CHANSPEC_CTL_SB_LLL; -+ } else if (sb_ul == 'u') { -+ chspec_ch = LOWER_20_SB(ctl_ch); -+ chspec_sb = WL_CHANSPEC_CTL_SB_LLU; -+ } -+ } -+ /* if the bw is 20, center and sideband are trivial */ -+ else if (chspec_bw == WL_CHANSPEC_BW_20) { -+ chspec_ch = ctl_ch; -+ chspec_sb = 0; -+ } -+ /* if the bw is 40/80/160, not 80+80, a single method -+ * can be used to to find the center and sideband -+ */ -+ else if (chspec_bw != WL_CHANSPEC_BW_8080) { -+ /* figure out ctl sideband based on ctl channel and bandwidth */ -+ const uint8 *center_ch = NULL; -+ int num_ch = 0; -+ int sb = -1; -+ -+ if (chspec_bw == WL_CHANSPEC_BW_40) { -+ center_ch = wf_5g_40m_chans; -+ num_ch = WF_NUM_5G_40M_CHANS; -+ } else if (chspec_bw == WL_CHANSPEC_BW_80) { -+ center_ch = wf_5g_80m_chans; -+ num_ch = WF_NUM_5G_80M_CHANS; -+ } else if (chspec_bw == WL_CHANSPEC_BW_160) { -+ center_ch = wf_5g_160m_chans; -+ num_ch = WF_NUM_5G_160M_CHANS; -+ } else { -+ return 0; -+ } -+ -+ for (i = 0; i < num_ch; i ++) { -+ sb = channel_to_sb(center_ch[i], ctl_ch, bw); -+ if (sb >= 0) { -+ chspec_ch = center_ch[i]; -+ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; -+ break; -+ } -+ } -+ -+ /* check for no matching sb/center */ -+ if (sb < 0) { -+ return 0; -+ } -+ } -+ /* Otherwise, bw is 80+80. Figure out channel pair and sb */ -+ else { -+ int ch1_id = 0, ch2_id = 0; -+ int sb; -+ -+ ch1_id = channel_80mhz_to_id(ch1); -+ ch2_id = channel_80mhz_to_id(ch2); -+ -+ /* validate channels */ -+ if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) -+ return 0; -+ -+ /* combined channel in chspec */ -+ chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | -+ ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); -+ -+ /* figure out ctl sideband */ -+ -+ /* does the primary channel fit with the 1st 80MHz channel ? */ -+ sb = channel_to_sb(ch1, ctl_ch, bw); -+ if (sb < 0) { -+ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ -+ sb = channel_to_sb(ch2, ctl_ch, bw); -+ if (sb < 0) { -+ /* no match for ctl_ch to either 80MHz center channel */ -+ return 0; -+ } -+ /* sb index is 0-3 for the low 80MHz channel, and 4-7 for -+ * the high 80MHz channel. Add 4 to to shift to high set. -+ */ -+ sb += 4; -+ } -+ -+ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; -+ } -+ -+ chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); -+ -+ if (wf_chspec_malformed(chspec)) -+ return 0; -+ -+ return chspec; -+} -+ -+/* -+ * Verify the chanspec is using a legal set of parameters, i.e. that the -+ * chanspec specified a band, bw, ctl_sb and channel and that the -+ * combination could be legal given any set of circumstances. -+ * RETURNS: TRUE is the chanspec is malformed, false if it looks good. -+ */ -+bool -+wf_chspec_malformed(chanspec_t chanspec) -+{ -+ uint chspec_bw = CHSPEC_BW(chanspec); -+ uint chspec_ch = CHSPEC_CHANNEL(chanspec); -+ -+ /* must be 2G or 5G band */ -+ if (CHSPEC_IS2G(chanspec)) { -+ /* must be valid bandwidth */ -+ if (chspec_bw != WL_CHANSPEC_BW_20 && -+ chspec_bw != WL_CHANSPEC_BW_40) { -+ return TRUE; -+ } -+ } else if (CHSPEC_IS5G(chanspec)) { -+ if (chspec_bw == WL_CHANSPEC_BW_8080) { -+ uint ch1_id, ch2_id; -+ -+ /* channel number in 80+80 must be in range */ -+ ch1_id = CHSPEC_CHAN1(chanspec); -+ ch2_id = CHSPEC_CHAN2(chanspec); -+ if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) -+ return TRUE; -+ -+ /* ch2 must be above ch1 for the chanspec */ -+ if (ch2_id <= ch1_id) -+ return TRUE; -+ } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || -+ chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { -+ -+ if (chspec_ch > MAXCHANNEL) { -+ return TRUE; -+ } -+ } else { -+ /* invalid bandwidth */ -+ return TRUE; -+ } -+ } else { -+ /* must be 2G or 5G band */ -+ return TRUE; -+ } -+ -+ /* side band needs to be consistent with bandwidth */ -+ if (chspec_bw == WL_CHANSPEC_BW_20) { -+ if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) -+ return TRUE; -+ } else if (chspec_bw == WL_CHANSPEC_BW_40) { -+ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) -+ return TRUE; -+ } else if (chspec_bw == WL_CHANSPEC_BW_80) { -+ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+/* -+ * Verify the chanspec specifies a valid channel according to 802.11. -+ * RETURNS: TRUE if the chanspec is a valid 802.11 channel -+ */ -+bool -+wf_chspec_valid(chanspec_t chanspec) -+{ -+ uint chspec_bw = CHSPEC_BW(chanspec); -+ uint chspec_ch = CHSPEC_CHANNEL(chanspec); -+ -+ if (wf_chspec_malformed(chanspec)) -+ return FALSE; -+ -+ if (CHSPEC_IS2G(chanspec)) { -+ /* must be valid bandwidth and channel range */ -+ if (chspec_bw == WL_CHANSPEC_BW_20) { -+ if (chspec_ch >= 1 && chspec_ch <= 14) -+ return TRUE; -+ } else if (chspec_bw == WL_CHANSPEC_BW_40) { -+ if (chspec_ch >= 3 && chspec_ch <= 11) -+ return TRUE; -+ } -+ } else if (CHSPEC_IS5G(chanspec)) { -+ if (chspec_bw == WL_CHANSPEC_BW_8080) { -+ uint16 ch1, ch2; -+ -+ ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; -+ ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; -+ -+ /* the two channels must be separated by more than 80MHz by VHT req, -+ * and ch2 above ch1 for the chanspec -+ */ -+ if (ch2 > ch1 + CH_80MHZ_APART) -+ return TRUE; -+ } else { -+ const uint8 *center_ch; -+ uint num_ch, i; -+ -+ if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { -+ center_ch = wf_5g_40m_chans; -+ num_ch = WF_NUM_5G_40M_CHANS; -+ } else if (chspec_bw == WL_CHANSPEC_BW_80) { -+ center_ch = wf_5g_80m_chans; -+ num_ch = WF_NUM_5G_80M_CHANS; -+ } else if (chspec_bw == WL_CHANSPEC_BW_160) { -+ center_ch = wf_5g_160m_chans; -+ num_ch = WF_NUM_5G_160M_CHANS; -+ } else { -+ /* invalid bandwidth */ -+ return FALSE; -+ } -+ -+ /* check for a valid center channel */ -+ if (chspec_bw == WL_CHANSPEC_BW_20) { -+ /* We don't have an array of legal 20MHz 5G channels, but they are -+ * each side of the legal 40MHz channels. Check the chanspec -+ * channel against either side of the 40MHz channels. -+ */ -+ for (i = 0; i < num_ch; i ++) { -+ if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || -+ chspec_ch == (uint)UPPER_20_SB(center_ch[i])) -+ break; /* match found */ -+ } -+ -+ if (i == num_ch) { -+ /* check for legacy JP channels on failure */ -+ if (chspec_ch == 34 || chspec_ch == 38 || -+ chspec_ch == 42 || chspec_ch == 46) -+ i = 0; -+ } -+ } else { -+ /* check the chanspec channel to each legal channel */ -+ for (i = 0; i < num_ch; i ++) { -+ if (chspec_ch == center_ch[i]) -+ break; /* match found */ -+ } -+ } -+ -+ if (i < num_ch) { -+ /* match found */ -+ return TRUE; -+ } -+ } -+ } -+ -+ return FALSE; -+} -+ -+/* -+ * This function returns the channel number that control traffic is being sent on, for 20MHz -+ * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ -+ * sideband depending on the chanspec selected -+ */ -+uint8 -+wf_chspec_ctlchan(chanspec_t chspec) -+{ -+ uint center_chan; -+ uint bw_mhz; -+ uint sb; -+ -+ ASSERT(!wf_chspec_malformed(chspec)); -+ -+ /* Is there a sideband ? */ -+ if (CHSPEC_IS20(chspec)) { -+ return CHSPEC_CHANNEL(chspec); -+ } else { -+ sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; -+ -+ if (CHSPEC_IS8080(chspec)) { -+ bw_mhz = 80; -+ -+ if (sb < 4) { -+ center_chan = CHSPEC_CHAN1(chspec); -+ } -+ else { -+ center_chan = CHSPEC_CHAN2(chspec); -+ sb -= 4; -+ } -+ -+ /* convert from channel index to channel number */ -+ center_chan = wf_5g_80m_chans[center_chan]; -+ } -+ else { -+ bw_mhz = bw_chspec_to_mhz(chspec); -+ center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; -+ } -+ -+ return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); -+ } -+} -+ -+/* -+ * This function returns the chanspec of the control channel of a given chanspec -+ */ -+chanspec_t -+wf_chspec_ctlchspec(chanspec_t chspec) -+{ -+ chanspec_t ctl_chspec = chspec; -+ uint8 ctl_chan; -+ -+ ASSERT(!wf_chspec_malformed(chspec)); -+ -+ /* Is there a sideband ? */ -+ if (!CHSPEC_IS20(chspec)) { -+ ctl_chan = wf_chspec_ctlchan(chspec); -+ ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; -+ ctl_chspec |= CHSPEC_BAND(chspec); -+ } -+ return ctl_chspec; -+} -+ -+/* return chanspec given control channel and bandwidth -+ * return 0 on error -+ */ -+uint16 -+wf_channel2chspec(uint ctl_ch, uint bw) -+{ -+ uint16 chspec; -+ const uint8 *center_ch = NULL; -+ int num_ch = 0; -+ int sb = -1; -+ int i = 0; -+ -+ chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); -+ -+ chspec |= bw; -+ -+ if (bw == WL_CHANSPEC_BW_40) { -+ center_ch = wf_5g_40m_chans; -+ num_ch = WF_NUM_5G_40M_CHANS; -+ bw = 40; -+ } else if (bw == WL_CHANSPEC_BW_80) { -+ center_ch = wf_5g_80m_chans; -+ num_ch = WF_NUM_5G_80M_CHANS; -+ bw = 80; -+ } else if (bw == WL_CHANSPEC_BW_160) { -+ center_ch = wf_5g_160m_chans; -+ num_ch = WF_NUM_5G_160M_CHANS; -+ bw = 160; -+ } else if (bw == WL_CHANSPEC_BW_20) { -+ chspec |= ctl_ch; -+ return chspec; -+ } else { -+ return 0; -+ } -+ -+ for (i = 0; i < num_ch; i ++) { -+ sb = channel_to_sb(center_ch[i], ctl_ch, bw); -+ if (sb >= 0) { -+ chspec |= center_ch[i]; -+ chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); -+ break; -+ } -+ } -+ -+ /* check for no matching sb/center */ -+ if (sb < 0) { -+ return 0; -+ } -+ -+ return chspec; -+} -+#endif /* D11AC_IOTYPES */ -+ -+/* -+ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. -+ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using -+ * as the primary 20MHz channel. -+ */ -+extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) -+{ -+ chanspec_t chspec40 = chspec; -+ uint center_chan; -+ uint sb; -+ -+ ASSERT(!wf_chspec_malformed(chspec)); -+ -+ if (CHSPEC_IS80(chspec)) { -+ center_chan = CHSPEC_CHANNEL(chspec); -+ sb = CHSPEC_CTL_SB(chspec); -+ -+ if (sb == WL_CHANSPEC_CTL_SB_UL) { -+ /* Primary 40MHz is on upper side */ -+ sb = WL_CHANSPEC_CTL_SB_L; -+ center_chan += CH_20MHZ_APART; -+ } else if (sb == WL_CHANSPEC_CTL_SB_UU) { -+ /* Primary 40MHz is on upper side */ -+ sb = WL_CHANSPEC_CTL_SB_U; -+ center_chan += CH_20MHZ_APART; -+ } else { -+ /* Primary 40MHz is on lower side */ -+ /* sideband bits are the same for LL/LU and L/U */ -+ center_chan -= CH_20MHZ_APART; -+ } -+ -+ /* Create primary 40MHz chanspec */ -+ chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | -+ sb | center_chan); -+ } -+ -+ return chspec40; -+} -+ -+/* -+ * Return the channel number for a given frequency and base frequency. -+ * The returned channel number is relative to the given base frequency. -+ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for -+ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. -+ * -+ * Frequency is specified in MHz. -+ * The base frequency is specified as (start_factor * 500 kHz). -+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for -+ * 2.4 GHz and 5 GHz bands. -+ * -+ * The returned channel will be in the range [1, 14] in the 2.4 GHz band -+ * and [0, 200] otherwise. -+ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the -+ * frequency is not a 2.4 GHz channel, or if the frequency is not and even -+ * multiple of 5 MHz from the base frequency to the base plus 1 GHz. -+ * -+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 -+ */ -+int -+wf_mhz2channel(uint freq, uint start_factor) -+{ -+ int ch = -1; -+ uint base; -+ int offset; -+ -+ /* take the default channel start frequency */ -+ if (start_factor == 0) { -+ if (freq >= 2400 && freq <= 2500) -+ start_factor = WF_CHAN_FACTOR_2_4_G; -+ else if (freq >= 5000 && freq <= 6000) -+ start_factor = WF_CHAN_FACTOR_5_G; -+ } -+ -+ if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) -+ return 14; -+ -+ base = start_factor / 2; -+ -+ /* check that the frequency is in 1GHz range of the base */ -+ if ((freq < base) || (freq > base + 1000)) -+ return -1; -+ -+ offset = freq - base; -+ ch = offset / 5; -+ -+ /* check that frequency is a 5MHz multiple from the base */ -+ if (offset != (ch * 5)) -+ return -1; -+ -+ /* restricted channel range check for 2.4G */ -+ if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) -+ return -1; -+ -+ return ch; -+} -+ -+/* -+ * Return the center frequency in MHz of the given channel and base frequency. -+ * The channel number is interpreted relative to the given base frequency. -+ * -+ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. -+ * The base frequency is specified as (start_factor * 500 kHz). -+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G -+ * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. -+ * The channel range of [1, 14] is only checked for a start_factor of -+ * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). -+ * Odd start_factors produce channels on .5 MHz boundaries, in which case -+ * the answer is rounded down to an integral MHz. -+ * -1 is returned for an out of range channel. -+ * -+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 -+ */ -+int -+wf_channel2mhz(uint ch, uint start_factor) -+{ -+ int freq; -+ -+ if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || -+ (ch > 200)) -+ freq = -1; -+ else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) -+ freq = 2484; -+ else -+ freq = ch * 5 + start_factor / 2; -+ -+ return freq; -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h -new file mode 100644 -index 00000000..84866162 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd.h -@@ -0,0 +1,875 @@ -+/* -+ * Header file describing the internal (inter-module) DHD interfaces. -+ * -+ * Provides type definitions and function prototypes used to link the -+ * DHD OS, bus, and protocol modules. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd.h 373887 2012-12-10 21:58:02Z $ -+ */ -+ -+/**************** -+ * Common types * -+ */ -+ -+#ifndef _dhd_h_ -+#define _dhd_h_ -+ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/skbuff.h> -+#include <linux/netdevice.h> -+#include <linux/etherdevice.h> -+#include <linux/random.h> -+#include <linux/spinlock.h> -+#include <linux/ethtool.h> -+#include <asm/uaccess.h> -+#include <asm/unaligned.h> -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) -+#include <linux/wakelock.h> -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -+/* The kernel threading is sdio-specific */ -+struct task_struct; -+struct sched_param; -+int setScheduler(struct task_struct *p, int policy, struct sched_param *param); -+ -+#define ALL_INTERFACES 0xff -+ -+#include <wlioctl.h> -+#include <wlfc_proto.h> -+ -+ -+/* Forward decls */ -+struct dhd_bus; -+struct dhd_prot; -+struct dhd_info; -+ -+/* The level of bus communication with the dongle */ -+enum dhd_bus_state { -+ DHD_BUS_DOWN, /* Not ready for frame transfers */ -+ DHD_BUS_LOAD, /* Download access only (CPU reset) */ -+ DHD_BUS_DATA /* Ready for frame transfers */ -+}; -+ -+enum dhd_op_flags { -+/* Firmware requested operation mode */ -+ DHD_FLAG_STA_MODE = BIT(0), /* STA only */ -+ DHD_FLAG_HOSTAP_MODE = BIT(1), /* SOFTAP only */ -+ DHD_FLAG_P2P_MODE = BIT(2), /* P2P Only */ -+ /* STA + P2P */ -+ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), -+ DHD_FLAG_CONCURR_MULTI_CHAN_MODE = BIT(4), /* STA + P2P */ -+ /* Current P2P mode for P2P connection */ -+ DHD_FLAG_P2P_GC_MODE = BIT(5), -+ DHD_FLAG_P2P_GO_MODE = BIT(6), -+ DHD_FLAG_MBSS_MODE = BIT(7) /* MBSS in future */ -+}; -+ -+#define MANUFACTRING_FW "WLTEST" -+ -+/* max sequential rxcntl timeouts to set HANG event */ -+#ifndef MAX_CNTL_TIMEOUT -+#define MAX_CNTL_TIMEOUT 2 -+#endif -+ -+#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ -+#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ -+#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ -+ -+#ifndef POWERUP_MAX_RETRY -+#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ -+#endif -+#ifndef POWERUP_WAIT_MS -+#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ -+#endif -+ -+enum dhd_bus_wake_state { -+ WAKE_LOCK_OFF, -+ WAKE_LOCK_PRIV, -+ WAKE_LOCK_DPC, -+ WAKE_LOCK_IOCTL, -+ WAKE_LOCK_DOWNLOAD, -+ WAKE_LOCK_TMOUT, -+ WAKE_LOCK_WATCHDOG, -+ WAKE_LOCK_LINK_DOWN_TMOUT, -+ WAKE_LOCK_PNO_FIND_TMOUT, -+ WAKE_LOCK_SOFTAP_SET, -+ WAKE_LOCK_SOFTAP_STOP, -+ WAKE_LOCK_SOFTAP_START, -+ WAKE_LOCK_SOFTAP_THREAD, -+ WAKE_LOCK_MAX -+}; -+ -+enum dhd_prealloc_index { -+ DHD_PREALLOC_PROT = 0, -+ DHD_PREALLOC_RXBUF, -+ DHD_PREALLOC_DATABUF, -+#if defined(STATIC_WL_PRIV_STRUCT) -+ DHD_PREALLOC_OSL_BUF, -+ DHD_PREALLOC_WIPHY_ESCAN0 = 5, -+#else -+ DHD_PREALLOC_OSL_BUF -+#endif /* STATIC_WL_PRIV_STRUCT */ -+}; -+ -+typedef enum { -+ DHD_IF_NONE = 0, -+ DHD_IF_ADD, -+ DHD_IF_DEL, -+ DHD_IF_CHANGE, -+ DHD_IF_DELETING -+} dhd_if_state_t; -+ -+ -+#if defined(CONFIG_DHD_USE_STATIC_BUF) -+ -+uint8* dhd_os_prealloc(void *osh, int section, uint size); -+void dhd_os_prefree(void *osh, void *addr, uint size); -+#define DHD_OS_PREALLOC(osh, section, size) dhd_os_prealloc(osh, section, size) -+#define DHD_OS_PREFREE(osh, addr, size) dhd_os_prefree(osh, addr, size) -+ -+#else -+ -+#define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size) -+#define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size) -+ -+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ -+ -+/* Packet alignment for most efficient SDIO (can change based on platform) */ -+#ifndef DHD_SDALIGN -+#define DHD_SDALIGN 32 -+#endif -+ -+/* host reordering packts logic */ -+/* followed the structure to hold the reorder buffers (void **p) */ -+typedef struct reorder_info { -+ void **p; -+ uint8 flow_id; -+ uint8 cur_idx; -+ uint8 exp_idx; -+ uint8 max_idx; -+ uint8 pend_pkts; -+} reorder_info_t; -+ -+/* Common structure for module and instance linkage */ -+typedef struct dhd_pub { -+ /* Linkage ponters */ -+ osl_t *osh; /* OSL handle */ -+ struct dhd_bus *bus; /* Bus module handle */ -+ struct dhd_prot *prot; /* Protocol module handle */ -+ struct dhd_info *info; /* Info module handle */ -+ -+ /* Internal dhd items */ -+ bool up; /* Driver up/down (to OS) */ -+ bool txoff; /* Transmit flow-controlled */ -+ bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ -+ enum dhd_bus_state busstate; -+ uint hdrlen; /* Total DHD header length (proto + bus) */ -+ uint maxctl; /* Max size rxctl request from proto to bus */ -+ uint rxsz; /* Rx buffer size bus module should use */ -+ uint8 wme_dp; /* wme discard priority */ -+ -+ /* Dongle media info */ -+ bool iswl; /* Dongle-resident driver is wl */ -+ ulong drv_version; /* Version of dongle-resident driver */ -+ struct ether_addr mac; /* MAC address obtained from dongle */ -+ dngl_stats_t dstats; /* Stats for dongle-based data */ -+ -+ /* Additional stats for the bus level */ -+ ulong tx_packets; /* Data packets sent to dongle */ -+ ulong tx_multicast; /* Multicast data packets sent to dongle */ -+ ulong tx_errors; /* Errors in sending data to dongle */ -+ ulong tx_ctlpkts; /* Control packets sent to dongle */ -+ ulong tx_ctlerrs; /* Errors sending control frames to dongle */ -+ ulong rx_packets; /* Packets sent up the network interface */ -+ ulong rx_multicast; /* Multicast packets sent up the network interface */ -+ ulong rx_errors; /* Errors processing rx data packets */ -+ ulong rx_ctlpkts; /* Control frames processed from dongle */ -+ ulong rx_ctlerrs; /* Errors in processing rx control frames */ -+ ulong rx_dropped; /* Packets dropped locally (no memory) */ -+ ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ -+ ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ -+ -+ ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ -+ ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ -+ ulong fc_packets; /* Number of flow control pkts recvd */ -+ -+ /* Last error return */ -+ int bcmerror; -+ uint tickcnt; -+ -+ /* Last error from dongle */ -+ int dongle_error; -+ -+ uint8 country_code[WLC_CNTRY_BUF_SZ]; -+ -+ /* Suspend disable flag and "in suspend" flag */ -+ int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ -+ int in_suspend; /* flag set to 1 when early suspend called */ -+#ifdef PNO_SUPPORT -+ int pno_enable; /* pno status : "1" is pno enable */ -+ int pno_suspend; /* pno suspend status : "1" is pno suspended */ -+#endif /* PNO_SUPPORT */ -+ /* DTIM skip value, default 0(or 1) means wake each DTIM -+ * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) -+ */ -+ int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ -+#ifdef PKT_FILTER_SUPPORT -+ int early_suspended; /* Early suspend status */ -+ int dhcp_in_progress; /* DHCP period */ -+#endif -+ -+ /* Pkt filter defination */ -+ char * pktfilter[100]; -+ int pktfilter_count; -+ -+ wl_country_t dhd_cspec; /* Current Locale info */ -+ char eventmask[WL_EVENTING_MASK_LEN]; -+ int op_mode; /* STA, HostAPD, WFD, SoftAP */ -+ -+/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. -+ * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework -+ * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile -+ */ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -+ struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ -+ struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ -+#endif -+ -+#ifdef WLBTAMP -+ uint16 maxdatablks; -+#endif /* WLBTAMP */ -+#ifdef PROP_TXSTATUS -+ int wlfc_enabled; -+ void* wlfc_state; -+#endif -+ bool dongle_isolation; -+ bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ -+ int hang_was_sent; -+ int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ -+ int txcnt_timeout; /* counter txcnt timeout to send HANG */ -+#ifdef WLMEDIA_HTSF -+ uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ -+#endif -+ struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; -+#if defined(ARP_OFFLOAD_SUPPORT) -+ uint32 arp_version; -+#endif -+} dhd_pub_t; -+ -+ -+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -+ -+ #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); -+ #define _DHD_PM_RESUME_WAIT(a, b) do {\ -+ int retry = 0; \ -+ SMP_RD_BARRIER_DEPENDS(); \ -+ while (dhd_mmc_suspend && retry++ != b) { \ -+ SMP_RD_BARRIER_DEPENDS(); \ -+ wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ -+ } \ -+ } while (0) -+ #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) -+ #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) -+ #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) -+ #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) -+ -+ #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); -+ #define SPINWAIT_SLEEP(a, exp, us) do { \ -+ uint countdown = (us) + 9999; \ -+ while ((exp) && (countdown >= 10000)) { \ -+ wait_event_interruptible_timeout(a, FALSE, 1); \ -+ countdown -= 10000; \ -+ } \ -+ } while (0) -+ -+ #else -+ -+ #define DHD_PM_RESUME_WAIT_INIT(a) -+ #define DHD_PM_RESUME_WAIT(a) -+ #define DHD_PM_RESUME_WAIT_FOREVER(a) -+ #define DHD_PM_RESUME_RETURN_ERROR(a) -+ #define DHD_PM_RESUME_RETURN -+ -+ #define DHD_SPINWAIT_SLEEP_INIT(a) -+ #define SPINWAIT_SLEEP(a, exp, us) do { \ -+ uint countdown = (us) + 9; \ -+ while ((exp) && (countdown >= 10)) { \ -+ OSL_DELAY(10); \ -+ countdown -= 10; \ -+ } \ -+ } while (0) -+ -+ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -+#ifndef DHDTHREAD -+#undef SPINWAIT_SLEEP -+#define SPINWAIT_SLEEP(a, exp, us) SPINWAIT(exp, us) -+#endif /* DHDTHREAD */ -+#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ -+ -+unsigned long dhd_os_spin_lock(dhd_pub_t *pub); -+void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); -+ -+/* Wakelock Functions */ -+extern int dhd_os_wake_lock(dhd_pub_t *pub); -+extern int dhd_os_wake_unlock(dhd_pub_t *pub); -+extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); -+extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); -+extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); -+extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); -+extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); -+ -+inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -+ mutex_init(&dhdp->wl_softap_lock); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+} -+ -+inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -+ mutex_lock(&dhdp->wl_softap_lock); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+} -+ -+inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 -+ mutex_unlock(&dhdp->wl_softap_lock); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+} -+ -+#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) -+#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) -+#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) -+#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) -+#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) -+#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ -+ dhd_os_wake_lock_rx_timeout_enable(pub, val) -+#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ -+ dhd_os_wake_lock_ctrl_timeout_enable(pub, val) -+#define DHD_PACKET_TIMEOUT_MS 1000 -+#define DHD_EVENT_TIMEOUT_MS 1500 -+ -+/* interface operations (register, remove) should be atomic, use this lock to prevent race -+ * condition among wifi on/off and interface operation functions -+ */ -+void dhd_net_if_lock(struct net_device *dev); -+void dhd_net_if_unlock(struct net_device *dev); -+ -+typedef struct dhd_if_event { -+ uint8 ifidx; -+ uint8 action; -+ uint8 flags; -+ uint8 bssidx; -+ uint8 is_AP; -+} dhd_if_event_t; -+ -+typedef enum dhd_attach_states -+{ -+ DHD_ATTACH_STATE_INIT = 0x0, -+ DHD_ATTACH_STATE_NET_ALLOC = 0x1, -+ DHD_ATTACH_STATE_DHD_ALLOC = 0x2, -+ DHD_ATTACH_STATE_ADD_IF = 0x4, -+ DHD_ATTACH_STATE_PROT_ATTACH = 0x8, -+ DHD_ATTACH_STATE_WL_ATTACH = 0x10, -+ DHD_ATTACH_STATE_THREADS_CREATED = 0x20, -+ DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, -+ DHD_ATTACH_STATE_CFG80211 = 0x80, -+ DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, -+ DHD_ATTACH_STATE_DONE = 0x200 -+} dhd_attach_states_t; -+ -+/* Value -1 means we are unsuccessful in creating the kthread. */ -+#define DHD_PID_KT_INVALID -1 -+/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ -+#define DHD_PID_KT_TL_INVALID -2 -+ -+/* -+ * Exported from dhd OS modules (dhd_linux/dhd_ndis) -+ */ -+ -+/* To allow osl_attach/detach calls from os-independent modules */ -+osl_t *dhd_osl_attach(void *pdev, uint bustype); -+void dhd_osl_detach(osl_t *osh); -+ -+/* Indication from bus module regarding presence/insertion of dongle. -+ * Return dhd_pub_t pointer, used as handle to OS module in later calls. -+ * Returned structure should have bus and prot pointers filled in. -+ * bus_hdrlen specifies required headroom for bus module header. -+ */ -+extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); -+#if defined(WLP2P) && defined(WL_CFG80211) -+/* To allow attach/detach calls corresponding to p2p0 interface */ -+extern int dhd_attach_p2p(dhd_pub_t *); -+extern int dhd_detach_p2p(dhd_pub_t *); -+#endif /* WLP2P && WL_CFG80211 */ -+extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); -+ -+/* Indication from bus module regarding removal/absence of dongle */ -+extern void dhd_detach(dhd_pub_t *dhdp); -+extern void dhd_free(dhd_pub_t *dhdp); -+ -+/* Indication from bus module to change flow-control state */ -+extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); -+ -+extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); -+ -+/* Receive frame for delivery to OS. Callee disposes of rxp. */ -+extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); -+ -+/* Return pointer to interface name */ -+extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); -+ -+/* Request scheduling of the bus dpc */ -+extern void dhd_sched_dpc(dhd_pub_t *dhdp); -+ -+/* Notify tx completion */ -+extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); -+ -+/* OS independent layer functions */ -+extern int dhd_os_proto_block(dhd_pub_t * pub); -+extern int dhd_os_proto_unblock(dhd_pub_t * pub); -+extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); -+extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); -+extern unsigned int dhd_os_get_ioctl_resp_timeout(void); -+extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); -+extern void * dhd_os_open_image(char * filename); -+extern int dhd_os_get_image_block(char * buf, int len, void * image); -+extern void dhd_os_close_image(void * image); -+extern void dhd_os_wd_timer(void *bus, uint wdtick); -+extern void dhd_os_sdlock(dhd_pub_t * pub); -+extern void dhd_os_sdunlock(dhd_pub_t * pub); -+extern void dhd_os_sdlock_txq(dhd_pub_t * pub); -+extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); -+extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); -+extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); -+extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); -+extern void dhd_customer_gpio_wlan_ctrl(int onoff); -+extern int dhd_custom_get_mac_address(unsigned char *buf); -+extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); -+extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); -+extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); -+extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); -+extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); -+extern int net_os_send_hang_message(struct net_device *dev); -+extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); -+ -+#ifdef PNO_SUPPORT -+extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); -+extern int dhd_pno_clean(dhd_pub_t *dhd); -+extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, -+ ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -+extern int dhd_pno_get_status(dhd_pub_t *dhd); -+extern int dhd_dev_pno_reset(struct net_device *dev); -+extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, -+ int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -+extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); -+extern int dhd_dev_get_pno_status(struct net_device *dev); -+#endif /* PNO_SUPPORT */ -+ -+#ifdef PKT_FILTER_SUPPORT -+#define DHD_UNICAST_FILTER_NUM 0 -+#define DHD_BROADCAST_FILTER_NUM 1 -+#define DHD_MULTICAST4_FILTER_NUM 2 -+#define DHD_MULTICAST6_FILTER_NUM 3 -+#define DHD_MDNS_FILTER_NUM 4 -+extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); -+extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); -+extern int net_os_enable_packet_filter(struct net_device *dev, int val); -+extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); -+#endif /* PKT_FILTER_SUPPORT */ -+ -+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); -+extern bool dhd_support_sta_mode(dhd_pub_t *dhd); -+ -+#ifdef DHD_DEBUG -+extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); -+#endif /* DHD_DEBUG */ -+#if defined(OOB_INTR_ONLY) -+extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); -+#endif /* defined(OOB_INTR_ONLY) */ -+extern void dhd_os_sdtxlock(dhd_pub_t * pub); -+extern void dhd_os_sdtxunlock(dhd_pub_t * pub); -+ -+typedef struct { -+ uint32 limit; /* Expiration time (usec) */ -+ uint32 increment; /* Current expiration increment (usec) */ -+ uint32 elapsed; /* Current elapsed time (usec) */ -+ uint32 tick; /* O/S tick time (usec) */ -+} dhd_timeout_t; -+ -+extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); -+extern int dhd_timeout_expired(dhd_timeout_t *tmo); -+ -+extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); -+extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); -+extern struct net_device * dhd_idx2net(void *pub, int ifidx); -+extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, -+ wl_event_msg_t *, void **data_ptr); -+extern void wl_event_to_host_order(wl_event_msg_t * evt); -+ -+extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); -+extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, -+ int ifindex); -+ -+extern void dhd_common_init(osl_t *osh); -+ -+extern int dhd_do_driver_init(struct net_device *net); -+extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, -+ char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); -+extern void dhd_del_if(struct dhd_info *dhd, int ifidx); -+ -+extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); -+extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); -+ -+extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); -+extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); -+ -+ -+/* Send packet to dongle via data channel */ -+extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); -+ -+/* send up locally generated event */ -+extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -+/* Send event to host */ -+extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -+extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); -+extern uint dhd_bus_status(dhd_pub_t *dhdp); -+extern int dhd_bus_start(dhd_pub_t *dhdp); -+extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); -+extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); -+extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); -+extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); -+extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); -+extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); -+ -+#if defined(KEEP_ALIVE) -+extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -+#endif /* KEEP_ALIVE */ -+ -+extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); -+ -+typedef enum cust_gpio_modes { -+ WLAN_RESET_ON, -+ WLAN_RESET_OFF, -+ WLAN_POWER_ON, -+ WLAN_POWER_OFF -+} cust_gpio_modes_t; -+ -+extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); -+extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); -+/* -+ * Insmod parameters for debug/test -+ */ -+ -+/* Watchdog timer interval */ -+extern uint dhd_watchdog_ms; -+ -+#if defined(DHD_DEBUG) -+/* Console output poll interval */ -+extern uint dhd_console_ms; -+extern uint wl_msg_level; -+#endif /* defined(DHD_DEBUG) */ -+ -+extern uint dhd_slpauto; -+ -+/* Use interrupts */ -+extern uint dhd_intr; -+ -+/* Use polling */ -+extern uint dhd_poll; -+ -+/* ARP offload agent mode */ -+extern uint dhd_arp_mode; -+ -+/* ARP offload enable */ -+extern uint dhd_arp_enable; -+ -+/* Pkt filte enable control */ -+extern uint dhd_pkt_filter_enable; -+ -+/* Pkt filter init setup */ -+extern uint dhd_pkt_filter_init; -+ -+/* Pkt filter mode control */ -+extern uint dhd_master_mode; -+ -+/* Roaming mode control */ -+extern uint dhd_roam_disable; -+ -+/* Roaming mode control */ -+extern uint dhd_radio_up; -+ -+/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ -+extern int dhd_idletime; -+#ifdef DHD_USE_IDLECOUNT -+#define DHD_IDLETIME_TICKS 5 -+#else -+#define DHD_IDLETIME_TICKS 1 -+#endif /* DHD_USE_IDLECOUNT */ -+ -+/* SDIO Drive Strength */ -+extern uint dhd_sdiod_drive_strength; -+ -+/* Override to force tx queueing all the time */ -+extern uint dhd_force_tx_queueing; -+/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -+#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ -+#ifndef CUSTOM_KEEP_ALIVE_SETTING -+#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE -+#endif /* DEFAULT_KEEP_ALIVE_VALUE */ -+ -+#define NULL_PKT_STR "null_pkt" -+ -+/* hooks for custom glom setting option via Makefile */ -+#define DEFAULT_GLOM_VALUE -1 -+#ifndef CUSTOM_GLOM_SETTING -+#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE -+#endif -+ -+/* hooks for custom Roaming Trigger setting via Makefile */ -+#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ -+#define DEFAULT_ROAM_TRIGGER_SETTING -1 -+#ifndef CUSTOM_ROAM_TRIGGER_SETTING -+#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE -+#endif -+ -+/* hooks for custom Roaming Romaing setting via Makefile */ -+#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ -+#define DEFAULT_ROAM_DELTA_SETTING -1 -+#ifndef CUSTOM_ROAM_DELTA_SETTING -+#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE -+#endif -+ -+/* hooks for custom PNO Event wake lock to guarantee enough time -+ for the Platform to detect Event before system suspended -+*/ -+#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ -+#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME -+#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME -+#endif -+ -+/* hooks for custom dhd_dpc_prio setting option via Makefile */ -+#define DEFAULT_DHP_DPC_PRIO 1 -+#ifndef CUSTOM_DPC_PRIO_SETTING -+#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO -+#endif -+ -+#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 -+#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM -+#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM -+#endif -+ -+#define MAX_DTIM_SKIP_BEACON_ITERVAL 100 /* max allowed associated AP beacon for dtim skip */ -+ -+#ifdef SDTEST -+/* Echo packet generator (SDIO), pkts/s */ -+extern uint dhd_pktgen; -+ -+/* Echo packet len (0 => sawtooth, max 1800) */ -+extern uint dhd_pktgen_len; -+#define MAX_PKTGEN_LEN 1800 -+#endif -+ -+ -+/* optionally set by a module_param_string() */ -+#define MOD_PARAM_PATHLEN 2048 -+extern char fw_path[MOD_PARAM_PATHLEN]; -+extern char nv_path[MOD_PARAM_PATHLEN]; -+ -+#define MOD_PARAM_INFOLEN 512 -+ -+#ifdef SOFTAP -+extern char fw_path2[MOD_PARAM_PATHLEN]; -+#endif -+ -+/* Flag to indicate if we should download firmware on driver load */ -+extern uint dhd_download_fw_on_driverload; -+ -+ -+/* For supporting multiple interfaces */ -+#define DHD_MAX_IFS 16 -+#define DHD_DEL_IF -0xe -+#define DHD_BAD_IF -0xf -+#define WL_AUTO_ROAM_TRIGGER -75 -+ -+#ifdef PROP_TXSTATUS -+/* Please be mindful that total pkttag space is 32 octets only */ -+typedef struct dhd_pkttag { -+ /* -+ b[11 ] - 1 = this packet was sent in response to one time packet request, -+ do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. -+ b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] -+ b[9 ] - 1 = packet is host->firmware (transmit direction) -+ - 0 = packet received from firmware (firmware->host) -+ b[8 ] - 1 = packet was sent due to credit_request (pspoll), -+ packet does not count against FIFO credit. -+ - 0 = normal transaction, packet counts against FIFO credit -+ b[7 ] - 1 = AP, 0 = STA -+ b[6:4] - AC FIFO number -+ b[3:0] - interface index -+ */ -+ uint16 if_flags; -+ /* destination MAC address for this packet so that not every -+ module needs to open the packet to find this -+ */ -+ uint8 dstn_ether[ETHER_ADDR_LEN]; -+ /* -+ This 32-bit goes from host to device for every packet. -+ */ -+ uint32 htod_tag; -+ /* bus specific stuff */ -+ union { -+ struct { -+ void* stuff; -+ uint32 thing1; -+ uint32 thing2; -+ } sd; -+ struct { -+ void* bus; -+ void* urb; -+ } usb; -+ } bus_specific; -+} dhd_pkttag_t; -+ -+#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) -+#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) -+ -+#define DHD_PKTTAG_IFMASK 0xf -+#define DHD_PKTTAG_IFTYPE_MASK 0x1 -+#define DHD_PKTTAG_IFTYPE_SHIFT 7 -+#define DHD_PKTTAG_FIFO_MASK 0x7 -+#define DHD_PKTTAG_FIFO_SHIFT 4 -+ -+#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 -+#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 -+ -+#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 -+#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 -+ -+#define DHD_PKTTAG_PKTDIR_MASK 0x1 -+#define DHD_PKTTAG_PKTDIR_SHIFT 9 -+ -+#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 -+#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 -+ -+#define DHD_PKTTAG_INVALID_FIFOID 0x7 -+ -+#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ -+ (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ -+ (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) -+#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ -+ DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) -+ -+#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ -+ (((dhd_pkttag_t*)(tag))->if_flags & ~DHD_PKTTAG_IFMASK) | ((if) & DHD_PKTTAG_IFMASK) -+#define DHD_PKTTAG_IF(tag) (((dhd_pkttag_t*)(tag))->if_flags & DHD_PKTTAG_IFMASK) -+ -+#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ -+ (((dhd_pkttag_t*)(tag))->if_flags & \ -+ ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ -+ (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) -+#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ -+ DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) -+ -+#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ -+ (((dhd_pkttag_t*)(tag))->if_flags & \ -+ ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ -+ (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) -+#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ -+ DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) -+ -+#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ -+ (((dhd_pkttag_t*)(tag))->if_flags & \ -+ ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ -+ (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) -+#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ -+ DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) -+ -+#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ -+ (((dhd_pkttag_t*)(tag))->if_flags & \ -+ ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ -+ (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) -+#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ -+ DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) -+ -+#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ -+ (((dhd_pkttag_t*)(tag))->if_flags & \ -+ ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ -+ (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) -+#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ -+ DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) -+ -+#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ -+ (dstn_MAC_ea), ETHER_ADDR_LEN) -+#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether -+ -+typedef int (*f_commitpkt_t)(void* ctx, void* p); -+ -+#ifdef PROP_TXSTATUS_DEBUG -+#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) -+#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) -+#else -+#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) -+#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) -+#endif -+ -+#endif /* PROP_TXSTATUS */ -+ -+extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); -+extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); -+ -+#define IFLOCK_INIT(lock) *lock = 0 -+#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ -+ NdisStallExecution(1); -+#define IFUNLOCK(lock) InterlockedExchange((lock), 0) -+#define IFLOCK_FREE(lock) -+ -+#ifdef PNO_SUPPORT -+extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); -+extern int dhd_pnoenable(dhd_pub_t *dhd, int pfn_enabled); -+extern int dhd_pno_clean(dhd_pub_t *dhd); -+extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, -+ ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -+extern int dhd_pno_get_status(dhd_pub_t *dhd); -+extern int dhd_pno_set_add(dhd_pub_t *dhd, wl_pfn_t *netinfo, int nssid, ushort scan_fr, -+ ushort slowscan_fr, uint8 pno_repeat, uint8 pno_freq_expo_max, int16 flags); -+extern int dhd_pno_cfg(dhd_pub_t *dhd, wl_pfn_cfg_t *pcfg); -+extern int dhd_pno_suspend(dhd_pub_t *dhd, int pfn_suspend); -+#endif /* PNO_SUPPORT */ -+#ifdef ARP_OFFLOAD_SUPPORT -+#define MAX_IPV4_ENTRIES 8 -+void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); -+void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); -+ -+/* dhd_commn arp offload wrapers */ -+void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); -+void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); -+int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); -+void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+#endif /* _dhd_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.c b/drivers/net/wireless/bcmdhd/dhd_bta.c -new file mode 100644 -index 00000000..15c605ea ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_bta.c -@@ -0,0 +1,338 @@ -+/* -+ * BT-AMP support routines -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_bta.c 303834 2011-12-20 06:17:39Z $ -+ */ -+#ifndef WLBTAMP -+#error "WLBTAMP is not defined" -+#endif /* WLBTAMP */ -+ -+#include <typedefs.h> -+#include <osl.h> -+#include <bcmcdc.h> -+#include <bcmutils.h> -+#include <bcmendian.h> -+#include <proto/802.11.h> -+#include <proto/802.11_bta.h> -+#include <proto/bt_amp_hci.h> -+#include <dngl_stats.h> -+#include <dhd.h> -+#include <dhd_bus.h> -+#include <dhd_proto.h> -+#include <dhdioctl.h> -+#include <dhd_dbg.h> -+ -+#include <dhd_bta.h> -+ -+ -+#ifdef SEND_HCI_CMD_VIA_IOCTL -+#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE -+ -+/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ -+int -+dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -+{ -+ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; -+ uint8 buf[BTA_HCI_CMD_MAX_LEN + 16]; -+ uint len = sizeof(buf); -+ wl_ioctl_t ioc; -+ -+ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) -+ return BCME_BADLEN; -+ -+ if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) -+ return BCME_BADLEN; -+ -+ len = bcm_mkiovar("HCI_cmd", -+ (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len); -+ -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ -+ ioc.cmd = WLC_SET_VAR; -+ ioc.buf = buf; -+ ioc.len = len; -+ ioc.set = TRUE; -+ -+ return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len); -+} -+#else /* !SEND_HCI_CMD_VIA_IOCTL */ -+ -+static void -+dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) -+{ -+ int prec; -+ struct pktq *q; -+ uint count = 0; -+ -+ q = dhd_bus_txq(pub->bus); -+ if (q == NULL) -+ return; -+ -+ DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); -+ -+ dhd_os_sdlock_txq(pub); -+ -+ /* Walk through the txq and toss all HCI ACL data packets */ -+ PKTQ_PREC_ITER(q, prec) { -+ void *head_pkt = NULL; -+ -+ while (pktq_ppeek(q, prec) != head_pkt) { -+ void *pkt = pktq_pdeq(q, prec); -+ int ifidx; -+ -+ PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); -+ dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); -+ -+ if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { -+ struct ether_header *eh = -+ (struct ether_header *)PKTDATA(pub->osh, pkt); -+ -+ if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { -+ struct dot11_llc_snap_header *lsh = -+ (struct dot11_llc_snap_header *)&eh[1]; -+ -+ if (bcmp(lsh, BT_SIG_SNAP_MPROT, -+ DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && -+ ntoh16(lsh->type) == BTA_PROT_L2CAP) { -+ amp_hci_ACL_data_t *ACL_data = -+ (amp_hci_ACL_data_t *)&lsh[1]; -+ uint16 handle = ltoh16(ACL_data->handle); -+ -+ if (HCI_ACL_DATA_HANDLE(handle) == llh) { -+ PKTFREE(pub->osh, pkt, TRUE); -+ count ++; -+ continue; -+ } -+ } -+ } -+ } -+ -+ dhd_prot_hdrpush(pub, ifidx, pkt); -+ PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); -+ -+ if (head_pkt == NULL) -+ head_pkt = pkt; -+ pktq_penq(q, prec, pkt); -+ } -+ } -+ -+ dhd_os_sdunlock_txq(pub); -+ -+ DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); -+} -+ -+/* Handle HCI cmd locally. -+ * Return 0: continue to send the cmd across SDIO -+ * < 0: stop, fail -+ * > 0: stop, succuess -+ */ -+static int -+_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) -+{ -+ int status = 0; -+ -+ switch (ltoh16_ua((uint8 *)&cmd->opcode)) { -+ case HCI_Enhanced_Flush: { -+ eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; -+ dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); -+ break; -+ } -+ default: -+ break; -+ } -+ -+ return status; -+} -+ -+/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ -+int -+dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -+{ -+ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; -+ struct ether_header *eh; -+ struct dot11_llc_snap_header *lsh; -+ osl_t *osh = pub->osh; -+ uint len; -+ void *p; -+ int status; -+ -+ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { -+ DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len)); -+ return BCME_BADLEN; -+ } -+ -+ if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { -+ DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", -+ len, cmd_len)); -+ /* return BCME_BADLEN; */ -+ } -+ -+ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); -+ if (p == NULL) { -+ DHD_ERROR(("dhd_bta_docmd: out of memory\n")); -+ return BCME_NOMEM; -+ } -+ -+ -+ /* intercept and handle the HCI cmd locally */ -+ if ((status = _dhd_bta_docmd(pub, cmd)) > 0) -+ return 0; -+ else if (status < 0) -+ return status; -+ -+ /* copy in HCI cmd */ -+ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); -+ bcopy(cmd, PKTDATA(osh, p), len); -+ -+ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ -+ PKTPUSH(osh, p, RFC1042_HDR_LEN); -+ eh = (struct ether_header *)PKTDATA(osh, p); -+ bzero(eh->ether_dhost, ETHER_ADDR_LEN); -+ ETHER_SET_LOCALADDR(eh->ether_dhost); -+ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); -+ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); -+ lsh = (struct dot11_llc_snap_header *)&eh[1]; -+ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); -+ lsh->type = 0; -+ -+ return dhd_sendpkt(pub, 0, p); -+} -+#endif /* !SEND_HCI_CMD_VIA_IOCTL */ -+ -+/* Send HCI ACL data to dongle via data channel */ -+int -+dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) -+{ -+ amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; -+ struct ether_header *eh; -+ struct dot11_llc_snap_header *lsh; -+ osl_t *osh = pub->osh; -+ uint len; -+ void *p; -+ -+ if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { -+ DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len)); -+ return BCME_BADLEN; -+ } -+ -+ if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { -+ DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", -+ len, data_len)); -+ /* return BCME_BADLEN; */ -+ } -+ -+ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); -+ if (p == NULL) { -+ DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n")); -+ return BCME_NOMEM; -+ } -+ -+ -+ /* copy in HCI ACL data header and HCI ACL data */ -+ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); -+ bcopy(data, PKTDATA(osh, p), len); -+ -+ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ -+ PKTPUSH(osh, p, RFC1042_HDR_LEN); -+ eh = (struct ether_header *)PKTDATA(osh, p); -+ bzero(eh->ether_dhost, ETHER_ADDR_LEN); -+ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); -+ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); -+ lsh = (struct dot11_llc_snap_header *)&eh[1]; -+ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); -+ lsh->type = HTON16(BTA_PROT_L2CAP); -+ -+ return dhd_sendpkt(pub, 0, p); -+} -+ -+/* txcomplete callback */ -+void -+dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) -+{ -+ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); -+ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); -+ uint16 handle = ltoh16(ACL_data->handle); -+ uint16 llh = HCI_ACL_DATA_HANDLE(handle); -+ -+ wl_event_msg_t event; -+ uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; -+ amp_hci_event_t *evt; -+ num_completed_data_blocks_evt_parms_t *parms; -+ -+ uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); -+ -+ /* update the event struct */ -+ memset(&event, 0, sizeof(event)); -+ event.version = hton16(BCM_EVENT_MSG_VERSION); -+ event.event_type = hton32(WLC_E_BTA_HCI_EVENT); -+ event.status = 0; -+ event.reason = 0; -+ event.auth_type = 0; -+ event.datalen = hton32(len); -+ event.flags = 0; -+ -+ /* generate Number of Completed Blocks event */ -+ evt = (amp_hci_event_t *)data; -+ evt->ecode = HCI_Number_of_Completed_Data_Blocks; -+ evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); -+ -+ parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; -+ htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); -+ parms->num_handles = 1; -+ htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); -+ parms->completed[0].pkts = 1; -+ parms->completed[0].blocks = 1; -+ -+ dhd_sendup_event_common(dhdp, &event, data); -+} -+ -+/* event callback */ -+void -+dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) -+{ -+ amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; -+ -+ switch (evt->ecode) { -+ case HCI_Command_Complete: { -+ cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; -+ switch (ltoh16_ua((uint8 *)&parms->opcode)) { -+ case HCI_Read_Data_Block_Size: { -+ read_data_block_size_evt_parms_t *parms2 = -+ (read_data_block_size_evt_parms_t *)parms->parms; -+ dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); -+ break; -+ } -+ } -+ break; -+ } -+ -+ case HCI_Flush_Occurred: { -+ flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; -+ dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); -+ break; -+ } -+ default: -+ break; -+ } -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.h b/drivers/net/wireless/bcmdhd/dhd_bta.h -new file mode 100644 -index 00000000..0337f15d ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_bta.h -@@ -0,0 +1,39 @@ -+/* -+ * BT-AMP support routines -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ -+ */ -+#ifndef __dhd_bta_h__ -+#define __dhd_bta_h__ -+ -+struct dhd_pub; -+ -+extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); -+ -+extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); -+ -+extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); -+extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); -+ -+ -+#endif /* __dhd_bta_h__ */ -diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h -new file mode 100644 -index 00000000..fcb4bbd6 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_bus.h -@@ -0,0 +1,111 @@ -+/* -+ * Header file describing the internal (inter-module) DHD interfaces. -+ * -+ * Provides type definitions and function prototypes used to link the -+ * DHD OS, bus, and protocol modules. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_bus.h 347614 2012-07-27 10:24:51Z $ -+ */ -+ -+#ifndef _dhd_bus_h_ -+#define _dhd_bus_h_ -+ -+/* -+ * Exported from dhd bus module (dhd_usb, dhd_sdio) -+ */ -+ -+/* Indicate (dis)interest in finding dongles. */ -+extern int dhd_bus_register(void); -+extern void dhd_bus_unregister(void); -+ -+/* Download firmware image and nvram image */ -+extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, -+ char *fw_path, char *nv_path); -+ -+/* Stop bus module: clear pending frames, disable data flow */ -+extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); -+ -+/* Initialize bus module: prepare for communication w/dongle */ -+extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); -+ -+/* Get the Bus Idle Time */ -+extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); -+ -+/* Set the Bus Idle Time */ -+extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); -+ -+/* Send a data frame to the dongle. Callee disposes of txp. */ -+extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); -+ -+/* Send/receive a control message to/from the dongle. -+ * Expects caller to enforce a single outstanding transaction. -+ */ -+extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); -+extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); -+ -+/* Watchdog timer function */ -+extern bool dhd_bus_watchdog(dhd_pub_t *dhd); -+extern void dhd_disable_intr(dhd_pub_t *dhd); -+ -+#if defined(DHD_DEBUG) -+/* Device console input function */ -+extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); -+#endif /* defined(DHD_DEBUG) */ -+ -+/* Deferred processing for the bus, return TRUE requests reschedule */ -+extern bool dhd_bus_dpc(struct dhd_bus *bus); -+extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); -+ -+ -+/* Check for and handle local prot-specific iovar commands */ -+extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, -+ void *params, int plen, void *arg, int len, bool set); -+ -+/* Add bus dump output to a buffer */ -+extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); -+ -+/* Clear any bus counters */ -+extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); -+ -+/* return the dongle chipid */ -+extern uint dhd_bus_chip(struct dhd_bus *bus); -+ -+/* Set user-specified nvram parameters. */ -+extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); -+ -+extern void *dhd_bus_pub(struct dhd_bus *bus); -+extern void *dhd_bus_txq(struct dhd_bus *bus); -+extern uint dhd_bus_hdrlen(struct dhd_bus *bus); -+ -+ -+#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ -+ (_bus)->dhd->busstate = DHD_BUS_DOWN; \ -+} while (0) -+ -+/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -+extern int dhd_bus_reg_sdio_notify(void* semaphore); -+extern void dhd_bus_unreg_sdio_notify(void); -+ -+extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); -+ -+#endif /* _dhd_bus_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c -new file mode 100644 -index 00000000..b51dbc6d ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c -@@ -0,0 +1,3189 @@ -+/* -+ * DHD Protocol Module for CDC and BDC. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_cdc.c 368762 2012-11-14 21:59:17Z $ -+ * -+ * BDC is like CDC, except it includes a header for data packets to convey -+ * packet priority over the bus, and flags (e.g. to indicate checksum status -+ * for dongle offload.) -+ */ -+ -+#include <typedefs.h> -+#include <osl.h> -+ -+#include <bcmutils.h> -+#include <bcmcdc.h> -+#include <bcmendian.h> -+ -+#include <dngl_stats.h> -+#include <dhd.h> -+#include <dhd_proto.h> -+#include <dhd_bus.h> -+#include <dhd_dbg.h> -+ -+ -+#ifdef PROP_TXSTATUS -+#include <wlfc_proto.h> -+#include <dhd_wlfc.h> -+#endif -+ -+ -+#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -+#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE -+ * defined in dhd_sdio.c (amount of header tha might be added) -+ * plus any space that might be needed for alignment padding. -+ */ -+#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for -+ * round off at the end of buffer -+ */ -+ -+#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ -+ -+#ifdef PROP_TXSTATUS -+typedef struct dhd_wlfc_commit_info { -+ uint8 needs_hdr; -+ uint8 ac_fifo_credit_spent; -+ ewlfc_packet_state_t pkt_type; -+ wlfc_mac_descriptor_t* mac_entry; -+ void* p; -+} dhd_wlfc_commit_info_t; -+#endif /* PROP_TXSTATUS */ -+ -+ -+typedef struct dhd_prot { -+ uint16 reqid; -+ uint8 pending; -+ uint32 lastcmd; -+ uint8 bus_header[BUS_HEADER_LEN]; -+ cdc_ioctl_t msg; -+ unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; -+} dhd_prot_t; -+ -+ -+static int -+dhdcdc_msg(dhd_pub_t *dhd) -+{ -+ int err = 0; -+ dhd_prot_t *prot = dhd->prot; -+ int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ DHD_OS_WAKE_LOCK(dhd); -+ -+ /* NOTE : cdc->msg.len holds the desired length of the buffer to be -+ * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area -+ * is actually sent to the dongle -+ */ -+ if (len > CDC_MAX_MSG_SIZE) -+ len = CDC_MAX_MSG_SIZE; -+ -+ /* Send request */ -+ err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); -+ -+ DHD_OS_WAKE_UNLOCK(dhd); -+ return err; -+} -+ -+static int -+dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) -+{ -+ int ret; -+ int cdc_len = len + sizeof(cdc_ioctl_t); -+ dhd_prot_t *prot = dhd->prot; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ do { -+ ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); -+ if (ret < 0) -+ break; -+ } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); -+ -+ return ret; -+} -+ -+static int -+dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -+{ -+ dhd_prot_t *prot = dhd->prot; -+ cdc_ioctl_t *msg = &prot->msg; -+ void *info; -+ int ret = 0, retries = 0; -+ uint32 id, flags = 0; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); -+ -+ -+ /* Respond "bcmerror" and "bcmerrorstr" with local cache */ -+ if (cmd == WLC_GET_VAR && buf) -+ { -+ if (!strcmp((char *)buf, "bcmerrorstr")) -+ { -+ strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); -+ goto done; -+ } -+ else if (!strcmp((char *)buf, "bcmerror")) -+ { -+ *(int *)buf = dhd->dongle_error; -+ goto done; -+ } -+ } -+ -+ memset(msg, 0, sizeof(cdc_ioctl_t)); -+ -+ msg->cmd = htol32(cmd); -+ msg->len = htol32(len); -+ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); -+ CDC_SET_IF_IDX(msg, ifidx); -+ /* add additional action bits */ -+ action &= WL_IOCTL_ACTION_MASK; -+ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); -+ msg->flags = htol32(msg->flags); -+ -+ if (buf) -+ memcpy(prot->buf, buf, len); -+ -+ if ((ret = dhdcdc_msg(dhd)) < 0) { -+ if (!dhd->hang_was_sent) -+ DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); -+ goto done; -+ } -+ -+retry: -+ /* wait for interrupt and get first fragment */ -+ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) -+ goto done; -+ -+ flags = ltoh32(msg->flags); -+ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; -+ -+ if ((id < prot->reqid) && (++retries < RETRIES)) -+ goto retry; -+ if (id != prot->reqid) { -+ DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", -+ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); -+ ret = -EINVAL; -+ goto done; -+ } -+ -+ /* Check info buffer */ -+ info = (void*)&msg[1]; -+ -+ /* Copy info buffer */ -+ if (buf) -+ { -+ if (ret < (int)len) -+ len = ret; -+ memcpy(buf, info, len); -+ } -+ -+ /* Check the ERROR flag */ -+ if (flags & CDCF_IOC_ERROR) -+ { -+ ret = ltoh32(msg->status); -+ /* Cache error from dongle */ -+ dhd->dongle_error = ret; -+ } -+ -+done: -+ return ret; -+} -+ -+static int -+dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -+{ -+ dhd_prot_t *prot = dhd->prot; -+ cdc_ioctl_t *msg = &prot->msg; -+ int ret = 0; -+ uint32 flags, id; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); -+ -+ if (dhd->busstate == DHD_BUS_DOWN) { -+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); -+ return -EIO; -+ } -+ -+ /* don't talk to the dongle if fw is about to be reloaded */ -+ if (dhd->hang_was_sent) { -+ DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", -+ __FUNCTION__)); -+ return -EIO; -+ } -+ -+ memset(msg, 0, sizeof(cdc_ioctl_t)); -+ -+ msg->cmd = htol32(cmd); -+ msg->len = htol32(len); -+ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); -+ CDC_SET_IF_IDX(msg, ifidx); -+ /* add additional action bits */ -+ action &= WL_IOCTL_ACTION_MASK; -+ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; -+ msg->flags = htol32(msg->flags); -+ -+ if (buf) -+ memcpy(prot->buf, buf, len); -+ -+ if ((ret = dhdcdc_msg(dhd)) < 0) { -+ DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); -+ goto done; -+ } -+ -+ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) -+ goto done; -+ -+ flags = ltoh32(msg->flags); -+ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; -+ -+ if (id != prot->reqid) { -+ DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", -+ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); -+ ret = -EINVAL; -+ goto done; -+ } -+ -+ /* Check the ERROR flag */ -+ if (flags & CDCF_IOC_ERROR) -+ { -+ ret = ltoh32(msg->status); -+ /* Cache error from dongle */ -+ dhd->dongle_error = ret; -+ } -+ -+done: -+ return ret; -+} -+ -+ -+int -+dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) -+{ -+ dhd_prot_t *prot = dhd->prot; -+ int ret = -1; -+ uint8 action; -+#if defined(NDIS630) -+ bool acquired = FALSE; -+#endif -+ -+ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { -+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); -+ goto done; -+ } -+#if defined(NDIS630) -+ if (dhd_os_proto_block(dhd)) -+ { -+ acquired = TRUE; -+ } -+ else -+ { -+ /* attempt to acquire protocol mutex timed out. */ -+ ret = -1; -+ return ret; -+ } -+#endif /* NDIS630 */ -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ ASSERT(len <= WLC_IOCTL_MAXLEN); -+ -+ if (len > WLC_IOCTL_MAXLEN) -+ goto done; -+ -+ if (prot->pending == TRUE) { -+ DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", -+ ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, -+ (unsigned long)prot->lastcmd)); -+ if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { -+ DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); -+ } -+ goto done; -+ } -+ -+ prot->pending = TRUE; -+ prot->lastcmd = ioc->cmd; -+ action = ioc->set; -+ if (action & WL_IOCTL_ACTION_SET) -+ ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); -+ else { -+ ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); -+ if (ret > 0) -+ ioc->used = ret - sizeof(cdc_ioctl_t); -+ } -+ -+ /* Too many programs assume ioctl() returns 0 on success */ -+ if (ret >= 0) -+ ret = 0; -+ else { -+ cdc_ioctl_t *msg = &prot->msg; -+ ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ -+ } -+ -+ /* Intercept the wme_dp ioctl here */ -+ if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { -+ int slen, val = 0; -+ -+ slen = strlen("wme_dp") + 1; -+ if (len >= (int)(slen + sizeof(int))) -+ bcopy(((char *)buf + slen), &val, sizeof(int)); -+ dhd->wme_dp = (uint8) ltoh32(val); -+ } -+ -+ prot->pending = FALSE; -+ -+done: -+#if defined(NDIS630) -+ if (acquired) -+ dhd_os_proto_unblock(dhd); -+#endif -+ return ret; -+} -+ -+int -+dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, -+ void *params, int plen, void *arg, int len, bool set) -+{ -+ return BCME_UNSUPPORTED; -+} -+ -+#ifdef PROP_TXSTATUS -+void -+dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -+{ -+ int i; -+ uint8* ea; -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhdp->wlfc_state; -+ wlfc_hanger_t* h; -+ wlfc_mac_descriptor_t* mac_table; -+ wlfc_mac_descriptor_t* interfaces; -+ char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; -+ -+ if (wlfc == NULL) { -+ bcm_bprintf(strbuf, "wlfc not initialized yet\n"); -+ return; -+ } -+ h = (wlfc_hanger_t*)wlfc->hanger; -+ if (h == NULL) { -+ bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); -+ } -+ -+ mac_table = wlfc->destination_entries.nodes; -+ interfaces = wlfc->destination_entries.interfaces; -+ bcm_bprintf(strbuf, "---- wlfc stats ----\n"); -+ if (h) { -+ bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," -+ "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", -+ h->pushed, -+ h->popped, -+ h->failed_to_push, -+ h->failed_to_pop, -+ h->failed_slotfind, -+ (h->pushed - h->popped)); -+ } -+ -+ bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " -+ "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n", -+ wlfc->stats.tlv_parse_failed, -+ wlfc->stats.credit_request_failed, -+ wlfc->stats.mac_update_failed, -+ wlfc->stats.psmode_update_failed, -+ wlfc->stats.delayq_full_error, -+ wlfc->stats.sendq_full_error, -+ wlfc->stats.rollback_failed); -+ -+ bcm_bprintf(strbuf, "SENDQ (len,credit,sent) " -+ "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n", -+ wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0], -+ wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1], -+ wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2], -+ wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3], -+ wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]); -+ -+#ifdef PROP_TXSTATUS_DEBUG -+ bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n", -+ wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1], -+ wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3], -+ wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]); -+#endif -+ -+ bcm_bprintf(strbuf, "\n"); -+ for (i = 0; i < WLFC_MAX_IFNUM; i++) { -+ if (interfaces[i].occupied) { -+ char* iftype_desc; -+ -+ if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) -+ iftype_desc = "<Unknown"; -+ else -+ iftype_desc = iftypes[interfaces[i].iftype]; -+ -+ ea = interfaces[i].ea; -+ bcm_bprintf(strbuf, "INTERFACE[%d].ea = " -+ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s" -+ "netif_flow_control:%s\n", i, -+ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], -+ interfaces[i].interface_id, -+ iftype_desc, ((wlfc->hostif_flow_state[i] == OFF) -+ ? " OFF":" ON")); -+ -+ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" -+ "= (%d,%s,%d)\n", -+ i, -+ interfaces[i].psq.len, -+ ((interfaces[i].state == -+ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), -+ interfaces[i].requested_credit); -+ -+ bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" -+ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " -+ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", -+ i, -+ interfaces[i].psq.q[0].len, -+ interfaces[i].psq.q[1].len, -+ interfaces[i].psq.q[2].len, -+ interfaces[i].psq.q[3].len, -+ interfaces[i].psq.q[4].len, -+ interfaces[i].psq.q[5].len, -+ interfaces[i].psq.q[6].len, -+ interfaces[i].psq.q[7].len); -+ } -+ } -+ -+ bcm_bprintf(strbuf, "\n"); -+ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { -+ if (mac_table[i].occupied) { -+ ea = mac_table[i].ea; -+ bcm_bprintf(strbuf, "MAC_table[%d].ea = " -+ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, -+ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], -+ mac_table[i].interface_id); -+ -+ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" -+ "= (%d,%s,%d)\n", -+ i, -+ mac_table[i].psq.len, -+ ((mac_table[i].state == -+ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), -+ mac_table[i].requested_credit); -+#ifdef PROP_TXSTATUS_DEBUG -+ bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", -+ i, mac_table[i].opened_ct, mac_table[i].closed_ct); -+#endif -+ bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" -+ "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " -+ "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", -+ i, -+ mac_table[i].psq.q[0].len, -+ mac_table[i].psq.q[1].len, -+ mac_table[i].psq.q[2].len, -+ mac_table[i].psq.q[3].len, -+ mac_table[i].psq.q[4].len, -+ mac_table[i].psq.q[5].len, -+ mac_table[i].psq.q[6].len, -+ mac_table[i].psq.q[7].len); -+ } -+ } -+ -+#ifdef PROP_TXSTATUS_DEBUG -+ { -+ int avg; -+ int moving_avg = 0; -+ int moving_samples; -+ -+ if (wlfc->stats.latency_sample_count) { -+ moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); -+ -+ for (i = 0; i < moving_samples; i++) -+ moving_avg += wlfc->stats.deltas[i]; -+ moving_avg /= moving_samples; -+ -+ avg = (100 * wlfc->stats.total_status_latency) / -+ wlfc->stats.latency_sample_count; -+ bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " -+ "(%d.%d, %03d, %03d)\n", -+ moving_samples, avg/100, (avg - (avg/100)*100), -+ wlfc->stats.latency_most_recent, -+ moving_avg); -+ } -+ } -+ -+ bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " -+ "back = (%d,%d,%d,%d,%d,%d)\n", -+ wlfc->stats.fifo_credits_sent[0], -+ wlfc->stats.fifo_credits_sent[1], -+ wlfc->stats.fifo_credits_sent[2], -+ wlfc->stats.fifo_credits_sent[3], -+ wlfc->stats.fifo_credits_sent[4], -+ wlfc->stats.fifo_credits_sent[5], -+ -+ wlfc->stats.fifo_credits_back[0], -+ wlfc->stats.fifo_credits_back[1], -+ wlfc->stats.fifo_credits_back[2], -+ wlfc->stats.fifo_credits_back[3], -+ wlfc->stats.fifo_credits_back[4], -+ wlfc->stats.fifo_credits_back[5]); -+ { -+ uint32 fifo_cr_sent = 0; -+ uint32 fifo_cr_acked = 0; -+ uint32 request_cr_sent = 0; -+ uint32 request_cr_ack = 0; -+ uint32 bc_mc_cr_ack = 0; -+ -+ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { -+ fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; -+ } -+ -+ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { -+ fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; -+ } -+ -+ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { -+ if (wlfc->destination_entries.nodes[i].occupied) { -+ request_cr_sent += -+ wlfc->destination_entries.nodes[i].dstncredit_sent_packets; -+ } -+ } -+ for (i = 0; i < WLFC_MAX_IFNUM; i++) { -+ if (wlfc->destination_entries.interfaces[i].occupied) { -+ request_cr_sent += -+ wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; -+ } -+ } -+ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { -+ if (wlfc->destination_entries.nodes[i].occupied) { -+ request_cr_ack += -+ wlfc->destination_entries.nodes[i].dstncredit_acks; -+ } -+ } -+ for (i = 0; i < WLFC_MAX_IFNUM; i++) { -+ if (wlfc->destination_entries.interfaces[i].occupied) { -+ request_cr_ack += -+ wlfc->destination_entries.interfaces[i].dstncredit_acks; -+ } -+ } -+ bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," -+ "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", -+ fifo_cr_sent, fifo_cr_acked, -+ request_cr_sent, request_cr_ack, -+ wlfc->destination_entries.other.dstncredit_acks, -+ bc_mc_cr_ack, -+ wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); -+ } -+#endif /* PROP_TXSTATUS_DEBUG */ -+ bcm_bprintf(strbuf, "\n"); -+ bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" -+ "(freed,free_err,rollback)) = " -+ "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", -+ wlfc->stats.pktin, -+ wlfc->stats.pkt2bus, -+ wlfc->stats.txstatus_in, -+ wlfc->stats.dhd_hdrpulls, -+ -+ wlfc->stats.pktdropped, -+ wlfc->stats.wlfc_header_only_pkt, -+ wlfc->stats.wlc_tossed_pkts, -+ -+ wlfc->stats.pkt_freed, -+ wlfc->stats.pkt_free_err, wlfc->stats.rollback); -+ -+ bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " -+ "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", -+ -+ wlfc->stats.d11_suppress, -+ wlfc->stats.wl_suppress, -+ wlfc->stats.bad_suppress, -+ -+ wlfc->stats.psq_d11sup_enq, -+ wlfc->stats.psq_wlsup_enq, -+ wlfc->stats.psq_hostq_enq, -+ wlfc->stats.mac_handle_notfound, -+ -+ wlfc->stats.psq_d11sup_retx, -+ wlfc->stats.psq_wlsup_retx, -+ wlfc->stats.psq_hostq_retx); -+ return; -+} -+ -+/* Create a place to store all packet pointers submitted to the firmware until -+ a status comes back, suppress or otherwise. -+ -+ hang-er: noun, a contrivance on which things are hung, as a hook. -+*/ -+static void* -+dhd_wlfc_hanger_create(osl_t *osh, int max_items) -+{ -+ int i; -+ wlfc_hanger_t* hanger; -+ -+ /* allow only up to a specific size for now */ -+ ASSERT(max_items == WLFC_HANGER_MAXITEMS); -+ -+ if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) -+ return NULL; -+ -+ memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); -+ hanger->max_items = max_items; -+ -+ for (i = 0; i < hanger->max_items; i++) { -+ hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; -+ } -+ return hanger; -+} -+ -+static int -+dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) -+{ -+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; -+ -+ if (h) { -+ MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); -+ return BCME_OK; -+ } -+ return BCME_BADARG; -+} -+ -+static uint16 -+dhd_wlfc_hanger_get_free_slot(void* hanger) -+{ -+ uint32 i; -+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; -+ -+ if (h) { -+ for (i = (h->slot_pos + 1); i != h->slot_pos;) { -+ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { -+ h->slot_pos = i; -+ return (uint16)i; -+ } -+ (i == h->max_items)? i = 0 : i++; -+ } -+ h->failed_slotfind++; -+ } -+ return WLFC_HANGER_MAXITEMS; -+} -+ -+static int -+dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) -+{ -+ int rc = BCME_OK; -+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; -+ -+ *gen = 0xff; -+ -+ /* this packet was not pushed at the time it went to the firmware */ -+ if (slot_id == WLFC_HANGER_MAXITEMS) -+ return BCME_NOTFOUND; -+ -+ if (h) { -+ if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || -+ (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { -+ *gen = h->items[slot_id].gen; -+ } -+ else { -+ rc = BCME_NOTFOUND; -+ } -+ } -+ else -+ rc = BCME_BADARG; -+ return rc; -+} -+ -+static int -+dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) -+{ -+ int rc = BCME_OK; -+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; -+ -+ if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { -+ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { -+ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; -+ h->items[slot_id].pkt = pkt; -+ h->items[slot_id].identifier = slot_id; -+ h->pushed++; -+ } -+ else { -+ h->failed_to_push++; -+ rc = BCME_NOTFOUND; -+ } -+ } -+ else -+ rc = BCME_BADARG; -+ return rc; -+} -+ -+static int -+dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) -+{ -+ int rc = BCME_OK; -+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; -+ -+ /* this packet was not pushed at the time it went to the firmware */ -+ if (slot_id == WLFC_HANGER_MAXITEMS) -+ return BCME_NOTFOUND; -+ -+ if (h) { -+ if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { -+ *pktout = h->items[slot_id].pkt; -+ if (remove_from_hanger) { -+ h->items[slot_id].state = -+ WLFC_HANGER_ITEM_STATE_FREE; -+ h->items[slot_id].pkt = NULL; -+ h->items[slot_id].identifier = 0; -+ h->items[slot_id].gen = 0xff; -+ h->popped++; -+ } -+ } -+ else { -+ h->failed_to_pop++; -+ rc = BCME_NOTFOUND; -+ } -+ } -+ else -+ rc = BCME_BADARG; -+ return rc; -+} -+ -+static int -+dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) -+{ -+ int rc = BCME_OK; -+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; -+ -+ /* this packet was not pushed at the time it went to the firmware */ -+ if (slot_id == WLFC_HANGER_MAXITEMS) -+ return BCME_NOTFOUND; -+ if (h) { -+ h->items[slot_id].gen = gen; -+ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { -+ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; -+ } -+ else -+ rc = BCME_BADARG; -+ } -+ else -+ rc = BCME_BADARG; -+ -+ return rc; -+} -+ -+static int -+_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, -+ uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) -+{ -+ uint32 wl_pktinfo = 0; -+ uint8* wlh; -+ uint8 dataOffset; -+ uint8 fillers; -+ uint8 tim_signal_len = 0; -+ -+ struct bdc_header *h; -+ -+ if (tim_signal) { -+ tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; -+ } -+ -+ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ -+ dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; -+ fillers = ROUNDUP(dataOffset, 4) - dataOffset; -+ dataOffset += fillers; -+ -+ PKTPUSH(ctx->osh, p, dataOffset); -+ wlh = (uint8*) PKTDATA(ctx->osh, p); -+ -+ wl_pktinfo = htol32(htodtag); -+ -+ wlh[0] = WLFC_CTL_TYPE_PKTTAG; -+ wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; -+ memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); -+ -+ if (tim_signal_len) { -+ wlh[dataOffset - fillers - tim_signal_len ] = -+ WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; -+ wlh[dataOffset - fillers - tim_signal_len + 1] = -+ WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; -+ wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; -+ wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; -+ } -+ if (fillers) -+ memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); -+ -+ PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); -+ h = (struct bdc_header *)PKTDATA(ctx->osh, p); -+ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); -+ if (PKTSUMNEEDED(p)) -+ h->flags |= BDC_FLAG_SUM_NEEDED; -+ -+ -+ h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); -+ h->flags2 = 0; -+ h->dataOffset = dataOffset >> 2; -+ BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); -+ return BCME_OK; -+} -+ -+static int -+_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) -+{ -+ struct bdc_header *h; -+ -+ if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { -+ WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, -+ PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); -+ return BCME_ERROR; -+ } -+ h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); -+ -+ /* pull BDC header */ -+ PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); -+ -+ if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) { -+ WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, -+ PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); -+ return BCME_ERROR; -+ } -+ /* pull wl-header */ -+ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); -+ return BCME_OK; -+} -+ -+static wlfc_mac_descriptor_t* -+_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) -+{ -+ int i; -+ wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; -+ uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); -+ uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); -+ -+ if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) || -+ ETHER_ISMULTI(dstn) || -+ (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) && -+ (ctx->destination_entries.interfaces[ifid].occupied)) { -+ return &ctx->destination_entries.interfaces[ifid]; -+ } -+ -+ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { -+ if (table[i].occupied) { -+ if (table[i].interface_id == ifid) { -+ if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) -+ return &table[i]; -+ } -+ } -+ } -+ return &ctx->destination_entries.other; -+} -+ -+static int -+_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, -+ void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) -+{ -+ /* -+ put the packet back to the head of queue -+ -+ - a packet from send-q will need to go back to send-q and not delay-q -+ since that will change the order of packets. -+ - suppressed packet goes back to suppress sub-queue -+ - pull out the header, if new or delayed packet -+ -+ Note: hslot is used only when header removal is done. -+ */ -+ wlfc_mac_descriptor_t* entry; -+ void* pktout; -+ int rc = BCME_OK; -+ int prec; -+ -+ entry = _dhd_wlfc_find_table_entry(ctx, p); -+ prec = DHD_PKTTAG_FIFO(PKTTAG(p)); -+ if (entry != NULL) { -+ if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { -+ /* wl-header is saved for suppressed packets */ -+ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ rc = BCME_ERROR; -+ } -+ } -+ else { -+ /* remove header first */ -+ rc = _dhd_wlfc_pullheader(ctx, p); -+ if (rc != BCME_OK) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ /* free the hanger slot */ -+ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); -+ PKTFREE(ctx->osh, p, TRUE); -+ rc = BCME_ERROR; -+ return rc; -+ } -+ -+ if (pkt_type == eWLFC_PKTTYPE_DELAYED) { -+ /* delay-q packets are going to delay-q */ -+ if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ rc = BCME_ERROR; -+ } -+ } -+ else { -+ /* these are going to SENDQ */ -+ if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ rc = BCME_ERROR; -+ } -+ } -+ /* free the hanger slot */ -+ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); -+ -+ /* decrement sequence count */ -+ WLFC_DECR_SEQCOUNT(entry, prec); -+ } -+ /* -+ if this packet did not count against FIFO credit, it must have -+ taken a requested_credit from the firmware (for pspoll etc.) -+ */ -+ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { -+ entry->requested_credit++; -+ } -+ } -+ else { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ rc = BCME_ERROR; -+ } -+ if (rc != BCME_OK) -+ ctx->stats.rollback_failed++; -+ else -+ ctx->stats.rollback++; -+ -+ return rc; -+} -+ -+static void -+_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) -+{ -+ if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { -+ /* start traffic */ -+ ctx->hostif_flow_state[if_id] = OFF; -+ /* -+ WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", -+ pq->len, if_id, __FUNCTION__)); -+ */ -+ WLFC_DBGMESG(("F")); -+ dhd_txflowcontrol(ctx->dhdp, if_id, OFF); -+ ctx->toggle_host_if = 0; -+ } -+ if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { -+ /* stop traffic */ -+ ctx->hostif_flow_state[if_id] = ON; -+ /* -+ WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", -+ pq->len, if_id, __FUNCTION__)); -+ */ -+ WLFC_DBGMESG(("N")); -+ dhd_txflowcontrol(ctx->dhdp, if_id, ON); -+ ctx->host_ifidx = if_id; -+ ctx->toggle_host_if = 1; -+ } -+ return; -+} -+ -+static int -+_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, -+ uint8 ta_bmp) -+{ -+ int rc = BCME_OK; -+ void* p = NULL; -+ int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; -+ -+ /* allocate a dummy packet */ -+ p = PKTGET(ctx->osh, dummylen, TRUE); -+ if (p) { -+ PKTPULL(ctx->osh, p, dummylen); -+ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); -+ _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); -+ DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); -+#ifdef PROP_TXSTATUS_DEBUG -+ ctx->stats.signal_only_pkts_sent++; -+#endif -+ rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); -+ if (rc != BCME_OK) { -+ PKTFREE(ctx->osh, p, TRUE); -+ } -+ } -+ else { -+ DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", -+ __FUNCTION__, dummylen)); -+ rc = BCME_NOMEM; -+ } -+ return rc; -+} -+ -+/* Return TRUE if traffic availability changed */ -+static bool -+_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, -+ int prec) -+{ -+ bool rc = FALSE; -+ -+ if (entry->state == WLFC_STATE_CLOSE) { -+ if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && -+ (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { -+ -+ if (entry->traffic_pending_bmp & NBITVAL(prec)) { -+ rc = TRUE; -+ entry->traffic_pending_bmp = -+ entry->traffic_pending_bmp & ~ NBITVAL(prec); -+ } -+ } -+ else { -+ if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { -+ rc = TRUE; -+ entry->traffic_pending_bmp = -+ entry->traffic_pending_bmp | NBITVAL(prec); -+ } -+ } -+ } -+ if (rc) { -+ /* request a TIM update to firmware at the next piggyback opportunity */ -+ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { -+ entry->send_tim_signal = 1; -+ _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); -+ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; -+ entry->send_tim_signal = 0; -+ } -+ else { -+ rc = FALSE; -+ } -+ } -+ return rc; -+} -+ -+static int -+_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) -+{ -+ wlfc_mac_descriptor_t* entry; -+ -+ entry = _dhd_wlfc_find_table_entry(ctx, p); -+ if (entry == NULL) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ return BCME_NOTFOUND; -+ } -+ /* -+ - suppressed packets go to sub_queue[2*prec + 1] AND -+ - delayed packets go to sub_queue[2*prec + 0] to ensure -+ order of delivery. -+ */ -+ if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { -+ ctx->stats.delayq_full_error++; -+ /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ -+ WLFC_DBGMESG(("s")); -+ return BCME_ERROR; -+ } -+ /* A packet has been pushed, update traffic availability bitmap, if applicable */ -+ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); -+ _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); -+ return BCME_OK; -+} -+ -+static int -+_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, -+ wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) -+{ -+ int rc = BCME_OK; -+ int hslot = WLFC_HANGER_MAXITEMS; -+ bool send_tim_update = FALSE; -+ uint32 htod = 0; -+ uint8 free_ctr; -+ -+ *slot = hslot; -+ -+ if (entry == NULL) { -+ entry = _dhd_wlfc_find_table_entry(ctx, p); -+ } -+ -+ if (entry == NULL) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ return BCME_ERROR; -+ } -+ if (entry->send_tim_signal) { -+ send_tim_update = TRUE; -+ entry->send_tim_signal = 0; -+ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; -+ } -+ if (header_needed) { -+ hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); -+ free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); -+ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); -+ WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); -+ entry->transit_count++; -+ } -+ else { -+ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); -+ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); -+ } -+ WLFC_PKTID_HSLOT_SET(htod, hslot); -+ WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); -+ DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); -+ WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); -+ WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); -+ -+ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { -+ /* -+ Indicate that this packet is being sent in response to an -+ explicit request from the firmware side. -+ */ -+ WLFC_PKTFLAG_SET_PKTREQUESTED(htod); -+ } -+ else { -+ WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); -+ } -+ if (header_needed) { -+ rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, -+ entry->traffic_lastreported_bmp, entry->mac_handle, htod); -+ if (rc == BCME_OK) { -+ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); -+ /* -+ a new header was created for this packet. -+ push to hanger slot and scrub q. Since bus -+ send succeeded, increment seq number as well. -+ */ -+ rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); -+ if (rc == BCME_OK) { -+ /* increment free running sequence count */ -+ WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); -+#ifdef PROP_TXSTATUS_DEBUG -+ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = -+ OSL_SYSUPTIME(); -+#endif -+ } -+ else { -+ WLFC_DBGMESG(("%s() hanger_pushpkt() failed, rc: %d\n", -+ __FUNCTION__, rc)); -+ } -+ } -+ } -+ else { -+ int gen; -+ -+ /* remove old header */ -+ rc = _dhd_wlfc_pullheader(ctx, p); -+ if (rc == BCME_OK) { -+ hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); -+ dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); -+ -+ WLFC_PKTFLAG_SET_GENERATION(htod, gen); -+ free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); -+ /* push new header */ -+ _dhd_wlfc_pushheader(ctx, p, send_tim_update, -+ entry->traffic_lastreported_bmp, entry->mac_handle, htod); -+ } -+ } -+ *slot = hslot; -+ return rc; -+} -+ -+static int -+_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, -+ wlfc_mac_descriptor_t* entry, int prec) -+{ -+ if (ctx->destination_entries.interfaces[entry->interface_id].iftype == -+ WLC_E_IF_ROLE_P2P_GO) { -+ /* - destination interface is of type p2p GO. -+ For a p2pGO interface, if the destination is OPEN but the interface is -+ CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is -+ destination-specific-credit left send packets. This is because the -+ firmware storing the destination-specific-requested packet in queue. -+ */ -+ if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && -+ (entry->requested_packet == 0)) -+ return 1; -+ } -+ /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ -+ if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && -+ (entry->requested_packet == 0)) || -+ (!(entry->ac_bitmap & (1 << prec)))) -+ return 1; -+ -+ return 0; -+} -+ -+static void* -+_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, -+ int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) -+{ -+ wlfc_mac_descriptor_t* entry; -+ wlfc_mac_descriptor_t* table; -+ uint8 token_pos; -+ int total_entries; -+ void* p = NULL; -+ int pout; -+ int i; -+ -+ *entry_out = NULL; -+ token_pos = ctx->token_pos[prec]; -+ /* most cases a packet will count against FIFO credit */ -+ *ac_credit_spent = 1; -+ *needs_hdr = 1; -+ -+ /* search all entries, include nodes as well as interfaces */ -+ table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; -+ total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); -+ -+ for (i = 0; i < total_entries; i++) { -+ entry = &table[(token_pos + i) % total_entries]; -+ if (entry->occupied) { -+ if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { -+ p = pktq_mdeq(&entry->psq, -+ /* higher precedence will be picked up first, -+ * i.e. suppressed packets before delayed ones -+ */ -+ NBITVAL((prec << 1) + 1), &pout); -+ *needs_hdr = 0; -+ -+ if (p == NULL) { -+ if (entry->suppressed == TRUE) { -+ if ((entry->suppr_transit_count <= -+ entry->suppress_count)) { -+ entry->suppressed = FALSE; -+ } else { -+ return NULL; -+ } -+ } -+ /* De-Q from delay Q */ -+ p = pktq_mdeq(&entry->psq, -+ NBITVAL((prec << 1)), -+ &pout); -+ *needs_hdr = 1; -+ } -+ -+ if (p != NULL) { -+ /* did the packet come from suppress sub-queue? */ -+ if (entry->requested_credit > 0) { -+ entry->requested_credit--; -+#ifdef PROP_TXSTATUS_DEBUG -+ entry->dstncredit_sent_packets++; -+#endif -+ /* -+ if the packet was pulled out while destination is in -+ closed state but had a non-zero packets requested, -+ then this should not count against the FIFO credit. -+ That is due to the fact that the firmware will -+ most likely hold onto this packet until a suitable -+ time later to push it to the appropriate AC FIFO. -+ */ -+ if (entry->state == WLFC_STATE_CLOSE) -+ *ac_credit_spent = 0; -+ } -+ else if (entry->requested_packet > 0) { -+ entry->requested_packet--; -+ DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); -+ if (entry->state == WLFC_STATE_CLOSE) -+ *ac_credit_spent = 0; -+ } -+ /* move token to ensure fair round-robin */ -+ ctx->token_pos[prec] = -+ (token_pos + i + 1) % total_entries; -+ *entry_out = entry; -+ _dhd_wlfc_flow_control_check(ctx, &entry->psq, -+ DHD_PKTTAG_IF(PKTTAG(p))); -+ /* -+ A packet has been picked up, update traffic -+ availability bitmap, if applicable -+ */ -+ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); -+ return p; -+ } -+ } -+ } -+ } -+ return NULL; -+} -+ -+static void* -+_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec) -+{ -+ wlfc_mac_descriptor_t* entry; -+ void* p; -+ -+ -+ p = pktq_pdeq(&ctx->SENDQ, prec); -+ if (p != NULL) { -+ if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p)))) -+ /* bc/mc packets do not have a delay queue */ -+ return p; -+ -+ entry = _dhd_wlfc_find_table_entry(ctx, p); -+ -+ if (entry == NULL) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ return p; -+ } -+ -+ while ((p != NULL)) { -+ /* -+ - suppressed packets go to sub_queue[2*prec + 1] AND -+ - delayed packets go to sub_queue[2*prec + 0] to ensure -+ order of delivery. -+ */ -+ if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) { -+ WLFC_DBGMESG(("D")); -+ /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ -+ PKTFREE(ctx->osh, p, TRUE); -+ ctx->stats.delayq_full_error++; -+ } -+ /* -+ A packet has been pushed, update traffic availability bitmap, -+ if applicable -+ */ -+ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); -+ -+ p = pktq_pdeq(&ctx->SENDQ, prec); -+ if (p == NULL) -+ break; -+ -+ entry = _dhd_wlfc_find_table_entry(ctx, p); -+ -+ if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) { -+ return p; -+ } -+ } -+ } -+ return p; -+} -+ -+static int -+_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, -+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -+{ -+ int rc = BCME_OK; -+ -+ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { -+ entry->occupied = 1; -+ entry->state = WLFC_STATE_OPEN; -+ entry->requested_credit = 0; -+ entry->interface_id = ifid; -+ entry->iftype = iftype; -+ entry->ac_bitmap = 0xff; /* update this when handling APSD */ -+ /* for an interface entry we may not care about the MAC address */ -+ if (ea != NULL) -+ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); -+ pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); -+ } -+ else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { -+ entry->occupied = 1; -+ entry->state = WLFC_STATE_OPEN; -+ entry->requested_credit = 0; -+ entry->interface_id = ifid; -+ entry->iftype = iftype; -+ entry->ac_bitmap = 0xff; /* update this when handling APSD */ -+ /* for an interface entry we may not care about the MAC address */ -+ if (ea != NULL) -+ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); -+ } -+ else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { -+ entry->occupied = 0; -+ entry->state = WLFC_STATE_CLOSE; -+ entry->requested_credit = 0; -+ /* enable after packets are queued-deqeued properly. -+ pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); -+ */ -+ } -+ return rc; -+} -+ -+int -+_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) -+{ -+ int lender_ac; -+ int rc = BCME_ERROR; -+ -+ if (ctx == NULL || available_credit_map == 0) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ return BCME_BADARG; -+ } -+ -+ /* Borrow from lowest priority available AC (including BC/MC credits) */ -+ for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { -+ if ((available_credit_map && (1 << lender_ac)) && -+ (ctx->FIFO_credit[lender_ac] > 0)) { -+ ctx->credits_borrowed[borrower_ac][lender_ac]++; -+ ctx->FIFO_credit[lender_ac]--; -+ rc = BCME_OK; -+ break; -+ } -+ } -+ -+ return rc; -+} -+ -+int -+dhd_wlfc_interface_entry_update(void* state, -+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -+{ -+ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; -+ wlfc_mac_descriptor_t* entry; -+ -+ if (ifid >= WLFC_MAX_IFNUM) -+ return BCME_BADARG; -+ -+ entry = &ctx->destination_entries.interfaces[ifid]; -+ return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); -+} -+ -+int -+dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) -+{ -+ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; -+ -+ /* update the AC FIFO credit map */ -+ ctx->FIFO_credit[0] = credits[0]; -+ ctx->FIFO_credit[1] = credits[1]; -+ ctx->FIFO_credit[2] = credits[2]; -+ ctx->FIFO_credit[3] = credits[3]; -+ /* credit for bc/mc packets */ -+ ctx->FIFO_credit[4] = credits[4]; -+ /* credit for ATIM FIFO is not used yet. */ -+ ctx->FIFO_credit[5] = 0; -+ return BCME_OK; -+} -+ -+int -+dhd_wlfc_enque_sendq(void* state, int prec, void* p) -+{ -+ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; -+ -+ if ((state == NULL) || -+ /* prec = AC_COUNT is used for bc/mc queue */ -+ (prec > AC_COUNT) || -+ (p == NULL)) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ return BCME_BADARG; -+ } -+ if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) { -+ ctx->stats.sendq_full_error++; -+ /* -+ WLFC_DBGMESG(("Error: %s():%d, qlen:%d\n", -+ __FUNCTION__, __LINE__, ctx->SENDQ.len)); -+ */ -+ WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec); -+ WLFC_DBGMESG(("Q")); -+ PKTFREE(ctx->osh, p, TRUE); -+ return BCME_ERROR; -+ } -+ ctx->stats.pktin++; -+ /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */ -+ return BCME_OK; -+} -+ -+int -+_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, -+ dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) -+{ -+ uint32 hslot; -+ int rc; -+ -+ /* -+ if ac_fifo_credit_spent = 0 -+ -+ This packet will not count against the FIFO credit. -+ To ensure the txstatus corresponding to this packet -+ does not provide an implied credit (default behavior) -+ mark the packet accordingly. -+ -+ if ac_fifo_credit_spent = 1 -+ -+ This is a normal packet and it counts against the FIFO -+ credit count. -+ */ -+ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); -+ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, -+ commit_info->needs_hdr, &hslot); -+ -+ if (rc == BCME_OK) -+ rc = fcommit(commit_ctx, commit_info->p); -+ else -+ ctx->stats.generic_error++; -+ -+ if (rc == BCME_OK) { -+ ctx->stats.pkt2bus++; -+ if (commit_info->ac_fifo_credit_spent) { -+ ctx->stats.sendq_pkts[ac]++; -+ WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); -+ } -+ } else if (rc == BCME_NORESOURCE) -+ rc = BCME_ERROR; -+ else { -+ /* -+ bus commit has failed, rollback. -+ - remove wl-header for a delayed packet -+ - save wl-header header for suppressed packets -+ */ -+ rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, -+ (commit_info->pkt_type), hslot); -+ if (rc != BCME_OK) -+ ctx->stats.rollback_failed++; -+ -+ rc = BCME_ERROR; -+ } -+ -+ return rc; -+} -+ -+int -+dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) -+{ -+ int ac; -+ int credit; -+ int rc; -+ dhd_wlfc_commit_info_t commit_info; -+ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; -+ int credit_count = 0; -+ int bus_retry_count = 0; -+ uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ -+ -+ if ((state == NULL) || -+ (fcommit == NULL)) { -+ WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); -+ return BCME_BADARG; -+ } -+ -+ memset(&commit_info, 0, sizeof(commit_info)); -+ -+ /* -+ Commit packets for regular AC traffic. Higher priority first. -+ First, use up FIFO credits available to each AC. Based on distribution -+ and credits left, borrow from other ACs as applicable -+ -+ -NOTE: -+ If the bus between the host and firmware is overwhelmed by the -+ traffic from host, it is possible that higher priority traffic -+ starves the lower priority queue. If that occurs often, we may -+ have to employ weighted round-robin or ucode scheme to avoid -+ low priority packet starvation. -+ */ -+ -+ for (ac = AC_COUNT; ac >= 0; ac--) { -+ -+ int initial_credit_count = ctx->FIFO_credit[ac]; -+ -+ /* packets from SENDQ are fresh and they'd need header and have no MAC entry */ -+ commit_info.needs_hdr = 1; -+ commit_info.mac_entry = NULL; -+ commit_info.pkt_type = eWLFC_PKTTYPE_NEW; -+ -+ do { -+ commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac); -+ if (commit_info.p == NULL) -+ break; -+ else if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(commit_info.p)))) { -+ ASSERT(ac == AC_COUNT); -+ -+ if (ctx->FIFO_credit[ac]) { -+ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, -+ fcommit, commit_ctx); -+ -+ /* Bus commits may fail (e.g. flow control); abort after retries */ -+ if (rc == BCME_OK) { -+ if (commit_info.ac_fifo_credit_spent) { -+ (void) _dhd_wlfc_borrow_credit(ctx, -+ ac_available, ac); -+ credit_count--; -+ } -+ } else { -+ bus_retry_count++; -+ if (bus_retry_count >= BUS_RETRIES) { -+ DHD_ERROR((" %s: bus error\n", -+ __FUNCTION__)); -+ return rc; -+ } -+ } -+ } -+ } -+ -+ } while (commit_info.p); -+ -+ for (credit = 0; credit < ctx->FIFO_credit[ac];) { -+ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, -+ &(commit_info.ac_fifo_credit_spent), -+ &(commit_info.needs_hdr), -+ &(commit_info.mac_entry)); -+ -+ if (commit_info.p == NULL) -+ break; -+ -+ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : -+ eWLFC_PKTTYPE_SUPPRESSED; -+ -+ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, -+ fcommit, commit_ctx); -+ -+ /* Bus commits may fail (e.g. flow control); abort after retries */ -+ if (rc == BCME_OK) { -+ if (commit_info.ac_fifo_credit_spent) { -+ credit++; -+ } -+ } -+ else { -+ bus_retry_count++; -+ if (bus_retry_count >= BUS_RETRIES) { -+ DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); -+ ctx->FIFO_credit[ac] -= credit; -+ return rc; -+ } -+ } -+ } -+ -+ ctx->FIFO_credit[ac] -= credit; -+ -+ -+ /* If no credits were used, the queue is idle and can be re-used -+ Note that resv credits cannot be borrowed -+ */ -+ if (initial_credit_count == ctx->FIFO_credit[ac]) { -+ ac_available |= (1 << ac); -+ credit_count += ctx->FIFO_credit[ac]; -+ } -+ } -+ -+ /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD -+ -+ Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: -+ a) ignore BC/MC for deferring borrow -+ b) ignore AC_BE being available along with other ACs -+ (this should happen only for pure BC/MC traffic) -+ -+ i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and -+ we do not care if AC_BE and BC/MC are available or not -+ */ -+ if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { -+ -+ if (ctx->allow_credit_borrow) { -+ ac = 1; /* Set ac to AC_BE and borrow credits */ -+ } -+ else { -+ int delta; -+ int curr_t = OSL_SYSUPTIME(); -+ -+ if (curr_t > ctx->borrow_defer_timestamp) -+ delta = curr_t - ctx->borrow_defer_timestamp; -+ else -+ delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; -+ -+ if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { -+ /* Reset borrow but defer to next iteration (defensive borrowing) */ -+ ctx->allow_credit_borrow = TRUE; -+ ctx->borrow_defer_timestamp = 0; -+ } -+ return BCME_OK; -+ } -+ } -+ else { -+ /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ -+ ctx->allow_credit_borrow = FALSE; -+ ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); -+ return BCME_OK; -+ } -+ -+ /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) -+ Generically use "ac" only in case we extend to all ACs in future -+ */ -+ for (; (credit_count > 0);) { -+ -+ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, -+ &(commit_info.ac_fifo_credit_spent), -+ &(commit_info.needs_hdr), -+ &(commit_info.mac_entry)); -+ if (commit_info.p == NULL) -+ break; -+ -+ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : -+ eWLFC_PKTTYPE_SUPPRESSED; -+ -+ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, -+ fcommit, commit_ctx); -+ -+ /* Bus commits may fail (e.g. flow control); abort after retries */ -+ if (rc == BCME_OK) { -+ if (commit_info.ac_fifo_credit_spent) { -+ (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); -+ credit_count--; -+ } -+ } -+ else { -+ bus_retry_count++; -+ if (bus_retry_count >= BUS_RETRIES) { -+ DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); -+ return rc; -+ } -+ } -+ } -+ -+ return BCME_OK; -+} -+ -+static uint8 -+dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) -+{ -+ wlfc_mac_descriptor_t* table = -+ ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; -+ uint8 table_index; -+ -+ if (ea != NULL) { -+ for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { -+ if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && -+ table[table_index].occupied) -+ return table_index; -+ } -+ } -+ return WLFC_MAC_DESC_ID_INVALID; -+} -+ -+void -+dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) -+{ -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ void* p; -+ int fifo_id; -+ -+ dhd_os_wlfc_block(dhd); -+ -+ if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { -+#ifdef PROP_TXSTATUS_DEBUG -+ wlfc->stats.signal_only_pkts_freed++; -+#endif -+ if (success) -+ /* is this a signal-only packet? */ -+ PKTFREE(wlfc->osh, txp, TRUE); -+ dhd_os_wlfc_unblock(dhd); -+ return; -+ } -+ if (!success) { -+ WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", -+ __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); -+ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG -+ (PKTTAG(txp))), &p, 1); -+ -+ /* indicate failure and free the packet */ -+ dhd_txcomplete(dhd, txp, FALSE); -+ -+ /* return the credit, if necessary */ -+ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { -+ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ -+ -+ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); -+ -+ /* Return credits to highest priority lender first */ -+ for (lender = AC_COUNT; lender >= 0; lender--) { -+ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { -+ wlfc->FIFO_credit[lender]++; -+ wlfc->credits_borrowed[fifo_id][lender]--; -+ credit_returned = 1; -+ break; -+ } -+ } -+ -+ if (!credit_returned) { -+ wlfc->FIFO_credit[fifo_id]++; -+ } -+ } -+ -+ PKTFREE(wlfc->osh, txp, TRUE); -+ } -+ dhd_os_wlfc_unblock(dhd); -+ return; -+} -+ -+static int -+dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) -+{ -+ uint8 status_flag; -+ uint32 status; -+ int ret; -+ int remove_from_hanger = 1; -+ void* pktbuf; -+ uint8 fifo_id; -+ uint8 count = 0; -+ uint32 status_g; -+ uint32 hslot, hcnt; -+ wlfc_mac_descriptor_t* entry = NULL; -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ -+ memcpy(&status, pkt_info, sizeof(uint32)); -+ status_flag = WL_TXSTATUS_GET_FLAGS(status); -+ status_g = status & 0xff000000; -+ hslot = (status & 0x00ffff00) >> 8; -+ hcnt = status & 0xff; -+ len = pkt_info[4]; -+ -+ wlfc->stats.txstatus_in++; -+ -+ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { -+ wlfc->stats.pkt_freed++; -+ } -+ -+ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { -+ wlfc->stats.d11_suppress++; -+ remove_from_hanger = 0; -+ } -+ -+ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { -+ wlfc->stats.wl_suppress++; -+ remove_from_hanger = 0; -+ } -+ -+ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { -+ wlfc->stats.wlc_tossed_pkts++; -+ } -+ while (count < len) { -+ status = (status_g << 24) | (hslot << 8) | (hcnt); -+ count++; -+ hslot++; -+ hcnt++; -+ -+ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, -+ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); -+ if (ret != BCME_OK) { -+ /* do something */ -+ continue; -+ } -+ -+ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); -+ -+ if (!remove_from_hanger) { -+ /* this packet was suppressed */ -+ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { -+ entry->suppressed = TRUE; -+ entry->suppress_count = pktq_mlen(&entry->psq, -+ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); -+ entry->suppr_transit_count = entry->transit_count; -+ } -+ entry->generation = WLFC_PKTID_GEN(status); -+ } -+ -+#ifdef PROP_TXSTATUS_DEBUG -+ { -+ uint32 new_t = OSL_SYSUPTIME(); -+ uint32 old_t; -+ uint32 delta; -+ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ -+ WLFC_PKTID_HSLOT_GET(status)].push_time; -+ -+ -+ wlfc->stats.latency_sample_count++; -+ if (new_t > old_t) -+ delta = new_t - old_t; -+ else -+ delta = 0xffffffff + new_t - old_t; -+ wlfc->stats.total_status_latency += delta; -+ wlfc->stats.latency_most_recent = delta; -+ -+ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; -+ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) -+ wlfc->stats.idx_delta = 0; -+ } -+#endif /* PROP_TXSTATUS_DEBUG */ -+ -+ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); -+ -+ /* pick up the implicit credit from this packet */ -+ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { -+ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { -+ -+ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ -+ -+ /* Return credits to highest priority lender first */ -+ for (lender = AC_COUNT; lender >= 0; lender--) { -+ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { -+ wlfc->FIFO_credit[lender]++; -+ wlfc->credits_borrowed[fifo_id][lender]--; -+ credit_returned = 1; -+ break; -+ } -+ } -+ -+ if (!credit_returned) { -+ wlfc->FIFO_credit[fifo_id]++; -+ } -+ } -+ } -+ else { -+ /* -+ if this packet did not count against FIFO credit, it must have -+ taken a requested_credit from the destination entry (for pspoll etc.) -+ */ -+ if (!entry) { -+ -+ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); -+ } -+ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) -+ entry->requested_credit++; -+#ifdef PROP_TXSTATUS_DEBUG -+ entry->dstncredit_acks++; -+#endif -+ } -+ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || -+ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { -+ -+ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); -+ if (ret != BCME_OK) { -+ /* delay q is full, drop this packet */ -+ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), -+ &pktbuf, 1); -+ -+ /* indicate failure and free the packet */ -+ dhd_txcomplete(dhd, pktbuf, FALSE); -+ entry->transit_count--; -+ /* packet is transmitted Successfully by dongle -+ * after first suppress. -+ */ -+ if (entry->suppressed) { -+ entry->suppr_transit_count--; -+ } -+ PKTFREE(wlfc->osh, pktbuf, TRUE); -+ } else { -+ /* Mark suppressed to avoid a double free during wlfc cleanup */ -+ -+ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, -+ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); -+ entry->suppress_count++; -+ } -+ } -+ else { -+ dhd_txcomplete(dhd, pktbuf, TRUE); -+ entry->transit_count--; -+ -+ /* This packet is transmitted Successfully by dongle -+ * even after first suppress. -+ */ -+ if (entry->suppressed) { -+ entry->suppr_transit_count--; -+ } -+ /* free the packet */ -+ PKTFREE(wlfc->osh, pktbuf, TRUE); -+ } -+ } -+ return BCME_OK; -+} -+ -+/* Handle discard or suppress indication */ -+static int -+dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) -+{ -+ uint8 status_flag; -+ uint32 status; -+ int ret; -+ int remove_from_hanger = 1; -+ void* pktbuf; -+ uint8 fifo_id; -+ wlfc_mac_descriptor_t* entry = NULL; -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ -+ memcpy(&status, pkt_info, sizeof(uint32)); -+ status_flag = WL_TXSTATUS_GET_FLAGS(status); -+ wlfc->stats.txstatus_in++; -+ -+ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { -+ wlfc->stats.pkt_freed++; -+ } -+ -+ else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { -+ wlfc->stats.d11_suppress++; -+ remove_from_hanger = 0; -+ } -+ -+ else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { -+ wlfc->stats.wl_suppress++; -+ remove_from_hanger = 0; -+ } -+ -+ else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { -+ wlfc->stats.wlc_tossed_pkts++; -+ } -+ -+ ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, -+ WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); -+ if (ret != BCME_OK) { -+ /* do something */ -+ return ret; -+ } -+ -+ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); -+ -+ if (!remove_from_hanger) { -+ /* this packet was suppressed */ -+ if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { -+ entry->suppressed = TRUE; -+ entry->suppress_count = pktq_mlen(&entry->psq, -+ NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); -+ entry->suppr_transit_count = entry->transit_count; -+ } -+ entry->generation = WLFC_PKTID_GEN(status); -+ } -+ -+#ifdef PROP_TXSTATUS_DEBUG -+ { -+ uint32 new_t = OSL_SYSUPTIME(); -+ uint32 old_t; -+ uint32 delta; -+ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ -+ WLFC_PKTID_HSLOT_GET(status)].push_time; -+ -+ -+ wlfc->stats.latency_sample_count++; -+ if (new_t > old_t) -+ delta = new_t - old_t; -+ else -+ delta = 0xffffffff + new_t - old_t; -+ wlfc->stats.total_status_latency += delta; -+ wlfc->stats.latency_most_recent = delta; -+ -+ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; -+ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) -+ wlfc->stats.idx_delta = 0; -+ } -+#endif /* PROP_TXSTATUS_DEBUG */ -+ -+ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); -+ -+ /* pick up the implicit credit from this packet */ -+ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { -+ if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { -+ -+ int lender, credit_returned = 0; /* Note that borrower is fifo_id */ -+ -+ /* Return credits to highest priority lender first */ -+ for (lender = AC_COUNT; lender >= 0; lender--) { -+ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { -+ wlfc->FIFO_credit[lender]++; -+ wlfc->credits_borrowed[fifo_id][lender]--; -+ credit_returned = 1; -+ break; -+ } -+ } -+ -+ if (!credit_returned) { -+ wlfc->FIFO_credit[fifo_id]++; -+ } -+ } -+ } -+ else { -+ /* -+ if this packet did not count against FIFO credit, it must have -+ taken a requested_credit from the destination entry (for pspoll etc.) -+ */ -+ if (!entry) { -+ -+ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); -+ } -+ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) -+ entry->requested_credit++; -+#ifdef PROP_TXSTATUS_DEBUG -+ entry->dstncredit_acks++; -+#endif -+ } -+ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || -+ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { -+ -+ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); -+ if (ret != BCME_OK) { -+ /* delay q is full, drop this packet */ -+ dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), -+ &pktbuf, 1); -+ -+ /* indicate failure and free the packet */ -+ dhd_txcomplete(dhd, pktbuf, FALSE); -+ entry->transit_count--; -+ /* This packet is transmitted Successfully by -+ * dongle even after first suppress. -+ */ -+ if (entry->suppressed) { -+ entry->suppr_transit_count--; -+ } -+ PKTFREE(wlfc->osh, pktbuf, TRUE); -+ } else { -+ /* Mark suppressed to avoid a double free during wlfc cleanup */ -+ dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, -+ WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); -+ entry->suppress_count++; -+ } -+ } -+ else { -+ dhd_txcomplete(dhd, pktbuf, TRUE); -+ entry->transit_count--; -+ -+ /* This packet is transmitted Successfully by dongle even after first suppress. */ -+ if (entry->suppressed) { -+ entry->suppr_transit_count--; -+ } -+ /* free the packet */ -+ PKTFREE(wlfc->osh, pktbuf, TRUE); -+ } -+ return BCME_OK; -+} -+ -+static int -+dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) -+{ -+ int i; -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { -+#ifdef PROP_TXSTATUS_DEBUG -+ wlfc->stats.fifo_credits_back[i] += credits[i]; -+#endif -+ /* update FIFO credits */ -+ if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) -+ { -+ int lender; /* Note that borrower is i */ -+ -+ /* Return credits to highest priority lender first */ -+ for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { -+ if (wlfc->credits_borrowed[i][lender] > 0) { -+ if (credits[i] >= wlfc->credits_borrowed[i][lender]) { -+ credits[i] -= wlfc->credits_borrowed[i][lender]; -+ wlfc->FIFO_credit[lender] += -+ wlfc->credits_borrowed[i][lender]; -+ wlfc->credits_borrowed[i][lender] = 0; -+ } -+ else { -+ wlfc->credits_borrowed[i][lender] -= credits[i]; -+ wlfc->FIFO_credit[lender] += credits[i]; -+ credits[i] = 0; -+ } -+ } -+ } -+ -+ /* If we have more credits left over, these must belong to the AC */ -+ if (credits[i] > 0) { -+ wlfc->FIFO_credit[i] += credits[i]; -+ } -+ } -+ } -+ -+ return BCME_OK; -+} -+ -+static int -+dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) -+{ -+ uint32 timestamp; -+ -+ (void)dhd; -+ -+ bcopy(&value[2], ×tamp, sizeof(uint32)); -+ DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); -+ return BCME_OK; -+} -+ -+ -+static int -+dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) -+{ -+ (void)dhd; -+ (void)rssi; -+ return BCME_OK; -+} -+ -+static int -+dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) -+{ -+ int rc; -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ wlfc_mac_descriptor_t* table; -+ uint8 existing_index; -+ uint8 table_index; -+ uint8 ifid; -+ uint8* ea; -+ -+ WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", -+ __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], -+ ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), -+ WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); -+ -+ table = wlfc->destination_entries.nodes; -+ table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); -+ ifid = value[1]; -+ ea = &value[2]; -+ -+ if (type == WLFC_CTL_TYPE_MACDESC_ADD) { -+ existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); -+ if (existing_index == WLFC_MAC_DESC_ID_INVALID) { -+ /* this MAC entry does not exist, create one */ -+ if (!table[table_index].occupied) { -+ table[table_index].mac_handle = value[0]; -+ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], -+ eWLFC_MAC_ENTRY_ACTION_ADD, ifid, -+ wlfc->destination_entries.interfaces[ifid].iftype, -+ ea); -+ } -+ else { -+ /* the space should have been empty, but it's not */ -+ wlfc->stats.mac_update_failed++; -+ } -+ } -+ else { -+ /* -+ there is an existing entry, move it to new index -+ if necessary. -+ */ -+ if (existing_index != table_index) { -+ /* if we already have an entry, free the old one */ -+ table[existing_index].occupied = 0; -+ table[existing_index].state = WLFC_STATE_CLOSE; -+ table[existing_index].requested_credit = 0; -+ table[existing_index].interface_id = 0; -+ /* enable after packets are queued-deqeued properly. -+ pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); -+ */ -+ } -+ } -+ } -+ if (type == WLFC_CTL_TYPE_MACDESC_DEL) { -+ if (table[table_index].occupied) { -+ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], -+ eWLFC_MAC_ENTRY_ACTION_DEL, ifid, -+ wlfc->destination_entries.interfaces[ifid].iftype, -+ ea); -+ } -+ else { -+ /* the space should have been occupied, but it's not */ -+ wlfc->stats.mac_update_failed++; -+ } -+ } -+ BCM_REFERENCE(rc); -+ return BCME_OK; -+} -+ -+static int -+dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) -+{ -+ /* Handle PS on/off indication */ -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ wlfc_mac_descriptor_t* table; -+ wlfc_mac_descriptor_t* desc; -+ uint8 mac_handle = value[0]; -+ int i; -+ -+ table = wlfc->destination_entries.nodes; -+ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; -+ if (desc->occupied) { -+ /* a fresh PS mode should wipe old ps credits? */ -+ desc->requested_credit = 0; -+ if (type == WLFC_CTL_TYPE_MAC_OPEN) { -+ desc->state = WLFC_STATE_OPEN; -+ DHD_WLFC_CTRINC_MAC_OPEN(desc); -+ } -+ else { -+ desc->state = WLFC_STATE_CLOSE; -+ DHD_WLFC_CTRINC_MAC_CLOSE(desc); -+ /* -+ Indicate to firmware if there is any traffic pending. -+ */ -+ for (i = AC_BE; i < AC_COUNT; i++) { -+ _dhd_wlfc_traffic_pending_check(wlfc, desc, i); -+ } -+ } -+ } -+ else { -+ wlfc->stats.psmode_update_failed++; -+ } -+ return BCME_OK; -+} -+ -+static int -+dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) -+{ -+ /* Handle PS on/off indication */ -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ wlfc_mac_descriptor_t* table; -+ uint8 if_id = value[0]; -+ -+ if (if_id < WLFC_MAX_IFNUM) { -+ table = wlfc->destination_entries.interfaces; -+ if (table[if_id].occupied) { -+ if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { -+ table[if_id].state = WLFC_STATE_OPEN; -+ /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ -+ } -+ else { -+ table[if_id].state = WLFC_STATE_CLOSE; -+ /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ -+ } -+ return BCME_OK; -+ } -+ } -+ wlfc->stats.interface_update_failed++; -+ -+ return BCME_OK; -+} -+ -+static int -+dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) -+{ -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ wlfc_mac_descriptor_t* table; -+ wlfc_mac_descriptor_t* desc; -+ uint8 mac_handle; -+ uint8 credit; -+ -+ table = wlfc->destination_entries.nodes; -+ mac_handle = value[1]; -+ credit = value[0]; -+ -+ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; -+ if (desc->occupied) { -+ desc->requested_credit = credit; -+ -+ desc->ac_bitmap = value[2]; -+ } -+ else { -+ wlfc->stats.credit_request_failed++; -+ } -+ return BCME_OK; -+} -+ -+static int -+dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) -+{ -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ wlfc_mac_descriptor_t* table; -+ wlfc_mac_descriptor_t* desc; -+ uint8 mac_handle; -+ uint8 packet_count; -+ -+ table = wlfc->destination_entries.nodes; -+ mac_handle = value[1]; -+ packet_count = value[0]; -+ -+ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; -+ if (desc->occupied) { -+ desc->requested_packet = packet_count; -+ -+ desc->ac_bitmap = value[2]; -+ } -+ else { -+ wlfc->stats.packet_request_failed++; -+ } -+ return BCME_OK; -+} -+ -+static void -+dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) -+{ -+ if (info_len) { -+ if (info_buf) { -+ bcopy(val, info_buf, len); -+ *info_len = len; -+ } -+ else -+ *info_len = 0; -+ } -+} -+ -+static int -+dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, -+ uint *reorder_info_len) -+{ -+ uint8 type, len; -+ uint8* value; -+ uint8* tmpbuf; -+ uint16 remainder = tlv_hdr_len; -+ uint16 processed = 0; -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); -+ if (remainder) { -+ while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { -+ type = tmpbuf[processed]; -+ if (type == WLFC_CTL_TYPE_FILLER) { -+ remainder -= 1; -+ processed += 1; -+ continue; -+ } -+ -+ len = tmpbuf[processed + 1]; -+ value = &tmpbuf[processed + 2]; -+ -+ if (remainder < (2 + len)) -+ break; -+ -+ remainder -= 2 + len; -+ processed += 2 + len; -+ if (type == WLFC_CTL_TYPE_TXSTATUS) -+ dhd_wlfc_txstatus_update(dhd, value); -+ if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) -+ dhd_wlfc_compressed_txstatus_update(dhd, value, len); -+ -+ else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) -+ dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, -+ reorder_info_len); -+ else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) -+ dhd_wlfc_fifocreditback_indicate(dhd, value); -+ -+ else if (type == WLFC_CTL_TYPE_RSSI) -+ dhd_wlfc_rssi_indicate(dhd, value); -+ -+ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) -+ dhd_wlfc_credit_request(dhd, value); -+ -+ else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) -+ dhd_wlfc_packet_request(dhd, value); -+ -+ else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || -+ (type == WLFC_CTL_TYPE_MAC_CLOSE)) -+ dhd_wlfc_psmode_update(dhd, value, type); -+ -+ else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || -+ (type == WLFC_CTL_TYPE_MACDESC_DEL)) -+ dhd_wlfc_mac_table_update(dhd, value, type); -+ -+ else if (type == WLFC_CTL_TYPE_TRANS_ID) -+ dhd_wlfc_dbg_senum_check(dhd, value); -+ -+ else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || -+ (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { -+ dhd_wlfc_interface_update(dhd, value, type); -+ } -+ } -+ if (remainder != 0) { -+ /* trouble..., something is not right */ -+ wlfc->stats.tlv_parse_failed++; -+ } -+ } -+ return BCME_OK; -+} -+ -+int -+dhd_wlfc_init(dhd_pub_t *dhd) -+{ -+ char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ -+ /* enable all signals & indicate host proptxstatus logic is active */ -+ uint32 tlv = dhd->wlfc_enabled? -+ WLFC_FLAGS_RSSI_SIGNALS | -+ WLFC_FLAGS_XONXOFF_SIGNALS | -+ WLFC_FLAGS_CREDIT_STATUS_SIGNALS | -+ WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | -+ WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; -+ /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ -+ -+ -+ /* -+ try to enable/disable signaling by sending "tlv" iovar. if that fails, -+ fallback to no flow control? Print a message for now. -+ */ -+ -+ /* enable proptxtstatus signaling by default */ -+ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); -+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { -+ DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); -+ } -+ else { -+ /* -+ Leaving the message for now, it should be removed after a while; once -+ the tlv situation is stable. -+ */ -+ DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", -+ dhd->wlfc_enabled?"enabled":"disabled", tlv)); -+ } -+ return BCME_OK; -+} -+ -+int -+dhd_wlfc_enable(dhd_pub_t *dhd) -+{ -+ int i; -+ athost_wl_status_info_t* wlfc; -+ -+ DHD_TRACE(("Enter %s\n", __FUNCTION__)); -+ -+ if (!dhd->wlfc_enabled || dhd->wlfc_state) -+ return BCME_OK; -+ -+ /* allocate space to track txstatus propagated from firmware */ -+ dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); -+ if (dhd->wlfc_state == NULL) -+ return BCME_NOMEM; -+ -+ /* initialize state space */ -+ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; -+ memset(wlfc, 0, sizeof(athost_wl_status_info_t)); -+ -+ /* remember osh & dhdp */ -+ wlfc->osh = dhd->osh; -+ wlfc->dhdp = dhd; -+ -+ wlfc->hanger = -+ dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); -+ if (wlfc->hanger == NULL) { -+ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); -+ dhd->wlfc_state = NULL; -+ return BCME_NOMEM; -+ } -+ -+ /* initialize all interfaces to accept traffic */ -+ for (i = 0; i < WLFC_MAX_IFNUM; i++) { -+ wlfc->hostif_flow_state[i] = OFF; -+ } -+ -+ /* -+ create the SENDQ containing -+ sub-queues for all AC precedences + 1 for bc/mc traffic -+ */ -+ pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN); -+ -+ wlfc->destination_entries.other.state = WLFC_STATE_OPEN; -+ /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ -+ wlfc->destination_entries.other.ac_bitmap = 0x1f; -+ wlfc->destination_entries.other.interface_id = 0; -+ -+ wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; -+ -+ wlfc->allow_credit_borrow = TRUE; -+ wlfc->borrow_defer_timestamp = 0; -+ -+ return BCME_OK; -+} -+ -+/* release all packet resources */ -+void -+dhd_wlfc_cleanup(dhd_pub_t *dhd) -+{ -+ int i; -+ int total_entries; -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ wlfc_mac_descriptor_t* table; -+ wlfc_hanger_t* h; -+ int prec; -+ void *pkt = NULL; -+ struct pktq *txq = NULL; -+ -+ DHD_TRACE(("Enter %s\n", __FUNCTION__)); -+ if (dhd->wlfc_state == NULL) -+ return; -+ /* flush bus->txq */ -+ txq = dhd_bus_txq(dhd->bus); -+ -+ /* any in the hanger? */ -+ h = (wlfc_hanger_t*)wlfc->hanger; -+ total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); -+ /* search all entries, include nodes as well as interfaces */ -+ table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; -+ -+ for (i = 0; i < total_entries; i++) { -+ if (table[i].occupied) { -+ if (table[i].psq.len) { -+ WLFC_DBGMESG(("%s(): DELAYQ[%d].len = %d\n", -+ __FUNCTION__, i, table[i].psq.len)); -+ /* release packets held in DELAYQ */ -+ pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0); -+ } -+ table[i].occupied = 0; -+ } -+ } -+ /* release packets held in SENDQ */ -+ if (wlfc->SENDQ.len) -+ pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); -+ for (prec = 0; prec < txq->num_prec; prec++) { -+ pkt = pktq_pdeq(txq, prec); -+ while (pkt) { -+ for (i = 0; i < h->max_items; i++) { -+ if (pkt == h->items[i].pkt) { -+ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { -+ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); -+ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; -+ h->items[i].pkt = NULL; -+ h->items[i].identifier = 0; -+ } else if (h->items[i].state == -+ WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { -+ /* These are already freed from the psq */ -+ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; -+ } -+ break; -+ } -+ } -+ pkt = pktq_pdeq(txq, prec); -+ } -+ } -+ /* flush remained pkt in hanger queue, not in bus->txq */ -+ for (i = 0; i < h->max_items; i++) { -+ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { -+ if (!dhd->hang_was_sent) { -+ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); -+ } else { -+ printk("%s: Skip freeing skb %p\n", __func__, h->items[i].pkt); -+ } -+ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; -+ h->items[i].pkt = NULL; -+ h->items[i].identifier = 0; -+ } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { -+ /* These are freed from the psq so no need to free again */ -+ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; -+ } -+ } -+ return; -+} -+ -+void -+dhd_wlfc_deinit(dhd_pub_t *dhd) -+{ -+ /* cleanup all psq related resources */ -+ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) -+ dhd->wlfc_state; -+ -+ DHD_TRACE(("Enter %s\n", __FUNCTION__)); -+ -+ dhd_os_wlfc_block(dhd); -+ if (dhd->wlfc_state == NULL) { -+ dhd_os_wlfc_unblock(dhd); -+ return; -+ } -+#ifdef PROP_TXSTATUS_DEBUG -+ { -+ int i; -+ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; -+ for (i = 0; i < h->max_items; i++) { -+ if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { -+ WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", -+ __FUNCTION__, i, h->items[i].pkt, -+ DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); -+ } -+ } -+ } -+#endif -+ /* delete hanger */ -+ dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); -+ -+ /* free top structure */ -+ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); -+ dhd->wlfc_state = NULL; -+ dhd_os_wlfc_unblock(dhd); -+ return; -+} -+#endif /* PROP_TXSTATUS */ -+ -+void -+dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -+{ -+ bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); -+#ifdef PROP_TXSTATUS -+ dhd_os_wlfc_block(dhdp); -+ if (dhdp->wlfc_state) -+ dhd_wlfc_dump(dhdp, strbuf); -+ dhd_os_wlfc_unblock(dhdp); -+#endif -+} -+ -+void -+dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) -+{ -+#ifdef BDC -+ struct bdc_header *h; -+#endif /* BDC */ -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+#ifdef BDC -+ /* Push BDC header used to convey priority for buses that don't */ -+ -+ PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); -+ -+ h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); -+ -+ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); -+ if (PKTSUMNEEDED(pktbuf)) -+ h->flags |= BDC_FLAG_SUM_NEEDED; -+ -+ -+ h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); -+ h->flags2 = 0; -+ h->dataOffset = 0; -+#endif /* BDC */ -+ BDC_SET_IF_IDX(h, ifidx); -+} -+ -+int -+dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, -+ uint *reorder_info_len) -+{ -+#ifdef BDC -+ struct bdc_header *h; -+#endif -+ uint8 data_offset = 0; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+#ifdef BDC -+ if (reorder_info_len) -+ *reorder_info_len = 0; -+ /* Pop BDC header used to convey priority for buses that don't */ -+ -+ if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { -+ DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, -+ PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); -+ return BCME_ERROR; -+ } -+ -+ h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); -+ -+#if defined(NDIS630) -+ h->dataOffset = 0; -+#endif -+ -+ if (!ifidx) { -+ /* for tx packet, skip the analysis and just exit */ -+ data_offset = h->dataOffset; -+ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); -+ goto exit; -+ } -+ -+ if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { -+ DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", -+ __FUNCTION__, *ifidx)); -+ return BCME_ERROR; -+ } -+ -+ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { -+ DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", -+ dhd_ifname(dhd, *ifidx), h->flags)); -+ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) -+ h->dataOffset = 0; -+ else -+ return BCME_ERROR; -+ } -+ -+ if (h->flags & BDC_FLAG_SUM_GOOD) { -+ DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", -+ dhd_ifname(dhd, *ifidx), h->flags)); -+ PKTSETSUMGOOD(pktbuf, TRUE); -+ } -+ -+ PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); -+ data_offset = h->dataOffset; -+ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); -+#endif /* BDC */ -+ -+#if !defined(NDIS630) -+ if (PKTLEN(dhd->osh, pktbuf) < (uint32) (data_offset << 2)) { -+ DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, -+ PKTLEN(dhd->osh, pktbuf), (data_offset * 4))); -+ return BCME_ERROR; -+ } -+#endif -+#ifdef PROP_TXSTATUS -+ if (dhd->wlfc_state && -+ ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode -+ != WLFC_FCMODE_NONE && -+ (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf)))) { -+ /* -+ - parse txstatus only for packets that came from the firmware -+ */ -+ dhd_os_wlfc_block(dhd); -+ dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), -+ reorder_buf_info, reorder_info_len); -+ ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++; -+ dhd_os_wlfc_unblock(dhd); -+ } -+#endif /* PROP_TXSTATUS */ -+exit: -+#if !defined(NDIS630) -+ PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); -+#endif -+ return 0; -+} -+ -+#if defined(PROP_TXSTATUS) -+void -+dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd) -+{ -+ if (dhd->wlfc_state && -+ (((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode -+ != WLFC_FCMODE_NONE)) { -+ dhd_os_wlfc_block(dhd); -+ dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, -+ (void *)dhd->bus); -+ dhd_os_wlfc_unblock(dhd); -+ } -+} -+#endif -+ -+int -+dhd_prot_attach(dhd_pub_t *dhd) -+{ -+ dhd_prot_t *cdc; -+ -+ if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd->osh, DHD_PREALLOC_PROT, -+ sizeof(dhd_prot_t)))) { -+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ memset(cdc, 0, sizeof(dhd_prot_t)); -+ -+ /* ensure that the msg buf directly follows the cdc msg struct */ -+ if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { -+ DHD_ERROR(("dhd_prot_t is not correctly defined\n")); -+ goto fail; -+ } -+ -+ dhd->prot = cdc; -+#ifdef BDC -+ dhd->hdrlen += BDC_HEADER_LEN; -+#endif -+ dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; -+ return 0; -+ -+fail: -+#ifndef CONFIG_DHD_USE_STATIC_BUF -+ if (cdc != NULL) -+ MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); -+#endif /* CONFIG_DHD_USE_STATIC_BUF */ -+ return BCME_NOMEM; -+} -+ -+/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ -+void -+dhd_prot_detach(dhd_pub_t *dhd) -+{ -+#ifdef PROP_TXSTATUS -+ dhd_wlfc_deinit(dhd); -+#endif -+#ifndef CONFIG_DHD_USE_STATIC_BUF -+ MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); -+#endif /* CONFIG_DHD_USE_STATIC_BUF */ -+ dhd->prot = NULL; -+} -+ -+void -+dhd_prot_dstats(dhd_pub_t *dhd) -+{ -+ /* No stats from dongle added yet, copy bus stats */ -+ dhd->dstats.tx_packets = dhd->tx_packets; -+ dhd->dstats.tx_errors = dhd->tx_errors; -+ dhd->dstats.rx_packets = dhd->rx_packets; -+ dhd->dstats.rx_errors = dhd->rx_errors; -+ dhd->dstats.rx_dropped = dhd->rx_dropped; -+ dhd->dstats.multicast = dhd->rx_multicast; -+ return; -+} -+ -+int -+dhd_prot_init(dhd_pub_t *dhd) -+{ -+ int ret = 0; -+ wlc_rev_info_t revinfo; -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ -+ /* Get the device rev info */ -+ memset(&revinfo, 0, sizeof(revinfo)); -+ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); -+ if (ret < 0) -+ goto done; -+ -+ -+#if defined(WL_CFG80211) -+ if (dhd_download_fw_on_driverload) -+#endif /* defined(WL_CFG80211) */ -+ ret = dhd_preinit_ioctls(dhd); -+ -+#ifdef PROP_TXSTATUS -+ ret = dhd_wlfc_init(dhd); -+#endif -+ -+ /* Always assumes wl for now */ -+ dhd->iswl = TRUE; -+ -+done: -+ return ret; -+} -+ -+void -+dhd_prot_stop(dhd_pub_t *dhd) -+{ -+ /* Nothing to do for CDC */ -+} -+ -+ -+static void -+dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, -+ uint32 *pkt_count, void **pplast, uint8 start, uint8 end) -+{ -+ uint i; -+ void *plast = NULL, *p; -+ uint32 pkt_cnt = 0; -+ -+ if (ptr->pend_pkts == 0) { -+ DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__)); -+ *pplast = NULL; -+ *pkt_count = 0; -+ *pkt = NULL; -+ return; -+ } -+ if (start == end) -+ i = ptr->max_idx + 1; -+ else { -+ if (start > end) -+ i = ((ptr->max_idx + 1) - start) + end; -+ else -+ i = end - start; -+ } -+ while (i) { -+ p = (void *)(ptr->p[start]); -+ ptr->p[start] = NULL; -+ -+ if (p != NULL) { -+ if (plast == NULL) -+ *pkt = p; -+ else -+ PKTSETNEXT(osh, plast, p); -+ -+ plast = p; -+ pkt_cnt++; -+ } -+ i--; -+ if (start++ == ptr->max_idx) -+ start = 0; -+ } -+ *pplast = plast; -+ *pkt_count = (uint32)pkt_cnt; -+} -+ -+int -+dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, -+ void **pkt, uint32 *pkt_count) -+{ -+ uint8 flow_id, max_idx, cur_idx, exp_idx; -+ struct reorder_info *ptr; -+ uint8 flags; -+ void *cur_pkt, *plast = NULL; -+ uint32 cnt = 0; -+ -+ if (pkt == NULL) { -+ if (pkt_count != NULL) -+ *pkt_count = 0; -+ return 0; -+ } -+ -+ flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; -+ flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; -+ -+ DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, -+ reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], -+ reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], -+ reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET])); -+ -+ /* validate flags and flow id */ -+ if (flags == 0xFF) { -+ DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__)); -+ *pkt_count = 1; -+ return 0; -+ } -+ -+ cur_pkt = *pkt; -+ *pkt = NULL; -+ -+ ptr = dhd->reorder_bufs[flow_id]; -+ if (flags & WLHOST_REORDERDATA_DEL_FLOW) { -+ uint32 buf_size = sizeof(struct reorder_info); -+ -+ DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n", -+ __FUNCTION__, flow_id)); -+ -+ if (ptr == NULL) { -+ DHD_ERROR(("%s: received flags to cleanup, but no flow (%d) yet\n", -+ __FUNCTION__, flow_id)); -+ *pkt_count = 1; -+ *pkt = cur_pkt; -+ return 0; -+ } -+ -+ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, -+ ptr->exp_idx, ptr->exp_idx); -+ /* set it to the last packet */ -+ if (plast) { -+ PKTSETNEXT(dhd->osh, plast, cur_pkt); -+ cnt++; -+ } -+ else { -+ if (cnt != 0) { -+ DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n", -+ __FUNCTION__, cnt)); -+ } -+ *pkt = cur_pkt; -+ cnt = 1; -+ } -+ buf_size += ((ptr->max_idx + 1) * sizeof(void *)); -+ MFREE(dhd->osh, ptr, buf_size); -+ dhd->reorder_bufs[flow_id] = NULL; -+ *pkt_count = cnt; -+ return 0; -+ } -+ /* all the other cases depend on the existance of the reorder struct for that flow id */ -+ if (ptr == NULL) { -+ uint32 buf_size_alloc = sizeof(reorder_info_t); -+ max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; -+ -+ buf_size_alloc += ((max_idx + 1) * sizeof(void*)); -+ /* allocate space to hold the buffers, index etc */ -+ -+ DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", -+ __FUNCTION__, buf_size_alloc, flow_id, max_idx)); -+ ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); -+ if (ptr == NULL) { -+ DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__)); -+ *pkt_count = 1; -+ return 0; -+ } -+ bzero(ptr, buf_size_alloc); -+ dhd->reorder_bufs[flow_id] = ptr; -+ ptr->p = (void *)(ptr+1); -+ ptr->max_idx = max_idx; -+ } -+ if (flags & WLHOST_REORDERDATA_NEW_HOLE) { -+ DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__)); -+ if (ptr->pend_pkts) { -+ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, -+ ptr->exp_idx, ptr->exp_idx); -+ ptr->pend_pkts = 0; -+ } -+ ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; -+ ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; -+ ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; -+ ptr->p[ptr->cur_idx] = cur_pkt; -+ ptr->pend_pkts++; -+ *pkt_count = cnt; -+ } -+ else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { -+ cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; -+ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; -+ -+ -+ if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { -+ /* still in the current hole */ -+ /* enqueue the current on the buffer chain */ -+ if (ptr->p[cur_idx] != NULL) { -+ DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n", -+ __FUNCTION__)); -+ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); -+ ptr->p[cur_idx] = NULL; -+ } -+ ptr->p[cur_idx] = cur_pkt; -+ ptr->pend_pkts++; -+ ptr->cur_idx = cur_idx; -+ DHD_REORDER(("%s: fill up a hole..pending packets is %d\n", -+ __FUNCTION__, ptr->pend_pkts)); -+ *pkt_count = 0; -+ *pkt = NULL; -+ } -+ else if (ptr->exp_idx == cur_idx) { -+ /* got the right one ..flush from cur to exp and update exp */ -+ DHD_REORDER(("%s: got the right one now, cur_idx is %d\n", -+ __FUNCTION__, cur_idx)); -+ if (ptr->p[cur_idx] != NULL) { -+ DHD_REORDER(("%s: Error buffer pending..free it\n", -+ __FUNCTION__)); -+ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); -+ ptr->p[cur_idx] = NULL; -+ } -+ ptr->p[cur_idx] = cur_pkt; -+ ptr->pend_pkts++; -+ -+ ptr->cur_idx = cur_idx; -+ ptr->exp_idx = exp_idx; -+ -+ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, -+ cur_idx, exp_idx); -+ ptr->pend_pkts -= (uint8)cnt; -+ *pkt_count = cnt; -+ DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n", -+ __FUNCTION__, cnt, ptr->pend_pkts)); -+ } -+ else { -+ uint8 end_idx; -+ bool flush_current = FALSE; -+ /* both cur and exp are moved now .. */ -+ DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", -+ __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, -+ ptr->exp_idx, exp_idx)); -+ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) -+ end_idx = ptr->exp_idx; -+ else -+ end_idx = exp_idx; -+ -+ /* flush pkts first */ -+ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, -+ ptr->exp_idx, end_idx); -+ -+ if (cur_idx == ptr->max_idx) { -+ if (exp_idx == 0) -+ flush_current = TRUE; -+ } else { -+ if (exp_idx == cur_idx + 1) -+ flush_current = TRUE; -+ } -+ if (flush_current) { -+ if (plast) -+ PKTSETNEXT(dhd->osh, plast, cur_pkt); -+ else -+ *pkt = cur_pkt; -+ cnt++; -+ } -+ else { -+ ptr->p[cur_idx] = cur_pkt; -+ ptr->pend_pkts++; -+ } -+ ptr->exp_idx = exp_idx; -+ ptr->cur_idx = cur_idx; -+ *pkt_count = cnt; -+ } -+ } -+ else { -+ uint8 end_idx; -+ /* no real packet but update to exp_seq...that means explicit window move */ -+ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; -+ -+ DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", -+ __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx)); -+ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) -+ end_idx = ptr->exp_idx; -+ else -+ end_idx = exp_idx; -+ -+ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); -+ ptr->pend_pkts -= (uint8)cnt; -+ if (plast) -+ PKTSETNEXT(dhd->osh, plast, cur_pkt); -+ else -+ *pkt = cur_pkt; -+ cnt++; -+ *pkt_count = cnt; -+ /* set the new expected idx */ -+ ptr->exp_idx = exp_idx; -+ } -+ return 0; -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c -new file mode 100644 -index 00000000..03671c46 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c -@@ -0,0 +1,678 @@ -+/* -+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ -+ */ -+ -+#include <net/rtnetlink.h> -+ -+#include <bcmutils.h> -+#include <wldev_common.h> -+#include <wl_cfg80211.h> -+#include <dhd_cfg80211.h> -+ -+#ifdef PKT_FILTER_SUPPORT -+#include <dngl_stats.h> -+#include <dhd.h> -+#endif -+ -+extern struct wl_priv *wlcfg_drv_priv; -+ -+#ifdef PKT_FILTER_SUPPORT -+extern uint dhd_pkt_filter_enable; -+extern uint dhd_master_mode; -+extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -+#endif -+ -+static int dhd_dongle_up = FALSE; -+ -+#include <dngl_stats.h> -+#include <dhd.h> -+#include <dhdioctl.h> -+#include <wlioctl.h> -+#include <dhd_cfg80211.h> -+ -+static s32 wl_dongle_up(struct net_device *ndev, u32 up); -+ -+/** -+ * Function implementations -+ */ -+ -+s32 dhd_cfg80211_init(struct wl_priv *wl) -+{ -+ dhd_dongle_up = FALSE; -+ return 0; -+} -+ -+s32 dhd_cfg80211_deinit(struct wl_priv *wl) -+{ -+ dhd_dongle_up = FALSE; -+ return 0; -+} -+ -+s32 dhd_cfg80211_down(struct wl_priv *wl) -+{ -+ dhd_dongle_up = FALSE; -+ return 0; -+} -+ -+s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) -+{ -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+ dhd->op_mode |= val; -+ WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); -+#ifdef ARP_OFFLOAD_SUPPORT -+ if (dhd->arp_version == 1) { -+ /* IF P2P is enabled, disable arpoe */ -+ dhd_arp_offload_set(dhd, 0); -+ dhd_arp_offload_enable(dhd, false); -+ } -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+ return 0; -+} -+ -+s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) -+{ -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+ dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); -+ WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+ if (dhd->arp_version == 1) { -+ /* IF P2P is disabled, enable arpoe back for STA mode. */ -+ dhd_arp_offload_set(dhd, dhd_arp_mode); -+ dhd_arp_offload_enable(dhd, true); -+ } -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+ return 0; -+} -+ -+static s32 wl_dongle_up(struct net_device *ndev, u32 up) -+{ -+ s32 err = 0; -+ -+ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_UP error (%d)\n", err)); -+ } -+ return err; -+} -+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) -+{ -+#ifndef DHD_SDALIGN -+#define DHD_SDALIGN 32 -+#endif -+ struct net_device *ndev; -+ s32 err = 0; -+ -+ WL_TRACE(("In\n")); -+ if (dhd_dongle_up) { -+ WL_ERR(("Dongle is already up\n")); -+ return err; -+ } -+ -+ ndev = wl_to_prmry_ndev(wl); -+ -+ if (need_lock) -+ rtnl_lock(); -+ -+ err = wl_dongle_up(ndev, 0); -+ if (unlikely(err)) { -+ WL_ERR(("wl_dongle_up failed\n")); -+ goto default_conf_out; -+ } -+ dhd_dongle_up = true; -+ -+default_conf_out: -+ if (need_lock) -+ rtnl_unlock(); -+ return err; -+ -+} -+ -+ -+/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ -+#define COEX_DHCP -+ -+#if defined(COEX_DHCP) -+ -+/* use New SCO/eSCO smart YG suppression */ -+#define BT_DHCP_eSCO_FIX -+/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ -+#define BT_DHCP_USE_FLAGS -+/* T1 start SCO/ESCo priority suppression */ -+#define BT_DHCP_OPPR_WIN_TIME 2500 -+/* T2 turn off SCO/SCO supperesion is (timeout) */ -+#define BT_DHCP_FLAG_FORCE_TIME 5500 -+ -+enum wl_cfg80211_btcoex_status { -+ BT_DHCP_IDLE, -+ BT_DHCP_START, -+ BT_DHCP_OPPR_WIN, -+ BT_DHCP_FLAG_FORCE_TIMEOUT -+}; -+ -+/* -+ * get named driver variable to uint register value and return error indication -+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) -+ */ -+static int -+dev_wlc_intvar_get_reg(struct net_device *dev, char *name, -+ uint reg, int *retval) -+{ -+ union { -+ char buf[WLC_IOCTL_SMLEN]; -+ int val; -+ } var; -+ int error; -+ -+ bcm_mkiovar(name, (char *)(®), sizeof(reg), -+ (char *)(&var), sizeof(var.buf)); -+ error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); -+ -+ *retval = dtoh32(var.val); -+ return (error); -+} -+ -+static int -+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) -+{ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) -+ char ioctlbuf_local[1024]; -+#else -+ static char ioctlbuf_local[1024]; -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ -+ -+ bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); -+ -+ return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); -+} -+/* -+get named driver variable to uint register value and return error indication -+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) -+*/ -+static int -+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) -+{ -+ char reg_addr[8]; -+ -+ memset(reg_addr, 0, sizeof(reg_addr)); -+ memcpy((char *)®_addr[0], (char *)addr, 4); -+ memcpy((char *)®_addr[4], (char *)val, 4); -+ -+ return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); -+} -+ -+static bool btcoex_is_sco_active(struct net_device *dev) -+{ -+ int ioc_res = 0; -+ bool res = FALSE; -+ int sco_id_cnt = 0; -+ int param27; -+ int i; -+ -+ for (i = 0; i < 12; i++) { -+ -+ ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); -+ -+ WL_TRACE(("%s, sample[%d], btc params: 27:%x\n", -+ __FUNCTION__, i, param27)); -+ -+ if (ioc_res < 0) { -+ WL_ERR(("%s ioc read btc params error\n", __FUNCTION__)); -+ break; -+ } -+ -+ if ((param27 & 0x6) == 2) { /* count both sco & esco */ -+ sco_id_cnt++; -+ } -+ -+ if (sco_id_cnt > 2) { -+ WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", -+ __FUNCTION__, sco_id_cnt, i)); -+ res = TRUE; -+ break; -+ } -+ -+ msleep(5); -+ } -+ -+ return res; -+} -+ -+#if defined(BT_DHCP_eSCO_FIX) -+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ -+static int set_btc_esco_params(struct net_device *dev, bool trump_sco) -+{ -+ static bool saved_status = FALSE; -+ -+ char buf_reg50va_dhcp_on[8] = -+ { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; -+ char buf_reg51va_dhcp_on[8] = -+ { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; -+ char buf_reg64va_dhcp_on[8] = -+ { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; -+ char buf_reg65va_dhcp_on[8] = -+ { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; -+ char buf_reg71va_dhcp_on[8] = -+ { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; -+ uint32 regaddr; -+ static uint32 saved_reg50; -+ static uint32 saved_reg51; -+ static uint32 saved_reg64; -+ static uint32 saved_reg65; -+ static uint32 saved_reg71; -+ -+ if (trump_sco) { -+ /* this should reduce eSCO agressive retransmit -+ * w/o breaking it -+ */ -+ -+ /* 1st save current */ -+ WL_TRACE(("Do new SCO/eSCO coex algo {save &" -+ "override}\n")); -+ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && -+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && -+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && -+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && -+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { -+ saved_status = TRUE; -+ WL_TRACE(("%s saved bt_params[50,51,64,65,71]:" -+ "0x%x 0x%x 0x%x 0x%x 0x%x\n", -+ __FUNCTION__, saved_reg50, saved_reg51, -+ saved_reg64, saved_reg65, saved_reg71)); -+ } else { -+ WL_ERR((":%s: save btc_params failed\n", -+ __FUNCTION__)); -+ saved_status = FALSE; -+ return -1; -+ } -+ -+ WL_TRACE(("override with [50,51,64,65,71]:" -+ "0x%x 0x%x 0x%x 0x%x 0x%x\n", -+ *(u32 *)(buf_reg50va_dhcp_on+4), -+ *(u32 *)(buf_reg51va_dhcp_on+4), -+ *(u32 *)(buf_reg64va_dhcp_on+4), -+ *(u32 *)(buf_reg65va_dhcp_on+4), -+ *(u32 *)(buf_reg71va_dhcp_on+4))); -+ -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg50va_dhcp_on[0], 8); -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg51va_dhcp_on[0], 8); -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg64va_dhcp_on[0], 8); -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg65va_dhcp_on[0], 8); -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg71va_dhcp_on[0], 8); -+ -+ saved_status = TRUE; -+ } else if (saved_status) { -+ /* restore previously saved bt params */ -+ WL_TRACE(("Do new SCO/eSCO coex algo {save &" -+ "override}\n")); -+ -+ regaddr = 50; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg50); -+ regaddr = 51; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg51); -+ regaddr = 64; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg64); -+ regaddr = 65; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg65); -+ regaddr = 71; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg71); -+ -+ WL_TRACE(("restore bt_params[50,51,64,65,71]:" -+ "0x%x 0x%x 0x%x 0x%x 0x%x\n", -+ saved_reg50, saved_reg51, saved_reg64, -+ saved_reg65, saved_reg71)); -+ -+ saved_status = FALSE; -+ } else { -+ WL_ERR((":%s att to restore not saved BTCOEX params\n", -+ __FUNCTION__)); -+ return -1; -+ } -+ return 0; -+} -+#endif /* BT_DHCP_eSCO_FIX */ -+ -+static void -+wl_cfg80211_bt_setflag(struct net_device *dev, bool set) -+{ -+#if defined(BT_DHCP_USE_FLAGS) -+ char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; -+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -+#endif -+ -+ -+#if defined(BT_DHCP_eSCO_FIX) -+ /* set = 1, save & turn on 0 - off & restore prev settings */ -+ set_btc_esco_params(dev, set); -+#endif -+ -+#if defined(BT_DHCP_USE_FLAGS) -+ WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); -+ if (set == TRUE) -+ /* Forcing bt_flag7 */ -+ dev_wlc_bufvar_set(dev, "btc_flags", -+ (char *)&buf_flag7_dhcp_on[0], -+ sizeof(buf_flag7_dhcp_on)); -+ else -+ /* Restoring default bt flag7 */ -+ dev_wlc_bufvar_set(dev, "btc_flags", -+ (char *)&buf_flag7_default[0], -+ sizeof(buf_flag7_default)); -+#endif -+} -+ -+static void wl_cfg80211_bt_timerfunc(ulong data) -+{ -+ struct btcoex_info *bt_local = (struct btcoex_info *)data; -+ WL_TRACE(("%s\n", __FUNCTION__)); -+ bt_local->timer_on = 0; -+ schedule_work(&bt_local->work); -+} -+ -+static void wl_cfg80211_bt_handler(struct work_struct *work) -+{ -+ struct btcoex_info *btcx_inf; -+ -+ btcx_inf = container_of(work, struct btcoex_info, work); -+ -+ if (btcx_inf->timer_on) { -+ btcx_inf->timer_on = 0; -+ del_timer_sync(&btcx_inf->timer); -+ } -+ -+ switch (btcx_inf->bt_state) { -+ case BT_DHCP_START: -+ /* DHCP started -+ * provide OPPORTUNITY window to get DHCP address -+ */ -+ WL_TRACE(("%s bt_dhcp stm: started \n", -+ __FUNCTION__)); -+ btcx_inf->bt_state = BT_DHCP_OPPR_WIN; -+ mod_timer(&btcx_inf->timer, -+ jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); -+ btcx_inf->timer_on = 1; -+ break; -+ -+ case BT_DHCP_OPPR_WIN: -+ if (btcx_inf->dhcp_done) { -+ WL_TRACE(("%s DHCP Done before T1 expiration\n", -+ __FUNCTION__)); -+ goto btc_coex_idle; -+ } -+ -+ /* DHCP is not over yet, start lowering BT priority -+ * enforce btc_params + flags if necessary -+ */ -+ WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__, -+ BT_DHCP_OPPR_WIN_TIME)); -+ if (btcx_inf->dev) -+ wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); -+ btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; -+ mod_timer(&btcx_inf->timer, -+ jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); -+ btcx_inf->timer_on = 1; -+ break; -+ -+ case BT_DHCP_FLAG_FORCE_TIMEOUT: -+ if (btcx_inf->dhcp_done) { -+ WL_TRACE(("%s DHCP Done before T2 expiration\n", -+ __FUNCTION__)); -+ } else { -+ /* Noo dhcp during T1+T2, restore BT priority */ -+ WL_TRACE(("%s DHCP wait interval T2:%d" -+ "msec expired\n", __FUNCTION__, -+ BT_DHCP_FLAG_FORCE_TIME)); -+ } -+ -+ /* Restoring default bt priority */ -+ if (btcx_inf->dev) -+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -+btc_coex_idle: -+ btcx_inf->bt_state = BT_DHCP_IDLE; -+ btcx_inf->timer_on = 0; -+ break; -+ -+ default: -+ WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__, -+ btcx_inf->bt_state)); -+ if (btcx_inf->dev) -+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -+ btcx_inf->bt_state = BT_DHCP_IDLE; -+ btcx_inf->timer_on = 0; -+ break; -+ } -+ -+ net_os_wake_unlock(btcx_inf->dev); -+} -+ -+int wl_cfg80211_btcoex_init(struct wl_priv *wl) -+{ -+ struct btcoex_info *btco_inf = NULL; -+ -+ btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); -+ if (!btco_inf) -+ return -ENOMEM; -+ -+ btco_inf->bt_state = BT_DHCP_IDLE; -+ btco_inf->ts_dhcp_start = 0; -+ btco_inf->ts_dhcp_ok = 0; -+ /* Set up timer for BT */ -+ btco_inf->timer_ms = 10; -+ init_timer(&btco_inf->timer); -+ btco_inf->timer.data = (ulong)btco_inf; -+ btco_inf->timer.function = wl_cfg80211_bt_timerfunc; -+ -+ btco_inf->dev = wl->wdev->netdev; -+ -+ INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); -+ -+ wl->btcoex_info = btco_inf; -+ return 0; -+} -+ -+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) -+{ -+ if (!wl->btcoex_info) -+ return; -+ -+ if (wl->btcoex_info->timer_on) { -+ wl->btcoex_info->timer_on = 0; -+ del_timer_sync(&wl->btcoex_info->timer); -+ } -+ -+ cancel_work_sync(&wl->btcoex_info->work); -+ -+ kfree(wl->btcoex_info); -+ wl->btcoex_info = NULL; -+} -+#endif -+ -+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) -+{ -+ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ char powermode_val = 0; -+ char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; -+ char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; -+ char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; -+ -+ uint32 regaddr; -+ static uint32 saved_reg66; -+ static uint32 saved_reg41; -+ static uint32 saved_reg68; -+ static bool saved_status = FALSE; -+ -+#ifdef COEX_DHCP -+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -+ struct btcoex_info *btco_inf = wl->btcoex_info; -+#endif /* COEX_DHCP */ -+ -+#ifdef PKT_FILTER_SUPPORT -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+#endif -+ -+ /* Figure out powermode 1 or o command */ -+ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); -+ -+ if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { -+ WL_TRACE_HW4(("%s: DHCP session starts\n", __FUNCTION__)); -+ -+#if defined(DHCP_SCAN_SUPPRESS) -+ /* Suppress scan during the DHCP */ -+ wl_cfg80211_scan_suppress(dev, 1); -+#endif -+ -+#ifdef PKT_FILTER_SUPPORT -+ dhd->dhcp_in_progress = 1; -+ -+ if (dhd->early_suspended) { -+ WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); -+ dhd_enable_packet_filter(0, dhd); -+ } -+#endif -+ -+ /* Retrieve and saved orig regs value */ -+ if ((saved_status == FALSE) && -+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && -+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && -+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { -+ saved_status = TRUE; -+ WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", -+ saved_reg66, saved_reg41, saved_reg68)); -+ -+ /* Disable PM mode during dhpc session */ -+ -+ /* Disable PM mode during dhpc session */ -+#ifdef COEX_DHCP -+ /* Start BT timer only for SCO connection */ -+ if (btcoex_is_sco_active(dev)) { -+ /* btc_params 66 */ -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg66va_dhcp_on[0], -+ sizeof(buf_reg66va_dhcp_on)); -+ /* btc_params 41 0x33 */ -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg41va_dhcp_on[0], -+ sizeof(buf_reg41va_dhcp_on)); -+ /* btc_params 68 0x190 */ -+ dev_wlc_bufvar_set(dev, "btc_params", -+ (char *)&buf_reg68va_dhcp_on[0], -+ sizeof(buf_reg68va_dhcp_on)); -+ saved_status = TRUE; -+ -+ btco_inf->bt_state = BT_DHCP_START; -+ btco_inf->timer_on = 1; -+ mod_timer(&btco_inf->timer, btco_inf->timer.expires); -+ WL_TRACE(("%s enable BT DHCP Timer\n", -+ __FUNCTION__)); -+ } -+#endif /* COEX_DHCP */ -+ } -+ else if (saved_status == TRUE) { -+ WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); -+ } -+ } -+ else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { -+ -+ -+#ifdef PKT_FILTER_SUPPORT -+ dhd->dhcp_in_progress = 0; -+ WL_TRACE_HW4(("%s: DHCP is complete \n", __FUNCTION__)); -+ -+#if defined(DHCP_SCAN_SUPPRESS) -+ /* Since DHCP is complete, enable the scan back */ -+ wl_cfg80211_scan_suppress(dev, 0); -+#endif -+ -+ /* Enable packet filtering */ -+ if (dhd->early_suspended) { -+ WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); -+ dhd_enable_packet_filter(1, dhd); -+ } -+#endif /* PKT_FILTER_SUPPORT */ -+ -+ /* Restoring PM mode */ -+ -+#ifdef COEX_DHCP -+ /* Stop any bt timer because DHCP session is done */ -+ WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); -+ if (btco_inf->timer_on) { -+ btco_inf->timer_on = 0; -+ del_timer_sync(&btco_inf->timer); -+ -+ if (btco_inf->bt_state != BT_DHCP_IDLE) { -+ /* need to restore original btc flags & extra btc params */ -+ WL_TRACE(("%s bt->bt_state:%d\n", -+ __FUNCTION__, btco_inf->bt_state)); -+ /* wake up btcoex thread to restore btlags+params */ -+ schedule_work(&btco_inf->work); -+ } -+ } -+ -+ /* Restoring btc_flag paramter anyway */ -+ if (saved_status == TRUE) -+ dev_wlc_bufvar_set(dev, "btc_flags", -+ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); -+#endif /* COEX_DHCP */ -+ -+ /* Restore original values */ -+ if (saved_status == TRUE) { -+ regaddr = 66; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg66); -+ regaddr = 41; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg41); -+ regaddr = 68; -+ dev_wlc_intvar_set_reg(dev, "btc_params", -+ (char *)®addr, (char *)&saved_reg68); -+ -+ WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", -+ saved_reg66, saved_reg41, saved_reg68)); -+ } -+ saved_status = FALSE; -+ -+ } -+ else { -+ WL_ERR(("%s Unkwown yet power setting, ignored\n", -+ __FUNCTION__)); -+ } -+ -+ snprintf(command, 3, "OK"); -+ -+ return (strlen("OK")); -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h -new file mode 100644 -index 00000000..922d6edd ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h -@@ -0,0 +1,44 @@ -+/* -+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ -+ */ -+ -+ -+#ifndef __DHD_CFG80211__ -+#define __DHD_CFG80211__ -+ -+#include <wl_cfg80211.h> -+#include <wl_cfgp2p.h> -+ -+s32 dhd_cfg80211_init(struct wl_priv *wl); -+s32 dhd_cfg80211_deinit(struct wl_priv *wl); -+s32 dhd_cfg80211_down(struct wl_priv *wl); -+s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val); -+s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl); -+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock); -+ -+int wl_cfg80211_btcoex_init(struct wl_priv *wl); -+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); -+ -+#endif /* __DHD_CFG80211__ */ -diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c -new file mode 100644 -index 00000000..bb765562 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_common.c -@@ -0,0 +1,2205 @@ -+/* -+ * Broadcom Dongle Host Driver (DHD), common DHD core. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_common.c 375022 2012-12-17 06:11:41Z $ -+ */ -+#include <typedefs.h> -+#include <osl.h> -+ -+#include <epivers.h> -+#include <bcmutils.h> -+ -+#include <bcmendian.h> -+#include <dngl_stats.h> -+#include <wlioctl.h> -+#include <dhd.h> -+ -+#include <proto/bcmevent.h> -+ -+#include <dhd_bus.h> -+#include <dhd_proto.h> -+#include <dhd_dbg.h> -+#include <msgtrace.h> -+ -+#ifdef WL_CFG80211 -+#include <wl_cfg80211.h> -+#endif -+#ifdef WLBTAMP -+#include <proto/bt_amp_hci.h> -+#include <dhd_bta.h> -+#endif -+#ifdef SET_RANDOM_MAC_SOFTAP -+#include <linux/random.h> -+#include <linux/jiffies.h> -+#endif -+ -+#define htod32(i) i -+#define htod16(i) i -+#define dtoh32(i) i -+#define dtoh16(i) i -+#define htodchanspec(i) i -+#define dtohchanspec(i) i -+ -+#ifdef PROP_TXSTATUS -+#include <wlfc_proto.h> -+#include <dhd_wlfc.h> -+#endif -+ -+ -+#ifdef WLMEDIA_HTSF -+extern void htsf_update(struct dhd_info *dhd, void *data); -+#endif -+int dhd_msg_level = DHD_ERROR_VAL; -+ -+ -+#include <wl_iw.h> -+ -+char fw_path[MOD_PARAM_PATHLEN]; -+char nv_path[MOD_PARAM_PATHLEN]; -+ -+#ifdef SOFTAP -+char fw_path2[MOD_PARAM_PATHLEN]; -+extern bool softap_enabled; -+#endif -+ -+/* Last connection success/failure status */ -+uint32 dhd_conn_event; -+uint32 dhd_conn_status; -+uint32 dhd_conn_reason; -+ -+extern int dhd_iscan_request(void * dhdp, uint16 action); -+extern void dhd_ind_scan_confirm(void *h, bool status); -+extern int dhd_iscan_in_progress(void *h); -+void dhd_iscan_lock(void); -+void dhd_iscan_unlock(void); -+extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); -+#if !defined(AP) && defined(WLP2P) -+extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); -+#endif -+bool ap_cfg_running = FALSE; -+bool ap_fw_loaded = FALSE; -+ -+ -+#ifdef DHD_DEBUG -+const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " -+ __DATE__ " at " __TIME__; -+#else -+const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; -+#endif -+ -+void dhd_set_timer(void *bus, uint wdtick); -+ -+/* IOVar table */ -+enum { -+ IOV_VERSION = 1, -+ IOV_MSGLEVEL, -+ IOV_BCMERRORSTR, -+ IOV_BCMERROR, -+ IOV_WDTICK, -+ IOV_DUMP, -+ IOV_CLEARCOUNTS, -+ IOV_LOGDUMP, -+ IOV_LOGCAL, -+ IOV_LOGSTAMP, -+ IOV_GPIOOB, -+ IOV_IOCTLTIMEOUT, -+#ifdef WLBTAMP -+ IOV_HCI_CMD, /* HCI command */ -+ IOV_HCI_ACL_DATA, /* HCI data packet */ -+#endif -+#if defined(DHD_DEBUG) -+ IOV_CONS, -+ IOV_DCONSOLE_POLL, -+#endif /* defined(DHD_DEBUG) */ -+#ifdef PROP_TXSTATUS -+ IOV_PROPTXSTATUS_ENABLE, -+ IOV_PROPTXSTATUS_MODE, -+#endif -+ IOV_BUS_TYPE, -+#ifdef WLMEDIA_HTSF -+ IOV_WLPKTDLYSTAT_SZ, -+#endif -+ IOV_CHANGEMTU, -+ IOV_HOSTREORDER_FLOWS, -+ IOV_LAST -+}; -+ -+const bcm_iovar_t dhd_iovars[] = { -+ {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, -+#ifdef DHD_DEBUG -+ {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, -+#endif /* DHD_DEBUG */ -+ {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, -+ {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, -+ {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, -+ {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, -+#ifdef DHD_DEBUG -+ {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, -+ {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, -+#endif -+ {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, -+ {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, -+ {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, -+#ifdef WLBTAMP -+ {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0}, -+ {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0}, -+#endif -+#ifdef PROP_TXSTATUS -+ {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 }, -+ /* -+ set the proptxtstatus operation mode: -+ 0 - Do not do any proptxtstatus flow control -+ 1 - Use implied credit from a packet status -+ 2 - Use explicit credit -+ */ -+ {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, -+#endif -+ {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, -+#ifdef WLMEDIA_HTSF -+ {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, -+#endif -+ {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, -+ {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, -+ (WLHOST_REORDERDATA_MAXFLOWS + 1) }, -+ {NULL, 0, 0, 0, 0 } -+}; -+ -+void -+dhd_common_init(osl_t *osh) -+{ -+#ifdef CONFIG_BCMDHD_FW_PATH -+ bcm_strncpy_s(fw_path, sizeof(fw_path), CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1); -+#else /* CONFIG_BCMDHD_FW_PATH */ -+ fw_path[0] = '\0'; -+#endif /* CONFIG_BCMDHD_FW_PATH */ -+#ifdef CONFIG_BCMDHD_NVRAM_PATH -+ bcm_strncpy_s(nv_path, sizeof(nv_path), CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1); -+#else /* CONFIG_BCMDHD_NVRAM_PATH */ -+ nv_path[0] = '\0'; -+#endif /* CONFIG_BCMDHD_NVRAM_PATH */ -+#ifdef SOFTAP -+ fw_path2[0] = '\0'; -+#endif -+} -+ -+static int -+dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) -+{ -+ char eabuf[ETHER_ADDR_STR_LEN]; -+ -+ struct bcmstrbuf b; -+ struct bcmstrbuf *strbuf = &b; -+ -+ bcm_binit(strbuf, buf, buflen); -+ -+ /* Base DHD info */ -+ bcm_bprintf(strbuf, "%s\n", dhd_version); -+ bcm_bprintf(strbuf, "\n"); -+ bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", -+ dhdp->up, dhdp->txoff, dhdp->busstate); -+ bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n", -+ dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); -+ bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", -+ dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); -+ bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt); -+ -+ bcm_bprintf(strbuf, "dongle stats:\n"); -+ bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n", -+ dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, -+ dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); -+ bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", -+ dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, -+ dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); -+ bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast); -+ -+ bcm_bprintf(strbuf, "bus stats:\n"); -+ bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", -+ dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); -+ bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", -+ dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); -+ bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", -+ dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); -+ bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n", -+ dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); -+ bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n", -+ dhdp->rx_readahead_cnt, dhdp->tx_realloc); -+ bcm_bprintf(strbuf, "\n"); -+ -+ /* Add any prot info */ -+ dhd_prot_dump(dhdp, strbuf); -+ bcm_bprintf(strbuf, "\n"); -+ -+ /* Add any bus info */ -+ dhd_bus_dump(dhdp, strbuf); -+ -+ return (!strbuf->size ? BCME_BUFTOOSHORT : 0); -+} -+ -+int -+dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) -+{ -+ wl_ioctl_t ioc; -+ -+ ioc.cmd = cmd; -+ ioc.buf = arg; -+ ioc.len = len; -+ ioc.set = set; -+ -+ return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); -+} -+ -+ -+int -+dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) -+{ -+ int ret; -+ -+ dhd_os_proto_block(dhd_pub); -+ -+ ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); -+ if ((ret) && (dhd_pub->up)) -+ /* Send hang event only if dhd_open() was success */ -+ dhd_os_check_hang(dhd_pub, ifindex, ret); -+ -+ dhd_os_proto_unblock(dhd_pub); -+ -+ return ret; -+} -+ -+static int -+dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, -+ void *params, int plen, void *arg, int len, int val_size) -+{ -+ int bcmerror = 0; -+ int32 int_val = 0; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); -+ -+ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) -+ goto exit; -+ -+ if (plen >= (int)sizeof(int_val)) -+ bcopy(params, &int_val, sizeof(int_val)); -+ -+ switch (actionid) { -+ case IOV_GVAL(IOV_VERSION): -+ /* Need to have checked buffer length */ -+ bcm_strncpy_s((char*)arg, len, dhd_version, len); -+ break; -+ -+ case IOV_GVAL(IOV_MSGLEVEL): -+ int_val = (int32)dhd_msg_level; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_MSGLEVEL): -+#ifdef WL_CFG80211 -+ /* Enable DHD and WL logs in oneshot */ -+ if (int_val & DHD_WL_VAL2) -+ wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2)); -+ else if (int_val & DHD_WL_VAL) -+ wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG); -+ if (!(int_val & DHD_WL_VAL2)) -+#endif /* WL_CFG80211 */ -+ dhd_msg_level = int_val; -+ break; -+ case IOV_GVAL(IOV_BCMERRORSTR): -+ bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); -+ ((char *)arg)[BCME_STRLEN - 1] = 0x00; -+ break; -+ -+ case IOV_GVAL(IOV_BCMERROR): -+ int_val = (int32)dhd_pub->bcmerror; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_GVAL(IOV_WDTICK): -+ int_val = (int32)dhd_watchdog_ms; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_WDTICK): -+ if (!dhd_pub->up) { -+ bcmerror = BCME_NOTUP; -+ break; -+ } -+ dhd_os_wd_timer(dhd_pub, (uint)int_val); -+ break; -+ -+ case IOV_GVAL(IOV_DUMP): -+ bcmerror = dhd_dump(dhd_pub, arg, len); -+ break; -+ -+#ifdef DHD_DEBUG -+ case IOV_GVAL(IOV_DCONSOLE_POLL): -+ int_val = (int32)dhd_console_ms; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_DCONSOLE_POLL): -+ dhd_console_ms = (uint)int_val; -+ break; -+ -+ case IOV_SVAL(IOV_CONS): -+ if (len > 0) -+ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); -+ break; -+#endif /* DHD_DEBUG */ -+ -+ case IOV_SVAL(IOV_CLEARCOUNTS): -+ dhd_pub->tx_packets = dhd_pub->rx_packets = 0; -+ dhd_pub->tx_errors = dhd_pub->rx_errors = 0; -+ dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; -+ dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; -+ dhd_pub->rx_dropped = 0; -+ dhd_pub->rx_readahead_cnt = 0; -+ dhd_pub->tx_realloc = 0; -+ dhd_pub->wd_dpc_sched = 0; -+ memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); -+ dhd_bus_clearcounts(dhd_pub); -+#ifdef PROP_TXSTATUS -+ /* clear proptxstatus related counters */ -+ if (dhd_pub->wlfc_state) { -+ athost_wl_status_info_t *wlfc = -+ (athost_wl_status_info_t*)dhd_pub->wlfc_state; -+ wlfc_hanger_t* hanger; -+ -+ memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); -+ -+ hanger = (wlfc_hanger_t*)wlfc->hanger; -+ hanger->pushed = 0; -+ hanger->popped = 0; -+ hanger->failed_slotfind = 0; -+ hanger->failed_to_pop = 0; -+ hanger->failed_to_push = 0; -+ } -+#endif /* PROP_TXSTATUS */ -+ break; -+ -+ -+ case IOV_GVAL(IOV_IOCTLTIMEOUT): { -+ int_val = (int32)dhd_os_get_ioctl_resp_timeout(); -+ bcopy(&int_val, arg, sizeof(int_val)); -+ break; -+ } -+ -+ case IOV_SVAL(IOV_IOCTLTIMEOUT): { -+ if (int_val <= 0) -+ bcmerror = BCME_BADARG; -+ else -+ dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); -+ break; -+ } -+ -+#ifdef WLBTAMP -+ case IOV_SVAL(IOV_HCI_CMD): { -+ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg; -+ -+ /* sanity check: command preamble present */ -+ if (len < HCI_CMD_PREAMBLE_SIZE) -+ return BCME_BUFTOOSHORT; -+ -+ /* sanity check: command parameters are present */ -+ if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen)) -+ return BCME_BUFTOOSHORT; -+ -+ dhd_bta_docmd(dhd_pub, cmd, len); -+ break; -+ } -+ -+ case IOV_SVAL(IOV_HCI_ACL_DATA): { -+ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg; -+ -+ /* sanity check: HCI header present */ -+ if (len < HCI_ACL_DATA_PREAMBLE_SIZE) -+ return BCME_BUFTOOSHORT; -+ -+ /* sanity check: ACL data is present */ -+ if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen)) -+ return BCME_BUFTOOSHORT; -+ -+ dhd_bta_tx_hcidata(dhd_pub, ACL_data, len); -+ break; -+ } -+#endif /* WLBTAMP */ -+ -+#ifdef PROP_TXSTATUS -+ case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): -+ int_val = dhd_pub->wlfc_enabled? 1 : 0; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): -+ dhd_pub->wlfc_enabled = int_val? 1 : 0; -+ break; -+ -+ case IOV_GVAL(IOV_PROPTXSTATUS_MODE): { -+ athost_wl_status_info_t *wlfc = -+ (athost_wl_status_info_t*)dhd_pub->wlfc_state; -+ int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0; -+ bcopy(&int_val, arg, val_size); -+ break; -+ } -+ -+ case IOV_SVAL(IOV_PROPTXSTATUS_MODE): -+ if (dhd_pub->wlfc_state) { -+ athost_wl_status_info_t *wlfc = -+ (athost_wl_status_info_t*)dhd_pub->wlfc_state; -+ wlfc->proptxstatus_mode = int_val & 0xff; -+ } -+ break; -+#endif /* PROP_TXSTATUS */ -+ -+ case IOV_GVAL(IOV_BUS_TYPE): -+ /* The dhd application queries the driver to check if its usb or sdio. */ -+#ifdef BCMDHDUSB -+ int_val = BUS_TYPE_USB; -+#endif -+ int_val = BUS_TYPE_SDIO; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ -+#ifdef WLMEDIA_HTSF -+ case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): -+ int_val = dhd_pub->htsfdlystat_sz; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): -+ dhd_pub->htsfdlystat_sz = int_val & 0xff; -+ printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); -+ break; -+#endif -+ case IOV_SVAL(IOV_CHANGEMTU): -+ int_val &= 0xffff; -+ bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); -+ break; -+ -+ case IOV_GVAL(IOV_HOSTREORDER_FLOWS): -+ { -+ uint i = 0; -+ uint8 *ptr = (uint8 *)arg; -+ uint8 count = 0; -+ -+ ptr++; -+ for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { -+ if (dhd_pub->reorder_bufs[i] != NULL) { -+ *ptr = dhd_pub->reorder_bufs[i]->flow_id; -+ ptr++; -+ count++; -+ } -+ } -+ ptr = (uint8 *)arg; -+ *ptr = count; -+ break; -+ } -+ -+ default: -+ bcmerror = BCME_UNSUPPORTED; -+ break; -+ } -+ -+exit: -+ DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); -+ return bcmerror; -+} -+ -+/* Store the status of a connection attempt for later retrieval by an iovar */ -+void -+dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) -+{ -+ /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID -+ * because an encryption/rsn mismatch results in both events, and -+ * the important information is in the WLC_E_PRUNE. -+ */ -+ if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && -+ dhd_conn_event == WLC_E_PRUNE)) { -+ dhd_conn_event = event; -+ dhd_conn_status = status; -+ dhd_conn_reason = reason; -+ } -+} -+ -+bool -+dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) -+{ -+ void *p; -+ int eprec = -1; /* precedence to evict from */ -+ bool discard_oldest; -+ -+ /* Fast case, precedence queue is not full and we are also not -+ * exceeding total queue length -+ */ -+ if (!pktq_pfull(q, prec) && !pktq_full(q)) { -+ pktq_penq(q, prec, pkt); -+ return TRUE; -+ } -+ -+ /* Determine precedence from which to evict packet, if any */ -+ if (pktq_pfull(q, prec)) -+ eprec = prec; -+ else if (pktq_full(q)) { -+ pktq_peek_tail(q, &eprec); -+ if (eprec > prec || eprec < 0) -+ return FALSE; -+ } -+ -+ /* Evict if needed */ -+ if (eprec >= 0) { -+ /* Detect queueing to unconfigured precedence */ -+ ASSERT(!pktq_pempty(q, eprec)); -+ discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); -+ if (eprec == prec && !discard_oldest) -+ return FALSE; /* refuse newer (incoming) packet */ -+ /* Evict packet according to discard policy */ -+ p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); -+ ASSERT(p); -+ -+ PKTFREE(dhdp->osh, p, TRUE); -+ } -+ -+ /* Enqueue */ -+ pktq_penq(q, prec, pkt); -+ -+ return TRUE; -+} -+ -+static int -+dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, -+ void *params, int plen, void *arg, int len, bool set) -+{ -+ int bcmerror = 0; -+ int val_size; -+ const bcm_iovar_t *vi = NULL; -+ uint32 actionid; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ ASSERT(name); -+ ASSERT(len >= 0); -+ -+ /* Get MUST have return space */ -+ ASSERT(set || (arg && len)); -+ -+ /* Set does NOT take qualifiers */ -+ ASSERT(!set || (!params && !plen)); -+ -+ if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { -+ bcmerror = BCME_UNSUPPORTED; -+ goto exit; -+ } -+ -+ DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, -+ name, (set ? "set" : "get"), len, plen)); -+ -+ /* set up 'params' pointer in case this is a set command so that -+ * the convenience int and bool code can be common to set and get -+ */ -+ if (params == NULL) { -+ params = arg; -+ plen = len; -+ } -+ -+ if (vi->type == IOVT_VOID) -+ val_size = 0; -+ else if (vi->type == IOVT_BUFFER) -+ val_size = len; -+ else -+ /* all other types are integer sized */ -+ val_size = sizeof(int); -+ -+ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); -+ -+ bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); -+ -+exit: -+ return bcmerror; -+} -+ -+int -+dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) -+{ -+ int bcmerror = 0; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (!buf) { -+ return BCME_BADARG; -+ } -+ -+ switch (ioc->cmd) { -+ case DHD_GET_MAGIC: -+ if (buflen < sizeof(int)) -+ bcmerror = BCME_BUFTOOSHORT; -+ else -+ *(int*)buf = DHD_IOCTL_MAGIC; -+ break; -+ -+ case DHD_GET_VERSION: -+ if (buflen < sizeof(int)) -+ bcmerror = BCME_BUFTOOSHORT; -+ else -+ *(int*)buf = DHD_IOCTL_VERSION; -+ break; -+ -+ case DHD_GET_VAR: -+ case DHD_SET_VAR: { -+ char *arg; -+ uint arglen; -+ -+ /* scan past the name to any arguments */ -+ for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) -+ ; -+ -+ if (*arg) { -+ bcmerror = BCME_BUFTOOSHORT; -+ break; -+ } -+ -+ /* account for the NUL terminator */ -+ arg++, arglen--; -+ -+ /* call with the appropriate arguments */ -+ if (ioc->cmd == DHD_GET_VAR) -+ bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, -+ buf, buflen, IOV_GET); -+ else -+ bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); -+ if (bcmerror != BCME_UNSUPPORTED) -+ break; -+ -+ /* not in generic table, try protocol module */ -+ if (ioc->cmd == DHD_GET_VAR) -+ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, -+ arglen, buf, buflen, IOV_GET); -+ else -+ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, -+ NULL, 0, arg, arglen, IOV_SET); -+ if (bcmerror != BCME_UNSUPPORTED) -+ break; -+ -+ /* if still not found, try bus module */ -+ if (ioc->cmd == DHD_GET_VAR) { -+ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, -+ arg, arglen, buf, buflen, IOV_GET); -+ } else { -+ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, -+ NULL, 0, arg, arglen, IOV_SET); -+ } -+ -+ break; -+ } -+ -+ default: -+ bcmerror = BCME_UNSUPPORTED; -+ } -+ -+ return bcmerror; -+} -+ -+#ifdef SHOW_EVENTS -+static void -+wl_show_host_event(wl_event_msg_t *event, void *event_data) -+{ -+ uint i, status, reason; -+ bool group = FALSE, flush_txq = FALSE, link = FALSE; -+ const char *auth_str; -+ const char *event_name; -+ uchar *buf; -+ char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; -+ uint event_type, flags, auth_type, datalen; -+ -+ event_type = ntoh32(event->event_type); -+ flags = ntoh16(event->flags); -+ status = ntoh32(event->status); -+ reason = ntoh32(event->reason); -+ BCM_REFERENCE(reason); -+ auth_type = ntoh32(event->auth_type); -+ datalen = ntoh32(event->datalen); -+ -+ /* debug dump of event messages */ -+ snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", -+ (uchar)event->addr.octet[0]&0xff, -+ (uchar)event->addr.octet[1]&0xff, -+ (uchar)event->addr.octet[2]&0xff, -+ (uchar)event->addr.octet[3]&0xff, -+ (uchar)event->addr.octet[4]&0xff, -+ (uchar)event->addr.octet[5]&0xff); -+ -+ event_name = "UNKNOWN"; -+ for (i = 0; i < (uint)bcmevent_names_size; i++) -+ if (bcmevent_names[i].event == event_type) -+ event_name = bcmevent_names[i].name; -+ -+ if (flags & WLC_EVENT_MSG_LINK) -+ link = TRUE; -+ if (flags & WLC_EVENT_MSG_GROUP) -+ group = TRUE; -+ if (flags & WLC_EVENT_MSG_FLUSHTXQ) -+ flush_txq = TRUE; -+ -+ switch (event_type) { -+ case WLC_E_START: -+ case WLC_E_DEAUTH: -+ case WLC_E_DISASSOC: -+ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); -+ break; -+ -+ case WLC_E_ASSOC_IND: -+ case WLC_E_REASSOC_IND: -+ -+ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); -+ break; -+ -+ case WLC_E_ASSOC: -+ case WLC_E_REASSOC: -+ if (status == WLC_E_STATUS_SUCCESS) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); -+ } else if (status == WLC_E_STATUS_TIMEOUT) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); -+ } else if (status == WLC_E_STATUS_FAIL) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", -+ event_name, eabuf, (int)reason)); -+ } else { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", -+ event_name, eabuf, (int)status)); -+ } -+ break; -+ -+ case WLC_E_DEAUTH_IND: -+ case WLC_E_DISASSOC_IND: -+ DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); -+ break; -+ -+ case WLC_E_AUTH: -+ case WLC_E_AUTH_IND: -+ if (auth_type == DOT11_OPEN_SYSTEM) -+ auth_str = "Open System"; -+ else if (auth_type == DOT11_SHARED_KEY) -+ auth_str = "Shared Key"; -+ else { -+ snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); -+ auth_str = err_msg; -+ } -+ if (event_type == WLC_E_AUTH_IND) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); -+ } else if (status == WLC_E_STATUS_SUCCESS) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", -+ event_name, eabuf, auth_str)); -+ } else if (status == WLC_E_STATUS_TIMEOUT) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", -+ event_name, eabuf, auth_str)); -+ } else if (status == WLC_E_STATUS_FAIL) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", -+ event_name, eabuf, auth_str, (int)reason)); -+ } -+ BCM_REFERENCE(auth_str); -+ -+ break; -+ -+ case WLC_E_JOIN: -+ case WLC_E_ROAM: -+ case WLC_E_SET_SSID: -+ if (status == WLC_E_STATUS_SUCCESS) { -+ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); -+ } else if (status == WLC_E_STATUS_FAIL) { -+ DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); -+ } else if (status == WLC_E_STATUS_NO_NETWORKS) { -+ DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); -+ } else { -+ DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", -+ event_name, (int)status)); -+ } -+ break; -+ -+ case WLC_E_BEACON_RX: -+ if (status == WLC_E_STATUS_SUCCESS) { -+ DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); -+ } else if (status == WLC_E_STATUS_FAIL) { -+ DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); -+ } else { -+ DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); -+ } -+ break; -+ -+ case WLC_E_LINK: -+ DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); -+ BCM_REFERENCE(link); -+ break; -+ -+ case WLC_E_MIC_ERROR: -+ DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", -+ event_name, eabuf, group, flush_txq)); -+ BCM_REFERENCE(group); -+ BCM_REFERENCE(flush_txq); -+ break; -+ -+ case WLC_E_ICV_ERROR: -+ case WLC_E_UNICAST_DECODE_ERROR: -+ case WLC_E_MULTICAST_DECODE_ERROR: -+ DHD_EVENT(("MACEVENT: %s, MAC %s\n", -+ event_name, eabuf)); -+ break; -+ -+ case WLC_E_TXFAIL: -+ DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); -+ break; -+ -+ case WLC_E_SCAN_COMPLETE: -+ case WLC_E_ASSOC_REQ_IE: -+ case WLC_E_ASSOC_RESP_IE: -+ case WLC_E_PMKID_CACHE: -+ DHD_EVENT(("MACEVENT: %s\n", event_name)); -+ break; -+ -+ case WLC_E_PFN_NET_FOUND: -+ case WLC_E_PFN_NET_LOST: -+ case WLC_E_PFN_SCAN_COMPLETE: -+ case WLC_E_PFN_SCAN_NONE: -+ case WLC_E_PFN_SCAN_ALLGONE: -+ DHD_EVENT(("PNOEVENT: %s\n", event_name)); -+ break; -+ -+ case WLC_E_PSK_SUP: -+ case WLC_E_PRUNE: -+ DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", -+ event_name, (int)status, (int)reason)); -+ break; -+ -+#ifdef WIFI_ACT_FRAME -+ case WLC_E_ACTION_FRAME: -+ DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); -+ break; -+#endif /* WIFI_ACT_FRAME */ -+ -+ case WLC_E_TRACE: { -+ static uint32 seqnum_prev = 0; -+ msgtrace_hdr_t hdr; -+ uint32 nblost; -+ char *s, *p; -+ -+ buf = (uchar *) event_data; -+ memcpy(&hdr, buf, MSGTRACE_HDRLEN); -+ -+ if (hdr.version != MSGTRACE_VERSION) { -+ printf("\nMACEVENT: %s [unsupported version --> " -+ "dhd version:%d dongle version:%d]\n", -+ event_name, MSGTRACE_VERSION, hdr.version); -+ /* Reset datalen to avoid display below */ -+ datalen = 0; -+ break; -+ } -+ -+ /* There are 2 bytes available at the end of data */ -+ buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; -+ -+ if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { -+ printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" -+ "discarded_bytes %d discarded_printf %d]\n", -+ ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); -+ } -+ -+ nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; -+ if (nblost > 0) { -+ printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", -+ ntoh32(hdr.seqnum), nblost); -+ } -+ seqnum_prev = ntoh32(hdr.seqnum); -+ -+ /* Display the trace buffer. Advance from \n to \n to avoid display big -+ * printf (issue with Linux printk ) -+ */ -+ p = (char *)&buf[MSGTRACE_HDRLEN]; -+ while ((s = strstr(p, "\n")) != NULL) { -+ *s = '\0'; -+ printf("%s\n", p); -+ p = s+1; -+ } -+ printf("%s\n", p); -+ -+ /* Reset datalen to avoid display below */ -+ datalen = 0; -+ break; -+ } -+ -+ -+ case WLC_E_RSSI: -+ DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); -+ break; -+ -+ case WLC_E_SERVICE_FOUND: -+ case WLC_E_P2PO_ADD_DEVICE: -+ case WLC_E_P2PO_DEL_DEVICE: -+ DHD_EVENT(("MACEVENT: %s, MAC: %s\n", event_name, eabuf)); -+ break; -+ -+ default: -+ DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", -+ event_name, event_type, eabuf, (int)status, (int)reason, -+ (int)auth_type)); -+ break; -+ } -+ -+ /* show any appended data */ -+ if (datalen) { -+ buf = (uchar *) event_data; -+ DHD_EVENT((" data (%d) : ", datalen)); -+ for (i = 0; i < datalen; i++) -+ DHD_EVENT((" 0x%02x ", *buf++)); -+ DHD_EVENT(("\n")); -+ } -+} -+#endif /* SHOW_EVENTS */ -+ -+int -+wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, -+ wl_event_msg_t *event, void **data_ptr) -+{ -+ /* check whether packet is a BRCM event pkt */ -+ bcm_event_t *pvt_data = (bcm_event_t *)pktdata; -+ uint8 *event_data; -+ uint32 type, status, datalen; -+ uint16 flags; -+ int evlen; -+ -+ if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { -+ DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__)); -+ return (BCME_ERROR); -+ } -+ -+ /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ -+ if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { -+ DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__)); -+ return (BCME_ERROR); -+ } -+ -+ *data_ptr = &pvt_data[1]; -+ event_data = *data_ptr; -+ -+ /* memcpy since BRCM event pkt may be unaligned. */ -+ memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t)); -+ -+ type = ntoh32_ua((void *)&event->event_type); -+ flags = ntoh16_ua((void *)&event->flags); -+ status = ntoh32_ua((void *)&event->status); -+ datalen = ntoh32_ua((void *)&event->datalen); -+ evlen = datalen + sizeof(bcm_event_t); -+ -+ switch (type) { -+#ifdef PROP_TXSTATUS -+ case WLC_E_FIFO_CREDIT_MAP: -+ dhd_wlfc_event(dhd_pub->info); -+ dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data); -+ WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " -+ "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], -+ event_data[2], -+ event_data[3], event_data[4], event_data[5])); -+ break; -+#endif -+ -+ case WLC_E_IF: -+ { -+ dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; -+#ifdef PROP_TXSTATUS -+ { -+ uint8* ea = pvt_data->eth.ether_dhost; -+ WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " -+ "[%02x:%02x:%02x:%02x:%02x:%02x]\n", -+ ifevent->ifidx, -+ ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), -+ ((ifevent->is_AP == 0) ? "STA":"AP "), -+ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); -+ (void)ea; -+ if (ifevent->action == WLC_E_IF_CHANGE) -+ dhd_wlfc_interface_event(dhd_pub->info, -+ eWLFC_MAC_ENTRY_ACTION_UPDATE, -+ ifevent->ifidx, ifevent->is_AP, ea); -+ else -+ dhd_wlfc_interface_event(dhd_pub->info, -+ ((ifevent->action == WLC_E_IF_ADD) ? -+ eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), -+ ifevent->ifidx, ifevent->is_AP, ea); -+ -+ -+ /* dhd already has created an interface by default, for 0 */ -+ if (ifevent->ifidx == 0) -+ break; -+ } -+#endif /* PROP_TXSTATUS */ -+ -+#ifdef WL_CFG80211 -+ if (wl_cfg80211_is_progress_ifchange()) { -+ DHD_ERROR(("%s: ifidx %d for %s action %d\n", -+ __FUNCTION__, ifevent->ifidx, -+ event->ifname, ifevent->action)); -+ if (ifevent->action == WLC_E_IF_ADD || -+ ifevent->action == WLC_E_IF_CHANGE) -+ wl_cfg80211_notify_ifchange(); -+ return (BCME_OK); -+ } -+#endif /* WL_CFG80211 */ -+ if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { -+ if (ifevent->action == WLC_E_IF_ADD) { -+ if (dhd_add_if(dhd_pub->info, ifevent->ifidx, -+ NULL, event->ifname, -+ event->addr.octet, -+ ifevent->flags, ifevent->bssidx)) { -+ DHD_ERROR(("%s: dhd_add_if failed!!" -+ " ifidx: %d for %s\n", -+ __FUNCTION__, -+ ifevent->ifidx, -+ event->ifname)); -+ return (BCME_ERROR); -+ } -+ } -+ else if (ifevent->action == WLC_E_IF_DEL) -+ dhd_del_if(dhd_pub->info, ifevent->ifidx); -+ } else { -+#ifndef PROP_TXSTATUS -+ DHD_ERROR(("%s: Invalid ifidx %d for %s\n", -+ __FUNCTION__, ifevent->ifidx, event->ifname)); -+#endif /* !PROP_TXSTATUS */ -+ } -+ } -+ /* send up the if event: btamp user needs it */ -+ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); -+ /* push up to external supp/auth */ -+ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); -+ break; -+ -+ -+#ifdef WLMEDIA_HTSF -+ case WLC_E_HTSFSYNC: -+ htsf_update(dhd_pub->info, event_data); -+ break; -+#endif /* WLMEDIA_HTSF */ -+#if defined(NDIS630) -+ case WLC_E_NDIS_LINK: -+ break; -+#else /* defined(NDIS630) && defined(BCMDONGLEHOST) */ -+ case WLC_E_NDIS_LINK: { -+ uint32 temp = hton32(WLC_E_LINK); -+ -+ memcpy((void *)(&pvt_data->event.event_type), &temp, -+ sizeof(pvt_data->event.event_type)); -+ } -+#endif -+ /* These are what external supplicant/authenticator wants */ -+ /* fall through */ -+ case WLC_E_LINK: -+ case WLC_E_DEAUTH: -+ case WLC_E_DEAUTH_IND: -+ case WLC_E_DISASSOC: -+ case WLC_E_DISASSOC_IND: -+ DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", -+ __FUNCTION__, type, flags, status)); -+ /* fall through */ -+ default: -+ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); -+ /* push up to external supp/auth */ -+ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); -+ DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", -+ __FUNCTION__, type, flags, status)); -+ BCM_REFERENCE(flags); -+ BCM_REFERENCE(status); -+ -+ /* put it back to WLC_E_NDIS_LINK */ -+ if (type == WLC_E_NDIS_LINK) { -+ uint32 temp; -+ -+ temp = ntoh32_ua((void *)&event->event_type); -+ DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); -+ -+ temp = ntoh32(WLC_E_NDIS_LINK); -+ memcpy((void *)(&pvt_data->event.event_type), &temp, -+ sizeof(pvt_data->event.event_type)); -+ } -+ break; -+ } -+ -+#ifdef SHOW_EVENTS -+ wl_show_host_event(event, (void *)event_data); -+#endif /* SHOW_EVENTS */ -+ -+ return (BCME_OK); -+} -+ -+void -+wl_event_to_host_order(wl_event_msg_t * evt) -+{ -+ /* Event struct members passed from dongle to host are stored in network -+ * byte order. Convert all members to host-order. -+ */ -+ evt->event_type = ntoh32(evt->event_type); -+ evt->flags = ntoh16(evt->flags); -+ evt->status = ntoh32(evt->status); -+ evt->reason = ntoh32(evt->reason); -+ evt->auth_type = ntoh32(evt->auth_type); -+ evt->datalen = ntoh32(evt->datalen); -+ evt->version = ntoh16(evt->version); -+} -+ -+void -+dhd_print_buf(void *pbuf, int len, int bytes_per_line) -+{ -+#ifdef DHD_DEBUG -+ int i, j = 0; -+ unsigned char *buf = pbuf; -+ -+ if (bytes_per_line == 0) { -+ bytes_per_line = len; -+ } -+ -+ for (i = 0; i < len; i++) { -+ printf("%2.2x", *buf++); -+ j++; -+ if (j == bytes_per_line) { -+ printf("\n"); -+ j = 0; -+ } else { -+ printf(":"); -+ } -+ } -+ printf("\n"); -+#endif /* DHD_DEBUG */ -+} -+ -+#ifndef strtoul -+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -+#endif -+ -+#ifdef PKT_FILTER_SUPPORT -+/* Convert user's input in hex pattern to byte-size mask */ -+static int -+wl_pattern_atoh(char *src, char *dst) -+{ -+ int i; -+ if (strncmp(src, "0x", 2) != 0 && -+ strncmp(src, "0X", 2) != 0) { -+ DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); -+ return -1; -+ } -+ src = src + 2; /* Skip past 0x */ -+ if (strlen(src) % 2 != 0) { -+ DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); -+ return -1; -+ } -+ for (i = 0; *src != '\0'; i++) { -+ char num[3]; -+ bcm_strncpy_s(num, sizeof(num), src, 2); -+ num[2] = '\0'; -+ dst[i] = (uint8)strtoul(num, NULL, 16); -+ src += 2; -+ } -+ return i; -+} -+ -+void -+dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) -+{ -+ char *argv[8]; -+ int i = 0; -+ const char *str; -+ int buf_len; -+ int str_len; -+ char *arg_save = 0, *arg_org = 0; -+ int rc; -+ char buf[128]; -+ wl_pkt_filter_enable_t enable_parm; -+ wl_pkt_filter_enable_t * pkt_filterp; -+ -+ if (!arg) -+ return; -+ -+ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { -+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ arg_org = arg_save; -+ memcpy(arg_save, arg, strlen(arg) + 1); -+ -+ argv[i] = bcmstrtok(&arg_save, " ", 0); -+ -+ i = 0; -+ if (argv[i] == NULL) { -+ DHD_ERROR(("No args provided\n")); -+ goto fail; -+ } -+ -+ str = "pkt_filter_enable"; -+ str_len = strlen(str); -+ bcm_strncpy_s(buf, sizeof(buf), str, str_len); -+ buf[str_len] = '\0'; -+ buf_len = str_len + 1; -+ -+ pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); -+ -+ /* Parse packet filter id. */ -+ enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); -+ -+ /* Parse enable/disable value. */ -+ enable_parm.enable = htod32(enable); -+ -+ buf_len += sizeof(enable_parm); -+ memcpy((char *)pkt_filterp, -+ &enable_parm, -+ sizeof(enable_parm)); -+ -+ /* Enable/disable the specified filter. */ -+ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); -+ rc = rc >= 0 ? 0 : rc; -+ if (rc) -+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", -+ __FUNCTION__, arg, rc)); -+ else -+ DHD_TRACE(("%s: successfully added pktfilter %s\n", -+ __FUNCTION__, arg)); -+ -+ /* Contorl the master mode */ -+ bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); -+ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); -+ rc = rc >= 0 ? 0 : rc; -+ if (rc) -+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", -+ __FUNCTION__, arg, rc)); -+ -+fail: -+ if (arg_org) -+ MFREE(dhd->osh, arg_org, strlen(arg) + 1); -+} -+ -+void -+dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) -+{ -+ const char *str; -+ wl_pkt_filter_t pkt_filter; -+ wl_pkt_filter_t *pkt_filterp; -+ int buf_len; -+ int str_len; -+ int rc; -+ uint32 mask_size; -+ uint32 pattern_size; -+ char *argv[8], * buf = 0; -+ int i = 0; -+ char *arg_save = 0, *arg_org = 0; -+#define BUF_SIZE 2048 -+ -+ if (!arg) -+ return; -+ -+ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { -+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ arg_org = arg_save; -+ -+ if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { -+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ memcpy(arg_save, arg, strlen(arg) + 1); -+ -+ if (strlen(arg) > BUF_SIZE) { -+ DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); -+ goto fail; -+ } -+ -+ argv[i] = bcmstrtok(&arg_save, " ", 0); -+ while (argv[i++]) -+ argv[i] = bcmstrtok(&arg_save, " ", 0); -+ -+ i = 0; -+ if (argv[i] == NULL) { -+ DHD_ERROR(("No args provided\n")); -+ goto fail; -+ } -+ -+ str = "pkt_filter_add"; -+ str_len = strlen(str); -+ bcm_strncpy_s(buf, BUF_SIZE, str, str_len); -+ buf[ str_len ] = '\0'; -+ buf_len = str_len + 1; -+ -+ pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); -+ -+ /* Parse packet filter id. */ -+ pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); -+ -+ if (argv[++i] == NULL) { -+ DHD_ERROR(("Polarity not provided\n")); -+ goto fail; -+ } -+ -+ /* Parse filter polarity. */ -+ pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); -+ -+ if (argv[++i] == NULL) { -+ DHD_ERROR(("Filter type not provided\n")); -+ goto fail; -+ } -+ -+ /* Parse filter type. */ -+ pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); -+ -+ if (argv[++i] == NULL) { -+ DHD_ERROR(("Offset not provided\n")); -+ goto fail; -+ } -+ -+ /* Parse pattern filter offset. */ -+ pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); -+ -+ if (argv[++i] == NULL) { -+ DHD_ERROR(("Bitmask not provided\n")); -+ goto fail; -+ } -+ -+ /* Parse pattern filter mask. */ -+ mask_size = -+ htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); -+ -+ if (argv[++i] == NULL) { -+ DHD_ERROR(("Pattern not provided\n")); -+ goto fail; -+ } -+ -+ /* Parse pattern filter pattern. */ -+ pattern_size = -+ htod32(wl_pattern_atoh(argv[i], -+ (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); -+ -+ if (mask_size != pattern_size) { -+ DHD_ERROR(("Mask and pattern not the same size\n")); -+ goto fail; -+ } -+ -+ pkt_filter.u.pattern.size_bytes = mask_size; -+ buf_len += WL_PKT_FILTER_FIXED_LEN; -+ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); -+ -+ /* Keep-alive attributes are set in local variable (keep_alive_pkt), and -+ ** then memcpy'ed into buffer (keep_alive_pktp) since there is no -+ ** guarantee that the buffer is properly aligned. -+ */ -+ memcpy((char *)pkt_filterp, -+ &pkt_filter, -+ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); -+ -+ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); -+ rc = rc >= 0 ? 0 : rc; -+ -+ if (rc) -+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", -+ __FUNCTION__, arg, rc)); -+ else -+ DHD_TRACE(("%s: successfully added pktfilter %s\n", -+ __FUNCTION__, arg)); -+ -+fail: -+ if (arg_org) -+ MFREE(dhd->osh, arg_org, strlen(arg) + 1); -+ -+ if (buf) -+ MFREE(dhd->osh, buf, BUF_SIZE); -+} -+#endif /* PKT_FILTER_SUPPORT */ -+ -+/* ========================== */ -+/* ==== ARP OFFLOAD SUPPORT = */ -+/* ========================== */ -+#ifdef ARP_OFFLOAD_SUPPORT -+void -+dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) -+{ -+ char iovbuf[32]; -+ int retcode; -+ -+ bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); -+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+ retcode = retcode >= 0 ? 0 : retcode; -+ if (retcode) -+ DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", -+ __FUNCTION__, arp_mode, retcode)); -+ else -+ DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", -+ __FUNCTION__, arp_mode)); -+} -+ -+void -+dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) -+{ -+ char iovbuf[32]; -+ int retcode; -+ -+ bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); -+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+ retcode = retcode >= 0 ? 0 : retcode; -+ if (retcode) -+ DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", -+ __FUNCTION__, arp_enable, retcode)); -+ else -+ DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", -+ __FUNCTION__, arp_enable)); -+ if (arp_enable) { -+ uint32 version; -+ bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf)); -+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); -+ if (retcode) { -+ DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n", -+ __FUNCTION__, retcode)); -+ dhd->arp_version = 1; -+ } -+ else { -+ memcpy(&version, iovbuf, sizeof(version)); -+ DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version)); -+ dhd->arp_version = version; -+ } -+ } -+} -+ -+void -+dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) -+{ -+ int ret = 0; -+ int iov_len = 0; -+ char iovbuf[128]; -+ -+ if (dhd == NULL) return; -+ if (dhd->arp_version == 1) -+ idx = 0; -+ -+ iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) -+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -+} -+ -+void -+dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) -+{ -+ int ret = 0; -+ int iov_len = 0; -+ char iovbuf[128]; -+ -+ if (dhd == NULL) return; -+ if (dhd->arp_version == 1) -+ idx = 0; -+ -+ iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0) -+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -+} -+ -+void -+dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) -+{ -+ int iov_len = 0; -+ char iovbuf[32]; -+ int retcode; -+ -+ -+ if (dhd == NULL) return; -+ if (dhd->arp_version == 1) -+ idx = 0; -+ iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, -+ sizeof(ipaddr), iovbuf, sizeof(iovbuf)); -+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); -+ -+ if (retcode) -+ DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", -+ __FUNCTION__, retcode)); -+ else -+ DHD_TRACE(("%s: sARP H ipaddr entry added \n", -+ __FUNCTION__)); -+} -+ -+int -+dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) -+{ -+ int retcode, i; -+ int iov_len; -+ uint32 *ptr32 = buf; -+ bool clr_bottom = FALSE; -+ -+ if (!buf) -+ return -1; -+ if (dhd == NULL) return -1; -+ if (dhd->arp_version == 1) -+ idx = 0; -+ -+ iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); -+ BCM_REFERENCE(iov_len); -+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx); -+ -+ if (retcode) { -+ DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", -+ __FUNCTION__, retcode)); -+ -+ return -1; -+ } -+ -+ /* clean up the buf, ascii reminder */ -+ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { -+ if (!clr_bottom) { -+ if (*ptr32 == 0) -+ clr_bottom = TRUE; -+ } else { -+ *ptr32 = 0; -+ } -+ ptr32++; -+ } -+ -+ return 0; -+} -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+/* send up locally generated event */ -+void -+dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -+{ -+ switch (ntoh32(event->event_type)) { -+#ifdef WLBTAMP -+ case WLC_E_BTA_HCI_EVENT: -+ break; -+#endif /* WLBTAMP */ -+ default: -+ break; -+ } -+ -+ /* Call per-port handler. */ -+ dhd_sendup_event(dhdp, event, data); -+} -+ -+ -+/* -+ * returns = TRUE if associated, FALSE if not associated -+ */ -+bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) -+{ -+ char bssid[6], zbuf[6]; -+ int ret = -1; -+ -+ bzero(bssid, 6); -+ bzero(zbuf, 6); -+ -+ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); -+ DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); -+ -+ if (ret == BCME_NOTASSOCIATED) { -+ DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); -+ } -+ -+ if (retval) -+ *retval = ret; -+ -+ if (ret < 0) -+ return FALSE; -+ -+ if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { -+ /* STA is assocoated BSSID is non zero */ -+ -+ if (bss_buf) { -+ /* return bss if caller provided buf */ -+ memcpy(bss_buf, bssid, ETHER_ADDR_LEN); -+ } -+ return TRUE; -+ } else { -+ DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); -+ return FALSE; -+ } -+} -+ -+ -+/* Function to estimate possible DTIM_SKIP value */ -+int -+dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) -+{ -+ int bcn_li_dtim = 1; /* deafult no dtim skip setting */ -+ int ret = -1; -+ int dtim_assoc = 0; -+ int ap_beacon = 0; -+ -+ /* Check if associated */ -+ if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { -+ DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); -+ goto exit; -+ } -+ -+ /* read associated AP beacon interval */ -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, -+ &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { -+ DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); -+ goto exit; -+ } -+ -+ /* if associated APs Beacon more that 100msec do no dtim skip */ -+ if (ap_beacon > MAX_DTIM_SKIP_BEACON_ITERVAL) { -+ DHD_ERROR(("%s NO dtim skip for AP with beacon %d ms\n", __FUNCTION__, ap_beacon)); -+ goto exit; -+ } -+ -+ /* read associated ap's dtim setup */ -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, -+ &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) { -+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -+ goto exit; -+ } -+ -+ /* if not assocated just eixt */ -+ if (dtim_assoc == 0) { -+ goto exit; -+ } -+ -+ /* attemp to use platform defined dtim skip interval */ -+ bcn_li_dtim = dhd->suspend_bcn_li_dtim; -+ -+ /* check if sta listen interval fits into AP dtim */ -+ if (dtim_assoc > LISTEN_INTERVAL) { -+ /* AP DTIM to big for our Listen Interval : no dtim skiping */ -+ bcn_li_dtim = 1; -+ DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", -+ __FUNCTION__, dtim_assoc, LISTEN_INTERVAL)); -+ goto exit; -+ } -+ -+ if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { -+ /* Round up dtim_skip to fit into STAs Listen Interval */ -+ bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); -+ DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); -+ } -+ -+ DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", -+ __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL)); -+ -+exit: -+ return bcn_li_dtim; -+} -+ -+/* Check if the mode supports STA MODE */ -+bool dhd_support_sta_mode(dhd_pub_t *dhd) -+{ -+ -+#ifdef WL_CFG80211 -+ if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) -+ return FALSE; -+ else -+#endif /* WL_CFG80211 */ -+ return TRUE; -+} -+ -+#if defined(PNO_SUPPORT) -+int -+dhd_pno_clean(dhd_pub_t *dhd) -+{ -+ char iovbuf[128]; -+ int pfn_enabled = 0; -+ int iov_len = 0; -+ int ret; -+ -+ /* Disable pfn */ -+ iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) { -+ /* clear pfn */ -+ iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); -+ if (iov_len) { -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, -+ iov_len, TRUE, 0)) < 0) { -+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -+ } -+ } -+ else { -+ ret = -1; -+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len)); -+ } -+ } -+ else -+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -+ -+ return ret; -+} -+ -+int -+dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) -+{ -+ char iovbuf[128]; -+ int ret = -1; -+ -+ if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { -+ DHD_ERROR(("%s error exit\n", __FUNCTION__)); -+ return ret; -+ } -+ -+#ifndef WL_SCHED_SCAN -+ if (!dhd_support_sta_mode(dhd)) -+ return (ret); -+ -+ memset(iovbuf, 0, sizeof(iovbuf)); -+ -+ if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) { -+ DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); -+ return ret; -+ } -+#endif /* !WL_SCHED_SCAN */ -+ -+ /* Enable/disable PNO */ -+ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, -+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { -+ DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret)); -+ return ret; -+ } -+ else { -+ dhd->pno_enable = pfn_enabled; -+ DHD_TRACE(("%s set pno as %s\n", -+ __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable")); -+ } -+ } -+ else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret)); -+ -+ return ret; -+} -+ -+/* Function to execute combined scan */ -+int -+dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, -+ int pno_repeat, int pno_freq_expo_max) -+{ -+ int err = -1; -+ char iovbuf[128]; -+ int k, i; -+ wl_pfn_param_t pfn_param; -+ wl_pfn_t pfn_element; -+ uint len = 0; -+ -+ DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr)); -+ -+ if ((!dhd) || (!ssids_local)) { -+ DHD_ERROR(("%s error exit(%s %s)\n", __FUNCTION__, -+ (!dhd)?"dhd is null":"", (!ssids_local)?"ssid is null":"")); -+ err = -1; -+ return err; -+ } -+#ifndef WL_SCHED_SCAN -+ if (!dhd_support_sta_mode(dhd)) -+ return err; -+#endif /* !WL_SCHED_SCAN */ -+ -+ /* Check for broadcast ssid */ -+ for (k = 0; k < nssid; k++) { -+ if (!ssids_local[k].SSID_len) { -+ DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k)); -+ return err; -+ } -+ } -+/* #define PNO_DUMP 1 */ -+#ifdef PNO_DUMP -+ { -+ int j; -+ for (j = 0; j < nssid; j++) { -+ DHD_ERROR(("%d: scan for %s size =%d\n", j, -+ ssids_local[j].SSID, ssids_local[j].SSID_len)); -+ } -+ } -+#endif /* PNO_DUMP */ -+ -+ /* clean up everything */ -+ if ((err = dhd_pno_clean(dhd)) < 0) { -+ DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err)); -+ return err; -+ } -+ memset(iovbuf, 0, sizeof(iovbuf)); -+ memset(&pfn_param, 0, sizeof(pfn_param)); -+ memset(&pfn_element, 0, sizeof(pfn_element)); -+ -+ /* set pfn parameters */ -+ pfn_param.version = htod32(PFN_VERSION); -+ pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); -+ -+ /* check and set extra pno params */ -+ if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) { -+ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); -+ pfn_param.repeat = (uchar) (pno_repeat); -+ pfn_param.exp = (uchar) (pno_freq_expo_max); -+ } -+ /* set up pno scan fr */ -+ if (scan_fr != 0) -+ pfn_param.scan_freq = htod32(scan_fr); -+ -+ if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) { -+ DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC)); -+ return err; -+ } -+ if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) { -+ DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); -+ return err; -+ } -+ -+ len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); -+ if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { -+ DHD_ERROR(("%s pfn_set failed for error=%d\n", -+ __FUNCTION__, err)); -+ return err; -+ } -+ -+ /* set all pfn ssid */ -+ for (i = 0; i < nssid; i++) { -+ -+ pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); -+ pfn_element.auth = (DOT11_OPEN_SYSTEM); -+ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); -+ pfn_element.wsec = htod32(0); -+ pfn_element.infra = htod32(1); -+ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); -+ memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); -+ pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; -+ -+ if ((len = -+ bcm_mkiovar("pfn_add", (char *)&pfn_element, -+ sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { -+ if ((err = -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { -+ DHD_ERROR(("%s failed for i=%d error=%d\n", -+ __FUNCTION__, i, err)); -+ return err; -+ } -+ else -+ DHD_TRACE(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", -+ __FUNCTION__, pfn_param.scan_freq, -+ pfn_param.repeat, pfn_param.exp)); -+ } -+ else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); -+ } -+ -+ /* Enable PNO */ -+ /* dhd_pno_enable(dhd, 1); */ -+ return err; -+} -+ -+int -+dhd_pno_get_status(dhd_pub_t *dhd) -+{ -+ int ret = -1; -+ -+ if (!dhd) -+ return ret; -+ else -+ return (dhd->pno_enable); -+} -+ -+#endif /* OEM_ANDROID && PNO_SUPPORT */ -+ -+#if defined(KEEP_ALIVE) -+int dhd_keep_alive_onoff(dhd_pub_t *dhd) -+{ -+ char buf[256]; -+ const char *str; -+ wl_mkeep_alive_pkt_t mkeep_alive_pkt; -+ wl_mkeep_alive_pkt_t *mkeep_alive_pktp; -+ int buf_len; -+ int str_len; -+ int res = -1; -+ -+ if (!dhd_support_sta_mode(dhd)) -+ return res; -+ -+ DHD_TRACE(("%s execution\n", __FUNCTION__)); -+ -+ str = "mkeep_alive"; -+ str_len = strlen(str); -+ strncpy(buf, str, str_len); -+ buf[ str_len ] = '\0'; -+ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); -+ mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING; -+ buf_len = str_len + 1; -+ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); -+ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); -+ /* Setup keep alive zero for null packet generation */ -+ mkeep_alive_pkt.keep_alive_id = 0; -+ mkeep_alive_pkt.len_bytes = 0; -+ buf_len += WL_MKEEP_ALIVE_FIXED_LEN; -+ bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); -+ /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and -+ * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no -+ * guarantee that the buffer is properly aligned. -+ */ -+ memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); -+ -+ res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); -+ -+ return res; -+} -+#endif /* defined(KEEP_ALIVE) */ -+/* Android ComboSCAN support */ -+ -+/* -+ * data parsing from ComboScan tlv list -+*/ -+int -+wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, -+ int input_size, int *bytes_left) -+{ -+ char* str; -+ uint16 short_temp; -+ uint32 int_temp; -+ -+ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { -+ DHD_ERROR(("%s error paramters\n", __FUNCTION__)); -+ return -1; -+ } -+ str = *list_str; -+ -+ /* Clean all dest bytes */ -+ memset(dst, 0, dst_size); -+ while (*bytes_left > 0) { -+ -+ if (str[0] != token) { -+ DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", -+ __FUNCTION__, token, str[0], *bytes_left)); -+ return -1; -+ } -+ -+ *bytes_left -= 1; -+ str += 1; -+ -+ if (input_size == 1) { -+ memcpy(dst, str, input_size); -+ } -+ else if (input_size == 2) { -+ memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), -+ input_size); -+ } -+ else if (input_size == 4) { -+ memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), -+ input_size); -+ } -+ -+ *bytes_left -= input_size; -+ str += input_size; -+ *list_str = str; -+ return 1; -+ } -+ return 1; -+} -+ -+/* -+ * channel list parsing from cscan tlv list -+*/ -+int -+wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, -+ int channel_num, int *bytes_left) -+{ -+ char* str; -+ int idx = 0; -+ -+ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { -+ DHD_ERROR(("%s error paramters\n", __FUNCTION__)); -+ return -1; -+ } -+ str = *list_str; -+ -+ while (*bytes_left > 0) { -+ -+ if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { -+ *list_str = str; -+ DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); -+ return idx; -+ } -+ /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ -+ *bytes_left -= 1; -+ str += 1; -+ -+ if (str[0] == 0) { -+ /* All channels */ -+ channel_list[idx] = 0x0; -+ } -+ else { -+ channel_list[idx] = (uint16)str[0]; -+ DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); -+ } -+ *bytes_left -= 1; -+ str += 1; -+ -+ if (idx++ > 255) { -+ DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); -+ return -1; -+ } -+ } -+ -+ *list_str = str; -+ return idx; -+} -+ -+/* -+ * SSIDs list parsing from cscan tlv list -+ */ -+int -+wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) -+{ -+ char* str; -+ int idx = 0; -+ -+ if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { -+ DHD_ERROR(("%s error paramters\n", __FUNCTION__)); -+ return -1; -+ } -+ str = *list_str; -+ while (*bytes_left > 0) { -+ -+ if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { -+ *list_str = str; -+ DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); -+ return idx; -+ } -+ -+ /* Get proper CSCAN_TLV_TYPE_SSID_IE */ -+ *bytes_left -= 1; -+ str += 1; -+ -+ if (str[0] == 0) { -+ /* Broadcast SSID */ -+ ssid[idx].SSID_len = 0; -+ memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); -+ *bytes_left -= 1; -+ str += 1; -+ -+ DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); -+ } -+ else if (str[0] <= DOT11_MAX_SSID_LEN) { -+ /* Get proper SSID size */ -+ ssid[idx].SSID_len = str[0]; -+ *bytes_left -= 1; -+ str += 1; -+ -+ /* Get SSID */ -+ if (ssid[idx].SSID_len > *bytes_left) { -+ DHD_ERROR(("%s out of memory range len=%d but left=%d\n", -+ __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); -+ return -1; -+ } -+ -+ memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); -+ -+ *bytes_left -= ssid[idx].SSID_len; -+ str += ssid[idx].SSID_len; -+ -+ DHD_TRACE(("%s :size=%d left=%d\n", -+ (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); -+ } -+ else { -+ DHD_ERROR(("### SSID size more that %d\n", str[0])); -+ return -1; -+ } -+ -+ if (idx++ > max) { -+ DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); -+ return -1; -+ } -+ } -+ -+ *list_str = str; -+ return idx; -+} -+ -+/* Parse a comma-separated list from list_str into ssid array, starting -+ * at index idx. Max specifies size of the ssid array. Parses ssids -+ * and returns updated idx; if idx >= max not all fit, the excess have -+ * not been copied. Returns -1 on empty string, or on ssid too long. -+ */ -+int -+wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) -+{ -+ char* str, *ptr; -+ -+ if ((list_str == NULL) || (*list_str == NULL)) -+ return -1; -+ -+ for (str = *list_str; str != NULL; str = ptr) { -+ -+ /* check for next TAG */ -+ if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { -+ *list_str = str + strlen(GET_CHANNEL); -+ return idx; -+ } -+ -+ if ((ptr = strchr(str, ',')) != NULL) { -+ *ptr++ = '\0'; -+ } -+ -+ if (strlen(str) > DOT11_MAX_SSID_LEN) { -+ DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); -+ return -1; -+ } -+ -+ if (strlen(str) == 0) -+ ssid[idx].SSID_len = 0; -+ -+ if (idx < max) { -+ bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); -+ strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); -+ ssid[idx].SSID_len = strlen(str); -+ } -+ idx++; -+ } -+ return idx; -+} -+ -+/* -+ * Parse channel list from iwpriv CSCAN -+ */ -+int -+wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) -+{ -+ int num; -+ int val; -+ char* str; -+ char* endptr = NULL; -+ -+ if ((list_str == NULL)||(*list_str == NULL)) -+ return -1; -+ -+ str = *list_str; -+ num = 0; -+ while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { -+ val = (int)strtoul(str, &endptr, 0); -+ if (endptr == str) { -+ printf("could not parse channel number starting at" -+ " substring \"%s\" in list:\n%s\n", -+ str, *list_str); -+ return -1; -+ } -+ str = endptr + strspn(endptr, " ,"); -+ -+ if (num == channel_num) { -+ DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", -+ channel_num, *list_str)); -+ return -1; -+ } -+ -+ channel_list[num++] = (uint16)val; -+ } -+ *list_str = str; -+ return num; -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c -new file mode 100644 -index 00000000..cfd1ac31 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c -@@ -0,0 +1,293 @@ -+/* -+* Customer code to add GPIO control during WLAN start/stop -+* Copyright (C) 1999-2012, Broadcom Corporation -+* -+* Unless you and Broadcom execute a separate written software license -+* agreement governing use of this software, this software is licensed to you -+* under the terms of the GNU General Public License version 2 (the "GPL"), -+* available at http://www.broadcom.com/licenses/GPLv2.php, with the -+* following added to such license: -+* -+* As a special exception, the copyright holders of this software give you -+* permission to link this software with independent modules, and to copy and -+* distribute the resulting executable under terms of your choice, provided that -+* you also meet, for each linked independent module, the terms and conditions of -+* the license of that module. An independent module is a module which is not -+* derived from this software. The special exception does not apply to any -+* modifications of the software. -+* -+* Notwithstanding the above, under no circumstances may you combine this -+* software in any way with any other Broadcom software provided under a license -+* other than the GPL, without Broadcom's express prior written consent. -+* -+* $Id: dhd_custom_gpio.c 345514 2012-07-18 07:47:36Z $ -+*/ -+ -+#include <typedefs.h> -+#include <linuxver.h> -+#include <osl.h> -+#include <bcmutils.h> -+ -+#include <dngl_stats.h> -+#include <dhd.h> -+ -+#include <wlioctl.h> -+#include <wl_iw.h> -+ -+#define WL_ERROR(x) printf x -+#define WL_TRACE(x) -+ -+#ifdef CUSTOMER_HW -+extern void bcm_wlan_power_off(int); -+extern void bcm_wlan_power_on(int); -+#endif /* CUSTOMER_HW */ -+#if defined(CUSTOMER_HW2) -+#ifdef CONFIG_WIFI_CONTROL_FUNC -+int wifi_set_power(int on, unsigned long msec); -+int wifi_get_irq_number(unsigned long *irq_flags_ptr); -+int wifi_get_mac_addr(unsigned char *buf); -+void *wifi_get_country_code(char *ccode); -+#else -+int wifi_set_power(int on, unsigned long msec) { return -1; } -+int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; } -+int wifi_get_mac_addr(unsigned char *buf) { return -1; } -+void *wifi_get_country_code(char *ccode) { return NULL; } -+#endif /* CONFIG_WIFI_CONTROL_FUNC */ -+#endif /* CUSTOMER_HW2 */ -+ -+#if defined(OOB_INTR_ONLY) -+ -+#if defined(BCMLXSDMMC) -+extern int sdioh_mmc_irq(int irq); -+#endif /* (BCMLXSDMMC) */ -+ -+#ifdef CUSTOMER_HW3 -+#include <mach/gpio.h> -+#endif -+ -+/* Customer specific Host GPIO defintion */ -+static int dhd_oob_gpio_num = -1; -+ -+module_param(dhd_oob_gpio_num, int, 0644); -+MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); -+ -+/* This function will return: -+ * 1) return : Host gpio interrupt number per customer platform -+ * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge -+ * -+ * NOTE : -+ * Customer should check his platform definitions -+ * and his Host Interrupt spec -+ * to figure out the proper setting for his platform. -+ * Broadcom provides just reference settings as example. -+ * -+ */ -+int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) -+{ -+ int host_oob_irq = 0; -+ -+#if defined(CUSTOMER_HW2) -+ host_oob_irq = wifi_get_irq_number(irq_flags_ptr); -+ -+#else -+#if defined(CUSTOM_OOB_GPIO_NUM) -+ if (dhd_oob_gpio_num < 0) { -+ dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; -+ } -+#endif /* CUSTOMER_OOB_GPIO_NUM */ -+ -+ if (dhd_oob_gpio_num < 0) { -+ WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", -+ __FUNCTION__)); -+ return (dhd_oob_gpio_num); -+ } -+ -+ WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", -+ __FUNCTION__, dhd_oob_gpio_num)); -+ -+#if defined CUSTOMER_HW -+ host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num); -+#elif defined CUSTOMER_HW3 -+ gpio_request(dhd_oob_gpio_num, "oob irq"); -+ host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); -+ gpio_direction_input(dhd_oob_gpio_num); -+#endif /* CUSTOMER_HW */ -+#endif /* CUSTOMER_HW2 */ -+ -+ return (host_oob_irq); -+} -+#endif /* defined(OOB_INTR_ONLY) */ -+ -+/* Customer function to control hw specific wlan gpios */ -+void -+dhd_customer_gpio_wlan_ctrl(int onoff) -+{ -+ switch (onoff) { -+ case WLAN_RESET_OFF: -+ WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n", -+ __FUNCTION__)); -+#ifdef CUSTOMER_HW -+ bcm_wlan_power_off(2); -+#endif /* CUSTOMER_HW */ -+#if defined(CUSTOMER_HW2) -+ wifi_set_power(0, 0); -+#endif -+ WL_ERROR(("=========== WLAN placed in RESET ========\n")); -+ break; -+ -+ case WLAN_RESET_ON: -+ WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n", -+ __FUNCTION__)); -+#ifdef CUSTOMER_HW -+ bcm_wlan_power_on(2); -+#endif /* CUSTOMER_HW */ -+#if defined(CUSTOMER_HW2) -+ wifi_set_power(1, 0); -+#endif -+ WL_ERROR(("=========== WLAN going back to live ========\n")); -+ break; -+ -+ case WLAN_POWER_OFF: -+ WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n", -+ __FUNCTION__)); -+#ifdef CUSTOMER_HW -+ bcm_wlan_power_off(1); -+#endif /* CUSTOMER_HW */ -+ break; -+ -+ case WLAN_POWER_ON: -+ WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n", -+ __FUNCTION__)); -+#ifdef CUSTOMER_HW -+ bcm_wlan_power_on(1); -+ /* Lets customer power to get stable */ -+ OSL_DELAY(200); -+#endif /* CUSTOMER_HW */ -+ break; -+ } -+} -+ -+#ifdef GET_CUSTOM_MAC_ENABLE -+/* Function to get custom MAC address */ -+int -+dhd_custom_get_mac_address(unsigned char *buf) -+{ -+ int ret = 0; -+ -+ WL_TRACE(("%s Enter\n", __FUNCTION__)); -+ if (!buf) -+ return -EINVAL; -+ -+ /* Customer access to MAC address stored outside of DHD driver */ -+#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) -+ ret = wifi_get_mac_addr(buf); -+#endif -+ -+#ifdef EXAMPLE_GET_MAC -+ /* EXAMPLE code */ -+ { -+ struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; -+ bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); -+ } -+#endif /* EXAMPLE_GET_MAC */ -+ -+ return ret; -+} -+#endif /* GET_CUSTOM_MAC_ENABLE */ -+ -+/* Customized Locale table : OPTIONAL feature */ -+const struct cntry_locales_custom translate_custom_table[] = { -+/* Table should be filled out based on custom platform regulatory requirement */ -+#ifdef EXAMPLE_TABLE -+ {"", "XY", 4}, /* Universal if Country code is unknown or empty */ -+ {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ -+ {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ -+ {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ -+ {"AT", "EU", 5}, -+ {"BE", "EU", 5}, -+ {"BG", "EU", 5}, -+ {"CY", "EU", 5}, -+ {"CZ", "EU", 5}, -+ {"DK", "EU", 5}, -+ {"EE", "EU", 5}, -+ {"FI", "EU", 5}, -+ {"FR", "EU", 5}, -+ {"DE", "EU", 5}, -+ {"GR", "EU", 5}, -+ {"HU", "EU", 5}, -+ {"IE", "EU", 5}, -+ {"IT", "EU", 5}, -+ {"LV", "EU", 5}, -+ {"LI", "EU", 5}, -+ {"LT", "EU", 5}, -+ {"LU", "EU", 5}, -+ {"MT", "EU", 5}, -+ {"NL", "EU", 5}, -+ {"PL", "EU", 5}, -+ {"PT", "EU", 5}, -+ {"RO", "EU", 5}, -+ {"SK", "EU", 5}, -+ {"SI", "EU", 5}, -+ {"ES", "EU", 5}, -+ {"SE", "EU", 5}, -+ {"GB", "EU", 5}, -+ {"KR", "XY", 3}, -+ {"AU", "XY", 3}, -+ {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ -+ {"TW", "XY", 3}, -+ {"AR", "XY", 3}, -+ {"MX", "XY", 3}, -+ {"IL", "IL", 0}, -+ {"CH", "CH", 0}, -+ {"TR", "TR", 0}, -+ {"NO", "NO", 0}, -+#endif /* EXMAPLE_TABLE */ -+}; -+ -+ -+/* Customized Locale convertor -+* input : ISO 3166-1 country abbreviation -+* output: customized cspec -+*/ -+void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) -+{ -+#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) -+ -+ struct cntry_locales_custom *cloc_ptr; -+ -+ if (!cspec) -+ return; -+ -+ cloc_ptr = wifi_get_country_code(country_iso_code); -+ if (cloc_ptr) { -+ strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); -+ cspec->rev = cloc_ptr->custom_locale_rev; -+ } -+ return; -+#else -+ int size, i; -+ -+ size = ARRAYSIZE(translate_custom_table); -+ -+ if (cspec == 0) -+ return; -+ -+ if (size == 0) -+ return; -+ -+ for (i = 0; i < size; i++) { -+ if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { -+ memcpy(cspec->ccode, -+ translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); -+ cspec->rev = translate_custom_table[i].custom_locale_rev; -+ return; -+ } -+ } -+#ifdef EXAMPLE_TABLE -+ /* if no country code matched return first universal code from translate_custom_table */ -+ memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); -+ cspec->rev = translate_custom_table[0].custom_locale_rev; -+#endif /* EXMAPLE_TABLE */ -+ return; -+#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */ -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h -new file mode 100644 -index 00000000..e1660ce1 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_dbg.h -@@ -0,0 +1,116 @@ -+/* -+ * Debug/trace/assert driver definitions for Dongle Host Driver. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_dbg.h 353490 2012-08-27 21:10:02Z $ -+ */ -+ -+#ifndef _dhd_dbg_ -+#define _dhd_dbg_ -+ -+#define USE_NET_RATELIMIT net_ratelimit() -+ -+#if defined(DHD_DEBUG) -+ -+#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && USE_NET_RATELIMIT) \ -+ printf args;} while (0) -+#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) -+#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) -+#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) -+#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) -+#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) -+#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) -+#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) -+#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) -+#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) -+#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) -+#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) -+#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) -+#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) -+#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) -+ -+#define DHD_TRACE_HW4 DHD_TRACE -+ -+#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) -+#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) -+#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) -+#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) -+#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) -+#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) -+#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) -+#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) -+#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) -+#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) -+#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) -+#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) -+#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) -+#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) -+#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) -+ -+#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ -+ -+#define DHD_ERROR(args) do {if (USE_NET_RATELIMIT) printf args;} while (0) -+#define DHD_TRACE(args) -+#define DHD_INFO(args) -+#define DHD_DATA(args) -+#define DHD_CTL(args) -+#define DHD_TIMER(args) -+#define DHD_HDRS(args) -+#define DHD_BYTES(args) -+#define DHD_INTR(args) -+#define DHD_GLOM(args) -+#define DHD_EVENT(args) -+#define DHD_BTA(args) -+#define DHD_ISCAN(args) -+#define DHD_ARPOE(args) -+#define DHD_REORDER(args) -+ -+#define DHD_TRACE_HW4 DHD_TRACE -+ -+#define DHD_ERROR_ON() 0 -+#define DHD_TRACE_ON() 0 -+#define DHD_INFO_ON() 0 -+#define DHD_DATA_ON() 0 -+#define DHD_CTL_ON() 0 -+#define DHD_TIMER_ON() 0 -+#define DHD_HDRS_ON() 0 -+#define DHD_BYTES_ON() 0 -+#define DHD_INTR_ON() 0 -+#define DHD_GLOM_ON() 0 -+#define DHD_EVENT_ON() 0 -+#define DHD_BTA_ON() 0 -+#define DHD_ISCAN_ON() 0 -+#define DHD_ARPOE_ON() 0 -+#define DHD_REORDER_ON() 0 -+#endif -+ -+#define DHD_LOG(args) -+ -+#define DHD_BLOG(cp, size) -+ -+#define DHD_NONE(args) -+extern int dhd_msg_level; -+ -+/* Defines msg bits */ -+#include <dhdioctl.h> -+ -+#endif /* _dhd_dbg_ */ -diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c -new file mode 100644 -index 00000000..76824951 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c -@@ -0,0 +1,6007 @@ -+/* -+ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface -+ * Basically selected code segments from usb-cdc.c and usb-rndis.c -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_linux.c 380566 2013-01-23 05:29:02Z $ -+ */ -+ -+#include <typedefs.h> -+#include <linuxver.h> -+#include <osl.h> -+ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/skbuff.h> -+#include <linux/netdevice.h> -+#include <linux/inetdevice.h> -+#include <linux/rtnetlink.h> -+#include <linux/etherdevice.h> -+#include <linux/random.h> -+#include <linux/spinlock.h> -+#include <linux/ethtool.h> -+#include <linux/fcntl.h> -+#include <linux/fs.h> -+ -+#include <asm/uaccess.h> -+#include <asm/unaligned.h> -+ -+#include <epivers.h> -+#include <bcmutils.h> -+#include <bcmendian.h> -+#include <bcmdevs.h> -+ -+#include <proto/ethernet.h> -+#include <dngl_stats.h> -+#include <dhd.h> -+#include <dhd_bus.h> -+#include <dhd_proto.h> -+#include <dhd_dbg.h> -+#ifdef CONFIG_HAS_WAKELOCK -+#include <linux/wakelock.h> -+#endif -+#ifdef WL_CFG80211 -+#include <wl_cfg80211.h> -+#endif -+ -+#ifdef WLBTAMP -+#include <proto/802.11_bta.h> -+#include <proto/bt_amp_hci.h> -+#include <dhd_bta.h> -+#endif -+ -+#ifdef WLMEDIA_HTSF -+#include <linux/time.h> -+#include <htsf.h> -+ -+#define HTSF_MINLEN 200 /* min. packet length to timestamp */ -+#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ -+#define TSMAX 1000 /* max no. of timing record kept */ -+#define NUMBIN 34 -+static uint32 tsidx = 0; -+static uint32 htsf_seqnum = 0; -+uint32 tsfsync; -+struct timeval tsync; -+static uint32 tsport = 5010; -+ -+typedef struct histo_ { -+ uint32 bin[NUMBIN]; -+} histo_t; -+ -+#if !ISPOWEROF2(DHD_SDALIGN) -+#error DHD_SDALIGN is not a power of 2! -+#endif -+ -+static histo_t vi_d1, vi_d2, vi_d3, vi_d4; -+#endif /* WLMEDIA_HTSF */ -+ -+#if defined(PKT_FILTER_SUPPORT) -+#endif /* PKT_FILTER_SUPPORT */ -+ -+#if defined(SOFTAP) -+extern bool ap_cfg_running; -+extern bool ap_fw_loaded; -+#endif -+ -+/* enable HOSTIP cache update from the host side when an eth0:N is up */ -+#define AOE_IP_ALIAS_SUPPORT 1 -+ -+#ifdef BCM_FD_AGGR -+#include <bcm_rpc.h> -+#include <bcm_rpc_tp.h> -+#endif -+#ifdef PROP_TXSTATUS -+#include <wlfc_proto.h> -+#include <dhd_wlfc.h> -+#endif -+ -+#include <wl_android.h> -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); -+static int dhd_device_event(struct notifier_block *this, -+ unsigned long event, -+ void *ptr); -+ -+static struct notifier_block dhd_notifier = { -+ .notifier_call = dhd_device_event -+}; -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -+#include <linux/suspend.h> -+volatile bool dhd_mmc_suspend = FALSE; -+DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -+ -+#if defined(OOB_INTR_ONLY) -+extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); -+#endif /* defined(OOB_INTR_ONLY) */ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+static void dhd_hang_process(struct work_struct *work); -+#endif -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+MODULE_LICENSE("GPL v2"); -+#endif /* LinuxVer */ -+ -+#include <dhd_bus.h> -+ -+#ifdef BCM_FD_AGGR -+#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) -+#else -+#ifndef PROP_TXSTATUS -+#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) -+#else -+#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) -+#endif -+#endif /* BCM_FD_AGGR */ -+ -+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) -+const char * -+print_tainted() -+{ -+ return ""; -+} -+#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ -+ -+/* Linux wireless extension support */ -+#if defined(CONFIG_WIRELESS_EXT) -+#include <wl_iw.h> -+extern wl_iw_extra_params_t g_wl_iw_params; -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -+#include <linux/earlysuspend.h> -+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ -+ -+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); -+ -+#ifdef PKT_FILTER_SUPPORT -+extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); -+extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -+#endif -+ -+#ifdef READ_MACADDR -+extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); -+#endif -+#ifdef RDWR_MACADDR -+extern int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, struct ether_addr *mac); -+extern int dhd_write_rdwr_macaddr(struct ether_addr *mac); -+#endif -+#ifdef WRITE_MACADDR -+extern int dhd_write_macaddr(struct ether_addr *mac); -+#endif -+#ifdef GET_MAC_FROM_OTP -+extern int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac); -+#endif -+#ifdef MIMO_ANT_SETTING -+extern int dhd_sel_ant_from_file(dhd_pub_t *dhd); -+#endif -+ -+#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE -+int dhd_customer_set_country(dhd_pub_t *dhd); -+#endif -+ -+/* Interface control information */ -+typedef struct dhd_if { -+ struct dhd_info *info; /* back pointer to dhd_info */ -+ /* OS/stack specifics */ -+ struct net_device *net; -+ struct net_device_stats stats; -+ int idx; /* iface idx in dongle */ -+ dhd_if_state_t state; /* interface state */ -+ uint subunit; /* subunit */ -+ uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ -+ bool attached; /* Delayed attachment when unset */ -+ bool txflowcontrol; /* Per interface flow control indicator */ -+ char name[IFNAMSIZ+1]; /* linux interface name */ -+ uint8 bssidx; /* bsscfg index for the interface */ -+ bool set_multicast; -+ bool event2cfg80211; /* To determine if pass event to cfg80211 */ -+} dhd_if_t; -+ -+#ifdef WLMEDIA_HTSF -+typedef struct { -+ uint32 low; -+ uint32 high; -+} tsf_t; -+ -+typedef struct { -+ uint32 last_cycle; -+ uint32 last_sec; -+ uint32 last_tsf; -+ uint32 coef; /* scaling factor */ -+ uint32 coefdec1; /* first decimal */ -+ uint32 coefdec2; /* second decimal */ -+} htsf_t; -+ -+typedef struct { -+ uint32 t1; -+ uint32 t2; -+ uint32 t3; -+ uint32 t4; -+} tstamp_t; -+ -+static tstamp_t ts[TSMAX]; -+static tstamp_t maxdelayts; -+static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; -+ -+#endif /* WLMEDIA_HTSF */ -+ -+/* Local private structure (extension of pub) */ -+typedef struct dhd_info { -+#if defined(CONFIG_WIRELESS_EXT) -+ wl_iw_t iw; /* wireless extensions state (must be first) */ -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+ dhd_pub_t pub; -+ -+ /* For supporting multiple interfaces */ -+ dhd_if_t *iflist[DHD_MAX_IFS]; -+ -+ struct semaphore proto_sem; -+#ifdef PROP_TXSTATUS -+ spinlock_t wlfc_spinlock; -+#endif /* PROP_TXSTATUS */ -+#ifdef WLMEDIA_HTSF -+ htsf_t htsf; -+#endif -+ wait_queue_head_t ioctl_resp_wait; -+ struct timer_list timer; -+ bool wd_timer_valid; -+ struct tasklet_struct tasklet; -+ spinlock_t sdlock; -+ spinlock_t txqlock; -+ spinlock_t dhd_lock; -+#ifdef DHDTHREAD -+ /* Thread based operation */ -+ bool threads_only; -+ struct semaphore sdsem; -+ -+ tsk_ctl_t thr_dpc_ctl; -+ tsk_ctl_t thr_wdt_ctl; -+#endif /* DHDTHREAD */ -+ bool dhd_tasklet_create; -+ tsk_ctl_t thr_sysioc_ctl; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ struct work_struct work_hang; -+#endif -+ -+ /* Wakelocks */ -+#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ struct wake_lock wl_wifi; /* Wifi wakelock */ -+ struct wake_lock wl_rxwake; /* Wifi rx wakelock */ -+ struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ -+ struct wake_lock wl_wdwake; /* Wifi wd wakelock */ -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ /* net_device interface lock, prevent race conditions among net_dev interface -+ * calls and wifi_on or wifi_off -+ */ -+ struct mutex dhd_net_if_mutex; -+ struct mutex dhd_suspend_mutex; -+#endif -+ spinlock_t wakelock_spinlock; -+ int wakelock_counter; -+ int wakelock_wd_counter; -+ int wakelock_rx_timeout_enable; -+ int wakelock_ctrl_timeout_enable; -+ -+ /* Thread to issue ioctl for multicast */ -+ unsigned char set_macaddress; -+ struct ether_addr macvalue; -+ wait_queue_head_t ctrl_wait; -+ atomic_t pend_8021x_cnt; -+ dhd_attach_states_t dhd_state; -+ -+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -+ struct early_suspend early_suspend; -+#endif /* CONFIG_HAS_EARLYSUSPEND && defined(DHD_USE_EARLYSUSPEND) */ -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+ u32 pend_ipaddr; -+#endif /* ARP_OFFLOAD_SUPPORT */ -+#ifdef BCM_FD_AGGR -+ void *rpc_th; -+ void *rpc_osh; -+ struct timer_list rpcth_timer; -+ bool rpcth_timer_active; -+ bool fdaggr; -+#endif -+} dhd_info_t; -+ -+/* Flag to indicate if we should download firmware on driver load */ -+uint dhd_download_fw_on_driverload = TRUE; -+ -+/* Definitions to provide path to the firmware and nvram -+ * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" -+ */ -+char firmware_path[MOD_PARAM_PATHLEN]; -+char nvram_path[MOD_PARAM_PATHLEN]; -+ -+/* information string to keep firmware, chio, cheip version info visiable from log */ -+char info_string[MOD_PARAM_INFOLEN]; -+module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); -+ -+int op_mode = 0; -+int disable_proptx = 0; -+module_param(op_mode, int, 0644); -+extern int wl_control_wl_start(struct net_device *dev); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+struct semaphore dhd_registration_sem; -+struct semaphore dhd_chipup_sem; -+int dhd_registration_check = FALSE; -+ -+#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+ -+/* Spawn a thread for system ioctls (set mac, set mcast) */ -+uint dhd_sysioc = TRUE; -+module_param(dhd_sysioc, uint, 0); -+ -+/* Error bits */ -+module_param(dhd_msg_level, int, 0); -+ -+/* Disable Prop tx */ -+module_param(disable_proptx, int, 0644); -+ -+/* load firmware and/or nvram values from the filesystem */ -+module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); -+module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); -+ -+/* Watchdog interval */ -+uint dhd_watchdog_ms = 10; -+module_param(dhd_watchdog_ms, uint, 0); -+ -+#if defined(DHD_DEBUG) -+/* Console poll interval */ -+uint dhd_console_ms = 0; -+module_param(dhd_console_ms, uint, 0644); -+#endif /* defined(DHD_DEBUG) */ -+ -+extern uint dhd_doflow; -+/* tunable paramter to update tx credit in each dpc */ -+extern uint dhd_dpcpoll; -+module_param(dhd_doflow, uint, 0644); -+module_param(dhd_dpcpoll, uint, 0644); -+uint dhd_slpauto = TRUE; -+module_param(dhd_slpauto, uint, 0); -+ -+/* ARP offload agent mode : Enable ARP Peer Auto-Reply */ -+uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; -+module_param(dhd_arp_mode, uint, 0); -+ -+/* ARP offload enable */ -+uint dhd_arp_enable = TRUE; -+module_param(dhd_arp_enable, uint, 0); -+ -+#ifdef PKT_FILTER_SUPPORT -+/* Global Pkt filter enable control */ -+uint dhd_pkt_filter_enable = TRUE; -+module_param(dhd_pkt_filter_enable, uint, 0); -+#endif -+ -+/* Pkt filter init setup */ -+uint dhd_pkt_filter_init = 0; -+module_param(dhd_pkt_filter_init, uint, 0); -+ -+/* Pkt filter mode control */ -+#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER -+uint dhd_master_mode = FALSE; -+#else -+uint dhd_master_mode = TRUE; -+#endif /* GAL_LITE_NAT_KEEPALIVE_FILTER */ -+module_param(dhd_master_mode, uint, 0); -+ -+#ifdef DHDTHREAD -+/* Watchdog thread priority, -1 to use kernel timer */ -+int dhd_watchdog_prio = 0; -+module_param(dhd_watchdog_prio, int, 0); -+ -+/* DPC thread priority */ -+int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; -+module_param(dhd_dpc_prio, int, 0); -+ -+extern int dhd_dongle_memsize; -+module_param(dhd_dongle_memsize, int, 0); -+#endif /* DHDTHREAD */ -+/* Control fw roaming */ -+uint dhd_roam_disable = 0; -+ -+/* Control radio state */ -+uint dhd_radio_up = 1; -+ -+/* Network inteface name */ -+char iface_name[IFNAMSIZ] = {'\0'}; -+module_param_string(iface_name, iface_name, IFNAMSIZ, 0); -+ -+/* The following are specific to the SDIO dongle */ -+ -+/* IOCTL response timeout */ -+int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; -+ -+/* Idle timeout for backplane clock */ -+int dhd_idletime = DHD_IDLETIME_TICKS; -+module_param(dhd_idletime, int, 0); -+ -+/* Use polling */ -+uint dhd_poll = FALSE; -+module_param(dhd_poll, uint, 0); -+ -+/* Use interrupts */ -+uint dhd_intr = TRUE; -+module_param(dhd_intr, uint, 0); -+ -+/* SDIO Drive Strength (in milliamps) */ -+uint dhd_sdiod_drive_strength = 6; -+module_param(dhd_sdiod_drive_strength, uint, 0); -+ -+/* Tx/Rx bounds */ -+extern uint dhd_txbound; -+extern uint dhd_rxbound; -+module_param(dhd_txbound, uint, 0); -+module_param(dhd_rxbound, uint, 0); -+ -+/* Deferred transmits */ -+extern uint dhd_deferred_tx; -+module_param(dhd_deferred_tx, uint, 0); -+ -+#ifdef BCMDBGFS -+extern void dhd_dbg_init(dhd_pub_t *dhdp); -+extern void dhd_dbg_remove(void); -+#endif /* BCMDBGFS */ -+ -+ -+ -+#ifdef SDTEST -+/* Echo packet generator (pkts/s) */ -+uint dhd_pktgen = 0; -+module_param(dhd_pktgen, uint, 0); -+ -+/* Echo packet len (0 => sawtooth, max 2040) */ -+uint dhd_pktgen_len = 0; -+module_param(dhd_pktgen_len, uint, 0); -+#endif /* SDTEST */ -+ -+/* Version string to report */ -+#ifdef DHD_DEBUG -+#ifndef SRCBASE -+#define SRCBASE "drivers/net/wireless/bcmdhd" -+#endif -+#define DHD_COMPILED "\nCompiled in " SRCBASE -+#else -+#define DHD_COMPILED -+#endif /* DHD_DEBUG */ -+ -+static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR -+#ifdef DHD_DEBUG -+"\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__ -+#endif -+; -+static void dhd_net_if_lock_local(dhd_info_t *dhd); -+static void dhd_net_if_unlock_local(dhd_info_t *dhd); -+static void dhd_suspend_lock(dhd_pub_t *dhdp); -+static void dhd_suspend_unlock(dhd_pub_t *dhdp); -+ -+#ifdef WLMEDIA_HTSF -+void htsf_update(dhd_info_t *dhd, void *data); -+tsf_t prev_tsf, cur_tsf; -+ -+uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); -+static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); -+static void dhd_dump_latency(void); -+static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); -+static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); -+static void dhd_dump_htsfhisto(histo_t *his, char *s); -+#endif /* WLMEDIA_HTSF */ -+ -+/* Monitor interface */ -+int dhd_monitor_init(void *dhd_pub); -+int dhd_monitor_uninit(void); -+ -+ -+#if defined(CONFIG_WIRELESS_EXT) -+struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+static void dhd_dpc(ulong data); -+/* forward decl */ -+extern int dhd_wait_pend8021x(struct net_device *dev); -+ -+#ifdef TOE -+#ifndef BDC -+#error TOE requires BDC -+#endif /* !BDC */ -+static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); -+static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); -+#endif /* TOE */ -+ -+static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, -+ wl_event_msg_t *event_ptr, void **data_ptr); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -+static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) -+{ -+ int ret = NOTIFY_DONE; -+ -+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) -+ switch (action) { -+ case PM_HIBERNATION_PREPARE: -+ case PM_SUSPEND_PREPARE: -+ dhd_mmc_suspend = TRUE; -+ ret = NOTIFY_OK; -+ break; -+ case PM_POST_HIBERNATION: -+ case PM_POST_SUSPEND: -+ dhd_mmc_suspend = FALSE; -+ ret = NOTIFY_OK; -+ break; -+ } -+ smp_mb(); -+#endif -+ return ret; -+} -+ -+static struct notifier_block dhd_sleep_pm_notifier = { -+ .notifier_call = dhd_sleep_pm_callback, -+ .priority = 10 -+}; -+extern int register_pm_notifier(struct notifier_block *nb); -+extern int unregister_pm_notifier(struct notifier_block *nb); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -+ -+void dhd_set_packet_filter(dhd_pub_t *dhd) -+{ -+#ifdef PKT_FILTER_SUPPORT -+ int i; -+ -+ DHD_TRACE(("%s: enter\n", __FUNCTION__)); -+ if (dhd_pkt_filter_enable) { -+ for (i = 0; i < dhd->pktfilter_count; i++) { -+ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); -+ } -+ } -+#endif /* PKT_FILTER_SUPPORT */ -+} -+ -+void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) -+{ -+#ifdef PKT_FILTER_SUPPORT -+ int i; -+ -+ DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); -+ /* 1 - Enable packet filter, only allow unicast packet to send up */ -+ /* 0 - Disable packet filter */ -+ if (dhd_pkt_filter_enable && (!value || -+ (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) { -+ for (i = 0; i < dhd->pktfilter_count; i++) { -+#ifdef PASS_ARP_PACKET -+ if (value && (i == dhd->pktfilter_count -1) && -+ !(dhd->op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) { -+ DHD_TRACE_HW4(("Do not turn on ARP white list pkt filter:" -+ "val %d, cnt %d, op_mode 0x%x\n", -+ value, i, dhd->op_mode)); -+ continue; -+ } -+#endif -+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], -+ value, dhd_master_mode); -+ } -+ } -+#endif /* PKT_FILTER_SUPPORT */ -+} -+ -+static int dhd_set_suspend(int value, dhd_pub_t *dhd) -+{ -+#if !defined(SUPPORT_PM2_ONLY) -+ int power_mode = PM_MAX; -+#endif -+ /* wl_pkt_filter_enable_t enable_parm; */ -+ char iovbuf[32]; -+ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ -+#ifndef DISABLE_FW_ROAM_SUSPEND -+ uint roamvar = 1; -+#endif -+#ifdef ENABLE_BCN_LI_BCN_WAKEUP -+ int bcn_li_bcn; -+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -+#ifdef PASS_ALL_MCAST_PKTS -+ struct dhd_info *dhdinfo = dhd->info; -+ uint32 allmulti; -+ uint i; -+#endif /* PASS_ALL_MCAST_PKTS */ -+ -+ DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", -+ __FUNCTION__, value, dhd->in_suspend)); -+ -+ dhd_suspend_lock(dhd); -+ if (dhd && dhd->up) { -+ if (value && dhd->in_suspend) { -+#ifdef PKT_FILTER_SUPPORT -+ dhd->early_suspended = 1; -+#endif -+ /* Kernel suspended */ -+ DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__)); -+ -+#if !defined(SUPPORT_PM2_ONLY) -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, -+ sizeof(power_mode), TRUE, 0); -+#endif -+ /* Enable packet filter, only allow unicast packet to send up */ -+ dhd_enable_packet_filter(1, dhd); -+#ifdef PASS_ALL_MCAST_PKTS -+ allmulti = 0; -+ bcm_mkiovar("allmulti", (char *)&allmulti, -+ 4, iovbuf, sizeof(iovbuf)); -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, -+ sizeof(iovbuf), TRUE, i); -+ } -+#endif /* PASS_ALL_MCAST_PKTS */ -+ -+ /* If DTIM skip is set up as default, force it to wake -+ * each third DTIM for better power savings. Note that -+ * one side effect is a chance to miss BC/MC packet. -+ */ -+ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); -+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, -+ 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+ -+#ifndef DISABLE_FW_ROAM_SUSPEND -+ /* Disable firmware roaming during suspend */ -+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, -+ iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#endif -+#ifdef ENABLE_BCN_LI_BCN_WAKEUP -+ bcn_li_bcn = 0; -+ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, -+ 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -+ -+ } else { -+#ifdef PKT_FILTER_SUPPORT -+ dhd->early_suspended = 0; -+#endif -+ /* Kernel resumed */ -+ DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__)); -+ -+#if !defined(SUPPORT_PM2_ONLY) -+ power_mode = PM_FAST; -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, -+ sizeof(power_mode), TRUE, 0); -+#endif -+ /* disable pkt filter */ -+ dhd_enable_packet_filter(0, dhd); -+#ifdef PASS_ALL_MCAST_PKTS -+ allmulti = 1; -+ bcm_mkiovar("allmulti", (char *)&allmulti, -+ 4, iovbuf, sizeof(iovbuf)); -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, -+ sizeof(iovbuf), TRUE, i); -+ } -+#endif /* PASS_ALL_MCAST_PKTS */ -+ -+ /* restore pre-suspend setting for dtim_skip */ -+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, -+ 4, iovbuf, sizeof(iovbuf)); -+ -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#ifndef DISABLE_FW_ROAM_SUSPEND -+ roamvar = dhd_roam_disable; -+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, -+ sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#endif -+#ifdef ENABLE_BCN_LI_BCN_WAKEUP -+ bcn_li_bcn = 1; -+ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, -+ 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -+ -+ } -+ } -+ -+ dhd_suspend_unlock(dhd); -+ return 0; -+} -+ -+static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) -+{ -+ dhd_pub_t *dhdp = &dhd->pub; -+ int ret = 0; -+ -+ DHD_OS_WAKE_LOCK(dhdp); -+ /* Set flag when early suspend was called */ -+ dhdp->in_suspend = val; -+ if ((force || !dhdp->suspend_disable_flag) && -+ dhd_support_sta_mode(dhdp)) -+ { -+ ret = dhd_set_suspend(val, dhdp); -+ } -+ -+ DHD_OS_WAKE_UNLOCK(dhdp); -+ return ret; -+} -+ -+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -+static void dhd_early_suspend(struct early_suspend *h) -+{ -+ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); -+ DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); -+ -+ if (dhd) -+ dhd_suspend_resume_helper(dhd, 1, 0); -+} -+ -+static void dhd_late_resume(struct early_suspend *h) -+{ -+ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); -+ DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); -+ -+ if (dhd) -+ dhd_suspend_resume_helper(dhd, 0, 0); -+} -+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ -+ -+/* -+ * Generalized timeout mechanism. Uses spin sleep with exponential back-off until -+ * the sleep time reaches one jiffy, then switches over to task delay. Usage: -+ * -+ * dhd_timeout_start(&tmo, usec); -+ * while (!dhd_timeout_expired(&tmo)) -+ * if (poll_something()) -+ * break; -+ * if (dhd_timeout_expired(&tmo)) -+ * fatal(); -+ */ -+ -+void -+dhd_timeout_start(dhd_timeout_t *tmo, uint usec) -+{ -+ tmo->limit = usec; -+ tmo->increment = 0; -+ tmo->elapsed = 0; -+ tmo->tick = jiffies_to_usecs(1); -+} -+ -+int -+dhd_timeout_expired(dhd_timeout_t *tmo) -+{ -+ /* Does nothing the first call */ -+ if (tmo->increment == 0) { -+ tmo->increment = 1; -+ return 0; -+ } -+ -+ if (tmo->elapsed >= tmo->limit) -+ return 1; -+ -+ /* Add the delay that's about to take place */ -+ tmo->elapsed += tmo->increment; -+ -+ if (tmo->increment < tmo->tick) { -+ OSL_DELAY(tmo->increment); -+ tmo->increment *= 2; -+ if (tmo->increment > tmo->tick) -+ tmo->increment = tmo->tick; -+ } else { -+ wait_queue_head_t delay_wait; -+ DECLARE_WAITQUEUE(wait, current); -+ init_waitqueue_head(&delay_wait); -+ add_wait_queue(&delay_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(1); -+ remove_wait_queue(&delay_wait, &wait); -+ set_current_state(TASK_RUNNING); -+ } -+ -+ return 0; -+} -+ -+int -+dhd_net2idx(dhd_info_t *dhd, struct net_device *net) -+{ -+ int i = 0; -+ -+ ASSERT(dhd); -+ while (i < DHD_MAX_IFS) { -+ if (dhd->iflist[i] && (dhd->iflist[i]->net == net)) -+ return i; -+ i++; -+ } -+ -+ return DHD_BAD_IF; -+} -+ -+struct net_device * dhd_idx2net(void *pub, int ifidx) -+{ -+ struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; -+ struct dhd_info *dhd_info; -+ -+ if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) -+ return NULL; -+ dhd_info = dhd_pub->info; -+ if (dhd_info && dhd_info->iflist[ifidx]) -+ return dhd_info->iflist[ifidx]->net; -+ return NULL; -+} -+ -+int -+dhd_ifname2idx(dhd_info_t *dhd, char *name) -+{ -+ int i = DHD_MAX_IFS; -+ -+ ASSERT(dhd); -+ -+ if (name == NULL || *name == '\0') -+ return 0; -+ -+ while (--i > 0) -+ if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) -+ break; -+ -+ DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); -+ -+ return i; /* default - the primary interface */ -+} -+ -+char * -+dhd_ifname(dhd_pub_t *dhdp, int ifidx) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -+ -+ ASSERT(dhd); -+ -+ if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { -+ DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); -+ return "<if_bad>"; -+ } -+ -+ if (dhd->iflist[ifidx] == NULL) { -+ DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); -+ return "<if_null>"; -+ } -+ -+ if (dhd->iflist[ifidx]->net) -+ return dhd->iflist[ifidx]->net->name; -+ -+ return "<if_none>"; -+} -+ -+uint8 * -+dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) -+{ -+ int i; -+ dhd_info_t *dhd = (dhd_info_t *)dhdp; -+ -+ ASSERT(dhd); -+ for (i = 0; i < DHD_MAX_IFS; i++) -+ if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) -+ return dhd->iflist[i]->mac_addr; -+ -+ return NULL; -+} -+ -+ -+static void -+_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) -+{ -+ struct net_device *dev; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) -+ struct netdev_hw_addr *ha; -+#else -+ struct dev_mc_list *mclist; -+#endif -+ uint32 allmulti, cnt; -+ -+ wl_ioctl_t ioc; -+ char *buf, *bufp; -+ uint buflen; -+ int ret; -+ -+ ASSERT(dhd && dhd->iflist[ifidx]); -+ dev = dhd->iflist[ifidx]->net; -+ if (!dev) -+ return; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) -+ netif_addr_lock_bh(dev); -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) -+ cnt = netdev_mc_count(dev); -+#else -+ cnt = dev->mc_count; -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) -+ netif_addr_unlock_bh(dev); -+#endif -+ -+ /* Determine initial value of allmulti flag */ -+ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; -+#ifdef PASS_ALL_MCAST_PKTS -+#ifdef PKT_FILTER_SUPPORT -+ if (!dhd->pub.early_suspended) -+#endif /* PKT_FILTER_SUPPORT */ -+ allmulti = TRUE; -+#endif /* PASS_ALL_MCAST_PKTS */ -+ -+ /* Send down the multicast list first. */ -+ -+ -+ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); -+ if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { -+ DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", -+ dhd_ifname(&dhd->pub, ifidx), cnt)); -+ return; -+ } -+ -+ strncpy(bufp, "mcast_list", buflen - 1); -+ bufp[buflen - 1] = '\0'; -+ bufp += strlen("mcast_list") + 1; -+ -+ cnt = htol32(cnt); -+ memcpy(bufp, &cnt, sizeof(cnt)); -+ bufp += sizeof(cnt); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) -+ netif_addr_lock_bh(dev); -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) -+ netdev_for_each_mc_addr(ha, dev) { -+ if (!cnt) -+ break; -+ memcpy(bufp, ha->addr, ETHER_ADDR_LEN); -+ bufp += ETHER_ADDR_LEN; -+ cnt--; -+ } -+#else -+ for (mclist = dev->mc_list; (mclist && (cnt > 0)); -+ cnt--, mclist = mclist->next) { -+ memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); -+ bufp += ETHER_ADDR_LEN; -+ } -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) -+ netif_addr_unlock_bh(dev); -+#endif -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ ioc.cmd = WLC_SET_VAR; -+ ioc.buf = buf; -+ ioc.len = buflen; -+ ioc.set = TRUE; -+ -+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); -+ if (ret < 0) { -+ DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", -+ dhd_ifname(&dhd->pub, ifidx), cnt)); -+ allmulti = cnt ? TRUE : allmulti; -+ } -+ -+ MFREE(dhd->pub.osh, buf, buflen); -+ -+ /* Now send the allmulti setting. This is based on the setting in the -+ * net_device flags, but might be modified above to be turned on if we -+ * were trying to set some addresses and dongle rejected it... -+ */ -+ -+ buflen = sizeof("allmulti") + sizeof(allmulti); -+ if (!(buf = MALLOC(dhd->pub.osh, buflen))) { -+ DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx))); -+ return; -+ } -+ allmulti = htol32(allmulti); -+ -+ if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) { -+ DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n", -+ dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen)); -+ MFREE(dhd->pub.osh, buf, buflen); -+ return; -+ } -+ -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ ioc.cmd = WLC_SET_VAR; -+ ioc.buf = buf; -+ ioc.len = buflen; -+ ioc.set = TRUE; -+ -+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); -+ if (ret < 0) { -+ DHD_ERROR(("%s: set allmulti %d failed\n", -+ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); -+ } -+ -+ MFREE(dhd->pub.osh, buf, buflen); -+ -+ /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ -+ -+ allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; -+ allmulti = htol32(allmulti); -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ ioc.cmd = WLC_SET_PROMISC; -+ ioc.buf = &allmulti; -+ ioc.len = sizeof(allmulti); -+ ioc.set = TRUE; -+ -+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); -+ if (ret < 0) { -+ DHD_ERROR(("%s: set promisc %d failed\n", -+ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); -+ } -+} -+ -+int -+_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) -+{ -+ char buf[32]; -+ wl_ioctl_t ioc; -+ int ret; -+ -+ if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) { -+ DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx))); -+ return -1; -+ } -+ memset(&ioc, 0, sizeof(ioc)); -+ ioc.cmd = WLC_SET_VAR; -+ ioc.buf = buf; -+ ioc.len = 32; -+ ioc.set = TRUE; -+ -+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); -+ if (ret < 0) { -+ DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); -+ } else { -+ memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); -+ memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); -+ } -+ -+ return ret; -+} -+ -+#ifdef SOFTAP -+extern struct net_device *ap_net_dev; -+extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ -+#endif -+ -+static void -+dhd_op_if(dhd_if_t *ifp) -+{ -+ dhd_info_t *dhd; -+ int ret = 0, err = 0; -+#ifdef SOFTAP -+ unsigned long flags; -+#endif -+ -+ if (!ifp || !ifp->info || !ifp->idx) -+ return; -+ ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ -+ dhd = ifp->info; -+ -+ DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state)); -+ -+#ifdef WL_CFG80211 -+ if (wl_cfg80211_is_progress_ifchange()) -+ return; -+ -+#endif -+ switch (ifp->state) { -+ case DHD_IF_ADD: -+ /* -+ * Delete the existing interface before overwriting it -+ * in case we missed the WLC_E_IF_DEL event. -+ */ -+ if (ifp->net != NULL) { -+ DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n", -+ __FUNCTION__, ifp->net->name)); -+ netif_stop_queue(ifp->net); -+ unregister_netdev(ifp->net); -+ free_netdev(ifp->net); -+ } -+ /* Allocate etherdev, including space for private structure */ -+ if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) { -+ DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); -+ ret = -ENOMEM; -+ } -+ if (ret == 0) { -+ strncpy(ifp->net->name, ifp->name, IFNAMSIZ); -+ ifp->net->name[IFNAMSIZ - 1] = '\0'; -+ memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd)); -+#ifdef WL_CFG80211 -+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) -+ if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, -+ (void*)dhd_net_attach)) { -+ ifp->state = DHD_IF_NONE; -+ ifp->event2cfg80211 = TRUE; -+ return; -+ } -+#endif -+ if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) { -+ DHD_ERROR(("%s: dhd_net_attach failed, err %d\n", -+ __FUNCTION__, err)); -+ ret = -EOPNOTSUPP; -+ } else { -+#if defined(SOFTAP) -+ if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { -+ /* semaphore that the soft AP CODE waits on */ -+ flags = dhd_os_spin_lock(&dhd->pub); -+ -+ /* save ptr to wl0.1 netdev for use in wl_iw.c */ -+ ap_net_dev = ifp->net; -+ /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ -+ up(&ap_eth_ctl.sema); -+ dhd_os_spin_unlock(&dhd->pub, flags); -+ } -+#endif -+ DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n", -+ current->pid, ifp->net->name)); -+ ifp->state = DHD_IF_NONE; -+ } -+ } -+ break; -+ case DHD_IF_DEL: -+ /* Make sure that we don't enter again here if .. */ -+ /* dhd_op_if is called again from some other context */ -+ ifp->state = DHD_IF_DELETING; -+ if (ifp->net != NULL) { -+ DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__)); -+ netif_stop_queue(ifp->net); -+#ifdef WL_CFG80211 -+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { -+ wl_cfg80211_ifdel_ops(ifp->net); -+ } -+#endif -+ unregister_netdev(ifp->net); -+ ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ -+#ifdef WL_CFG80211 -+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { -+ wl_cfg80211_notify_ifdel(); -+ } -+#endif -+ } -+ break; -+ case DHD_IF_DELETING: -+ break; -+ default: -+ DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state)); -+ ASSERT(!ifp->state); -+ break; -+ } -+ -+ if (ret < 0) { -+ ifp->set_multicast = FALSE; -+ if (ifp->net) { -+ free_netdev(ifp->net); -+ ifp->net = NULL; -+ } -+ dhd->iflist[ifp->idx] = NULL; -+#ifdef SOFTAP -+ flags = dhd_os_spin_lock(&dhd->pub); -+ if (ifp->net == ap_net_dev) -+ ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ -+ dhd_os_spin_unlock(&dhd->pub, flags); -+#endif /* SOFTAP */ -+ MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); -+ } -+} -+ -+static int -+_dhd_sysioc_thread(void *data) -+{ -+ tsk_ctl_t *tsk = (tsk_ctl_t *)data; -+ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; -+ -+ -+ int i; -+#ifdef SOFTAP -+ bool in_ap = FALSE; -+ unsigned long flags; -+#endif -+ -+ DAEMONIZE("dhd_sysioc"); -+ -+ complete(&tsk->completed); -+ -+ while (down_interruptible(&tsk->sema) == 0) { -+ -+ SMP_RD_BARRIER_DEPENDS(); -+ if (tsk->terminated) { -+ break; -+ } -+ -+ dhd_net_if_lock_local(dhd); -+ DHD_OS_WAKE_LOCK(&dhd->pub); -+ -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ if (dhd->iflist[i]) { -+ DHD_TRACE(("%s: interface %d\n", __FUNCTION__, i)); -+#ifdef SOFTAP -+ flags = dhd_os_spin_lock(&dhd->pub); -+ in_ap = (ap_net_dev != NULL); -+ dhd_os_spin_unlock(&dhd->pub, flags); -+#endif /* SOFTAP */ -+ if (dhd->iflist[i] && dhd->iflist[i]->state) -+ dhd_op_if(dhd->iflist[i]); -+ -+ if (dhd->iflist[i] == NULL) { -+ DHD_TRACE(("\n\n %s: interface %d just been removed," -+ "!\n\n", __FUNCTION__, i)); -+ continue; -+ } -+#ifdef SOFTAP -+ if (in_ap && dhd->set_macaddress == i+1) { -+ DHD_TRACE(("attempt to set MAC for %s in AP Mode," -+ "blocked. \n", dhd->iflist[i]->net->name)); -+ dhd->set_macaddress = 0; -+ continue; -+ } -+ -+ if (in_ap && dhd->iflist[i]->set_multicast) { -+ DHD_TRACE(("attempt to set MULTICAST list for %s" -+ "in AP Mode, blocked. \n", dhd->iflist[i]->net->name)); -+ dhd->iflist[i]->set_multicast = FALSE; -+ continue; -+ } -+#endif /* SOFTAP */ -+ if (dhd->pub.up == 0) -+ continue; -+ if (dhd->iflist[i]->set_multicast) { -+ dhd->iflist[i]->set_multicast = FALSE; -+ _dhd_set_multicast_list(dhd, i); -+ } -+ if (dhd->set_macaddress == i+1) { -+ dhd->set_macaddress = 0; -+ if (_dhd_set_mac_address(dhd, i, &dhd->macvalue) == 0) { -+ DHD_INFO(( -+ "dhd_sysioc_thread: MACID is overwritten\n")); -+ } else { -+ DHD_ERROR(( -+ "dhd_sysioc_thread: _dhd_set_mac_address() failed\n")); -+ } -+ } -+ } -+ } -+ -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ dhd_net_if_unlock_local(dhd); -+ } -+ DHD_TRACE(("%s: stopped\n", __FUNCTION__)); -+ complete_and_exit(&tsk->completed, 0); -+} -+ -+static int -+dhd_set_mac_address(struct net_device *dev, void *addr) -+{ -+ int ret = 0; -+ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ struct sockaddr *sa = (struct sockaddr *)addr; -+ int ifidx; -+ -+ ifidx = dhd_net2idx(dhd, dev); -+ if (ifidx == DHD_BAD_IF) -+ return -1; -+ -+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); -+ memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); -+ dhd->set_macaddress = ifidx+1; -+ up(&dhd->thr_sysioc_ctl.sema); -+ -+ return ret; -+} -+ -+static void -+dhd_set_multicast_list(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ifidx; -+ -+ ifidx = dhd_net2idx(dhd, dev); -+ if (ifidx == DHD_BAD_IF) -+ return; -+ -+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); -+ dhd->iflist[ifidx]->set_multicast = TRUE; -+ up(&dhd->thr_sysioc_ctl.sema); -+} -+ -+#ifdef PROP_TXSTATUS -+int -+dhd_os_wlfc_block(dhd_pub_t *pub) -+{ -+ dhd_info_t *di = (dhd_info_t *)(pub->info); -+ ASSERT(di != NULL); -+ spin_lock_bh(&di->wlfc_spinlock); -+ return 1; -+} -+ -+int -+dhd_os_wlfc_unblock(dhd_pub_t *pub) -+{ -+ dhd_info_t *di = (dhd_info_t *)(pub->info); -+ -+ ASSERT(di != NULL); -+ spin_unlock_bh(&di->wlfc_spinlock); -+ return 1; -+} -+ -+const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; -+uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; -+#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] -+ -+#endif /* PROP_TXSTATUS */ -+int -+dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -+{ -+ int ret; -+ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); -+ struct ether_header *eh = NULL; -+ -+ /* Reject if down */ -+ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { -+ /* free the packet here since the caller won't */ -+ PKTFREE(dhdp->osh, pktbuf, TRUE); -+ return -ENODEV; -+ } -+ -+ /* Update multicast statistic */ -+ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { -+ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); -+ eh = (struct ether_header *)pktdata; -+ -+ if (ETHER_ISMULTI(eh->ether_dhost)) -+ dhdp->tx_multicast++; -+ if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) -+ atomic_inc(&dhd->pend_8021x_cnt); -+ } else { -+ PKTFREE(dhd->pub.osh, pktbuf, TRUE); -+ return BCME_ERROR; -+ } -+ -+ /* Look into the packet and update the packet priority */ -+#ifndef PKTPRIO_OVERRIDE -+ if (PKTPRIO(pktbuf) == 0) -+#endif -+ pktsetprio(pktbuf, FALSE); -+ -+#ifdef PROP_TXSTATUS -+ if (dhdp->wlfc_state) { -+ /* store the interface ID */ -+ DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); -+ -+ /* store destination MAC in the tag as well */ -+ DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); -+ -+ /* decide which FIFO this packet belongs to */ -+ if (ETHER_ISMULTI(eh->ether_dhost)) -+ /* one additional queue index (highest AC + 1) is used for bc/mc queue */ -+ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); -+ else -+ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); -+ } else -+#endif /* PROP_TXSTATUS */ -+ /* If the protocol uses a data header, apply it */ -+ dhd_prot_hdrpush(dhdp, ifidx, pktbuf); -+ -+ /* Use bus module to send data frame */ -+#ifdef WLMEDIA_HTSF -+ dhd_htsf_addtxts(dhdp, pktbuf); -+#endif -+#ifdef PROP_TXSTATUS -+ dhd_os_wlfc_block(dhdp); -+ if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode -+ != WLFC_FCMODE_NONE) { -+ ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)), -+ pktbuf); -+ dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, -+ dhdp->bus); -+ if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { -+ ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; -+ } -+ dhd_os_wlfc_unblock(dhdp); -+ } -+ else { -+ dhd_os_wlfc_unblock(dhdp); -+ /* non-proptxstatus way */ -+ ret = dhd_bus_txdata(dhdp->bus, pktbuf); -+ } -+#else -+ ret = dhd_bus_txdata(dhdp->bus, pktbuf); -+#endif /* PROP_TXSTATUS */ -+ -+ return ret; -+} -+ -+int -+dhd_start_xmit(struct sk_buff *skb, struct net_device *net) -+{ -+ int ret; -+ void *pktbuf; -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -+ int ifidx; -+#ifdef WLMEDIA_HTSF -+ uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; -+#else -+ uint8 htsfdlystat_sz = 0; -+#endif -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ DHD_OS_WAKE_LOCK(&dhd->pub); -+ -+ /* Reject if down */ -+ if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { -+ DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", -+ __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); -+ netif_stop_queue(net); -+ /* Send Event when bus down detected during data session */ -+ if (dhd->pub.up) { -+ DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); -+ net_os_send_hang_message(net); -+ } -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) -+ return -ENODEV; -+#else -+ return NETDEV_TX_BUSY; -+#endif -+ } -+ -+ ifidx = dhd_net2idx(dhd, net); -+ if (ifidx == DHD_BAD_IF) { -+ DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); -+ netif_stop_queue(net); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) -+ return -ENODEV; -+#else -+ return NETDEV_TX_BUSY; -+#endif -+ } -+ -+ /* Make sure there's enough room for any header */ -+ -+ if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { -+ struct sk_buff *skb2; -+ -+ DHD_INFO(("%s: insufficient headroom\n", -+ dhd_ifname(&dhd->pub, ifidx))); -+ dhd->pub.tx_realloc++; -+ -+ skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); -+ -+ dev_kfree_skb(skb); -+ if ((skb = skb2) == NULL) { -+ DHD_ERROR(("%s: skb_realloc_headroom failed\n", -+ dhd_ifname(&dhd->pub, ifidx))); -+ ret = -ENOMEM; -+ goto done; -+ } -+ } -+ -+ /* Convert to packet */ -+ if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { -+ DHD_ERROR(("%s: PKTFRMNATIVE failed\n", -+ dhd_ifname(&dhd->pub, ifidx))); -+ dev_kfree_skb_any(skb); -+ ret = -ENOMEM; -+ goto done; -+ } -+#ifdef WLMEDIA_HTSF -+ if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { -+ uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); -+ struct ether_header *eh = (struct ether_header *)pktdata; -+ -+ if (!ETHER_ISMULTI(eh->ether_dhost) && -+ (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { -+ eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); -+ } -+ } -+#endif -+ -+ ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); -+ -+ -+done: -+ if (ret) -+ dhd->pub.dstats.tx_dropped++; -+ else -+ dhd->pub.tx_packets++; -+ -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ -+ /* Return ok: we always eat the packet */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) -+ return 0; -+#else -+ return NETDEV_TX_OK; -+#endif -+} -+ -+void -+dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) -+{ -+ struct net_device *net; -+ dhd_info_t *dhd = dhdp->info; -+ int i; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ ASSERT(dhd); -+ -+ if (ifidx == ALL_INTERFACES) { -+ /* Flow control on all active interfaces */ -+ dhdp->txoff = state; -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ if (dhd->iflist[i]) { -+ net = dhd->iflist[i]->net; -+ if (state == ON) -+ netif_stop_queue(net); -+ else -+ netif_wake_queue(net); -+ } -+ } -+ } -+ else { -+ if (dhd->iflist[ifidx]) { -+ net = dhd->iflist[ifidx]->net; -+ if (state == ON) -+ netif_stop_queue(net); -+ else -+ netif_wake_queue(net); -+ } -+ } -+} -+ -+#ifdef DHD_RX_DUMP -+typedef struct { -+ uint16 type; -+ const char *str; -+} PKTTYPE_INFO; -+ -+static const PKTTYPE_INFO packet_type_info[] = -+{ -+ { ETHER_TYPE_IP, "IP" }, -+ { ETHER_TYPE_ARP, "ARP" }, -+ { ETHER_TYPE_BRCM, "BRCM" }, -+ { ETHER_TYPE_802_1X, "802.1X" }, -+ { ETHER_TYPE_WAI, "WAPI" }, -+ { 0, ""} -+}; -+ -+static const char *_get_packet_type_str(uint16 type) -+{ -+ int i; -+ int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; -+ -+ for (i = 0; i < n; i++) { -+ if (packet_type_info[i].type == type) -+ return packet_type_info[i].str; -+ } -+ -+ return packet_type_info[n].str; -+} -+#endif /* DHD_RX_DUMP */ -+ -+void -+dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -+ struct sk_buff *skb; -+ uchar *eth; -+ uint len; -+ void *data, *pnext = NULL; -+ int i; -+ dhd_if_t *ifp; -+ wl_event_msg_t event; -+ int tout_rx = 0; -+ int tout_ctrl = 0; -+ -+#ifdef DHD_RX_DUMP -+#ifdef DHD_RX_FULL_DUMP -+ int k; -+#endif /* DHD_RX_FULL_DUMP */ -+ char *dump_data; -+ uint16 protocol; -+#endif /* DHD_RX_DUMP */ -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { -+#ifdef WLBTAMP -+ struct ether_header *eh; -+ struct dot11_llc_snap_header *lsh; -+#endif -+ -+ ifp = dhd->iflist[ifidx]; -+ if (ifp == NULL) { -+ DHD_ERROR(("%s: ifp is NULL. drop packet\n", -+ __FUNCTION__)); -+ pnext = PKTNEXT(dhdp->osh, pktbuf); -+ PKTSETNEXT(wl->sh.osh, pktbuf, NULL); -+ PKTFREE(dhdp->osh, pktbuf, TRUE); -+ continue; -+ } -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+ /* Dropping packets before registering net device to avoid kernel panic */ -+#ifndef PROP_TXSTATUS_VSDB -+ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) { -+#else -+ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) { -+#endif /* PROP_TXSTATUS_VSDB */ -+ DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", -+ __FUNCTION__)); -+ pnext = PKTNEXT(dhdp->osh, pktbuf); -+ PKTSETNEXT(wl->sh.osh, pktbuf, NULL); -+ PKTFREE(dhdp->osh, pktbuf, TRUE); -+ continue; -+ } -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ -+ -+ pnext = PKTNEXT(dhdp->osh, pktbuf); -+ PKTSETNEXT(wl->sh.osh, pktbuf, NULL); -+ -+#ifdef WLBTAMP -+ eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf); -+ lsh = (struct dot11_llc_snap_header *)&eh[1]; -+ -+ if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) && -+ (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) && -+ bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && -+ lsh->type == HTON16(BTA_PROT_L2CAP)) { -+ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *) -+ ((uint8 *)eh + RFC1042_HDR_LEN); -+ ACL_data = NULL; -+ } -+#endif /* WLBTAMP */ -+ -+#ifdef PROP_TXSTATUS -+ if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) { -+ /* WLFC may send header only packet when -+ there is an urgent message but no packet to -+ piggy-back on -+ */ -+ ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; -+ PKTFREE(dhdp->osh, pktbuf, TRUE); -+ continue; -+ } -+#endif -+ -+ skb = PKTTONATIVE(dhdp->osh, pktbuf); -+ -+ /* Get the protocol, maintain skb around eth_type_trans() -+ * The main reason for this hack is for the limitation of -+ * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' -+ * to perform skb_pull inside vs ETH_HLEN. Since to avoid -+ * coping of the packet coming from the network stack to add -+ * BDC, Hardware header etc, during network interface registration -+ * we set the 'net->hard_header_len' to ETH_HLEN + extra space required -+ * for BDC, Hardware header etc. and not just the ETH_HLEN -+ */ -+ eth = skb->data; -+ len = skb->len; -+ -+#ifdef DHD_RX_DUMP -+ dump_data = skb->data; -+ protocol = (dump_data[12] << 8) | dump_data[13]; -+ DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); -+ -+#ifdef DHD_RX_FULL_DUMP -+ if (protocol != ETHER_TYPE_BRCM) { -+ for (k = 0; k < skb->len; k++) { -+ DHD_ERROR(("%02X ", dump_data[k])); -+ if ((k & 15) == 15) -+ DHD_ERROR(("\n")); -+ } -+ DHD_ERROR(("\n")); -+ } -+#endif /* DHD_RX_FULL_DUMP */ -+ -+ if (protocol != ETHER_TYPE_BRCM) { -+ if (dump_data[0] == 0xFF) { -+ DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); -+ -+ if ((dump_data[12] == 8) && -+ (dump_data[13] == 6)) { -+ DHD_ERROR(("%s: ARP %d\n", -+ __FUNCTION__, dump_data[0x15])); -+ } -+ } else if (dump_data[0] & 1) { -+ DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", -+ __FUNCTION__, MAC2STRDBG(dump_data))); -+ } -+ -+ if (protocol == ETHER_TYPE_802_1X) { -+ DHD_ERROR(("ETHER_TYPE_802_1X: " -+ "ver %d, type %d, replay %d\n", -+ dump_data[14], dump_data[15], -+ dump_data[30])); -+ } -+ } -+ -+#endif /* DHD_RX_DUMP */ -+ -+ ifp = dhd->iflist[ifidx]; -+ if (ifp == NULL) -+ ifp = dhd->iflist[0]; -+ -+ ASSERT(ifp); -+ skb->dev = ifp->net; -+ skb->protocol = eth_type_trans(skb, skb->dev); -+ -+ if (skb->pkt_type == PACKET_MULTICAST) { -+ dhd->pub.rx_multicast++; -+ } -+ -+ skb->data = eth; -+ skb->len = len; -+ -+#ifdef WLMEDIA_HTSF -+ dhd_htsf_addrxts(dhdp, pktbuf); -+#endif -+ /* Strip header, count, deliver upward */ -+ skb_pull(skb, ETH_HLEN); -+ -+ /* Process special event packets and then discard them */ -+ if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { -+ dhd_wl_host_event(dhd, &ifidx, -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -+ skb->mac_header, -+#else -+ skb->mac.raw, -+#endif -+ &event, -+ &data); -+ -+ wl_event_to_host_order(&event); -+ if (!tout_ctrl) -+ tout_ctrl = DHD_PACKET_TIMEOUT_MS; -+#ifdef WLBTAMP -+ if (event.event_type == WLC_E_BTA_HCI_EVENT) { -+ dhd_bta_doevt(dhdp, data, event.datalen); -+ } -+#endif /* WLBTAMP */ -+ -+#if defined(PNO_SUPPORT) -+ if (event.event_type == WLC_E_PFN_NET_FOUND) { -+ /* enforce custom wake lock to garantee that Kernel not suspended */ -+ tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; -+ } -+#endif /* PNO_SUPPORT */ -+ -+#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -+ PKTFREE(dhdp->osh, pktbuf, TRUE); -+ continue; -+#endif -+ } else { -+ tout_rx = DHD_PACKET_TIMEOUT_MS; -+ } -+ -+ ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); -+ if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) -+ ifp = dhd->iflist[ifidx]; -+ -+ if (ifp->net) -+ ifp->net->last_rx = jiffies; -+ -+ dhdp->dstats.rx_bytes += skb->len; -+ dhdp->rx_packets++; /* Local count */ -+ -+ if (in_interrupt()) { -+ netif_rx(skb); -+ } else { -+ /* If the receive is not processed inside an ISR, -+ * the softirqd must be woken explicitly to service -+ * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled -+ * by netif_rx_ni(), but in earlier kernels, we need -+ * to do it manually. -+ */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+ netif_rx_ni(skb); -+#else -+ ulong flags; -+ netif_rx(skb); -+ local_irq_save(flags); -+ RAISE_RX_SOFTIRQ(); -+ local_irq_restore(flags); -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ -+ } -+ } -+ -+ DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); -+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); -+} -+ -+void -+dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) -+{ -+ /* Linux version has nothing to do */ -+ return; -+} -+ -+void -+dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); -+ struct ether_header *eh; -+ uint16 type; -+#ifdef WLBTAMP -+ uint len; -+#endif -+ -+ dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); -+ -+ eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); -+ type = ntoh16(eh->ether_type); -+ -+ if (type == ETHER_TYPE_802_1X) -+ atomic_dec(&dhd->pend_8021x_cnt); -+ -+#ifdef WLBTAMP -+ /* Crack open the packet and check to see if it is BT HCI ACL data packet. -+ * If yes generate packet completion event. -+ */ -+ len = PKTLEN(dhdp->osh, txp); -+ -+ /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */ -+ if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) { -+ struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1]; -+ -+ if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && -+ ntoh16(lsh->type) == BTA_PROT_L2CAP) { -+ -+ dhd_bta_tx_hcidata_complete(dhdp, txp, success); -+ } -+ } -+#endif /* WLBTAMP */ -+} -+ -+static struct net_device_stats * -+dhd_get_stats(struct net_device *net) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -+ dhd_if_t *ifp; -+ int ifidx; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ ifidx = dhd_net2idx(dhd, net); -+ if (ifidx == DHD_BAD_IF) { -+ DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); -+ return NULL; -+ } -+ -+ ifp = dhd->iflist[ifidx]; -+ ASSERT(dhd && ifp); -+ -+ if (dhd->pub.up) { -+ /* Use the protocol to get dongle stats */ -+ dhd_prot_dstats(&dhd->pub); -+ } -+ -+ /* Copy dongle stats to net device stats */ -+ ifp->stats.rx_packets = dhd->pub.dstats.rx_packets; -+ ifp->stats.tx_packets = dhd->pub.dstats.tx_packets; -+ ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes; -+ ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes; -+ ifp->stats.rx_errors = dhd->pub.dstats.rx_errors; -+ ifp->stats.tx_errors = dhd->pub.dstats.tx_errors; -+ ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped; -+ ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped; -+ ifp->stats.multicast = dhd->pub.dstats.multicast; -+ -+ return &ifp->stats; -+} -+ -+#ifdef DHDTHREAD -+static int -+dhd_watchdog_thread(void *data) -+{ -+ tsk_ctl_t *tsk = (tsk_ctl_t *)data; -+ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; -+ /* This thread doesn't need any user-level access, -+ * so get rid of all our resources -+ */ -+ if (dhd_watchdog_prio > 0) { -+ struct sched_param param; -+ param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? -+ dhd_watchdog_prio:(MAX_RT_PRIO-1); -+ setScheduler(current, SCHED_FIFO, ¶m); -+ } -+ -+ DAEMONIZE("dhd_watchdog"); -+ -+ /* Run until signal received */ -+ complete(&tsk->completed); -+ -+ while (1) -+ if (down_interruptible (&tsk->sema) == 0) { -+ unsigned long flags; -+ unsigned long jiffies_at_start = jiffies; -+ unsigned long time_lapse; -+ -+ SMP_RD_BARRIER_DEPENDS(); -+ if (tsk->terminated) { -+ break; -+ } -+ -+ dhd_os_sdlock(&dhd->pub); -+ if (dhd->pub.dongle_reset == FALSE) { -+ DHD_TIMER(("%s:\n", __FUNCTION__)); -+ -+ /* Call the bus module watchdog */ -+ dhd_bus_watchdog(&dhd->pub); -+ -+ flags = dhd_os_spin_lock(&dhd->pub); -+ /* Count the tick for reference */ -+ dhd->pub.tickcnt++; -+ time_lapse = jiffies - jiffies_at_start; -+ -+ /* Reschedule the watchdog */ -+ if (dhd->wd_timer_valid) -+ mod_timer(&dhd->timer, -+ jiffies + -+ msecs_to_jiffies(dhd_watchdog_ms) - -+ min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); -+ dhd_os_spin_unlock(&dhd->pub, flags); -+ } -+ dhd_os_sdunlock(&dhd->pub); -+ } else { -+ break; -+ } -+ -+ complete_and_exit(&tsk->completed, 0); -+} -+#endif /* DHDTHREAD */ -+ -+static void dhd_watchdog(ulong data) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)data; -+ unsigned long flags; -+ -+ if (dhd->pub.dongle_reset) { -+ return; -+ } -+ -+#ifdef DHDTHREAD -+ if (dhd->thr_wdt_ctl.thr_pid >= 0) { -+ up(&dhd->thr_wdt_ctl.sema); -+ return; -+ } -+#endif /* DHDTHREAD */ -+ -+ dhd_os_sdlock(&dhd->pub); -+ /* Call the bus module watchdog */ -+ dhd_bus_watchdog(&dhd->pub); -+ -+ flags = dhd_os_spin_lock(&dhd->pub); -+ /* Count the tick for reference */ -+ dhd->pub.tickcnt++; -+ -+ /* Reschedule the watchdog */ -+ if (dhd->wd_timer_valid) -+ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); -+ dhd_os_spin_unlock(&dhd->pub, flags); -+ dhd_os_sdunlock(&dhd->pub); -+} -+ -+#ifdef DHDTHREAD -+static int -+dhd_dpc_thread(void *data) -+{ -+ tsk_ctl_t *tsk = (tsk_ctl_t *)data; -+ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; -+ -+ /* This thread doesn't need any user-level access, -+ * so get rid of all our resources -+ */ -+ if (dhd_dpc_prio > 0) -+ { -+ struct sched_param param; -+ param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); -+ setScheduler(current, SCHED_FIFO, ¶m); -+ } -+ -+ DAEMONIZE("dhd_dpc"); -+ /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ -+ -+ /* signal: thread has started */ -+ complete(&tsk->completed); -+ -+ /* Run until signal received */ -+ while (1) { -+ if (down_interruptible(&tsk->sema) == 0) { -+ -+ SMP_RD_BARRIER_DEPENDS(); -+ if (tsk->terminated) { -+ break; -+ } -+ -+ /* Call bus dpc unless it indicated down (then clean stop) */ -+ if (dhd->pub.busstate != DHD_BUS_DOWN) { -+ if (dhd_bus_dpc(dhd->pub.bus)) { -+ up(&tsk->sema); -+ } -+ else { -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ } -+ } else { -+ if (dhd->pub.up) -+ dhd_bus_stop(dhd->pub.bus, TRUE); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ } -+ } -+ else -+ break; -+ } -+ -+ complete_and_exit(&tsk->completed, 0); -+} -+#endif /* DHDTHREAD */ -+ -+static void -+dhd_dpc(ulong data) -+{ -+ dhd_info_t *dhd; -+ -+ dhd = (dhd_info_t *)data; -+ -+ /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] -+ * down below , wake lock is set, -+ * the tasklet is initialized in dhd_attach() -+ */ -+ /* Call bus dpc unless it indicated down (then clean stop) */ -+ if (dhd->pub.busstate != DHD_BUS_DOWN) { -+ if (dhd_bus_dpc(dhd->pub.bus)) -+ tasklet_schedule(&dhd->tasklet); -+ else -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ } else { -+ dhd_bus_stop(dhd->pub.bus, TRUE); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ } -+} -+ -+void -+dhd_sched_dpc(dhd_pub_t *dhdp) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -+ -+ DHD_OS_WAKE_LOCK(dhdp); -+#ifdef DHDTHREAD -+ if (dhd->thr_dpc_ctl.thr_pid >= 0) { -+ up(&dhd->thr_dpc_ctl.sema); -+ return; -+ } -+#endif /* DHDTHREAD */ -+ -+ if (dhd->dhd_tasklet_create) -+ tasklet_schedule(&dhd->tasklet); -+} -+ -+#ifdef TOE -+/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ -+static int -+dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) -+{ -+ wl_ioctl_t ioc; -+ char buf[32]; -+ int ret; -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ -+ ioc.cmd = WLC_GET_VAR; -+ ioc.buf = buf; -+ ioc.len = (uint)sizeof(buf); -+ ioc.set = FALSE; -+ -+ strncpy(buf, "toe_ol", sizeof(buf) - 1); -+ buf[sizeof(buf) - 1] = '\0'; -+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { -+ /* Check for older dongle image that doesn't support toe_ol */ -+ if (ret == -EIO) { -+ DHD_ERROR(("%s: toe not supported by device\n", -+ dhd_ifname(&dhd->pub, ifidx))); -+ return -EOPNOTSUPP; -+ } -+ -+ DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); -+ return ret; -+ } -+ -+ memcpy(toe_ol, buf, sizeof(uint32)); -+ return 0; -+} -+ -+/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ -+static int -+dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) -+{ -+ wl_ioctl_t ioc; -+ char buf[32]; -+ int toe, ret; -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ -+ ioc.cmd = WLC_SET_VAR; -+ ioc.buf = buf; -+ ioc.len = (uint)sizeof(buf); -+ ioc.set = TRUE; -+ -+ /* Set toe_ol as requested */ -+ -+ strncpy(buf, "toe_ol", sizeof(buf) - 1); -+ buf[sizeof(buf) - 1] = '\0'; -+ memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); -+ -+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { -+ DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", -+ dhd_ifname(&dhd->pub, ifidx), ret)); -+ return ret; -+ } -+ -+ /* Enable toe globally only if any components are enabled. */ -+ -+ toe = (toe_ol != 0); -+ -+ strcpy(buf, "toe"); -+ memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); -+ -+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { -+ DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); -+ return ret; -+ } -+ -+ return 0; -+} -+#endif /* TOE */ -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -+static void -+dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -+ -+ snprintf(info->driver, sizeof(info->driver), "wl"); -+ snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); -+} -+ -+struct ethtool_ops dhd_ethtool_ops = { -+ .get_drvinfo = dhd_ethtool_get_drvinfo -+}; -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ -+ -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) -+static int -+dhd_ethtool(dhd_info_t *dhd, void *uaddr) -+{ -+ struct ethtool_drvinfo info; -+ char drvname[sizeof(info.driver)]; -+ uint32 cmd; -+#ifdef TOE -+ struct ethtool_value edata; -+ uint32 toe_cmpnt, csum_dir; -+ int ret; -+#endif -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ /* all ethtool calls start with a cmd word */ -+ if (copy_from_user(&cmd, uaddr, sizeof (uint32))) -+ return -EFAULT; -+ -+ switch (cmd) { -+ case ETHTOOL_GDRVINFO: -+ /* Copy out any request driver name */ -+ if (copy_from_user(&info, uaddr, sizeof(info))) -+ return -EFAULT; -+ strncpy(drvname, info.driver, sizeof(info.driver)); -+ drvname[sizeof(info.driver)-1] = '\0'; -+ -+ /* clear struct for return */ -+ memset(&info, 0, sizeof(info)); -+ info.cmd = cmd; -+ -+ /* if dhd requested, identify ourselves */ -+ if (strcmp(drvname, "?dhd") == 0) { -+ snprintf(info.driver, sizeof(info.driver), "dhd"); -+ strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); -+ info.version[sizeof(info.version) - 1] = '\0'; -+ } -+ -+ /* otherwise, require dongle to be up */ -+ else if (!dhd->pub.up) { -+ DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); -+ return -ENODEV; -+ } -+ -+ /* finally, report dongle driver type */ -+ else if (dhd->pub.iswl) -+ snprintf(info.driver, sizeof(info.driver), "wl"); -+ else -+ snprintf(info.driver, sizeof(info.driver), "xx"); -+ -+ snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); -+ if (copy_to_user(uaddr, &info, sizeof(info))) -+ return -EFAULT; -+ DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, -+ (int)sizeof(drvname), drvname, info.driver)); -+ break; -+ -+#ifdef TOE -+ /* Get toe offload components from dongle */ -+ case ETHTOOL_GRXCSUM: -+ case ETHTOOL_GTXCSUM: -+ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) -+ return ret; -+ -+ csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; -+ -+ edata.cmd = cmd; -+ edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; -+ -+ if (copy_to_user(uaddr, &edata, sizeof(edata))) -+ return -EFAULT; -+ break; -+ -+ /* Set toe offload components in dongle */ -+ case ETHTOOL_SRXCSUM: -+ case ETHTOOL_STXCSUM: -+ if (copy_from_user(&edata, uaddr, sizeof(edata))) -+ return -EFAULT; -+ -+ /* Read the current settings, update and write back */ -+ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) -+ return ret; -+ -+ csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; -+ -+ if (edata.data != 0) -+ toe_cmpnt |= csum_dir; -+ else -+ toe_cmpnt &= ~csum_dir; -+ -+ if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) -+ return ret; -+ -+ /* If setting TX checksum mode, tell Linux the new mode */ -+ if (cmd == ETHTOOL_STXCSUM) { -+ if (edata.data) -+ dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; -+ else -+ dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; -+ } -+ -+ break; -+#endif /* TOE */ -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ -+ -+static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) -+{ -+ dhd_info_t * dhd; -+ -+ if (!dhdp) -+ return FALSE; -+ -+ dhd = (dhd_info_t *)dhdp->info; -+ if (dhd->thr_sysioc_ctl.thr_pid < 0) { -+ DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); -+ return FALSE; -+ } -+ -+ if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || -+ ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { -+ DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, -+ dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); -+ net_os_send_hang_message(net); -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+static int -+dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -+ dhd_ioctl_t ioc; -+ int bcmerror = 0; -+ int buflen = 0; -+ void *buf = NULL; -+ uint driver = 0; -+ int ifidx; -+ int ret; -+ -+ DHD_OS_WAKE_LOCK(&dhd->pub); -+ -+ /* send to dongle only if we are not waiting for reload already */ -+ if (dhd->pub.hang_was_sent) { -+ DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); -+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return OSL_ERROR(BCME_DONGLE_DOWN); -+ } -+ -+ ifidx = dhd_net2idx(dhd, net); -+ DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); -+ -+ if (ifidx == DHD_BAD_IF) { -+ DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return -1; -+ } -+ -+#if defined(CONFIG_WIRELESS_EXT) -+ /* linux wireless extensions */ -+ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { -+ /* may recurse, do NOT lock */ -+ ret = wl_iw_ioctl(net, ifr, cmd); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return ret; -+ } -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) -+ if (cmd == SIOCETHTOOL) { -+ ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return ret; -+ } -+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ -+ -+ if (cmd == SIOCDEVPRIVATE+1) { -+ ret = wl_android_priv_cmd(net, ifr, cmd); -+ dhd_check_hang(net, &dhd->pub, ret); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return ret; -+ } -+ -+ if (cmd != SIOCDEVPRIVATE) { -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return -EOPNOTSUPP; -+ } -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ -+ /* Copy the ioc control structure part of ioctl request */ -+ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { -+ bcmerror = BCME_BADADDR; -+ goto done; -+ } -+ -+ /* Copy out any buffer passed */ -+ if (ioc.buf) { -+ if (ioc.len == 0) { -+ DHD_TRACE(("%s: ioc.len=0, returns BCME_BADARG \n", __FUNCTION__)); -+ bcmerror = BCME_BADARG; -+ goto done; -+ } -+ buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); -+ /* optimization for direct ioctl calls from kernel */ -+ /* -+ if (segment_eq(get_fs(), KERNEL_DS)) { -+ buf = ioc.buf; -+ } else { -+ */ -+ { -+ if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { -+ bcmerror = BCME_NOMEM; -+ goto done; -+ } -+ if (copy_from_user(buf, ioc.buf, buflen)) { -+ bcmerror = BCME_BADADDR; -+ goto done; -+ } -+ } -+ } -+ -+ /* To differentiate between wl and dhd read 4 more byes */ -+ if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), -+ sizeof(uint)) != 0)) { -+ bcmerror = BCME_BADADDR; -+ goto done; -+ } -+ -+ if (!capable(CAP_NET_ADMIN)) { -+ bcmerror = BCME_EPERM; -+ goto done; -+ } -+ -+ /* check for local dhd ioctl and handle it */ -+ if (driver == DHD_IOCTL_MAGIC) { -+ bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen); -+ if (bcmerror) -+ dhd->pub.bcmerror = bcmerror; -+ goto done; -+ } -+ -+ /* send to dongle (must be up, and wl). */ -+ if (dhd->pub.busstate != DHD_BUS_DATA) { -+ bcmerror = BCME_DONGLE_DOWN; -+ goto done; -+ } -+ -+ if (!dhd->pub.iswl) { -+ bcmerror = BCME_DONGLE_DOWN; -+ goto done; -+ } -+ -+ /* -+ * Flush the TX queue if required for proper message serialization: -+ * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to -+ * prevent M4 encryption and -+ * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to -+ * prevent disassoc frame being sent before WPS-DONE frame. -+ */ -+ if (ioc.cmd == WLC_SET_KEY || -+ (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && -+ strncmp("wsec_key", ioc.buf, 9) == 0) || -+ (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && -+ strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) || -+ ioc.cmd == WLC_DISASSOC) -+ dhd_wait_pend8021x(net); -+ -+#ifdef WLMEDIA_HTSF -+ if (ioc.buf) { -+ /* short cut wl ioctl calls here */ -+ if (strcmp("htsf", ioc.buf) == 0) { -+ dhd_ioctl_htsf_get(dhd, 0); -+ return BCME_OK; -+ } -+ -+ if (strcmp("htsflate", ioc.buf) == 0) { -+ if (ioc.set) { -+ memset(ts, 0, sizeof(tstamp_t)*TSMAX); -+ memset(&maxdelayts, 0, sizeof(tstamp_t)); -+ maxdelay = 0; -+ tspktcnt = 0; -+ maxdelaypktno = 0; -+ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); -+ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); -+ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); -+ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); -+ } else { -+ dhd_dump_latency(); -+ } -+ return BCME_OK; -+ } -+ if (strcmp("htsfclear", ioc.buf) == 0) { -+ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); -+ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); -+ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); -+ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); -+ htsf_seqnum = 0; -+ return BCME_OK; -+ } -+ if (strcmp("htsfhis", ioc.buf) == 0) { -+ dhd_dump_htsfhisto(&vi_d1, "H to D"); -+ dhd_dump_htsfhisto(&vi_d2, "D to D"); -+ dhd_dump_htsfhisto(&vi_d3, "D to H"); -+ dhd_dump_htsfhisto(&vi_d4, "H to H"); -+ return BCME_OK; -+ } -+ if (strcmp("tsport", ioc.buf) == 0) { -+ if (ioc.set) { -+ memcpy(&tsport, ioc.buf + 7, 4); -+ } else { -+ DHD_ERROR(("current timestamp port: %d \n", tsport)); -+ } -+ return BCME_OK; -+ } -+ } -+#endif /* WLMEDIA_HTSF */ -+ -+ if ((ioc.cmd == WLC_SET_VAR || ioc.cmd == WLC_GET_VAR) && -+ ioc.buf != NULL && strncmp("rpc_", ioc.buf, 4) == 0) { -+#ifdef BCM_FD_AGGR -+ bcmerror = dhd_fdaggr_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); -+#else -+ bcmerror = BCME_UNSUPPORTED; -+#endif -+ goto done; -+ } -+ bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); -+ -+done: -+ dhd_check_hang(net, &dhd->pub, bcmerror); -+ -+ if (!bcmerror && buf && ioc.buf) { -+ if (copy_to_user(ioc.buf, buf, buflen)) -+ bcmerror = -EFAULT; -+ } -+ -+ if (buf) -+ MFREE(dhd->pub.osh, buf, buflen); -+ -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ -+ return OSL_ERROR(bcmerror); -+} -+ -+#ifdef WL_CFG80211 -+static int -+dhd_cleanup_virt_ifaces(dhd_info_t *dhd) -+{ -+ int i = 1; /* Leave ifidx 0 [Primary Interface] */ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ int rollback_lock = FALSE; -+#endif -+ -+ DHD_TRACE(("%s: Enter \n", __func__)); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ /* release lock for unregister_netdev */ -+ if (rtnl_is_locked()) { -+ rtnl_unlock(); -+ rollback_lock = TRUE; -+ } -+#endif -+ -+ for (i = 1; i < DHD_MAX_IFS; i++) { -+ dhd_net_if_lock_local(dhd); -+ if (dhd->iflist[i]) { -+ DHD_TRACE(("Deleting IF: %d \n", i)); -+ if ((dhd->iflist[i]->state != DHD_IF_DEL) && -+ (dhd->iflist[i]->state != DHD_IF_DELETING)) { -+ dhd->iflist[i]->state = DHD_IF_DEL; -+ dhd->iflist[i]->idx = i; -+ dhd_op_if(dhd->iflist[i]); -+ } -+ } -+ dhd_net_if_unlock_local(dhd); -+ } -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ if (rollback_lock) -+ rtnl_lock(); -+#endif -+ -+ return 0; -+} -+#endif /* WL_CFG80211 */ -+ -+ -+static int -+dhd_stop(struct net_device *net) -+{ -+ int ifidx = 0; -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -+ DHD_OS_WAKE_LOCK(&dhd->pub); -+ DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); -+ if (dhd->pub.up == 0) { -+ goto exit; -+ } -+ ifidx = dhd_net2idx(dhd, net); -+ BCM_REFERENCE(ifidx); -+ -+ /* Set state and stop OS transmissions */ -+ netif_stop_queue(net); -+ dhd->pub.up = 0; -+ -+#ifdef WL_CFG80211 -+ if (ifidx == 0) { -+ wl_cfg80211_down(NULL); -+ -+ /* -+ * For CFG80211: Clean up all the left over virtual interfaces -+ * when the primary Interface is brought down. [ifconfig wlan0 down] -+ */ -+ if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && -+ (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { -+ dhd_cleanup_virt_ifaces(dhd); -+ } -+ } -+#endif -+ -+#ifdef PROP_TXSTATUS -+ dhd_os_wlfc_block(&dhd->pub); -+ dhd_wlfc_cleanup(&dhd->pub); -+ dhd_os_wlfc_unblock(&dhd->pub); -+#endif -+ /* Stop the protocol module */ -+ dhd_prot_stop(&dhd->pub); -+ -+ OLD_MOD_DEC_USE_COUNT; -+exit: -+#if defined(WL_CFG80211) -+ if (ifidx == 0) { -+ if (!dhd_download_fw_on_driverload) -+ wl_android_wifi_off(net); -+ } -+#endif -+ dhd->pub.rxcnt_timeout = 0; -+ dhd->pub.txcnt_timeout = 0; -+ -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return 0; -+} -+ -+static int -+dhd_open(struct net_device *net) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -+#ifdef TOE -+ uint32 toe_ol; -+#endif -+ int ifidx; -+ int32 ret = 0; -+ -+ DHD_OS_WAKE_LOCK(&dhd->pub); -+ /* Update FW path if it was changed */ -+ if (strlen(firmware_path) != 0) { -+ if (firmware_path[strlen(firmware_path)-1] == '\n') -+ firmware_path[strlen(firmware_path)-1] = '\0'; -+ strncpy(fw_path, firmware_path, sizeof(fw_path)-1); -+ fw_path[sizeof(fw_path)-1] = '\0'; -+ firmware_path[0] = '\0'; -+ } -+ -+ -+ dhd->pub.dongle_trap_occured = 0; -+ dhd->pub.hang_was_sent = 0; -+#if !defined(WL_CFG80211) -+ /* -+ * Force start if ifconfig_up gets called before START command -+ * We keep WEXT's wl_control_wl_start to provide backward compatibility -+ * This should be removed in the future -+ */ -+ ret = wl_control_wl_start(net); -+ if (ret != 0) { -+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); -+ ret = -1; -+ goto exit; -+ } -+#endif -+ -+ ifidx = dhd_net2idx(dhd, net); -+ DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); -+ -+ if (ifidx < 0) { -+ DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); -+ ret = -1; -+ goto exit; -+ } -+ -+ if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == DHD_IF_DEL) { -+ DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); -+ ret = -1; -+ goto exit; -+ } -+ -+ if (ifidx == 0) { -+ atomic_set(&dhd->pend_8021x_cnt, 0); -+#if defined(WL_CFG80211) -+ DHD_ERROR(("\n%s\n", dhd_version)); -+ if (!dhd_download_fw_on_driverload) { -+ ret = wl_android_wifi_on(net); -+ if (ret != 0) { -+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); -+ ret = -1; -+ goto exit; -+ } -+ } else { -+ } -+#endif -+ -+ if (dhd->pub.busstate != DHD_BUS_DATA) { -+ -+ /* try to bring up bus */ -+ if ((ret = dhd_bus_start(&dhd->pub)) != 0) { -+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); -+ ret = -1; -+ goto exit; -+ } -+ -+ } -+ -+ /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */ -+ memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); -+ -+#ifdef TOE -+ /* Get current TOE mode from dongle */ -+ if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) -+ dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; -+ else -+ dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; -+#endif /* TOE */ -+ -+#if defined(WL_CFG80211) -+ if (unlikely(wl_cfg80211_up(NULL))) { -+ DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); -+ ret = -1; -+ goto exit; -+ } -+#endif /* WL_CFG80211 */ -+ } -+ -+ /* Allow transmit calls */ -+ netif_start_queue(net); -+ dhd->pub.up = 1; -+ -+#ifdef BCMDBGFS -+ dhd_dbg_init(&dhd->pub); -+#endif -+ -+ OLD_MOD_INC_USE_COUNT; -+exit: -+ if (ret) -+ dhd_stop(net); -+ -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ return ret; -+} -+ -+int dhd_do_driver_init(struct net_device *net) -+{ -+ dhd_info_t *dhd = NULL; -+ -+ if (!net) { -+ DHD_ERROR(("Primary Interface not initialized \n")); -+ return -EINVAL; -+ } -+ -+ dhd = *(dhd_info_t **)netdev_priv(net); -+ -+ /* If driver is already initialized, do nothing -+ */ -+ if (dhd->pub.busstate == DHD_BUS_DATA) { -+ DHD_TRACE(("Driver already Inititalized. Nothing to do")); -+ return 0; -+ } -+ -+ if (dhd_open(net) < 0) { -+ DHD_ERROR(("Driver Init Failed \n")); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+osl_t * -+dhd_osl_attach(void *pdev, uint bustype) -+{ -+ return osl_attach(pdev, bustype, TRUE); -+} -+ -+void -+dhd_osl_detach(osl_t *osh) -+{ -+ if (MALLOCED(osh)) { -+ DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); -+ } -+ osl_detach(osh); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ dhd_registration_check = FALSE; -+ up(&dhd_registration_sem); -+#if defined(BCMLXSDMMC) -+ up(&dhd_chipup_sem); -+#endif -+#endif -+} -+ -+int -+dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, -+ uint8 *mac_addr, uint32 flags, uint8 bssidx) -+{ -+ dhd_if_t *ifp; -+ -+ DHD_TRACE(("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle)); -+ -+ ASSERT(dhd && (ifidx < DHD_MAX_IFS)); -+ -+ ifp = dhd->iflist[ifidx]; -+ if (ifp != NULL) { -+ if (ifp->net != NULL) { -+ netif_stop_queue(ifp->net); -+ unregister_netdev(ifp->net); -+ free_netdev(ifp->net); -+ } -+ } else -+ if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) { -+ DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__)); -+ return -ENOMEM; -+ } -+ -+ memset(ifp, 0, sizeof(dhd_if_t)); -+ ifp->event2cfg80211 = FALSE; -+ ifp->info = dhd; -+ dhd->iflist[ifidx] = ifp; -+ strncpy(ifp->name, name, IFNAMSIZ); -+ ifp->name[IFNAMSIZ] = '\0'; -+ if (mac_addr != NULL) -+ memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN); -+ -+ if (handle == NULL) { -+ ifp->state = DHD_IF_ADD; -+ ifp->idx = ifidx; -+ ifp->bssidx = bssidx; -+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); -+ up(&dhd->thr_sysioc_ctl.sema); -+ } else -+ ifp->net = (struct net_device *)handle; -+ -+ if (ifidx == 0) { -+ ifp->event2cfg80211 = TRUE; -+ } -+ -+ return 0; -+} -+ -+void -+dhd_del_if(dhd_info_t *dhd, int ifidx) -+{ -+ dhd_if_t *ifp; -+ -+ DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx)); -+ -+ ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS)); -+ ifp = dhd->iflist[ifidx]; -+ if (!ifp) { -+ DHD_ERROR(("%s: Null interface\n", __FUNCTION__)); -+ return; -+ } -+ -+ ifp->state = DHD_IF_DEL; -+ ifp->idx = ifidx; -+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); -+ up(&dhd->thr_sysioc_ctl.sema); -+} -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -+static struct net_device_ops dhd_ops_pri = { -+ .ndo_open = dhd_open, -+ .ndo_stop = dhd_stop, -+ .ndo_get_stats = dhd_get_stats, -+ .ndo_do_ioctl = dhd_ioctl_entry, -+ .ndo_start_xmit = dhd_start_xmit, -+ .ndo_set_mac_address = dhd_set_mac_address, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) -+ .ndo_set_rx_mode = dhd_set_multicast_list, -+#else -+ .ndo_set_multicast_list = dhd_set_multicast_list, -+#endif -+}; -+ -+static struct net_device_ops dhd_ops_virt = { -+ .ndo_get_stats = dhd_get_stats, -+ .ndo_do_ioctl = dhd_ioctl_entry, -+ .ndo_start_xmit = dhd_start_xmit, -+ .ndo_set_mac_address = dhd_set_mac_address, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) -+ .ndo_set_rx_mode = dhd_set_multicast_list, -+#else -+ .ndo_set_multicast_list = dhd_set_multicast_list, -+#endif -+}; -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ -+ -+dhd_pub_t * -+dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) -+{ -+ dhd_info_t *dhd = NULL; -+ struct net_device *net = NULL; -+ -+ dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ /* updates firmware nvram path if it was provided as module parameters */ -+ if (strlen(firmware_path) != 0) { -+ strncpy(fw_path, firmware_path, sizeof(fw_path) - 1); -+ fw_path[sizeof(fw_path) - 1] = '\0'; -+ } -+ if (strlen(nvram_path) != 0) { -+ strncpy(nv_path, nvram_path, sizeof(nv_path) -1); -+ nv_path[sizeof(nv_path) -1] = '\0'; -+ } -+ -+ /* Allocate etherdev, including space for private structure */ -+ if (!(net = alloc_etherdev(sizeof(dhd)))) { -+ DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); -+ goto fail; -+ } -+ dhd_state |= DHD_ATTACH_STATE_NET_ALLOC; -+ -+ /* Allocate primary dhd_info */ -+ if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { -+ DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); -+ goto fail; -+ } -+ memset(dhd, 0, sizeof(dhd_info_t)); -+ -+#ifdef DHDTHREAD -+ dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; -+ dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; -+#endif /* DHDTHREAD */ -+ dhd->dhd_tasklet_create = FALSE; -+ dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID; -+ dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; -+ -+ /* -+ * Save the dhd_info into the priv -+ */ -+ memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd)); -+ dhd->pub.osh = osh; -+ -+ /* Link to info module */ -+ dhd->pub.info = dhd; -+ /* Link to bus module */ -+ dhd->pub.bus = bus; -+ dhd->pub.hdrlen = bus_hdrlen; -+ -+ /* Set network interface name if it was provided as module parameter */ -+ if (iface_name[0]) { -+ int len; -+ char ch; -+ strncpy(net->name, iface_name, IFNAMSIZ); -+ net->name[IFNAMSIZ - 1] = 0; -+ len = strlen(net->name); -+ ch = net->name[len - 1]; -+ if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) -+ strcat(net->name, "%d"); -+ } -+ -+ if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) -+ goto fail; -+ dhd_state |= DHD_ATTACH_STATE_ADD_IF; -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) -+ net->open = NULL; -+#else -+ net->netdev_ops = NULL; -+#endif -+ -+ sema_init(&dhd->proto_sem, 1); -+ -+#ifdef PROP_TXSTATUS -+ spin_lock_init(&dhd->wlfc_spinlock); -+#ifdef PROP_TXSTATUS_VSDB -+ dhd->pub.wlfc_enabled = FALSE; -+#else -+ dhd->pub.wlfc_enabled = TRUE; -+#endif /* PROP_TXSTATUS_VSDB */ -+#endif /* PROP_TXSTATUS */ -+ -+ /* Initialize other structure content */ -+ init_waitqueue_head(&dhd->ioctl_resp_wait); -+ init_waitqueue_head(&dhd->ctrl_wait); -+ -+ /* Initialize the spinlocks */ -+ spin_lock_init(&dhd->sdlock); -+ spin_lock_init(&dhd->txqlock); -+ spin_lock_init(&dhd->dhd_lock); -+ -+ /* Initialize Wakelock stuff */ -+ spin_lock_init(&dhd->wakelock_spinlock); -+ dhd->wakelock_counter = 0; -+ dhd->wakelock_wd_counter = 0; -+ dhd->wakelock_rx_timeout_enable = 0; -+ dhd->wakelock_ctrl_timeout_enable = 0; -+#ifdef CONFIG_HAS_WAKELOCK -+ wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); -+ wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); -+ wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); -+ wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); -+#endif -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ mutex_init(&dhd->dhd_net_if_mutex); -+ mutex_init(&dhd->dhd_suspend_mutex); -+#endif -+ dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; -+ -+ /* Attach and link in the protocol */ -+ if (dhd_prot_attach(&dhd->pub) != 0) { -+ DHD_ERROR(("dhd_prot_attach failed\n")); -+ goto fail; -+ } -+ dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; -+ -+#ifdef WL_CFG80211 -+ /* Attach and link in the cfg80211 */ -+ if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { -+ DHD_ERROR(("wl_cfg80211_attach failed\n")); -+ goto fail; -+ } -+ -+ dhd_monitor_init(&dhd->pub); -+ dhd_state |= DHD_ATTACH_STATE_CFG80211; -+#endif -+#if defined(CONFIG_WIRELESS_EXT) -+ /* Attach and link in the iw */ -+ if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { -+ if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { -+ DHD_ERROR(("wl_iw_attach failed\n")); -+ goto fail; -+ } -+ dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; -+ } -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+ -+ /* Set up the watchdog timer */ -+ init_timer(&dhd->timer); -+ dhd->timer.data = (ulong)dhd; -+ dhd->timer.function = dhd_watchdog; -+ -+#ifdef DHDTHREAD -+ /* Initialize thread based operation and lock */ -+ sema_init(&dhd->sdsem, 1); -+ if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) { -+ dhd->threads_only = TRUE; -+ } -+ else { -+ dhd->threads_only = FALSE; -+ } -+ -+ if (dhd_watchdog_prio >= 0) { -+ /* Initialize watchdog thread */ -+ PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); -+ } else { -+ dhd->thr_wdt_ctl.thr_pid = -1; -+ } -+ -+ /* Set up the bottom half handler */ -+ if (dhd_dpc_prio >= 0) { -+ /* Initialize DPC thread */ -+ PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); -+ } else { -+ /* use tasklet for dpc */ -+ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); -+ dhd->thr_dpc_ctl.thr_pid = -1; -+ } -+#else -+ /* Set up the bottom half handler */ -+ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); -+ dhd->dhd_tasklet_create = TRUE; -+#endif /* DHDTHREAD */ -+ -+ if (dhd_sysioc) { -+ PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); -+ } else { -+ dhd->thr_sysioc_ctl.thr_pid = -1; -+ } -+ dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ INIT_WORK(&dhd->work_hang, dhd_hang_process); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+ /* -+ * Save the dhd_info into the priv -+ */ -+ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -+ register_pm_notifier(&dhd_sleep_pm_notifier); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -+ -+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -+ dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; -+ dhd->early_suspend.suspend = dhd_early_suspend; -+ dhd->early_suspend.resume = dhd_late_resume; -+ register_early_suspend(&dhd->early_suspend); -+ dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; -+#endif -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+ dhd->pend_ipaddr = 0; -+ register_inetaddr_notifier(&dhd_notifier); -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+ dhd_state |= DHD_ATTACH_STATE_DONE; -+ dhd->dhd_state = dhd_state; -+ return &dhd->pub; -+ -+fail: -+ if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) { -+ if (net) free_netdev(net); -+ } else { -+ DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", -+ __FUNCTION__, dhd_state, &dhd->pub)); -+ dhd->dhd_state = dhd_state; -+ dhd_detach(&dhd->pub); -+ dhd_free(&dhd->pub); -+ } -+ -+ return NULL; -+} -+ -+int -+dhd_bus_start(dhd_pub_t *dhdp) -+{ -+ int ret = -1; -+ dhd_info_t *dhd = (dhd_info_t*)dhdp->info; -+ unsigned long flags; -+ -+ ASSERT(dhd); -+ -+ DHD_TRACE(("Enter %s:\n", __FUNCTION__)); -+ -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ dhd_os_sdlock(dhdp); -+#endif /* DHDTHREAD */ -+ -+ -+ /* try to download image and nvram to the dongle */ -+ if ((dhd->pub.busstate == DHD_BUS_DOWN) && -+ (fw_path != NULL) && (fw_path[0] != '\0') && -+ (nv_path != NULL) && (nv_path[0] != '\0')) { -+ /* wake lock moved to dhdsdio_download_firmware */ -+ if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, -+ fw_path, nv_path))) { -+ DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", -+ __FUNCTION__, fw_path, nv_path)); -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ dhd_os_sdunlock(dhdp); -+#endif /* DHDTHREAD */ -+ return -1; -+ } -+ } -+ if (dhd->pub.busstate != DHD_BUS_LOAD) { -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ dhd_os_sdunlock(dhdp); -+#endif /* DHDTHREAD */ -+ return -ENETDOWN; -+ } -+ -+ /* Start the watchdog timer */ -+ dhd->pub.tickcnt = 0; -+ dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); -+ -+ /* Bring up the bus */ -+ if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { -+ -+ DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ dhd_os_sdunlock(dhdp); -+#endif /* DHDTHREAD */ -+ return ret; -+ } -+#if defined(OOB_INTR_ONLY) -+ /* Host registration for OOB interrupt */ -+ if (bcmsdh_register_oob_intr(dhdp)) { -+ /* deactivate timer and wait for the handler to finish */ -+ -+ flags = dhd_os_spin_lock(&dhd->pub); -+ dhd->wd_timer_valid = FALSE; -+ dhd_os_spin_unlock(&dhd->pub, flags); -+ del_timer_sync(&dhd->timer); -+ DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ dhd_os_sdunlock(dhdp); -+#endif /* DHDTHREAD */ -+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); -+ return -ENODEV; -+ } -+ -+ /* Enable oob at firmware */ -+ dhd_enable_oob_intr(dhd->pub.bus, TRUE); -+#endif /* defined(OOB_INTR_ONLY) */ -+ -+ /* If bus is not ready, can't come up */ -+ if (dhd->pub.busstate != DHD_BUS_DATA) { -+ flags = dhd_os_spin_lock(&dhd->pub); -+ dhd->wd_timer_valid = FALSE; -+ dhd_os_spin_unlock(&dhd->pub, flags); -+ del_timer_sync(&dhd->timer); -+ DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ dhd_os_sdunlock(dhdp); -+#endif /* DHDTHREAD */ -+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); -+ return -ENODEV; -+ } -+ -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ dhd_os_sdunlock(dhdp); -+#endif /* DHDTHREAD */ -+ -+#ifdef BCMSDIOH_TXGLOM -+ if ((dhd->pub.busstate == DHD_BUS_DATA) && bcmsdh_glom_enabled()) { -+ dhd_txglom_enable(dhdp, TRUE); -+ } -+#endif -+ -+#ifdef READ_MACADDR -+ dhd_read_macaddr(dhd); -+#endif -+ -+ /* Bus is ready, do any protocol initialization */ -+ if ((ret = dhd_prot_init(&dhd->pub)) < 0) -+ return ret; -+ -+#ifdef WRITE_MACADDR -+ dhd_write_macaddr(dhd->pub.mac.octet); -+#endif -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+ if (dhd->pend_ipaddr) { -+#ifdef AOE_IP_ALIAS_SUPPORT -+ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); -+#endif /* AOE_IP_ALIAS_SUPPORT */ -+ dhd->pend_ipaddr = 0; -+ } -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+ return 0; -+} -+ -+bool dhd_is_concurrent_mode(dhd_pub_t *dhd) -+{ -+ if (!dhd) -+ return FALSE; -+ -+ if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) -+ return TRUE; -+ else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == -+ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) -+ return TRUE; -+ else -+ return FALSE; -+} -+ -+#if !defined(AP) && defined(WLP2P) -+/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware -+ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA -+ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware -+ * would still be named as fw_bcmdhd_apsta. -+ */ -+uint32 -+dhd_get_concurrent_capabilites(dhd_pub_t *dhd) -+{ -+ int32 ret = 0; -+ char buf[WLC_IOCTL_SMLEN]; -+ bool mchan_supported = FALSE; -+ /* if dhd->op_mode is already set for HOSTAP, -+ * that means we only will use the mode as it is -+ */ -+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) -+ return 0; -+ memset(buf, 0, sizeof(buf)); -+ bcm_mkiovar("cap", 0, 0, buf, sizeof(buf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), -+ FALSE, 0)) < 0) { -+ DHD_ERROR(("%s: Get Capability failed (error=%d)\n", -+ __FUNCTION__, ret)); -+ return 0; -+ } -+ if (strstr(buf, "vsdb")) { -+ mchan_supported = TRUE; -+ } -+ if (strstr(buf, "p2p") == NULL) { -+ DHD_TRACE(("Chip does not support p2p\n")); -+ return 0; -+ } -+ else { -+ /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ -+ memset(buf, 0, sizeof(buf)); -+ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), -+ FALSE, 0)) < 0) { -+ DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); -+ return 0; -+ } -+ else { -+ if (buf[0] == 1) { -+ /* By default, chip supports single chan concurrency, -+ * now lets check for mchan -+ */ -+ ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; -+ if (mchan_supported) -+ ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; -+#if defined(WL_ENABLE_P2P_IF) -+ /* For customer_hw4, although ICS, -+ * we still support concurrent mode -+ */ -+ return ret; -+#else -+ return 0; -+#endif -+ } -+ } -+ } -+ return 0; -+} -+#endif -+int -+dhd_preinit_ioctls(dhd_pub_t *dhd) -+{ -+ int ret = 0; -+ char eventmask[WL_EVENTING_MASK_LEN]; -+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ -+ -+#if !defined(WL_CFG80211) -+ uint up = 0; -+#endif /* !defined(WL_CFG80211) */ -+ uint power_mode = PM_FAST; -+ uint32 dongle_align = DHD_SDALIGN; -+ uint32 glom = CUSTOM_GLOM_SETTING; -+#if defined(VSDB) || defined(ROAM_ENABLE) -+ uint bcn_timeout = 8; -+#else -+ uint bcn_timeout = 4; -+#endif -+#ifdef ENABLE_BCN_LI_BCN_WAKEUP -+ uint32 bcn_li_bcn = 1; -+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -+ uint retry_max = 3; -+#if defined(ARP_OFFLOAD_SUPPORT) -+ int arpoe = 1; -+#endif -+ int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; -+ int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; -+ int scan_passive_time = DHD_SCAN_PASSIVE_TIME; -+ char buf[WLC_IOCTL_SMLEN]; -+ char *ptr; -+ uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ -+#ifdef ROAM_ENABLE -+ uint roamvar = 0; -+ int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; -+ int roam_scan_period[2] = {10, WLC_BAND_ALL}; -+ int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; -+#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC -+ int roam_fullscan_period = 60; -+#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ -+ int roam_fullscan_period = 120; -+#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ -+#else -+#ifdef DISABLE_BUILTIN_ROAM -+ uint roamvar = 1; -+#endif /* DISABLE_BUILTIN_ROAM */ -+#endif /* ROAM_ENABLE */ -+ -+#if defined(SOFTAP) -+ uint dtim = 1; -+#endif -+#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) -+ uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ -+ struct ether_addr p2p_ea; -+#endif -+ -+#if defined(AP) || defined(WLP2P) -+ uint32 apsta = 1; /* Enable APSTA mode */ -+#endif /* defined(AP) || defined(WLP2P) */ -+#ifdef GET_CUSTOM_MAC_ENABLE -+ struct ether_addr ea_addr; -+#endif /* GET_CUSTOM_MAC_ENABLE */ -+#ifdef DISABLE_11N -+ uint32 nmode = 0; -+#else -+#ifdef AMPDU_HOSTREORDER -+ uint32 hostreorder = 1; -+#endif -+#endif /* DISABLE_11N */ -+ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; -+#ifdef PROP_TXSTATUS -+#ifdef PROP_TXSTATUS_VSDB -+ dhd->wlfc_enabled = FALSE; -+ /* enable WLFC only if the firmware is VSDB */ -+#else -+ dhd->wlfc_enabled = TRUE; -+#endif /* PROP_TXSTATUS_VSDB */ -+#endif /* PROP_TXSTATUS */ -+ DHD_TRACE(("Enter %s\n", __FUNCTION__)); -+ dhd->op_mode = 0; -+#ifdef GET_CUSTOM_MAC_ENABLE -+ ret = dhd_custom_get_mac_address(ea_addr.octet); -+ if (!ret) { -+ memset(buf, 0, sizeof(buf)); -+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); -+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); -+ if (ret < 0) { -+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); -+ return BCME_NOTUP; -+ } -+ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); -+ } else { -+#endif /* GET_CUSTOM_MAC_ENABLE */ -+ /* Get the default device MAC address directly from firmware */ -+ memset(buf, 0, sizeof(buf)); -+ bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), -+ FALSE, 0)) < 0) { -+ DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); -+ return BCME_NOTUP; -+ } -+ /* Update public MAC address after reading from Firmware */ -+ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); -+ -+#ifdef GET_CUSTOM_MAC_ENABLE -+ } -+#endif /* GET_CUSTOM_MAC_ENABLE */ -+ -+ DHD_TRACE(("Firmware = %s\n", fw_path)); -+ -+ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || -+ (op_mode == DHD_FLAG_HOSTAP_MODE)) { -+#ifdef SET_RANDOM_MAC_SOFTAP -+ uint rand_mac; -+#endif -+ dhd->op_mode = DHD_FLAG_HOSTAP_MODE; -+#if defined(ARP_OFFLOAD_SUPPORT) -+ arpoe = 0; -+#endif -+#ifdef PKT_FILTER_SUPPORT -+ dhd_pkt_filter_enable = FALSE; -+#endif -+#ifdef SET_RANDOM_MAC_SOFTAP -+ srandom32((uint)jiffies); -+ rand_mac = random32(); -+ iovbuf[0] = 0x02; /* locally administered bit */ -+ iovbuf[1] = 0x1A; -+ iovbuf[2] = 0x11; -+ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; -+ iovbuf[4] = (unsigned char)(rand_mac >> 8); -+ iovbuf[5] = (unsigned char)(rand_mac >> 16); -+ -+ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); -+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); -+ if (ret < 0) { -+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); -+ } else -+ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); -+#endif /* SET_RANDOM_MAC_SOFTAP */ -+#if !defined(AP) && defined(WL_CFG80211) -+ /* Turn off MPC in AP mode */ -+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, -+ sizeof(iovbuf), TRUE, 0)) < 0) { -+ DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); -+ } -+#endif -+ -+ } -+ else { -+ uint32 concurrent_mode = 0; -+ if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || -+ (op_mode == DHD_FLAG_P2P_MODE)) { -+#if defined(ARP_OFFLOAD_SUPPORT) -+ arpoe = 0; -+#endif -+#ifdef PKT_FILTER_SUPPORT -+ dhd_pkt_filter_enable = FALSE; -+#endif -+ dhd->op_mode = DHD_FLAG_P2P_MODE; -+ } -+ else -+ dhd->op_mode = DHD_FLAG_STA_MODE; -+#if !defined(AP) && defined(WLP2P) -+ if ((concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { -+#if defined(ARP_OFFLOAD_SUPPORT) -+ arpoe = 1; -+#endif -+ dhd->op_mode |= concurrent_mode; -+ } -+ -+ /* Check if we are enabling p2p */ -+ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { -+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, -+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { -+ DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); -+ } -+ -+ memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); -+ ETHER_SET_LOCALADDR(&p2p_ea); -+ bcm_mkiovar("p2p_da_override", (char *)&p2p_ea, -+ ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, -+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { -+ DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); -+ } else { -+ DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); -+ } -+ } -+#else -+ (void)concurrent_mode; -+#endif -+ } -+ -+ DHD_ERROR(("Firmware up: op_mode=0x%04x, " -+ "Broadcom Dongle Host Driver mac="MACDBG"\n", -+ dhd->op_mode, -+ MAC2STRDBG(dhd->mac.octet))); -+ /* Set Country code */ -+ if (dhd->dhd_cspec.ccode[0] != 0) { -+ bcm_mkiovar("country", (char *)&dhd->dhd_cspec, -+ sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) -+ DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); -+ } -+ -+ /* Set Listen Interval */ -+ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) -+ DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); -+ -+#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) -+ /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ -+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -+#ifdef ROAM_ENABLE -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, -+ sizeof(roam_trigger), TRUE, 0)) < 0) -+ DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, -+ sizeof(roam_scan_period), TRUE, 0)) < 0) -+ DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); -+ if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, -+ sizeof(roam_delta), TRUE, 0)) < 0) -+ DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); -+ bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) -+ DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); -+#endif /* ROAM_ENABLE */ -+ -+ /* Set PowerSave mode */ -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); -+ -+ /* Match Host and Dongle rx alignment */ -+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+ -+ if (glom != DEFAULT_GLOM_VALUE) { -+ DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); -+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+ } -+ -+ /* Setup timeout if Beacons are lost and roam is off to report link down */ -+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+ /* Setup assoc_retry_max count to reconnect target AP in dongle */ -+ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#if defined(AP) && !defined(WLP2P) -+ /* Turn off MPC in AP mode */ -+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#endif /* defined(AP) && !defined(WLP2P) */ -+ -+#if defined(SOFTAP) -+ if (ap_fw_loaded == TRUE) { -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); -+ } -+#endif -+ -+#if defined(KEEP_ALIVE) -+ { -+ /* Set Keep Alive : be sure to use FW with -keepalive */ -+ int res; -+ -+#if defined(SOFTAP) -+ if (ap_fw_loaded == FALSE) -+#endif -+ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { -+ if ((res = dhd_keep_alive_onoff(dhd)) < 0) -+ DHD_ERROR(("%s set keeplive failed %d\n", -+ __FUNCTION__, res)); -+ } -+ } -+#endif /* defined(KEEP_ALIVE) */ -+ -+ /* Read event_msgs mask */ -+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { -+ DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); -+ goto done; -+ } -+ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); -+ -+ /* Setup event_msgs */ -+ setbit(eventmask, WLC_E_SET_SSID); -+ setbit(eventmask, WLC_E_PRUNE); -+ setbit(eventmask, WLC_E_AUTH); -+ setbit(eventmask, WLC_E_ASSOC); -+ setbit(eventmask, WLC_E_REASSOC); -+ setbit(eventmask, WLC_E_REASSOC_IND); -+ setbit(eventmask, WLC_E_DEAUTH); -+ setbit(eventmask, WLC_E_DEAUTH_IND); -+ setbit(eventmask, WLC_E_DISASSOC_IND); -+ setbit(eventmask, WLC_E_DISASSOC); -+ setbit(eventmask, WLC_E_JOIN); -+ setbit(eventmask, WLC_E_ASSOC_IND); -+ setbit(eventmask, WLC_E_PSK_SUP); -+ setbit(eventmask, WLC_E_LINK); -+ setbit(eventmask, WLC_E_NDIS_LINK); -+ setbit(eventmask, WLC_E_MIC_ERROR); -+ setbit(eventmask, WLC_E_ASSOC_REQ_IE); -+ setbit(eventmask, WLC_E_ASSOC_RESP_IE); -+#ifndef WL_CFG80211 -+ setbit(eventmask, WLC_E_PMKID_CACHE); -+ setbit(eventmask, WLC_E_TXFAIL); -+#endif -+ setbit(eventmask, WLC_E_JOIN_START); -+ setbit(eventmask, WLC_E_SCAN_COMPLETE); -+#ifdef WLMEDIA_HTSF -+ setbit(eventmask, WLC_E_HTSFSYNC); -+#endif /* WLMEDIA_HTSF */ -+#ifdef PNO_SUPPORT -+ setbit(eventmask, WLC_E_PFN_NET_FOUND); -+#endif /* PNO_SUPPORT */ -+ /* enable dongle roaming event */ -+ setbit(eventmask, WLC_E_ROAM); -+#ifdef WL_CFG80211 -+ setbit(eventmask, WLC_E_ESCAN_RESULT); -+ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { -+ setbit(eventmask, WLC_E_ACTION_FRAME_RX); -+ setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); -+ } -+#endif /* WL_CFG80211 */ -+ -+ /* Write updated Event mask */ -+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { -+ DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); -+ goto done; -+ } -+ -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, -+ sizeof(scan_assoc_time), TRUE, 0); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, -+ sizeof(scan_unassoc_time), TRUE, 0); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, -+ sizeof(scan_passive_time), TRUE, 0); -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+ /* Set and enable ARP offload feature for STA only */ -+#if defined(SOFTAP) -+ if (arpoe && !ap_fw_loaded) { -+#else -+ if (arpoe) { -+#endif -+ dhd_arp_offload_enable(dhd, TRUE); -+ dhd_arp_offload_set(dhd, dhd_arp_mode); -+ } else { -+ dhd_arp_offload_enable(dhd, FALSE); -+ dhd_arp_offload_set(dhd, 0); -+ } -+ dhd_arp_enable = arpoe; -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+#ifdef PKT_FILTER_SUPPORT -+ /* Setup default defintions for pktfilter , enable in suspend */ -+ dhd->pktfilter_count = 5; -+ /* Setup filter to allow only unicast */ -+ dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; -+ dhd->pktfilter[1] = NULL; -+ dhd->pktfilter[2] = NULL; -+ dhd->pktfilter[3] = NULL; -+ /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ -+ dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; -+ dhd_set_packet_filter(dhd); -+#if defined(SOFTAP) -+ if (ap_fw_loaded) { -+ dhd_enable_packet_filter(0, dhd); -+ } -+#endif /* defined(SOFTAP) */ -+#endif /* PKT_FILTER_SUPPORT */ -+#ifdef DISABLE_11N -+ bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) -+ DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); -+#else -+#ifdef AMPDU_HOSTREORDER -+ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, buf, sizeof(buf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); -+#endif /* AMPDU_HOSTREORDER */ -+#endif /* DISABLE_11N */ -+ -+#if !defined(WL_CFG80211) -+ /* Force STA UP */ -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { -+ DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret)); -+ goto done; -+ } -+#endif -+ -+#ifdef ENABLE_BCN_LI_BCN_WAKEUP -+ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); -+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -+ -+ /* query for 'ver' to get version info from firmware */ -+ memset(buf, 0, sizeof(buf)); -+ ptr = buf; -+ bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf)); -+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) -+ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); -+ else { -+ bcmstrtok(&ptr, "\n", 0); -+ /* Print fw version info */ -+ DHD_ERROR(("Firmware version = %s\n", buf)); -+ -+ dhd_set_version_info(dhd, buf); -+ -+ DHD_BLOG(buf, strlen(buf) + 1); -+ DHD_BLOG(dhd_version, strlen(dhd_version) + 1); -+ -+ /* Check and adjust IOCTL response timeout for Manufactring firmware */ -+ if (strstr(buf, MANUFACTRING_FW) != NULL) { -+ dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT * 10); -+ DHD_ERROR(("%s : adjust IOCTL response time for Manufactring Firmware\n", -+ __FUNCTION__)); -+ } -+ } -+ -+done: -+ return ret; -+} -+ -+ -+int -+dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set) -+{ -+ char buf[strlen(name) + 1 + cmd_len]; -+ int len = sizeof(buf); -+ wl_ioctl_t ioc; -+ int ret; -+ -+ len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ -+ ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; -+ ioc.buf = buf; -+ ioc.len = len; -+ ioc.set = TRUE; -+ -+ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); -+ if (!set && ret >= 0) -+ memcpy(cmd_buf, buf, cmd_len); -+ -+ return ret; -+} -+ -+int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) -+{ -+ struct dhd_info *dhd = dhdp->info; -+ struct net_device *dev = NULL; -+ -+ ASSERT(dhd && dhd->iflist[ifidx]); -+ dev = dhd->iflist[ifidx]->net; -+ ASSERT(dev); -+ -+ if (netif_running(dev)) { -+ DHD_ERROR(("%s: Must be down to change its MTU", dev->name)); -+ return BCME_NOTDOWN; -+ } -+ -+#define DHD_MIN_MTU 1500 -+#define DHD_MAX_MTU 1752 -+ -+ if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { -+ DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); -+ return BCME_BADARG; -+ } -+ -+ dev->mtu = new_mtu; -+ return 0; -+} -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ -+void -+aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) -+{ -+ u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ -+ int i; -+ int ret; -+ -+ bzero(ipv4_buf, sizeof(ipv4_buf)); -+ -+ /* display what we've got */ -+ ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); -+ DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); -+#ifdef AOE_DBG -+ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -+#endif -+ /* now we saved hoste_ip table, clr it in the dongle AOE */ -+ dhd_aoe_hostip_clr(dhd_pub, idx); -+ -+ if (ret) { -+ DHD_ERROR(("%s failed\n", __FUNCTION__)); -+ return; -+ } -+ -+ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { -+ if (add && (ipv4_buf[i] == 0)) { -+ ipv4_buf[i] = ipa; -+ add = FALSE; /* added ipa to local table */ -+ DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", -+ __FUNCTION__, i)); -+ } else if (ipv4_buf[i] == ipa) { -+ ipv4_buf[i] = 0; -+ DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", -+ __FUNCTION__, ipa, i)); -+ } -+ -+ if (ipv4_buf[i] != 0) { -+ /* add back host_ip entries from our local cache */ -+ dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); -+ DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", -+ __FUNCTION__, ipv4_buf[i], i)); -+ } -+ } -+#ifdef AOE_DBG -+ /* see the resulting hostip table */ -+ dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); -+ DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); -+ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -+#endif -+} -+ -+/* -+ * Notification mechanism from kernel to our driver. This function is called by the Linux kernel -+ * whenever there is an event related to an IP address. -+ * ptr : kernel provided pointer to IP address that has changed -+ */ -+static int dhd_device_event(struct notifier_block *this, -+ unsigned long event, -+ void *ptr) -+{ -+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; -+ -+ dhd_info_t *dhd; -+ dhd_pub_t *dhd_pub; -+ int idx; -+ -+ if (!dhd_arp_enable) -+ return NOTIFY_DONE; -+ if (!ifa || !(ifa->ifa_dev->dev)) -+ return NOTIFY_DONE; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -+ /* Filter notifications meant for non Broadcom devices */ -+ if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && -+ (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { -+#ifdef WLP2P -+ if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) -+#endif -+ return NOTIFY_DONE; -+ } -+#endif /* LINUX_VERSION_CODE */ -+ -+ dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); -+ if (!dhd) -+ return NOTIFY_DONE; -+ -+ dhd_pub = &dhd->pub; -+ -+ if (dhd_pub->arp_version == 1) { -+ idx = 0; -+ } -+ else { -+ for (idx = 0; idx < DHD_MAX_IFS; idx++) { -+ if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) -+ break; -+ } -+ if (idx < DHD_MAX_IFS) -+ DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, -+ dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); -+ else { -+ DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label)); -+ idx = 0; -+ } -+ } -+ -+ switch (event) { -+ case NETDEV_UP: -+ DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", -+ __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); -+ -+ if (dhd->pub.busstate != DHD_BUS_DATA) { -+ DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); -+ if (dhd->pend_ipaddr) { -+ DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", -+ __FUNCTION__, dhd->pend_ipaddr)); -+ } -+ dhd->pend_ipaddr = ifa->ifa_address; -+ break; -+ } -+ -+#ifdef AOE_IP_ALIAS_SUPPORT -+ DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", -+ __FUNCTION__)); -+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); -+#endif -+ break; -+ -+ case NETDEV_DOWN: -+ DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", -+ __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); -+ dhd->pend_ipaddr = 0; -+#ifdef AOE_IP_ALIAS_SUPPORT -+ DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n", -+ __FUNCTION__)); -+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); -+#else -+ dhd_aoe_hostip_clr(&dhd->pub, idx); -+ dhd_aoe_arp_clr(&dhd->pub, idx); -+#endif /* AOE_IP_ALIAS_SUPPORT */ -+ break; -+ -+ default: -+ DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", -+ __func__, ifa->ifa_label, event)); -+ break; -+ } -+ return NOTIFY_DONE; -+} -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+int -+dhd_net_attach(dhd_pub_t *dhdp, int ifidx) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -+ struct net_device *net = NULL; -+ int err = 0; -+ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; -+ -+ DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); -+ -+ ASSERT(dhd && dhd->iflist[ifidx]); -+ -+ net = dhd->iflist[ifidx]->net; -+ ASSERT(net); -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) -+ ASSERT(!net->open); -+ net->get_stats = dhd_get_stats; -+ net->do_ioctl = dhd_ioctl_entry; -+ net->hard_start_xmit = dhd_start_xmit; -+ net->set_mac_address = dhd_set_mac_address; -+ net->set_multicast_list = dhd_set_multicast_list; -+ net->open = net->stop = NULL; -+#else -+ ASSERT(!net->netdev_ops); -+ net->netdev_ops = &dhd_ops_virt; -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ -+ -+ /* Ok, link into the network layer... */ -+ if (ifidx == 0) { -+ /* -+ * device functions for the primary interface only -+ */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) -+ net->open = dhd_open; -+ net->stop = dhd_stop; -+#else -+ net->netdev_ops = &dhd_ops_pri; -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ -+ if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) -+ memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); -+ } else { -+ /* -+ * We have to use the primary MAC for virtual interfaces -+ */ -+ memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); -+ /* -+ * Android sets the locally administered bit to indicate that this is a -+ * portable hotspot. This will not work in simultaneous AP/STA mode, -+ * nor with P2P. Need to set the Donlge's MAC address, and then use that. -+ */ -+ if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, -+ ETHER_ADDR_LEN)) { -+ DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", -+ __func__, net->name)); -+ temp_addr[0] |= 0x02; -+ } -+ } -+ -+ net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -+ net->ethtool_ops = &dhd_ethtool_ops; -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ -+ -+#if defined(CONFIG_WIRELESS_EXT) -+#if WIRELESS_EXT < 19 -+ net->get_wireless_stats = dhd_get_wireless_stats; -+#endif /* WIRELESS_EXT < 19 */ -+#if WIRELESS_EXT > 12 -+ net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; -+#endif /* WIRELESS_EXT > 12 */ -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); -+ -+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); -+ -+ if ((err = register_netdev(net)) != 0) { -+ DHD_ERROR(("couldn't register the net device, err %d\n", err)); -+ goto fail; -+ } -+ printf("Broadcom Dongle Host Driver: register interface [%s]" -+ " MAC: "MACDBG"\n", -+ net->name, -+ MAC2STRDBG(net->dev_addr)); -+ -+#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) -+ wl_iw_iscan_set_scan_broadcast_prep(net, 1); -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ if (ifidx == 0) { -+ dhd_registration_check = TRUE; -+ up(&dhd_registration_sem); -+ } -+#endif -+ return 0; -+ -+fail: -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) -+ net->open = NULL; -+#else -+ net->netdev_ops = NULL; -+#endif -+ return err; -+} -+ -+void -+dhd_bus_detach(dhd_pub_t *dhdp) -+{ -+ dhd_info_t *dhd; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (dhdp) { -+ dhd = (dhd_info_t *)dhdp->info; -+ if (dhd) { -+ -+ /* -+ * In case of Android cfg80211 driver, the bus is down in dhd_stop, -+ * calling stop again will cuase SD read/write errors. -+ */ -+ if (dhd->pub.busstate != DHD_BUS_DOWN) { -+ /* Stop the protocol module */ -+ dhd_prot_stop(&dhd->pub); -+ -+ /* Stop the bus module */ -+ dhd_bus_stop(dhd->pub.bus, TRUE); -+ } -+ -+#if defined(OOB_INTR_ONLY) -+ bcmsdh_unregister_oob_intr(); -+#endif /* defined(OOB_INTR_ONLY) */ -+ } -+ } -+} -+ -+ -+void dhd_detach(dhd_pub_t *dhdp) -+{ -+ dhd_info_t *dhd; -+ unsigned long flags; -+ int timer_valid = FALSE; -+ -+ if (!dhdp) -+ return; -+ -+ dhd = (dhd_info_t *)dhdp->info; -+ if (!dhd) -+ return; -+ -+ DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); -+ -+ dhd->pub.up = 0; -+ if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { -+ /* Give sufficient time for threads to start running in case -+ * dhd_attach() has failed -+ */ -+ osl_delay(1000*100); -+ } -+ -+ if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { -+ dhd_bus_detach(dhdp); -+ -+ if (dhdp->prot) -+ dhd_prot_detach(dhdp); -+ } -+ -+#ifdef ARP_OFFLOAD_SUPPORT -+ unregister_inetaddr_notifier(&dhd_notifier); -+#endif /* ARP_OFFLOAD_SUPPORT */ -+ -+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -+ if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { -+ if (dhd->early_suspend.suspend) -+ unregister_early_suspend(&dhd->early_suspend); -+ } -+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ cancel_work_sync(&dhd->work_hang); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+ -+#if defined(CONFIG_WIRELESS_EXT) -+ if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { -+ /* Detatch and unlink in the iw */ -+ wl_iw_detach(); -+ } -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+ if (dhd->thr_sysioc_ctl.thr_pid >= 0) { -+ PROC_STOP(&dhd->thr_sysioc_ctl); -+ } -+ -+ /* delete all interfaces, start with virtual */ -+ if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { -+ int i = 1; -+ dhd_if_t *ifp; -+ -+ /* Cleanup virtual interfaces */ -+ for (i = 1; i < DHD_MAX_IFS; i++) { -+ dhd_net_if_lock_local(dhd); -+ if (dhd->iflist[i]) { -+ dhd->iflist[i]->state = DHD_IF_DEL; -+ dhd->iflist[i]->idx = i; -+ dhd_op_if(dhd->iflist[i]); -+ } -+ -+ dhd_net_if_unlock_local(dhd); -+ } -+ /* delete primary interface 0 */ -+ ifp = dhd->iflist[0]; -+ ASSERT(ifp); -+ ASSERT(ifp->net); -+ if (ifp && ifp->net) { -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) -+ if (ifp->net->open) -+#else -+ if (ifp->net->netdev_ops == &dhd_ops_pri) -+#endif -+ { -+ unregister_netdev(ifp->net); -+ free_netdev(ifp->net); -+ ifp->net = NULL; -+ MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); -+ dhd->iflist[0] = NULL; -+ } -+ } -+ } -+ -+ /* Clear the watchdog timer */ -+ flags = dhd_os_spin_lock(&dhd->pub); -+ timer_valid = dhd->wd_timer_valid; -+ dhd->wd_timer_valid = FALSE; -+ dhd_os_spin_unlock(&dhd->pub, flags); -+ if (timer_valid) -+ del_timer_sync(&dhd->timer); -+ -+ if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { -+#ifdef DHDTHREAD -+ if (dhd->thr_wdt_ctl.thr_pid >= 0) { -+ PROC_STOP(&dhd->thr_wdt_ctl); -+ } -+ -+ if (dhd->thr_dpc_ctl.thr_pid >= 0) { -+ PROC_STOP(&dhd->thr_dpc_ctl); -+ } -+ else -+#endif /* DHDTHREAD */ -+ tasklet_kill(&dhd->tasklet); -+ } -+ -+#ifdef WL_CFG80211 -+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { -+ wl_cfg80211_detach(NULL); -+ dhd_monitor_uninit(); -+ } -+#endif -+ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -+ unregister_pm_notifier(&dhd_sleep_pm_notifier); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -+ /* && defined(CONFIG_PM_SLEEP) */ -+ -+ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { -+#ifdef CONFIG_HAS_WAKELOCK -+ dhd->wakelock_counter = 0; -+ dhd->wakelock_wd_counter = 0; -+ dhd->wakelock_rx_timeout_enable = 0; -+ dhd->wakelock_ctrl_timeout_enable = 0; -+ wake_lock_destroy(&dhd->wl_wifi); -+ wake_lock_destroy(&dhd->wl_rxwake); -+ wake_lock_destroy(&dhd->wl_ctrlwake); -+ wake_lock_destroy(&dhd->wl_wdwake); -+#endif /* CONFIG_HAS_WAKELOCK */ -+ } -+} -+ -+ -+void -+dhd_free(dhd_pub_t *dhdp) -+{ -+ dhd_info_t *dhd; -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (dhdp) { -+ int i; -+ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { -+ if (dhdp->reorder_bufs[i]) { -+ reorder_info_t *ptr; -+ uint32 buf_size = sizeof(struct reorder_info); -+ -+ ptr = dhdp->reorder_bufs[i]; -+ -+ buf_size += ((ptr->max_idx + 1) * sizeof(void*)); -+ DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", -+ i, ptr->max_idx, buf_size)); -+ -+ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); -+ dhdp->reorder_bufs[i] = NULL; -+ } -+ } -+ dhd = (dhd_info_t *)dhdp->info; -+ if (dhd) -+ MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); -+ } -+} -+ -+static void __exit -+dhd_module_cleanup(void) -+{ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ dhd_bus_unregister(); -+ -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+ wl_android_wifictrl_func_del(); -+#endif /* CONFIG_WIFI_CONTROL_FUNC */ -+ wl_android_exit(); -+ -+ /* Call customer gpio to turn off power with WL_REG_ON signal */ -+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); -+} -+ -+ -+static int __init -+dhd_module_init(void) -+{ -+ int error = 0; -+ -+#if defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ int retry = POWERUP_MAX_RETRY; -+ int chip_up = 0; -+#endif -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ wl_android_init(); -+ -+#if defined(DHDTHREAD) -+ /* Sanity check on the module parameters */ -+ do { -+ /* Both watchdog and DPC as tasklets are ok */ -+ if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0)) -+ break; -+ -+ /* If both watchdog and DPC are threads, TX must be deferred */ -+ if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx) -+ break; -+ -+ DHD_ERROR(("Invalid module parameters.\n")); -+ return -EINVAL; -+ } while (0); -+#endif -+ -+#if defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ do { -+ sema_init(&dhd_chipup_sem, 0); -+ dhd_bus_reg_sdio_notify(&dhd_chipup_sem); -+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+ if (wl_android_wifictrl_func_add() < 0) { -+ dhd_bus_unreg_sdio_notify(); -+ goto fail_1; -+ } -+#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ -+ if (down_timeout(&dhd_chipup_sem, -+ msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { -+ dhd_bus_unreg_sdio_notify(); -+ chip_up = 1; -+ break; -+ } -+ DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", -+ retry+1)); -+ dhd_bus_unreg_sdio_notify(); -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+ wl_android_wifictrl_func_del(); -+#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ -+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); -+ } while (retry-- > 0); -+ -+ if (!chip_up) { -+ DHD_ERROR(("\nfailed to power up wifi chip, max retry reached, exits **\n\n")); -+ return -ENODEV; -+ } -+#else -+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+ if (wl_android_wifictrl_func_add() < 0) -+ goto fail_1; -+#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ -+ -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ sema_init(&dhd_registration_sem, 0); -+#endif -+ -+ -+ error = dhd_bus_register(); -+ -+ if (!error) -+ printf("\n%s\n", dhd_version); -+ else { -+ DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); -+ goto fail_1; -+ } -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ /* -+ * Wait till MMC sdio_register_driver callback called and made driver attach. -+ * It's needed to make sync up exit from dhd insmod and -+ * Kernel MMC sdio device callback registration -+ */ -+ if ((down_timeout(&dhd_registration_sem, -+ msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) || -+ (dhd_registration_check != TRUE)) { -+ error = -ENODEV; -+ DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); -+ goto fail_2; -+ } -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+#if defined(WL_CFG80211) -+ wl_android_post_init(); -+#endif /* defined(WL_CFG80211) */ -+ -+ return error; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+fail_2: -+ dhd_bus_unregister(); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+ -+fail_1: -+ -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+ wl_android_wifictrl_func_del(); -+#endif -+ -+ /* Call customer gpio to turn off power with WL_REG_ON signal */ -+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); -+ -+ return error; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+late_initcall(dhd_module_init); -+#else -+module_init(dhd_module_init); -+#endif -+ -+module_exit(dhd_module_cleanup); -+ -+/* -+ * OS specific functions required to implement DHD driver in OS independent way -+ */ -+int -+dhd_os_proto_block(dhd_pub_t *pub) -+{ -+ dhd_info_t * dhd = (dhd_info_t *)(pub->info); -+ -+ if (dhd) { -+ down(&dhd->proto_sem); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+int -+dhd_os_proto_unblock(dhd_pub_t *pub) -+{ -+ dhd_info_t * dhd = (dhd_info_t *)(pub->info); -+ -+ if (dhd) { -+ up(&dhd->proto_sem); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+unsigned int -+dhd_os_get_ioctl_resp_timeout(void) -+{ -+ return ((unsigned int)dhd_ioctl_timeout_msec); -+} -+ -+void -+dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) -+{ -+ dhd_ioctl_timeout_msec = (int)timeout_msec; -+} -+ -+int -+dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) -+{ -+ dhd_info_t * dhd = (dhd_info_t *)(pub->info); -+ int timeout; -+ -+ /* Convert timeout in millsecond to jiffies */ -+ timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); -+ -+ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); -+ return timeout; -+} -+ -+int -+dhd_os_ioctl_resp_wake(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ -+ if (waitqueue_active(&dhd->ioctl_resp_wait)) { -+ wake_up(&dhd->ioctl_resp_wait); -+ } -+ -+ return 0; -+} -+ -+void -+dhd_os_wd_timer(void *bus, uint wdtick) -+{ -+ dhd_pub_t *pub = bus; -+ dhd_info_t *dhd = (dhd_info_t *)pub->info; -+ unsigned long flags; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (!dhd) -+ return; -+ -+ flags = dhd_os_spin_lock(pub); -+ -+ /* don't start the wd until fw is loaded */ -+ if (pub->busstate == DHD_BUS_DOWN) { -+ dhd_os_spin_unlock(pub, flags); -+ if (!wdtick) -+ DHD_OS_WD_WAKE_UNLOCK(pub); -+ return; -+ } -+ -+ /* totally stop the timer */ -+ if (!wdtick && dhd->wd_timer_valid == TRUE) { -+ dhd->wd_timer_valid = FALSE; -+ dhd_os_spin_unlock(pub, flags); -+#ifdef DHDTHREAD -+ del_timer_sync(&dhd->timer); -+#else -+ del_timer(&dhd->timer); -+#endif /* DHDTHREAD */ -+ DHD_OS_WD_WAKE_UNLOCK(pub); -+ return; -+ } -+ -+ if (wdtick) { -+ DHD_OS_WD_WAKE_LOCK(pub); -+ dhd_watchdog_ms = (uint)wdtick; -+ /* Re arm the timer, at last watchdog period */ -+ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); -+ dhd->wd_timer_valid = TRUE; -+ } -+ dhd_os_spin_unlock(pub, flags); -+} -+ -+void * -+dhd_os_open_image(char *filename) -+{ -+ struct file *fp; -+ -+ fp = filp_open(filename, O_RDONLY, 0); -+ /* -+ * 2.6.11 (FC4) supports filp_open() but later revs don't? -+ * Alternative: -+ * fp = open_namei(AT_FDCWD, filename, O_RD, 0); -+ * ??? -+ */ -+ if (IS_ERR(fp)) -+ fp = NULL; -+ -+ return fp; -+} -+ -+int -+dhd_os_get_image_block(char *buf, int len, void *image) -+{ -+ struct file *fp = (struct file *)image; -+ int rdlen; -+ -+ if (!image) -+ return 0; -+ -+ rdlen = kernel_read(fp, fp->f_pos, buf, len); -+ if (rdlen > 0) -+ fp->f_pos += rdlen; -+ -+ return rdlen; -+} -+ -+void -+dhd_os_close_image(void *image) -+{ -+ if (image) -+ filp_close((struct file *)image, NULL); -+} -+ -+ -+void -+dhd_os_sdlock(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd; -+ -+ dhd = (dhd_info_t *)(pub->info); -+ -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ down(&dhd->sdsem); -+ else -+#endif /* DHDTHREAD */ -+ spin_lock_bh(&dhd->sdlock); -+} -+ -+void -+dhd_os_sdunlock(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd; -+ -+ dhd = (dhd_info_t *)(pub->info); -+ -+#ifdef DHDTHREAD -+ if (dhd->threads_only) -+ up(&dhd->sdsem); -+ else -+#endif /* DHDTHREAD */ -+ spin_unlock_bh(&dhd->sdlock); -+} -+ -+void -+dhd_os_sdlock_txq(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd; -+ -+ dhd = (dhd_info_t *)(pub->info); -+ spin_lock_bh(&dhd->txqlock); -+} -+ -+void -+dhd_os_sdunlock_txq(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd; -+ -+ dhd = (dhd_info_t *)(pub->info); -+ spin_unlock_bh(&dhd->txqlock); -+} -+ -+void -+dhd_os_sdlock_rxq(dhd_pub_t *pub) -+{ -+} -+ -+void -+dhd_os_sdunlock_rxq(dhd_pub_t *pub) -+{ -+} -+ -+void -+dhd_os_sdtxlock(dhd_pub_t *pub) -+{ -+ dhd_os_sdlock(pub); -+} -+ -+void -+dhd_os_sdtxunlock(dhd_pub_t *pub) -+{ -+ dhd_os_sdunlock(pub); -+} -+ -+#if defined(CONFIG_DHD_USE_STATIC_BUF) -+uint8* dhd_os_prealloc(void *osh, int section, uint size) -+{ -+ return (uint8*)wl_android_prealloc(section, size); -+} -+ -+void dhd_os_prefree(void *osh, void *addr, uint size) -+{ -+} -+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ -+ -+#if defined(CONFIG_WIRELESS_EXT) -+struct iw_statistics * -+dhd_get_wireless_stats(struct net_device *dev) -+{ -+ int res = 0; -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ if (!dhd->pub.up) { -+ return NULL; -+ } -+ -+ res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); -+ -+ if (res == 0) -+ return &dhd->iw.wstats; -+ else -+ return NULL; -+} -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+static int -+dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, -+ wl_event_msg_t *event, void **data) -+{ -+ int bcmerror = 0; -+ ASSERT(dhd != NULL); -+ -+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data); -+ if (bcmerror != BCME_OK) -+ return (bcmerror); -+ -+#if defined(CONFIG_WIRELESS_EXT) -+ if (event->bsscfgidx == 0) { -+ /* -+ * Wireless ext is on primary interface only -+ */ -+ -+ ASSERT(dhd->iflist[*ifidx] != NULL); -+ ASSERT(dhd->iflist[*ifidx]->net != NULL); -+ -+ if (dhd->iflist[*ifidx]->net) { -+ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); -+ } -+ } -+#endif /* defined(CONFIG_WIRELESS_EXT) */ -+ -+#ifdef WL_CFG80211 -+ if ((ntoh32(event->event_type) == WLC_E_IF) && -+ (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD)) -+ /* If ADD_IF has been called directly by wl utility then we -+ * should not report this. In case if ADD_IF was called from -+ * CFG stack, then too this event need not be reported back -+ */ -+ return (BCME_OK); -+ if ((wl_cfg80211_is_progress_ifchange() || -+ wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) { -+ /* -+ * If IF_ADD/CHANGE operation is going on, -+ * discard any event received on the virtual I/F -+ */ -+ return (BCME_OK); -+ } -+ -+ ASSERT(dhd->iflist[*ifidx] != NULL); -+ ASSERT(dhd->iflist[*ifidx]->net != NULL); -+ if (dhd->iflist[*ifidx]->event2cfg80211 && dhd->iflist[*ifidx]->net) { -+ wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); -+ } -+#endif /* defined(WL_CFG80211) */ -+ -+ return (bcmerror); -+} -+ -+/* send up locally generated event */ -+void -+dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -+{ -+ switch (ntoh32(event->event_type)) { -+#ifdef WLBTAMP -+ /* Send up locally generated AMP HCI Events */ -+ case WLC_E_BTA_HCI_EVENT: { -+ struct sk_buff *p, *skb; -+ bcm_event_t *msg; -+ wl_event_msg_t *p_bcm_event; -+ char *ptr; -+ uint32 len; -+ uint32 pktlen; -+ dhd_if_t *ifp; -+ dhd_info_t *dhd; -+ uchar *eth; -+ int ifidx; -+ -+ len = ntoh32(event->datalen); -+ pktlen = sizeof(bcm_event_t) + len + 2; -+ dhd = dhdp->info; -+ ifidx = dhd_ifname2idx(dhd, event->ifname); -+ -+ if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { -+ ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); -+ -+ msg = (bcm_event_t *) PKTDATA(dhdp->osh, p); -+ -+ bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN); -+ bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN); -+ ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost); -+ -+ msg->eth.ether_type = hton16(ETHER_TYPE_BRCM); -+ -+ /* BCM Vendor specific header... */ -+ msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG); -+ msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION; -+ bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN); -+ -+ /* vendor spec header length + pvt data length (private indication -+ * hdr + actual message itself) -+ */ -+ msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH + -+ BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len); -+ msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT); -+ -+ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); -+ -+ /* copy wl_event_msg_t into sk_buf */ -+ -+ /* pointer to wl_event_msg_t in sk_buf */ -+ p_bcm_event = &msg->event; -+ bcopy(event, p_bcm_event, sizeof(wl_event_msg_t)); -+ -+ /* copy hci event into sk_buf */ -+ bcopy(data, (p_bcm_event + 1), len); -+ -+ msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) + -+ ntoh16(msg->bcm_hdr.length)); -+ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); -+ -+ ptr = (char *)(msg + 1); -+ /* Last 2 bytes of the message are 0x00 0x00 to signal that there -+ * are no ethertypes which are following this -+ */ -+ ptr[len+0] = 0x00; -+ ptr[len+1] = 0x00; -+ -+ skb = PKTTONATIVE(dhdp->osh, p); -+ eth = skb->data; -+ len = skb->len; -+ -+ ifp = dhd->iflist[ifidx]; -+ if (ifp == NULL) -+ ifp = dhd->iflist[0]; -+ -+ ASSERT(ifp); -+ skb->dev = ifp->net; -+ skb->protocol = eth_type_trans(skb, skb->dev); -+ -+ skb->data = eth; -+ skb->len = len; -+ -+ /* Strip header, count, deliver upward */ -+ skb_pull(skb, ETH_HLEN); -+ -+ /* Send the packet */ -+ if (in_interrupt()) { -+ netif_rx(skb); -+ } else { -+ netif_rx_ni(skb); -+ } -+ } -+ else { -+ /* Could not allocate a sk_buf */ -+ DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__)); -+ } -+ break; -+ } /* case WLC_E_BTA_HCI_EVENT */ -+#endif /* WLBTAMP */ -+ -+ default: -+ break; -+ } -+} -+ -+void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+ struct dhd_info *dhdinfo = dhd->info; -+ int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); -+ dhd_os_sdunlock(dhd); -+ wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); -+ dhd_os_sdlock(dhd); -+#endif -+ return; -+} -+ -+void dhd_wait_event_wakeup(dhd_pub_t *dhd) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+ struct dhd_info *dhdinfo = dhd->info; -+ if (waitqueue_active(&dhdinfo->ctrl_wait)) -+ wake_up(&dhdinfo->ctrl_wait); -+#endif -+ return; -+} -+ -+int -+dhd_dev_reset(struct net_device *dev, uint8 flag) -+{ -+ int ret; -+ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ if (flag == TRUE) { -+ /* Issue wl down command before resetting the chip */ -+ if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { -+ DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); -+ } -+ } -+ -+ ret = dhd_bus_devreset(&dhd->pub, flag); -+ if (ret) { -+ DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); -+ return ret; -+ } -+ -+ return ret; -+} -+ -+int net_os_set_suspend_disable(struct net_device *dev, int val) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ret = 0; -+ -+ if (dhd) { -+ ret = dhd->pub.suspend_disable_flag; -+ dhd->pub.suspend_disable_flag = val; -+ } -+ return ret; -+} -+ -+int net_os_set_suspend(struct net_device *dev, int val, int force) -+{ -+ int ret = 0; -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ if (dhd) { -+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -+ ret = dhd_set_suspend(val, &dhd->pub); -+#else -+ ret = dhd_suspend_resume_helper(dhd, val, force); -+#endif -+#ifdef WL_CFG80211 -+ wl_cfg80211_update_power_mode(dev); -+#endif -+ } -+ return ret; -+} -+ -+int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ if (dhd) -+ dhd->pub.suspend_bcn_li_dtim = val; -+ -+ return 0; -+} -+ -+#ifdef PKT_FILTER_SUPPORT -+int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) -+{ -+#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ char *filterp = NULL; -+ int ret = 0; -+ -+ if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || -+ (num == DHD_MDNS_FILTER_NUM)) -+ return ret; -+ if (num >= dhd->pub.pktfilter_count) -+ return -EINVAL; -+ if (add_remove) { -+ switch (num) { -+ case DHD_BROADCAST_FILTER_NUM: -+ filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; -+ break; -+ case DHD_MULTICAST4_FILTER_NUM: -+ filterp = "102 0 0 0 0xFFFFFF 0x01005E"; -+ break; -+ case DHD_MULTICAST6_FILTER_NUM: -+ filterp = "103 0 0 0 0xFFFF 0x3333"; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } -+ dhd->pub.pktfilter[num] = filterp; -+ dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]); -+ return ret; -+#else -+ return 0; -+#endif -+} -+ -+int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) -+{ -+ int ret = 0; -+ -+ /* Packet filtering is set only if we still in early-suspend and -+ * we need either to turn it ON or turn it OFF -+ * We can always turn it OFF in case of early-suspend, but we turn it -+ * back ON only if suspend_disable_flag was not set -+ */ -+ if (dhdp && dhdp->up) { -+ if (dhdp->in_suspend) { -+ if (!val || (val && !dhdp->suspend_disable_flag)) -+ dhd_enable_packet_filter(val, dhdp); -+ } -+ } -+ return ret; -+ -+} -+ -+int net_os_enable_packet_filter(struct net_device *dev, int val) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ return dhd_os_enable_packet_filter(&dhd->pub, val); -+} -+#endif /* PKT_FILTER_SUPPORT */ -+ -+int -+dhd_dev_init_ioctl(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ return dhd_preinit_ioctls(&dhd->pub); -+} -+ -+#ifdef PNO_SUPPORT -+/* Linux wrapper to call common dhd_pno_clean */ -+int -+dhd_dev_pno_reset(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ return (dhd_pno_clean(&dhd->pub)); -+} -+ -+ -+/* Linux wrapper to call common dhd_pno_enable */ -+int -+dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ return (dhd_pno_enable(&dhd->pub, pfn_enabled)); -+} -+ -+ -+/* Linux wrapper to call common dhd_pno_set */ -+int -+dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, -+ ushort scan_fr, int pno_repeat, int pno_freq_expo_max) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max)); -+} -+ -+/* Linux wrapper to get pno status */ -+int -+dhd_dev_get_pno_status(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ return (dhd_pno_get_status(&dhd->pub)); -+} -+ -+#endif /* PNO_SUPPORT */ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+static void dhd_hang_process(struct work_struct *work) -+{ -+ dhd_info_t *dhd; -+ struct net_device *dev; -+ -+ dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang); -+ dev = dhd->iflist[0]->net; -+ -+ if (dev) { -+ rtnl_lock(); -+ dev_close(dev); -+ rtnl_unlock(); -+#if defined(WL_WIRELESS_EXT) -+ wl_iw_send_priv_event(dev, "HANG"); -+#endif -+#if defined(WL_CFG80211) -+ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -+#endif -+ } -+} -+ -+int dhd_os_send_hang_message(dhd_pub_t *dhdp) -+{ -+ int ret = 0; -+ if (dhdp) { -+ if (!dhdp->hang_was_sent) { -+ dhdp->hang_was_sent = 1; -+ schedule_work(&dhdp->info->work_hang); -+ } -+ } -+ return ret; -+} -+ -+int net_os_send_hang_message(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ret = 0; -+ -+ if (dhd) -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ ret = dhd_os_send_hang_message(&dhd->pub); -+#else -+ ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -+#endif -+ return ret; -+} -+#endif -+ -+void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ -+ if (dhd && dhd->pub.up) { -+ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); -+#ifdef WL_CFG80211 -+ wl_update_wiphybands(NULL, notify); -+#endif -+ } -+} -+ -+void dhd_bus_band_set(struct net_device *dev, uint band) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ if (dhd && dhd->pub.up) { -+#ifdef WL_CFG80211 -+ wl_update_wiphybands(NULL, true); -+#endif -+ } -+} -+ -+void dhd_net_if_lock(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ dhd_net_if_lock_local(dhd); -+} -+ -+void dhd_net_if_unlock(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ dhd_net_if_unlock_local(dhd); -+} -+ -+static void dhd_net_if_lock_local(dhd_info_t *dhd) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ if (dhd) -+ mutex_lock(&dhd->dhd_net_if_mutex); -+#endif -+} -+ -+static void dhd_net_if_unlock_local(dhd_info_t *dhd) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ if (dhd) -+ mutex_unlock(&dhd->dhd_net_if_mutex); -+#endif -+} -+ -+static void dhd_suspend_lock(dhd_pub_t *pub) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ if (dhd) -+ mutex_lock(&dhd->dhd_suspend_mutex); -+#endif -+} -+ -+static void dhd_suspend_unlock(dhd_pub_t *pub) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ if (dhd) -+ mutex_unlock(&dhd->dhd_suspend_mutex); -+#endif -+} -+ -+unsigned long dhd_os_spin_lock(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags = 0; -+ -+ if (dhd) -+ spin_lock_irqsave(&dhd->dhd_lock, flags); -+ -+ return flags; -+} -+ -+void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ -+ if (dhd) -+ spin_unlock_irqrestore(&dhd->dhd_lock, flags); -+} -+ -+static int -+dhd_get_pend_8021x_cnt(dhd_info_t *dhd) -+{ -+ return (atomic_read(&dhd->pend_8021x_cnt)); -+} -+ -+#define MAX_WAIT_FOR_8021X_TX 25 -+ -+int -+dhd_wait_pend8021x(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int timeout = msecs_to_jiffies(10); -+ int ntimes = MAX_WAIT_FOR_8021X_TX; -+ int pend = dhd_get_pend_8021x_cnt(dhd); -+ -+ while (ntimes && pend) { -+ if (pend) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(timeout); -+ set_current_state(TASK_RUNNING); -+ ntimes--; -+ } -+ pend = dhd_get_pend_8021x_cnt(dhd); -+ } -+ if (ntimes == 0) -+ DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); -+ return pend; -+} -+ -+#ifdef DHD_DEBUG -+int -+write_to_file(dhd_pub_t *dhd, uint8 *buf, int size) -+{ -+ int ret = 0; -+ struct file *fp; -+ mm_segment_t old_fs; -+ loff_t pos = 0; -+ -+ /* change to KERNEL_DS address limit */ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ -+ /* open file to write */ -+ fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); -+ if (!fp) { -+ printf("%s: open file error\n", __FUNCTION__); -+ ret = -1; -+ goto exit; -+ } -+ -+ /* Write buf to file */ -+ fp->f_op->write(fp, buf, size, &pos); -+ -+exit: -+ /* free buf before return */ -+ MFREE(dhd->osh, buf, size); -+ /* close file before return */ -+ if (fp) -+ filp_close(fp, current->files); -+ /* restore previous address limit */ -+ set_fs(old_fs); -+ -+ return ret; -+} -+#endif /* DHD_DEBUG */ -+ -+int dhd_os_wake_lock_timeout(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags; -+ int ret = 0; -+ -+ if (dhd) { -+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -+ ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? -+ dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; -+#ifdef CONFIG_HAS_WAKELOCK -+ if (dhd->wakelock_rx_timeout_enable) -+ wake_lock_timeout(&dhd->wl_rxwake, -+ msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); -+ if (dhd->wakelock_ctrl_timeout_enable) -+ wake_lock_timeout(&dhd->wl_ctrlwake, -+ msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); -+#endif -+ dhd->wakelock_rx_timeout_enable = 0; -+ dhd->wakelock_ctrl_timeout_enable = 0; -+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -+ } -+ return ret; -+} -+ -+int net_os_wake_lock_timeout(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ret = 0; -+ -+ if (dhd) -+ ret = dhd_os_wake_lock_timeout(&dhd->pub); -+ return ret; -+} -+ -+int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags; -+ -+ if (dhd) { -+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -+ if (val > dhd->wakelock_rx_timeout_enable) -+ dhd->wakelock_rx_timeout_enable = val; -+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -+ } -+ return 0; -+} -+ -+int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags; -+ -+ if (dhd) { -+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -+ if (val > dhd->wakelock_ctrl_timeout_enable) -+ dhd->wakelock_ctrl_timeout_enable = val; -+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -+ } -+ return 0; -+} -+ -+int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ret = 0; -+ -+ if (dhd) -+ ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); -+ return ret; -+} -+ -+int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ret = 0; -+ -+ if (dhd) -+ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); -+ return ret; -+} -+ -+int dhd_os_wake_lock(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags; -+ int ret = 0; -+ -+ if (dhd) { -+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -+#ifdef CONFIG_HAS_WAKELOCK -+ if (!dhd->wakelock_counter) -+ wake_lock(&dhd->wl_wifi); -+#endif -+ dhd->wakelock_counter++; -+ ret = dhd->wakelock_counter; -+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -+ } -+ return ret; -+} -+ -+int net_os_wake_lock(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ret = 0; -+ -+ if (dhd) -+ ret = dhd_os_wake_lock(&dhd->pub); -+ return ret; -+} -+ -+int dhd_os_wake_unlock(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags; -+ int ret = 0; -+ -+ dhd_os_wake_lock_timeout(pub); -+ if (dhd) { -+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -+ if (dhd->wakelock_counter) { -+ dhd->wakelock_counter--; -+#ifdef CONFIG_HAS_WAKELOCK -+ if (!dhd->wakelock_counter) -+ wake_unlock(&dhd->wl_wifi); -+#endif -+ ret = dhd->wakelock_counter; -+ } -+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -+ } -+ return ret; -+} -+ -+int dhd_os_check_wakelock(void *dhdp) -+{ -+#ifdef CONFIG_HAS_WAKELOCK -+ dhd_pub_t *pub = (dhd_pub_t *)dhdp; -+ dhd_info_t *dhd; -+ -+ if (!pub) -+ return 0; -+ dhd = (dhd_info_t *)(pub->info); -+ -+ if (dhd && (wake_lock_active(&dhd->wl_wifi) || -+ wake_lock_active(&dhd->wl_wdwake))) -+ return 1; -+#endif -+ return 0; -+} -+ -+int net_os_wake_unlock(struct net_device *dev) -+{ -+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -+ int ret = 0; -+ -+ if (dhd) -+ ret = dhd_os_wake_unlock(&dhd->pub); -+ return ret; -+} -+ -+int dhd_os_wd_wake_lock(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags; -+ int ret = 0; -+ -+ if (dhd) { -+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -+#ifdef CONFIG_HAS_WAKELOCK -+ if (!dhd->wakelock_wd_counter) -+ wake_lock(&dhd->wl_wdwake); -+#endif -+ dhd->wakelock_wd_counter++; -+ ret = dhd->wakelock_wd_counter; -+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -+ } -+ return ret; -+} -+ -+int dhd_os_wd_wake_unlock(dhd_pub_t *pub) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(pub->info); -+ unsigned long flags; -+ int ret = 0; -+ -+ if (dhd) { -+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -+ if (dhd->wakelock_wd_counter) { -+ dhd->wakelock_wd_counter = 0; -+#ifdef CONFIG_HAS_WAKELOCK -+ wake_unlock(&dhd->wl_wdwake); -+#endif -+ } -+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -+ } -+ return ret; -+} -+ -+int dhd_os_check_if_up(void *dhdp) -+{ -+ dhd_pub_t *pub = (dhd_pub_t *)dhdp; -+ -+ if (!pub) -+ return 0; -+ return pub->up; -+} -+ -+/* function to collect firmware, chip id and chip version info */ -+void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) -+{ -+ int i; -+ -+ i = snprintf(info_string, sizeof(info_string), -+ " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); -+ -+ if (!dhdp) -+ return; -+ -+ i = snprintf(&info_string[i], sizeof(info_string) - i, -+ "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), -+ dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); -+} -+ -+int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) -+{ -+ int ifidx; -+ int ret = 0; -+ dhd_info_t *dhd = NULL; -+ -+ if (!net || !netdev_priv(net)) { -+ DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); -+ return -EINVAL; -+ } -+ -+ dhd = *(dhd_info_t **)netdev_priv(net); -+ ifidx = dhd_net2idx(dhd, net); -+ if (ifidx == DHD_BAD_IF) { -+ DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); -+ return -ENODEV; -+ } -+ -+ DHD_OS_WAKE_LOCK(&dhd->pub); -+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); -+ dhd_check_hang(net, &dhd->pub, ret); -+ DHD_OS_WAKE_UNLOCK(&dhd->pub); -+ -+ return ret; -+} -+ -+bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) -+{ -+ struct net_device *net; -+ -+ net = dhd_idx2net(dhdp, ifidx); -+ return dhd_check_hang(net, dhdp, ret); -+} -+ -+ -+#ifdef PROP_TXSTATUS -+extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid, -+ uint8 iftype, uint8* ea); -+extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); -+ -+int dhd_wlfc_interface_event(struct dhd_info *dhd, -+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -+{ -+ int ret = BCME_OK; -+ -+ dhd_os_wlfc_block(&dhd->pub); -+ if (dhd->pub.wlfc_state != NULL) -+ ret = dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); -+ dhd_os_wlfc_unblock(&dhd->pub); -+ return ret; -+} -+ -+int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) -+{ -+ int ret = BCME_OK; -+ -+ dhd_os_wlfc_block(&dhd->pub); -+ if (dhd->pub.wlfc_state != NULL) -+ ret = dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); -+ dhd_os_wlfc_unblock(&dhd->pub); -+ return ret; -+} -+ -+int dhd_wlfc_event(struct dhd_info *dhd) -+{ -+ int ret; -+ -+ dhd_os_wlfc_block(&dhd->pub); -+ ret = dhd_wlfc_enable(&dhd->pub); -+ dhd_os_wlfc_unblock(&dhd->pub); -+ return ret; -+} -+#endif /* PROP_TXSTATUS */ -+ -+#ifdef BCMDBGFS -+ -+#include <linux/debugfs.h> -+ -+extern uint32 dhd_readregl(void *bp, uint32 addr); -+extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); -+ -+typedef struct dhd_dbgfs { -+ struct dentry *debugfs_dir; -+ struct dentry *debugfs_mem; -+ dhd_pub_t *dhdp; -+ uint32 size; -+} dhd_dbgfs_t; -+ -+dhd_dbgfs_t g_dbgfs; -+ -+static int -+dhd_dbg_state_open(struct inode *inode, struct file *file) -+{ -+ file->private_data = inode->i_private; -+ return 0; -+} -+ -+static ssize_t -+dhd_dbg_state_read(struct file *file, char __user *ubuf, -+ size_t count, loff_t *ppos) -+{ -+ ssize_t rval; -+ uint32 tmp; -+ loff_t pos = *ppos; -+ size_t ret; -+ -+ if (pos < 0) -+ return -EINVAL; -+ if (pos >= g_dbgfs.size || !count) -+ return 0; -+ if (count > g_dbgfs.size - pos) -+ count = g_dbgfs.size - pos; -+ -+ /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ -+ tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); -+ -+ ret = copy_to_user(ubuf, &tmp, 4); -+ if (ret == count) -+ return -EFAULT; -+ -+ count -= ret; -+ *ppos = pos + count; -+ rval = count; -+ -+ return rval; -+} -+ -+ -+static ssize_t -+dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) -+{ -+ loff_t pos = *ppos; -+ size_t ret; -+ uint32 buf; -+ -+ if (pos < 0) -+ return -EINVAL; -+ if (pos >= g_dbgfs.size || !count) -+ return 0; -+ if (count > g_dbgfs.size - pos) -+ count = g_dbgfs.size - pos; -+ -+ ret = copy_from_user(&buf, ubuf, sizeof(uint32)); -+ if (ret == count) -+ return -EFAULT; -+ -+ /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ -+ dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); -+ -+ return count; -+} -+ -+ -+loff_t -+dhd_debugfs_lseek(struct file *file, loff_t off, int whence) -+{ -+ loff_t pos = -1; -+ -+ switch (whence) { -+ case 0: -+ pos = off; -+ break; -+ case 1: -+ pos = file->f_pos + off; -+ break; -+ case 2: -+ pos = g_dbgfs.size - off; -+ } -+ return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); -+} -+ -+static const struct file_operations dhd_dbg_state_ops = { -+ .read = dhd_dbg_state_read, -+ .write = dhd_debugfs_write, -+ .open = dhd_dbg_state_open, -+ .llseek = dhd_debugfs_lseek -+}; -+ -+static void dhd_dbg_create(void) -+{ -+ if (g_dbgfs.debugfs_dir) { -+ g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, -+ NULL, &dhd_dbg_state_ops); -+ } -+} -+ -+void dhd_dbg_init(dhd_pub_t *dhdp) -+{ -+ int err; -+ -+ g_dbgfs.dhdp = dhdp; -+ g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ -+ -+ g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); -+ if (IS_ERR(g_dbgfs.debugfs_dir)) { -+ err = PTR_ERR(g_dbgfs.debugfs_dir); -+ g_dbgfs.debugfs_dir = NULL; -+ return; -+ } -+ -+ dhd_dbg_create(); -+ -+ return; -+} -+ -+void dhd_dbg_remove(void) -+{ -+ debugfs_remove(g_dbgfs.debugfs_mem); -+ debugfs_remove(g_dbgfs.debugfs_dir); -+ -+ bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); -+ -+} -+#endif /* ifdef BCMDBGFS */ -+ -+#ifdef WLMEDIA_HTSF -+ -+static -+void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); -+ struct sk_buff *skb; -+ uint32 htsf = 0; -+ uint16 dport = 0, oldmagic = 0xACAC; -+ char *p1; -+ htsfts_t ts; -+ -+ /* timestamp packet */ -+ -+ p1 = (char*) PKTDATA(dhdp->osh, pktbuf); -+ -+ if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { -+/* memcpy(&proto, p1+26, 4); */ -+ memcpy(&dport, p1+40, 2); -+/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ -+ dport = ntoh16(dport); -+ } -+ -+ /* timestamp only if icmp or udb iperf with port 5555 */ -+/* if (proto == 17 && dport == tsport) { */ -+ if (dport >= tsport && dport <= tsport + 20) { -+ -+ skb = (struct sk_buff *) pktbuf; -+ -+ htsf = dhd_get_htsf(dhd, 0); -+ memset(skb->data + 44, 0, 2); /* clear checksum */ -+ memcpy(skb->data+82, &oldmagic, 2); -+ memcpy(skb->data+84, &htsf, 4); -+ -+ memset(&ts, 0, sizeof(htsfts_t)); -+ ts.magic = HTSFMAGIC; -+ ts.prio = PKTPRIO(pktbuf); -+ ts.seqnum = htsf_seqnum++; -+ ts.c10 = get_cycles(); -+ ts.t10 = htsf; -+ ts.endmagic = HTSFENDMAGIC; -+ -+ memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); -+ } -+} -+ -+static void dhd_dump_htsfhisto(histo_t *his, char *s) -+{ -+ int pktcnt = 0, curval = 0, i; -+ for (i = 0; i < (NUMBIN-2); i++) { -+ curval += 500; -+ printf("%d ", his->bin[i]); -+ pktcnt += his->bin[i]; -+ } -+ printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, -+ his->bin[NUMBIN-1], s); -+} -+ -+static -+void sorttobin(int value, histo_t *histo) -+{ -+ int i, binval = 0; -+ -+ if (value < 0) { -+ histo->bin[NUMBIN-1]++; -+ return; -+ } -+ if (value > histo->bin[NUMBIN-2]) /* store the max value */ -+ histo->bin[NUMBIN-2] = value; -+ -+ for (i = 0; i < (NUMBIN-2); i++) { -+ binval += 500; /* 500m s bins */ -+ if (value <= binval) { -+ histo->bin[i]++; -+ return; -+ } -+ } -+ histo->bin[NUMBIN-3]++; -+} -+ -+static -+void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) -+{ -+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -+ struct sk_buff *skb; -+ char *p1; -+ uint16 old_magic; -+ int d1, d2, d3, end2end; -+ htsfts_t *htsf_ts; -+ uint32 htsf; -+ -+ skb = PKTTONATIVE(dhdp->osh, pktbuf); -+ p1 = (char*)PKTDATA(dhdp->osh, pktbuf); -+ -+ if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { -+ memcpy(&old_magic, p1+78, 2); -+ htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); -+ } -+ else -+ return; -+ -+ if (htsf_ts->magic == HTSFMAGIC) { -+ htsf_ts->tE0 = dhd_get_htsf(dhd, 0); -+ htsf_ts->cE0 = get_cycles(); -+ } -+ -+ if (old_magic == 0xACAC) { -+ -+ tspktcnt++; -+ htsf = dhd_get_htsf(dhd, 0); -+ memcpy(skb->data+92, &htsf, sizeof(uint32)); -+ -+ memcpy(&ts[tsidx].t1, skb->data+80, 16); -+ -+ d1 = ts[tsidx].t2 - ts[tsidx].t1; -+ d2 = ts[tsidx].t3 - ts[tsidx].t2; -+ d3 = ts[tsidx].t4 - ts[tsidx].t3; -+ end2end = ts[tsidx].t4 - ts[tsidx].t1; -+ -+ sorttobin(d1, &vi_d1); -+ sorttobin(d2, &vi_d2); -+ sorttobin(d3, &vi_d3); -+ sorttobin(end2end, &vi_d4); -+ -+ if (end2end > 0 && end2end > maxdelay) { -+ maxdelay = end2end; -+ maxdelaypktno = tspktcnt; -+ memcpy(&maxdelayts, &ts[tsidx], 16); -+ } -+ if (++tsidx >= TSMAX) -+ tsidx = 0; -+ } -+} -+ -+uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) -+{ -+ uint32 htsf = 0, cur_cycle, delta, delta_us; -+ uint32 factor, baseval, baseval2; -+ cycles_t t; -+ -+ t = get_cycles(); -+ cur_cycle = t; -+ -+ if (cur_cycle > dhd->htsf.last_cycle) -+ delta = cur_cycle - dhd->htsf.last_cycle; -+ else { -+ delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); -+ } -+ -+ delta = delta >> 4; -+ -+ if (dhd->htsf.coef) { -+ /* times ten to get the first digit */ -+ factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); -+ baseval = (delta*10)/factor; -+ baseval2 = (delta*10)/(factor+1); -+ delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); -+ htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; -+ } -+ else { -+ DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); -+ } -+ -+ return htsf; -+} -+ -+static void dhd_dump_latency(void) -+{ -+ int i, max = 0; -+ int d1, d2, d3, d4, d5; -+ -+ printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); -+ for (i = 0; i < TSMAX; i++) { -+ d1 = ts[i].t2 - ts[i].t1; -+ d2 = ts[i].t3 - ts[i].t2; -+ d3 = ts[i].t4 - ts[i].t3; -+ d4 = ts[i].t4 - ts[i].t1; -+ d5 = ts[max].t4-ts[max].t1; -+ if (d4 > d5 && d4 > 0) { -+ max = i; -+ } -+ printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", -+ ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, -+ d1, d2, d3, d4, i); -+ } -+ -+ printf("current idx = %d \n", tsidx); -+ -+ printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); -+ printf("%08X %08X %08X %08X \t%d %d %d %d\n", -+ maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, -+ maxdelayts.t2 - maxdelayts.t1, -+ maxdelayts.t3 - maxdelayts.t2, -+ maxdelayts.t4 - maxdelayts.t3, -+ maxdelayts.t4 - maxdelayts.t1); -+} -+ -+ -+static int -+dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) -+{ -+ wl_ioctl_t ioc; -+ char buf[32]; -+ int ret; -+ uint32 s1, s2; -+ -+ struct tsf { -+ uint32 low; -+ uint32 high; -+ } tsf_buf; -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ memset(&tsf_buf, 0, sizeof(tsf_buf)); -+ -+ ioc.cmd = WLC_GET_VAR; -+ ioc.buf = buf; -+ ioc.len = (uint)sizeof(buf); -+ ioc.set = FALSE; -+ -+ strncpy(buf, "tsf", sizeof(buf) - 1); -+ buf[sizeof(buf) - 1] = '\0'; -+ s1 = dhd_get_htsf(dhd, 0); -+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { -+ if (ret == -EIO) { -+ DHD_ERROR(("%s: tsf is not supported by device\n", -+ dhd_ifname(&dhd->pub, ifidx))); -+ return -EOPNOTSUPP; -+ } -+ return ret; -+ } -+ s2 = dhd_get_htsf(dhd, 0); -+ -+ memcpy(&tsf_buf, buf, sizeof(tsf_buf)); -+ printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", -+ tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, -+ dhd->htsf.coefdec2, s2-tsf_buf.low); -+ printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); -+ return 0; -+} -+ -+void htsf_update(dhd_info_t *dhd, void *data) -+{ -+ static ulong cur_cycle = 0, prev_cycle = 0; -+ uint32 htsf, tsf_delta = 0; -+ uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; -+ ulong b, a; -+ cycles_t t; -+ -+ /* cycles_t in inlcude/mips/timex.h */ -+ -+ t = get_cycles(); -+ -+ prev_cycle = cur_cycle; -+ cur_cycle = t; -+ -+ if (cur_cycle > prev_cycle) -+ cyc_delta = cur_cycle - prev_cycle; -+ else { -+ b = cur_cycle; -+ a = prev_cycle; -+ cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); -+ } -+ -+ if (data == NULL) -+ printf(" tsf update ata point er is null \n"); -+ -+ memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); -+ memcpy(&cur_tsf, data, sizeof(tsf_t)); -+ -+ if (cur_tsf.low == 0) { -+ DHD_INFO((" ---- 0 TSF, do not update, return\n")); -+ return; -+ } -+ -+ if (cur_tsf.low > prev_tsf.low) -+ tsf_delta = (cur_tsf.low - prev_tsf.low); -+ else { -+ DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", -+ cur_tsf.low, prev_tsf.low)); -+ if (cur_tsf.high > prev_tsf.high) { -+ tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); -+ DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); -+ } -+ else -+ return; /* do not update */ -+ } -+ -+ if (tsf_delta) { -+ hfactor = cyc_delta / tsf_delta; -+ tmp = (cyc_delta - (hfactor * tsf_delta))*10; -+ dec1 = tmp/tsf_delta; -+ dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; -+ tmp = (tmp - (dec1*tsf_delta))*10; -+ dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; -+ -+ if (dec3 > 4) { -+ if (dec2 == 9) { -+ dec2 = 0; -+ if (dec1 == 9) { -+ dec1 = 0; -+ hfactor++; -+ } -+ else { -+ dec1++; -+ } -+ } -+ else -+ dec2++; -+ } -+ } -+ -+ if (hfactor) { -+ htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; -+ dhd->htsf.coef = hfactor; -+ dhd->htsf.last_cycle = cur_cycle; -+ dhd->htsf.last_tsf = cur_tsf.low; -+ dhd->htsf.coefdec1 = dec1; -+ dhd->htsf.coefdec2 = dec2; -+ } -+ else { -+ htsf = prev_tsf.low; -+ } -+} -+ -+#endif /* WLMEDIA_HTSF */ -diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c -new file mode 100644 -index 00000000..290caf7e ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c -@@ -0,0 +1,39 @@ -+/* -+ * Expose some of the kernel scheduler routines -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_linux_sched.c 291086 2011-10-21 01:17:24Z $ -+ */ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/sched.h> -+#include <typedefs.h> -+#include <linuxver.h> -+ -+int setScheduler(struct task_struct *p, int policy, struct sched_param *param) -+{ -+ int rc = 0; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+ rc = sched_setscheduler(p, policy, param); -+#endif /* LinuxVer */ -+ return rc; -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd/dhd_proto.h -new file mode 100644 -index 00000000..09d54680 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_proto.h -@@ -0,0 +1,113 @@ -+/* -+ * Header file describing the internal (inter-module) DHD interfaces. -+ * -+ * Provides type definitions and function prototypes used to link the -+ * DHD OS, bus, and protocol modules. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_proto.h 343390 2012-07-06 22:34:19Z $ -+ */ -+ -+#ifndef _dhd_proto_h_ -+#define _dhd_proto_h_ -+ -+#include <dhdioctl.h> -+#include <wlioctl.h> -+ -+#ifndef IOCTL_RESP_TIMEOUT -+#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */ -+#endif /* IOCTL_RESP_TIMEOUT */ -+ -+/* -+ * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) -+ */ -+ -+/* Linkage, sets prot link and updates hdrlen in pub */ -+extern int dhd_prot_attach(dhd_pub_t *dhdp); -+ -+/* Unlink, frees allocated protocol memory (including dhd_prot) */ -+extern void dhd_prot_detach(dhd_pub_t *dhdp); -+ -+/* Initialize protocol: sync w/dongle state. -+ * Sets dongle media info (iswl, drv_version, mac address). -+ */ -+extern int dhd_prot_init(dhd_pub_t *dhdp); -+ -+/* Stop protocol: sync w/dongle state. */ -+extern void dhd_prot_stop(dhd_pub_t *dhdp); -+#ifdef PROP_TXSTATUS -+extern int dhd_wlfc_init(dhd_pub_t *dhd); -+extern void dhd_wlfc_deinit(dhd_pub_t *dhd); -+#endif /* PROP_TXSTATUS */ -+ -+/* Add any protocol-specific data header. -+ * Caller must reserve prot_hdrlen prepend space. -+ */ -+extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); -+ -+/* Remove any protocol-specific data header. */ -+extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); -+ -+/* Use protocol to issue ioctl to dongle */ -+extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); -+ -+/* Handles a protocol control response asynchronously */ -+extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); -+ -+/* Check for and handle local prot-specific iovar commands */ -+extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, -+ void *params, int plen, void *arg, int len, bool set); -+ -+/* Add prot dump output to a buffer */ -+extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); -+ -+/* Update local copy of dongle statistics */ -+extern void dhd_prot_dstats(dhd_pub_t *dhdp); -+ -+extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); -+ -+extern int dhd_preinit_ioctls(dhd_pub_t *dhd); -+ -+#ifdef PROP_TXSTATUS -+extern int dhd_wlfc_enque_sendq(void* state, int prec, void* p); -+extern int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx); -+extern void dhd_wlfc_cleanup(dhd_pub_t *dhd); -+#endif /* PROP_TXSTATUS */ -+ -+extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, -+ uint reorder_info_len, void **pkt, uint32 *free_buf_count); -+ -+ -+/******************************** -+ * For version-string expansion * -+ */ -+#if defined(BDC) -+#define DHD_PROTOCOL "bdc" -+#elif defined(CDC) -+#define DHD_PROTOCOL "cdc" -+#elif defined(RNDIS) -+#define DHD_PROTOCOL "rndis" -+#else -+#define DHD_PROTOCOL "unknown" -+#endif /* proto */ -+ -+#endif /* _dhd_proto_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c -new file mode 100644 -index 00000000..c6342934 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c -@@ -0,0 +1,7694 @@ -+/* -+ * DHD Bus Module for SDIO -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_sdio.c 378263 2013-01-11 03:03:05Z $ -+ */ -+ -+#include <typedefs.h> -+#include <osl.h> -+#include <bcmsdh.h> -+ -+#ifdef BCMEMBEDIMAGE -+#include BCMEMBEDIMAGE -+#endif /* BCMEMBEDIMAGE */ -+ -+#include <bcmdefs.h> -+#include <bcmutils.h> -+#include <bcmendian.h> -+#include <bcmdevs.h> -+ -+#include <siutils.h> -+#include <hndpmu.h> -+#include <hndsoc.h> -+#include <bcmsdpcm.h> -+#if defined(DHD_DEBUG) -+#include <hndrte_armtrap.h> -+#include <hndrte_cons.h> -+#endif /* defined(DHD_DEBUG) */ -+#include <sbchipc.h> -+#include <sbhnddma.h> -+ -+#include <sdio.h> -+#include <sbsdio.h> -+#include <sbsdpcmdev.h> -+#include <bcmsdpcm.h> -+#include <bcmsdbus.h> -+ -+#include <proto/ethernet.h> -+#include <proto/802.1d.h> -+#include <proto/802.11.h> -+ -+#include <dngl_stats.h> -+#include <dhd.h> -+#include <dhd_bus.h> -+#include <dhd_proto.h> -+#include <dhd_dbg.h> -+#include <dhdioctl.h> -+#include <sdiovar.h> -+ -+#ifndef DHDSDIO_MEM_DUMP_FNAME -+#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" -+#endif -+ -+#define QLEN 256 /* bulk rx and tx queue lengths */ -+#define FCHI (QLEN - 10) -+#define FCLOW (FCHI / 2) -+#define PRIOMASK 7 -+ -+#define TXRETRIES 2 /* # of retries for tx frames */ -+ -+#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ -+ -+#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ -+ -+#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ -+ -+#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ -+#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */ -+#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */ -+ -+#ifndef DHD_FIRSTREAD -+#define DHD_FIRSTREAD 32 -+#endif -+#if !ISPOWEROF2(DHD_FIRSTREAD) -+#error DHD_FIRSTREAD is not a power of 2! -+#endif -+ -+#ifdef BCMSDIOH_TXGLOM -+/* Total length of TX frame header for dongle protocol */ -+#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN) -+/* Total length of RX frame for dongle protocol */ -+#else -+/* Total length of TX frame header for dongle protocol */ -+#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) -+#endif -+ -+#define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) -+ -+#ifdef SDTEST -+#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) -+#else -+#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) -+#endif -+ -+/* Space for header read, limit for data packets */ -+#ifndef MAX_HDR_READ -+#define MAX_HDR_READ 32 -+#endif -+#if !ISPOWEROF2(MAX_HDR_READ) -+#error MAX_HDR_READ is not a power of 2! -+#endif -+ -+#define MAX_RX_DATASZ 2048 -+ -+/* Maximum milliseconds to wait for F2 to come up */ -+#define DHD_WAIT_F2RDY 3000 -+ -+/* Bump up limit on waiting for HT to account for first startup; -+ * if the image is doing a CRC calculation before programming the PMU -+ * for HT availability, it could take a couple hundred ms more, so -+ * max out at a 1 second (1000000us). -+ */ -+#if (PMU_MAX_TRANSITION_DLY <= 1000000) -+#undef PMU_MAX_TRANSITION_DLY -+#define PMU_MAX_TRANSITION_DLY 1000000 -+#endif -+ -+/* Value for ChipClockCSR during initial setup */ -+#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) -+#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) -+ -+/* Flags for SDH calls */ -+#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) -+ -+/* Packet free applicable unconditionally for sdio and sdspi. Conditional if -+ * bufpool was present for gspi bus. -+ */ -+#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ -+ PKTFREE(bus->dhd->osh, pkt, FALSE); -+DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); -+#if defined(OOB_INTR_ONLY) -+extern void bcmsdh_set_irq(int flag); -+#endif /* defined(OOB_INTR_ONLY) */ -+#ifdef PROP_TXSTATUS -+extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); -+extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd); -+#endif -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+DEFINE_MUTEX(_dhd_sdio_mutex_lock_); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -+ -+#ifdef DHD_DEBUG -+/* Device console log buffer state */ -+#define CONSOLE_LINE_MAX 192 -+#define CONSOLE_BUFFER_MAX 2024 -+typedef struct dhd_console { -+ uint count; /* Poll interval msec counter */ -+ uint log_addr; /* Log struct address (fixed) */ -+ hndrte_log_t log; /* Log struct (host copy) */ -+ uint bufsize; /* Size of log buffer */ -+ uint8 *buf; /* Log buffer (host copy) */ -+ uint last; /* Last buffer read index */ -+} dhd_console_t; -+#endif /* DHD_DEBUG */ -+ -+#define REMAP_ENAB(bus) ((bus)->remap) -+#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) -+#define KSO_ENAB(bus) ((bus)->kso) -+#define SR_ENAB(bus) ((bus)->_srenab) -+#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) -+#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) -+#define MIN_RSRC_SR 0x3 -+#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) -+#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) -+#define RCTL_MACPHY_DISABLE_MASK (1 << 26) -+#define RCTL_LOGIC_DISABLE_MASK (1 << 27) -+ -+#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) -+#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ -+#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ -+#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ -+#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) -+ -+#define CC_PMUCC3 (0x3) -+/* Private data for SDIO bus interaction */ -+typedef struct dhd_bus { -+ dhd_pub_t *dhd; -+ -+ bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ -+ si_t *sih; /* Handle for SI calls */ -+ char *vars; /* Variables (from CIS and/or other) */ -+ uint varsz; /* Size of variables buffer */ -+ uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ -+ -+ sdpcmd_regs_t *regs; /* Registers for SDIO core */ -+ uint sdpcmrev; /* SDIO core revision */ -+ uint armrev; /* CPU core revision */ -+ uint ramrev; /* SOCRAM core revision */ -+ uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ -+ uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ -+ uint32 srmemsize; /* Size of SRMEM */ -+ -+ uint32 bus; /* gSPI or SDIO bus */ -+ uint32 hostintmask; /* Copy of Host Interrupt Mask */ -+ uint32 intstatus; /* Intstatus bits (events) pending */ -+ bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ -+ bool fcstate; /* State of dongle flow-control */ -+ -+ uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ -+ char *fw_path; /* module_param: path to firmware image */ -+ char *nv_path; /* module_param: path to nvram vars file */ -+ const char *nvram_params; /* user specified nvram params. */ -+ -+ uint blocksize; /* Block size of SDIO transfers */ -+ uint roundup; /* Max roundup limit */ -+ -+ struct pktq txq; /* Queue length used for flow-control */ -+ uint8 flowcontrol; /* per prio flow control bitmask */ -+ uint8 tx_seq; /* Transmit sequence number (next) */ -+ uint8 tx_max; /* Maximum transmit sequence allowed */ -+ -+ uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; -+ uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ -+ uint16 nextlen; /* Next Read Len from last header */ -+ uint8 rx_seq; /* Receive sequence number (expected) */ -+ bool rxskip; /* Skip receive (awaiting NAK ACK) */ -+ -+ void *glomd; /* Packet containing glomming descriptor */ -+ void *glom; /* Packet chain for glommed superframe */ -+ uint glomerr; /* Glom packet read errors */ -+ -+ uint8 *rxbuf; /* Buffer for receiving control packets */ -+ uint rxblen; /* Allocated length of rxbuf */ -+ uint8 *rxctl; /* Aligned pointer into rxbuf */ -+ uint8 *databuf; /* Buffer for receiving big glom packet */ -+ uint8 *dataptr; /* Aligned pointer into databuf */ -+ uint rxlen; /* Length of valid data in buffer */ -+ -+ uint8 sdpcm_ver; /* Bus protocol reported by dongle */ -+ -+ bool intr; /* Use interrupts */ -+ bool poll; /* Use polling */ -+ bool ipend; /* Device interrupt is pending */ -+ bool intdis; /* Interrupts disabled by isr */ -+ uint intrcount; /* Count of device interrupt callbacks */ -+ uint lastintrs; /* Count as of last watchdog timer */ -+ uint spurious; /* Count of spurious interrupts */ -+ uint pollrate; /* Ticks between device polls */ -+ uint polltick; /* Tick counter */ -+ uint pollcnt; /* Count of active polls */ -+ -+#ifdef DHD_DEBUG -+ dhd_console_t console; /* Console output polling support */ -+ uint console_addr; /* Console address from shared struct */ -+#endif /* DHD_DEBUG */ -+ -+ uint regfails; /* Count of R_REG/W_REG failures */ -+ -+ uint clkstate; /* State of sd and backplane clock(s) */ -+ bool activity; /* Activity flag for clock down */ -+ int32 idletime; /* Control for activity timeout */ -+ int32 idlecount; /* Activity timeout counter */ -+ int32 idleclock; /* How to set bus driver when idle */ -+ int32 sd_divisor; /* Speed control to bus driver */ -+ int32 sd_mode; /* Mode control to bus driver */ -+ int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ -+ bool use_rxchain; /* If dhd should use PKT chains */ -+ bool sleeping; /* Is SDIO bus sleeping? */ -+ uint rxflow_mode; /* Rx flow control mode */ -+ bool rxflow; /* Is rx flow control on */ -+ uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ -+ bool alp_only; /* Don't use HT clock (ALP only) */ -+ /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ -+ bool usebufpool; -+ -+#ifdef SDTEST -+ /* external loopback */ -+ bool ext_loop; -+ uint8 loopid; -+ -+ /* pktgen configuration */ -+ uint pktgen_freq; /* Ticks between bursts */ -+ uint pktgen_count; /* Packets to send each burst */ -+ uint pktgen_print; /* Bursts between count displays */ -+ uint pktgen_total; /* Stop after this many */ -+ uint pktgen_minlen; /* Minimum packet data len */ -+ uint pktgen_maxlen; /* Maximum packet data len */ -+ uint pktgen_mode; /* Configured mode: tx, rx, or echo */ -+ uint pktgen_stop; /* Number of tx failures causing stop */ -+ -+ /* active pktgen fields */ -+ uint pktgen_tick; /* Tick counter for bursts */ -+ uint pktgen_ptick; /* Burst counter for printing */ -+ uint pktgen_sent; /* Number of test packets generated */ -+ uint pktgen_rcvd; /* Number of test packets received */ -+ uint pktgen_prev_time; /* Time at which previous stats where printed */ -+ uint pktgen_prev_sent; /* Number of test packets generated when -+ * previous stats were printed -+ */ -+ uint pktgen_prev_rcvd; /* Number of test packets received when -+ * previous stats were printed -+ */ -+ uint pktgen_fail; /* Number of failed send attempts */ -+ uint16 pktgen_len; /* Length of next packet to send */ -+#define PKTGEN_RCV_IDLE (0) -+#define PKTGEN_RCV_ONGOING (1) -+ uint16 pktgen_rcv_state; /* receive state */ -+ uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ -+#endif /* SDTEST */ -+ -+ /* Some additional counters */ -+ uint tx_sderrs; /* Count of tx attempts with sd errors */ -+ uint fcqueued; /* Tx packets that got queued */ -+ uint rxrtx; /* Count of rtx requests (NAK to dongle) */ -+ uint rx_toolong; /* Receive frames too long to receive */ -+ uint rxc_errors; /* SDIO errors when reading control frames */ -+ uint rx_hdrfail; /* SDIO errors on header reads */ -+ uint rx_badhdr; /* Bad received headers (roosync?) */ -+ uint rx_badseq; /* Mismatched rx sequence number */ -+ uint fc_rcvd; /* Number of flow-control events received */ -+ uint fc_xoff; /* Number which turned on flow-control */ -+ uint fc_xon; /* Number which turned off flow-control */ -+ uint rxglomfail; /* Failed deglom attempts */ -+ uint rxglomframes; /* Number of glom frames (superframes) */ -+ uint rxglompkts; /* Number of packets from glom frames */ -+ uint f2rxhdrs; /* Number of header reads */ -+ uint f2rxdata; /* Number of frame data reads */ -+ uint f2txdata; /* Number of f2 frame writes */ -+ uint f1regdata; /* Number of f1 register accesses */ -+ -+ uint8 *ctrl_frame_buf; -+ uint32 ctrl_frame_len; -+ bool ctrl_frame_stat; -+ uint32 rxint_mode; /* rx interrupt mode */ -+ bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram -+ * Available with socram rev 16 -+ * Remap region not DMA-able -+ */ -+ bool kso; -+ bool _slpauto; -+ bool _oobwakeup; -+ bool _srenab; -+ bool readframes; -+ bool reqbussleep; -+ uint32 resetinstr; -+ uint32 dongle_ram_base; -+#ifdef BCMSDIOH_TXGLOM -+ void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ -+ uint16 glom_cnt; /* Number of pkts in the glom array */ -+ uint16 glom_total_len; /* Total length of pkts in glom array */ -+ bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ -+ uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */ -+ uint32 glomsize; /* Glom size limitation */ -+#endif -+} dhd_bus_t; -+ -+/* clkstate */ -+#define CLK_NONE 0 -+#define CLK_SDONLY 1 -+#define CLK_PENDING 2 /* Not used yet */ -+#define CLK_AVAIL 3 -+ -+#define DHD_NOPMU(dhd) (FALSE) -+ -+#ifdef DHD_DEBUG -+static int qcount[NUMPRIO]; -+static int tx_packets[NUMPRIO]; -+#endif /* DHD_DEBUG */ -+ -+/* Deferred transmit */ -+const uint dhd_deferred_tx = 1; -+ -+extern uint dhd_watchdog_ms; -+extern void dhd_os_wd_timer(void *bus, uint wdtick); -+ -+/* Tx/Rx bounds */ -+uint dhd_txbound; -+uint dhd_rxbound; -+uint dhd_txminmax = DHD_TXMINMAX; -+ -+/* override the RAM size if possible */ -+#define DONGLE_MIN_MEMSIZE (128 *1024) -+int dhd_dongle_memsize; -+ -+uint dhd_doflow = TRUE; -+uint dhd_dpcpoll = FALSE; -+static bool dhd_alignctl; -+ -+static bool sd1idle; -+ -+static bool retrydata; -+#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) -+ -+#if defined(SDIO_CRC_ERROR_FIX) -+static uint watermark = 48; -+static uint mesbusyctrl = 80; -+#else -+static const uint watermark = 8; -+static const uint mesbusyctrl = 0; -+#endif -+static const uint firstread = DHD_FIRSTREAD; -+ -+#define HDATLEN (firstread - (SDPCM_HDRLEN)) -+ -+/* Retry count for register access failures */ -+static const uint retry_limit = 2; -+ -+/* Force even SD lengths (some host controllers mess up on odd bytes) */ -+static bool forcealign; -+ -+#define ALIGNMENT 4 -+ -+#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -+extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); -+#endif -+ -+#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) -+#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD -+#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ -+#define PKTALIGN(osh, p, len, align) \ -+ do { \ -+ uint datalign; \ -+ datalign = (uintptr)PKTDATA((osh), (p)); \ -+ datalign = ROUNDUP(datalign, (align)) - datalign; \ -+ ASSERT(datalign < (align)); \ -+ ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ -+ if (datalign) \ -+ PKTPULL((osh), (p), datalign); \ -+ PKTSETLEN((osh), (p), (len)); \ -+ } while (0) -+ -+/* Limit on rounding up frames */ -+static const uint max_roundup = 512; -+ -+/* Try doing readahead */ -+static bool dhd_readahead; -+ -+ -+/* To check if there's window offered */ -+#define DATAOK(bus) \ -+ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ -+ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) -+ -+/* To check if there's window offered for ctrl frame */ -+#define TXCTLOK(bus) \ -+ (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ -+ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) -+ -+/* Number of pkts available in dongle for data RX */ -+#define DATABUFCNT(bus) \ -+ ((uint8)(bus->tx_max - bus->tx_seq) - 1) -+ -+/* Macros to get register read/write status */ -+/* NOTE: these assume a local dhdsdio_bus_t *bus! */ -+#define R_SDREG(regvar, regaddr, retryvar) \ -+do { \ -+ retryvar = 0; \ -+ do { \ -+ regvar = R_REG(bus->dhd->osh, regaddr); \ -+ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ -+ if (retryvar) { \ -+ bus->regfails += (retryvar-1); \ -+ if (retryvar > retry_limit) { \ -+ DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ -+ __FUNCTION__, __LINE__)); \ -+ regvar = 0; \ -+ } \ -+ } \ -+} while (0) -+ -+#define W_SDREG(regval, regaddr, retryvar) \ -+do { \ -+ retryvar = 0; \ -+ do { \ -+ W_REG(bus->dhd->osh, regaddr, regval); \ -+ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ -+ if (retryvar) { \ -+ bus->regfails += (retryvar-1); \ -+ if (retryvar > retry_limit) \ -+ DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ -+ __FUNCTION__, __LINE__)); \ -+ } \ -+} while (0) -+ -+#define BUS_WAKE(bus) \ -+ do { \ -+ bus->idlecount = 0; \ -+ if ((bus)->sleeping) \ -+ dhdsdio_bussleep((bus), FALSE); \ -+ } while (0); -+ -+/* -+ * pktavail interrupts from dongle to host can be managed in 3 different ways -+ * whenever there is a packet available in dongle to transmit to host. -+ * -+ * Mode 0: Dongle writes the software host mailbox and host is interrupted. -+ * Mode 1: (sdiod core rev >= 4) -+ * Device sets a new bit in the intstatus whenever there is a packet -+ * available in fifo. Host can't clear this specific status bit until all the -+ * packets are read from the FIFO. No need to ack dongle intstatus. -+ * Mode 2: (sdiod core rev >= 4) -+ * Device sets a bit in the intstatus, and host acks this by writing -+ * one to this bit. Dongle won't generate anymore packet interrupts -+ * until host reads all the packets from the dongle and reads a zero to -+ * figure that there are no more packets. No need to disable host ints. -+ * Need to ack the intstatus. -+ */ -+ -+#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ -+#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ -+#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ -+ -+ -+#define FRAME_AVAIL_MASK(bus) \ -+ ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) -+ -+#define DHD_BUS SDIO_BUS -+ -+#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) -+ -+#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) -+ -+#define GSPI_PR55150_BAILOUT -+ -+#ifdef SDTEST -+static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); -+static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); -+#endif -+ -+#ifdef DHD_DEBUG -+static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); -+static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); -+#endif /* DHD_DEBUG */ -+ -+static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); -+static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); -+ -+static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); -+static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); -+static void dhdsdio_disconnect(void *ptr); -+static bool dhdsdio_chipmatch(uint16 chipid); -+static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, -+ void * regsva, uint16 devid); -+static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); -+static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -+static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, -+ bool reset_flag); -+ -+static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); -+static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, -+ uint8 *buf, uint nbytes, -+ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); -+static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, -+ uint8 *buf, uint nbytes, -+ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); -+#ifdef BCMSDIOH_TXGLOM -+static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len); -+static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus); -+#endif -+ -+static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); -+static int _dhdsdio_download_firmware(dhd_bus_t *bus); -+ -+static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); -+static int dhdsdio_download_nvram(dhd_bus_t *bus); -+#ifdef BCMEMBEDIMAGE -+static int dhdsdio_download_code_array(dhd_bus_t *bus); -+#endif -+static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); -+static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); -+static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); -+ -+#ifdef WLMEDIA_HTSF -+#include <htsf.h> -+extern uint32 dhd_get_htsf(void *dhd, int ifidx); -+#endif /* WLMEDIA_HTSF */ -+ -+static void -+dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) -+{ -+ int32 min_size = DONGLE_MIN_MEMSIZE; -+ /* Restrict the memsize to user specified limit */ -+ DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", -+ dhd_dongle_memsize, min_size)); -+ if ((dhd_dongle_memsize > min_size) && -+ (dhd_dongle_memsize < (int32)bus->orig_ramsize)) -+ bus->ramsize = dhd_dongle_memsize; -+} -+ -+static int -+dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) -+{ -+ int err = 0; -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, -+ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); -+ if (!err) -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, -+ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); -+ if (!err) -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, -+ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); -+ return err; -+} -+ -+ -+#ifdef USE_OOB_GPIO1 -+static int -+dhdsdio_oobwakeup_init(dhd_bus_t *bus) -+{ -+ uint32 val, addr, data; -+ -+ bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); -+ -+ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); -+ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); -+ -+ /* Set device for gpio1 wakeup */ -+ bcmsdh_reg_write(bus->sdh, addr, 4, 2); -+ val = bcmsdh_reg_read(bus->sdh, data, 4); -+ val |= CC_CHIPCTRL2_GPIO1_WAKEUP; -+ bcmsdh_reg_write(bus->sdh, data, 4, val); -+ -+ bus->_oobwakeup = TRUE; -+ -+ return 0; -+} -+#endif /* USE_OOB_GPIO1 */ -+ -+/* -+ * Query if FW is in SR mode -+ */ -+static bool -+dhdsdio_sr_cap(dhd_bus_t *bus) -+{ -+ bool cap = FALSE; -+ uint32 min = 0, core_capext, addr, data; -+ if (bus->sih->chip == BCM4324_CHIP_ID) { -+ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); -+ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); -+ bcmsdh_reg_write(bus->sdh, addr, 4, 3); -+ core_capext = bcmsdh_reg_read(bus->sdh, data, 4); -+ } else if (bus->sih->chip == BCM4330_CHIP_ID) { -+ core_capext = FALSE; -+ } else if (bus->sih->chip == BCM4335_CHIP_ID) { -+ core_capext = TRUE; -+ } else { -+ core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); -+ core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); -+ } -+ if (!(core_capext)) -+ return FALSE; -+ -+ if (bus->sih->chip == BCM4324_CHIP_ID) { -+ /* FIX: Should change to query SR control register instead */ -+ min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); -+ if (min == MIN_RSRC_SR) -+ cap = TRUE; -+ } else if (bus->sih->chip == BCM4335_CHIP_ID) { -+ uint32 enabval = 0; -+ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); -+ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); -+ bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); -+ enabval = bcmsdh_reg_read(bus->sdh, data, 4); -+ -+ if (enabval) -+ cap = TRUE; -+ } else { -+ data = bcmsdh_reg_read(bus->sdh, -+ SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); -+ if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) -+ cap = TRUE; -+ } -+ -+ return cap; -+} -+ -+static int -+dhdsdio_srwar_init(dhd_bus_t *bus) -+{ -+ -+ bcmsdh_gpio_init(bus->sdh); -+ -+#ifdef USE_OOB_GPIO1 -+ dhdsdio_oobwakeup_init(bus); -+#endif -+ -+ -+ return 0; -+} -+ -+static int -+dhdsdio_sr_init(dhd_bus_t *bus) -+{ -+ uint8 val; -+ int err = 0; -+ -+ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) -+ dhdsdio_srwar_init(bus); -+ -+ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); -+ val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, -+ 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); -+ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); -+ -+ /* Add CMD14 Support */ -+ dhdsdio_devcap_set(bus, -+ (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); -+ -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); -+ -+ bus->_slpauto = dhd_slpauto ? TRUE : FALSE; -+ -+ bus->_srenab = TRUE; -+ -+ return 0; -+} -+ -+/* -+ * FIX: Be sure KSO bit is enabled -+ * Currently, it's defaulting to 0 which should be 1. -+ */ -+static int -+dhdsdio_clk_kso_init(dhd_bus_t *bus) -+{ -+ uint8 val; -+ int err = 0; -+ -+ /* set flag */ -+ bus->kso = TRUE; -+ -+ /* -+ * Enable KeepSdioOn (KSO) bit for normal operation -+ * Default is 0 (4334A0) so set it. Fixed in B0. -+ */ -+ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); -+ if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { -+ val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); -+ if (err) -+ DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err)); -+ } -+ -+ return 0; -+} -+ -+#define KSO_DBG(x) -+#define MAX_KSO_ATTEMPTS 64 -+static int -+dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) -+{ -+ uint8 wr_val = 0, rd_val, cmp_val, bmask; -+ int err = 0; -+ int try_cnt = 0; -+ -+ KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); -+ -+ wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); -+ -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); -+ -+ if (on) { -+ cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; -+ bmask = cmp_val; -+ -+ msleep(3); -+ -+ } else { -+ /* Put device to sleep, turn off KSO */ -+ cmp_val = 0; -+ bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; -+ } -+ -+ do { -+ rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); -+ if (((rd_val & bmask) == cmp_val) && !err) -+ break; -+ -+ KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); -+ OSL_DELAY(50); -+ -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); -+ -+ } while (try_cnt++ < MAX_KSO_ATTEMPTS); -+ -+ -+ if (try_cnt > 1) { -+ KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", -+ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); -+ } -+ -+ if (try_cnt > MAX_KSO_ATTEMPTS) { -+ DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", -+ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); -+ } -+ return err; -+} -+ -+static int -+dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) -+{ -+ int err = 0; -+ -+ if (on == FALSE) { -+ -+ BUS_WAKE(bus); -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__, -+ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, &err))); -+ dhdsdio_clk_kso_enab(bus, FALSE); -+ } else { -+ DHD_ERROR(("%s: KSO enable\n", __FUNCTION__)); -+ -+ /* Make sure we have SD bus access */ -+ if (bus->clkstate == CLK_NONE) { -+ DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); -+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -+ } -+ -+ /* Double-write to be safe in case transition of AOS */ -+ dhdsdio_clk_kso_enab(bus, TRUE); -+ dhdsdio_clk_kso_enab(bus, TRUE); -+ OSL_DELAY(4000); -+ -+ /* Wait for device ready during transition to wake-up */ -+ SPINWAIT(((dhdsdio_sleepcsr_get(bus)) != -+ (SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | -+ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), -+ (10000)); -+ -+ DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, -+ dhdsdio_sleepcsr_get(bus))); -+ } -+ -+ bus->kso = on; -+ BCM_REFERENCE(err); -+ -+ return 0; -+} -+ -+static uint8 -+dhdsdio_sleepcsr_get(dhd_bus_t *bus) -+{ -+ int err = 0; -+ uint8 val = 0; -+ -+ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); -+ if (err) -+ DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err)); -+ -+ return val; -+} -+ -+uint8 -+dhdsdio_devcap_get(dhd_bus_t *bus) -+{ -+ return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); -+} -+ -+static int -+dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) -+{ -+ int err = 0; -+ -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); -+ if (err) -+ DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err)); -+ -+ return 0; -+} -+ -+static int -+dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) -+{ -+ int err = 0, retry; -+ uint8 val; -+ -+ retry = 0; -+ if (on == TRUE) { -+ /* Enter Sleep */ -+ -+ /* Be sure we request clk before going to sleep -+ * so we can wake-up with clk request already set -+ * else device can go back to sleep immediately -+ */ -+ if (!SLPAUTO_ENAB(bus)) -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ else { -+ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); -+ if ((val & SBSDIO_CSR_MASK) == 0) { -+ DHD_ERROR(("%s: No clock before enter sleep:0x%x\n", -+ __FUNCTION__, val)); -+ -+ /* Reset clock request */ -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, -+ SBSDIO_ALP_AVAIL_REQ, &err); -+ DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__, -+ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, &err))); -+ } -+ } -+ -+ DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, -+ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, &err))); -+#ifdef USE_CMD14 -+ err = bcmsdh_sleep(bus->sdh, TRUE); -+#else -+ err = dhdsdio_clk_kso_enab(bus, FALSE); -+ if (OOB_WAKEUP_ENAB(bus)) -+ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ -+#endif -+ } else { -+ /* Exit Sleep */ -+ /* Make sure we have SD bus access */ -+ if (bus->clkstate == CLK_NONE) { -+ DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__)); -+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -+ } -+ -+ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { -+ SPINWAIT((bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), -+ GPIO_DEV_SRSTATE_TIMEOUT); -+ -+ if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { -+ DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); -+ } -+ } -+#ifdef USE_CMD14 -+ err = bcmsdh_sleep(bus->sdh, FALSE); -+ if (SLPAUTO_ENAB(bus) && (err != 0)) { -+ OSL_DELAY(10000); -+ DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); -+ -+ /* Toggle sleep to resync with host and device */ -+ err = bcmsdh_sleep(bus->sdh, TRUE); -+ OSL_DELAY(10000); -+ err = bcmsdh_sleep(bus->sdh, FALSE); -+ -+ if (err) { -+ OSL_DELAY(10000); -+ DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); -+ -+ /* Toggle sleep to resync with host and device */ -+ err = bcmsdh_sleep(bus->sdh, TRUE); -+ OSL_DELAY(10000); -+ err = bcmsdh_sleep(bus->sdh, FALSE); -+ if (err) { -+ DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); -+ DHD_ERROR(("%s: FATAL: Device non-response!\n", -+ __FUNCTION__)); -+ err = 0; -+ } -+ } -+ } -+#else -+ if (OOB_WAKEUP_ENAB(bus)) -+ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ -+ -+ do { -+ err = dhdsdio_clk_kso_enab(bus, TRUE); -+ if (err) -+ OSL_DELAY(10000); -+ } while ((err != 0) && (++retry < 3)); -+ -+ if (err != 0) { -+ DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); -+ err = 0; /* continue anyway */ -+ } -+#endif /* !USE_CMD14 */ -+ -+ if (err == 0) { -+ uint8 csr; -+ -+ /* Wait for device ready during transition to wake-up */ -+ SPINWAIT((((csr = dhdsdio_sleepcsr_get(bus)) & -+ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != -+ (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); -+ -+ DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); -+ -+ if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { -+ DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", -+ __FUNCTION__, csr)); -+ err = BCME_NODEVICE; -+ } -+ -+ SPINWAIT((((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != -+ (SBSDIO_HT_AVAIL)), (10000)); -+ -+ } -+ } -+ -+ /* Update if successful */ -+ if (err == 0) -+ bus->kso = on ? FALSE : TRUE; -+ else { -+ DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err)); -+ if (!on && retry > 2) -+ bus->kso = TRUE; -+ } -+ -+ return err; -+} -+ -+/* Turn backplane clock on or off */ -+static int -+dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) -+{ -+#define HT_AVAIL_ERROR_MAX 10 -+ static int ht_avail_error = 0; -+ int err; -+ uint8 clkctl, clkreq, devctl; -+ bcmsdh_info_t *sdh; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+#if defined(OOB_INTR_ONLY) -+ pendok = FALSE; -+#endif /* defined(OOB_INTR_ONLY) */ -+ clkctl = 0; -+ sdh = bus->sdh; -+ -+ -+ if (!KSO_ENAB(bus)) -+ return BCME_OK; -+ -+ if (SLPAUTO_ENAB(bus)) { -+ bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); -+ return BCME_OK; -+ } -+ -+ if (on) { -+ /* Request HT Avail */ -+ clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; -+ -+ -+ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); -+ if (err) { -+ ht_avail_error++; -+ if (ht_avail_error < HT_AVAIL_ERROR_MAX) { -+ DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); -+ } -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) -+ else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { -+ dhd_os_send_hang_message(bus->dhd); -+ } -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ -+ return BCME_ERROR; -+ } else { -+ ht_avail_error = 0; -+ } -+ -+ if (pendok && -+ ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) { -+ uint32 dummy, retries; -+ R_SDREG(dummy, &bus->regs->clockctlstatus, retries); -+ BCM_REFERENCE(dummy); -+ } -+ -+ /* Check current status */ -+ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); -+ if (err) { -+ DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ -+ /* Go to pending and await interrupt if appropriate */ -+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { -+ /* Allow only clock-available interrupt */ -+ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); -+ if (err) { -+ DHD_ERROR(("%s: Devctl access error setting CA: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ -+ devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); -+ DHD_INFO(("CLKCTL: set PENDING\n")); -+ bus->clkstate = CLK_PENDING; -+ return BCME_OK; -+ } else if (bus->clkstate == CLK_PENDING) { -+ /* Cancel CA-only interrupt filter */ -+ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); -+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); -+ } -+ -+ /* Otherwise, wait here (polling) for HT Avail */ -+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { -+ SPINWAIT_SLEEP(sdioh_spinwait_sleep, -+ ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, &err)), -+ !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); -+ } -+ if (err) { -+ DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { -+ DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", -+ __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); -+ return BCME_ERROR; -+ } -+ -+ /* Mark clock available */ -+ bus->clkstate = CLK_AVAIL; -+ DHD_INFO(("CLKCTL: turned ON\n")); -+ -+#if defined(DHD_DEBUG) -+ if (bus->alp_only == TRUE) { -+#if !defined(BCMLXSDMMC) -+ if (!SBSDIO_ALPONLY(clkctl)) { -+ DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); -+ } -+#endif /* !defined(BCMLXSDMMC) */ -+ } else { -+ if (SBSDIO_ALPONLY(clkctl)) { -+ DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); -+ } -+ } -+#endif /* defined (DHD_DEBUG) */ -+ -+ bus->activity = TRUE; -+#ifdef DHD_USE_IDLECOUNT -+ bus->idlecount = 0; -+#endif /* DHD_USE_IDLECOUNT */ -+ } else { -+ clkreq = 0; -+ if (bus->clkstate == CLK_PENDING) { -+ /* Cancel CA-only interrupt filter */ -+ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); -+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); -+ } -+ -+ bus->clkstate = CLK_SDONLY; -+ if (!SR_ENAB(bus)) { -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); -+ DHD_INFO(("CLKCTL: turned OFF\n")); -+ if (err) { -+ DHD_ERROR(("%s: Failed access turning clock off: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ } -+ } -+ return BCME_OK; -+} -+ -+/* Change idle/active SD state */ -+static int -+dhdsdio_sdclk(dhd_bus_t *bus, bool on) -+{ -+ int err; -+ int32 iovalue; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (on) { -+ if (bus->idleclock == DHD_IDLE_STOP) { -+ /* Turn on clock and restore mode */ -+ iovalue = 1; -+ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, -+ &iovalue, sizeof(iovalue), TRUE); -+ if (err) { -+ DHD_ERROR(("%s: error enabling sd_clock: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ -+ iovalue = bus->sd_mode; -+ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, -+ &iovalue, sizeof(iovalue), TRUE); -+ if (err) { -+ DHD_ERROR(("%s: error changing sd_mode: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { -+ /* Restore clock speed */ -+ iovalue = bus->sd_divisor; -+ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, -+ &iovalue, sizeof(iovalue), TRUE); -+ if (err) { -+ DHD_ERROR(("%s: error restoring sd_divisor: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ } -+ bus->clkstate = CLK_SDONLY; -+ } else { -+ /* Stop or slow the SD clock itself */ -+ if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { -+ DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", -+ __FUNCTION__, bus->sd_divisor, bus->sd_mode)); -+ return BCME_ERROR; -+ } -+ if (bus->idleclock == DHD_IDLE_STOP) { -+ if (sd1idle) { -+ /* Change to SD1 mode and turn off clock */ -+ iovalue = 1; -+ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, -+ &iovalue, sizeof(iovalue), TRUE); -+ if (err) { -+ DHD_ERROR(("%s: error changing sd_clock: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ } -+ -+ iovalue = 0; -+ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, -+ &iovalue, sizeof(iovalue), TRUE); -+ if (err) { -+ DHD_ERROR(("%s: error disabling sd_clock: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { -+ /* Set divisor to idle value */ -+ iovalue = bus->idleclock; -+ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, -+ &iovalue, sizeof(iovalue), TRUE); -+ if (err) { -+ DHD_ERROR(("%s: error changing sd_divisor: %d\n", -+ __FUNCTION__, err)); -+ return BCME_ERROR; -+ } -+ } -+ bus->clkstate = CLK_NONE; -+ } -+ -+ return BCME_OK; -+} -+ -+/* Transition SD and backplane clock readiness */ -+static int -+dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) -+{ -+ int ret = BCME_OK; -+#ifdef DHD_DEBUG -+ uint oldstate = bus->clkstate; -+#endif /* DHD_DEBUG */ -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ /* Early exit if we're already there */ -+ if (bus->clkstate == target) { -+ if (target == CLK_AVAIL) { -+ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); -+ bus->activity = TRUE; -+#ifdef DHD_USE_IDLECOUNT -+ bus->idlecount = 0; -+#endif /* DHD_USE_IDLECOUNT */ -+ } -+ return ret; -+ } -+ -+ switch (target) { -+ case CLK_AVAIL: -+ /* Make sure SD clock is available */ -+ if (bus->clkstate == CLK_NONE) -+ dhdsdio_sdclk(bus, TRUE); -+ /* Now request HT Avail on the backplane */ -+ ret = dhdsdio_htclk(bus, TRUE, pendok); -+ if (ret == BCME_OK) { -+ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); -+ bus->activity = TRUE; -+#ifdef DHD_USE_IDLECOUNT -+ bus->idlecount = 0; -+#endif /* DHD_USE_IDLECOUNT */ -+ } -+ break; -+ -+ case CLK_SDONLY: -+ /* Remove HT request, or bring up SD clock */ -+ if (bus->clkstate == CLK_NONE) -+ ret = dhdsdio_sdclk(bus, TRUE); -+ else if (bus->clkstate == CLK_AVAIL) -+ ret = dhdsdio_htclk(bus, FALSE, FALSE); -+ else -+ DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", -+ bus->clkstate, target)); -+ if (ret == BCME_OK) { -+ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); -+ } -+ break; -+ -+ case CLK_NONE: -+ /* Make sure to remove HT request */ -+ if (bus->clkstate == CLK_AVAIL) -+ ret = dhdsdio_htclk(bus, FALSE, FALSE); -+ /* Now remove the SD clock */ -+ ret = dhdsdio_sdclk(bus, FALSE); -+#ifdef DHD_DEBUG -+ if (dhd_console_ms == 0) -+#endif /* DHD_DEBUG */ -+ if (bus->poll == 0) -+ dhd_os_wd_timer(bus->dhd, 0); -+ break; -+ } -+#ifdef DHD_DEBUG -+ DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); -+#endif /* DHD_DEBUG */ -+ -+ return ret; -+} -+ -+static int -+dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) -+{ -+ int err = 0; -+ bcmsdh_info_t *sdh = bus->sdh; -+ sdpcmd_regs_t *regs = bus->regs; -+ uint retries = 0; -+ -+ DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", -+ (sleep ? "SLEEP" : "WAKE"), -+ (bus->sleeping ? "SLEEP" : "WAKE"))); -+ -+ /* Done if we're already in the requested state */ -+ if (sleep == bus->sleeping) -+ return BCME_OK; -+ -+ /* Going to sleep: set the alarm and turn off the lights... */ -+ if (sleep) { -+ /* Don't sleep if something is pending */ -+ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) -+ return BCME_BUSY; -+ -+ -+ if (!SLPAUTO_ENAB(bus)) { -+ /* Disable SDIO interrupts (no longer interested) */ -+ bcmsdh_intr_disable(bus->sdh); -+ -+ /* Make sure the controller has the bus up */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ /* Tell device to start using OOB wakeup */ -+ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); -+ if (retries > retry_limit) -+ DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); -+ -+ /* Turn off our contribution to the HT clock request */ -+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -+ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, -+ SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); -+ -+ /* Isolate the bus */ -+ if (bus->sih->chip != BCM4329_CHIP_ID && -+ bus->sih->chip != BCM4319_CHIP_ID) { -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, -+ SBSDIO_DEVCTL_PADS_ISO, NULL); -+ } -+ } else { -+ /* Leave interrupts enabled since device can exit sleep and -+ * interrupt host -+ */ -+ err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); -+ } -+ -+ /* Change state */ -+ bus->sleeping = TRUE; -+ -+ } else { -+ /* Waking up: bus power up is ok, set local state */ -+ -+ if (!SLPAUTO_ENAB(bus)) { -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); -+ -+ /* Force pad isolation off if possible (in case power never toggled) */ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); -+ -+ -+ /* Make sure the controller has the bus up */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ /* Send misc interrupt to indicate OOB not needed */ -+ W_SDREG(0, ®s->tosbmailboxdata, retries); -+ if (retries <= retry_limit) -+ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); -+ -+ if (retries > retry_limit) -+ DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); -+ -+ /* Make sure we have SD bus access */ -+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -+ -+ /* Enable interrupts again */ -+ if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { -+ bus->intdis = FALSE; -+ bcmsdh_intr_enable(bus->sdh); -+ } -+ } else { -+ err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); -+ } -+ -+ if (err == 0) { -+ /* Change state */ -+ bus->sleeping = FALSE; -+ } -+ } -+ -+ return err; -+} -+ -+#if defined(OOB_INTR_ONLY) -+void -+dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) -+{ -+#if defined(HW_OOB) -+ bcmsdh_enable_hw_oob_intr(bus->sdh, enable); -+#else -+ sdpcmd_regs_t *regs = bus->regs; -+ uint retries = 0; -+ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ if (enable == TRUE) { -+ -+ /* Tell device to start using OOB wakeup */ -+ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); -+ if (retries > retry_limit) -+ DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); -+ -+ } else { -+ /* Send misc interrupt to indicate OOB not needed */ -+ W_SDREG(0, ®s->tosbmailboxdata, retries); -+ if (retries <= retry_limit) -+ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); -+ } -+ -+ /* Turn off our contribution to the HT clock request */ -+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -+#endif /* !defined(HW_OOB) */ -+} -+#endif /* defined(OOB_INTR_ONLY) */ -+ -+/* Writes a HW/SW header into the packet and sends it. */ -+/* Assumes: (a) header space already there, (b) caller holds lock */ -+static int -+dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only) -+{ -+ int ret; -+ osl_t *osh; -+ uint8 *frame; -+ uint16 len, pad1 = 0; -+ uint32 swheader; -+ uint retries = 0; -+ bcmsdh_info_t *sdh; -+ void *new; -+ int i; -+ int pkt_cnt; -+#ifdef BCMSDIOH_TXGLOM -+ uint8 *frame_tmp; -+#endif -+#ifdef WLMEDIA_HTSF -+ char *p; -+ htsfts_t *htsf_ts; -+#endif -+ -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ sdh = bus->sdh; -+ osh = bus->dhd->osh; -+ -+ if (bus->dhd->dongle_reset) { -+ ret = BCME_NOTREADY; -+ goto done; -+ } -+ -+ frame = (uint8*)PKTDATA(osh, pkt); -+ -+#ifdef WLMEDIA_HTSF -+ if (PKTLEN(osh, pkt) >= 100) { -+ p = PKTDATA(osh, pkt); -+ htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12); -+ if (htsf_ts->magic == HTSFMAGIC) { -+ htsf_ts->c20 = get_cycles(); -+ htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); -+ } -+ } -+#endif /* WLMEDIA_HTSF */ -+ -+ /* Add alignment padding, allocate new packet if needed */ -+ if (!((uintptr)frame & 1) && (pad1 = ((uintptr)frame % DHD_SDALIGN))) { -+ if (PKTHEADROOM(osh, pkt) < pad1) { -+ DHD_INFO(("%s: insufficient headroom %d for %d pad1\n", -+ __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1)); -+ bus->dhd->tx_realloc++; -+ new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE); -+ if (!new) { -+ DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", -+ __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN)); -+ ret = BCME_NOMEM; -+ goto done; -+ } -+ -+ PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN); -+ bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt)); -+ if (free_pkt) -+ PKTFREE(osh, pkt, TRUE); -+ /* free the pkt if canned one is not used */ -+ free_pkt = TRUE; -+ pkt = new; -+ frame = (uint8*)PKTDATA(osh, pkt); -+ ASSERT(((uintptr)frame % DHD_SDALIGN) == 0); -+ pad1 = 0; -+ } else { -+ PKTPUSH(osh, pkt, pad1); -+ frame = (uint8*)PKTDATA(osh, pkt); -+ -+ ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt)); -+ bzero(frame, pad1 + SDPCM_HDRLEN); -+ } -+ } -+ ASSERT(pad1 < DHD_SDALIGN); -+ -+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ -+ len = (uint16)PKTLEN(osh, pkt); -+ *(uint16*)frame = htol16(len); -+ *(((uint16*)frame) + 1) = htol16(~len); -+ -+#ifdef BCMSDIOH_TXGLOM -+ if (bus->glom_enable) { -+ uint32 hwheader1 = 0, hwheader2 = 0, act_len = len; -+ -+ /* Software tag: channel, sequence number, data offset */ -+ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | -+ ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) | -+ (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); -+ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); -+ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader)); -+ -+ if (queue_only) { -+ if (forcealign && (len & (ALIGNMENT - 1))) -+ len = ROUNDUP(len, ALIGNMENT); -+ /* Hardware extention tag */ -+ /* 2byte frame length, 1byte-, 1byte frame flag, -+ * 2byte-hdrlength, 2byte padlenght -+ */ -+ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24); -+ hwheader2 = (len - act_len) << 16; -+ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); -+ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); -+ /* Post the frame pointer to sdio glom array */ -+ dhd_bcmsdh_glom_post(bus, frame, len); -+ /* Save the pkt pointer in bus glom array */ -+ bus->glom_pkt_arr[bus->glom_cnt] = pkt; -+ bus->glom_total_len += len; -+ bus->glom_cnt++; -+ return BCME_OK; -+ } else { -+ /* Raise len to next SDIO block to eliminate tail command */ -+ if (bus->roundup && bus->blocksize && -+ ((bus->glom_total_len + len) > bus->blocksize)) { -+ uint16 pad2 = bus->blocksize - -+ ((bus->glom_total_len + len) % bus->blocksize); -+ if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) { -+ len += pad2; -+ } else { -+ } -+ } else if ((bus->glom_total_len + len) % DHD_SDALIGN) { -+ len += DHD_SDALIGN -+ - ((bus->glom_total_len + len) % DHD_SDALIGN); -+ } -+ if (forcealign && (len & (ALIGNMENT - 1))) { -+ len = ROUNDUP(len, ALIGNMENT); -+ } -+ -+ /* Hardware extention tag */ -+ /* 2byte frame length, 1byte-, 1byte frame flag, -+ * 2byte-hdrlength, 2byte padlenght -+ */ -+ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24); -+ hwheader2 = (len - act_len) << 16; -+ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); -+ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); -+ -+ /* Post the frame pointer to sdio glom array */ -+ dhd_bcmsdh_glom_post(bus, frame, len); -+ /* Save the pkt pointer in bus glom array */ -+ bus->glom_pkt_arr[bus->glom_cnt] = pkt; -+ bus->glom_cnt++; -+ bus->glom_total_len += len; -+ -+ /* Update the total length on the first pkt */ -+ frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]); -+ *(uint16*)frame_tmp = htol16(bus->glom_total_len); -+ *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len); -+ } -+ } else -+#endif /* BCMSDIOH_TXGLOM */ -+ { -+ /* Software tag: channel, sequence number, data offset */ -+ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | -+ (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); -+ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); -+ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); -+ -+#ifdef DHD_DEBUG -+ if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) { -+ tx_packets[PKTPRIO(pkt)]++; -+ } -+ if (DHD_BYTES_ON() && -+ (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || -+ (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { -+ prhex("Tx Frame", frame, len); -+ } else if (DHD_HDRS_ON()) { -+ prhex("TxHdr", frame, MIN(len, 16)); -+ } -+#endif -+ -+ /* Raise len to next SDIO block to eliminate tail command */ -+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { -+ uint16 pad2 = bus->blocksize - (len % bus->blocksize); -+ if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) -+#ifdef NOTUSED -+ if (pad2 <= PKTTAILROOM(osh, pkt)) -+#endif /* NOTUSED */ -+ len += pad2; -+ } else if (len % DHD_SDALIGN) { -+ len += DHD_SDALIGN - (len % DHD_SDALIGN); -+ } -+ -+ /* Some controllers have trouble with odd bytes -- round to even */ -+ if (forcealign && (len & (ALIGNMENT - 1))) { -+#ifdef NOTUSED -+ if (PKTTAILROOM(osh, pkt)) -+#endif -+ len = ROUNDUP(len, ALIGNMENT); -+#ifdef NOTUSED -+ else -+ DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len)); -+#endif -+ } -+ } -+ -+ do { -+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, -+ frame, len, pkt, NULL, NULL); -+ bus->f2txdata++; -+ ASSERT(ret != BCME_PENDING); -+ -+ if (ret == BCME_NODEVICE) { -+ DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); -+ } else if (ret < 0) { -+ /* On failure, abort the command and terminate the frame */ -+ DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", -+ __FUNCTION__, ret)); -+ bus->tx_sderrs++; -+ -+ bcmsdh_abort(sdh, SDIO_FUNC_2); -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, -+ SFC_WF_TERM, NULL); -+ bus->f1regdata++; -+ -+ for (i = 0; i < 3; i++) { -+ uint8 hi, lo; -+ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_WFRAMEBCHI, NULL); -+ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_WFRAMEBCLO, NULL); -+ bus->f1regdata += 2; -+ if ((hi == 0) && (lo == 0)) -+ break; -+ } -+ } -+ if (ret == 0) { -+#ifdef BCMSDIOH_TXGLOM -+ if (bus->glom_enable) { -+ bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP; -+ } else -+#endif -+ { -+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; -+ } -+ } -+ } while ((ret < 0) && retrydata && retries++ < TXRETRIES); -+ -+done: -+ -+#ifdef BCMSDIOH_TXGLOM -+ if (bus->glom_enable) { -+ dhd_bcmsdh_glom_clear(bus); -+ pkt_cnt = bus->glom_cnt; -+ } else -+#endif -+ { -+ pkt_cnt = 1; -+ } -+ /* restore pkt buffer pointer before calling tx complete routine */ -+ while (pkt_cnt) { -+#ifdef BCMSDIOH_TXGLOM -+ uint32 doff; -+ if (bus->glom_enable) { -+ pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt]; -+ frame = (uint8*)PKTDATA(osh, pkt); -+ doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); -+ doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; -+ PKTPULL(osh, pkt, doff); -+ } else -+#endif -+ { -+ PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); -+ } -+#ifdef PROP_TXSTATUS -+ if (bus->dhd->wlfc_state) { -+ dhd_os_sdunlock(bus->dhd); -+ dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0); -+ dhd_os_sdlock(bus->dhd); -+ } else { -+#endif /* PROP_TXSTATUS */ -+#ifdef SDTEST -+ if (chan != SDPCM_TEST_CHANNEL) { -+ dhd_txcomplete(bus->dhd, pkt, ret != 0); -+ } -+#else /* SDTEST */ -+ dhd_txcomplete(bus->dhd, pkt, ret != 0); -+#endif /* SDTEST */ -+ if (free_pkt) -+ PKTFREE(osh, pkt, TRUE); -+ -+#ifdef PROP_TXSTATUS -+ } -+#endif -+ pkt_cnt--; -+ } -+ -+#ifdef BCMSDIOH_TXGLOM -+ /* Reset the glom array */ -+ if (bus->glom_enable) { -+ bus->glom_cnt = 0; -+ bus->glom_total_len = 0; -+ } -+#endif -+ return ret; -+} -+ -+int -+dhd_bus_txdata(struct dhd_bus *bus, void *pkt) -+{ -+ int ret = BCME_ERROR; -+ osl_t *osh; -+ uint datalen, prec; -+#ifdef DHD_TX_DUMP -+ uint8 *dump_data; -+ uint16 protocol; -+#ifdef DHD_TX_FULL_DUMP -+ int i; -+#endif /* DHD_TX_FULL_DUMP */ -+#endif /* DHD_TX_DUMP */ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ osh = bus->dhd->osh; -+ datalen = PKTLEN(osh, pkt); -+ -+#ifdef SDTEST -+ /* Push the test header if doing loopback */ -+ if (bus->ext_loop) { -+ uint8* data; -+ PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); -+ data = PKTDATA(osh, pkt); -+ *data++ = SDPCM_TEST_ECHOREQ; -+ *data++ = (uint8)bus->loopid++; -+ *data++ = (datalen >> 0); -+ *data++ = (datalen >> 8); -+ datalen += SDPCM_TEST_HDRLEN; -+ } -+#endif /* SDTEST */ -+ -+#ifdef DHD_TX_DUMP -+ dump_data = PKTDATA(osh, pkt); -+ dump_data += 4; /* skip 4 bytes header */ -+ protocol = (dump_data[12] << 8) | dump_data[13]; -+#ifdef DHD_TX_FULL_DUMP -+ DHD_ERROR(("TX DUMP\n")); -+ -+ for (i = 0; i < (datalen - 4); i++) { -+ DHD_ERROR(("%02X ", dump_data[i])); -+ if ((i & 15) == 15) -+ printk("\n"); -+ } -+ DHD_ERROR(("\n")); -+ -+#endif /* DHD_TX_FULL_DUMP */ -+ if (protocol == ETHER_TYPE_802_1X) { -+ DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n", -+ dump_data[14], dump_data[15], dump_data[30])); -+ } -+#endif /* DHD_TX_DUMP */ -+ -+ /* Add space for the header */ -+ PKTPUSH(osh, pkt, SDPCM_HDRLEN); -+ ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); -+ -+ prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); -+#ifndef DHDTHREAD -+ /* Lock: we're about to use shared data/code (and SDIO) */ -+ dhd_os_sdlock(bus->dhd); -+#endif /* DHDTHREAD */ -+ -+ /* Check for existing queue, current flow-control, pending event, or pending clock */ -+ if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || -+ (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || -+ (bus->clkstate != CLK_AVAIL)) { -+ DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, -+ pktq_len(&bus->txq))); -+ bus->fcqueued++; -+ -+ /* Priority based enq */ -+ dhd_os_sdlock_txq(bus->dhd); -+ if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) { -+ PKTPULL(osh, pkt, SDPCM_HDRLEN); -+#ifndef DHDTHREAD -+ /* Need to also release txqlock before releasing sdlock. -+ * This thread still has txqlock and releases sdlock. -+ * Deadlock happens when dpc() grabs sdlock first then -+ * attempts to grab txqlock. -+ */ -+ dhd_os_sdunlock_txq(bus->dhd); -+ dhd_os_sdunlock(bus->dhd); -+#endif -+#ifdef PROP_TXSTATUS -+ if (bus->dhd->wlfc_state) -+ dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE); -+ else -+#endif -+ dhd_txcomplete(bus->dhd, pkt, FALSE); -+#ifndef DHDTHREAD -+ dhd_os_sdlock(bus->dhd); -+ dhd_os_sdlock_txq(bus->dhd); -+#endif -+#ifdef PROP_TXSTATUS -+ /* let the caller decide whether to free the packet */ -+ if (!bus->dhd->wlfc_state) -+#endif -+ PKTFREE(osh, pkt, TRUE); -+ ret = BCME_NORESOURCE; -+ } -+ else -+ ret = BCME_OK; -+ dhd_os_sdunlock_txq(bus->dhd); -+ -+ if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) -+ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); -+ -+#ifdef DHD_DEBUG -+ if (pktq_plen(&bus->txq, prec) > qcount[prec]) -+ qcount[prec] = pktq_plen(&bus->txq, prec); -+#endif -+ /* Schedule DPC if needed to send queued packet(s) */ -+ if (dhd_deferred_tx && !bus->dpc_sched) { -+ bus->dpc_sched = TRUE; -+ dhd_sched_dpc(bus->dhd); -+ } -+ } else { -+#ifdef DHDTHREAD -+ /* Lock: we're about to use shared data/code (and SDIO) */ -+ dhd_os_sdlock(bus->dhd); -+#endif /* DHDTHREAD */ -+ -+ /* Otherwise, send it now */ -+ BUS_WAKE(bus); -+ /* Make sure back plane ht clk is on, no pending allowed */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); -+#ifndef SDTEST -+ ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); -+#else -+ ret = dhdsdio_txpkt(bus, pkt, -+ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE); -+#endif -+ if (ret) -+ bus->dhd->tx_errors++; -+ else -+ bus->dhd->dstats.tx_bytes += datalen; -+ -+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { -+ bus->activity = FALSE; -+ dhdsdio_clkctl(bus, CLK_NONE, TRUE); -+ } -+ -+#ifdef DHDTHREAD -+ dhd_os_sdunlock(bus->dhd); -+#endif /* DHDTHREAD */ -+ } -+ -+#ifndef DHDTHREAD -+ dhd_os_sdunlock(bus->dhd); -+#endif /* DHDTHREAD */ -+ -+ return ret; -+} -+ -+static uint -+dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) -+{ -+ void *pkt; -+ uint32 intstatus = 0; -+ uint retries = 0; -+ int ret = 0, prec_out; -+ uint cnt = 0; -+ uint datalen; -+ uint8 tx_prec_map; -+#ifdef BCMSDIOH_TXGLOM -+ uint i; -+ uint8 glom_cnt; -+#endif -+ -+ dhd_pub_t *dhd = bus->dhd; -+ sdpcmd_regs_t *regs = bus->regs; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (!KSO_ENAB(bus)) { -+ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); -+ return BCME_NODEVICE; -+ } -+ -+ tx_prec_map = ~bus->flowcontrol; -+ -+ /* Send frames until the limit or some other event */ -+ for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { -+#ifdef BCMSDIOH_TXGLOM -+ if (bus->glom_enable) { -+ glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize); -+ glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map)); -+ glom_cnt = MIN(glom_cnt, maxframes-cnt); -+ -+ /* Limiting the size to 2pkts in case of copy */ -+ if (bus->glom_mode == SDPCM_TXGLOM_CPY) -+ glom_cnt = MIN(glom_cnt, 5); -+ -+ if (glom_cnt == 0) -+ break; -+ datalen = 0; -+ for (i = 0; i < glom_cnt; i++) { -+ dhd_os_sdlock_txq(bus->dhd); -+ if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { -+ /* This case should not happen */ -+ DHD_ERROR(("No pkts in the queue for glomming\n")); -+ dhd_os_sdunlock_txq(bus->dhd); -+ break; -+ } -+ dhd_os_sdunlock_txq(bus->dhd); -+ -+ datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN); -+#ifndef SDTEST -+ ret = dhdsdio_txpkt(bus, -+ pkt, -+ SDPCM_DATA_CHANNEL, -+ TRUE, -+ (i == (glom_cnt-1))? FALSE: TRUE); -+#else -+ ret = dhdsdio_txpkt(bus, -+ pkt, -+ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), -+ TRUE, -+ (i == (glom_cnt-1))? FALSE: TRUE); -+#endif -+ } -+ cnt += i-1; -+ } else -+#endif /* BCMSDIOH_TXGLOM */ -+ { -+ dhd_os_sdlock_txq(bus->dhd); -+ if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { -+ dhd_os_sdunlock_txq(bus->dhd); -+ break; -+ } -+ dhd_os_sdunlock_txq(bus->dhd); -+ datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN; -+ -+#ifndef SDTEST -+ ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE); -+#else -+ ret = dhdsdio_txpkt(bus, -+ pkt, -+ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), -+ TRUE, -+ FALSE); -+#endif -+ } -+ -+ if (ret) -+ bus->dhd->tx_errors++; -+ else -+ bus->dhd->dstats.tx_bytes += datalen; -+ -+ /* In poll mode, need to check for other events */ -+ if (!bus->intr && cnt) -+ { -+ /* Check device status, signal pending interrupt */ -+ R_SDREG(intstatus, ®s->intstatus, retries); -+ bus->f2txdata++; -+ if (bcmsdh_regfail(bus->sdh)) -+ break; -+ if (intstatus & bus->hostintmask) -+ bus->ipend = TRUE; -+ } -+ } -+ -+ /* Deflow-control stack if needed */ -+ if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && -+ dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) -+ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); -+ -+ return cnt; -+} -+ -+int -+dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) -+{ -+ uint8 *frame; -+ uint16 len; -+ uint32 swheader; -+ uint retries = 0; -+ bcmsdh_info_t *sdh = bus->sdh; -+ uint8 doff = 0; -+ int ret = -1; -+ int i; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (bus->dhd->dongle_reset) -+ return -EIO; -+ -+ /* Back the pointer to make a room for bus header */ -+ frame = msg - SDPCM_HDRLEN; -+ len = (msglen += SDPCM_HDRLEN); -+ -+ /* Add alignment padding (optional for ctl frames) */ -+ if (dhd_alignctl) { -+ if ((doff = ((uintptr)frame % DHD_SDALIGN))) { -+ frame -= doff; -+ len += doff; -+ msglen += doff; -+ bzero(frame, doff + SDPCM_HDRLEN); -+ } -+ ASSERT(doff < DHD_SDALIGN); -+ } -+ doff += SDPCM_HDRLEN; -+ -+ /* Round send length to next SDIO block */ -+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { -+ uint16 pad = bus->blocksize - (len % bus->blocksize); -+ if ((pad <= bus->roundup) && (pad < bus->blocksize)) -+ len += pad; -+ } else if (len % DHD_SDALIGN) { -+ len += DHD_SDALIGN - (len % DHD_SDALIGN); -+ } -+ -+ /* Satisfy length-alignment requirements */ -+ if (forcealign && (len & (ALIGNMENT - 1))) -+ len = ROUNDUP(len, ALIGNMENT); -+ -+ ASSERT(ISALIGNED((uintptr)frame, 2)); -+ -+ -+ /* Need to lock here to protect txseq and SDIO tx calls */ -+ dhd_os_sdlock(bus->dhd); -+ -+ BUS_WAKE(bus); -+ -+ /* Make sure backplane clock is on */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ -+ *(uint16*)frame = htol16((uint16)msglen); -+ *(((uint16*)frame) + 1) = htol16(~msglen); -+ -+#ifdef BCMSDIOH_TXGLOM -+ if (bus->glom_enable) { -+ uint32 hwheader1, hwheader2; -+ /* Software tag: channel, sequence number, data offset */ -+ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) -+ | bus->tx_seq -+ | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); -+ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); -+ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN -+ + SDPCM_HWEXT_LEN + sizeof(swheader)); -+ -+ hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); -+ hwheader2 = (len - (msglen)) << 16; -+ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); -+ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); -+ -+ *(uint16*)frame = htol16(len); -+ *(((uint16*)frame) + 1) = htol16(~(len)); -+ } else -+#endif /* BCMSDIOH_TXGLOM */ -+ { -+ /* Software tag: channel, sequence number, data offset */ -+ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) -+ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); -+ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); -+ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); -+ } -+ if (!TXCTLOK(bus)) { -+ DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", -+ __FUNCTION__, bus->tx_max, bus->tx_seq)); -+ bus->ctrl_frame_stat = TRUE; -+ /* Send from dpc */ -+ bus->ctrl_frame_buf = frame; -+ bus->ctrl_frame_len = len; -+ -+ if (!bus->dpc_sched) { -+ bus->dpc_sched = TRUE; -+ dhd_sched_dpc(bus->dhd); -+ } -+ if (bus->ctrl_frame_stat) { -+ dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); -+ } -+ -+ if (bus->ctrl_frame_stat == FALSE) { -+ DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); -+ ret = 0; -+ } else { -+ bus->dhd->txcnt_timeout++; -+ if (!bus->dhd->hang_was_sent) { -+ DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", -+ __FUNCTION__, bus->dhd->txcnt_timeout)); -+ } -+ ret = -1; -+ bus->ctrl_frame_stat = FALSE; -+ goto done; -+ } -+ } -+ -+ bus->dhd->txcnt_timeout = 0; -+ -+ if (ret == -1) { -+#ifdef DHD_DEBUG -+ if (DHD_BYTES_ON() && DHD_CTL_ON()) { -+ prhex("Tx Frame", frame, len); -+ } else if (DHD_HDRS_ON()) { -+ prhex("TxHdr", frame, MIN(len, 16)); -+ } -+#endif -+ -+ do { -+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, -+ frame, len, NULL, NULL, NULL); -+ ASSERT(ret != BCME_PENDING); -+ -+ if (ret == BCME_NODEVICE) { -+ DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); -+ } else if (ret < 0) { -+ /* On failure, abort the command and terminate the frame */ -+ DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", -+ __FUNCTION__, ret)); -+ bus->tx_sderrs++; -+ -+ bcmsdh_abort(sdh, SDIO_FUNC_2); -+ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, -+ SFC_WF_TERM, NULL); -+ bus->f1regdata++; -+ -+ for (i = 0; i < 3; i++) { -+ uint8 hi, lo; -+ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_WFRAMEBCHI, NULL); -+ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_WFRAMEBCLO, NULL); -+ bus->f1regdata += 2; -+ if ((hi == 0) && (lo == 0)) -+ break; -+ } -+ } -+ if (ret == 0) { -+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; -+ } -+ } while ((ret < 0) && retries++ < TXRETRIES); -+ } -+ -+done: -+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { -+ bus->activity = FALSE; -+ dhdsdio_clkctl(bus, CLK_NONE, TRUE); -+ } -+ -+ dhd_os_sdunlock(bus->dhd); -+ -+ if (ret) -+ bus->dhd->tx_ctlerrs++; -+ else -+ bus->dhd->tx_ctlpkts++; -+ -+ if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) -+ return -ETIMEDOUT; -+ -+ return ret ? -EIO : 0; -+} -+ -+int -+dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) -+{ -+ int timeleft; -+ uint rxlen = 0; -+ bool pending; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (bus->dhd->dongle_reset) -+ return -EIO; -+ -+ /* Wait until control frame is available */ -+ timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); -+ -+ dhd_os_sdlock(bus->dhd); -+ rxlen = bus->rxlen; -+ bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); -+ bus->rxlen = 0; -+ dhd_os_sdunlock(bus->dhd); -+ -+ if (rxlen) { -+ DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", -+ __FUNCTION__, rxlen, msglen)); -+ } else if (timeleft == 0) { -+#ifdef DHD_DEBUG -+ uint32 status, retry = 0; -+ R_SDREG(status, &bus->regs->intstatus, retry); -+ DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", -+ __FUNCTION__, status)); -+#else -+ DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); -+#endif /* DHD_DEBUG */ -+#ifdef DHD_DEBUG -+ dhd_os_sdlock(bus->dhd); -+ dhdsdio_checkdied(bus, NULL, 0); -+ dhd_os_sdunlock(bus->dhd); -+#endif /* DHD_DEBUG */ -+ } else if (pending == TRUE) { -+ /* signal pending */ -+ DHD_ERROR(("%s: signal pending\n", __FUNCTION__)); -+ return -EINTR; -+ } else { -+ DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); -+#ifdef DHD_DEBUG -+ dhd_os_sdlock(bus->dhd); -+ dhdsdio_checkdied(bus, NULL, 0); -+ dhd_os_sdunlock(bus->dhd); -+#endif /* DHD_DEBUG */ -+ } -+ if (timeleft == 0) { -+ bus->dhd->rxcnt_timeout++; -+ DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); -+ } -+ else -+ bus->dhd->rxcnt_timeout = 0; -+ -+ if (rxlen) -+ bus->dhd->rx_ctlpkts++; -+ else -+ bus->dhd->rx_ctlerrs++; -+ -+ if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) -+ return -ETIMEDOUT; -+ -+ if (bus->dhd->dongle_trap_occured) -+ return -EREMOTEIO; -+ -+ return rxlen ? (int)rxlen : -EIO; -+} -+ -+/* IOVar table */ -+enum { -+ IOV_INTR = 1, -+ IOV_POLLRATE, -+ IOV_SDREG, -+ IOV_SBREG, -+ IOV_SDCIS, -+ IOV_MEMBYTES, -+ IOV_MEMSIZE, -+#ifdef DHD_DEBUG -+ IOV_CHECKDIED, -+ IOV_SERIALCONS, -+#endif /* DHD_DEBUG */ -+ IOV_SET_DOWNLOAD_STATE, -+ IOV_SOCRAM_STATE, -+ IOV_FORCEEVEN, -+ IOV_SDIOD_DRIVE, -+ IOV_READAHEAD, -+ IOV_SDRXCHAIN, -+ IOV_ALIGNCTL, -+ IOV_SDALIGN, -+ IOV_DEVRESET, -+ IOV_CPU, -+#if defined(SDIO_CRC_ERROR_FIX) -+ IOV_WATERMARK, -+ IOV_MESBUSYCTRL, -+#endif /* SDIO_CRC_ERROR_FIX */ -+#ifdef SDTEST -+ IOV_PKTGEN, -+ IOV_EXTLOOP, -+#endif /* SDTEST */ -+ IOV_SPROM, -+ IOV_TXBOUND, -+ IOV_RXBOUND, -+ IOV_TXMINMAX, -+ IOV_IDLETIME, -+ IOV_IDLECLOCK, -+ IOV_SD1IDLE, -+ IOV_SLEEP, -+ IOV_DONGLEISOLATION, -+ IOV_KSO, -+ IOV_DEVSLEEP, -+ IOV_DEVCAP, -+ IOV_VARS, -+#ifdef SOFTAP -+ IOV_FWPATH, -+#endif -+ IOV_TXGLOMSIZE, -+ IOV_TXGLOMMODE -+}; -+ -+const bcm_iovar_t dhdsdio_iovars[] = { -+ {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, -+ {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, -+ {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, -+ {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, -+ {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, -+ {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, -+ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, -+ {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, -+ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, -+ {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, -+ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, -+ {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, -+ {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, -+ {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, -+ {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, -+ {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, -+ {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, -+#ifdef DHD_DEBUG -+ {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, -+ {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, -+ {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, -+ {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, -+ {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, -+ {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, -+ {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, -+ {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, -+#ifdef DHD_DEBUG -+ {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, -+ {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, -+#endif /* DHD_DEBUG */ -+#endif /* DHD_DEBUG */ -+#ifdef SDTEST -+ {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, -+ {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, -+#endif /* SDTEST */ -+#if defined(SDIO_CRC_ERROR_FIX) -+ {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 }, -+ {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 }, -+#endif /* SDIO_CRC_ERROR_FIX */ -+ {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, -+ {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, -+ {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, -+ {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, -+#ifdef SOFTAP -+ {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, -+#endif -+ {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 }, -+ {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 }, -+ {NULL, 0, 0, 0, 0 } -+}; -+ -+static void -+dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) -+{ -+ uint q1, q2; -+ -+ if (!div) { -+ bcm_bprintf(strbuf, "%s N/A", desc); -+ } else { -+ q1 = num / div; -+ q2 = (100 * (num - (q1 * div))) / div; -+ bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); -+ } -+} -+ -+void -+dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ -+ bcm_bprintf(strbuf, "Bus SDIO structure:\n"); -+ bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", -+ bus->hostintmask, bus->intstatus, bus->sdpcm_ver); -+ bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", -+ bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, -+ bus->rxlen, bus->rx_seq); -+ bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", -+ bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); -+ bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n", -+ bus->pollrate, bus->pollcnt, bus->regfails); -+ -+ bcm_bprintf(strbuf, "\nAdditional counters:\n"); -+ bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n", -+ bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, -+ bus->rxc_errors); -+ bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n", -+ bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); -+ bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n", -+ bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); -+ bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n", -+ bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); -+ bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n", -+ (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, -+ bus->f2txdata, bus->f1regdata); -+ { -+ dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, -+ (bus->f2rxhdrs + bus->f2rxdata)); -+ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); -+ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, -+ (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); -+ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); -+ bcm_bprintf(strbuf, "\n"); -+ -+ dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), -+ bus->dhd->rx_packets); -+ dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); -+ bcm_bprintf(strbuf, "\n"); -+ -+ dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); -+ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); -+ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, -+ (bus->f2txdata + bus->f1regdata)); -+ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); -+ bcm_bprintf(strbuf, "\n"); -+ -+ dhd_dump_pct(strbuf, "Total: pkts/f2rw", -+ (bus->dhd->tx_packets + bus->dhd->rx_packets), -+ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); -+ dhd_dump_pct(strbuf, ", pkts/f1sd", -+ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); -+ dhd_dump_pct(strbuf, ", pkts/sd", -+ (bus->dhd->tx_packets + bus->dhd->rx_packets), -+ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); -+ dhd_dump_pct(strbuf, ", pkts/int", -+ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); -+ bcm_bprintf(strbuf, "\n\n"); -+ } -+ -+#ifdef SDTEST -+ if (bus->pktgen_count) { -+ bcm_bprintf(strbuf, "pktgen config and count:\n"); -+ bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n", -+ bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, -+ bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); -+ bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n", -+ bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); -+ } -+#endif /* SDTEST */ -+#ifdef DHD_DEBUG -+ bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", -+ bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); -+ bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup); -+#endif /* DHD_DEBUG */ -+ bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", -+ bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); -+} -+ -+void -+dhd_bus_clearcounts(dhd_pub_t *dhdp) -+{ -+ dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; -+ -+ bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; -+ bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; -+ bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; -+ bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; -+ bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; -+ bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; -+} -+ -+#ifdef SDTEST -+static int -+dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) -+{ -+ dhd_pktgen_t pktgen; -+ -+ pktgen.version = DHD_PKTGEN_VERSION; -+ pktgen.freq = bus->pktgen_freq; -+ pktgen.count = bus->pktgen_count; -+ pktgen.print = bus->pktgen_print; -+ pktgen.total = bus->pktgen_total; -+ pktgen.minlen = bus->pktgen_minlen; -+ pktgen.maxlen = bus->pktgen_maxlen; -+ pktgen.numsent = bus->pktgen_sent; -+ pktgen.numrcvd = bus->pktgen_rcvd; -+ pktgen.numfail = bus->pktgen_fail; -+ pktgen.mode = bus->pktgen_mode; -+ pktgen.stop = bus->pktgen_stop; -+ -+ bcopy(&pktgen, arg, sizeof(pktgen)); -+ -+ return 0; -+} -+ -+static int -+dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) -+{ -+ dhd_pktgen_t pktgen; -+ uint oldcnt, oldmode; -+ -+ bcopy(arg, &pktgen, sizeof(pktgen)); -+ if (pktgen.version != DHD_PKTGEN_VERSION) -+ return BCME_BADARG; -+ -+ oldcnt = bus->pktgen_count; -+ oldmode = bus->pktgen_mode; -+ -+ bus->pktgen_freq = pktgen.freq; -+ bus->pktgen_count = pktgen.count; -+ bus->pktgen_print = pktgen.print; -+ bus->pktgen_total = pktgen.total; -+ bus->pktgen_minlen = pktgen.minlen; -+ bus->pktgen_maxlen = pktgen.maxlen; -+ bus->pktgen_mode = pktgen.mode; -+ bus->pktgen_stop = pktgen.stop; -+ -+ bus->pktgen_tick = bus->pktgen_ptick = 0; -+ bus->pktgen_prev_time = jiffies; -+ bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); -+ bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); -+ -+ /* Clear counts for a new pktgen (mode change, or was stopped) */ -+ if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) { -+ bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0; -+ bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; -+ } -+ -+ return 0; -+} -+#endif /* SDTEST */ -+ -+static void -+dhdsdio_devram_remap(dhd_bus_t *bus, bool val) -+{ -+ uint8 enable, protect, remap; -+ -+ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); -+ remap = val ? TRUE : FALSE; -+ si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); -+} -+ -+static int -+dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) -+{ -+ int bcmerror = 0; -+ uint32 sdaddr; -+ uint dsize; -+ -+ /* In remap mode, adjust address beyond socram and redirect -+ * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize -+ * is not backplane accessible -+ */ -+ if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { -+ address -= bus->orig_ramsize; -+ address += SOCDEVRAM_BP_ADDR; -+ } -+ -+ /* Determine initial transfer parameters */ -+ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; -+ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) -+ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); -+ else -+ dsize = size; -+ -+ /* Set the backplane window to include the start address */ -+ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { -+ DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); -+ goto xfer_done; -+ } -+ -+ /* Do the transfer(s) */ -+ while (size) { -+ DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", -+ __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, -+ (address & SBSDIO_SBWINDOW_MASK))); -+ if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { -+ DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__)); -+ break; -+ } -+ -+ /* Adjust for next transfer (if any) */ -+ if ((size -= dsize)) { -+ data += dsize; -+ address += dsize; -+ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { -+ DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); -+ break; -+ } -+ sdaddr = 0; -+ dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); -+ } -+ -+ } -+ -+xfer_done: -+ /* Return the window to backplane enumeration space for core access */ -+ if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { -+ DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, -+ bcmsdh_cur_sbwad(bus->sdh))); -+ } -+ -+ return bcmerror; -+} -+ -+#ifdef DHD_DEBUG -+static int -+dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) -+{ -+ uint32 addr; -+ int rv, i; -+ uint32 shaddr = 0; -+ -+ shaddr = bus->dongle_ram_base + bus->ramsize - 4; -+ i = 0; -+ do { -+ /* Read last word in memory to determine address of sdpcm_shared structure */ -+ if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) -+ return rv; -+ -+ addr = ltoh32(addr); -+ -+ DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); -+ -+ /* -+ * Check if addr is valid. -+ * NVRAM length at the end of memory should have been overwritten. -+ */ -+ if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { -+ if ((bus->srmemsize > 0) && (i++ == 0)) { -+ shaddr -= bus->srmemsize; -+ } else { -+ DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", -+ __FUNCTION__, addr)); -+ return BCME_ERROR; -+ } -+ } else -+ break; -+ } while (i < 2); -+ -+ /* Read hndrte_shared structure */ -+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) -+ return rv; -+ -+ /* Endianness */ -+ sh->flags = ltoh32(sh->flags); -+ sh->trap_addr = ltoh32(sh->trap_addr); -+ sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); -+ sh->assert_file_addr = ltoh32(sh->assert_file_addr); -+ sh->assert_line = ltoh32(sh->assert_line); -+ sh->console_addr = ltoh32(sh->console_addr); -+ sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); -+ -+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) -+ return BCME_OK; -+ -+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { -+ DHD_ERROR(("%s: sdpcm_shared version %d in dhd " -+ "is different than sdpcm_shared version %d in dongle\n", -+ __FUNCTION__, SDPCM_SHARED_VERSION, -+ sh->flags & SDPCM_SHARED_VERSION_MASK)); -+ return BCME_ERROR; -+ } -+ -+ return BCME_OK; -+} -+ -+#define CONSOLE_LINE_MAX 192 -+ -+static int -+dhdsdio_readconsole(dhd_bus_t *bus) -+{ -+ dhd_console_t *c = &bus->console; -+ uint8 line[CONSOLE_LINE_MAX], ch; -+ uint32 n, idx, addr; -+ int rv; -+ -+ /* Don't do anything until FWREADY updates console address */ -+ if (bus->console_addr == 0) -+ return 0; -+ -+ if (!KSO_ENAB(bus)) -+ return 0; -+ -+ /* Read console log struct */ -+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log); -+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) -+ return rv; -+ -+ /* Allocate console buffer (one time only) */ -+ if (c->buf == NULL) { -+ c->bufsize = ltoh32(c->log.buf_size); -+ if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) -+ return BCME_NOMEM; -+ } -+ -+ idx = ltoh32(c->log.idx); -+ -+ /* Protect against corrupt value */ -+ if (idx > c->bufsize) -+ return BCME_ERROR; -+ -+ /* Skip reading the console buffer if the index pointer has not moved */ -+ if (idx == c->last) -+ return BCME_OK; -+ -+ /* Read the console buffer */ -+ addr = ltoh32(c->log.buf); -+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0) -+ return rv; -+ -+ while (c->last != idx) { -+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { -+ if (c->last == idx) { -+ /* This would output a partial line. Instead, back up -+ * the buffer pointer and output this line next time around. -+ */ -+ if (c->last >= n) -+ c->last -= n; -+ else -+ c->last = c->bufsize - n; -+ goto break2; -+ } -+ ch = c->buf[c->last]; -+ c->last = (c->last + 1) % c->bufsize; -+ if (ch == '\n') -+ break; -+ line[n] = ch; -+ } -+ -+ if (n > 0) { -+ if (line[n - 1] == '\r') -+ n--; -+ line[n] = 0; -+ printf("CONSOLE: %s\n", line); -+ } -+ } -+break2: -+ -+ return BCME_OK; -+} -+ -+static int -+dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) -+{ -+ int bcmerror = 0; -+ uint msize = 512; -+ char *mbuffer = NULL; -+ char *console_buffer = NULL; -+ uint maxstrlen = 256; -+ char *str = NULL; -+ trap_t tr; -+ sdpcm_shared_t sdpcm_shared; -+ struct bcmstrbuf strbuf; -+ uint32 console_ptr, console_size, console_index; -+ uint8 line[CONSOLE_LINE_MAX], ch; -+ uint32 n, i, addr; -+ int rv; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (data == NULL) { -+ /* -+ * Called after a rx ctrl timeout. "data" is NULL. -+ * allocate memory to trace the trap or assert. -+ */ -+ size = msize; -+ mbuffer = data = MALLOC(bus->dhd->osh, msize); -+ if (mbuffer == NULL) { -+ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); -+ bcmerror = BCME_NOMEM; -+ goto done; -+ } -+ } -+ -+ if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { -+ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); -+ bcmerror = BCME_NOMEM; -+ goto done; -+ } -+ -+ if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) -+ goto done; -+ -+ bcm_binit(&strbuf, data, size); -+ -+ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", -+ sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); -+ -+ if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { -+ /* NOTE: Misspelled assert is intentional - DO NOT FIX. -+ * (Avoids conflict with real asserts for programmatic parsing of output.) -+ */ -+ bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); -+ } -+ -+ if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { -+ /* NOTE: Misspelled assert is intentional - DO NOT FIX. -+ * (Avoids conflict with real asserts for programmatic parsing of output.) -+ */ -+ bcm_bprintf(&strbuf, "No trap%s in dongle", -+ (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) -+ ?"/assrt" :""); -+ } else { -+ if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { -+ /* Download assert */ -+ bcm_bprintf(&strbuf, "Dongle assert"); -+ if (sdpcm_shared.assert_exp_addr != 0) { -+ str[0] = '\0'; -+ if ((bcmerror = dhdsdio_membytes(bus, FALSE, -+ sdpcm_shared.assert_exp_addr, -+ (uint8 *)str, maxstrlen)) < 0) -+ goto done; -+ -+ str[maxstrlen - 1] = '\0'; -+ bcm_bprintf(&strbuf, " expr \"%s\"", str); -+ } -+ -+ if (sdpcm_shared.assert_file_addr != 0) { -+ str[0] = '\0'; -+ if ((bcmerror = dhdsdio_membytes(bus, FALSE, -+ sdpcm_shared.assert_file_addr, -+ (uint8 *)str, maxstrlen)) < 0) -+ goto done; -+ -+ str[maxstrlen - 1] = '\0'; -+ bcm_bprintf(&strbuf, " file \"%s\"", str); -+ } -+ -+ bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); -+ } -+ -+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { -+ bus->dhd->dongle_trap_occured = TRUE; -+ if ((bcmerror = dhdsdio_membytes(bus, FALSE, -+ sdpcm_shared.trap_addr, -+ (uint8*)&tr, sizeof(trap_t))) < 0) -+ goto done; -+ -+ bcm_bprintf(&strbuf, -+ "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," -+ "lp 0x%x, rpc 0x%x Trap offset 0x%x, " -+ "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " -+ "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", -+ ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), -+ ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), -+ ltoh32(sdpcm_shared.trap_addr), -+ ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), -+ ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); -+ -+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log); -+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, -+ (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) -+ goto printbuf; -+ -+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size); -+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, -+ (uint8 *)&console_size, sizeof(console_size))) < 0) -+ goto printbuf; -+ -+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx); -+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, -+ (uint8 *)&console_index, sizeof(console_index))) < 0) -+ goto printbuf; -+ -+ console_ptr = ltoh32(console_ptr); -+ console_size = ltoh32(console_size); -+ console_index = ltoh32(console_index); -+ -+ if (console_size > CONSOLE_BUFFER_MAX || -+ !(console_buffer = MALLOC(bus->dhd->osh, console_size))) -+ goto printbuf; -+ -+ if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, -+ (uint8 *)console_buffer, console_size)) < 0) -+ goto printbuf; -+ -+ for (i = 0, n = 0; i < console_size; i += n + 1) { -+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { -+ ch = console_buffer[(console_index + i + n) % console_size]; -+ if (ch == '\n') -+ break; -+ line[n] = ch; -+ } -+ -+ -+ if (n > 0) { -+ if (line[n - 1] == '\r') -+ n--; -+ line[n] = 0; -+ /* Don't use DHD_ERROR macro since we print -+ * a lot of information quickly. The macro -+ * will truncate a lot of the printfs -+ */ -+ -+ if (dhd_msg_level & DHD_ERROR_VAL) -+ printf("CONSOLE: %s\n", line); -+ } -+ } -+ } -+ } -+ -+printbuf: -+ if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { -+ DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); -+ } -+ -+ -+done: -+ if (mbuffer) -+ MFREE(bus->dhd->osh, mbuffer, msize); -+ if (str) -+ MFREE(bus->dhd->osh, str, maxstrlen); -+ if (console_buffer) -+ MFREE(bus->dhd->osh, console_buffer, console_size); -+ -+ return bcmerror; -+} -+#endif /* #ifdef DHD_DEBUG */ -+ -+ -+int -+dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) -+{ -+ int bcmerror = BCME_OK; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ /* Basic sanity checks */ -+ if (bus->dhd->up) { -+ bcmerror = BCME_NOTDOWN; -+ goto err; -+ } -+ if (!len) { -+ bcmerror = BCME_BUFTOOSHORT; -+ goto err; -+ } -+ -+ /* Free the old ones and replace with passed variables */ -+ if (bus->vars) -+ MFREE(bus->dhd->osh, bus->vars, bus->varsz); -+ -+ bus->vars = MALLOC(bus->dhd->osh, len); -+ bus->varsz = bus->vars ? len : 0; -+ if (bus->vars == NULL) { -+ bcmerror = BCME_NOMEM; -+ goto err; -+ } -+ -+ /* Copy the passed variables, which should include the terminating double-null */ -+ bcopy(arg, bus->vars, bus->varsz); -+err: -+ return bcmerror; -+} -+ -+#ifdef DHD_DEBUG -+ -+#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) -+#define CC_CHIPCTRL_JTAG_SEL (1 << 3) -+#define CC_CHIPCTRL_GPIO_SEL (0x3) -+#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) -+ -+static int -+dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) -+{ -+ int int_val; -+ uint32 addr, data, uart_enab = 0; -+ uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; -+ uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; -+ -+ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); -+ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); -+ *bcmerror = 0; -+ -+ bcmsdh_reg_write(bus->sdh, addr, 4, 1); -+ if (bcmsdh_regfail(bus->sdh)) { -+ *bcmerror = BCME_SDIO_ERROR; -+ return -1; -+ } -+ int_val = bcmsdh_reg_read(bus->sdh, data, 4); -+ if (bcmsdh_regfail(bus->sdh)) { -+ *bcmerror = BCME_SDIO_ERROR; -+ return -1; -+ } -+ if (bus->sih->chip == BCM4330_CHIP_ID) { -+ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; -+ } -+ else if (bus->sih->chip == BCM4334_CHIP_ID || -+ bus->sih->chip == BCM43341_CHIP_ID) { -+ if (enable) { -+ /* Moved to PMU chipcontrol 1 from 4330 */ -+ int_val &= ~gpio_sel; -+ int_val |= jtag_sel; -+ } else { -+ int_val |= gpio_sel; -+ int_val &= ~jtag_sel; -+ } -+ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; -+ } -+ -+ if (!set) -+ return (int_val & uart_enab); -+ if (enable) -+ int_val |= uart_enab; -+ else -+ int_val &= ~uart_enab; -+ bcmsdh_reg_write(bus->sdh, data, 4, int_val); -+ if (bcmsdh_regfail(bus->sdh)) { -+ *bcmerror = BCME_SDIO_ERROR; -+ return -1; -+ } -+ if (bus->sih->chip == BCM4330_CHIP_ID) { -+ uint32 chipcontrol; -+ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); -+ chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); -+ chipcontrol &= ~jtag_sel; -+ if (enable) { -+ chipcontrol |= jtag_sel; -+ chipcontrol &= ~gpio_sel; -+ } -+ bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); -+ } -+ -+ return (int_val & uart_enab); -+} -+#endif -+ -+static int -+dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, -+ void *params, int plen, void *arg, int len, int val_size) -+{ -+ int bcmerror = 0; -+ int32 int_val = 0; -+ bool bool_val = 0; -+ -+ DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", -+ __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); -+ -+ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) -+ goto exit; -+ -+ if (plen >= (int)sizeof(int_val)) -+ bcopy(params, &int_val, sizeof(int_val)); -+ -+ bool_val = (int_val != 0) ? TRUE : FALSE; -+ -+ -+ /* Some ioctls use the bus */ -+ dhd_os_sdlock(bus->dhd); -+ -+ /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ -+ if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || -+ actionid == IOV_GVAL(IOV_DEVRESET))) { -+ bcmerror = BCME_NOTREADY; -+ goto exit; -+ } -+ -+ /* -+ * Special handling for keepSdioOn: New SDIO Wake-up Mechanism -+ */ -+ if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { -+ dhdsdio_clk_kso_iovar(bus, bool_val); -+ goto exit; -+ } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { -+ { -+ dhdsdio_clk_devsleep_iovar(bus, bool_val); -+ if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { -+ DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n", -+ bus->dpc_sched)); -+ if (!bus->dpc_sched) { -+ bus->dpc_sched = TRUE; -+ dhd_sched_dpc(bus->dhd); -+ } -+ } -+ } -+ goto exit; -+ } -+ -+ /* Handle sleep stuff before any clock mucking */ -+ if (vi->varid == IOV_SLEEP) { -+ if (IOV_ISSET(actionid)) { -+ bcmerror = dhdsdio_bussleep(bus, bool_val); -+ } else { -+ int_val = (int32)bus->sleeping; -+ bcopy(&int_val, arg, val_size); -+ } -+ goto exit; -+ } -+ -+ /* Request clock to allow SDIO accesses */ -+ if (!bus->dhd->dongle_reset) { -+ BUS_WAKE(bus); -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ } -+ -+ switch (actionid) { -+ case IOV_GVAL(IOV_INTR): -+ int_val = (int32)bus->intr; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_INTR): -+ bus->intr = bool_val; -+ bus->intdis = FALSE; -+ if (bus->dhd->up) { -+ if (bus->intr) { -+ DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); -+ bcmsdh_intr_enable(bus->sdh); -+ } else { -+ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); -+ bcmsdh_intr_disable(bus->sdh); -+ } -+ } -+ break; -+ -+ case IOV_GVAL(IOV_POLLRATE): -+ int_val = (int32)bus->pollrate; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_POLLRATE): -+ bus->pollrate = (uint)int_val; -+ bus->poll = (bus->pollrate != 0); -+ break; -+ -+ case IOV_GVAL(IOV_IDLETIME): -+ int_val = bus->idletime; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_IDLETIME): -+ if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { -+ bcmerror = BCME_BADARG; -+ } else { -+ bus->idletime = int_val; -+ } -+ break; -+ -+ case IOV_GVAL(IOV_IDLECLOCK): -+ int_val = (int32)bus->idleclock; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_IDLECLOCK): -+ bus->idleclock = int_val; -+ break; -+ -+ case IOV_GVAL(IOV_SD1IDLE): -+ int_val = (int32)sd1idle; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_SD1IDLE): -+ sd1idle = bool_val; -+ break; -+ -+ -+ case IOV_SVAL(IOV_MEMBYTES): -+ case IOV_GVAL(IOV_MEMBYTES): -+ { -+ uint32 address; -+ uint size, dsize; -+ uint8 *data; -+ -+ bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); -+ -+ ASSERT(plen >= 2*sizeof(int)); -+ -+ address = (uint32)int_val; -+ bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); -+ size = (uint)int_val; -+ -+ /* Do some validation */ -+ dsize = set ? plen - (2 * sizeof(int)) : len; -+ if (dsize < size) { -+ DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", -+ __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ -+ DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, -+ (set ? "write" : "read"), size, address)); -+ -+ /* If we know about SOCRAM, check for a fit */ -+ if ((bus->orig_ramsize) && -+ ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) -+ { -+ uint8 enable, protect, remap; -+ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); -+ if (!enable || protect) { -+ DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", -+ __FUNCTION__, bus->orig_ramsize, size, address)); -+ DHD_ERROR(("%s: socram enable %d, protect %d\n", -+ __FUNCTION__, enable, protect)); -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ -+ if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { -+ uint32 devramsize = si_socdevram_size(bus->sih); -+ if ((address < SOCDEVRAM_ARM_ADDR) || -+ (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { -+ DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", -+ __FUNCTION__, address, size)); -+ DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", -+ __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ /* move it such that address is real now */ -+ address -= SOCDEVRAM_ARM_ADDR; -+ address += SOCDEVRAM_BP_ADDR; -+ DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", -+ __FUNCTION__, (set ? "write" : "read"), size, address)); -+ } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { -+ /* Can not access remap region while devram remap bit is set -+ * ROM content would be returned in this case -+ */ -+ DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", -+ __FUNCTION__, address)); -+ bcmerror = BCME_ERROR; -+ break; -+ } -+ } -+ -+ /* Generate the actual data pointer */ -+ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; -+ -+ /* Call to do the transfer */ -+ bcmerror = dhdsdio_membytes(bus, set, address, data, size); -+ -+ break; -+ } -+ -+ case IOV_GVAL(IOV_MEMSIZE): -+ int_val = (int32)bus->ramsize; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_GVAL(IOV_SDIOD_DRIVE): -+ int_val = (int32)dhd_sdiod_drive_strength; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_SDIOD_DRIVE): -+ dhd_sdiod_drive_strength = int_val; -+ si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); -+ break; -+ -+ case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): -+ bcmerror = dhdsdio_download_state(bus, bool_val); -+ break; -+ -+ case IOV_SVAL(IOV_SOCRAM_STATE): -+ bcmerror = dhdsdio_download_state(bus, bool_val); -+ break; -+ -+ case IOV_SVAL(IOV_VARS): -+ bcmerror = dhdsdio_downloadvars(bus, arg, len); -+ break; -+ -+ case IOV_GVAL(IOV_READAHEAD): -+ int_val = (int32)dhd_readahead; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_READAHEAD): -+ if (bool_val && !dhd_readahead) -+ bus->nextlen = 0; -+ dhd_readahead = bool_val; -+ break; -+ -+ case IOV_GVAL(IOV_SDRXCHAIN): -+ int_val = (int32)bus->use_rxchain; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_SDRXCHAIN): -+ if (bool_val && !bus->sd_rxchain) -+ bcmerror = BCME_UNSUPPORTED; -+ else -+ bus->use_rxchain = bool_val; -+ break; -+ case IOV_GVAL(IOV_ALIGNCTL): -+ int_val = (int32)dhd_alignctl; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_ALIGNCTL): -+ dhd_alignctl = bool_val; -+ break; -+ -+ case IOV_GVAL(IOV_SDALIGN): -+ int_val = DHD_SDALIGN; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+#ifdef DHD_DEBUG -+ case IOV_GVAL(IOV_VARS): -+ if (bus->varsz < (uint)len) -+ bcopy(bus->vars, arg, bus->varsz); -+ else -+ bcmerror = BCME_BUFTOOSHORT; -+ break; -+#endif /* DHD_DEBUG */ -+ -+#ifdef DHD_DEBUG -+ case IOV_GVAL(IOV_SDREG): -+ { -+ sdreg_t *sd_ptr; -+ uint32 addr, size; -+ -+ sd_ptr = (sdreg_t *)params; -+ -+ addr = (uintptr)bus->regs + sd_ptr->offset; -+ size = sd_ptr->func; -+ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); -+ if (bcmsdh_regfail(bus->sdh)) -+ bcmerror = BCME_SDIO_ERROR; -+ bcopy(&int_val, arg, sizeof(int32)); -+ break; -+ } -+ -+ case IOV_SVAL(IOV_SDREG): -+ { -+ sdreg_t *sd_ptr; -+ uint32 addr, size; -+ -+ sd_ptr = (sdreg_t *)params; -+ -+ addr = (uintptr)bus->regs + sd_ptr->offset; -+ size = sd_ptr->func; -+ bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); -+ if (bcmsdh_regfail(bus->sdh)) -+ bcmerror = BCME_SDIO_ERROR; -+ break; -+ } -+ -+ /* Same as above, but offset is not backplane (not SDIO core) */ -+ case IOV_GVAL(IOV_SBREG): -+ { -+ sdreg_t sdreg; -+ uint32 addr, size; -+ -+ bcopy(params, &sdreg, sizeof(sdreg)); -+ -+ addr = SI_ENUM_BASE + sdreg.offset; -+ size = sdreg.func; -+ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); -+ if (bcmsdh_regfail(bus->sdh)) -+ bcmerror = BCME_SDIO_ERROR; -+ bcopy(&int_val, arg, sizeof(int32)); -+ break; -+ } -+ -+ case IOV_SVAL(IOV_SBREG): -+ { -+ sdreg_t sdreg; -+ uint32 addr, size; -+ -+ bcopy(params, &sdreg, sizeof(sdreg)); -+ -+ addr = SI_ENUM_BASE + sdreg.offset; -+ size = sdreg.func; -+ bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); -+ if (bcmsdh_regfail(bus->sdh)) -+ bcmerror = BCME_SDIO_ERROR; -+ break; -+ } -+ -+ case IOV_GVAL(IOV_SDCIS): -+ { -+ *(char *)arg = 0; -+ -+ bcmstrcat(arg, "\nFunc 0\n"); -+ bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); -+ bcmstrcat(arg, "\nFunc 1\n"); -+ bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); -+ bcmstrcat(arg, "\nFunc 2\n"); -+ bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); -+ break; -+ } -+ -+ case IOV_GVAL(IOV_FORCEEVEN): -+ int_val = (int32)forcealign; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_FORCEEVEN): -+ forcealign = bool_val; -+ break; -+ -+ case IOV_GVAL(IOV_TXBOUND): -+ int_val = (int32)dhd_txbound; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_TXBOUND): -+ dhd_txbound = (uint)int_val; -+ break; -+ -+ case IOV_GVAL(IOV_RXBOUND): -+ int_val = (int32)dhd_rxbound; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_RXBOUND): -+ dhd_rxbound = (uint)int_val; -+ break; -+ -+ case IOV_GVAL(IOV_TXMINMAX): -+ int_val = (int32)dhd_txminmax; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_TXMINMAX): -+ dhd_txminmax = (uint)int_val; -+ break; -+ -+ case IOV_GVAL(IOV_SERIALCONS): -+ int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); -+ if (bcmerror != 0) -+ break; -+ -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_SERIALCONS): -+ dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); -+ break; -+ -+ -+ -+#endif /* DHD_DEBUG */ -+ -+ -+#ifdef SDTEST -+ case IOV_GVAL(IOV_EXTLOOP): -+ int_val = (int32)bus->ext_loop; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_EXTLOOP): -+ bus->ext_loop = bool_val; -+ break; -+ -+ case IOV_GVAL(IOV_PKTGEN): -+ bcmerror = dhdsdio_pktgen_get(bus, arg); -+ break; -+ -+ case IOV_SVAL(IOV_PKTGEN): -+ bcmerror = dhdsdio_pktgen_set(bus, arg); -+ break; -+#endif /* SDTEST */ -+ -+#if defined(SDIO_CRC_ERROR_FIX) -+ case IOV_GVAL(IOV_WATERMARK): -+ int_val = (int32)watermark; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_WATERMARK): -+ watermark = (uint)int_val; -+ watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; -+ DHD_ERROR(("Setting watermark as 0x%x.\n", watermark)); -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); -+ break; -+ -+ case IOV_GVAL(IOV_MESBUSYCTRL): -+ int_val = (int32)mesbusyctrl; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_MESBUSYCTRL): -+ mesbusyctrl = (uint)int_val; -+ mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) -+ ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; -+ DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, -+ ((uint8)mesbusyctrl | 0x80), NULL); -+ break; -+#endif /* SDIO_CRC_ERROR_FIX */ -+ -+ case IOV_GVAL(IOV_DONGLEISOLATION): -+ int_val = bus->dhd->dongle_isolation; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_DONGLEISOLATION): -+ bus->dhd->dongle_isolation = bool_val; -+ break; -+ -+ case IOV_SVAL(IOV_DEVRESET): -+ DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", -+ __FUNCTION__, bool_val, bus->dhd->dongle_reset, -+ bus->dhd->busstate)); -+ -+ ASSERT(bus->dhd->osh); -+ /* ASSERT(bus->cl_devid); */ -+ -+ dhd_bus_devreset(bus->dhd, (uint8)bool_val); -+ -+ break; -+#ifdef SOFTAP -+ case IOV_GVAL(IOV_FWPATH): -+ { -+ uint32 fw_path_len; -+ -+ fw_path_len = strlen(bus->fw_path); -+ DHD_INFO(("[softap] get fwpath, l=%d\n", len)); -+ -+ if (fw_path_len > len-1) { -+ bcmerror = BCME_BUFTOOSHORT; -+ break; -+ } -+ -+ if (fw_path_len) { -+ bcopy(bus->fw_path, arg, fw_path_len); -+ ((uchar*)arg)[fw_path_len] = 0; -+ } -+ break; -+ } -+ -+ case IOV_SVAL(IOV_FWPATH): -+ DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val)); -+ -+ switch (int_val) { -+ case 1: -+ bus->fw_path = fw_path; /* ordinary one */ -+ break; -+ case 2: -+ bus->fw_path = fw_path2; -+ break; -+ default: -+ bcmerror = BCME_BADARG; -+ break; -+ } -+ -+ DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL"))); -+ break; -+ -+#endif /* SOFTAP */ -+ case IOV_GVAL(IOV_DEVRESET): -+ DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); -+ -+ /* Get its status */ -+ int_val = (bool) bus->dhd->dongle_reset; -+ bcopy(&int_val, arg, val_size); -+ -+ break; -+ -+ case IOV_GVAL(IOV_KSO): -+ int_val = dhdsdio_sleepcsr_get(bus); -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_GVAL(IOV_DEVCAP): -+ int_val = dhdsdio_devcap_get(bus); -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_DEVCAP): -+ dhdsdio_devcap_set(bus, (uint8) int_val); -+ break; -+ -+#ifdef BCMSDIOH_TXGLOM -+ case IOV_GVAL(IOV_TXGLOMSIZE): -+ int_val = (int32)bus->glomsize; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_TXGLOMSIZE): -+ if (int_val > SDPCM_MAXGLOM_SIZE) { -+ bcmerror = BCME_ERROR; -+ } else { -+ bus->glomsize = (uint)int_val; -+ } -+ break; -+ case IOV_GVAL(IOV_TXGLOMMODE): -+ int_val = (int32)bus->glom_mode; -+ bcopy(&int_val, arg, val_size); -+ break; -+ -+ case IOV_SVAL(IOV_TXGLOMMODE): -+ if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) { -+ bcmerror = BCME_RANGE; -+ } else { -+ if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val) -+ bcmerror = BCME_ERROR; -+ } -+ break; -+#endif /* BCMSDIOH_TXGLOM */ -+ default: -+ bcmerror = BCME_UNSUPPORTED; -+ break; -+ } -+ -+exit: -+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { -+ bus->activity = FALSE; -+ dhdsdio_clkctl(bus, CLK_NONE, TRUE); -+ } -+ -+ dhd_os_sdunlock(bus->dhd); -+ -+ return bcmerror; -+} -+ -+static int -+dhdsdio_write_vars(dhd_bus_t *bus) -+{ -+ int bcmerror = 0; -+ uint32 varsize, phys_size; -+ uint32 varaddr; -+ uint8 *vbuffer; -+ uint32 varsizew; -+#ifdef DHD_DEBUG -+ uint8 *nvram_ularray; -+#endif /* DHD_DEBUG */ -+ -+ /* Even if there are no vars are to be written, we still need to set the ramsize. */ -+ varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0; -+ varaddr = (bus->ramsize - 4) - varsize; -+ -+ varaddr += bus->dongle_ram_base; -+ -+ if (bus->vars) { -+ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { -+ if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { -+ DHD_ERROR(("PR85623WAR in place\n")); -+ varsize += 4; -+ varaddr -= 4; -+ } -+ } -+ -+ vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); -+ if (!vbuffer) -+ return BCME_NOMEM; -+ -+ bzero(vbuffer, varsize); -+ bcopy(bus->vars, vbuffer, bus->varsz); -+ -+ /* Write the vars list */ -+ bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); -+#ifdef DHD_DEBUG -+ /* Verify NVRAM bytes */ -+ DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); -+ nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); -+ if (!nvram_ularray) -+ return BCME_NOMEM; -+ -+ /* Upload image to verify downloaded contents. */ -+ memset(nvram_ularray, 0xaa, varsize); -+ -+ /* Read the vars list to temp buffer for comparison */ -+ bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); -+ if (bcmerror) { -+ DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", -+ __FUNCTION__, bcmerror, varsize, varaddr)); -+ } -+ /* Compare the org NVRAM with the one read from RAM */ -+ if (memcmp(vbuffer, nvram_ularray, varsize)) { -+ DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); -+ } else -+ DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", -+ __FUNCTION__)); -+ -+ MFREE(bus->dhd->osh, nvram_ularray, varsize); -+#endif /* DHD_DEBUG */ -+ -+ MFREE(bus->dhd->osh, vbuffer, varsize); -+ } -+ -+ phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; -+ -+ phys_size += bus->dongle_ram_base; -+ -+ /* adjust to the user specified RAM */ -+ DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", -+ phys_size, bus->ramsize)); -+ DHD_INFO(("Vars are at %d, orig varsize is %d\n", -+ varaddr, varsize)); -+ varsize = ((phys_size - 4) - varaddr); -+ -+ /* -+ * Determine the length token: -+ * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. -+ */ -+ if (bcmerror) { -+ varsizew = 0; -+ } else { -+ varsizew = varsize / 4; -+ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); -+ varsizew = htol32(varsizew); -+ } -+ -+ DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); -+ -+ /* Write the length token to the last word */ -+ bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), -+ (uint8*)&varsizew, 4); -+ -+ return bcmerror; -+} -+ -+static int -+dhdsdio_download_state(dhd_bus_t *bus, bool enter) -+{ -+ uint retries; -+ int bcmerror = 0; -+ int foundcr4 = 0; -+ -+ /* To enter download state, disable ARM and reset SOCRAM. -+ * To exit download state, simply reset ARM (default is RAM boot). -+ */ -+ if (enter) { -+ bus->alp_only = TRUE; -+ -+ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && -+ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { -+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { -+ foundcr4 = 1; -+ } else { -+ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ } -+ -+ if (!foundcr4) { -+ si_core_disable(bus->sih, 0); -+ if (bcmsdh_regfail(bus->sdh)) { -+ bcmerror = BCME_SDIO_ERROR; -+ goto fail; -+ } -+ -+ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { -+ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ -+ si_core_reset(bus->sih, 0, 0); -+ if (bcmsdh_regfail(bus->sdh)) { -+ DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__)); -+ bcmerror = BCME_SDIO_ERROR; -+ goto fail; -+ } -+ -+ /* Disable remap for download */ -+ if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) -+ dhdsdio_devram_remap(bus, FALSE); -+ -+ /* Clear the top bit of memory */ -+ if (bus->ramsize) { -+ uint32 zeros = 0; -+ if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) { -+ bcmerror = BCME_SDIO_ERROR; -+ goto fail; -+ } -+ } -+ } else { -+ /* For CR4, -+ * Halt ARM -+ * Remove ARM reset -+ * Read RAM base address [0x18_0000] -+ * [next] Download firmware -+ * [done at else] Populate the reset vector -+ * [done at else] Remove ARM halt -+ */ -+ /* Halt ARM & remove reset */ -+ si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); -+ } -+ } else { -+ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { -+ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { -+ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ -+ if (!si_iscoreup(bus->sih)) { -+ DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ -+ if ((bcmerror = dhdsdio_write_vars(bus))) { -+ DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ /* Enable remap before ARM reset but after vars. -+ * No backplane access in remap mode -+ */ -+ if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) -+ dhdsdio_devram_remap(bus, TRUE); -+ -+ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && -+ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { -+ DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); -+ -+ -+ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && -+ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { -+ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ } else { -+ /* cr4 has no socram, but tcm's */ -+ /* write vars */ -+ if ((bcmerror = dhdsdio_write_vars(bus))) { -+ DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && -+ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { -+ DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); -+ -+ /* switch back to arm core again */ -+ if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { -+ DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); -+ bcmerror = BCME_ERROR; -+ goto fail; -+ } -+ /* write address 0 with reset instruction */ -+ bcmerror = dhdsdio_membytes(bus, TRUE, 0, -+ (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); -+ -+ /* now remove reset and halt and continue to run CR4 */ -+ } -+ -+ si_core_reset(bus->sih, 0, 0); -+ if (bcmsdh_regfail(bus->sdh)) { -+ DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__)); -+ bcmerror = BCME_SDIO_ERROR; -+ goto fail; -+ } -+ -+ /* Allow HT Clock now that the ARM is running. */ -+ bus->alp_only = FALSE; -+ -+ bus->dhd->busstate = DHD_BUS_LOAD; -+ } -+ -+fail: -+ /* Always return to SDIOD core */ -+ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) -+ si_setcore(bus->sih, SDIOD_CORE_ID, 0); -+ -+ return bcmerror; -+} -+ -+int -+dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, -+ void *params, int plen, void *arg, int len, bool set) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ const bcm_iovar_t *vi = NULL; -+ int bcmerror = 0; -+ int val_size; -+ uint32 actionid; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ ASSERT(name); -+ ASSERT(len >= 0); -+ -+ /* Get MUST have return space */ -+ ASSERT(set || (arg && len)); -+ -+ /* Set does NOT take qualifiers */ -+ ASSERT(!set || (!params && !plen)); -+ -+ /* Look up var locally; if not found pass to host driver */ -+ if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { -+ dhd_os_sdlock(bus->dhd); -+ -+ BUS_WAKE(bus); -+ -+ /* Turn on clock in case SD command needs backplane */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); -+ -+ /* Check for bus configuration changes of interest */ -+ -+ /* If it was divisor change, read the new one */ -+ if (set && strcmp(name, "sd_divisor") == 0) { -+ if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, -+ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { -+ bus->sd_divisor = -1; -+ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); -+ } else { -+ DHD_INFO(("%s: noted %s update, value now %d\n", -+ __FUNCTION__, name, bus->sd_divisor)); -+ } -+ } -+ /* If it was a mode change, read the new one */ -+ if (set && strcmp(name, "sd_mode") == 0) { -+ if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, -+ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { -+ bus->sd_mode = -1; -+ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); -+ } else { -+ DHD_INFO(("%s: noted %s update, value now %d\n", -+ __FUNCTION__, name, bus->sd_mode)); -+ } -+ } -+ /* Similar check for blocksize change */ -+ if (set && strcmp(name, "sd_blocksize") == 0) { -+ int32 fnum = 2; -+ if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), -+ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { -+ bus->blocksize = 0; -+ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); -+ } else { -+ DHD_INFO(("%s: noted %s update, value now %d\n", -+ __FUNCTION__, "sd_blocksize", bus->blocksize)); -+ } -+ } -+ bus->roundup = MIN(max_roundup, bus->blocksize); -+ -+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { -+ bus->activity = FALSE; -+ dhdsdio_clkctl(bus, CLK_NONE, TRUE); -+ } -+ -+ dhd_os_sdunlock(bus->dhd); -+ goto exit; -+ } -+ -+ DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, -+ name, (set ? "set" : "get"), len, plen)); -+ -+ /* set up 'params' pointer in case this is a set command so that -+ * the convenience int and bool code can be common to set and get -+ */ -+ if (params == NULL) { -+ params = arg; -+ plen = len; -+ } -+ -+ if (vi->type == IOVT_VOID) -+ val_size = 0; -+ else if (vi->type == IOVT_BUFFER) -+ val_size = len; -+ else -+ /* all other types are integer sized */ -+ val_size = sizeof(int); -+ -+ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); -+ bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); -+ -+exit: -+ return bcmerror; -+} -+ -+void -+dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) -+{ -+ osl_t *osh; -+ uint32 local_hostintmask; -+ uint8 saveclk, dat; -+ uint retries; -+ int err; -+ if (!bus->dhd) -+ return; -+ -+ osh = bus->dhd->osh; -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ bcmsdh_waitlockfree(NULL); -+ -+ if (enforce_mutex) -+ dhd_os_sdlock(bus->dhd); -+ -+ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ bus->hostintmask = 0; -+ bcmsdh_intr_disable(bus->sdh); -+ } else { -+ BUS_WAKE(bus); -+ -+ if (KSO_ENAB(bus)) { -+ /* Mask the interrupt */ -+ dat = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, NULL); -+ dat &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, dat, NULL); -+ } -+ -+ /* Change our idea of bus state */ -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ -+ if (KSO_ENAB(bus)) { -+ -+ /* Enable clock for device interrupts */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ /* Disable and clear interrupts at the chip level also */ -+ W_SDREG(0, &bus->regs->hostintmask, retries); -+ local_hostintmask = bus->hostintmask; -+ bus->hostintmask = 0; -+ -+ /* Force clocks on backplane to be sure F2 interrupt propagates */ -+ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); -+ if (!err) { -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, -+ (saveclk | SBSDIO_FORCE_HT), &err); -+ } -+ if (err) { -+ DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); -+ } -+ -+ /* Turn off the bus (F2), free any pending packets */ -+ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); -+ bcmsdh_intr_disable(bus->sdh); -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); -+ -+ /* Clear any pending interrupts now that F2 is disabled */ -+ W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); -+ } -+ -+ /* Turn off the backplane clock (only) */ -+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -+ } -+ -+ /* Clear the data packet queues */ -+ pktq_flush(osh, &bus->txq, TRUE, NULL, 0); -+ -+ /* Clear any held glomming stuff */ -+ if (bus->glomd) -+ PKTFREE(osh, bus->glomd, FALSE); -+ -+ if (bus->glom) -+ PKTFREE(osh, bus->glom, FALSE); -+ -+ bus->glom = bus->glomd = NULL; -+ -+ /* Clear rx control and wake any waiters */ -+ bus->rxlen = 0; -+ dhd_os_ioctl_resp_wake(bus->dhd); -+ -+ /* Reset some F2 state stuff */ -+ bus->rxskip = FALSE; -+ bus->tx_seq = bus->rx_seq = 0; -+ -+ if (enforce_mutex) -+ dhd_os_sdunlock(bus->dhd); -+} -+ -+#ifdef BCMSDIOH_TXGLOM -+void -+dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ -+ char buf[256]; -+ uint32 rxglom; -+ int32 ret; -+ -+ if (enable) { -+ rxglom = 1; -+ memset(buf, 0, sizeof(buf)); -+ bcm_mkiovar("bus:rxglom", -+ (void *)&rxglom, -+ 4, buf, sizeof(buf)); -+ ret = dhd_wl_ioctl_cmd(dhdp, -+ WLC_SET_VAR, buf, -+ sizeof(buf), TRUE, 0); -+ if (!(ret < 0)) { -+ bus->glom_enable = TRUE; -+ } -+ } else { -+ bus->glom_enable = FALSE; -+ } -+} -+#endif /* BCMSDIOH_TXGLOM */ -+ -+int -+dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ dhd_timeout_t tmo; -+ uint retries = 0; -+ uint8 ready, enable; -+ int err, ret = 0; -+ uint8 saveclk; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ ASSERT(bus->dhd); -+ if (!bus->dhd) -+ return 0; -+ -+ if (enforce_mutex) -+ dhd_os_sdlock(bus->dhd); -+ -+ /* Make sure backplane clock is on, needed to generate F2 interrupt */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ if (bus->clkstate != CLK_AVAIL) { -+ DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); -+ ret = -1; -+ goto exit; -+ } -+ -+ -+ /* Force clocks on backplane to be sure F2 interrupt propagates */ -+ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); -+ if (!err) { -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, -+ (saveclk | SBSDIO_FORCE_HT), &err); -+ } -+ if (err) { -+ DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); -+ ret = -1; -+ goto exit; -+ } -+ -+ /* Enable function 2 (frame transfers) */ -+ W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), -+ &bus->regs->tosbmailboxdata, retries); -+ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); -+ -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); -+ -+ /* Give the dongle some time to do its thing and set IOR2 */ -+ dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); -+ -+ ready = 0; -+ while (ready != enable && !dhd_timeout_expired(&tmo)) -+ ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); -+ -+ DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", -+ __FUNCTION__, enable, ready, tmo.elapsed)); -+ -+ -+ /* If F2 successfully enabled, set core and enable interrupts */ -+ if (ready == enable) { -+ /* Make sure we're talking to the core. */ -+ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) -+ bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); -+ ASSERT(bus->regs != NULL); -+ -+ /* Set up the interrupt mask and enable interrupts */ -+ bus->hostintmask = HOSTINTMASK; -+ /* corerev 4 could use the newer interrupt logic to detect the frames */ -+ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && -+ (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { -+ bus->hostintmask &= ~I_HMB_FRAME_IND; -+ bus->hostintmask |= I_XMTDATA_AVAIL; -+ } -+ W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); -+#ifdef SDIO_CRC_ERROR_FIX -+ if (bus->blocksize < 512) { -+ mesbusyctrl = watermark = bus->blocksize / 4; -+ } -+#endif /* SDIO_CRC_ERROR_FIX */ -+ -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); -+#ifdef SDIO_CRC_ERROR_FIX -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, -+ (uint8)mesbusyctrl|0x80, &err); -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, -+ SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL); -+#endif /* SDIO_CRC_ERROR_FIX */ -+ -+ /* Set bus state according to enable result */ -+ dhdp->busstate = DHD_BUS_DATA; -+ -+ /* bcmsdh_intr_unmask(bus->sdh); */ -+ -+ bus->intdis = FALSE; -+ if (bus->intr) { -+ DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); -+ bcmsdh_intr_enable(bus->sdh); -+ } else { -+ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); -+ bcmsdh_intr_disable(bus->sdh); -+ } -+ -+ } -+ -+ -+ else { -+ /* Disable F2 again */ -+ enable = SDIO_FUNC_ENABLE_1; -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); -+ } -+ -+ if (dhdsdio_sr_cap(bus)) -+ dhdsdio_sr_init(bus); -+ else -+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); -+ -+ /* If we didn't come up, turn off backplane clock */ -+ if (dhdp->busstate != DHD_BUS_DATA) -+ dhdsdio_clkctl(bus, CLK_NONE, FALSE); -+ -+exit: -+ if (enforce_mutex) -+ dhd_os_sdunlock(bus->dhd); -+ -+ return ret; -+} -+ -+static void -+dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) -+{ -+ bcmsdh_info_t *sdh = bus->sdh; -+ sdpcmd_regs_t *regs = bus->regs; -+ uint retries = 0; -+ uint16 lastrbc; -+ uint8 hi, lo; -+ int err; -+ -+ DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__, -+ (abort ? "abort command, " : ""), (rtx ? ", send NAK" : ""))); -+ -+ if (!KSO_ENAB(bus)) { -+ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); -+ return; -+ } -+ -+ if (abort) { -+ bcmsdh_abort(sdh, SDIO_FUNC_2); -+ } -+ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); -+ bus->f1regdata++; -+ -+ /* Wait until the packet has been flushed (device/FIFO stable) */ -+ for (lastrbc = retries = 0xffff; retries > 0; retries--) { -+ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); -+ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL); -+ bus->f1regdata += 2; -+ -+ if ((hi == 0) && (lo == 0)) -+ break; -+ -+ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { -+ DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n", -+ __FUNCTION__, lastrbc, ((hi << 8) + lo))); -+ } -+ lastrbc = (hi << 8) + lo; -+ } -+ -+ if (!retries) { -+ DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc)); -+ } else { -+ DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries))); -+ } -+ -+ if (rtx) { -+ bus->rxrtx++; -+ W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); -+ bus->f1regdata++; -+ if (retries <= retry_limit) { -+ bus->rxskip = TRUE; -+ } -+ } -+ -+ /* Clear partial in any case */ -+ bus->nextlen = 0; -+ -+ /* If we can't reach the device, signal failure */ -+ if (err || bcmsdh_regfail(sdh)) -+ bus->dhd->busstate = DHD_BUS_DOWN; -+} -+ -+static void -+dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) -+{ -+ bcmsdh_info_t *sdh = bus->sdh; -+ uint rdlen, pad; -+ -+ int sdret; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ /* Control data already received in aligned rxctl */ -+ if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) -+ goto gotpkt; -+ -+ ASSERT(bus->rxbuf); -+ /* Set rxctl for frame (w/optional alignment) */ -+ bus->rxctl = bus->rxbuf; -+ if (dhd_alignctl) { -+ bus->rxctl += firstread; -+ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) -+ bus->rxctl += (DHD_SDALIGN - pad); -+ bus->rxctl -= firstread; -+ } -+ ASSERT(bus->rxctl >= bus->rxbuf); -+ -+ /* Copy the already-read portion over */ -+ bcopy(hdr, bus->rxctl, firstread); -+ if (len <= firstread) -+ goto gotpkt; -+ -+ /* Copy the full data pkt in gSPI case and process ioctl. */ -+ if (bus->bus == SPI_BUS) { -+ bcopy(hdr, bus->rxctl, len); -+ goto gotpkt; -+ } -+ -+ /* Raise rdlen to next SDIO block to avoid tail command */ -+ rdlen = len - firstread; -+ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { -+ pad = bus->blocksize - (rdlen % bus->blocksize); -+ if ((pad <= bus->roundup) && (pad < bus->blocksize) && -+ ((len + pad) < bus->dhd->maxctl)) -+ rdlen += pad; -+ } else if (rdlen % DHD_SDALIGN) { -+ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); -+ } -+ -+ /* Satisfy length-alignment requirements */ -+ if (forcealign && (rdlen & (ALIGNMENT - 1))) -+ rdlen = ROUNDUP(rdlen, ALIGNMENT); -+ -+ /* Drop if the read is too big or it exceeds our maximum */ -+ if ((rdlen + firstread) > bus->dhd->maxctl) { -+ DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n", -+ __FUNCTION__, rdlen, bus->dhd->maxctl)); -+ bus->dhd->rx_errors++; -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ goto done; -+ } -+ -+ if ((len - doff) > bus->dhd->maxctl) { -+ DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", -+ __FUNCTION__, len, (len - doff), bus->dhd->maxctl)); -+ bus->dhd->rx_errors++; bus->rx_toolong++; -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ goto done; -+ } -+ -+ -+ /* Read remainder of frame body into the rxctl buffer */ -+ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, -+ (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); -+ bus->f2rxdata++; -+ ASSERT(sdret != BCME_PENDING); -+ -+ /* Control frame failures need retransmission */ -+ if (sdret < 0) { -+ DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret)); -+ bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ -+ dhdsdio_rxfail(bus, TRUE, TRUE); -+ goto done; -+ } -+ -+gotpkt: -+ -+#ifdef DHD_DEBUG -+ if (DHD_BYTES_ON() && DHD_CTL_ON()) { -+ prhex("RxCtrl", bus->rxctl, len); -+ } -+#endif -+ -+ /* Point to valid data and indicate its length */ -+ bus->rxctl += doff; -+ bus->rxlen = len - doff; -+ -+done: -+ /* Awake any waiters */ -+ dhd_os_ioctl_resp_wake(bus->dhd); -+} -+ -+static uint8 -+dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) -+{ -+ uint16 dlen, totlen; -+ uint8 *dptr, num = 0; -+ -+ uint16 sublen, check; -+ void *pfirst, *plast, *pnext; -+ void * list_tail[DHD_MAX_IFS] = { NULL }; -+ void * list_head[DHD_MAX_IFS] = { NULL }; -+ uint8 idx; -+ osl_t *osh = bus->dhd->osh; -+ -+ int errcode; -+ uint8 chan, seq, doff, sfdoff; -+ uint8 txmax; -+ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; -+ uint reorder_info_len; -+ -+ int ifidx = 0; -+ bool usechain = bus->use_rxchain; -+ -+ /* If packets, issue read(s) and send up packet chain */ -+ /* Return sequence numbers consumed? */ -+ -+ DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom)); -+ -+ /* If there's a descriptor, generate the packet chain */ -+ if (bus->glomd) { -+ dhd_os_sdlock_rxq(bus->dhd); -+ -+ pfirst = plast = pnext = NULL; -+ dlen = (uint16)PKTLEN(osh, bus->glomd); -+ dptr = PKTDATA(osh, bus->glomd); -+ if (!dlen || (dlen & 1)) { -+ DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n", -+ __FUNCTION__, dlen)); -+ dlen = 0; -+ } -+ -+ for (totlen = num = 0; dlen; num++) { -+ /* Get (and move past) next length */ -+ sublen = ltoh16_ua(dptr); -+ dlen -= sizeof(uint16); -+ dptr += sizeof(uint16); -+ if ((sublen < SDPCM_HDRLEN_RX) || -+ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) { -+ DHD_ERROR(("%s: descriptor len %d bad: %d\n", -+ __FUNCTION__, num, sublen)); -+ pnext = NULL; -+ break; -+ } -+ if (sublen % DHD_SDALIGN) { -+ DHD_ERROR(("%s: sublen %d not a multiple of %d\n", -+ __FUNCTION__, sublen, DHD_SDALIGN)); -+ usechain = FALSE; -+ } -+ totlen += sublen; -+ -+ /* For last frame, adjust read len so total is a block multiple */ -+ if (!dlen) { -+ sublen += (ROUNDUP(totlen, bus->blocksize) - totlen); -+ totlen = ROUNDUP(totlen, bus->blocksize); -+ } -+ -+ /* Allocate/chain packet for next subframe */ -+ if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { -+ DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", -+ __FUNCTION__, num, sublen)); -+ break; -+ } -+ ASSERT(!PKTLINK(pnext)); -+ if (!pfirst) { -+ ASSERT(!plast); -+ pfirst = plast = pnext; -+ } else { -+ ASSERT(plast); -+ PKTSETNEXT(osh, plast, pnext); -+ plast = pnext; -+ } -+ -+ /* Adhere to start alignment requirements */ -+ PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); -+ } -+ -+ /* If all allocations succeeded, save packet chain in bus structure */ -+ if (pnext) { -+ DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n", -+ __FUNCTION__, totlen, num)); -+ if (DHD_GLOM_ON() && bus->nextlen) { -+ if (totlen != bus->nextlen) { -+ DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " -+ "rxseq %d\n", __FUNCTION__, bus->nextlen, -+ totlen, rxseq)); -+ } -+ } -+ bus->glom = pfirst; -+ pfirst = pnext = NULL; -+ } else { -+ if (pfirst) -+ PKTFREE(osh, pfirst, FALSE); -+ bus->glom = NULL; -+ num = 0; -+ } -+ -+ /* Done with descriptor packet */ -+ PKTFREE(osh, bus->glomd, FALSE); -+ bus->glomd = NULL; -+ bus->nextlen = 0; -+ -+ dhd_os_sdunlock_rxq(bus->dhd); -+ } -+ -+ /* Ok -- either we just generated a packet chain, or had one from before */ -+ if (bus->glom) { -+ if (DHD_GLOM_ON()) { -+ DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__)); -+ for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { -+ DHD_GLOM((" %p: %p len 0x%04x (%d)\n", -+ pnext, (uint8*)PKTDATA(osh, pnext), -+ PKTLEN(osh, pnext), PKTLEN(osh, pnext))); -+ } -+ } -+ -+ pfirst = bus->glom; -+ dlen = (uint16)pkttotlen(osh, pfirst); -+ -+ /* Do an SDIO read for the superframe. Configurable iovar to -+ * read directly into the chained packet, or allocate a large -+ * packet and and copy into the chain. -+ */ -+ if (usechain) { -+ errcode = dhd_bcmsdh_recv_buf(bus, -+ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, -+ F2SYNC, (uint8*)PKTDATA(osh, pfirst), -+ dlen, pfirst, NULL, NULL); -+ } else if (bus->dataptr) { -+ errcode = dhd_bcmsdh_recv_buf(bus, -+ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, -+ F2SYNC, bus->dataptr, -+ dlen, NULL, NULL, NULL); -+ sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); -+ if (sublen != dlen) { -+ DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", -+ __FUNCTION__, dlen, sublen)); -+ errcode = -1; -+ } -+ pnext = NULL; -+ } else { -+ DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen)); -+ errcode = -1; -+ } -+ bus->f2rxdata++; -+ ASSERT(errcode != BCME_PENDING); -+ -+ /* On failure, kill the superframe, allow a couple retries */ -+ if (errcode < 0) { -+ DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", -+ __FUNCTION__, dlen, errcode)); -+ bus->dhd->rx_errors++; -+ -+ if (bus->glomerr++ < 3) { -+ dhdsdio_rxfail(bus, TRUE, TRUE); -+ } else { -+ bus->glomerr = 0; -+ dhdsdio_rxfail(bus, TRUE, FALSE); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE(osh, bus->glom, FALSE); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ bus->rxglomfail++; -+ bus->glom = NULL; -+ } -+ return 0; -+ } -+ -+#ifdef DHD_DEBUG -+ if (DHD_GLOM_ON()) { -+ prhex("SUPERFRAME", PKTDATA(osh, pfirst), -+ MIN(PKTLEN(osh, pfirst), 48)); -+ } -+#endif -+ -+ -+ /* Validate the superframe header */ -+ dptr = (uint8 *)PKTDATA(osh, pfirst); -+ sublen = ltoh16_ua(dptr); -+ check = ltoh16_ua(dptr + sizeof(uint16)); -+ -+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -+ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); -+ bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; -+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { -+ DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n", -+ __FUNCTION__, bus->nextlen, seq)); -+ bus->nextlen = 0; -+ } -+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -+ txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -+ -+ errcode = 0; -+ if ((uint16)~(sublen^check)) { -+ DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", -+ __FUNCTION__, sublen, check)); -+ errcode = -1; -+ } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { -+ DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", -+ __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen)); -+ errcode = -1; -+ } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { -+ DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__, -+ SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]))); -+ errcode = -1; -+ } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { -+ DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); -+ errcode = -1; -+ } else if ((doff < SDPCM_HDRLEN_RX) || -+ (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) { -+ DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", -+ __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), -+ SDPCM_HDRLEN_RX)); -+ errcode = -1; -+ } -+ -+ /* Check sequence number of superframe SW header */ -+ if (rxseq != seq) { -+ DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", -+ __FUNCTION__, seq, rxseq)); -+ bus->rx_badseq++; -+ rxseq = seq; -+ } -+ -+ /* Check window for sanity */ -+ if ((uint8)(txmax - bus->tx_seq) > 0x40) { -+ DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", -+ __FUNCTION__, txmax, bus->tx_seq)); -+ txmax = bus->tx_max; -+ } -+ bus->tx_max = txmax; -+ -+ /* Remove superframe header, remember offset */ -+ PKTPULL(osh, pfirst, doff); -+ sfdoff = doff; -+ -+ /* Validate all the subframe headers */ -+ for (num = 0, pnext = pfirst; pnext && !errcode; -+ num++, pnext = PKTNEXT(osh, pnext)) { -+ dptr = (uint8 *)PKTDATA(osh, pnext); -+ dlen = (uint16)PKTLEN(osh, pnext); -+ sublen = ltoh16_ua(dptr); -+ check = ltoh16_ua(dptr + sizeof(uint16)); -+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -+#ifdef DHD_DEBUG -+ if (DHD_GLOM_ON()) { -+ prhex("subframe", dptr, 32); -+ } -+#endif -+ -+ if ((uint16)~(sublen^check)) { -+ DHD_ERROR(("%s (subframe %d): HW hdr error: " -+ "len/check 0x%04x/0x%04x\n", -+ __FUNCTION__, num, sublen, check)); -+ errcode = -1; -+ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) { -+ DHD_ERROR(("%s (subframe %d): length mismatch: " -+ "len 0x%04x, expect 0x%04x\n", -+ __FUNCTION__, num, sublen, dlen)); -+ errcode = -1; -+ } else if ((chan != SDPCM_DATA_CHANNEL) && -+ (chan != SDPCM_EVENT_CHANNEL)) { -+ DHD_ERROR(("%s (subframe %d): bad channel %d\n", -+ __FUNCTION__, num, chan)); -+ errcode = -1; -+ } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) { -+ DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", -+ __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX)); -+ errcode = -1; -+ } -+ } -+ -+ if (errcode) { -+ /* Terminate frame on error, request a couple retries */ -+ if (bus->glomerr++ < 3) { -+ /* Restore superframe header space */ -+ PKTPUSH(osh, pfirst, sfdoff); -+ dhdsdio_rxfail(bus, TRUE, TRUE); -+ } else { -+ bus->glomerr = 0; -+ dhdsdio_rxfail(bus, TRUE, FALSE); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE(osh, bus->glom, FALSE); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ bus->rxglomfail++; -+ bus->glom = NULL; -+ } -+ bus->nextlen = 0; -+ return 0; -+ } -+ -+ /* Basic SD framing looks ok - process each packet (header) */ -+ bus->glom = NULL; -+ plast = NULL; -+ -+ dhd_os_sdlock_rxq(bus->dhd); -+ for (num = 0; pfirst; rxseq++, pfirst = pnext) { -+ pnext = PKTNEXT(osh, pfirst); -+ PKTSETNEXT(osh, pfirst, NULL); -+ -+ dptr = (uint8 *)PKTDATA(osh, pfirst); -+ sublen = ltoh16_ua(dptr); -+ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -+ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); -+ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -+ -+ DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", -+ __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), -+ PKTLEN(osh, pfirst), sublen, chan, seq)); -+ -+ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); -+ -+ if (rxseq != seq) { -+ DHD_GLOM(("%s: rx_seq %d, expected %d\n", -+ __FUNCTION__, seq, rxseq)); -+ bus->rx_badseq++; -+ rxseq = seq; -+ } -+ -+#ifdef DHD_DEBUG -+ if (DHD_BYTES_ON() && DHD_DATA_ON()) { -+ prhex("Rx Subframe Data", dptr, dlen); -+ } -+#endif -+ -+ PKTSETLEN(osh, pfirst, sublen); -+ PKTPULL(osh, pfirst, doff); -+ -+ reorder_info_len = sizeof(reorder_info_buf); -+ -+ if (PKTLEN(osh, pfirst) == 0) { -+ PKTFREE(bus->dhd->osh, pfirst, FALSE); -+ continue; -+ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, -+ &reorder_info_len) != 0) { -+ DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); -+ bus->dhd->rx_errors++; -+ PKTFREE(osh, pfirst, FALSE); -+ continue; -+ } -+ if (reorder_info_len) { -+ uint32 free_buf_count; -+ void *ppfirst; -+ -+ ppfirst = pfirst; -+ /* Reordering info from the firmware */ -+ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, -+ reorder_info_len, &ppfirst, &free_buf_count); -+ -+ if (free_buf_count == 0) { -+ continue; -+ } -+ else { -+ void *temp; -+ -+ /* go to the end of the chain and attach the pnext there */ -+ temp = ppfirst; -+ while (PKTNEXT(osh, temp) != NULL) { -+ temp = PKTNEXT(osh, temp); -+ } -+ pfirst = temp; -+ if (list_tail[ifidx] == NULL) { -+ list_head[ifidx] = ppfirst; -+ list_tail[ifidx] = pfirst; -+ } -+ else { -+ PKTSETNEXT(osh, list_tail[ifidx], ppfirst); -+ list_tail[ifidx] = pfirst; -+ } -+ } -+ -+ num += (uint8)free_buf_count; -+ } -+ else { -+ /* this packet will go up, link back into chain and count it */ -+ -+ if (list_tail[ifidx] == NULL) { -+ list_head[ifidx] = list_tail[ifidx] = pfirst; -+ } -+ else { -+ PKTSETNEXT(osh, list_tail[ifidx], pfirst); -+ list_tail[ifidx] = pfirst; -+ } -+ num++; -+ } -+#ifdef DHD_DEBUG -+ if (DHD_GLOM_ON()) { -+ DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", -+ __FUNCTION__, num, pfirst, -+ PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), -+ PKTNEXT(osh, pfirst), PKTLINK(pfirst))); -+ prhex("", (uint8 *)PKTDATA(osh, pfirst), -+ MIN(PKTLEN(osh, pfirst), 32)); -+ } -+#endif /* DHD_DEBUG */ -+ } -+ dhd_os_sdunlock_rxq(bus->dhd); -+ -+ for (idx = 0; idx < DHD_MAX_IFS; idx++) { -+ if (list_head[idx]) { -+ void *temp; -+ uint8 cnt = 0; -+ temp = list_head[idx]; -+ do { -+ temp = PKTNEXT(osh, temp); -+ cnt++; -+ } while (temp); -+ if (cnt) { -+ dhd_os_sdunlock(bus->dhd); -+ dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); -+ dhd_os_sdlock(bus->dhd); -+ } -+ } -+ } -+ bus->rxglomframes++; -+ bus->rxglompkts += num; -+ } -+ return num; -+} -+ -+ -+/* Return TRUE if there may be more frames to read */ -+static uint -+dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) -+{ -+ osl_t *osh = bus->dhd->osh; -+ bcmsdh_info_t *sdh = bus->sdh; -+ -+ uint16 len, check; /* Extracted hardware header fields */ -+ uint8 chan, seq, doff; /* Extracted software header fields */ -+ uint8 fcbits; /* Extracted fcbits from software header */ -+ uint8 delta; -+ -+ void *pkt; /* Packet for event or data frames */ -+ uint16 pad; /* Number of pad bytes to read */ -+ uint16 rdlen; /* Total number of bytes to read */ -+ uint8 rxseq; /* Next sequence number to expect */ -+ uint rxleft = 0; /* Remaining number of frames allowed */ -+ int sdret; /* Return code from bcmsdh calls */ -+ uint8 txmax; /* Maximum tx sequence offered */ -+ bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ -+ uint8 *rxbuf; -+ int ifidx = 0; -+ uint rxcount = 0; /* Total frames read */ -+ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; -+ uint reorder_info_len; -+ uint pkt_count; -+ -+#if defined(DHD_DEBUG) || defined(SDTEST) -+ bool sdtest = FALSE; /* To limit message spew from test mode */ -+#endif -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ bus->readframes = TRUE; -+ -+ if (!KSO_ENAB(bus)) { -+ DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); -+ bus->readframes = FALSE; -+ return 0; -+ } -+ -+ ASSERT(maxframes); -+ -+#ifdef SDTEST -+ /* Allow pktgen to override maxframes */ -+ if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { -+ maxframes = bus->pktgen_count; -+ sdtest = TRUE; -+ } -+#endif -+ -+ /* Not finished unless we encounter no more frames indication */ -+ *finished = FALSE; -+ -+ -+ for (rxseq = bus->rx_seq, rxleft = maxframes; -+ !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; -+ rxseq++, rxleft--) { -+ -+#ifdef DHDTHREAD -+ /* tx more to improve rx performance */ -+ if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && -+ pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) { -+ dhdsdio_sendfromq(bus, dhd_txbound); -+ } -+#endif /* DHDTHREAD */ -+ -+ /* Handle glomming separately */ -+ if (bus->glom || bus->glomd) { -+ uint8 cnt; -+ DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", -+ __FUNCTION__, bus->glomd, bus->glom)); -+ cnt = dhdsdio_rxglom(bus, rxseq); -+ DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt)); -+ rxseq += cnt - 1; -+ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; -+ continue; -+ } -+ -+ /* Try doing single read if we can */ -+ if (dhd_readahead && bus->nextlen) { -+ uint16 nextlen = bus->nextlen; -+ bus->nextlen = 0; -+ -+ if (bus->bus == SPI_BUS) { -+ rdlen = len = nextlen; -+ } -+ else { -+ rdlen = len = nextlen << 4; -+ -+ /* Pad read to blocksize for efficiency */ -+ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { -+ pad = bus->blocksize - (rdlen % bus->blocksize); -+ if ((pad <= bus->roundup) && (pad < bus->blocksize) && -+ ((rdlen + pad + firstread) < MAX_RX_DATASZ)) -+ rdlen += pad; -+ } else if (rdlen % DHD_SDALIGN) { -+ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); -+ } -+ } -+ -+ /* We use bus->rxctl buffer in WinXP for initial control pkt receives. -+ * Later we use buffer-poll for data as well as control packets. -+ * This is required because dhd receives full frame in gSPI unlike SDIO. -+ * After the frame is received we have to distinguish whether it is data -+ * or non-data frame. -+ */ -+ /* Allocate a packet buffer */ -+ dhd_os_sdlock_rxq(bus->dhd); -+ if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { -+ if (bus->bus == SPI_BUS) { -+ bus->usebufpool = FALSE; -+ bus->rxctl = bus->rxbuf; -+ if (dhd_alignctl) { -+ bus->rxctl += firstread; -+ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) -+ bus->rxctl += (DHD_SDALIGN - pad); -+ bus->rxctl -= firstread; -+ } -+ ASSERT(bus->rxctl >= bus->rxbuf); -+ rxbuf = bus->rxctl; -+ /* Read the entire frame */ -+ sdret = dhd_bcmsdh_recv_buf(bus, -+ bcmsdh_cur_sbwad(sdh), -+ SDIO_FUNC_2, -+ F2SYNC, rxbuf, rdlen, -+ NULL, NULL, NULL); -+ bus->f2rxdata++; -+ ASSERT(sdret != BCME_PENDING); -+ -+ -+ /* Control frame failures need retransmission */ -+ if (sdret < 0) { -+ DHD_ERROR(("%s: read %d control bytes failed: %d\n", -+ __FUNCTION__, rdlen, sdret)); -+ /* dhd.rx_ctlerrs is higher level */ -+ bus->rxc_errors++; -+ dhd_os_sdunlock_rxq(bus->dhd); -+ dhdsdio_rxfail(bus, TRUE, -+ (bus->bus == SPI_BUS) ? FALSE : TRUE); -+ continue; -+ } -+ } else { -+ /* Give up on data, request rtx of events */ -+ DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " -+ "expected rxseq %d\n", -+ __FUNCTION__, len, rdlen, rxseq)); -+ /* Just go try again w/normal header read */ -+ dhd_os_sdunlock_rxq(bus->dhd); -+ continue; -+ } -+ } else { -+ if (bus->bus == SPI_BUS) -+ bus->usebufpool = TRUE; -+ -+ ASSERT(!PKTLINK(pkt)); -+ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); -+ rxbuf = (uint8 *)PKTDATA(osh, pkt); -+ /* Read the entire frame */ -+ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), -+ SDIO_FUNC_2, -+ F2SYNC, rxbuf, rdlen, -+ pkt, NULL, NULL); -+ bus->f2rxdata++; -+ ASSERT(sdret != BCME_PENDING); -+ -+ if (sdret < 0) { -+ DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", -+ __FUNCTION__, rdlen, sdret)); -+ PKTFREE(bus->dhd->osh, pkt, FALSE); -+ bus->dhd->rx_errors++; -+ dhd_os_sdunlock_rxq(bus->dhd); -+ /* Force retry w/normal header read. Don't attempt NAK for -+ * gSPI -+ */ -+ dhdsdio_rxfail(bus, TRUE, -+ (bus->bus == SPI_BUS) ? FALSE : TRUE); -+ continue; -+ } -+ } -+ dhd_os_sdunlock_rxq(bus->dhd); -+ -+ /* Now check the header */ -+ bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX); -+ -+ /* Extract hardware header fields */ -+ len = ltoh16_ua(bus->rxhdr); -+ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); -+ -+ /* All zeros means readahead info was bad */ -+ if (!(len|check)) { -+ DHD_INFO(("%s (nextlen): read zeros in HW header???\n", -+ __FUNCTION__)); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE2(); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ GSPI_PR55150_BAILOUT; -+ continue; -+ } -+ -+ /* Validate check bytes */ -+ if ((uint16)~(len^check)) { -+ DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check" -+ " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, -+ len, check)); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE2(); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ bus->rx_badhdr++; -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ GSPI_PR55150_BAILOUT; -+ continue; -+ } -+ -+ /* Validate frame length */ -+ if (len < SDPCM_HDRLEN_RX) { -+ DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", -+ __FUNCTION__, len)); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE2(); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ GSPI_PR55150_BAILOUT; -+ continue; -+ } -+ -+ /* Check for consistency with readahead info */ -+ len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4)); -+ if (len_consistent) { -+ /* Mismatch, force retry w/normal header (may be >4K) */ -+ DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " -+ "expected rxseq %d\n", -+ __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq)); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE2(); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); -+ GSPI_PR55150_BAILOUT; -+ continue; -+ } -+ -+ -+ /* Extract software header fields */ -+ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ -+ bus->nextlen = -+ bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; -+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { -+ DHD_INFO(("%s (nextlen): got frame w/nextlen too large" -+ " (%d), seq %d\n", __FUNCTION__, bus->nextlen, -+ seq)); -+ bus->nextlen = 0; -+ } -+ -+ bus->dhd->rx_readahead_cnt ++; -+ /* Handle Flow Control */ -+ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ -+ delta = 0; -+ if (~bus->flowcontrol & fcbits) { -+ bus->fc_xoff++; -+ delta = 1; -+ } -+ if (bus->flowcontrol & ~fcbits) { -+ bus->fc_xon++; -+ delta = 1; -+ } -+ -+ if (delta) { -+ bus->fc_rcvd++; -+ bus->flowcontrol = fcbits; -+ } -+ -+ /* Check and update sequence number */ -+ if (rxseq != seq) { -+ DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n", -+ __FUNCTION__, seq, rxseq)); -+ bus->rx_badseq++; -+ rxseq = seq; -+ } -+ -+ /* Check window for sanity */ -+ if ((uint8)(txmax - bus->tx_seq) > 0x40) { -+ DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", -+ __FUNCTION__, txmax, bus->tx_seq)); -+ txmax = bus->tx_max; -+ } -+ bus->tx_max = txmax; -+ -+#ifdef DHD_DEBUG -+ if (DHD_BYTES_ON() && DHD_DATA_ON()) { -+ prhex("Rx Data", rxbuf, len); -+ } else if (DHD_HDRS_ON()) { -+ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); -+ } -+#endif -+ -+ if (chan == SDPCM_CONTROL_CHANNEL) { -+ if (bus->bus == SPI_BUS) { -+ dhdsdio_read_control(bus, rxbuf, len, doff); -+ if (bus->usebufpool) { -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE(bus->dhd->osh, pkt, FALSE); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ } -+ continue; -+ } else { -+ DHD_ERROR(("%s (nextlen): readahead on control" -+ " packet %d?\n", __FUNCTION__, seq)); -+ /* Force retry w/normal header read */ -+ bus->nextlen = 0; -+ dhdsdio_rxfail(bus, FALSE, TRUE); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE2(); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ continue; -+ } -+ } -+ -+ if ((bus->bus == SPI_BUS) && !bus->usebufpool) { -+ DHD_ERROR(("Received %d bytes on %d channel. Running out of " -+ "rx pktbuf's or not yet malloced.\n", len, chan)); -+ continue; -+ } -+ -+ /* Validate data offset */ -+ if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { -+ DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", -+ __FUNCTION__, doff, len, SDPCM_HDRLEN_RX)); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE2(); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ ASSERT(0); -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ continue; -+ } -+ -+ /* All done with this one -- now deliver the packet */ -+ goto deliver; -+ } -+ /* gSPI frames should not be handled in fractions */ -+ if (bus->bus == SPI_BUS) { -+ break; -+ } -+ -+ /* Read frame header (hardware and software) */ -+ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, -+ bus->rxhdr, firstread, NULL, NULL, NULL); -+ bus->f2rxhdrs++; -+ ASSERT(sdret != BCME_PENDING); -+ -+ if (sdret < 0) { -+ DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); -+ bus->rx_hdrfail++; -+ dhdsdio_rxfail(bus, TRUE, TRUE); -+ continue; -+ } -+ -+#ifdef DHD_DEBUG -+ if (DHD_BYTES_ON() || DHD_HDRS_ON()) { -+ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX); -+ } -+#endif -+ -+ /* Extract hardware header fields */ -+ len = ltoh16_ua(bus->rxhdr); -+ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); -+ -+ /* All zeros means no more frames */ -+ if (!(len|check)) { -+ *finished = TRUE; -+ break; -+ } -+ -+ /* Validate check bytes */ -+ if ((uint16)~(len^check)) { -+ DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n", -+ __FUNCTION__, len, check)); -+ bus->rx_badhdr++; -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ continue; -+ } -+ -+ /* Validate frame length */ -+ if (len < SDPCM_HDRLEN_RX) { -+ DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len)); -+ continue; -+ } -+ -+ /* Extract software header fields */ -+ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ -+ /* Validate data offset */ -+ if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) { -+ DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", -+ __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq)); -+ bus->rx_badhdr++; -+ ASSERT(0); -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ continue; -+ } -+ -+ /* Save the readahead length if there is one */ -+ bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; -+ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { -+ DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", -+ __FUNCTION__, bus->nextlen, seq)); -+ bus->nextlen = 0; -+ } -+ -+ /* Handle Flow Control */ -+ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); -+ -+ delta = 0; -+ if (~bus->flowcontrol & fcbits) { -+ bus->fc_xoff++; -+ delta = 1; -+ } -+ if (bus->flowcontrol & ~fcbits) { -+ bus->fc_xon++; -+ delta = 1; -+ } -+ -+ if (delta) { -+ bus->fc_rcvd++; -+ bus->flowcontrol = fcbits; -+ } -+ -+ /* Check and update sequence number */ -+ if (rxseq != seq) { -+ DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq)); -+ bus->rx_badseq++; -+ rxseq = seq; -+ } -+ -+ /* Check window for sanity */ -+ if ((uint8)(txmax - bus->tx_seq) > 0x40) { -+ DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", -+ __FUNCTION__, txmax, bus->tx_seq)); -+ txmax = bus->tx_max; -+ } -+ bus->tx_max = txmax; -+ -+ /* Call a separate function for control frames */ -+ if (chan == SDPCM_CONTROL_CHANNEL) { -+ dhdsdio_read_control(bus, bus->rxhdr, len, doff); -+ continue; -+ } -+ -+ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || -+ (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); -+ -+ /* Length to read */ -+ rdlen = (len > firstread) ? (len - firstread) : 0; -+ -+ /* May pad read to blocksize for efficiency */ -+ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { -+ pad = bus->blocksize - (rdlen % bus->blocksize); -+ if ((pad <= bus->roundup) && (pad < bus->blocksize) && -+ ((rdlen + pad + firstread) < MAX_RX_DATASZ)) -+ rdlen += pad; -+ } else if (rdlen % DHD_SDALIGN) { -+ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); -+ } -+ -+ /* Satisfy length-alignment requirements */ -+ if (forcealign && (rdlen & (ALIGNMENT - 1))) -+ rdlen = ROUNDUP(rdlen, ALIGNMENT); -+ -+ if ((rdlen + firstread) > MAX_RX_DATASZ) { -+ /* Too long -- skip this frame */ -+ DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen)); -+ bus->dhd->rx_errors++; bus->rx_toolong++; -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ continue; -+ } -+ -+ dhd_os_sdlock_rxq(bus->dhd); -+ if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { -+ /* Give up on data, request rtx of events */ -+ DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", -+ __FUNCTION__, rdlen, chan)); -+ bus->dhd->rx_dropped++; -+ dhd_os_sdunlock_rxq(bus->dhd); -+ dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); -+ continue; -+ } -+ dhd_os_sdunlock_rxq(bus->dhd); -+ -+ ASSERT(!PKTLINK(pkt)); -+ -+ /* Leave room for what we already read, and align remainder */ -+ ASSERT(firstread < (PKTLEN(osh, pkt))); -+ PKTPULL(osh, pkt, firstread); -+ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); -+ -+ /* Read the remaining frame data */ -+ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, -+ ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); -+ bus->f2rxdata++; -+ ASSERT(sdret != BCME_PENDING); -+ -+ if (sdret < 0) { -+ DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, -+ ((chan == SDPCM_EVENT_CHANNEL) ? "event" : -+ ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret)); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE(bus->dhd->osh, pkt, FALSE); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ bus->dhd->rx_errors++; -+ dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); -+ continue; -+ } -+ -+ /* Copy the already-read portion */ -+ PKTPUSH(osh, pkt, firstread); -+ bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); -+ -+#ifdef DHD_DEBUG -+ if (DHD_BYTES_ON() && DHD_DATA_ON()) { -+ prhex("Rx Data", PKTDATA(osh, pkt), len); -+ } -+#endif -+ -+deliver: -+ /* Save superframe descriptor and allocate packet frame */ -+ if (chan == SDPCM_GLOM_CHANNEL) { -+ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { -+ DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", -+ __FUNCTION__, len)); -+#ifdef DHD_DEBUG -+ if (DHD_GLOM_ON()) { -+ prhex("Glom Data", PKTDATA(osh, pkt), len); -+ } -+#endif -+ PKTSETLEN(osh, pkt, len); -+ ASSERT(doff == SDPCM_HDRLEN_RX); -+ PKTPULL(osh, pkt, SDPCM_HDRLEN_RX); -+ bus->glomd = pkt; -+ } else { -+ DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); -+ dhdsdio_rxfail(bus, FALSE, FALSE); -+ } -+ continue; -+ } -+ -+ /* Fill in packet len and prio, deliver upward */ -+ PKTSETLEN(osh, pkt, len); -+ PKTPULL(osh, pkt, doff); -+ -+#ifdef SDTEST -+ /* Test channel packets are processed separately */ -+ if (chan == SDPCM_TEST_CHANNEL) { -+ dhdsdio_testrcv(bus, pkt, seq); -+ continue; -+ } -+#endif /* SDTEST */ -+ -+ if (PKTLEN(osh, pkt) == 0) { -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE(bus->dhd->osh, pkt, FALSE); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ continue; -+ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, -+ &reorder_info_len) != 0) { -+ DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); -+ dhd_os_sdlock_rxq(bus->dhd); -+ PKTFREE(bus->dhd->osh, pkt, FALSE); -+ dhd_os_sdunlock_rxq(bus->dhd); -+ bus->dhd->rx_errors++; -+ continue; -+ } -+ if (reorder_info_len) { -+ /* Reordering info from the firmware */ -+ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, -+ &pkt, &pkt_count); -+ if (pkt_count == 0) -+ continue; -+ } -+ else -+ pkt_count = 1; -+ -+ -+ /* Unlock during rx call */ -+ dhd_os_sdunlock(bus->dhd); -+ dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); -+ dhd_os_sdlock(bus->dhd); -+ } -+ rxcount = maxframes - rxleft; -+#ifdef DHD_DEBUG -+ /* Message if we hit the limit */ -+ if (!rxleft && !sdtest) -+ DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes)); -+ else -+#endif /* DHD_DEBUG */ -+ DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount)); -+ /* Back off rxseq if awaiting rtx, update rx_seq */ -+ if (bus->rxskip) -+ rxseq--; -+ bus->rx_seq = rxseq; -+ -+ if (bus->reqbussleep) -+ { -+ dhdsdio_bussleep(bus, TRUE); -+ bus->reqbussleep = FALSE; -+ } -+ bus->readframes = FALSE; -+ -+ return rxcount; -+} -+ -+static uint32 -+dhdsdio_hostmail(dhd_bus_t *bus) -+{ -+ sdpcmd_regs_t *regs = bus->regs; -+ uint32 intstatus = 0; -+ uint32 hmb_data; -+ uint8 fcbits; -+ uint retries = 0; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ /* Read mailbox data and ack that we did so */ -+ R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); -+ if (retries <= retry_limit) -+ W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); -+ bus->f1regdata += 2; -+ -+ /* Dongle recomposed rx frames, accept them again */ -+ if (hmb_data & HMB_DATA_NAKHANDLED) { -+ DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq)); -+ if (!bus->rxskip) { -+ DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); -+ } -+ bus->rxskip = FALSE; -+ intstatus |= FRAME_AVAIL_MASK(bus); -+ } -+ -+ /* -+ * DEVREADY does not occur with gSPI. -+ */ -+ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { -+ bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT; -+ if (bus->sdpcm_ver != SDPCM_PROT_VERSION) -+ DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", -+ bus->sdpcm_ver, SDPCM_PROT_VERSION)); -+ else -+ DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); -+ /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ -+ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && -+ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { -+ uint32 val; -+ -+ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); -+ val &= ~CC_XMTDATAAVAIL_MODE; -+ val |= CC_XMTDATAAVAIL_CTRL; -+ W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); -+ -+ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); -+ } -+ -+#ifdef DHD_DEBUG -+ /* Retrieve console state address now that firmware should have updated it */ -+ { -+ sdpcm_shared_t shared; -+ if (dhdsdio_readshared(bus, &shared) == 0) -+ bus->console_addr = shared.console_addr; -+ } -+#endif /* DHD_DEBUG */ -+ } -+ -+ /* -+ * Flow Control has been moved into the RX headers and this out of band -+ * method isn't used any more. Leave this here for possibly remaining backward -+ * compatible with older dongles -+ */ -+ if (hmb_data & HMB_DATA_FC) { -+ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT; -+ -+ if (fcbits & ~bus->flowcontrol) -+ bus->fc_xoff++; -+ if (bus->flowcontrol & ~fcbits) -+ bus->fc_xon++; -+ -+ bus->fc_rcvd++; -+ bus->flowcontrol = fcbits; -+ } -+ -+#ifdef DHD_DEBUG -+ /* At least print a message if FW halted */ -+ if (hmb_data & HMB_DATA_FWHALT) { -+ DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n")); -+ dhdsdio_checkdied(bus, NULL, 0); -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ } -+#endif /* DHD_DEBUG */ -+ -+ /* Shouldn't be any others */ -+ if (hmb_data & ~(HMB_DATA_DEVREADY | -+ HMB_DATA_FWHALT | -+ HMB_DATA_NAKHANDLED | -+ HMB_DATA_FC | -+ HMB_DATA_FWREADY | -+ HMB_DATA_FCDATA_MASK | -+ HMB_DATA_VERSION_MASK)) { -+ DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); -+ } -+ -+ return intstatus; -+} -+ -+static bool -+dhdsdio_dpc(dhd_bus_t *bus) -+{ -+ bcmsdh_info_t *sdh = bus->sdh; -+ sdpcmd_regs_t *regs = bus->regs; -+ uint32 intstatus, newstatus = 0; -+ uint retries = 0; -+ uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ -+ uint txlimit = dhd_txbound; /* Tx frames to send before resched */ -+ uint framecnt = 0; /* Temporary counter of tx/rx frames */ -+ bool rxdone = TRUE; /* Flag for no more read data */ -+ bool resched = FALSE; /* Flag indicating resched wanted */ -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (bus->dhd->busstate == DHD_BUS_DOWN) { -+ DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); -+ bus->intstatus = 0; -+ return 0; -+ } -+ -+ /* Start with leftover status bits */ -+ intstatus = bus->intstatus; -+ -+ dhd_os_sdlock(bus->dhd); -+ -+ if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { -+ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); -+ goto exit; -+ } -+ -+ /* If waiting for HTAVAIL, check status */ -+ if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { -+ int err; -+ uint8 clkctl, devctl = 0; -+ -+#ifdef DHD_DEBUG -+ /* Check for inconsistent device control */ -+ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); -+ if (err) { -+ DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ } else { -+ ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); -+ } -+#endif /* DHD_DEBUG */ -+ -+ /* Read CSR, if clock on switch to AVAIL, else ignore */ -+ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); -+ if (err) { -+ DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err)); -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ } -+ -+ DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl)); -+ -+ if (SBSDIO_HTAV(clkctl)) { -+ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); -+ if (err) { -+ DHD_ERROR(("%s: error reading DEVCTL: %d\n", -+ __FUNCTION__, err)); -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ } -+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); -+ if (err) { -+ DHD_ERROR(("%s: error writing DEVCTL: %d\n", -+ __FUNCTION__, err)); -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ } -+ bus->clkstate = CLK_AVAIL; -+ } else { -+ goto clkwait; -+ } -+ } -+ -+ BUS_WAKE(bus); -+ -+ /* Make sure backplane clock is on */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); -+ if (bus->clkstate != CLK_AVAIL) -+ goto clkwait; -+ -+ /* Pending interrupt indicates new device status */ -+ if (bus->ipend) { -+ bus->ipend = FALSE; -+ R_SDREG(newstatus, ®s->intstatus, retries); -+ bus->f1regdata++; -+ if (bcmsdh_regfail(bus->sdh)) -+ newstatus = 0; -+ newstatus &= bus->hostintmask; -+ bus->fcstate = !!(newstatus & I_HMB_FC_STATE); -+ if (newstatus) { -+ bus->f1regdata++; -+ if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && -+ (newstatus == I_XMTDATA_AVAIL)) { -+ } -+ else -+ W_SDREG(newstatus, ®s->intstatus, retries); -+ } -+ } -+ -+ /* Merge new bits with previous */ -+ intstatus |= newstatus; -+ bus->intstatus = 0; -+ -+ /* Handle flow-control change: read new state in case our ack -+ * crossed another change interrupt. If change still set, assume -+ * FC ON for safety, let next loop through do the debounce. -+ */ -+ if (intstatus & I_HMB_FC_CHANGE) { -+ intstatus &= ~I_HMB_FC_CHANGE; -+ W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); -+ R_SDREG(newstatus, ®s->intstatus, retries); -+ bus->f1regdata += 2; -+ bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); -+ intstatus |= (newstatus & bus->hostintmask); -+ } -+ -+ /* Just being here means nothing more to do for chipactive */ -+ if (intstatus & I_CHIPACTIVE) { -+ /* ASSERT(bus->clkstate == CLK_AVAIL); */ -+ intstatus &= ~I_CHIPACTIVE; -+ } -+ -+ /* Handle host mailbox indication */ -+ if (intstatus & I_HMB_HOST_INT) { -+ intstatus &= ~I_HMB_HOST_INT; -+ intstatus |= dhdsdio_hostmail(bus); -+ } -+ -+ /* Generally don't ask for these, can get CRC errors... */ -+ if (intstatus & I_WR_OOSYNC) { -+ DHD_ERROR(("Dongle reports WR_OOSYNC\n")); -+ intstatus &= ~I_WR_OOSYNC; -+ } -+ -+ if (intstatus & I_RD_OOSYNC) { -+ DHD_ERROR(("Dongle reports RD_OOSYNC\n")); -+ intstatus &= ~I_RD_OOSYNC; -+ } -+ -+ if (intstatus & I_SBINT) { -+ DHD_ERROR(("Dongle reports SBINT\n")); -+ intstatus &= ~I_SBINT; -+ } -+ -+ /* Would be active due to wake-wlan in gSPI */ -+ if (intstatus & I_CHIPACTIVE) { -+ DHD_INFO(("Dongle reports CHIPACTIVE\n")); -+ intstatus &= ~I_CHIPACTIVE; -+ } -+ -+ /* Ignore frame indications if rxskip is set */ -+ if (bus->rxskip) { -+ intstatus &= ~FRAME_AVAIL_MASK(bus); -+ } -+ -+ /* On frame indication, read available frames */ -+ if (PKT_AVAILABLE(bus, intstatus)) { -+ framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); -+ if (rxdone || bus->rxskip) -+ intstatus &= ~FRAME_AVAIL_MASK(bus); -+ rxlimit -= MIN(framecnt, rxlimit); -+ } -+ -+ /* Keep still-pending events for next scheduling */ -+ bus->intstatus = intstatus; -+ -+clkwait: -+ /* Re-enable interrupts to detect new device events (mailbox, rx frame) -+ * or clock availability. (Allows tx loop to check ipend if desired.) -+ * (Unless register access seems hosed, as we may not be able to ACK...) -+ */ -+ if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { -+ DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", -+ __FUNCTION__, rxdone, framecnt)); -+ bus->intdis = FALSE; -+#if defined(OOB_INTR_ONLY) -+ bcmsdh_oob_intr_set(1); -+#endif /* defined(OOB_INTR_ONLY) */ -+ bcmsdh_intr_enable(sdh); -+ } -+ -+#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) -+ /* In case of SW-OOB(using edge trigger), -+ * Check interrupt status in the dongle again after enable irq on the host. -+ * and rechedule dpc if interrupt is pended in the dongle. -+ * There is a chance to miss OOB interrupt while irq is disabled on the host. -+ * No need to do this with HW-OOB(level trigger) -+ */ -+ R_SDREG(newstatus, ®s->intstatus, retries); -+ if (bcmsdh_regfail(bus->sdh)) -+ newstatus = 0; -+ if (newstatus & bus->hostintmask) { -+ bus->ipend = TRUE; -+ resched = TRUE; -+ } -+#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ -+#ifdef PROP_TXSTATUS -+ dhd_wlfc_trigger_pktcommit(bus->dhd); -+#endif -+ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { -+ int ret, i; -+ -+ uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; -+ -+ if (*frame_seq != bus->tx_seq) { -+ DHD_INFO(("%s IOCTL frame seq lag detected!" -+ " frm_seq:%d != bus->tx_seq:%d, corrected\n", -+ __FUNCTION__, *frame_seq, bus->tx_seq)); -+ *frame_seq = bus->tx_seq; -+ } -+ -+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, -+ (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, -+ NULL, NULL, NULL); -+ ASSERT(ret != BCME_PENDING); -+ if (ret == BCME_NODEVICE) { -+ DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); -+ } else if (ret < 0) { -+ /* On failure, abort the command and terminate the frame */ -+ DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", -+ __FUNCTION__, ret)); -+ bus->tx_sderrs++; -+ -+ bcmsdh_abort(sdh, SDIO_FUNC_2); -+ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, -+ SFC_WF_TERM, NULL); -+ bus->f1regdata++; -+ -+ for (i = 0; i < 3; i++) { -+ uint8 hi, lo; -+ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_WFRAMEBCHI, NULL); -+ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_WFRAMEBCLO, NULL); -+ bus->f1regdata += 2; -+ if ((hi == 0) && (lo == 0)) -+ break; -+ } -+ } -+ if (ret == 0) { -+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; -+ } -+ -+ bus->ctrl_frame_stat = FALSE; -+ dhd_wait_event_wakeup(bus->dhd); -+ } -+ /* Send queued frames (limit 1 if rx may still be pending) */ -+ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && -+ pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { -+ framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); -+ framecnt = dhdsdio_sendfromq(bus, framecnt); -+ txlimit -= framecnt; -+ } -+ /* Resched the DPC if ctrl cmd is pending on bus credit */ -+ if (bus->ctrl_frame_stat) -+ resched = TRUE; -+ -+ /* Resched if events or tx frames are pending, else await next interrupt */ -+ /* On failed register access, all bets are off: no resched or interrupts */ -+ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { -+ if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & -+ SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { -+ /* Bus failed because of KSO */ -+ DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); -+ bus->kso = FALSE; -+ } else { -+ DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", -+ __FUNCTION__)); -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ bus->intstatus = 0; -+ } -+ } else if (bus->clkstate == CLK_PENDING) { -+ /* Awaiting I_CHIPACTIVE; don't resched */ -+ } else if (bus->intstatus || bus->ipend || -+ (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || -+ PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ -+ resched = TRUE; -+ } -+ -+ bus->dpc_sched = resched; -+ -+ /* If we're done for now, turn off clock request. */ -+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { -+ bus->activity = FALSE; -+ dhdsdio_clkctl(bus, CLK_NONE, FALSE); -+ } -+ -+exit: -+ /* attemp to update tx credit before exiting dpc */ -+ if (!resched && dhd_dpcpoll) { -+ if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) -+ resched = TRUE; -+ } -+ dhd_os_sdunlock(bus->dhd); -+ return resched; -+} -+ -+bool -+dhd_bus_dpc(struct dhd_bus *bus) -+{ -+ bool resched; -+ -+ /* Call the DPC directly. */ -+ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); -+ resched = dhdsdio_dpc(bus); -+ -+ return resched; -+} -+ -+void -+dhdsdio_isr(void *arg) -+{ -+ dhd_bus_t *bus = (dhd_bus_t*)arg; -+ bcmsdh_info_t *sdh; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (!bus) { -+ DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); -+ return; -+ } -+ sdh = bus->sdh; -+ -+ if (bus->dhd->busstate == DHD_BUS_DOWN) { -+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); -+ return; -+ } -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ /* Count the interrupt call */ -+ bus->intrcount++; -+ bus->ipend = TRUE; -+ -+ /* Shouldn't get this interrupt if we're sleeping? */ -+ if (!SLPAUTO_ENAB(bus)) { -+ if (bus->sleeping) { -+ DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n")); -+ return; -+ } else if (!KSO_ENAB(bus)) { -+ DHD_ERROR(("ISR in devsleep 1\n")); -+ } -+ } -+ -+ /* Disable additional interrupts (is this needed now)? */ -+ if (bus->intr) { -+ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); -+ } else { -+ DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n")); -+ } -+ -+ bcmsdh_intr_disable(sdh); -+ bus->intdis = TRUE; -+ -+#if defined(SDIO_ISR_THREAD) -+ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); -+ DHD_OS_WAKE_LOCK(bus->dhd); -+ while (dhdsdio_dpc(bus)); -+ DHD_OS_WAKE_UNLOCK(bus->dhd); -+#else -+ bus->dpc_sched = TRUE; -+ dhd_sched_dpc(bus->dhd); -+#endif -+ -+} -+ -+#ifdef SDTEST -+static void -+dhdsdio_pktgen_init(dhd_bus_t *bus) -+{ -+ /* Default to specified length, or full range */ -+ if (dhd_pktgen_len) { -+ bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); -+ bus->pktgen_minlen = bus->pktgen_maxlen; -+ } else { -+ bus->pktgen_maxlen = MAX_PKTGEN_LEN; -+ bus->pktgen_minlen = 0; -+ } -+ bus->pktgen_len = (uint16)bus->pktgen_minlen; -+ -+ /* Default to per-watchdog burst with 10s print time */ -+ bus->pktgen_freq = 1; -+ bus->pktgen_print = dhd_watchdog_ms ? (10000/dhd_watchdog_ms):0; -+ bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; -+ -+ /* Default to echo mode */ -+ bus->pktgen_mode = DHD_PKTGEN_ECHO; -+ bus->pktgen_stop = 1; -+} -+ -+static void -+dhdsdio_pktgen(dhd_bus_t *bus) -+{ -+ void *pkt; -+ uint8 *data; -+ uint pktcount; -+ uint fillbyte; -+ osl_t *osh = bus->dhd->osh; -+ uint16 len; -+ ulong time_lapse; -+ uint sent_pkts; -+ uint rcvd_pkts; -+ -+ /* Display current count if appropriate */ -+ if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { -+ bus->pktgen_ptick = 0; -+ printf("%s: send attempts %d, rcvd %d, errors %d\n", -+ __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); -+ -+ /* Print throughput stats only for constant length packet runs */ -+ if (bus->pktgen_minlen == bus->pktgen_maxlen) { -+ time_lapse = jiffies - bus->pktgen_prev_time; -+ bus->pktgen_prev_time = jiffies; -+ sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; -+ bus->pktgen_prev_sent = bus->pktgen_sent; -+ rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; -+ bus->pktgen_prev_rcvd = bus->pktgen_rcvd; -+ -+ printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", -+ __FUNCTION__, -+ (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, -+ (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); -+ } -+ } -+ -+ /* For recv mode, just make sure dongle has started sending */ -+ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { -+ if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { -+ bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; -+ dhdsdio_sdtest_set(bus, bus->pktgen_total); -+ } -+ return; -+ } -+ -+ /* Otherwise, generate or request the specified number of packets */ -+ for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { -+ /* Stop if total has been reached */ -+ if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { -+ bus->pktgen_count = 0; -+ break; -+ } -+ -+ /* Allocate an appropriate-sized packet */ -+ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { -+ len = SDPCM_TEST_PKT_CNT_FLD_LEN; -+ } else { -+ len = bus->pktgen_len; -+ } -+ if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), -+ TRUE))) {; -+ DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); -+ break; -+ } -+ PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); -+ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; -+ -+ /* Write test header cmd and extra based on mode */ -+ switch (bus->pktgen_mode) { -+ case DHD_PKTGEN_ECHO: -+ *data++ = SDPCM_TEST_ECHOREQ; -+ *data++ = (uint8)bus->pktgen_sent; -+ break; -+ -+ case DHD_PKTGEN_SEND: -+ *data++ = SDPCM_TEST_DISCARD; -+ *data++ = (uint8)bus->pktgen_sent; -+ break; -+ -+ case DHD_PKTGEN_RXBURST: -+ *data++ = SDPCM_TEST_BURST; -+ *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ -+ break; -+ -+ default: -+ DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); -+ PKTFREE(osh, pkt, TRUE); -+ bus->pktgen_count = 0; -+ return; -+ } -+ -+ /* Write test header length field */ -+ *data++ = (bus->pktgen_len >> 0); -+ *data++ = (bus->pktgen_len >> 8); -+ -+ /* Write frame count in a 4 byte field adjucent to SDPCM test header for -+ * burst mode -+ */ -+ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { -+ *data++ = (uint8)(bus->pktgen_count >> 0); -+ *data++ = (uint8)(bus->pktgen_count >> 8); -+ *data++ = (uint8)(bus->pktgen_count >> 16); -+ *data++ = (uint8)(bus->pktgen_count >> 24); -+ } else { -+ -+ /* Then fill in the remainder -- N/A for burst */ -+ for (fillbyte = 0; fillbyte < len; fillbyte++) -+ *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); -+ } -+ -+#ifdef DHD_DEBUG -+ if (DHD_BYTES_ON() && DHD_DATA_ON()) { -+ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; -+ prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); -+ } -+#endif -+ -+ /* Send it */ -+ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) { -+ bus->pktgen_fail++; -+ if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) -+ bus->pktgen_count = 0; -+ } -+ bus->pktgen_sent++; -+ -+ /* Bump length if not fixed, wrap at max */ -+ if (++bus->pktgen_len > bus->pktgen_maxlen) -+ bus->pktgen_len = (uint16)bus->pktgen_minlen; -+ -+ /* Special case for burst mode: just send one request! */ -+ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) -+ break; -+ } -+} -+ -+static void -+dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) -+{ -+ void *pkt; -+ uint8 *data; -+ osl_t *osh = bus->dhd->osh; -+ -+ /* Allocate the packet */ -+ if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + -+ SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { -+ DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); -+ return; -+ } -+ PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + -+ SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); -+ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; -+ -+ /* Fill in the test header */ -+ *data++ = SDPCM_TEST_SEND; -+ *data++ = (count > 0)?TRUE:FALSE; -+ *data++ = (bus->pktgen_maxlen >> 0); -+ *data++ = (bus->pktgen_maxlen >> 8); -+ *data++ = (uint8)(count >> 0); -+ *data++ = (uint8)(count >> 8); -+ *data++ = (uint8)(count >> 16); -+ *data++ = (uint8)(count >> 24); -+ -+ /* Send it */ -+ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) -+ bus->pktgen_fail++; -+} -+ -+ -+static void -+dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) -+{ -+ osl_t *osh = bus->dhd->osh; -+ uint8 *data; -+ uint pktlen; -+ -+ uint8 cmd; -+ uint8 extra; -+ uint16 len; -+ uint16 offset; -+ -+ /* Check for min length */ -+ if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { -+ DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); -+ PKTFREE(osh, pkt, FALSE); -+ return; -+ } -+ -+ /* Extract header fields */ -+ data = PKTDATA(osh, pkt); -+ cmd = *data++; -+ extra = *data++; -+ len = *data++; len += *data++ << 8; -+ DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); -+ /* Check length for relevant commands */ -+ if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { -+ if (pktlen != len + SDPCM_TEST_HDRLEN) { -+ DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" -+ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); -+ PKTFREE(osh, pkt, FALSE); -+ return; -+ } -+ } -+ -+ /* Process as per command */ -+ switch (cmd) { -+ case SDPCM_TEST_ECHOREQ: -+ /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ -+ *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; -+ if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) { -+ bus->pktgen_sent++; -+ } else { -+ bus->pktgen_fail++; -+ PKTFREE(osh, pkt, FALSE); -+ } -+ bus->pktgen_rcvd++; -+ break; -+ -+ case SDPCM_TEST_ECHORSP: -+ if (bus->ext_loop) { -+ PKTFREE(osh, pkt, FALSE); -+ bus->pktgen_rcvd++; -+ break; -+ } -+ -+ for (offset = 0; offset < len; offset++, data++) { -+ if (*data != SDPCM_TEST_FILL(offset, extra)) { -+ DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " -+ "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", -+ offset, len, SDPCM_TEST_FILL(offset, extra), *data)); -+ break; -+ } -+ } -+ PKTFREE(osh, pkt, FALSE); -+ bus->pktgen_rcvd++; -+ break; -+ -+ case SDPCM_TEST_DISCARD: -+ { -+ int i = 0; -+ uint8 *prn = data; -+ uint8 testval = extra; -+ for (i = 0; i < len; i++) { -+ if (*prn != testval) { -+ DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", -+ i, bus->pktgen_rcvd_rcvsession, testval, *prn)); -+ prn++; testval++; -+ } -+ } -+ } -+ PKTFREE(osh, pkt, FALSE); -+ bus->pktgen_rcvd++; -+ break; -+ -+ case SDPCM_TEST_BURST: -+ case SDPCM_TEST_SEND: -+ default: -+ DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" -+ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); -+ PKTFREE(osh, pkt, FALSE); -+ break; -+ } -+ -+ /* For recv mode, stop at limit (and tell dongle to stop sending) */ -+ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { -+ if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { -+ bus->pktgen_rcvd_rcvsession++; -+ -+ if (bus->pktgen_total && -+ (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { -+ bus->pktgen_count = 0; -+ DHD_ERROR(("Pktgen:rcv test complete!\n")); -+ bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; -+ dhdsdio_sdtest_set(bus, FALSE); -+ bus->pktgen_rcvd_rcvsession = 0; -+ } -+ } -+ } -+} -+#endif /* SDTEST */ -+ -+extern void -+dhd_disable_intr(dhd_pub_t *dhdp) -+{ -+ dhd_bus_t *bus; -+ bus = dhdp->bus; -+ bcmsdh_intr_disable(bus->sdh); -+} -+ -+extern bool -+dhd_bus_watchdog(dhd_pub_t *dhdp) -+{ -+ dhd_bus_t *bus; -+ -+ DHD_TIMER(("%s: Enter\n", __FUNCTION__)); -+ -+ bus = dhdp->bus; -+ -+ if (bus->dhd->dongle_reset) -+ return FALSE; -+ -+ /* Ignore the timer if simulating bus down */ -+ if (!SLPAUTO_ENAB(bus) && bus->sleeping) -+ return FALSE; -+ -+ if (dhdp->busstate == DHD_BUS_DOWN) -+ return FALSE; -+ -+ /* Poll period: check device if appropriate. */ -+ if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { -+ uint32 intstatus = 0; -+ -+ /* Reset poll tick */ -+ bus->polltick = 0; -+ -+ /* Check device if no interrupts */ -+ if (!bus->intr || (bus->intrcount == bus->lastintrs)) { -+ -+ if (!bus->dpc_sched) { -+ uint8 devpend; -+ devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, -+ SDIOD_CCCR_INTPEND, NULL); -+ intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); -+ } -+ -+ /* If there is something, make like the ISR and schedule the DPC */ -+ if (intstatus) { -+ bus->pollcnt++; -+ bus->ipend = TRUE; -+ if (bus->intr) { -+ bcmsdh_intr_disable(bus->sdh); -+ } -+ bus->dpc_sched = TRUE; -+ dhd_sched_dpc(bus->dhd); -+ -+ } -+ } -+ -+ /* Update interrupt tracking */ -+ bus->lastintrs = bus->intrcount; -+ } -+ -+#ifdef DHD_DEBUG -+ /* Poll for console output periodically */ -+ if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { -+ bus->console.count += dhd_watchdog_ms; -+ if (bus->console.count >= dhd_console_ms) { -+ bus->console.count -= dhd_console_ms; -+ /* Make sure backplane clock is on */ -+ if (SLPAUTO_ENAB(bus)) -+ dhdsdio_bussleep(bus, FALSE); -+ else -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ if (dhdsdio_readconsole(bus) < 0) -+ dhd_console_ms = 0; /* On error, stop trying */ -+ } -+ } -+#endif /* DHD_DEBUG */ -+ -+#ifdef SDTEST -+ /* Generate packets if configured */ -+ if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { -+ /* Make sure backplane clock is on */ -+ if (SLPAUTO_ENAB(bus)) -+ dhdsdio_bussleep(bus, FALSE); -+ else -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ bus->pktgen_tick = 0; -+ dhdsdio_pktgen(bus); -+ } -+#endif -+ -+ /* On idle timeout clear activity flag and/or turn off clock */ -+#ifdef DHD_USE_IDLECOUNT -+ if (bus->activity) -+ bus->activity = FALSE; -+ else { -+ bus->idlecount++; -+ -+ if (bus->idlecount >= bus->idletime) { -+ DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); -+ -+ if (SLPAUTO_ENAB(bus)) { -+ if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) -+ dhd_os_wd_timer(bus->dhd, 0); -+ } else -+ dhdsdio_clkctl(bus, CLK_NONE, FALSE); -+ -+ bus->idlecount = 0; -+ } -+ } -+#else -+ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { -+ if (++bus->idlecount > bus->idletime) { -+ bus->idlecount = 0; -+ if (bus->activity) { -+ bus->activity = FALSE; -+ if (SLPAUTO_ENAB(bus)) { -+ if (!bus->readframes) -+ dhdsdio_bussleep(bus, TRUE); -+ else -+ bus->reqbussleep = TRUE; -+ } -+ else -+ dhdsdio_clkctl(bus, CLK_NONE, FALSE); -+ } -+ } -+ } -+#endif /* DHD_USE_IDLECOUNT */ -+ -+ return bus->ipend; -+} -+ -+#ifdef DHD_DEBUG -+extern int -+dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ uint32 addr, val; -+ int rv; -+ void *pkt; -+ -+ /* Address could be zero if CONSOLE := 0 in dongle Makefile */ -+ if (bus->console_addr == 0) -+ return BCME_UNSUPPORTED; -+ -+ /* Exclusive bus access */ -+ dhd_os_sdlock(bus->dhd); -+ -+ /* Don't allow input if dongle is in reset */ -+ if (bus->dhd->dongle_reset) { -+ dhd_os_sdunlock(bus->dhd); -+ return BCME_NOTREADY; -+ } -+ -+ /* Request clock to allow SDIO accesses */ -+ BUS_WAKE(bus); -+ /* No pend allowed since txpkt is called later, ht clk has to be on */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ /* Zero cbuf_index */ -+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx); -+ val = htol32(0); -+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) -+ goto done; -+ -+ /* Write message into cbuf */ -+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf); -+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) -+ goto done; -+ -+ /* Write length into vcons_in */ -+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in); -+ val = htol32(msglen); -+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) -+ goto done; -+ -+ /* Bump dongle by sending an empty packet on the event channel. -+ * sdpcm_sendup (RX) checks for virtual console input. -+ */ -+ if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) -+ dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE); -+ -+done: -+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { -+ bus->activity = FALSE; -+ dhdsdio_clkctl(bus, CLK_NONE, TRUE); -+ } -+ -+ dhd_os_sdunlock(bus->dhd); -+ -+ return rv; -+} -+#endif /* DHD_DEBUG */ -+ -+#ifdef DHD_DEBUG -+static void -+dhd_dump_cis(uint fn, uint8 *cis) -+{ -+ uint byte, tag, tdata; -+ DHD_INFO(("Function %d CIS:\n", fn)); -+ -+ for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { -+ if ((byte % 16) == 0) -+ DHD_INFO((" ")); -+ DHD_INFO(("%02x ", cis[byte])); -+ if ((byte % 16) == 15) -+ DHD_INFO(("\n")); -+ if (!tdata--) { -+ tag = cis[byte]; -+ if (tag == 0xff) -+ break; -+ else if (!tag) -+ tdata = 0; -+ else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) -+ tdata = cis[byte + 1] + 1; -+ else -+ DHD_INFO(("]")); -+ } -+ } -+ if ((byte % 16) != 15) -+ DHD_INFO(("\n")); -+} -+#endif /* DHD_DEBUG */ -+ -+static bool -+dhdsdio_chipmatch(uint16 chipid) -+{ -+ if (chipid == BCM4325_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4329_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4315_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4319_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4336_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4330_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM43237_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM43362_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4314_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4334_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM43341_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM43239_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4324_CHIP_ID) -+ return TRUE; -+ if (chipid == BCM4335_CHIP_ID) -+ return TRUE; -+ return FALSE; -+} -+ -+static void * -+dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, -+ uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) -+{ -+ int ret; -+ dhd_bus_t *bus; -+#ifdef GET_CUSTOM_MAC_ENABLE -+ struct ether_addr ea_addr; -+#endif /* GET_CUSTOM_MAC_ENABLE */ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ -+ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { -+ DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); -+ } -+ else { -+ DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); -+ } -+ mutex_lock(&_dhd_sdio_mutex_lock_); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -+ -+ /* Init global variables at run-time, not as part of the declaration. -+ * This is required to support init/de-init of the driver. Initialization -+ * of globals as part of the declaration results in non-deterministic -+ * behavior since the value of the globals may be different on the -+ * first time that the driver is initialized vs subsequent initializations. -+ */ -+ dhd_txbound = DHD_TXBOUND; -+ dhd_rxbound = DHD_RXBOUND; -+ dhd_alignctl = TRUE; -+ sd1idle = TRUE; -+ dhd_readahead = TRUE; -+ retrydata = FALSE; -+ dhd_doflow = FALSE; -+ dhd_dongle_memsize = 0; -+ dhd_txminmax = DHD_TXMINMAX; -+ -+ forcealign = TRUE; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); -+ -+ /* We make assumptions about address window mappings */ -+ ASSERT((uintptr)regsva == SI_ENUM_BASE); -+ -+ /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start -+ * means early parse could fail, so here we should get either an ID -+ * we recognize OR (-1) indicating we must request power first. -+ */ -+ /* Check the Vendor ID */ -+ switch (venid) { -+ case 0x0000: -+ case VENDOR_BROADCOM: -+ break; -+ default: -+ DHD_ERROR(("%s: unknown vendor: 0x%04x\n", -+ __FUNCTION__, venid)); -+ goto forcereturn; -+ } -+ -+ /* Check the Device ID and make sure it's one that we support */ -+ switch (devid) { -+ case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ -+ case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ -+ case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ -+ DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__)); -+ break; -+ case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ -+ case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ -+ case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ -+ case 0x4329: -+ DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__)); -+ break; -+ case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ -+ case BCM4315_D11G_ID: /* 4315 802.11g id */ -+ case BCM4315_D11A_ID: /* 4315 802.11a id */ -+ DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__)); -+ break; -+ case BCM4319_D11N_ID: /* 4319 802.11n id */ -+ case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ -+ case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ -+ DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__)); -+ break; -+ case 0: -+ DHD_INFO(("%s: allow device id 0, will check chip internals\n", -+ __FUNCTION__)); -+ break; -+ -+ default: -+ DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", -+ __FUNCTION__, venid, devid)); -+ goto forcereturn; -+ } -+ -+ if (osh == NULL) { -+ /* Ask the OS interface part for an OSL handle */ -+ if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) { -+ DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__)); -+ goto forcereturn; -+ } -+ } -+ -+ /* Allocate private bus interface state */ -+ if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { -+ DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ bzero(bus, sizeof(dhd_bus_t)); -+ bus->sdh = sdh; -+ bus->cl_devid = (uint16)devid; -+ bus->bus = DHD_BUS; -+ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; -+ bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ -+ -+ /* attach the common module */ -+ dhd_common_init(osh); -+ -+ /* attempt to attach to the dongle */ -+ if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { -+ DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ /* Attach to the dhd/OS/network interface */ -+ if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { -+ DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ /* Allocate buffers */ -+ if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { -+ DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ if (!(dhdsdio_probe_init(bus, osh, sdh))) { -+ DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ if (bus->intr) { -+ /* Register interrupt callback, but mask it (not operational yet). */ -+ DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); -+ bcmsdh_intr_disable(sdh); -+ if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { -+ DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", -+ __FUNCTION__, ret)); -+ goto fail; -+ } -+ DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); -+ } else { -+ DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", -+ __FUNCTION__)); -+ } -+ -+ DHD_INFO(("%s: completed!!\n", __FUNCTION__)); -+ -+#ifdef GET_CUSTOM_MAC_ENABLE -+ /* Read MAC address from external customer place */ -+ memset(&ea_addr, 0, sizeof(ea_addr)); -+ ret = dhd_custom_get_mac_address(ea_addr.octet); -+ if (!ret) { -+ memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); -+ } -+#endif /* GET_CUSTOM_MAC_ENABLE */ -+ -+ /* if firmware path present try to download and bring up bus */ -+ if (dhd_download_fw_on_driverload) { -+ if ((ret = dhd_bus_start(bus->dhd)) != 0) { -+ DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); -+ goto fail; -+ } -+ } -+ /* Ok, have the per-port tell the stack we're open for business */ -+ if (dhd_net_attach(bus->dhd, 0) != 0) { -+ DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ mutex_unlock(&_dhd_sdio_mutex_lock_); -+ DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+ -+ return bus; -+ -+fail: -+ dhdsdio_release(bus, osh); -+ -+forcereturn: -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ mutex_unlock(&_dhd_sdio_mutex_lock_); -+ DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -+ -+ return NULL; -+} -+ -+static bool -+dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, -+ uint16 devid) -+{ -+ int err = 0; -+ uint8 clkctl = 0; -+ -+ bus->alp_only = TRUE; -+ bus->sih = NULL; -+ -+ /* Return the window to backplane enumeration space for core access */ -+ if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { -+ DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); -+ } -+ -+#ifdef DHD_DEBUG -+ DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", -+ bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4))); -+ -+#endif /* DHD_DEBUG */ -+ -+ -+ /* Force PLL off until si_attach() programs PLL control regs */ -+ -+ -+ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); -+ if (!err) -+ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); -+ -+ if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { -+ DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", -+ err, DHD_INIT_CLKCTL1, clkctl)); -+ goto fail; -+ } -+ -+#ifdef DHD_DEBUG -+ if (DHD_INFO_ON()) { -+ uint fn, numfn; -+ uint8 *cis[SDIOD_MAX_IOFUNCS]; -+ int err = 0; -+ -+ numfn = bcmsdh_query_iofnum(sdh); -+ ASSERT(numfn <= SDIOD_MAX_IOFUNCS); -+ -+ /* Make sure ALP is available before trying to read CIS */ -+ SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), -+ !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); -+ -+ /* Now request ALP be put on the bus */ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, -+ DHD_INIT_CLKCTL2, &err); -+ OSL_DELAY(65); -+ -+ for (fn = 0; fn <= numfn; fn++) { -+ if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { -+ DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn)); -+ break; -+ } -+ bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); -+ -+ if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { -+ DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err)); -+ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); -+ break; -+ } -+ dhd_dump_cis(fn, cis[fn]); -+ } -+ -+ while (fn-- > 0) { -+ ASSERT(cis[fn]); -+ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); -+ } -+ -+ if (err) { -+ DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n")); -+ goto fail; -+ } -+ } -+#endif /* DHD_DEBUG */ -+ -+ /* si_attach() will provide an SI handle and scan the backplane */ -+ if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, -+ &bus->vars, &bus->varsz))) { -+ DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); -+ -+ if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { -+ DHD_ERROR(("%s: unsupported chip: 0x%04x\n", -+ __FUNCTION__, bus->sih->chip)); -+ goto fail; -+ } -+ -+ if (bus->sih->buscorerev >= 12) -+ dhdsdio_clk_kso_init(bus); -+ else -+ bus->kso = TRUE; -+ -+ if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { -+ } -+ -+ si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); -+ -+ -+ /* Get info on the ARM and SOCRAM cores... */ -+ if (!DHD_NOPMU(bus)) { -+ if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || -+ (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || -+ (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { -+ bus->armrev = si_corerev(bus->sih); -+ } else { -+ DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); -+ goto fail; -+ } -+ -+ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { -+ if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { -+ DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); -+ goto fail; -+ } -+ } else { -+ /* cr4 has a different way to find the RAM size from TCM's */ -+ if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { -+ DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); -+ goto fail; -+ } -+ /* also populate base address */ -+ bus->dongle_ram_base = CR4_RAM_BASE; -+ } -+ bus->ramsize = bus->orig_ramsize; -+ if (dhd_dongle_memsize) -+ dhd_dongle_setmemsize(bus, dhd_dongle_memsize); -+ -+ DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n", -+ bus->ramsize, bus->orig_ramsize)); -+ -+ bus->srmemsize = si_socram_srmem_size(bus->sih); -+ } -+ -+ /* ...but normally deal with the SDPCMDEV core */ -+ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && -+ !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { -+ DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__)); -+ goto fail; -+ } -+ bus->sdpcmrev = si_corerev(bus->sih); -+ -+ /* Set core control so an SDIO reset does a backplane reset */ -+ OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); -+ bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; -+ -+ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && -+ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) -+ { -+ uint32 val; -+ -+ val = R_REG(osh, &bus->regs->corecontrol); -+ val &= ~CC_XMTDATAAVAIL_MODE; -+ val |= CC_XMTDATAAVAIL_CTRL; -+ W_REG(osh, &bus->regs->corecontrol, val); -+ } -+ -+ -+ pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); -+ -+ /* Locate an appropriately-aligned portion of hdrbuf */ -+ bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); -+ -+ /* Set the poll and/or interrupt flags */ -+ bus->intr = (bool)dhd_intr; -+ if ((bus->poll = (bool)dhd_poll)) -+ bus->pollrate = 1; -+ -+#ifdef BCMSDIOH_TXGLOM -+ /* Setting default Glom mode */ -+ bus->glom_mode = SDPCM_TXGLOM_CPY; -+ /* Setting default Glom size */ -+ bus->glomsize = SDPCM_DEFGLOM_SIZE; -+#endif -+ -+ return TRUE; -+ -+fail: -+ if (bus->sih != NULL) { -+ si_detach(bus->sih); -+ bus->sih = NULL; -+ } -+ return FALSE; -+} -+ -+static bool -+dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) -+{ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (bus->dhd->maxctl) { -+ bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; -+ if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) { -+ DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", -+ __FUNCTION__, bus->rxblen)); -+ goto fail; -+ } -+ } -+ /* Allocate buffer to receive glomed packet */ -+ if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { -+ DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", -+ __FUNCTION__, MAX_DATA_BUF)); -+ /* release rxbuf which was already located as above */ -+ if (!bus->rxblen) -+ DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen); -+ goto fail; -+ } -+ -+ /* Align the buffer */ -+ if ((uintptr)bus->databuf % DHD_SDALIGN) -+ bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); -+ else -+ bus->dataptr = bus->databuf; -+ -+ return TRUE; -+ -+fail: -+ return FALSE; -+} -+ -+static bool -+dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) -+{ -+ int32 fnum; -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+#ifdef SDTEST -+ dhdsdio_pktgen_init(bus); -+#endif /* SDTEST */ -+ -+ /* Disable F2 to clear any intermediate frame state on the dongle */ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); -+ -+ bus->dhd->busstate = DHD_BUS_DOWN; -+ bus->sleeping = FALSE; -+ bus->rxflow = FALSE; -+ bus->prev_rxlim_hit = 0; -+ -+ /* Done with backplane-dependent accesses, can drop clock... */ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); -+ -+ /* ...and initialize clock/power states */ -+ bus->clkstate = CLK_SDONLY; -+ bus->idletime = (int32)dhd_idletime; -+ bus->idleclock = DHD_IDLE_ACTIVE; -+ -+ /* Query the SD clock speed */ -+ if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, -+ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { -+ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor")); -+ bus->sd_divisor = -1; -+ } else { -+ DHD_INFO(("%s: Initial value for %s is %d\n", -+ __FUNCTION__, "sd_divisor", bus->sd_divisor)); -+ } -+ -+ /* Query the SD bus mode */ -+ if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, -+ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { -+ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode")); -+ bus->sd_mode = -1; -+ } else { -+ DHD_INFO(("%s: Initial value for %s is %d\n", -+ __FUNCTION__, "sd_mode", bus->sd_mode)); -+ } -+ -+ /* Query the F2 block size, set roundup accordingly */ -+ fnum = 2; -+ if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), -+ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { -+ bus->blocksize = 0; -+ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); -+ } else { -+ DHD_INFO(("%s: Initial value for %s is %d\n", -+ __FUNCTION__, "sd_blocksize", bus->blocksize)); -+ } -+ bus->roundup = MIN(max_roundup, bus->blocksize); -+ -+ /* Query if bus module supports packet chaining, default to use if supported */ -+ if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, -+ &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { -+ bus->sd_rxchain = FALSE; -+ } else { -+ DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n", -+ __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support"))); -+ } -+ bus->use_rxchain = (bool)bus->sd_rxchain; -+ -+ return TRUE; -+} -+ -+bool -+dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, -+ char *pfw_path, char *pnv_path) -+{ -+ bool ret; -+ bus->fw_path = pfw_path; -+ bus->nv_path = pnv_path; -+ -+ ret = dhdsdio_download_firmware(bus, osh, bus->sdh); -+ -+ -+ return ret; -+} -+ -+static bool -+dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) -+{ -+ bool ret; -+ -+ DHD_OS_WAKE_LOCK(bus->dhd); -+ -+ /* Download the firmware */ -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ -+ ret = _dhdsdio_download_firmware(bus) == 0; -+ -+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -+ -+ DHD_OS_WAKE_UNLOCK(bus->dhd); -+ return ret; -+} -+ -+/* Detach and free everything */ -+static void -+dhdsdio_release(dhd_bus_t *bus, osl_t *osh) -+{ -+ bool dongle_isolation = FALSE; -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (bus) { -+ ASSERT(osh); -+ -+ if (bus->dhd) { -+ dongle_isolation = bus->dhd->dongle_isolation; -+ dhd_detach(bus->dhd); -+ } -+ -+ /* De-register interrupt handler */ -+ bcmsdh_intr_disable(bus->sdh); -+ bcmsdh_intr_dereg(bus->sdh); -+ -+ if (bus->dhd) { -+ dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); -+ dhd_free(bus->dhd); -+ bus->dhd = NULL; -+ } -+ -+ dhdsdio_release_malloc(bus, osh); -+ -+#ifdef DHD_DEBUG -+ if (bus->console.buf != NULL) -+ MFREE(osh, bus->console.buf, bus->console.bufsize); -+#endif -+ -+ MFREE(osh, bus, sizeof(dhd_bus_t)); -+ } -+ -+ if (osh) -+ dhd_osl_detach(osh); -+ -+ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -+} -+ -+static void -+dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) -+{ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (bus->dhd && bus->dhd->dongle_reset) -+ return; -+ -+ if (bus->rxbuf) { -+#ifndef CONFIG_DHD_USE_STATIC_BUF -+ MFREE(osh, bus->rxbuf, bus->rxblen); -+#endif -+ bus->rxctl = bus->rxbuf = NULL; -+ bus->rxlen = 0; -+ } -+ -+ if (bus->databuf) { -+#ifndef CONFIG_DHD_USE_STATIC_BUF -+ MFREE(osh, bus->databuf, MAX_DATA_BUF); -+#endif -+ bus->databuf = NULL; -+ } -+ -+ if (bus->vars && bus->varsz) { -+ MFREE(osh, bus->vars, bus->varsz); -+ bus->vars = NULL; -+ } -+ -+} -+ -+ -+static void -+dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) -+{ -+ DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, -+ bus->dhd, bus->dhd->dongle_reset)); -+ -+ if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) -+ return; -+ -+ if (bus->sih) { -+#if !defined(BCMLXSDMMC) -+ if (bus->dhd) { -+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); -+ } -+ if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) -+ si_watchdog(bus->sih, 4); -+#endif /* !defined(BCMLXSDMMC) */ -+ if (bus->dhd) { -+ dhdsdio_clkctl(bus, CLK_NONE, FALSE); -+ } -+ si_detach(bus->sih); -+ bus->sih = NULL; -+ if (bus->vars && bus->varsz) -+ MFREE(osh, bus->vars, bus->varsz); -+ bus->vars = NULL; -+ } -+ -+ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -+} -+ -+static void -+dhdsdio_disconnect(void *ptr) -+{ -+ dhd_bus_t *bus = (dhd_bus_t *)ptr; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ -+ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { -+ DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); -+ } -+ else { -+ DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); -+ } -+ mutex_lock(&_dhd_sdio_mutex_lock_); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -+ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ if (bus) { -+ ASSERT(bus->dhd); -+ dhdsdio_release(bus, bus->dhd->osh); -+ } -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ mutex_unlock(&_dhd_sdio_mutex_lock_); -+ DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -+ -+ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -+} -+ -+ -+/* Register/Unregister functions are called by the main DHD entry -+ * point (e.g. module insertion) to link with the bus driver, in -+ * order to look for or await the device. -+ */ -+ -+static bcmsdh_driver_t dhd_sdio = { -+ dhdsdio_probe, -+ dhdsdio_disconnect -+}; -+ -+int -+dhd_bus_register(void) -+{ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ return bcmsdh_register(&dhd_sdio); -+} -+ -+void -+dhd_bus_unregister(void) -+{ -+ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -+ -+ bcmsdh_unregister(); -+} -+ -+#if defined(BCMLXSDMMC) -+/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -+int dhd_bus_reg_sdio_notify(void* semaphore) -+{ -+ return bcmsdh_reg_sdio_notify(semaphore); -+} -+ -+void dhd_bus_unreg_sdio_notify(void) -+{ -+ bcmsdh_unreg_sdio_notify(); -+} -+#endif /* defined(BCMLXSDMMC) */ -+ -+#ifdef BCMEMBEDIMAGE -+static int -+dhdsdio_download_code_array(struct dhd_bus *bus) -+{ -+ int bcmerror = -1; -+ int offset = 0; -+ unsigned char *ularray = NULL; -+ -+ DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); -+ -+ /* Download image */ -+ while ((offset + MEMBLOCK) < sizeof(dlarray)) { -+ bcmerror = dhdsdio_membytes(bus, TRUE, offset, -+ (uint8 *) (dlarray + offset), MEMBLOCK); -+ if (bcmerror) { -+ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", -+ __FUNCTION__, bcmerror, MEMBLOCK, offset)); -+ goto err; -+ } -+ -+ offset += MEMBLOCK; -+ } -+ -+ if (offset < sizeof(dlarray)) { -+ bcmerror = dhdsdio_membytes(bus, TRUE, offset, -+ (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); -+ if (bcmerror) { -+ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", -+ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); -+ goto err; -+ } -+ } -+ -+#ifdef DHD_DEBUG -+ /* Upload and compare the downloaded code */ -+ { -+ ularray = MALLOC(bus->dhd->osh, bus->ramsize); -+ /* Upload image to verify downloaded contents. */ -+ offset = 0; -+ memset(ularray, 0xaa, bus->ramsize); -+ while ((offset + MEMBLOCK) < sizeof(dlarray)) { -+ bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); -+ if (bcmerror) { -+ DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", -+ __FUNCTION__, bcmerror, MEMBLOCK, offset)); -+ goto err; -+ } -+ -+ offset += MEMBLOCK; -+ } -+ -+ if (offset < sizeof(dlarray)) { -+ bcmerror = dhdsdio_membytes(bus, FALSE, offset, -+ ularray + offset, sizeof(dlarray) - offset); -+ if (bcmerror) { -+ DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", -+ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); -+ goto err; -+ } -+ } -+ -+ if (memcmp(dlarray, ularray, sizeof(dlarray))) { -+ DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", -+ __FUNCTION__, dlimagename, dlimagever, dlimagedate)); -+ goto err; -+ } else -+ DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", -+ __FUNCTION__, dlimagename, dlimagever, dlimagedate)); -+ -+ } -+#endif /* DHD_DEBUG */ -+ -+err: -+ if (ularray) -+ MFREE(bus->dhd->osh, ularray, bus->ramsize); -+ return bcmerror; -+} -+#endif /* BCMEMBEDIMAGE */ -+ -+static int -+dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) -+{ -+ int bcmerror = -1; -+ int offset = 0; -+ int len; -+ void *image = NULL; -+ uint8 *memblock = NULL, *memptr; -+ -+ DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); -+ -+ image = dhd_os_open_image(pfw_path); -+ if (image == NULL) -+ goto err; -+ -+ memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); -+ if (memblock == NULL) { -+ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); -+ goto err; -+ } -+ if ((uint32)(uintptr)memblock % DHD_SDALIGN) -+ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); -+ -+ /* Download image */ -+ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { -+ if (len < 0) { -+ DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); -+ bcmerror = BCME_ERROR; -+ goto err; -+ } -+ bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); -+ if (bcmerror) { -+ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", -+ __FUNCTION__, bcmerror, MEMBLOCK, offset)); -+ goto err; -+ } -+ -+ offset += MEMBLOCK; -+ } -+ -+err: -+ if (memblock) -+ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); -+ -+ if (image) -+ dhd_os_close_image(image); -+ -+ return bcmerror; -+} -+ -+/* -+ EXAMPLE: nvram_array -+ nvram_arry format: -+ name=value -+ Use carriage return at the end of each assignment, and an empty string with -+ carriage return at the end of array. -+ -+ For example: -+ unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; -+ Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. -+ -+ Search "EXAMPLE: nvram_array" to see how the array is activated. -+*/ -+ -+void -+dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) -+{ -+ bus->nvram_params = nvram_params; -+} -+ -+static int -+dhdsdio_download_nvram(struct dhd_bus *bus) -+{ -+ int bcmerror = -1; -+ uint len; -+ void * image = NULL; -+ char * memblock = NULL; -+ char *bufp; -+ char *pnv_path; -+ bool nvram_file_exists; -+ -+ pnv_path = bus->nv_path; -+ -+ nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); -+ if (!nvram_file_exists && (bus->nvram_params == NULL)) -+ return (0); -+ -+ if (nvram_file_exists) { -+ image = dhd_os_open_image(pnv_path); -+ if (image == NULL) -+ goto err; -+ } -+ -+ memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); -+ if (memblock == NULL) { -+ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", -+ __FUNCTION__, MAX_NVRAMBUF_SIZE)); -+ goto err; -+ } -+ -+ /* Download variables */ -+ if (nvram_file_exists) { -+ len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); -+ } -+ else { -+ len = strlen(bus->nvram_params); -+ ASSERT(len <= MAX_NVRAMBUF_SIZE); -+ memcpy(memblock, bus->nvram_params, len); -+ } -+ if (len > 0 && len < MAX_NVRAMBUF_SIZE) { -+ bufp = (char *)memblock; -+ bufp[len] = 0; -+ len = process_nvram_vars(bufp, len); -+ if (len % 4) { -+ len += 4 - (len % 4); -+ } -+ bufp += len; -+ *bufp++ = 0; -+ if (len) -+ bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); -+ if (bcmerror) { -+ DHD_ERROR(("%s: error downloading vars: %d\n", -+ __FUNCTION__, bcmerror)); -+ } -+ } -+ else { -+ DHD_ERROR(("%s: error reading nvram file: %d\n", -+ __FUNCTION__, len)); -+ bcmerror = BCME_SDIO_ERROR; -+ } -+ -+err: -+ if (memblock) -+ MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); -+ -+ if (image) -+ dhd_os_close_image(image); -+ -+ return bcmerror; -+} -+ -+static int -+_dhdsdio_download_firmware(struct dhd_bus *bus) -+{ -+ int bcmerror = -1; -+ -+ bool embed = FALSE; /* download embedded firmware */ -+ bool dlok = FALSE; /* download firmware succeeded */ -+ -+ /* Out immediately if no image to download */ -+ if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { -+#ifdef BCMEMBEDIMAGE -+ embed = TRUE; -+#else -+ return 0; -+#endif -+ } -+ -+ /* Keep arm in reset */ -+ if (dhdsdio_download_state(bus, TRUE)) { -+ DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ /* External image takes precedence if specified */ -+ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { -+ if (dhdsdio_download_code_file(bus, bus->fw_path)) { -+ DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); -+#ifdef BCMEMBEDIMAGE -+ embed = TRUE; -+#else -+ goto err; -+#endif -+ } -+ else { -+ embed = FALSE; -+ dlok = TRUE; -+ } -+ } -+#ifdef BCMEMBEDIMAGE -+ if (embed) { -+ if (dhdsdio_download_code_array(bus)) { -+ DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); -+ goto err; -+ } -+ else { -+ dlok = TRUE; -+ } -+ } -+#else -+ BCM_REFERENCE(embed); -+#endif -+ if (!dlok) { -+ DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ /* EXAMPLE: nvram_array */ -+ /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ -+ /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ -+ -+ /* External nvram takes precedence if specified */ -+ if (dhdsdio_download_nvram(bus)) { -+ DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ /* Take arm out of reset */ -+ if (dhdsdio_download_state(bus, FALSE)) { -+ DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); -+ goto err; -+ } -+ -+ bcmerror = 0; -+ -+err: -+ return bcmerror; -+} -+ -+static int -+dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, -+ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) -+{ -+ int status; -+ -+ if (!KSO_ENAB(bus)) { -+ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); -+ return BCME_NODEVICE; -+ } -+ -+ status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); -+ -+ return status; -+} -+ -+static int -+dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, -+ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) -+{ -+ if (!KSO_ENAB(bus)) { -+ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); -+ return BCME_NODEVICE; -+ } -+ -+ return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle)); -+} -+ -+#ifdef BCMSDIOH_TXGLOM -+static void -+dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len) -+{ -+ bcmsdh_glom_post(bus->sdh, frame, len); -+} -+ -+static void -+dhd_bcmsdh_glom_clear(dhd_bus_t *bus) -+{ -+ bcmsdh_glom_clear(bus->sdh); -+} -+#endif -+ -+uint -+dhd_bus_chip(struct dhd_bus *bus) -+{ -+ ASSERT(bus->sih != NULL); -+ return bus->sih->chip; -+} -+ -+void * -+dhd_bus_pub(struct dhd_bus *bus) -+{ -+ return bus->dhd; -+} -+ -+void * -+dhd_bus_txq(struct dhd_bus *bus) -+{ -+ return &bus->txq; -+} -+ -+uint -+dhd_bus_hdrlen(struct dhd_bus *bus) -+{ -+ return SDPCM_HDRLEN; -+} -+ -+int -+dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) -+{ -+ int bcmerror = 0; -+ dhd_bus_t *bus; -+ -+ bus = dhdp->bus; -+ -+ if (flag == TRUE) { -+ if (!bus->dhd->dongle_reset) { -+ dhd_os_sdlock(dhdp); -+ dhd_os_wd_timer(dhdp, 0); -+#if !defined(IGNORE_ETH0_DOWN) -+ /* Force flow control as protection when stop come before ifconfig_down */ -+ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); -+#endif /* !defined(IGNORE_ETH0_DOWN) */ -+ /* Expect app to have torn down any connection before calling */ -+ /* Stop the bus, disable F2 */ -+ dhd_bus_stop(bus, FALSE); -+ -+#if defined(OOB_INTR_ONLY) -+ /* Clean up any pending IRQ */ -+ bcmsdh_set_irq(FALSE); -+#endif /* defined(OOB_INTR_ONLY) */ -+ -+ /* Clean tx/rx buffer pointers, detach from the dongle */ -+ dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); -+ -+ bus->dhd->dongle_reset = TRUE; -+ bus->dhd->up = FALSE; -+#ifdef BCMSDIOH_TXGLOM -+ dhd_txglom_enable(dhdp, FALSE); -+#endif -+ dhd_os_sdunlock(dhdp); -+ -+ DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); -+ /* App can now remove power from device */ -+ } else -+ bcmerror = BCME_SDIO_ERROR; -+ } else { -+ /* App must have restored power to device before calling */ -+ -+ DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__)); -+ -+ if (bus->dhd->dongle_reset) { -+ /* Turn on WLAN */ -+#ifdef DHDTHREAD -+ dhd_os_sdlock(dhdp); -+#endif /* DHDTHREAD */ -+ /* Reset SD client */ -+ bcmsdh_reset(bus->sdh); -+ -+ /* Attempt to re-attach & download */ -+ if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, -+ (uint32 *)SI_ENUM_BASE, -+ bus->cl_devid)) { -+ /* Attempt to download binary to the dongle */ -+ if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && -+ dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) { -+ -+ /* Re-init bus, enable F2 transfer */ -+ bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); -+ if (bcmerror == BCME_OK) { -+#if defined(OOB_INTR_ONLY) -+ bcmsdh_set_irq(TRUE); -+ dhd_enable_oob_intr(bus, TRUE); -+#endif /* defined(OOB_INTR_ONLY) */ -+ -+ bus->dhd->dongle_reset = FALSE; -+ bus->dhd->up = TRUE; -+ -+#if !defined(IGNORE_ETH0_DOWN) -+ /* Restore flow control */ -+ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); -+#endif -+ dhd_os_wd_timer(dhdp, dhd_watchdog_ms); -+#ifdef BCMSDIOH_TXGLOM -+ if ((dhdp->busstate == DHD_BUS_DATA) && -+ bcmsdh_glom_enabled()) { -+ dhd_txglom_enable(dhdp, TRUE); -+ } -+#endif /* BCMSDIOH_TXGLOM */ -+ DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); -+ } else { -+ dhd_bus_stop(bus, FALSE); -+ dhdsdio_release_dongle(bus, bus->dhd->osh, -+ TRUE, FALSE); -+ } -+ } else -+ bcmerror = BCME_SDIO_ERROR; -+ } else -+ bcmerror = BCME_SDIO_ERROR; -+ -+#ifdef DHDTHREAD -+ dhd_os_sdunlock(dhdp); -+#endif /* DHDTHREAD */ -+ } else { -+ bcmerror = BCME_SDIO_ERROR; -+ DHD_INFO(("%s called when dongle is not in reset\n", -+ __FUNCTION__)); -+ DHD_INFO(("Will call dhd_bus_start instead\n")); -+ sdioh_start(NULL, 1); -+ if ((bcmerror = dhd_bus_start(dhdp)) != 0) -+ DHD_ERROR(("%s: dhd_bus_start fail with %d\n", -+ __FUNCTION__, bcmerror)); -+ } -+ } -+ return bcmerror; -+} -+ -+/* Get Chip ID version */ -+uint dhd_bus_chip_id(dhd_pub_t *dhdp) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ -+ return bus->sih->chip; -+} -+ -+/* Get Chip Rev ID version */ -+uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ -+ return bus->sih->chiprev; -+} -+ -+/* Get Chip Pkg ID version */ -+uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) -+{ -+ dhd_bus_t *bus = dhdp->bus; -+ -+ return bus->sih->chippkg; -+} -+ -+int -+dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) -+{ -+ dhd_bus_t *bus; -+ -+ bus = dhdp->bus; -+ return dhdsdio_membytes(bus, set, address, data, size); -+} -diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h -new file mode 100644 -index 00000000..5a64e6fd ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h -@@ -0,0 +1,287 @@ -+/* -+* Copyright (C) 1999-2012, Broadcom Corporation -+* -+* Unless you and Broadcom execute a separate written software license -+* agreement governing use of this software, this software is licensed to you -+* under the terms of the GNU General Public License version 2 (the "GPL"), -+* available at http://www.broadcom.com/licenses/GPLv2.php, with the -+* following added to such license: -+* -+* As a special exception, the copyright holders of this software give you -+* permission to link this software with independent modules, and to copy and -+* distribute the resulting executable under terms of your choice, provided that -+* you also meet, for each linked independent module, the terms and conditions of -+* the license of that module. An independent module is a module which is not -+* derived from this software. The special exception does not apply to any -+* modifications of the software. -+* -+* Notwithstanding the above, under no circumstances may you combine this -+* software in any way with any other Broadcom software provided under a license -+* other than the GPL, without Broadcom's express prior written consent. -+* $Id: dhd_wlfc.h 361006 2012-10-05 07:45:51Z $ -+* -+*/ -+#ifndef __wlfc_host_driver_definitions_h__ -+#define __wlfc_host_driver_definitions_h__ -+ -+/* 16 bits will provide an absolute max of 65536 slots */ -+#define WLFC_HANGER_MAXITEMS 1024 -+ -+#define WLFC_HANGER_ITEM_STATE_FREE 1 -+#define WLFC_HANGER_ITEM_STATE_INUSE 2 -+#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 -+#define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */ -+#define WLFC_PKTID_HSLOT_SHIFT 8 -+ -+/* x -> TXSTATUS TAG to/from firmware */ -+#define WLFC_PKTID_HSLOT_GET(x) \ -+ (((x) >> WLFC_PKTID_HSLOT_SHIFT) & WLFC_PKTID_HSLOT_MASK) -+#define WLFC_PKTID_HSLOT_SET(var, slot) \ -+ ((var) = ((var) & ~(WLFC_PKTID_HSLOT_MASK << WLFC_PKTID_HSLOT_SHIFT)) | \ -+ (((slot) & WLFC_PKTID_HSLOT_MASK) << WLFC_PKTID_HSLOT_SHIFT)) -+ -+#define WLFC_PKTID_FREERUNCTR_MASK 0xff -+ -+#define WLFC_PKTID_FREERUNCTR_GET(x) ((x) & WLFC_PKTID_FREERUNCTR_MASK) -+#define WLFC_PKTID_FREERUNCTR_SET(var, ctr) \ -+ ((var) = (((var) & ~WLFC_PKTID_FREERUNCTR_MASK) | \ -+ (((ctr) & WLFC_PKTID_FREERUNCTR_MASK)))) -+ -+#define WLFC_PKTQ_PENQ(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec)))? \ -+ NULL : pktq_penq((pq), (prec), (p))) -+#define WLFC_PKTQ_PENQ_HEAD(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec))) ? \ -+ NULL : pktq_penq_head((pq), (prec), (p))) -+ -+typedef enum ewlfc_packet_state { -+ eWLFC_PKTTYPE_NEW, -+ eWLFC_PKTTYPE_DELAYED, -+ eWLFC_PKTTYPE_SUPPRESSED, -+ eWLFC_PKTTYPE_MAX -+} ewlfc_packet_state_t; -+ -+typedef enum ewlfc_mac_entry_action { -+ eWLFC_MAC_ENTRY_ACTION_ADD, -+ eWLFC_MAC_ENTRY_ACTION_DEL, -+ eWLFC_MAC_ENTRY_ACTION_UPDATE, -+ eWLFC_MAC_ENTRY_ACTION_MAX -+} ewlfc_mac_entry_action_t; -+ -+typedef struct wlfc_hanger_item { -+ uint8 state; -+ uint8 gen; -+ uint8 pad[2]; -+ uint32 identifier; -+ void* pkt; -+#ifdef PROP_TXSTATUS_DEBUG -+ uint32 push_time; -+#endif -+} wlfc_hanger_item_t; -+ -+typedef struct wlfc_hanger { -+ int max_items; -+ uint32 pushed; -+ uint32 popped; -+ uint32 failed_to_push; -+ uint32 failed_to_pop; -+ uint32 failed_slotfind; -+ wlfc_hanger_item_t items[1]; -+ uint32 slot_pos; -+} wlfc_hanger_t; -+ -+#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ -+ sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) -+ -+#define WLFC_STATE_OPEN 1 -+#define WLFC_STATE_CLOSE 2 -+ -+#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ -+ -+#define WLFC_PSQ_LEN 2048 -+ -+#define WLFC_SENDQ_LEN 256 -+ -+ -+#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) -+#define WLFC_FLOWCONTROL_LOWATER 256 -+ -+ -+typedef struct wlfc_mac_descriptor { -+ uint8 occupied; -+ uint8 interface_id; -+ uint8 iftype; -+ uint8 state; -+ uint8 ac_bitmap; /* for APSD */ -+ uint8 requested_credit; -+ uint8 requested_packet; -+ uint8 ea[ETHER_ADDR_LEN]; -+ /* -+ maintain (MAC,AC) based seq count for -+ packets going to the device. As well as bc/mc. -+ */ -+ uint8 seq[AC_COUNT + 1]; -+ uint8 generation; -+ struct pktq psq; -+ /* The AC pending bitmap that was reported to the fw at last change */ -+ uint8 traffic_lastreported_bmp; -+ /* The new AC pending bitmap */ -+ uint8 traffic_pending_bmp; -+ /* 1= send on next opportunity */ -+ uint8 send_tim_signal; -+ uint8 mac_handle; -+ uint transit_count; -+ uint suppr_transit_count; -+ uint suppress_count; -+ uint8 suppressed; -+ -+#ifdef PROP_TXSTATUS_DEBUG -+ uint32 dstncredit_sent_packets; -+ uint32 dstncredit_acks; -+ uint32 opened_ct; -+ uint32 closed_ct; -+#endif -+} wlfc_mac_descriptor_t; -+ -+#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ -+ entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) -+ -+#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ -+#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] -+ -+typedef struct athost_wl_stat_counters { -+ uint32 pktin; -+ uint32 pkt2bus; -+ uint32 pktdropped; -+ uint32 tlv_parse_failed; -+ uint32 rollback; -+ uint32 rollback_failed; -+ uint32 sendq_full_error; -+ uint32 delayq_full_error; -+ uint32 credit_request_failed; -+ uint32 packet_request_failed; -+ uint32 mac_update_failed; -+ uint32 psmode_update_failed; -+ uint32 interface_update_failed; -+ uint32 wlfc_header_only_pkt; -+ uint32 txstatus_in; -+ uint32 d11_suppress; -+ uint32 wl_suppress; -+ uint32 bad_suppress; -+ uint32 pkt_freed; -+ uint32 pkt_free_err; -+ uint32 psq_wlsup_retx; -+ uint32 psq_wlsup_enq; -+ uint32 psq_d11sup_retx; -+ uint32 psq_d11sup_enq; -+ uint32 psq_hostq_retx; -+ uint32 psq_hostq_enq; -+ uint32 mac_handle_notfound; -+ uint32 wlc_tossed_pkts; -+ uint32 dhd_hdrpulls; -+ uint32 generic_error; -+ /* an extra one for bc/mc traffic */ -+ uint32 sendq_pkts[AC_COUNT + 1]; -+#ifdef PROP_TXSTATUS_DEBUG -+ /* all pkt2bus -> txstatus latency accumulated */ -+ uint32 latency_sample_count; -+ uint32 total_status_latency; -+ uint32 latency_most_recent; -+ int idx_delta; -+ uint32 deltas[10]; -+ uint32 fifo_credits_sent[6]; -+ uint32 fifo_credits_back[6]; -+ uint32 dropped_qfull[6]; -+ uint32 signal_only_pkts_sent; -+ uint32 signal_only_pkts_freed; -+#endif -+} athost_wl_stat_counters_t; -+ -+#ifdef PROP_TXSTATUS_DEBUG -+#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ -+ (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) -+#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ -+ (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) -+#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ -+ (ctx)->stats.dropped_qfull[(ac)]++;} while (0) -+#else -+#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) -+#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) -+#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) -+#endif -+ -+#define WLFC_FCMODE_NONE 0 -+#define WLFC_FCMODE_IMPLIED_CREDIT 1 -+#define WLFC_FCMODE_EXPLICIT_CREDIT 2 -+ -+/* How long to defer borrowing in milliseconds */ -+#define WLFC_BORROW_DEFER_PERIOD_MS 100 -+ -+/* Mask to represent available ACs (note: BC/MC is ignored */ -+#define WLFC_AC_MASK 0xF -+ -+/* Mask to check for only on-going AC_BE traffic */ -+#define WLFC_AC_BE_TRAFFIC_ONLY 0xD -+ -+typedef struct athost_wl_status_info { -+ uint8 last_seqid_to_wlc; -+ -+ /* OSL handle */ -+ osl_t* osh; -+ /* dhd pub */ -+ void* dhdp; -+ -+ /* stats */ -+ athost_wl_stat_counters_t stats; -+ -+ /* the additional ones are for bc/mc and ATIM FIFO */ -+ int FIFO_credit[AC_COUNT + 2]; -+ -+ /* Credit borrow counts for each FIFO from each of the other FIFOs */ -+ int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; -+ -+ struct pktq SENDQ; -+ -+ /* packet hanger and MAC->handle lookup table */ -+ void* hanger; -+ struct { -+ /* table for individual nodes */ -+ wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; -+ /* table for interfaces */ -+ wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; -+ /* OS may send packets to unknown (unassociated) destinations */ -+ /* A place holder for bc/mc and packets to unknown destinations */ -+ wlfc_mac_descriptor_t other; -+ } destination_entries; -+ /* token position for different priority packets */ -+ uint8 token_pos[AC_COUNT+1]; -+ /* ON/OFF state for flow control to the host network interface */ -+ uint8 hostif_flow_state[WLFC_MAX_IFNUM]; -+ uint8 host_ifidx; -+ /* to flow control an OS interface */ -+ uint8 toggle_host_if; -+ -+ /* -+ Mode in which the dhd flow control shall operate. Must be set before -+ traffic starts to the device. -+ 0 - Do not do any proptxtstatus flow control -+ 1 - Use implied credit from a packet status -+ 2 - Use explicit credit -+ */ -+ uint8 proptxstatus_mode; -+ -+ /* To borrow credits */ -+ uint8 allow_credit_borrow; -+ -+ /* Timestamp to compute how long to defer borrowing for */ -+ uint32 borrow_defer_timestamp; -+ -+} athost_wl_status_info_t; -+ -+int dhd_wlfc_enable(dhd_pub_t *dhd); -+int dhd_wlfc_interface_event(struct dhd_info *, -+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea); -+int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data); -+int dhd_wlfc_event(struct dhd_info *dhd); -+int dhd_os_wlfc_block(dhd_pub_t *pub); -+int dhd_os_wlfc_unblock(dhd_pub_t *pub); -+ -+#endif /* __wlfc_host_driver_definitions_h__ */ -diff --git a/drivers/net/wireless/bcmdhd/dngl_stats.h b/drivers/net/wireless/bcmdhd/dngl_stats.h -new file mode 100644 -index 00000000..5e5a2e2e ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dngl_stats.h -@@ -0,0 +1,43 @@ -+/* -+ * Common stats definitions for clients of dongle -+ * ports -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dngl_stats.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _dngl_stats_h_ -+#define _dngl_stats_h_ -+ -+typedef struct { -+ unsigned long rx_packets; /* total packets received */ -+ unsigned long tx_packets; /* total packets transmitted */ -+ unsigned long rx_bytes; /* total bytes received */ -+ unsigned long tx_bytes; /* total bytes transmitted */ -+ unsigned long rx_errors; /* bad packets received */ -+ unsigned long tx_errors; /* packet transmit problems */ -+ unsigned long rx_dropped; /* packets dropped by dongle */ -+ unsigned long tx_dropped; /* packets dropped by dongle */ -+ unsigned long multicast; /* multicast packets received */ -+} dngl_stats_t; -+ -+#endif /* _dngl_stats_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h -new file mode 100644 -index 00000000..0e37df6e ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h -@@ -0,0 +1,40 @@ -+/* -+ * Dongle WL Header definitions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dngl_wlhdr.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _dngl_wlhdr_h_ -+#define _dngl_wlhdr_h_ -+ -+typedef struct wl_header { -+ uint8 type; /* Header type */ -+ uint8 version; /* Header version */ -+ int8 rssi; /* RSSI */ -+ uint8 pad; /* Unused */ -+} wl_header_t; -+ -+#define WL_HEADER_LEN sizeof(wl_header_t) -+#define WL_HEADER_TYPE 0 -+#define WL_HEADER_VER 1 -+#endif /* _dngl_wlhdr_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c -new file mode 100644 -index 00000000..e639015b ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/hndpmu.c -@@ -0,0 +1,208 @@ -+/* -+ * Misc utility routines for accessing PMU corerev specific features -+ * of the SiliconBackplane-based Broadcom chips. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: hndpmu.c 354194 2012-08-30 08:39:03Z $ -+ */ -+ -+#include <bcm_cfg.h> -+#include <typedefs.h> -+#include <bcmdefs.h> -+#include <osl.h> -+#include <bcmutils.h> -+#include <siutils.h> -+#include <bcmdevs.h> -+#include <hndsoc.h> -+#include <sbchipc.h> -+#include <hndpmu.h> -+ -+#define PMU_ERROR(args) -+ -+#define PMU_MSG(args) -+ -+/* To check in verbose debugging messages not intended -+ * to be on except on private builds. -+ */ -+#define PMU_NONE(args) -+ -+ -+/* SDIO Pad drive strength to select value mappings. -+ * The last strength value in each table must be 0 (the tri-state value). -+ */ -+typedef struct { -+ uint8 strength; /* Pad Drive Strength in mA */ -+ uint8 sel; /* Chip-specific select value */ -+} sdiod_drive_str_t; -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 1 */ -+static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = { -+ {4, 0x2}, -+ {2, 0x3}, -+ {1, 0x0}, -+ {0, 0x0} }; -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ -+static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = { -+ {12, 0x7}, -+ {10, 0x6}, -+ {8, 0x5}, -+ {6, 0x4}, -+ {4, 0x2}, -+ {2, 0x1}, -+ {0, 0x0} }; -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ -+static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { -+ {32, 0x7}, -+ {26, 0x6}, -+ {22, 0x5}, -+ {16, 0x4}, -+ {12, 0x3}, -+ {8, 0x2}, -+ {4, 0x1}, -+ {0, 0x0} }; -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ -+static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { -+ {32, 0x6}, -+ {26, 0x7}, -+ {22, 0x4}, -+ {16, 0x5}, -+ {12, 0x2}, -+ {8, 0x3}, -+ {4, 0x0}, -+ {0, 0x1} }; -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ -+static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { -+ {6, 0x7}, -+ {5, 0x6}, -+ {4, 0x5}, -+ {3, 0x4}, -+ {2, 0x2}, -+ {1, 0x1}, -+ {0, 0x0} }; -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ -+ -+/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ -+static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { -+ {3, 0x3}, -+ {2, 0x2}, -+ {1, 0x1}, -+ {0, 0x0} }; -+ -+#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) -+ -+void -+si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) -+{ -+ chipcregs_t *cc; -+ uint origidx, intr_val = 0; -+ sdiod_drive_str_t *str_tab = NULL; -+ uint32 str_mask = 0; -+ uint32 str_shift = 0; -+ -+ if (!(sih->cccaps & CC_CAP_PMU)) { -+ return; -+ } -+ -+ /* Remember original core before switch to chipc */ -+ cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); -+ -+ switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) { -+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): -+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; -+ str_mask = 0x30000000; -+ str_shift = 28; -+ break; -+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): -+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): -+ case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): -+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; -+ str_mask = 0x00003800; -+ str_shift = 11; -+ break; -+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): -+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): -+ if (sih->pmurev == 8) { -+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; -+ } -+ else if (sih->pmurev == 11) { -+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; -+ } -+ str_mask = 0x00003800; -+ str_shift = 11; -+ break; -+ case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): -+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; -+ str_mask = 0x00003800; -+ str_shift = 11; -+ break; -+ case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): -+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; -+ str_mask = 0x00003800; -+ str_shift = 11; -+ break; -+ case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): -+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; -+ str_mask = 0x00001800; -+ str_shift = 11; -+ break; -+ default: -+ PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", -+ bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); -+ -+ break; -+ } -+ -+ if (str_tab != NULL && cc != NULL) { -+ uint32 cc_data_temp; -+ int i; -+ -+ /* Pick the lowest available drive strength equal or greater than the -+ * requested strength. Drive strength of 0 requests tri-state. -+ */ -+ for (i = 0; drivestrength < str_tab[i].strength; i++) -+ ; -+ -+ if (i > 0 && drivestrength > str_tab[i].strength) -+ i--; -+ -+ W_REG(osh, &cc->chipcontrol_addr, 1); -+ cc_data_temp = R_REG(osh, &cc->chipcontrol_data); -+ cc_data_temp &= ~str_mask; -+ cc_data_temp |= str_tab[i].sel << str_shift; -+ W_REG(osh, &cc->chipcontrol_data, cc_data_temp); -+ -+ PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", -+ drivestrength, str_tab[i].strength)); -+ } -+ -+ /* Return to original core */ -+ si_restore_core(sih, origidx, intr_val); -+} -diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile -new file mode 100644 -index 00000000..42b3b689 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/Makefile -@@ -0,0 +1,53 @@ -+#!/bin/bash -+# -+# This script serves following purpose: -+# -+# 1. It generates native version information by querying -+# automerger maintained database to see where src/include -+# came from -+# 2. For select components, as listed in compvers.sh -+# it generates component version files -+# -+# Copyright 2005, Broadcom, Inc. -+# -+# $Id: Makefile 241686 2011-02-19 00:22:45Z $ -+# -+ -+SRCBASE := .. -+ -+TARGETS := epivers.h -+ -+ifdef VERBOSE -+export VERBOSE -+endif -+ -+all release: epivers compvers -+ -+# Generate epivers.h for native branch version -+epivers: -+ bash epivers.sh -+ -+# Generate epivers.h for native branch version -+compvers: -+ @if [ -s "compvers.sh" ]; then \ -+ echo "Generating component versions, if any"; \ -+ bash compvers.sh; \ -+ else \ -+ echo "Skipping component version generation"; \ -+ fi -+ -+# Generate epivers.h for native branch version -+clean_compvers: -+ @if [ -s "compvers.sh" ]; then \ -+ echo "bash compvers.sh clean"; \ -+ bash compvers.sh clean; \ -+ else \ -+ echo "Skipping component version clean"; \ -+ fi -+ -+clean: -+ rm -f $(TARGETS) *.prev -+ -+clean_all: clean clean_compvers -+ -+.PHONY: all release clean epivers compvers clean_compvers -diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h -new file mode 100644 -index 00000000..63513e6f ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/aidmp.h -@@ -0,0 +1,375 @@ -+/* -+ * Broadcom AMBA Interconnect definitions. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: aidmp.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _AIDMP_H -+#define _AIDMP_H -+ -+ -+#define MFGID_ARM 0x43b -+#define MFGID_BRCM 0x4bf -+#define MFGID_MIPS 0x4a7 -+ -+ -+#define CC_SIM 0 -+#define CC_EROM 1 -+#define CC_CORESIGHT 9 -+#define CC_VERIF 0xb -+#define CC_OPTIMO 0xd -+#define CC_GEN 0xe -+#define CC_PRIMECELL 0xf -+ -+ -+#define ER_EROMENTRY 0x000 -+#define ER_REMAPCONTROL 0xe00 -+#define ER_REMAPSELECT 0xe04 -+#define ER_MASTERSELECT 0xe10 -+#define ER_ITCR 0xf00 -+#define ER_ITIP 0xf04 -+ -+ -+#define ER_TAG 0xe -+#define ER_TAG1 0x6 -+#define ER_VALID 1 -+#define ER_CI 0 -+#define ER_MP 2 -+#define ER_ADD 4 -+#define ER_END 0xe -+#define ER_BAD 0xffffffff -+ -+ -+#define CIA_MFG_MASK 0xfff00000 -+#define CIA_MFG_SHIFT 20 -+#define CIA_CID_MASK 0x000fff00 -+#define CIA_CID_SHIFT 8 -+#define CIA_CCL_MASK 0x000000f0 -+#define CIA_CCL_SHIFT 4 -+ -+ -+#define CIB_REV_MASK 0xff000000 -+#define CIB_REV_SHIFT 24 -+#define CIB_NSW_MASK 0x00f80000 -+#define CIB_NSW_SHIFT 19 -+#define CIB_NMW_MASK 0x0007c000 -+#define CIB_NMW_SHIFT 14 -+#define CIB_NSP_MASK 0x00003e00 -+#define CIB_NSP_SHIFT 9 -+#define CIB_NMP_MASK 0x000001f0 -+#define CIB_NMP_SHIFT 4 -+ -+ -+#define MPD_MUI_MASK 0x0000ff00 -+#define MPD_MUI_SHIFT 8 -+#define MPD_MP_MASK 0x000000f0 -+#define MPD_MP_SHIFT 4 -+ -+ -+#define AD_ADDR_MASK 0xfffff000 -+#define AD_SP_MASK 0x00000f00 -+#define AD_SP_SHIFT 8 -+#define AD_ST_MASK 0x000000c0 -+#define AD_ST_SHIFT 6 -+#define AD_ST_SLAVE 0x00000000 -+#define AD_ST_BRIDGE 0x00000040 -+#define AD_ST_SWRAP 0x00000080 -+#define AD_ST_MWRAP 0x000000c0 -+#define AD_SZ_MASK 0x00000030 -+#define AD_SZ_SHIFT 4 -+#define AD_SZ_4K 0x00000000 -+#define AD_SZ_8K 0x00000010 -+#define AD_SZ_16K 0x00000020 -+#define AD_SZ_SZD 0x00000030 -+#define AD_AG32 0x00000008 -+#define AD_ADDR_ALIGN 0x00000fff -+#define AD_SZ_BASE 0x00001000 -+ -+ -+#define SD_SZ_MASK 0xfffff000 -+#define SD_SG32 0x00000008 -+#define SD_SZ_ALIGN 0x00000fff -+ -+ -+#ifndef _LANGUAGE_ASSEMBLY -+ -+typedef volatile struct _aidmp { -+ uint32 oobselina30; -+ uint32 oobselina74; -+ uint32 PAD[6]; -+ uint32 oobselinb30; -+ uint32 oobselinb74; -+ uint32 PAD[6]; -+ uint32 oobselinc30; -+ uint32 oobselinc74; -+ uint32 PAD[6]; -+ uint32 oobselind30; -+ uint32 oobselind74; -+ uint32 PAD[38]; -+ uint32 oobselouta30; -+ uint32 oobselouta74; -+ uint32 PAD[6]; -+ uint32 oobseloutb30; -+ uint32 oobseloutb74; -+ uint32 PAD[6]; -+ uint32 oobseloutc30; -+ uint32 oobseloutc74; -+ uint32 PAD[6]; -+ uint32 oobseloutd30; -+ uint32 oobseloutd74; -+ uint32 PAD[38]; -+ uint32 oobsynca; -+ uint32 oobseloutaen; -+ uint32 PAD[6]; -+ uint32 oobsyncb; -+ uint32 oobseloutben; -+ uint32 PAD[6]; -+ uint32 oobsyncc; -+ uint32 oobseloutcen; -+ uint32 PAD[6]; -+ uint32 oobsyncd; -+ uint32 oobseloutden; -+ uint32 PAD[38]; -+ uint32 oobaextwidth; -+ uint32 oobainwidth; -+ uint32 oobaoutwidth; -+ uint32 PAD[5]; -+ uint32 oobbextwidth; -+ uint32 oobbinwidth; -+ uint32 oobboutwidth; -+ uint32 PAD[5]; -+ uint32 oobcextwidth; -+ uint32 oobcinwidth; -+ uint32 oobcoutwidth; -+ uint32 PAD[5]; -+ uint32 oobdextwidth; -+ uint32 oobdinwidth; -+ uint32 oobdoutwidth; -+ uint32 PAD[37]; -+ uint32 ioctrlset; -+ uint32 ioctrlclear; -+ uint32 ioctrl; -+ uint32 PAD[61]; -+ uint32 iostatus; -+ uint32 PAD[127]; -+ uint32 ioctrlwidth; -+ uint32 iostatuswidth; -+ uint32 PAD[62]; -+ uint32 resetctrl; -+ uint32 resetstatus; -+ uint32 resetreadid; -+ uint32 resetwriteid; -+ uint32 PAD[60]; -+ uint32 errlogctrl; -+ uint32 errlogdone; -+ uint32 errlogstatus; -+ uint32 errlogaddrlo; -+ uint32 errlogaddrhi; -+ uint32 errlogid; -+ uint32 errloguser; -+ uint32 errlogflags; -+ uint32 PAD[56]; -+ uint32 intstatus; -+ uint32 PAD[255]; -+ uint32 config; -+ uint32 PAD[63]; -+ uint32 itcr; -+ uint32 PAD[3]; -+ uint32 itipooba; -+ uint32 itipoobb; -+ uint32 itipoobc; -+ uint32 itipoobd; -+ uint32 PAD[4]; -+ uint32 itipoobaout; -+ uint32 itipoobbout; -+ uint32 itipoobcout; -+ uint32 itipoobdout; -+ uint32 PAD[4]; -+ uint32 itopooba; -+ uint32 itopoobb; -+ uint32 itopoobc; -+ uint32 itopoobd; -+ uint32 PAD[4]; -+ uint32 itopoobain; -+ uint32 itopoobbin; -+ uint32 itopoobcin; -+ uint32 itopoobdin; -+ uint32 PAD[4]; -+ uint32 itopreset; -+ uint32 PAD[15]; -+ uint32 peripherialid4; -+ uint32 peripherialid5; -+ uint32 peripherialid6; -+ uint32 peripherialid7; -+ uint32 peripherialid0; -+ uint32 peripherialid1; -+ uint32 peripherialid2; -+ uint32 peripherialid3; -+ uint32 componentid0; -+ uint32 componentid1; -+ uint32 componentid2; -+ uint32 componentid3; -+} aidmp_t; -+ -+#endif -+ -+ -+#define OOB_BUSCONFIG 0x020 -+#define OOB_STATUSA 0x100 -+#define OOB_STATUSB 0x104 -+#define OOB_STATUSC 0x108 -+#define OOB_STATUSD 0x10c -+#define OOB_ENABLEA0 0x200 -+#define OOB_ENABLEA1 0x204 -+#define OOB_ENABLEA2 0x208 -+#define OOB_ENABLEA3 0x20c -+#define OOB_ENABLEB0 0x280 -+#define OOB_ENABLEB1 0x284 -+#define OOB_ENABLEB2 0x288 -+#define OOB_ENABLEB3 0x28c -+#define OOB_ENABLEC0 0x300 -+#define OOB_ENABLEC1 0x304 -+#define OOB_ENABLEC2 0x308 -+#define OOB_ENABLEC3 0x30c -+#define OOB_ENABLED0 0x380 -+#define OOB_ENABLED1 0x384 -+#define OOB_ENABLED2 0x388 -+#define OOB_ENABLED3 0x38c -+#define OOB_ITCR 0xf00 -+#define OOB_ITIPOOBA 0xf10 -+#define OOB_ITIPOOBB 0xf14 -+#define OOB_ITIPOOBC 0xf18 -+#define OOB_ITIPOOBD 0xf1c -+#define OOB_ITOPOOBA 0xf30 -+#define OOB_ITOPOOBB 0xf34 -+#define OOB_ITOPOOBC 0xf38 -+#define OOB_ITOPOOBD 0xf3c -+ -+ -+#define AI_OOBSELINA30 0x000 -+#define AI_OOBSELINA74 0x004 -+#define AI_OOBSELINB30 0x020 -+#define AI_OOBSELINB74 0x024 -+#define AI_OOBSELINC30 0x040 -+#define AI_OOBSELINC74 0x044 -+#define AI_OOBSELIND30 0x060 -+#define AI_OOBSELIND74 0x064 -+#define AI_OOBSELOUTA30 0x100 -+#define AI_OOBSELOUTA74 0x104 -+#define AI_OOBSELOUTB30 0x120 -+#define AI_OOBSELOUTB74 0x124 -+#define AI_OOBSELOUTC30 0x140 -+#define AI_OOBSELOUTC74 0x144 -+#define AI_OOBSELOUTD30 0x160 -+#define AI_OOBSELOUTD74 0x164 -+#define AI_OOBSYNCA 0x200 -+#define AI_OOBSELOUTAEN 0x204 -+#define AI_OOBSYNCB 0x220 -+#define AI_OOBSELOUTBEN 0x224 -+#define AI_OOBSYNCC 0x240 -+#define AI_OOBSELOUTCEN 0x244 -+#define AI_OOBSYNCD 0x260 -+#define AI_OOBSELOUTDEN 0x264 -+#define AI_OOBAEXTWIDTH 0x300 -+#define AI_OOBAINWIDTH 0x304 -+#define AI_OOBAOUTWIDTH 0x308 -+#define AI_OOBBEXTWIDTH 0x320 -+#define AI_OOBBINWIDTH 0x324 -+#define AI_OOBBOUTWIDTH 0x328 -+#define AI_OOBCEXTWIDTH 0x340 -+#define AI_OOBCINWIDTH 0x344 -+#define AI_OOBCOUTWIDTH 0x348 -+#define AI_OOBDEXTWIDTH 0x360 -+#define AI_OOBDINWIDTH 0x364 -+#define AI_OOBDOUTWIDTH 0x368 -+ -+ -+#define AI_IOCTRLSET 0x400 -+#define AI_IOCTRLCLEAR 0x404 -+#define AI_IOCTRL 0x408 -+#define AI_IOSTATUS 0x500 -+#define AI_RESETCTRL 0x800 -+#define AI_RESETSTATUS 0x804 -+ -+#define AI_IOCTRLWIDTH 0x700 -+#define AI_IOSTATUSWIDTH 0x704 -+ -+#define AI_RESETREADID 0x808 -+#define AI_RESETWRITEID 0x80c -+#define AI_ERRLOGCTRL 0xa00 -+#define AI_ERRLOGDONE 0xa04 -+#define AI_ERRLOGSTATUS 0xa08 -+#define AI_ERRLOGADDRLO 0xa0c -+#define AI_ERRLOGADDRHI 0xa10 -+#define AI_ERRLOGID 0xa14 -+#define AI_ERRLOGUSER 0xa18 -+#define AI_ERRLOGFLAGS 0xa1c -+#define AI_INTSTATUS 0xa00 -+#define AI_CONFIG 0xe00 -+#define AI_ITCR 0xf00 -+#define AI_ITIPOOBA 0xf10 -+#define AI_ITIPOOBB 0xf14 -+#define AI_ITIPOOBC 0xf18 -+#define AI_ITIPOOBD 0xf1c -+#define AI_ITIPOOBAOUT 0xf30 -+#define AI_ITIPOOBBOUT 0xf34 -+#define AI_ITIPOOBCOUT 0xf38 -+#define AI_ITIPOOBDOUT 0xf3c -+#define AI_ITOPOOBA 0xf50 -+#define AI_ITOPOOBB 0xf54 -+#define AI_ITOPOOBC 0xf58 -+#define AI_ITOPOOBD 0xf5c -+#define AI_ITOPOOBAIN 0xf70 -+#define AI_ITOPOOBBIN 0xf74 -+#define AI_ITOPOOBCIN 0xf78 -+#define AI_ITOPOOBDIN 0xf7c -+#define AI_ITOPRESET 0xf90 -+#define AI_PERIPHERIALID4 0xfd0 -+#define AI_PERIPHERIALID5 0xfd4 -+#define AI_PERIPHERIALID6 0xfd8 -+#define AI_PERIPHERIALID7 0xfdc -+#define AI_PERIPHERIALID0 0xfe0 -+#define AI_PERIPHERIALID1 0xfe4 -+#define AI_PERIPHERIALID2 0xfe8 -+#define AI_PERIPHERIALID3 0xfec -+#define AI_COMPONENTID0 0xff0 -+#define AI_COMPONENTID1 0xff4 -+#define AI_COMPONENTID2 0xff8 -+#define AI_COMPONENTID3 0xffc -+ -+ -+#define AIRC_RESET 1 -+ -+ -+#define AICFG_OOB 0x00000020 -+#define AICFG_IOS 0x00000010 -+#define AICFG_IOC 0x00000008 -+#define AICFG_TO 0x00000004 -+#define AICFG_ERRL 0x00000002 -+#define AICFG_RST 0x00000001 -+ -+ -+#define OOB_SEL_OUTEN_B_5 15 -+#define OOB_SEL_OUTEN_B_6 23 -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd/include/bcm_cfg.h -new file mode 100644 -index 00000000..26da7521 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcm_cfg.h -@@ -0,0 +1,29 @@ -+/* -+ * BCM common config options -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcm_cfg.h 294399 2011-11-07 03:31:22Z $ -+ */ -+ -+#ifndef _bcm_cfg_h_ -+#define _bcm_cfg_h_ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h -new file mode 100644 -index 00000000..8fe3de7a ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h -@@ -0,0 +1,361 @@ -+/* -+ * Memory pools library, Public interface -+ * -+ * API Overview -+ * -+ * This package provides a memory allocation subsystem based on pools of -+ * homogenous objects. -+ * -+ * Instrumentation is available for reporting memory utilization both -+ * on a per-data-structure basis and system wide. -+ * -+ * There are two main types defined in this API. -+ * -+ * pool manager: A singleton object that acts as a factory for -+ * pool allocators. It also is used for global -+ * instrumentation, such as reporting all blocks -+ * in use across all data structures. The pool manager -+ * creates and provides individual memory pools -+ * upon request to application code. -+ * -+ * memory pool: An object for allocating homogenous memory blocks. -+ * -+ * Global identifiers in this module use the following prefixes: -+ * bcm_mpm_* Memory pool manager -+ * bcm_mp_* Memory pool -+ * -+ * There are two main types of memory pools: -+ * -+ * prealloc: The contiguous memory block of objects can either be supplied -+ * by the client or malloc'ed by the memory manager. The objects are -+ * allocated out of a block of memory and freed back to the block. -+ * -+ * heap: The memory pool allocator uses the heap (malloc/free) for memory. -+ * In this case, the pool allocator is just providing statistics -+ * and instrumentation on top of the heap, without modifying the heap -+ * allocation implementation. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id$ -+ */ -+ -+#ifndef _BCM_MPOOL_PUB_H -+#define _BCM_MPOOL_PUB_H 1 -+ -+#include <typedefs.h> /* needed for uint16 */ -+ -+ -+/* -+************************************************************************** -+* -+* Type definitions, handles -+* -+************************************************************************** -+*/ -+ -+/* Forward declaration of OSL handle. */ -+struct osl_info; -+ -+/* Forward declaration of string buffer. */ -+struct bcmstrbuf; -+ -+/* -+ * Opaque type definition for the pool manager handle. This object is used for global -+ * memory pool operations such as obtaining a new pool, deleting a pool, iterating and -+ * instrumentation/debugging. -+ */ -+struct bcm_mpm_mgr; -+typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; -+ -+/* -+ * Opaque type definition for an instance of a pool. This handle is used for allocating -+ * and freeing memory through the pool, as well as management/instrumentation on this -+ * specific pool. -+ */ -+struct bcm_mp_pool; -+typedef struct bcm_mp_pool *bcm_mp_pool_h; -+ -+ -+/* -+ * To make instrumentation more readable, every memory -+ * pool must have a readable name. Pool names are up to -+ * 8 bytes including '\0' termination. (7 printable characters.) -+ */ -+#define BCM_MP_NAMELEN 8 -+ -+ -+/* -+ * Type definition for pool statistics. -+ */ -+typedef struct bcm_mp_stats { -+ char name[BCM_MP_NAMELEN]; /* Name of this pool. */ -+ unsigned int objsz; /* Object size allocated in this pool */ -+ uint16 nobj; /* Total number of objects in this pool */ -+ uint16 num_alloc; /* Number of objects currently allocated */ -+ uint16 high_water; /* Max number of allocated objects. */ -+ uint16 failed_alloc; /* Failed allocations. */ -+} bcm_mp_stats_t; -+ -+ -+/* -+************************************************************************** -+* -+* API Routines on the pool manager. -+* -+************************************************************************** -+*/ -+ -+/* -+ * bcm_mpm_init() - initialize the whole memory pool system. -+ * -+ * Parameters: -+ * osh: INPUT Operating system handle. Needed for heap memory allocation. -+ * max_pools: INPUT Maximum number of mempools supported. -+ * mgr: OUTPUT The handle is written with the new pools manager object/handle. -+ * -+ * Returns: -+ * BCME_OK Object initialized successfully. May be used. -+ * BCME_NOMEM Initialization failed due to no memory. Object must not be used. -+ */ -+int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); -+ -+ -+/* -+ * bcm_mpm_deinit() - de-initialize the whole memory pool system. -+ * -+ * Parameters: -+ * mgr: INPUT Pointer to pool manager handle. -+ * -+ * Returns: -+ * BCME_OK Memory pool manager successfully de-initialized. -+ * other Indicated error occured during de-initialization. -+ */ -+int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); -+ -+/* -+ * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The -+ * pool uses a contiguous block of pre-alloced -+ * memory. The memory block may either be provided -+ * by the client or dynamically allocated by the -+ * pool manager. -+ * -+ * Parameters: -+ * mgr: INPUT The handle to the pool manager -+ * obj_sz: INPUT Size of objects that will be allocated by the new pool -+ * Must be >= sizeof(void *). -+ * nobj: INPUT Maximum number of concurrently existing objects to support -+ * memstart INPUT Pointer to the memory to use, or NULL to malloc() -+ * memsize INPUT Number of bytes referenced from memstart (for error checking). -+ * Must be 0 if 'memstart' is NULL. -+ * poolname INPUT For instrumentation, the name of the pool -+ * newp: OUTPUT The handle for the new pool, if creation is successful -+ * -+ * Returns: -+ * BCME_OK Pool created ok. -+ * other Pool not created due to indicated error. newpoolp set to NULL. -+ * -+ * -+ */ -+int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, -+ unsigned int obj_sz, -+ int nobj, -+ void *memstart, -+ unsigned int memsize, -+ char poolname[BCM_MP_NAMELEN], -+ bcm_mp_pool_h *newp); -+ -+ -+/* -+ * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after -+ * all memory objects have been freed back to the pool. -+ * -+ * Parameters: -+ * mgr: INPUT The handle to the pools manager -+ * pool: INPUT The handle of the pool to delete -+ * -+ * Returns: -+ * BCME_OK Pool deleted ok. -+ * other Pool not deleted due to indicated error. -+ * -+ */ -+int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); -+ -+/* -+ * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory -+ * pool allocator uses the heap (malloc/free) for memory. -+ * In this case, the pool allocator is just providing -+ * statistics and instrumentation on top of the heap, -+ * without modifying the heap allocation implementation. -+ * -+ * Parameters: -+ * mgr: INPUT The handle to the pool manager -+ * obj_sz: INPUT Size of objects that will be allocated by the new pool -+ * poolname INPUT For instrumentation, the name of the pool -+ * newp: OUTPUT The handle for the new pool, if creation is successful -+ * -+ * Returns: -+ * BCME_OK Pool created ok. -+ * other Pool not created due to indicated error. newpoolp set to NULL. -+ * -+ * -+ */ -+int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, -+ char poolname[BCM_MP_NAMELEN], -+ bcm_mp_pool_h *newp); -+ -+ -+/* -+ * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after -+ * all memory objects have been freed back to the pool. -+ * -+ * Parameters: -+ * mgr: INPUT The handle to the pools manager -+ * pool: INPUT The handle of the pool to delete -+ * -+ * Returns: -+ * BCME_OK Pool deleted ok. -+ * other Pool not deleted due to indicated error. -+ * -+ */ -+int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); -+ -+ -+/* -+ * bcm_mpm_stats() - Return stats for all pools -+ * -+ * Parameters: -+ * mgr: INPUT The handle to the pools manager -+ * stats: OUTPUT Array of pool statistics. -+ * nentries: MOD Max elements in 'stats' array on INPUT. Actual number -+ * of array elements copied to 'stats' on OUTPUT. -+ * -+ * Returns: -+ * BCME_OK Ok -+ * other Error getting stats. -+ * -+ */ -+int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); -+ -+ -+/* -+ * bcm_mpm_dump() - Display statistics on all pools -+ * -+ * Parameters: -+ * mgr: INPUT The handle to the pools manager -+ * b: OUTPUT Output buffer. -+ * -+ * Returns: -+ * BCME_OK Ok -+ * other Error during dump. -+ * -+ */ -+int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); -+ -+ -+/* -+ * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to -+ * compensate for alignment requirements of the objects. -+ * This function provides the padded object size. If clients -+ * pre-allocate a memory slab for a memory pool, the -+ * padded object size should be used by the client to allocate -+ * the memory slab (in order to provide sufficent space for -+ * the maximum number of objects). -+ * -+ * Parameters: -+ * mgr: INPUT The handle to the pools manager. -+ * obj_sz: INPUT Input object size. -+ * padded_obj_sz: OUTPUT Padded object size. -+ * -+ * Returns: -+ * BCME_OK Ok -+ * BCME_BADARG Bad arguments. -+ * -+ */ -+int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); -+ -+ -+/* -+*************************************************************************** -+* -+* API Routines on a specific pool. -+* -+*************************************************************************** -+*/ -+ -+ -+/* -+ * bcm_mp_alloc() - Allocate a memory pool object. -+ * -+ * Parameters: -+ * pool: INPUT The handle to the pool. -+ * -+ * Returns: -+ * A pointer to the new object. NULL on error. -+ * -+ */ -+void* bcm_mp_alloc(bcm_mp_pool_h pool); -+ -+/* -+ * bcm_mp_free() - Free a memory pool object. -+ * -+ * Parameters: -+ * pool: INPUT The handle to the pool. -+ * objp: INPUT A pointer to the object to free. -+ * -+ * Returns: -+ * BCME_OK Ok -+ * other Error during free. -+ * -+ */ -+int bcm_mp_free(bcm_mp_pool_h pool, void *objp); -+ -+/* -+ * bcm_mp_stats() - Return stats for this pool -+ * -+ * Parameters: -+ * pool: INPUT The handle to the pool -+ * stats: OUTPUT Pool statistics -+ * -+ * Returns: -+ * BCME_OK Ok -+ * other Error getting statistics. -+ * -+ */ -+int bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); -+ -+ -+/* -+ * bcm_mp_dump() - Dump a pool -+ * -+ * Parameters: -+ * pool: INPUT The handle to the pool -+ * b OUTPUT Output buffer -+ * -+ * Returns: -+ * BCME_OK Ok -+ * other Error during dump. -+ * -+ */ -+int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); -+ -+ -+#endif /* _BCM_MPOOL_PUB_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h -new file mode 100644 -index 00000000..9bae1c20 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmcdc.h -@@ -0,0 +1,126 @@ -+/* -+ * CDC network driver ioctl/indication encoding -+ * Broadcom 802.11abg Networking Device Driver -+ * -+ * Definitions subject to change without notice. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmcdc.h 318308 2012-03-02 02:23:42Z $ -+ */ -+#ifndef _bcmcdc_h_ -+#define _bcmcdc_h_ -+#include <proto/ethernet.h> -+ -+typedef struct cdc_ioctl { -+ uint32 cmd; -+ uint32 len; -+ uint32 flags; -+ uint32 status; -+} cdc_ioctl_t; -+ -+ -+#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN -+ -+ -+#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF -+ -+#define CDCL_IOC_OUTLEN_SHIFT 0 -+#define CDCL_IOC_INLEN_MASK 0xFFFF0000 -+#define CDCL_IOC_INLEN_SHIFT 16 -+ -+ -+#define CDCF_IOC_ERROR 0x01 -+#define CDCF_IOC_SET 0x02 -+#define CDCF_IOC_OVL_IDX_MASK 0x3c -+#define CDCF_IOC_OVL_RSV 0x40 -+#define CDCF_IOC_OVL 0x80 -+#define CDCF_IOC_ACTION_MASK 0xfe -+#define CDCF_IOC_ACTION_SHIFT 1 -+#define CDCF_IOC_IF_MASK 0xF000 -+#define CDCF_IOC_IF_SHIFT 12 -+#define CDCF_IOC_ID_MASK 0xFFFF0000 -+#define CDCF_IOC_ID_SHIFT 16 -+ -+#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) -+#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) -+ -+#define CDC_GET_IF_IDX(hdr) \ -+ ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) -+#define CDC_SET_IF_IDX(hdr, idx) \ -+ ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) -+ -+ -+ -+struct bdc_header { -+ uint8 flags; -+ uint8 priority; -+ uint8 flags2; -+ uint8 dataOffset; -+}; -+ -+#define BDC_HEADER_LEN 4 -+ -+ -+#define BDC_FLAG_80211_PKT 0x01 -+#define BDC_FLAG_SUM_GOOD 0x04 -+#define BDC_FLAG_SUM_NEEDED 0x08 -+#define BDC_FLAG_EVENT_MSG 0x08 -+#define BDC_FLAG_VER_MASK 0xf0 -+#define BDC_FLAG_VER_SHIFT 4 -+ -+ -+#define BDC_PRIORITY_MASK 0x07 -+#define BDC_PRIORITY_FC_MASK 0xf0 -+#define BDC_PRIORITY_FC_SHIFT 4 -+ -+ -+#define BDC_FLAG2_IF_MASK 0x0f -+#define BDC_FLAG2_IF_SHIFT 0 -+#define BDC_FLAG2_FC_FLAG 0x10 -+ -+ -+ -+#define BDC_PROTO_VER_1 1 -+#define BDC_PROTO_VER 2 -+ -+ -+#define BDC_GET_IF_IDX(hdr) \ -+ ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) -+#define BDC_SET_IF_IDX(hdr, idx) \ -+ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT))) -+ -+#define BDC_FLAG2_PAD_MASK 0xf0 -+#define BDC_FLAG_PAD_MASK 0x03 -+#define BDC_FLAG2_PAD_SHIFT 2 -+#define BDC_FLAG_PAD_SHIFT 0 -+#define BDC_FLAG2_PAD_IDX 0x3c -+#define BDC_FLAG_PAD_IDX 0x03 -+#define BDC_GET_PAD_LEN(hdr) \ -+ ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ -+ ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) -+#define BDC_SET_PAD_LEN(hdr, idx) \ -+ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ -+ (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ -+ ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ -+ (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h -new file mode 100644 -index 00000000..a35ed72a ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmdefs.h -@@ -0,0 +1,239 @@ -+/* -+ * Misc system wide definitions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmdefs.h 316830 2012-02-23 20:29:22Z $ -+ */ -+ -+#ifndef _bcmdefs_h_ -+#define _bcmdefs_h_ -+ -+ -+ -+ -+#define BCM_REFERENCE(data) ((void)(data)) -+ -+ -+#define STATIC_ASSERT(expr) { \ -+ \ -+ typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e; \ -+ \ -+ typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1]; \ -+} -+ -+ -+ -+#define bcmreclaimed 0 -+#define _data _data -+#define _fn _fn -+#define BCMPREATTACHDATA(_data) _data -+#define BCMPREATTACHFN(_fn) _fn -+#define _data _data -+#define _fn _fn -+#define _fn _fn -+#define BCMNMIATTACHFN(_fn) _fn -+#define BCMNMIATTACHDATA(_data) _data -+#define CONST const -+#ifndef BCMFASTPATH -+#define BCMFASTPATH -+#define BCMFASTPATH_HOST -+#endif -+ -+ -+ -+#define _data _data -+#define BCMROMDAT_NAME(_data) _data -+#define _fn _fn -+#define _fn _fn -+#define STATIC static -+#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) -+#define BCMROMDAT_SIZEOF(data) sizeof(data) -+#define BCMROMDAT_APATCH(data) -+#define BCMROMDAT_SPATCH(data) -+ -+ -+#define SI_BUS 0 -+#define PCI_BUS 1 -+#define PCMCIA_BUS 2 -+#define SDIO_BUS 3 -+#define JTAG_BUS 4 -+#define USB_BUS 5 -+#define SPI_BUS 6 -+#define RPC_BUS 7 -+ -+ -+#ifdef BCMBUSTYPE -+#define BUSTYPE(bus) (BCMBUSTYPE) -+#else -+#define BUSTYPE(bus) (bus) -+#endif -+ -+ -+#ifdef BCMCHIPTYPE -+#define CHIPTYPE(bus) (BCMCHIPTYPE) -+#else -+#define CHIPTYPE(bus) (bus) -+#endif -+ -+ -+ -+#if defined(BCMSPROMBUS) -+#define SPROMBUS (BCMSPROMBUS) -+#elif defined(SI_PCMCIA_SROM) -+#define SPROMBUS (PCMCIA_BUS) -+#else -+#define SPROMBUS (PCI_BUS) -+#endif -+ -+ -+#ifdef BCMCHIPID -+#define CHIPID(chip) (BCMCHIPID) -+#else -+#define CHIPID(chip) (chip) -+#endif -+ -+#ifdef BCMCHIPREV -+#define CHIPREV(rev) (BCMCHIPREV) -+#else -+#define CHIPREV(rev) (rev) -+#endif -+ -+ -+#define DMADDR_MASK_32 0x0 -+#define DMADDR_MASK_30 0xc0000000 -+#define DMADDR_MASK_0 0xffffffff -+ -+#define DMADDRWIDTH_30 30 -+#define DMADDRWIDTH_32 32 -+#define DMADDRWIDTH_63 63 -+#define DMADDRWIDTH_64 64 -+ -+#ifdef BCMDMA64OSL -+typedef struct { -+ uint32 loaddr; -+ uint32 hiaddr; -+} dma64addr_t; -+ -+typedef dma64addr_t dmaaddr_t; -+#define PHYSADDRHI(_pa) ((_pa).hiaddr) -+#define PHYSADDRHISET(_pa, _val) \ -+ do { \ -+ (_pa).hiaddr = (_val); \ -+ } while (0) -+#define PHYSADDRLO(_pa) ((_pa).loaddr) -+#define PHYSADDRLOSET(_pa, _val) \ -+ do { \ -+ (_pa).loaddr = (_val); \ -+ } while (0) -+ -+#else -+typedef unsigned long dmaaddr_t; -+#define PHYSADDRHI(_pa) (0) -+#define PHYSADDRHISET(_pa, _val) -+#define PHYSADDRLO(_pa) ((_pa)) -+#define PHYSADDRLOSET(_pa, _val) \ -+ do { \ -+ (_pa) = (_val); \ -+ } while (0) -+#endif -+ -+ -+typedef struct { -+ dmaaddr_t addr; -+ uint32 length; -+} hnddma_seg_t; -+ -+#define MAX_DMA_SEGS 4 -+ -+ -+typedef struct { -+ void *oshdmah; -+ uint origsize; -+ uint nsegs; -+ hnddma_seg_t segs[MAX_DMA_SEGS]; -+} hnddma_seg_map_t; -+ -+ -+ -+ -+#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) -+ -+#define BCMEXTRAHDROOM 220 -+#else -+#define BCMEXTRAHDROOM 172 -+#endif -+ -+ -+#ifndef SDALIGN -+#define SDALIGN 32 -+#endif -+ -+ -+#define BCMDONGLEHDRSZ 12 -+#define BCMDONGLEPADSZ 16 -+ -+#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) -+ -+ -+#if defined(NO_BCMDBG_ASSERT) -+# undef BCMDBG_ASSERT -+# undef BCMASSERT_LOG -+#endif -+ -+#if defined(BCMASSERT_LOG) -+#define BCMASSERT_SUPPORT -+#endif -+ -+ -+#define BITFIELD_MASK(width) \ -+ (((unsigned)1 << (width)) - 1) -+#define GFIELD(val, field) \ -+ (((val) >> field ## _S) & field ## _M) -+#define SFIELD(val, field, bits) \ -+ (((val) & (~(field ## _M << field ## _S))) | \ -+ ((unsigned)(bits) << field ## _S)) -+ -+ -+#ifdef BCMSMALL -+#undef BCMSPACE -+#define bcmspace FALSE -+#else -+#define BCMSPACE -+#define bcmspace TRUE -+#endif -+ -+ -+#define MAXSZ_NVRAM_VARS 4096 -+ -+ -+ -+#ifdef DL_NVRAM -+#define NVRAM_ARRAY_MAXSIZE DL_NVRAM -+#else -+#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS -+#endif -+ -+#ifdef BCMUSBDEV_ENABLED -+extern uint32 gFWID; -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h -new file mode 100644 -index 00000000..c7e06ff4 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h -@@ -0,0 +1,495 @@ -+/* -+ * Broadcom device-specific manifest constants. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmdevs.h 329854 2012-04-27 01:42:28Z $ -+ */ -+ -+#ifndef _BCMDEVS_H -+#define _BCMDEVS_H -+ -+ -+#define VENDOR_EPIGRAM 0xfeda -+#define VENDOR_BROADCOM 0x14e4 -+#define VENDOR_3COM 0x10b7 -+#define VENDOR_NETGEAR 0x1385 -+#define VENDOR_DIAMOND 0x1092 -+#define VENDOR_INTEL 0x8086 -+#define VENDOR_DELL 0x1028 -+#define VENDOR_HP 0x103c -+#define VENDOR_HP_COMPAQ 0x0e11 -+#define VENDOR_APPLE 0x106b -+#define VENDOR_SI_IMAGE 0x1095 -+#define VENDOR_BUFFALO 0x1154 -+#define VENDOR_TI 0x104c -+#define VENDOR_RICOH 0x1180 -+#define VENDOR_JMICRON 0x197b -+ -+ -+ -+#define VENDOR_BROADCOM_PCMCIA 0x02d0 -+ -+ -+#define VENDOR_BROADCOM_SDIO 0x00BF -+ -+ -+#define BCM_DNGL_VID 0x0a5c -+#define BCM_DNGL_BL_PID_4328 0xbd12 -+#define BCM_DNGL_BL_PID_4322 0xbd13 -+#define BCM_DNGL_BL_PID_4319 0xbd16 -+#define BCM_DNGL_BL_PID_43236 0xbd17 -+#define BCM_DNGL_BL_PID_4332 0xbd18 -+#define BCM_DNGL_BL_PID_4330 0xbd19 -+#define BCM_DNGL_BL_PID_4334 0xbd1a -+#define BCM_DNGL_BL_PID_43239 0xbd1b -+#define BCM_DNGL_BL_PID_4324 0xbd1c -+#define BCM_DNGL_BL_PID_4360 0xbd1d -+ -+#define BCM_DNGL_BDC_PID 0x0bdc -+#define BCM_DNGL_JTAG_PID 0x4a44 -+ -+ -+#define BCM_HWUSB_PID_43239 43239 -+ -+ -+#define BCM4210_DEVICE_ID 0x1072 -+#define BCM4230_DEVICE_ID 0x1086 -+#define BCM4401_ENET_ID 0x170c -+#define BCM3352_DEVICE_ID 0x3352 -+#define BCM3360_DEVICE_ID 0x3360 -+#define BCM4211_DEVICE_ID 0x4211 -+#define BCM4231_DEVICE_ID 0x4231 -+#define BCM4303_D11B_ID 0x4303 -+#define BCM4311_D11G_ID 0x4311 -+#define BCM4311_D11DUAL_ID 0x4312 -+#define BCM4311_D11A_ID 0x4313 -+#define BCM4328_D11DUAL_ID 0x4314 -+#define BCM4328_D11G_ID 0x4315 -+#define BCM4328_D11A_ID 0x4316 -+#define BCM4318_D11G_ID 0x4318 -+#define BCM4318_D11DUAL_ID 0x4319 -+#define BCM4318_D11A_ID 0x431a -+#define BCM4325_D11DUAL_ID 0x431b -+#define BCM4325_D11G_ID 0x431c -+#define BCM4325_D11A_ID 0x431d -+#define BCM4306_D11G_ID 0x4320 -+#define BCM4306_D11A_ID 0x4321 -+#define BCM4306_UART_ID 0x4322 -+#define BCM4306_V90_ID 0x4323 -+#define BCM4306_D11DUAL_ID 0x4324 -+#define BCM4306_D11G_ID2 0x4325 -+#define BCM4321_D11N_ID 0x4328 -+#define BCM4321_D11N2G_ID 0x4329 -+#define BCM4321_D11N5G_ID 0x432a -+#define BCM4322_D11N_ID 0x432b -+#define BCM4322_D11N2G_ID 0x432c -+#define BCM4322_D11N5G_ID 0x432d -+#define BCM4329_D11N_ID 0x432e -+#define BCM4329_D11N2G_ID 0x432f -+#define BCM4329_D11N5G_ID 0x4330 -+#define BCM4315_D11DUAL_ID 0x4334 -+#define BCM4315_D11G_ID 0x4335 -+#define BCM4315_D11A_ID 0x4336 -+#define BCM4319_D11N_ID 0x4337 -+#define BCM4319_D11N2G_ID 0x4338 -+#define BCM4319_D11N5G_ID 0x4339 -+#define BCM43231_D11N2G_ID 0x4340 -+#define BCM43221_D11N2G_ID 0x4341 -+#define BCM43222_D11N_ID 0x4350 -+#define BCM43222_D11N2G_ID 0x4351 -+#define BCM43222_D11N5G_ID 0x4352 -+#define BCM43224_D11N_ID 0x4353 -+#define BCM43224_D11N_ID_VEN1 0x0576 -+#define BCM43226_D11N_ID 0x4354 -+#define BCM43236_D11N_ID 0x4346 -+#define BCM43236_D11N2G_ID 0x4347 -+#define BCM43236_D11N5G_ID 0x4348 -+#define BCM43225_D11N2G_ID 0x4357 -+#define BCM43421_D11N_ID 0xA99D -+#define BCM4313_D11N2G_ID 0x4727 -+#define BCM4330_D11N_ID 0x4360 -+#define BCM4330_D11N2G_ID 0x4361 -+#define BCM4330_D11N5G_ID 0x4362 -+#define BCM4336_D11N_ID 0x4343 -+#define BCM6362_D11N_ID 0x435f -+#define BCM4331_D11N_ID 0x4331 -+#define BCM4331_D11N2G_ID 0x4332 -+#define BCM4331_D11N5G_ID 0x4333 -+#define BCM43237_D11N_ID 0x4355 -+#define BCM43237_D11N5G_ID 0x4356 -+#define BCM43227_D11N2G_ID 0x4358 -+#define BCM43228_D11N_ID 0x4359 -+#define BCM43228_D11N5G_ID 0x435a -+#define BCM43362_D11N_ID 0x4363 -+#define BCM43239_D11N_ID 0x4370 -+#define BCM4324_D11N_ID 0x4374 -+#define BCM43217_D11N2G_ID 0x43a9 -+#define BCM43131_D11N2G_ID 0x43aa -+#define BCM4314_D11N2G_ID 0x4364 -+#define BCM43142_D11N2G_ID 0x4365 -+#define BCM4334_D11N_ID 0x4380 -+#define BCM4334_D11N2G_ID 0x4381 -+#define BCM4334_D11N5G_ID 0x4382 -+#define BCM43341_D11N_ID 0x4386 -+#define BCM43341_D11N2G_ID 0x4387 -+#define BCM43341_D11N5G_ID 0x4388 -+#define BCM4360_D11AC_ID 0x43a0 -+#define BCM4360_D11AC2G_ID 0x43a1 -+#define BCM4360_D11AC5G_ID 0x43a2 -+ -+ -+#define BCM943228HMB_SSID_VEN1 0x0607 -+#define BCM94313HMGBL_SSID_VEN1 0x0608 -+#define BCM94313HMG_SSID_VEN1 0x0609 -+ -+ -+#define BCM4335_D11AC_ID 0x43ae -+#define BCM4335_D11AC2G_ID 0x43af -+#define BCM4335_D11AC5G_ID 0x43b0 -+#define BCM4352_D11AC_ID 0x43b1 -+#define BCM4352_D11AC2G_ID 0x43b2 -+#define BCM4352_D11AC5G_ID 0x43b3 -+ -+#define BCMGPRS_UART_ID 0x4333 -+#define BCMGPRS2_UART_ID 0x4344 -+#define FPGA_JTAGM_ID 0x43f0 -+#define BCM_JTAGM_ID 0x43f1 -+#define SDIOH_FPGA_ID 0x43f2 -+#define BCM_SDIOH_ID 0x43f3 -+#define SDIOD_FPGA_ID 0x43f4 -+#define SPIH_FPGA_ID 0x43f5 -+#define BCM_SPIH_ID 0x43f6 -+#define MIMO_FPGA_ID 0x43f8 -+#define BCM_JTAGM2_ID 0x43f9 -+#define SDHCI_FPGA_ID 0x43fa -+#define BCM4402_ENET_ID 0x4402 -+#define BCM4402_V90_ID 0x4403 -+#define BCM4410_DEVICE_ID 0x4410 -+#define BCM4412_DEVICE_ID 0x4412 -+#define BCM4430_DEVICE_ID 0x4430 -+#define BCM4432_DEVICE_ID 0x4432 -+#define BCM4704_ENET_ID 0x4706 -+#define BCM4710_DEVICE_ID 0x4710 -+#define BCM47XX_AUDIO_ID 0x4711 -+#define BCM47XX_V90_ID 0x4712 -+#define BCM47XX_ENET_ID 0x4713 -+#define BCM47XX_EXT_ID 0x4714 -+#define BCM47XX_GMAC_ID 0x4715 -+#define BCM47XX_USBH_ID 0x4716 -+#define BCM47XX_USBD_ID 0x4717 -+#define BCM47XX_IPSEC_ID 0x4718 -+#define BCM47XX_ROBO_ID 0x4719 -+#define BCM47XX_USB20H_ID 0x471a -+#define BCM47XX_USB20D_ID 0x471b -+#define BCM47XX_ATA100_ID 0x471d -+#define BCM47XX_SATAXOR_ID 0x471e -+#define BCM47XX_GIGETH_ID 0x471f -+#define BCM4712_MIPS_ID 0x4720 -+#define BCM4716_DEVICE_ID 0x4722 -+#define BCM47XX_SMBUS_EMU_ID 0x47fe -+#define BCM47XX_XOR_EMU_ID 0x47ff -+#define EPI41210_DEVICE_ID 0xa0fa -+#define EPI41230_DEVICE_ID 0xa10e -+#define JINVANI_SDIOH_ID 0x4743 -+#define BCM27XX_SDIOH_ID 0x2702 -+#define PCIXX21_FLASHMEDIA_ID 0x803b -+#define PCIXX21_SDIOH_ID 0x803c -+#define R5C822_SDIOH_ID 0x0822 -+#define JMICRON_SDIOH_ID 0x2381 -+ -+ -+#define BCM4306_CHIP_ID 0x4306 -+#define BCM4311_CHIP_ID 0x4311 -+#define BCM43111_CHIP_ID 43111 -+#define BCM43112_CHIP_ID 43112 -+#define BCM4312_CHIP_ID 0x4312 -+#define BCM4313_CHIP_ID 0x4313 -+#define BCM43131_CHIP_ID 43131 -+#define BCM4315_CHIP_ID 0x4315 -+#define BCM4318_CHIP_ID 0x4318 -+#define BCM4319_CHIP_ID 0x4319 -+#define BCM4320_CHIP_ID 0x4320 -+#define BCM4321_CHIP_ID 0x4321 -+#define BCM43217_CHIP_ID 43217 -+#define BCM4322_CHIP_ID 0x4322 -+#define BCM43221_CHIP_ID 43221 -+#define BCM43222_CHIP_ID 43222 -+#define BCM43224_CHIP_ID 43224 -+#define BCM43225_CHIP_ID 43225 -+#define BCM43227_CHIP_ID 43227 -+#define BCM43228_CHIP_ID 43228 -+#define BCM43226_CHIP_ID 43226 -+#define BCM43231_CHIP_ID 43231 -+#define BCM43234_CHIP_ID 43234 -+#define BCM43235_CHIP_ID 43235 -+#define BCM43236_CHIP_ID 43236 -+#define BCM43237_CHIP_ID 43237 -+#define BCM43238_CHIP_ID 43238 -+#define BCM43239_CHIP_ID 43239 -+#define BCM43420_CHIP_ID 43420 -+#define BCM43421_CHIP_ID 43421 -+#define BCM43428_CHIP_ID 43428 -+#define BCM43431_CHIP_ID 43431 -+#define BCM43460_CHIP_ID 43460 -+#define BCM4325_CHIP_ID 0x4325 -+#define BCM4328_CHIP_ID 0x4328 -+#define BCM4329_CHIP_ID 0x4329 -+#define BCM4331_CHIP_ID 0x4331 -+#define BCM4336_CHIP_ID 0x4336 -+#define BCM43362_CHIP_ID 43362 -+#define BCM4330_CHIP_ID 0x4330 -+#define BCM6362_CHIP_ID 0x6362 -+#define BCM4314_CHIP_ID 0x4314 -+#define BCM43142_CHIP_ID 43142 -+#define BCM4324_CHIP_ID 0x4324 -+#define BCM43242_CHIP_ID 43242 -+#define BCM4334_CHIP_ID 0x4334 -+#define BCM4360_CHIP_ID 0x4360 -+#define BCM4352_CHIP_ID 0x4352 -+#define BCM43526_CHIP_ID 0xAA06 -+#define BCM43341_CHIP_ID 43341 -+#define BCM43342_CHIP_ID 43342 -+ -+#define BCM4335_CHIP_ID 0x4335 -+ -+#define BCM4342_CHIP_ID 4342 -+#define BCM4402_CHIP_ID 0x4402 -+#define BCM4704_CHIP_ID 0x4704 -+#define BCM4706_CHIP_ID 0x5300 -+#define BCM4710_CHIP_ID 0x4710 -+#define BCM4712_CHIP_ID 0x4712 -+#define BCM4716_CHIP_ID 0x4716 -+#define BCM47162_CHIP_ID 47162 -+#define BCM4748_CHIP_ID 0x4748 -+#define BCM4749_CHIP_ID 0x4749 -+#define BCM4785_CHIP_ID 0x4785 -+#define BCM5350_CHIP_ID 0x5350 -+#define BCM5352_CHIP_ID 0x5352 -+#define BCM5354_CHIP_ID 0x5354 -+#define BCM5365_CHIP_ID 0x5365 -+#define BCM5356_CHIP_ID 0x5356 -+#define BCM5357_CHIP_ID 0x5357 -+#define BCM53572_CHIP_ID 53572 -+ -+ -+#define BCM4303_PKG_ID 2 -+#define BCM4309_PKG_ID 1 -+#define BCM4712LARGE_PKG_ID 0 -+#define BCM4712SMALL_PKG_ID 1 -+#define BCM4712MID_PKG_ID 2 -+#define BCM4328USBD11G_PKG_ID 2 -+#define BCM4328USBDUAL_PKG_ID 3 -+#define BCM4328SDIOD11G_PKG_ID 4 -+#define BCM4328SDIODUAL_PKG_ID 5 -+#define BCM4329_289PIN_PKG_ID 0 -+#define BCM4329_182PIN_PKG_ID 1 -+#define BCM5354E_PKG_ID 1 -+#define BCM4716_PKG_ID 8 -+#define BCM4717_PKG_ID 9 -+#define BCM4718_PKG_ID 10 -+#define BCM5356_PKG_NONMODE 1 -+#define BCM5358U_PKG_ID 8 -+#define BCM5358_PKG_ID 9 -+#define BCM47186_PKG_ID 10 -+#define BCM5357_PKG_ID 11 -+#define BCM5356U_PKG_ID 12 -+#define BCM53572_PKG_ID 8 -+#define BCM5357C0_PKG_ID 8 -+#define BCM47188_PKG_ID 9 -+#define BCM5358C0_PKG_ID 0xa -+#define BCM5356C0_PKG_ID 0xb -+#define BCM4331TT_PKG_ID 8 -+#define BCM4331TN_PKG_ID 9 -+#define BCM4331TNA0_PKG_ID 0xb -+#define BCM4706L_PKG_ID 1 -+ -+#define HDLSIM5350_PKG_ID 1 -+#define HDLSIM_PKG_ID 14 -+#define HWSIM_PKG_ID 15 -+#define BCM43224_FAB_CSM 0x8 -+#define BCM43224_FAB_SMIC 0xa -+#define BCM4336_WLBGA_PKG_ID 0x8 -+#define BCM4330_WLBGA_PKG_ID 0x0 -+#define BCM4314PCIE_ARM_PKG_ID (8 | 0) -+#define BCM4314SDIO_PKG_ID (8 | 1) -+#define BCM4314PCIE_PKG_ID (8 | 2) -+#define BCM4314SDIO_ARM_PKG_ID (8 | 3) -+#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) -+#define BCM4314DEV_PKG_ID (8 | 6) -+ -+#define PCIXX21_FLASHMEDIA0_ID 0x8033 -+#define PCIXX21_SDIOH0_ID 0x8034 -+ -+ -+#define BFL_BTC2WIRE 0x00000001 -+#define BFL_BTCOEX 0x00000001 -+#define BFL_PACTRL 0x00000002 -+#define BFL_AIRLINEMODE 0x00000004 -+#define BFL_ADCDIV 0x00000008 -+#define BFL_RFPLL 0x00000008 -+#define BFL_ENETROBO 0x00000010 -+#define BFL_NOPLLDOWN 0x00000020 -+#define BFL_CCKHIPWR 0x00000040 -+#define BFL_ENETADM 0x00000080 -+#define BFL_ENETVLAN 0x00000100 -+#define BFL_UNUSED 0x00000200 -+#define BFL_NOPCI 0x00000400 -+#define BFL_FEM 0x00000800 -+#define BFL_EXTLNA 0x00001000 -+#define BFL_HGPA 0x00002000 -+#define BFL_BTC2WIRE_ALTGPIO 0x00004000 -+#define BFL_ALTIQ 0x00008000 -+#define BFL_NOPA 0x00010000 -+#define BFL_RSSIINV 0x00020000 -+#define BFL_PAREF 0x00040000 -+#define BFL_3TSWITCH 0x00080000 -+#define BFL_PHASESHIFT 0x00100000 -+#define BFL_BUCKBOOST 0x00200000 -+#define BFL_FEM_BT 0x00400000 -+#define BFL_NOCBUCK 0x00800000 -+#define BFL_CCKFAVOREVM 0x01000000 -+#define BFL_PALDO 0x02000000 -+#define BFL_LNLDO2_2P5 0x04000000 -+#define BFL_FASTPWR 0x08000000 -+#define BFL_UCPWRCTL_MININDX 0x08000000 -+#define BFL_EXTLNA_5GHz 0x10000000 -+#define BFL_TRSW_1by2 0x20000000 -+#define BFL_LO_TRSW_R_5GHz 0x40000000 -+#define BFL_ELNA_GAINDEF 0x80000000 -+#define BFL_EXTLNA_TX 0x20000000 -+ -+ -+#define BFL2_RXBB_INT_REG_DIS 0x00000001 -+#define BFL2_APLL_WAR 0x00000002 -+#define BFL2_TXPWRCTRL_EN 0x00000004 -+#define BFL2_2X4_DIV 0x00000008 -+#define BFL2_5G_PWRGAIN 0x00000010 -+#define BFL2_PCIEWAR_OVR 0x00000020 -+#define BFL2_CAESERS_BRD 0x00000040 -+#define BFL2_BTC3WIRE 0x00000080 -+#define BFL2_BTCLEGACY 0x00000080 -+#define BFL2_SKWRKFEM_BRD 0x00000100 -+#define BFL2_SPUR_WAR 0x00000200 -+#define BFL2_GPLL_WAR 0x00000400 -+#define BFL2_TRISTATE_LED 0x00000800 -+#define BFL2_SINGLEANT_CCK 0x00001000 -+#define BFL2_2G_SPUR_WAR 0x00002000 -+#define BFL2_BPHY_ALL_TXCORES 0x00004000 -+#define BFL2_FCC_BANDEDGE_WAR 0x00008000 -+#define BFL2_GPLL_WAR2 0x00010000 -+#define BFL2_IPALVLSHIFT_3P3 0x00020000 -+#define BFL2_INTERNDET_TXIQCAL 0x00040000 -+#define BFL2_XTALBUFOUTEN 0x00080000 -+ -+ -+ -+#define BFL2_ANAPACTRL_2G 0x00100000 -+#define BFL2_ANAPACTRL_5G 0x00200000 -+#define BFL2_ELNACTRL_TRSW_2G 0x00400000 -+#define BFL2_BT_SHARE_ANT0 0x00800000 -+#define BFL2_TEMPSENSE_HIGHER 0x01000000 -+#define BFL2_BTC3WIREONLY 0x02000000 -+#define BFL2_PWR_NOMINAL 0x04000000 -+#define BFL2_EXTLNA_PWRSAVE 0x08000000 -+ -+#define BFL2_4313_RADIOREG 0x10000000 -+ -+#define BFL2_SDR_EN 0x20000000 -+ -+ -+#define BOARD_GPIO_BTC3W_IN 0x850 -+#define BOARD_GPIO_BTC3W_OUT 0x020 -+#define BOARD_GPIO_BTCMOD_IN 0x010 -+#define BOARD_GPIO_BTCMOD_OUT 0x020 -+#define BOARD_GPIO_BTC_IN 0x080 -+#define BOARD_GPIO_BTC_OUT 0x100 -+#define BOARD_GPIO_PACTRL 0x200 -+#define BOARD_GPIO_12 0x1000 -+#define BOARD_GPIO_13 0x2000 -+#define BOARD_GPIO_BTC4_IN 0x0800 -+#define BOARD_GPIO_BTC4_BT 0x2000 -+#define BOARD_GPIO_BTC4_STAT 0x4000 -+#define BOARD_GPIO_BTC4_WLAN 0x8000 -+#define BOARD_GPIO_1_WLAN_PWR 0x02 -+#define BOARD_GPIO_3_WLAN_PWR 0x08 -+#define BOARD_GPIO_4_WLAN_PWR 0x10 -+ -+#define GPIO_BTC4W_OUT_4312 0x010 -+#define GPIO_BTC4W_OUT_43224 0x020 -+#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 -+#define GPIO_BTC4W_OUT_43225 0x0e0 -+#define GPIO_BTC4W_OUT_43421 0x020 -+#define GPIO_BTC4W_OUT_4313 0x060 -+#define GPIO_BTC4W_OUT_4331_SHARED 0x010 -+ -+#define PCI_CFG_GPIO_SCS 0x10 -+#define PCI_CFG_GPIO_HWRAD 0x20 -+#define PCI_CFG_GPIO_XTAL 0x40 -+#define PCI_CFG_GPIO_PLL 0x80 -+ -+ -+#define PLL_DELAY 150 -+#define FREF_DELAY 200 -+#define MIN_SLOW_CLK 32 -+#define XTAL_ON_DELAY 1000 -+ -+ -+ -+#define BCM943341WLABGS_SSID 0x062d -+ -+ -+#define GPIO_NUMPINS 32 -+ -+ -+#define RDL_RAM_BASE_4319 0x60000000 -+#define RDL_RAM_BASE_4329 0x60000000 -+#define RDL_RAM_SIZE_4319 0x48000 -+#define RDL_RAM_SIZE_4329 0x48000 -+#define RDL_RAM_SIZE_43236 0x70000 -+#define RDL_RAM_BASE_43236 0x60000000 -+#define RDL_RAM_SIZE_4328 0x60000 -+#define RDL_RAM_BASE_4328 0x80000000 -+#define RDL_RAM_SIZE_4322 0x60000 -+#define RDL_RAM_BASE_4322 0x60000000 -+ -+ -+#define MUXENAB_UART 0x00000001 -+#define MUXENAB_GPIO 0x00000002 -+#define MUXENAB_ERCX 0x00000004 -+#define MUXENAB_JTAG 0x00000008 -+#define MUXENAB_HOST_WAKE 0x00000010 -+#define MUXENAB_I2S_EN 0x00000020 -+#define MUXENAB_I2S_MASTER 0x00000040 -+#define MUXENAB_I2S_FULL 0x00000080 -+#define MUXENAB_SFLASH 0x00000100 -+#define MUXENAB_RFSWCTRL0 0x00000200 -+#define MUXENAB_RFSWCTRL1 0x00000400 -+#define MUXENAB_RFSWCTRL2 0x00000800 -+#define MUXENAB_SECI 0x00001000 -+#define MUXENAB_BT_LEGACY 0x00002000 -+#define MUXENAB_HOST_WAKE1 0x00004000 -+ -+ -+#define FLASH_KERNEL_NFLASH 0x00000001 -+#define FLASH_BOOT_NFLASH 0x00000002 -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h -new file mode 100644 -index 00000000..22eb7dbc ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmendian.h -@@ -0,0 +1,278 @@ -+/* -+ * Byte order utilities -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmendian.h 241182 2011-02-17 21:50:03Z $ -+ * -+ * This file by default provides proper behavior on little-endian architectures. -+ * On big-endian architectures, IL_BIGENDIAN should be defined. -+ */ -+ -+#ifndef _BCMENDIAN_H_ -+#define _BCMENDIAN_H_ -+ -+#include <typedefs.h> -+ -+ -+#define BCMSWAP16(val) \ -+ ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ -+ (((uint16)(val) & (uint16)0xff00U) >> 8))) -+ -+ -+#define BCMSWAP32(val) \ -+ ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ -+ (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ -+ (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ -+ (((uint32)(val) & (uint32)0xff000000U) >> 24))) -+ -+ -+#define BCMSWAP32BY16(val) \ -+ ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ -+ (((uint32)(val) & (uint32)0xffff0000U) >> 16))) -+ -+ -+#ifndef hton16 -+#define HTON16(i) BCMSWAP16(i) -+#define hton16(i) bcmswap16(i) -+#define HTON32(i) BCMSWAP32(i) -+#define hton32(i) bcmswap32(i) -+#define NTOH16(i) BCMSWAP16(i) -+#define ntoh16(i) bcmswap16(i) -+#define NTOH32(i) BCMSWAP32(i) -+#define ntoh32(i) bcmswap32(i) -+#define LTOH16(i) (i) -+#define ltoh16(i) (i) -+#define LTOH32(i) (i) -+#define ltoh32(i) (i) -+#define HTOL16(i) (i) -+#define htol16(i) (i) -+#define HTOL32(i) (i) -+#define htol32(i) (i) -+#endif -+ -+#define ltoh16_buf(buf, i) -+#define htol16_buf(buf, i) -+ -+ -+#define load32_ua(a) ltoh32_ua(a) -+#define store32_ua(a, v) htol32_ua_store(v, a) -+#define load16_ua(a) ltoh16_ua(a) -+#define store16_ua(a, v) htol16_ua_store(v, a) -+ -+#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) -+#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) -+#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) -+#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) -+ -+#define ltoh_ua(ptr) \ -+ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ -+ sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ -+ sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ -+ *(uint8 *)0) -+ -+#define ntoh_ua(ptr) \ -+ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ -+ sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ -+ sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ -+ *(uint8 *)0) -+ -+#ifdef __GNUC__ -+ -+ -+ -+#define bcmswap16(val) ({ \ -+ uint16 _val = (val); \ -+ BCMSWAP16(_val); \ -+}) -+ -+#define bcmswap32(val) ({ \ -+ uint32 _val = (val); \ -+ BCMSWAP32(_val); \ -+}) -+ -+#define bcmswap32by16(val) ({ \ -+ uint32 _val = (val); \ -+ BCMSWAP32BY16(_val); \ -+}) -+ -+#define bcmswap16_buf(buf, len) ({ \ -+ uint16 *_buf = (uint16 *)(buf); \ -+ uint _wds = (len) / 2; \ -+ while (_wds--) { \ -+ *_buf = bcmswap16(*_buf); \ -+ _buf++; \ -+ } \ -+}) -+ -+#define htol16_ua_store(val, bytes) ({ \ -+ uint16 _val = (val); \ -+ uint8 *_bytes = (uint8 *)(bytes); \ -+ _bytes[0] = _val & 0xff; \ -+ _bytes[1] = _val >> 8; \ -+}) -+ -+#define htol32_ua_store(val, bytes) ({ \ -+ uint32 _val = (val); \ -+ uint8 *_bytes = (uint8 *)(bytes); \ -+ _bytes[0] = _val & 0xff; \ -+ _bytes[1] = (_val >> 8) & 0xff; \ -+ _bytes[2] = (_val >> 16) & 0xff; \ -+ _bytes[3] = _val >> 24; \ -+}) -+ -+#define hton16_ua_store(val, bytes) ({ \ -+ uint16 _val = (val); \ -+ uint8 *_bytes = (uint8 *)(bytes); \ -+ _bytes[0] = _val >> 8; \ -+ _bytes[1] = _val & 0xff; \ -+}) -+ -+#define hton32_ua_store(val, bytes) ({ \ -+ uint32 _val = (val); \ -+ uint8 *_bytes = (uint8 *)(bytes); \ -+ _bytes[0] = _val >> 24; \ -+ _bytes[1] = (_val >> 16) & 0xff; \ -+ _bytes[2] = (_val >> 8) & 0xff; \ -+ _bytes[3] = _val & 0xff; \ -+}) -+ -+#define ltoh16_ua(bytes) ({ \ -+ const uint8 *_bytes = (const uint8 *)(bytes); \ -+ _LTOH16_UA(_bytes); \ -+}) -+ -+#define ltoh32_ua(bytes) ({ \ -+ const uint8 *_bytes = (const uint8 *)(bytes); \ -+ _LTOH32_UA(_bytes); \ -+}) -+ -+#define ntoh16_ua(bytes) ({ \ -+ const uint8 *_bytes = (const uint8 *)(bytes); \ -+ _NTOH16_UA(_bytes); \ -+}) -+ -+#define ntoh32_ua(bytes) ({ \ -+ const uint8 *_bytes = (const uint8 *)(bytes); \ -+ _NTOH32_UA(_bytes); \ -+}) -+ -+#else -+ -+ -+static INLINE uint16 -+bcmswap16(uint16 val) -+{ -+ return BCMSWAP16(val); -+} -+ -+static INLINE uint32 -+bcmswap32(uint32 val) -+{ -+ return BCMSWAP32(val); -+} -+ -+static INLINE uint32 -+bcmswap32by16(uint32 val) -+{ -+ return BCMSWAP32BY16(val); -+} -+ -+ -+ -+ -+static INLINE void -+bcmswap16_buf(uint16 *buf, uint len) -+{ -+ len = len / 2; -+ -+ while (len--) { -+ *buf = bcmswap16(*buf); -+ buf++; -+ } -+} -+ -+ -+static INLINE void -+htol16_ua_store(uint16 val, uint8 *bytes) -+{ -+ bytes[0] = val & 0xff; -+ bytes[1] = val >> 8; -+} -+ -+ -+static INLINE void -+htol32_ua_store(uint32 val, uint8 *bytes) -+{ -+ bytes[0] = val & 0xff; -+ bytes[1] = (val >> 8) & 0xff; -+ bytes[2] = (val >> 16) & 0xff; -+ bytes[3] = val >> 24; -+} -+ -+ -+static INLINE void -+hton16_ua_store(uint16 val, uint8 *bytes) -+{ -+ bytes[0] = val >> 8; -+ bytes[1] = val & 0xff; -+} -+ -+ -+static INLINE void -+hton32_ua_store(uint32 val, uint8 *bytes) -+{ -+ bytes[0] = val >> 24; -+ bytes[1] = (val >> 16) & 0xff; -+ bytes[2] = (val >> 8) & 0xff; -+ bytes[3] = val & 0xff; -+} -+ -+ -+static INLINE uint16 -+ltoh16_ua(const void *bytes) -+{ -+ return _LTOH16_UA((const uint8 *)bytes); -+} -+ -+ -+static INLINE uint32 -+ltoh32_ua(const void *bytes) -+{ -+ return _LTOH32_UA((const uint8 *)bytes); -+} -+ -+ -+static INLINE uint16 -+ntoh16_ua(const void *bytes) -+{ -+ return _NTOH16_UA((const uint8 *)bytes); -+} -+ -+ -+static INLINE uint32 -+ntoh32_ua(const void *bytes) -+{ -+ return _NTOH32_UA((const uint8 *)bytes); -+} -+ -+#endif -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h -new file mode 100644 -index 00000000..44b263ce ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h -@@ -0,0 +1,181 @@ -+/* -+ * Broadcom PCI-SPI Host Controller Register Definitions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmpcispi.h 241182 2011-02-17 21:50:03Z $ -+ */ -+#ifndef _BCM_PCI_SPI_H -+#define _BCM_PCI_SPI_H -+ -+/* cpp contortions to concatenate w/arg prescan */ -+#ifndef PAD -+#define _PADLINE(line) pad ## line -+#define _XSTR(line) _PADLINE(line) -+#define PAD _XSTR(__LINE__) -+#endif /* PAD */ -+ -+ -+typedef volatile struct { -+ uint32 spih_ctrl; /* 0x00 SPI Control Register */ -+ uint32 spih_stat; /* 0x04 SPI Status Register */ -+ uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ -+ uint32 spih_ext; /* 0x0C SPI Extension Register */ -+ uint32 PAD[4]; /* 0x10-0x1F PADDING */ -+ -+ uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ -+ uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ -+ uint32 PAD[6]; /* 0x28-0x3F PADDING */ -+ -+ uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ -+ uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ -+ /* 1=Active High) */ -+ uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ -+ uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ -+ uint32 PAD[4]; /* 0x50-0x5F PADDING */ -+ -+ uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ -+ uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ -+ uint32 PAD[1]; /* 0x68 PADDING */ -+ uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ -+ uint32 PAD[4]; /* 0x70-0x7F PADDING */ -+ uint32 PAD[8]; /* 0x80-0x9F PADDING */ -+ uint32 PAD[8]; /* 0xA0-0xBF PADDING */ -+ uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ -+ uint32 spih_pll_status; /* 0xC4 PLL Status Register */ -+ uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ -+ uint32 spih_clk_count; /* 0xCC External Clock Count Register */ -+ -+} spih_regs_t; -+ -+typedef volatile struct { -+ uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ -+ uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ -+ -+ uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ -+ uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ -+ uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ -+ uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ -+ uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ -+ uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ -+ uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ -+ uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ -+ uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ -+ uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ -+ uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ -+ uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ -+ uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ -+ uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ -+ uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ -+ uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ -+ uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ -+ uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ -+ uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ -+ uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ -+ uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ -+ uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ -+ uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ -+ uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ -+ uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ -+ uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ -+ -+ uint32 PAD[5]; /* 0x16C-0x17F PADDING */ -+ -+ uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ -+ uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ -+ uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ -+ uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ -+ uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ -+ uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ -+ uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ -+ uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ -+ uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ -+ uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ -+ uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ -+ uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ -+ uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ -+ uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ -+ uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ -+ uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ -+ uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ -+ uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ -+ uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ -+ uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ -+ uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ -+ uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ -+ uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ -+ uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ -+ uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ -+ uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ -+ -+ uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ -+ uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ -+ uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ -+} spih_pciregs_t; -+ -+/* -+ * PCI Core interrupt enable and status bit definitions. -+ */ -+ -+/* PCI Core ICR Register bit definitions */ -+#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ -+#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ -+#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ -+#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ -+#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ -+#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ -+ -+ -+/* PCI Core ISR Register bit definitions */ -+#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ -+#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ -+#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ -+#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ -+#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ -+ -+ -+/* Registers on the Wishbone bus */ -+#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ -+#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ -+#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ -+ -+/* GPIO Bit definitions */ -+#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ -+#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ -+#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ -+ -+/* SPI Status Register Bit definitions */ -+#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ -+#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ -+#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ -+#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ -+#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ -+#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ -+ -+#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ -+ -+#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ -+#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ -+ -+/* Spin bit loop bound check */ -+#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ -+ -+#endif /* _BCM_PCI_SPI_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h -new file mode 100644 -index 00000000..74383076 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmperf.h -@@ -0,0 +1,36 @@ -+/* -+ * Performance counters software interface. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmperf.h 241182 2011-02-17 21:50:03Z $ -+ */ -+/* essai */ -+#ifndef _BCMPERF_H_ -+#define _BCMPERF_H_ -+/* get cache hits and misses */ -+#define BCMPERF_ENABLE_INSTRCOUNT() -+#define BCMPERF_ENABLE_ICACHE_MISS() -+#define BCMPERF_ENABLE_ICACHE_HIT() -+#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) -+#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) -+#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) -+#endif /* _BCMPERF_H_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h -new file mode 100644 -index 00000000..2fa706db ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h -@@ -0,0 +1,152 @@ -+/* -+ * Definitions for API from sdio common code (bcmsdh) to individual -+ * host controller drivers. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdbus.h 347614 2012-07-27 10:24:51Z $ -+ */ -+ -+#ifndef _sdio_api_h_ -+#define _sdio_api_h_ -+ -+ -+#define SDIOH_API_RC_SUCCESS (0x00) -+#define SDIOH_API_RC_FAIL (0x01) -+#define SDIOH_API_SUCCESS(status) (status == 0) -+ -+#define SDIOH_READ 0 /* Read request */ -+#define SDIOH_WRITE 1 /* Write request */ -+ -+#define SDIOH_DATA_FIX 0 /* Fixed addressing */ -+#define SDIOH_DATA_INC 1 /* Incremental addressing */ -+ -+#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */ -+#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */ -+#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */ -+ -+#define SDIOH_DATA_PIO 0 /* PIO mode */ -+#define SDIOH_DATA_DMA 1 /* DMA mode */ -+ -+#ifdef BCMSDIOH_TXGLOM -+/* Max number of glommed pkts */ -+#define SDPCM_MAXGLOM_SIZE 10 -+#define SDPCM_DEFGLOM_SIZE 3 -+ -+#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ -+#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ -+#endif -+ -+ -+typedef int SDIOH_API_RC; -+ -+/* SDio Host structure */ -+typedef struct sdioh_info sdioh_info_t; -+ -+/* callback function, taking one arg */ -+typedef void (*sdioh_cb_fn_t)(void *); -+ -+/* attach, return handler on success, NULL if failed. -+ * The handler shall be provided by all subsequent calls. No local cache -+ * cfghdl points to the starting address of pci device mapped memory -+ */ -+extern sdioh_info_t * sdioh_attach(osl_t *osh, void *cfghdl, uint irq); -+extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *si); -+extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); -+extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); -+ -+/* query whether SD interrupt is enabled or not */ -+extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); -+ -+/* enable or disable SD interrupt */ -+extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); -+ -+#if defined(DHD_DEBUG) -+extern bool sdioh_interrupt_pending(sdioh_info_t *si); -+#endif -+ -+/* read or write one byte using cmd52 */ -+extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); -+ -+/* read or write 2/4 bytes using cmd53 */ -+extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, -+ uint addr, uint32 *word, uint nbyte); -+ -+/* read or write any buffer using cmd53 */ -+extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, -+ uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, -+ void *pkt); -+ -+#ifdef BCMSDIOH_TXGLOM -+extern void sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, uint len); -+extern void sdioh_glom_clear(sdioh_info_t *sd); -+extern uint sdioh_set_mode(sdioh_info_t *sd, uint mode); -+extern bool sdioh_glom_enabled(void); -+#else -+#define sdioh_glom_post(a, b, c) -+#define sdioh_glom_clear(a) -+#define sdioh_set_mode(a) (0) -+#define sdioh_glom_enabled() (FALSE) -+#endif -+ -+/* get cis data */ -+extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); -+ -+extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); -+extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); -+ -+/* query number of io functions */ -+extern uint sdioh_query_iofnum(sdioh_info_t *si); -+ -+/* handle iovars */ -+extern int sdioh_iovar_op(sdioh_info_t *si, const char *name, -+ void *params, int plen, void *arg, int len, bool set); -+ -+/* Issue abort to the specified function and clear controller as needed */ -+extern int sdioh_abort(sdioh_info_t *si, uint fnc); -+ -+/* Start and Stop SDIO without re-enumerating the SD card. */ -+extern int sdioh_start(sdioh_info_t *si, int stage); -+extern int sdioh_stop(sdioh_info_t *si); -+ -+/* Wait system lock free */ -+extern int sdioh_waitlockfree(sdioh_info_t *si); -+ -+/* Reset and re-initialize the device */ -+extern int sdioh_sdio_reset(sdioh_info_t *si); -+ -+/* Helper function */ -+void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); -+ -+ -+ -+#if defined(BCMSDIOH_STD) -+ #define SDIOH_SLEEP_ENABLED -+#endif -+extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); -+ -+/* GPIO support */ -+extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); -+extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); -+extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); -+extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); -+ -+#endif /* _sdio_api_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h -new file mode 100644 -index 00000000..1c8a6b3e ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h -@@ -0,0 +1,242 @@ -+/* -+ * SDIO host client driver interface of Broadcom HNBU -+ * export functions to client drivers -+ * abstract OS and BUS specific details of SDIO -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdh.h 347614 2012-07-27 10:24:51Z $ -+ */ -+ -+/** -+ * @file bcmsdh.h -+ */ -+ -+#ifndef _bcmsdh_h_ -+#define _bcmsdh_h_ -+ -+#define BCMSDH_ERROR_VAL 0x0001 /* Error */ -+#define BCMSDH_INFO_VAL 0x0002 /* Info */ -+extern const uint bcmsdh_msglevel; -+ -+#define BCMSDH_ERROR(x) -+#define BCMSDH_INFO(x) -+ -+#if (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || defined(BCMSDIOH_SPI)) -+#define BCMSDH_ADAPTER -+#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ -+ -+/* forward declarations */ -+typedef struct bcmsdh_info bcmsdh_info_t; -+typedef void (*bcmsdh_cb_fn_t)(void *); -+ -+/* Attach and build an interface to the underlying SD host driver. -+ * - Allocates resources (structs, arrays, mem, OS handles, etc) needed by bcmsdh. -+ * - Returns the bcmsdh handle and virtual address base for register access. -+ * The returned handle should be used in all subsequent calls, but the bcmsh -+ * implementation may maintain a single "default" handle (e.g. the first or -+ * most recent one) to enable single-instance implementations to pass NULL. -+ */ -+ -+#if 0 && (NDISVER >= 0x0630) && 1 -+extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, -+ void **regsva, uint irq, shared_info_t *sh); -+#else -+extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq); -+#endif -+ -+/* Detach - freeup resources allocated in attach */ -+extern int bcmsdh_detach(osl_t *osh, void *sdh); -+ -+/* Query if SD device interrupts are enabled */ -+extern bool bcmsdh_intr_query(void *sdh); -+ -+/* Enable/disable SD interrupt */ -+extern int bcmsdh_intr_enable(void *sdh); -+extern int bcmsdh_intr_disable(void *sdh); -+ -+/* Register/deregister device interrupt handler. */ -+extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); -+extern int bcmsdh_intr_dereg(void *sdh); -+/* Enable/disable SD card interrupt forward */ -+extern void bcmsdh_intr_forward(void *sdh, bool pass); -+ -+#if defined(DHD_DEBUG) -+/* Query pending interrupt status from the host controller */ -+extern bool bcmsdh_intr_pending(void *sdh); -+#endif -+ -+/* Register a callback to be called if and when bcmsdh detects -+ * device removal. No-op in the case of non-removable/hardwired devices. -+ */ -+extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); -+ -+/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). -+ * fn: function number -+ * addr: unmodified SDIO-space address -+ * data: data byte to write -+ * err: pointer to error code (or NULL) -+ */ -+extern uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); -+extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); -+ -+/* Read/Write 4bytes from/to cfg space */ -+extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); -+extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err); -+ -+/* Read CIS content for specified function. -+ * fn: function whose CIS is being requested (0 is common CIS) -+ * cis: pointer to memory location to place results -+ * length: number of bytes to read -+ * Internally, this routine uses the values from the cis base regs (0x9-0xB) -+ * to form an SDIO-space address to read the data from. -+ */ -+extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); -+ -+/* Synchronous access to device (client) core registers via CMD53 to F1. -+ * addr: backplane address (i.e. >= regsva from attach) -+ * size: register width in bytes (2 or 4) -+ * data: data for register write -+ */ -+extern uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); -+extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); -+ -+/* set sb address window */ -+extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); -+ -+/* Indicate if last reg read/write failed */ -+extern bool bcmsdh_regfail(void *sdh); -+ -+/* Buffer transfer to/from device (client) core via cmd53. -+ * fn: function number -+ * addr: backplane address (i.e. >= regsva from attach) -+ * flags: backplane width, address increment, sync/async -+ * buf: pointer to memory data buffer -+ * nbytes: number of bytes to transfer to/from buf -+ * pkt: pointer to packet associated with buf (if any) -+ * complete: callback function for command completion (async only) -+ * handle: handle for completion callback (first arg in callback) -+ * Returns 0 or error code. -+ * NOTE: Async operation is not currently supported. -+ */ -+typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); -+extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, -+ uint8 *buf, uint nbytes, void *pkt, -+ bcmsdh_cmplt_fn_t complete_fn, void *handle); -+extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, -+ uint8 *buf, uint nbytes, void *pkt, -+ bcmsdh_cmplt_fn_t complete_fn, void *handle); -+ -+extern void bcmsdh_glom_post(void *sdh, uint8 *frame, uint len); -+extern void bcmsdh_glom_clear(void *sdh); -+extern uint bcmsdh_set_mode(void *sdh, uint mode); -+extern bool bcmsdh_glom_enabled(void); -+/* Flags bits */ -+#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */ -+#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */ -+#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */ -+#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ -+ -+/* Pending (non-error) return code */ -+#define BCME_PENDING 1 -+ -+/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). -+ * rw: read or write (0/1) -+ * addr: direct SDIO address -+ * buf: pointer to memory data buffer -+ * nbytes: number of bytes to transfer to/from buf -+ * Returns 0 or error code. -+ */ -+extern int bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); -+ -+/* Issue an abort to the specified function */ -+extern int bcmsdh_abort(void *sdh, uint fn); -+ -+/* Start SDIO Host Controller communication */ -+extern int bcmsdh_start(void *sdh, int stage); -+ -+/* Stop SDIO Host Controller communication */ -+extern int bcmsdh_stop(void *sdh); -+ -+/* Wait system lock free */ -+extern int bcmsdh_waitlockfree(void *sdh); -+ -+/* Returns the "Device ID" of target device on the SDIO bus. */ -+extern int bcmsdh_query_device(void *sdh); -+ -+/* Returns the number of IO functions reported by the device */ -+extern uint bcmsdh_query_iofnum(void *sdh); -+ -+/* Miscellaneous knob tweaker. */ -+extern int bcmsdh_iovar_op(void *sdh, const char *name, -+ void *params, int plen, void *arg, int len, bool set); -+ -+/* Reset and reinitialize the device */ -+extern int bcmsdh_reset(bcmsdh_info_t *sdh); -+ -+/* helper functions */ -+ -+extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); -+ -+/* callback functions */ -+typedef struct { -+ /* attach to device */ -+ void *(*attach)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, -+ uint16 func, uint bustype, void * regsva, osl_t * osh, -+ void * param); -+ /* detach from device */ -+ void (*detach)(void *ch); -+} bcmsdh_driver_t; -+ -+/* platform specific/high level functions */ -+extern int bcmsdh_register(bcmsdh_driver_t *driver); -+extern void bcmsdh_unregister(void); -+extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); -+extern void bcmsdh_device_remove(void * sdh); -+ -+extern int bcmsdh_reg_sdio_notify(void* semaphore); -+extern void bcmsdh_unreg_sdio_notify(void); -+ -+#if defined(OOB_INTR_ONLY) -+extern int bcmsdh_register_oob_intr(void * dhdp); -+extern void bcmsdh_unregister_oob_intr(void); -+extern void bcmsdh_oob_intr_set(bool enable); -+#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ -+ -+/* Function to pass device-status bits to DHD. */ -+extern uint32 bcmsdh_get_dstatus(void *sdh); -+ -+/* Function to return current window addr */ -+extern uint32 bcmsdh_cur_sbwad(void *sdh); -+ -+/* Function to pass chipid and rev to lower layers for controlling pr's */ -+extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); -+ -+ -+extern int bcmsdh_sleep(void *sdh, bool enab); -+ -+/* GPIO support */ -+extern int bcmsdh_gpio_init(void *sd); -+extern bool bcmsdh_gpioin(void *sd, uint32 gpio); -+extern int bcmsdh_gpioouten(void *sd, uint32 gpio); -+extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); -+ -+#endif /* _bcmsdh_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h -new file mode 100644 -index 00000000..0e11b11e ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h -@@ -0,0 +1,125 @@ -+/* -+ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdh_sdmmc.h 355594 2012-09-07 10:22:02Z $ -+ */ -+ -+#ifndef __BCMSDH_SDMMC_H__ -+#define __BCMSDH_SDMMC_H__ -+ -+#define sd_err(x) -+#define sd_trace(x) -+#define sd_info(x) -+#define sd_debug(x) -+#define sd_data(x) -+#define sd_ctrl(x) -+ -+#define sd_trace_hw4 sd_trace -+ -+#define sd_sync_dma(sd, read, nbytes) -+#define sd_init_dma(sd) -+#define sd_ack_intr(sd) -+#define sd_wakeup(sd); -+ -+/* Allocate/init/free per-OS private data */ -+extern int sdioh_sdmmc_osinit(sdioh_info_t *sd); -+extern void sdioh_sdmmc_osfree(sdioh_info_t *sd); -+ -+#define sd_log(x) -+ -+#define SDIOH_ASSERT(exp) \ -+ do { if (!(exp)) \ -+ printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ -+ } while (0) -+ -+#define BLOCK_SIZE_4318 64 -+#define BLOCK_SIZE_4328 512 -+ -+/* internal return code */ -+#define SUCCESS 0 -+#define ERROR 1 -+ -+/* private bus modes */ -+#define SDIOH_MODE_SD4 2 -+#define CLIENT_INTR 0x100 /* Get rid of this! */ -+ -+struct sdioh_info { -+ osl_t *osh; /* osh handler */ -+ bool client_intr_enabled; /* interrupt connnected flag */ -+ bool intr_handler_valid; /* client driver interrupt handler valid */ -+ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ -+ void *intr_handler_arg; /* argument to call interrupt handler */ -+ uint16 intmask; /* Current active interrupts */ -+ void *sdos_info; /* Pointer to per-OS private data */ -+ -+ uint irq; /* Client irq */ -+ int intrcount; /* Client interrupts */ -+ -+ bool sd_use_dma; /* DMA on CMD53 */ -+ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ -+ /* Must be on for sd_multiblock to be effective */ -+ bool use_client_ints; /* If this is false, make sure to restore */ -+ int sd_mode; /* SD1/SD4/SPI */ -+ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ -+ uint8 num_funcs; /* Supported funcs on client */ -+ uint32 com_cis_ptr; -+ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; -+ -+#define SDIOH_SDMMC_MAX_SG_ENTRIES 32 -+ struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; -+ bool use_rxchain; -+}; -+ -+/************************************************************ -+ * Internal interfaces: per-port references into bcmsdh_sdmmc.c -+ */ -+ -+/* Global message bits */ -+extern uint sd_msglevel; -+ -+/* OS-independent interrupt handler */ -+extern bool check_client_intr(sdioh_info_t *sd); -+ -+/* Core interrupt enable/disable of device interrupts */ -+extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); -+extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); -+ -+ -+/************************************************************** -+ * Internal interfaces: bcmsdh_sdmmc.c references to per-port code -+ */ -+ -+/* Register mapping routines */ -+extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); -+extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); -+ -+/* Interrupt (de)registration routines */ -+extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); -+extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); -+ -+typedef struct _BCMSDH_SDMMC_INSTANCE { -+ sdioh_info_t *sd; -+ struct sdio_func *func[SDIOD_MAX_IOFUNCS]; -+} BCMSDH_SDMMC_INSTANCE, *PBCMSDH_SDMMC_INSTANCE; -+ -+#endif /* __BCMSDH_SDMMC_H__ */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h -new file mode 100644 -index 00000000..fb2ec3af ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h -@@ -0,0 +1,281 @@ -+/* -+ * Broadcom SDIO/PCMCIA -+ * Software-specific definitions shared between device and host side -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdpcm.h 362722 2012-10-12 23:55:55Z $ -+ */ -+ -+#ifndef _bcmsdpcm_h_ -+#define _bcmsdpcm_h_ -+ -+/* -+ * Software allocation of To SB Mailbox resources -+ */ -+ -+/* intstatus bits */ -+#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ -+#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ -+#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ -+#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ -+ -+#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) -+ -+/* tosbmailbox bits corresponding to intstatus bits */ -+#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ -+#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ -+#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ -+#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ -+#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ -+ -+/* tosbmailboxdata */ -+#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ -+#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ -+ -+/* -+ * Software allocation of To Host Mailbox resources -+ */ -+ -+/* intstatus bits */ -+#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ -+#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ -+#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ -+#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ -+ -+#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT) -+ -+/* tohostmailbox bits corresponding to intstatus bits */ -+#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */ -+#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */ -+#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ -+#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ -+#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ -+ -+/* tohostmailboxdata */ -+#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ -+#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ -+#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ -+#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ -+#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ -+ -+#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ -+#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ -+ -+#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ -+#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ -+ -+/* -+ * Software-defined protocol header -+ */ -+ -+/* Current protocol version */ -+#define SDPCM_PROT_VERSION 4 -+ -+/* SW frame header */ -+#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ -+#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ -+ -+#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ -+#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ -+#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ -+ -+#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ -+#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ -+#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ -+ -+/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ -+#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ -+#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ -+#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ -+#define SDPCM_NEXTLEN_OFFSET 2 -+ -+/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ -+#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ -+#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) -+#define SDPCM_DOFFSET_MASK 0xff000000 -+#define SDPCM_DOFFSET_SHIFT 24 -+ -+#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ -+#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) -+#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ -+#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) -+#define SDPCM_VERSION_OFFSET 6 /* Version # */ -+#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) -+#define SDPCM_UNUSED_OFFSET 7 /* Spare */ -+#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) -+ -+#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ -+ -+/* logical channel numbers */ -+#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */ -+#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ -+#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ -+#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */ -+#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ -+#define SDPCM_MAX_CHANNEL 15 -+ -+#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ -+ -+#define SDPCM_FLAG_RESVD0 0x01 -+#define SDPCM_FLAG_RESVD1 0x02 -+#define SDPCM_FLAG_GSPI_TXENAB 0x04 -+#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ -+ -+/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ -+#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) -+ -+#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80) -+ -+/* For TEST_CHANNEL packets, define another 4-byte header */ -+#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2); -+ * Semantics of Ext byte depend on command. -+ * Len is current or requested frame length, not -+ * including test header; sent little-endian. -+ */ -+#define SDPCM_TEST_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ -+#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ -+#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ -+#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ -+#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count -+ * (Backward compatabilty) Set frame count in a -+ * 4 byte filed adjacent to the HDR -+ */ -+#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off -+ * Set frame count in a 4 byte filed adjacent to -+ * the HDR -+ */ -+ -+/* Handy macro for filling in datagen packets with a pattern */ -+#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) -+ -+/* -+ * Software counters (first part matches hardware counters) -+ */ -+ -+typedef volatile struct { -+ uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ -+ uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ -+ uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ -+ uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ -+ uint32 abort; /* AbortCount, SDIO: aborts */ -+ uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ -+ uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ -+ uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ -+ uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ -+ uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ -+ uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ -+ uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ -+ uint32 rxdescuflo; /* receive descriptor underflows */ -+ uint32 rxfifooflo; /* receive fifo overflows */ -+ uint32 txfifouflo; /* transmit fifo underflows */ -+ uint32 runt; /* runt (too short) frames recv'd from bus */ -+ uint32 badlen; /* frame's rxh len does not match its hw tag len */ -+ uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ -+ uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ -+ uint32 rxfcrc; /* frame rx header indicates crc error */ -+ uint32 rxfwoos; /* frame rx header indicates write out of sync */ -+ uint32 rxfwft; /* frame rx header indicates write frame termination */ -+ uint32 rxfabort; /* frame rx header indicates frame aborted */ -+ uint32 woosint; /* write out of sync interrupt */ -+ uint32 roosint; /* read out of sync interrupt */ -+ uint32 rftermint; /* read frame terminate interrupt */ -+ uint32 wftermint; /* write frame terminate interrupt */ -+} sdpcmd_cnt_t; -+ -+/* -+ * Register Access Macros -+ */ -+ -+#define SDIODREV_IS(var, val) ((var) == (val)) -+#define SDIODREV_GE(var, val) ((var) >= (val)) -+#define SDIODREV_GT(var, val) ((var) > (val)) -+#define SDIODREV_LT(var, val) ((var) < (val)) -+#define SDIODREV_LE(var, val) ((var) <= (val)) -+ -+#define SDIODDMAREG32(h, dir, chnl) \ -+ ((dir) == DMA_TX ? \ -+ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ -+ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) -+ -+#define SDIODDMAREG64(h, dir, chnl) \ -+ ((dir) == DMA_TX ? \ -+ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ -+ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) -+ -+#define SDIODDMAREG(h, dir, chnl) \ -+ (SDIODREV_LT((h)->corerev, 1) ? \ -+ SDIODDMAREG32((h), (dir), (chnl)) : \ -+ SDIODDMAREG64((h), (dir), (chnl))) -+ -+#define PCMDDMAREG(h, dir, chnl) \ -+ ((dir) == DMA_TX ? \ -+ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ -+ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) -+ -+#define SDPCMDMAREG(h, dir, chnl, coreid) \ -+ ((coreid) == SDIOD_CORE_ID ? \ -+ SDIODDMAREG(h, dir, chnl) : \ -+ PCMDDMAREG(h, dir, chnl)) -+ -+#define SDIODFIFOREG(h, corerev) \ -+ (SDIODREV_LT((corerev), 1) ? \ -+ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ -+ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) -+ -+#define PCMDFIFOREG(h) \ -+ ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) -+ -+#define SDPCMFIFOREG(h, coreid, corerev) \ -+ ((coreid) == SDIOD_CORE_ID ? \ -+ SDIODFIFOREG(h, corerev) : \ -+ PCMDFIFOREG(h)) -+ -+/* -+ * Shared structure between dongle and the host. -+ * The structure contains pointers to trap or assert information. -+ */ -+#define SDPCM_SHARED_VERSION 0x0001 -+#define SDPCM_SHARED_VERSION_MASK 0x00FF -+#define SDPCM_SHARED_ASSERT_BUILT 0x0100 -+#define SDPCM_SHARED_ASSERT 0x0200 -+#define SDPCM_SHARED_TRAP 0x0400 -+#define SDPCM_SHARED_IN_BRPT 0x0800 -+#define SDPCM_SHARED_SET_BRPT 0x1000 -+#define SDPCM_SHARED_PENDING_BRPT 0x2000 -+ -+typedef struct { -+ uint32 flags; -+ uint32 trap_addr; -+ uint32 assert_exp_addr; -+ uint32 assert_file_addr; -+ uint32 assert_line; -+ uint32 console_addr; /* Address of hndrte_cons_t */ -+ uint32 msgtrace_addr; -+ uint32 brpt_addr; -+} sdpcm_shared_t; -+ -+extern sdpcm_shared_t sdpcm_shared; -+ -+/* Function can be used to notify host of FW halt */ -+extern void sdpcmd_fwhalt(void); -+ -+#endif /* _bcmsdpcm_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h -new file mode 100644 -index 00000000..3d444f3b ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h -@@ -0,0 +1,135 @@ -+/* -+ * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdspi.h 294363 2011-11-06 23:02:20Z $ -+ */ -+#ifndef _BCM_SD_SPI_H -+#define _BCM_SD_SPI_H -+ -+/* global msglevel for debug messages - bitvals come from sdiovar.h */ -+ -+#define sd_err(x) -+#define sd_trace(x) -+#define sd_info(x) -+#define sd_debug(x) -+#define sd_data(x) -+#define sd_ctrl(x) -+ -+#define sd_log(x) -+ -+#define SDIOH_ASSERT(exp) \ -+ do { if (!(exp)) \ -+ printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ -+ } while (0) -+ -+#define BLOCK_SIZE_4318 64 -+#define BLOCK_SIZE_4328 512 -+ -+/* internal return code */ -+#define SUCCESS 0 -+#undef ERROR -+#define ERROR 1 -+ -+/* private bus modes */ -+#define SDIOH_MODE_SPI 0 -+ -+#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -+#define USE_MULTIBLOCK 0x4 -+ -+struct sdioh_info { -+ uint cfg_bar; /* pci cfg address for bar */ -+ uint32 caps; /* cached value of capabilities reg */ -+ uint bar0; /* BAR0 for PCI Device */ -+ osl_t *osh; /* osh handler */ -+ void *controller; /* Pointer to SPI Controller's private data struct */ -+ -+ uint lockcount; /* nest count of sdspi_lock() calls */ -+ bool client_intr_enabled; /* interrupt connnected flag */ -+ bool intr_handler_valid; /* client driver interrupt handler valid */ -+ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ -+ void *intr_handler_arg; /* argument to call interrupt handler */ -+ bool initialized; /* card initialized */ -+ uint32 target_dev; /* Target device ID */ -+ uint32 intmask; /* Current active interrupts */ -+ void *sdos_info; /* Pointer to per-OS private data */ -+ -+ uint32 controller_type; /* Host controller type */ -+ uint8 version; /* Host Controller Spec Compliance Version */ -+ uint irq; /* Client irq */ -+ uint32 intrcount; /* Client interrupts */ -+ uint32 local_intrcount; /* Controller interrupts */ -+ bool host_init_done; /* Controller initted */ -+ bool card_init_done; /* Client SDIO interface initted */ -+ bool polled_mode; /* polling for command completion */ -+ -+ bool sd_use_dma; /* DMA on CMD53 */ -+ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ -+ /* Must be on for sd_multiblock to be effective */ -+ bool use_client_ints; /* If this is false, make sure to restore */ -+ bool got_hcint; /* Host Controller interrupt. */ -+ /* polling hack in wl_linux.c:wl_timer() */ -+ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ -+ int sd_mode; /* SD1/SD4/SPI */ -+ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ -+ uint32 data_xfer_count; /* Current register transfer size */ -+ uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ -+ uint32 card_response; /* Used to pass back response status byte */ -+ uint32 card_rsp_data; /* Used to pass back response data word */ -+ uint16 card_rca; /* Current Address */ -+ uint8 num_funcs; /* Supported funcs on client */ -+ uint32 com_cis_ptr; -+ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; -+ void *dma_buf; -+ ulong dma_phys; -+ int r_cnt; /* rx count */ -+ int t_cnt; /* tx_count */ -+}; -+ -+/************************************************************ -+ * Internal interfaces: per-port references into bcmsdspi.c -+ */ -+ -+/* Global message bits */ -+extern uint sd_msglevel; -+ -+/************************************************************** -+ * Internal interfaces: bcmsdspi.c references to per-port code -+ */ -+ -+/* Register mapping routines */ -+extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); -+extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); -+ -+/* Interrupt (de)registration routines */ -+extern int spi_register_irq(sdioh_info_t *sd, uint irq); -+extern void spi_free_irq(uint irq, sdioh_info_t *sd); -+ -+/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -+extern void spi_lock(sdioh_info_t *sd); -+extern void spi_unlock(sdioh_info_t *sd); -+ -+/* Allocate/init/free per-OS private data */ -+extern int spi_osinit(sdioh_info_t *sd); -+extern void spi_osfree(sdioh_info_t *sd); -+ -+#endif /* _BCM_SD_SPI_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h -new file mode 100644 -index 00000000..896686cf ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h -@@ -0,0 +1,264 @@ -+/* -+ * 'Standard' SDIO HOST CONTROLLER driver -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmsdstd.h 347614 2012-07-27 10:24:51Z $ -+ */ -+#ifndef _BCM_SD_STD_H -+#define _BCM_SD_STD_H -+ -+/* global msglevel for debug messages - bitvals come from sdiovar.h */ -+#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) -+#define sd_trace(x) -+#define sd_info(x) -+#define sd_debug(x) -+#define sd_data(x) -+#define sd_ctrl(x) -+#define sd_dma(x) -+ -+#define sd_sync_dma(sd, read, nbytes) -+#define sd_init_dma(sd) -+#define sd_ack_intr(sd) -+#define sd_wakeup(sd); -+/* Allocate/init/free per-OS private data */ -+extern int sdstd_osinit(sdioh_info_t *sd); -+extern void sdstd_osfree(sdioh_info_t *sd); -+ -+#define sd_log(x) -+ -+#define SDIOH_ASSERT(exp) \ -+ do { if (!(exp)) \ -+ printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ -+ } while (0) -+ -+#define BLOCK_SIZE_4318 64 -+#define BLOCK_SIZE_4328 512 -+ -+/* internal return code */ -+#define SUCCESS 0 -+#define ERROR 1 -+ -+/* private bus modes */ -+#define SDIOH_MODE_SPI 0 -+#define SDIOH_MODE_SD1 1 -+#define SDIOH_MODE_SD4 2 -+ -+#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ -+#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ -+ -+#define SDIOH_TYPE_ARASAN_HDK 1 -+#define SDIOH_TYPE_BCM27XX 2 -+#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ -+#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ -+#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ -+ -+/* For linux, allow yielding for dongle */ -+#define BCMSDYIELD -+ -+/* Expected card status value for CMD7 */ -+#define SDIOH_CMD7_EXP_STATUS 0x00001E00 -+ -+#define RETRIES_LARGE 100000 -+#define sdstd_os_yield(sd) do {} while (0) -+#define RETRIES_SMALL 100 -+ -+ -+#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ -+#define USE_MULTIBLOCK 0x4 -+ -+#define USE_FIFO 0x8 /* Fifo vs non-fifo */ -+ -+#define CLIENT_INTR 0x100 /* Get rid of this! */ -+ -+#define HC_INTR_RETUNING 0x1000 -+ -+ -+#ifdef BCMSDIOH_TXGLOM -+/* Setting the MAX limit to 10 */ -+#define SDIOH_MAXGLOM_SIZE 10 -+ -+typedef struct glom_buf { -+ uint32 count; /* Total number of pkts queued */ -+ void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ -+ ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ -+ uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ -+} glom_buf_t; -+#endif -+ -+struct sdioh_info { -+ uint cfg_bar; /* pci cfg address for bar */ -+ uint32 caps; /* cached value of capabilities reg */ -+ uint32 curr_caps; /* max current capabilities reg */ -+ -+ osl_t *osh; /* osh handler */ -+ volatile char *mem_space; /* pci device memory va */ -+ uint lockcount; /* nest count of sdstd_lock() calls */ -+ bool client_intr_enabled; /* interrupt connnected flag */ -+ bool intr_handler_valid; /* client driver interrupt handler valid */ -+ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ -+ void *intr_handler_arg; /* argument to call interrupt handler */ -+ bool initialized; /* card initialized */ -+ uint target_dev; /* Target device ID */ -+ uint16 intmask; /* Current active interrupts */ -+ void *sdos_info; /* Pointer to per-OS private data */ -+ -+ uint32 controller_type; /* Host controller type */ -+ uint8 version; /* Host Controller Spec Compliance Version */ -+ uint irq; /* Client irq */ -+ int intrcount; /* Client interrupts */ -+ int local_intrcount; /* Controller interrupts */ -+ bool host_init_done; /* Controller initted */ -+ bool card_init_done; /* Client SDIO interface initted */ -+ bool polled_mode; /* polling for command completion */ -+ -+ bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */ -+ /* Must be on for sd_multiblock to be effective */ -+ bool use_client_ints; /* If this is false, make sure to restore */ -+ /* polling hack in wl_linux.c:wl_timer() */ -+ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ -+ int sd_mode; /* SD1/SD4/SPI */ -+ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ -+ uint32 data_xfer_count; /* Current transfer */ -+ uint16 card_rca; /* Current Address */ -+ int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ -+ uint8 num_funcs; /* Supported funcs on client */ -+ uint32 com_cis_ptr; -+ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; -+ void *dma_buf; /* DMA Buffer virtual address */ -+ ulong dma_phys; /* DMA Buffer physical address */ -+ void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ -+ ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ -+ -+ /* adjustments needed to make the dma align properly */ -+ void *dma_start_buf; -+ ulong dma_start_phys; -+ uint alloced_dma_size; -+ void *adma2_dscr_start_buf; -+ ulong adma2_dscr_start_phys; -+ uint alloced_adma2_dscr_size; -+ -+ int r_cnt; /* rx count */ -+ int t_cnt; /* tx_count */ -+ bool got_hcint; /* local interrupt flag */ -+ uint16 last_intrstatus; /* to cache intrstatus */ -+ int host_UHSISupported; /* whether UHSI is supported for HC. */ -+ int card_UHSI_voltage_Supported; /* whether UHSI is supported for -+ * Card in terms of Voltage [1.8 or 3.3]. -+ */ -+ int global_UHSI_Supp; /* type of UHSI support in both host and card. -+ * HOST_SDR_UNSUPP: capabilities not supported/matched -+ * HOST_SDR_12_25: SDR12 and SDR25 supported -+ * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd -+ */ -+ volatile int sd3_dat_state; /* data transfer state used for retuning check */ -+ volatile int sd3_tun_state; /* tuning state used for retuning check */ -+ bool sd3_tuning_reqd; /* tuning requirement parameter */ -+ uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ -+#ifdef BCMSDIOH_TXGLOM -+ glom_buf_t glom_info; /* pkt information used for glomming */ -+ uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ -+#endif -+}; -+ -+#define DMA_MODE_NONE 0 -+#define DMA_MODE_SDMA 1 -+#define DMA_MODE_ADMA1 2 -+#define DMA_MODE_ADMA2 3 -+#define DMA_MODE_ADMA2_64 4 -+#define DMA_MODE_AUTO -1 -+ -+#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) -+ -+/* States for Tuning and corr data */ -+#define TUNING_IDLE 0 -+#define TUNING_START 1 -+#define TUNING_START_AFTER_DAT 2 -+#define TUNING_ONGOING 3 -+ -+#define DATA_TRANSFER_IDLE 0 -+#define DATA_TRANSFER_ONGOING 1 -+ -+#define CHECK_TUNING_PRE_DATA 1 -+#define CHECK_TUNING_POST_DATA 2 -+ -+/************************************************************ -+ * Internal interfaces: per-port references into bcmsdstd.c -+ */ -+ -+/* Global message bits */ -+extern uint sd_msglevel; -+ -+/* OS-independent interrupt handler */ -+extern bool check_client_intr(sdioh_info_t *sd); -+ -+/* Core interrupt enable/disable of device interrupts */ -+extern void sdstd_devintr_on(sdioh_info_t *sd); -+extern void sdstd_devintr_off(sdioh_info_t *sd); -+ -+/* Enable/disable interrupts for local controller events */ -+extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); -+extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); -+ -+/* Wait for specified interrupt and error bits to be set */ -+extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); -+ -+ -+/************************************************************** -+ * Internal interfaces: bcmsdstd.c references to per-port code -+ */ -+ -+/* Register mapping routines */ -+extern uint32 *sdstd_reg_map(osl_t *osh, int32 addr, int size); -+extern void sdstd_reg_unmap(osl_t *osh, int32 addr, int size); -+ -+/* Interrupt (de)registration routines */ -+extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); -+extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); -+ -+/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ -+extern void sdstd_lock(sdioh_info_t *sd); -+extern void sdstd_unlock(sdioh_info_t *sd); -+extern void sdstd_waitlockfree(sdioh_info_t *sd); -+ -+/* OS-specific wait-for-interrupt-or-status */ -+extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); -+ -+/* used by bcmsdstd_linux [implemented in sdstd] */ -+extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); -+extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); -+extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); -+extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); -+extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); -+extern int sdstd_3_get_tune_state(sdioh_info_t *sd); -+extern int sdstd_3_get_data_state(sdioh_info_t *sd); -+extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); -+extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); -+extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); -+extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); -+extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); -+ -+/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ -+extern void sdstd_3_start_tuning(sdioh_info_t *sd); -+extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); -+extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); -+ -+#endif /* _BCM_SD_STD_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h -new file mode 100644 -index 00000000..e226cb10 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmspi.h -@@ -0,0 +1,40 @@ -+/* -+ * Broadcom SPI Low-Level Hardware Driver API -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmspi.h 241182 2011-02-17 21:50:03Z $ -+ */ -+#ifndef _BCM_SPI_H -+#define _BCM_SPI_H -+ -+extern void spi_devintr_off(sdioh_info_t *sd); -+extern void spi_devintr_on(sdioh_info_t *sd); -+extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); -+extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); -+extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); -+extern bool spi_hw_attach(sdioh_info_t *sd); -+extern bool spi_hw_detach(sdioh_info_t *sd); -+extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); -+extern void spi_spinbits(sdioh_info_t *sd); -+extern void spi_waitbits(sdioh_info_t *sd, bool yield); -+ -+#endif /* _BCM_SPI_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h -new file mode 100644 -index 00000000..6db5e932 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h -@@ -0,0 +1,773 @@ -+/* -+ * Misc useful os-independent macros and functions. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmutils.h 347624 2012-07-27 10:49:56Z $ -+ */ -+ -+#ifndef _bcmutils_h_ -+#define _bcmutils_h_ -+ -+#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) -+#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) -+#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#ifdef PKTQ_LOG -+#include <wlioctl.h> -+#endif -+ -+ -+#define _BCM_U 0x01 -+#define _BCM_L 0x02 -+#define _BCM_D 0x04 -+#define _BCM_C 0x08 -+#define _BCM_P 0x10 -+#define _BCM_S 0x20 -+#define _BCM_X 0x40 -+#define _BCM_SP 0x80 -+ -+extern const unsigned char bcm_ctype[]; -+#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) -+ -+#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) -+#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) -+#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) -+#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) -+#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) -+#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) -+#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) -+#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) -+#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) -+#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) -+#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) -+#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -+#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) -+ -+ -+ -+struct bcmstrbuf { -+ char *buf; -+ unsigned int size; -+ char *origbuf; -+ unsigned int origsize; -+}; -+ -+ -+#ifdef BCMDRIVER -+#include <osl.h> -+ -+#define GPIO_PIN_NOTDEFINED 0x20 -+ -+ -+#define SPINWAIT(exp, us) { \ -+ uint countdown = (us) + 9; \ -+ while ((exp) && (countdown >= 10)) {\ -+ OSL_DELAY(10); \ -+ countdown -= 10; \ -+ } \ -+} -+ -+ -+#ifndef PKTQ_LEN_DEFAULT -+#define PKTQ_LEN_DEFAULT 128 -+#endif -+#ifndef PKTQ_MAX_PREC -+#define PKTQ_MAX_PREC 16 -+#endif -+ -+typedef struct pktq_prec { -+ void *head; -+ void *tail; -+ uint16 len; -+ uint16 max; -+} pktq_prec_t; -+ -+#ifdef PKTQ_LOG -+typedef struct { -+ uint32 requested; -+ uint32 stored; -+ uint32 saved; -+ uint32 selfsaved; -+ uint32 full_dropped; -+ uint32 dropped; -+ uint32 sacrificed; -+ uint32 busy; -+ uint32 retry; -+ uint32 ps_retry; -+ uint32 retry_drop; -+ uint32 max_avail; -+ uint32 max_used; -+ uint32 queue_capacity; -+} pktq_counters_t; -+#endif -+ -+ -+#define PKTQ_COMMON \ -+ uint16 num_prec; \ -+ uint16 hi_prec; \ -+ uint16 max; \ -+ uint16 len; -+ -+ -+struct pktq { -+ PKTQ_COMMON -+ -+ struct pktq_prec q[PKTQ_MAX_PREC]; -+#ifdef PKTQ_LOG -+ pktq_counters_t _prec_cnt[PKTQ_MAX_PREC]; -+#endif -+}; -+ -+ -+struct spktq { -+ PKTQ_COMMON -+ -+ struct pktq_prec q[1]; -+}; -+ -+#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) -+ -+ -+typedef bool (*ifpkt_cb_t)(void*, int); -+ -+#ifdef BCMPKTPOOL -+#define POOL_ENAB(pool) ((pool) && (pool)->inited) -+#define SHARED_POOL (pktpool_shared) -+#else -+#define POOL_ENAB(bus) 0 -+#define SHARED_POOL ((struct pktpool *)NULL) -+#endif -+ -+#ifndef PKTPOOL_LEN_MAX -+#define PKTPOOL_LEN_MAX 40 -+#endif -+#define PKTPOOL_CB_MAX 3 -+ -+struct pktpool; -+typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); -+typedef struct { -+ pktpool_cb_t cb; -+ void *arg; -+} pktpool_cbinfo_t; -+ -+#ifdef BCMDBG_POOL -+ -+#define POOL_IDLE 0 -+#define POOL_RXFILL 1 -+#define POOL_RXDH 2 -+#define POOL_RXD11 3 -+#define POOL_TXDH 4 -+#define POOL_TXD11 5 -+#define POOL_AMPDU 6 -+#define POOL_TXENQ 7 -+ -+typedef struct { -+ void *p; -+ uint32 cycles; -+ uint32 dur; -+} pktpool_dbg_t; -+ -+typedef struct { -+ uint8 txdh; -+ uint8 txd11; -+ uint8 enq; -+ uint8 rxdh; -+ uint8 rxd11; -+ uint8 rxfill; -+ uint8 idle; -+} pktpool_stats_t; -+#endif -+ -+typedef struct pktpool { -+ bool inited; -+ uint16 r; -+ uint16 w; -+ uint16 len; -+ uint16 maxlen; -+ uint16 plen; -+ bool istx; -+ bool empty; -+ uint8 cbtoggle; -+ uint8 cbcnt; -+ uint8 ecbcnt; -+ bool emptycb_disable; -+ pktpool_cbinfo_t *availcb_excl; -+ pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; -+ pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; -+ void *q[PKTPOOL_LEN_MAX + 1]; -+ -+#ifdef BCMDBG_POOL -+ uint8 dbg_cbcnt; -+ pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; -+ uint16 dbg_qlen; -+ pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; -+#endif -+} pktpool_t; -+ -+extern pktpool_t *pktpool_shared; -+ -+extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx); -+extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); -+extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); -+extern void* pktpool_get(pktpool_t *pktp); -+extern void pktpool_free(pktpool_t *pktp, void *p); -+extern int pktpool_add(pktpool_t *pktp, void *p); -+extern uint16 pktpool_avail(pktpool_t *pktp); -+extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); -+extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); -+extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -+extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -+extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); -+extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); -+extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); -+extern bool pktpool_emptycb_disabled(pktpool_t *pktp); -+ -+#define POOLPTR(pp) ((pktpool_t *)(pp)) -+#define pktpool_len(pp) (POOLPTR(pp)->len - 1) -+#define pktpool_plen(pp) (POOLPTR(pp)->plen) -+#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) -+ -+#ifdef BCMDBG_POOL -+extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); -+extern int pktpool_start_trigger(pktpool_t *pktp, void *p); -+extern int pktpool_dbg_dump(pktpool_t *pktp); -+extern int pktpool_dbg_notify(pktpool_t *pktp); -+extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); -+#endif -+ -+ -+ -+struct ether_addr; -+ -+extern int ether_isbcast(const void *ea); -+extern int ether_isnulladdr(const void *ea); -+ -+ -+ -+#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) -+#define pktq_pmax(pq, prec) ((pq)->q[prec].max) -+#define pktq_plen(pq, prec) ((pq)->q[prec].len) -+#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) -+#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) -+#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) -+ -+#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) -+#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) -+ -+extern void *pktq_penq(struct pktq *pq, int prec, void *p); -+extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); -+extern void *pktq_pdeq(struct pktq *pq, int prec); -+extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); -+extern void *pktq_pdeq_tail(struct pktq *pq, int prec); -+ -+extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, -+ ifpkt_cb_t fn, int arg); -+ -+extern bool pktq_pdel(struct pktq *pq, void *p, int prec); -+ -+ -+ -+extern int pktq_mlen(struct pktq *pq, uint prec_bmp); -+extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); -+extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); -+ -+ -+ -+#define pktq_len(pq) ((int)(pq)->len) -+#define pktq_max(pq) ((int)(pq)->max) -+#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) -+#define pktq_full(pq) ((pq)->len >= (pq)->max) -+#define pktq_empty(pq) ((pq)->len == 0) -+ -+ -+#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) -+#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) -+#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) -+#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) -+#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) -+ -+extern void pktq_init(struct pktq *pq, int num_prec, int max_len); -+extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); -+ -+ -+extern void *pktq_deq(struct pktq *pq, int *prec_out); -+extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); -+extern void *pktq_peek(struct pktq *pq, int *prec_out); -+extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); -+extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); -+ -+ -+ -+extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); -+extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); -+extern uint pkttotlen(osl_t *osh, void *p); -+extern void *pktlast(osl_t *osh, void *p); -+extern uint pktsegcnt(osl_t *osh, void *p); -+extern uint pktsegcnt_war(osl_t *osh, void *p); -+extern uint8 *pktoffset(osl_t *osh, void *p, uint offset); -+ -+ -+#define PKTPRIO_VDSCP 0x100 -+#define PKTPRIO_VLAN 0x200 -+#define PKTPRIO_UPD 0x400 -+#define PKTPRIO_DSCP 0x800 -+ -+extern uint pktsetprio(void *pkt, bool update_vtag); -+ -+ -+extern int bcm_atoi(const char *s); -+extern ulong bcm_strtoul(const char *cp, char **endp, uint base); -+extern char *bcmstrstr(const char *haystack, const char *needle); -+extern char *bcmstrcat(char *dest, const char *src); -+extern char *bcmstrncat(char *dest, const char *src, uint size); -+extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); -+char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); -+int bcmstricmp(const char *s1, const char *s2); -+int bcmstrnicmp(const char* s1, const char* s2, int cnt); -+ -+ -+ -+extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); -+extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); -+ -+ -+struct ipv4_addr; -+extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); -+ -+ -+extern void bcm_mdelay(uint ms); -+ -+#define NVRAM_RECLAIM_CHECK(name) -+ -+extern char *getvar(char *vars, const char *name); -+extern int getintvar(char *vars, const char *name); -+extern int getintvararray(char *vars, const char *name, int index); -+extern int getintvararraysize(char *vars, const char *name); -+extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); -+#define bcm_perf_enable() -+#define bcmstats(fmt) -+#define bcmlog(fmt, a1, a2) -+#define bcmdumplog(buf, size) *buf = '\0' -+#define bcmdumplogent(buf, idx) -1 -+ -+#define bcmtslog(tstamp, fmt, a1, a2) -+#define bcmprinttslogs() -+#define bcmprinttstamp(us) -+#define bcmdumptslog(buf, size) -+ -+extern char *bcm_nvram_vars(uint *length); -+extern int bcm_nvram_cache(void *sih); -+ -+ -+ -+ -+typedef struct bcm_iovar { -+ const char *name; -+ uint16 varid; -+ uint16 flags; -+ uint16 type; -+ uint16 minlen; -+} bcm_iovar_t; -+ -+ -+ -+ -+#define IOV_GET 0 -+#define IOV_SET 1 -+ -+ -+#define IOV_GVAL(id) ((id) * 2) -+#define IOV_SVAL(id) ((id) * 2 + IOV_SET) -+#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) -+#define IOV_ID(actionid) (actionid >> 1) -+ -+ -+ -+extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); -+extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); -+#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ -+ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) -+extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); -+#endif -+#endif -+ -+ -+#define IOVT_VOID 0 -+#define IOVT_BOOL 1 -+#define IOVT_INT8 2 -+#define IOVT_UINT8 3 -+#define IOVT_INT16 4 -+#define IOVT_UINT16 5 -+#define IOVT_INT32 6 -+#define IOVT_UINT32 7 -+#define IOVT_BUFFER 8 -+#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) -+ -+ -+#define BCM_IOV_TYPE_INIT { \ -+ "void", \ -+ "bool", \ -+ "int8", \ -+ "uint8", \ -+ "int16", \ -+ "uint16", \ -+ "int32", \ -+ "uint32", \ -+ "buffer", \ -+ "" } -+ -+#define BCM_IOVT_IS_INT(type) (\ -+ (type == IOVT_BOOL) || \ -+ (type == IOVT_INT8) || \ -+ (type == IOVT_UINT8) || \ -+ (type == IOVT_INT16) || \ -+ (type == IOVT_UINT16) || \ -+ (type == IOVT_INT32) || \ -+ (type == IOVT_UINT32)) -+ -+ -+ -+#define BCME_STRLEN 64 -+#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) -+ -+ -+ -+ -+#define BCME_OK 0 -+#define BCME_ERROR -1 -+#define BCME_BADARG -2 -+#define BCME_BADOPTION -3 -+#define BCME_NOTUP -4 -+#define BCME_NOTDOWN -5 -+#define BCME_NOTAP -6 -+#define BCME_NOTSTA -7 -+#define BCME_BADKEYIDX -8 -+#define BCME_RADIOOFF -9 -+#define BCME_NOTBANDLOCKED -10 -+#define BCME_NOCLK -11 -+#define BCME_BADRATESET -12 -+#define BCME_BADBAND -13 -+#define BCME_BUFTOOSHORT -14 -+#define BCME_BUFTOOLONG -15 -+#define BCME_BUSY -16 -+#define BCME_NOTASSOCIATED -17 -+#define BCME_BADSSIDLEN -18 -+#define BCME_OUTOFRANGECHAN -19 -+#define BCME_BADCHAN -20 -+#define BCME_BADADDR -21 -+#define BCME_NORESOURCE -22 -+#define BCME_UNSUPPORTED -23 -+#define BCME_BADLEN -24 -+#define BCME_NOTREADY -25 -+#define BCME_EPERM -26 -+#define BCME_NOMEM -27 -+#define BCME_ASSOCIATED -28 -+#define BCME_RANGE -29 -+#define BCME_NOTFOUND -30 -+#define BCME_WME_NOT_ENABLED -31 -+#define BCME_TSPEC_NOTFOUND -32 -+#define BCME_ACM_NOTSUPPORTED -33 -+#define BCME_NOT_WME_ASSOCIATION -34 -+#define BCME_SDIO_ERROR -35 -+#define BCME_DONGLE_DOWN -36 -+#define BCME_VERSION -37 -+#define BCME_TXFAIL -38 -+#define BCME_RXFAIL -39 -+#define BCME_NODEVICE -40 -+#define BCME_NMODE_DISABLED -41 -+#define BCME_NONRESIDENT -42 -+#define BCME_LAST BCME_NONRESIDENT -+ -+ -+#define BCMERRSTRINGTABLE { \ -+ "OK", \ -+ "Undefined error", \ -+ "Bad Argument", \ -+ "Bad Option", \ -+ "Not up", \ -+ "Not down", \ -+ "Not AP", \ -+ "Not STA", \ -+ "Bad Key Index", \ -+ "Radio Off", \ -+ "Not band locked", \ -+ "No clock", \ -+ "Bad Rate valueset", \ -+ "Bad Band", \ -+ "Buffer too short", \ -+ "Buffer too long", \ -+ "Busy", \ -+ "Not Associated", \ -+ "Bad SSID len", \ -+ "Out of Range Channel", \ -+ "Bad Channel", \ -+ "Bad Address", \ -+ "Not Enough Resources", \ -+ "Unsupported", \ -+ "Bad length", \ -+ "Not Ready", \ -+ "Not Permitted", \ -+ "No Memory", \ -+ "Associated", \ -+ "Not In Range", \ -+ "Not Found", \ -+ "WME Not Enabled", \ -+ "TSPEC Not Found", \ -+ "ACM Not Supported", \ -+ "Not WME Association", \ -+ "SDIO Bus Error", \ -+ "Dongle Not Accessible", \ -+ "Incorrect version", \ -+ "TX Failure", \ -+ "RX Failure", \ -+ "Device Not Present", \ -+ "NMODE Disabled", \ -+ "Nonresident overlay access", \ -+} -+ -+#ifndef ABS -+#define ABS(a) (((a) < 0) ? -(a) : (a)) -+#endif -+ -+#ifndef MIN -+#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -+#endif -+ -+#ifndef MAX -+#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -+#endif -+ -+#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) -+#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -+#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) -+#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ -+ & ~((boundary) - 1)) -+#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ -+ & ~((boundary) - 1)) -+#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) -+#define VALID_MASK(mask) !((mask) & ((mask) + 1)) -+ -+#ifndef OFFSETOF -+#ifdef __ARMCC_VERSION -+ -+#include <stddef.h> -+#define OFFSETOF(type, member) offsetof(type, member) -+#else -+#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) -+#endif -+#endif -+ -+#ifndef ARRAYSIZE -+#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) -+#endif -+ -+ -+extern void *_bcmutils_dummy_fn; -+#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) -+ -+ -+#ifndef setbit -+#ifndef NBBY -+#define NBBY 8 -+#endif -+#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) -+#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) -+#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) -+#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) -+#endif -+ -+#define NBITS(type) (sizeof(type) * 8) -+#define NBITVAL(nbits) (1 << (nbits)) -+#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) -+#define NBITMASK(nbits) MAXBITVAL(nbits) -+#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) -+ -+ -+#define MUX(pred, true, false) ((pred) ? (true) : (false)) -+ -+ -+#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1) -+#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) -+ -+ -+#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) -+#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) -+ -+ -+#define MODADD(x, y, bound) \ -+ MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) -+#define MODSUB(x, y, bound) \ -+ MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) -+ -+ -+#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) -+#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) -+ -+ -+#define CRC8_INIT_VALUE 0xff -+#define CRC8_GOOD_VALUE 0x9f -+#define CRC16_INIT_VALUE 0xffff -+#define CRC16_GOOD_VALUE 0xf0b8 -+#define CRC32_INIT_VALUE 0xffffffff -+#define CRC32_GOOD_VALUE 0xdebb20e3 -+ -+ -+#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" -+#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ -+ ((struct ether_addr *) (ea))->octet[1], \ -+ ((struct ether_addr *) (ea))->octet[2], \ -+ ((struct ether_addr *) (ea))->octet[3], \ -+ ((struct ether_addr *) (ea))->octet[4], \ -+ ((struct ether_addr *) (ea))->octet[5] -+ -+#define ETHER_TO_MACF(ea) (ea).octet[0], \ -+ (ea).octet[1], \ -+ (ea).octet[2], \ -+ (ea).octet[3], \ -+ (ea).octet[4], \ -+ (ea).octet[5] -+#if !defined(SIMPLE_MAC_PRINT) -+#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" -+#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] -+#else -+#define MACDBG "%02x:%02x:%02x" -+#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] -+#endif /* SIMPLE_MAC_PRINT */ -+ -+typedef struct bcm_bit_desc { -+ uint32 bit; -+ const char* name; -+} bcm_bit_desc_t; -+ -+ -+typedef struct bcm_tlv { -+ uint8 id; -+ uint8 len; -+ uint8 data[1]; -+} bcm_tlv_t; -+ -+ -+#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len)) -+ -+ -+#define ETHER_ADDR_STR_LEN 18 -+ -+ -+ -+static INLINE void -+xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) -+{ -+ if ( -+#ifdef __i386__ -+ 1 || -+#endif -+ (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { -+ -+ -+ ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; -+ ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; -+ ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; -+ ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; -+ } else { -+ -+ int k; -+ for (k = 0; k < 16; k++) -+ dst[k] = src1[k] ^ src2[k]; -+ } -+} -+ -+ -+ -+extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); -+extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); -+extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); -+ -+ -+#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ -+ defined(WLMSG_ASSOC) -+extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); -+#endif -+ -+#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ -+ defined(WLMSG_ASSOC) || defined(WLMEDIA_PEAKRATE) -+extern int bcm_format_hex(char *str, const void *bytes, int len); -+#endif -+ -+extern const char *bcm_crypto_algo_name(uint algo); -+extern char *bcm_chipname(uint chipid, char *buf, uint len); -+extern char *bcm_brev_str(uint32 brev, char *buf); -+extern void printbig(char *buf); -+extern void prhex(const char *msg, uchar *buf, uint len); -+ -+ -+extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); -+extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); -+extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); -+ -+ -+extern const char *bcmerrorstr(int bcmerror); -+extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); -+ -+ -+typedef uint32 mbool; -+#define mboolset(mb, bit) ((mb) |= (bit)) -+#define mboolclr(mb, bit) ((mb) &= ~(bit)) -+#define mboolisset(mb, bit) (((mb) & (bit)) != 0) -+#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) -+ -+ -+struct fielddesc { -+ const char *nameandfmt; -+ uint32 offset; -+ uint32 len; -+}; -+ -+extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); -+extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); -+ -+extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); -+extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); -+extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); -+ -+typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); -+extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, -+ char *buf, uint32 bufsize); -+extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); -+ -+extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); -+ -+ -+extern uint16 bcm_qdbm_to_mw(uint8 qdbm); -+extern uint8 bcm_mw_to_qdbm(uint16 mw); -+extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); -+ -+unsigned int process_nvram_vars(char *varbuf, unsigned int len); -+ -+#ifdef __cplusplus -+ } -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h -new file mode 100644 -index 00000000..bc57aca2 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmwifi_channels.h -@@ -0,0 +1,490 @@ -+/* -+ * Misc utility routines for WL and Apps -+ * This header file housing the define and function prototype use by -+ * both the wl driver, tools & Apps. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ -+ */ -+ -+#ifndef _bcmwifi_channels_h_ -+#define _bcmwifi_channels_h_ -+ -+ -+/* A chanspec holds the channel number, band, bandwidth and control sideband */ -+typedef uint16 chanspec_t; -+ -+/* channel defines */ -+#define CH_UPPER_SB 0x01 -+#define CH_LOWER_SB 0x02 -+#define CH_EWA_VALID 0x04 -+#define CH_80MHZ_APART 16 -+#define CH_40MHZ_APART 8 -+#define CH_20MHZ_APART 4 -+#define CH_10MHZ_APART 2 -+#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ -+#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ -+#define MAXCHANNEL 224 /* max # supported channels. The max channel no is 216, -+ * this is that + 1 rounded up to a multiple of NBBY (8). -+ * DO NOT MAKE it > 255: channels are uint8's all over -+ */ -+#define CHSPEC_CTLOVLP(sp1, sp2, sep) ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep) -+ -+/* All builds use the new 11ac ratespec/chanspec */ -+#undef D11AC_IOTYPES -+#define D11AC_IOTYPES -+ -+#ifndef D11AC_IOTYPES -+ -+#define WL_CHANSPEC_CHAN_MASK 0x00ff -+#define WL_CHANSPEC_CHAN_SHIFT 0 -+ -+#define WL_CHANSPEC_CTL_SB_MASK 0x0300 -+#define WL_CHANSPEC_CTL_SB_SHIFT 8 -+#define WL_CHANSPEC_CTL_SB_LOWER 0x0100 -+#define WL_CHANSPEC_CTL_SB_UPPER 0x0200 -+#define WL_CHANSPEC_CTL_SB_NONE 0x0300 -+ -+#define WL_CHANSPEC_BW_MASK 0x0C00 -+#define WL_CHANSPEC_BW_SHIFT 10 -+#define WL_CHANSPEC_BW_10 0x0400 -+#define WL_CHANSPEC_BW_20 0x0800 -+#define WL_CHANSPEC_BW_40 0x0C00 -+ -+#define WL_CHANSPEC_BAND_MASK 0xf000 -+#define WL_CHANSPEC_BAND_SHIFT 12 -+#ifdef WL_CHANSPEC_BAND_5G -+#undef WL_CHANSPEC_BAND_5G -+#endif -+#ifdef WL_CHANSPEC_BAND_2G -+#undef WL_CHANSPEC_BAND_2G -+#endif -+#define WL_CHANSPEC_BAND_5G 0x1000 -+#define WL_CHANSPEC_BAND_2G 0x2000 -+#define INVCHANSPEC 255 -+ -+/* channel defines */ -+#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0) -+#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ -+ ((channel) + CH_10MHZ_APART) : 0) -+#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) -+#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ -+ WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ -+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -+#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ -+ ((channel) + CH_20MHZ_APART) : 0) -+#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ -+ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ -+ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ -+ WL_CHANSPEC_BAND_5G)) -+#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) -+#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) -+ -+/* chanspec stores radio channel & flags to indicate control channel location, i.e. upper/lower */ -+#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) -+#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) -+ -+#ifdef WL11N_20MHZONLY -+ -+#define CHSPEC_IS10(chspec) 0 -+#define CHSPEC_IS20(chspec) 1 -+#ifndef CHSPEC_IS40 -+#define CHSPEC_IS40(chspec) 0 -+#endif -+ -+#else /* !WL11N_20MHZONLY */ -+ -+#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) -+#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) -+#ifndef CHSPEC_IS40 -+#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) -+#endif -+ -+#endif /* !WL11N_20MHZONLY */ -+ -+#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) -+#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) -+#define CHSPEC_SB_NONE(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) -+#define CHSPEC_SB_UPPER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) -+#define CHSPEC_SB_LOWER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) -+#define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \ -+ (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \ -+ (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK)))) -+#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) -+ -+#define CHANSPEC_STR_LEN 8 -+ -+#else /* D11AC_IOTYPES */ -+ -+#define WL_CHANSPEC_CHAN_MASK 0x00ff -+#define WL_CHANSPEC_CHAN_SHIFT 0 -+#define WL_CHANSPEC_CHAN1_MASK 0x000f -+#define WL_CHANSPEC_CHAN1_SHIFT 0 -+#define WL_CHANSPEC_CHAN2_MASK 0x00f0 -+#define WL_CHANSPEC_CHAN2_SHIFT 4 -+ -+#define WL_CHANSPEC_CTL_SB_MASK 0x0700 -+#define WL_CHANSPEC_CTL_SB_SHIFT 8 -+#define WL_CHANSPEC_CTL_SB_LLL 0x0000 -+#define WL_CHANSPEC_CTL_SB_LLU 0x0100 -+#define WL_CHANSPEC_CTL_SB_LUL 0x0200 -+#define WL_CHANSPEC_CTL_SB_LUU 0x0300 -+#define WL_CHANSPEC_CTL_SB_ULL 0x0400 -+#define WL_CHANSPEC_CTL_SB_ULU 0x0500 -+#define WL_CHANSPEC_CTL_SB_UUL 0x0600 -+#define WL_CHANSPEC_CTL_SB_UUU 0x0700 -+#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL -+#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU -+#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL -+#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU -+#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL -+#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU -+#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL -+#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU -+ -+#define WL_CHANSPEC_BW_MASK 0x3800 -+#define WL_CHANSPEC_BW_SHIFT 11 -+#define WL_CHANSPEC_BW_5 0x0000 -+#define WL_CHANSPEC_BW_10 0x0800 -+#define WL_CHANSPEC_BW_20 0x1000 -+#define WL_CHANSPEC_BW_40 0x1800 -+#define WL_CHANSPEC_BW_80 0x2000 -+#define WL_CHANSPEC_BW_160 0x2800 -+#define WL_CHANSPEC_BW_8080 0x3000 -+ -+#define WL_CHANSPEC_BAND_MASK 0xc000 -+#define WL_CHANSPEC_BAND_SHIFT 14 -+#define WL_CHANSPEC_BAND_2G 0x0000 -+#define WL_CHANSPEC_BAND_3G 0x4000 -+#define WL_CHANSPEC_BAND_4G 0x8000 -+#define WL_CHANSPEC_BAND_5G 0xc000 -+#define INVCHANSPEC 255 -+ -+/* channel defines */ -+#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ -+ ((channel) - CH_10MHZ_APART) : 0) -+#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ -+ ((channel) + CH_10MHZ_APART) : 0) -+#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) -+#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) -+#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) -+#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ -+ (((channel) <= CH_MAX_2G_CHANNEL) ? \ -+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -+#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ -+ ((channel) + CH_20MHZ_APART) : 0) -+#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ -+ ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ -+ ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ -+ WL_CHANSPEC_BAND_5G)) -+#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ -+ ((channel) | (ctlsb) | \ -+ WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) -+#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ -+ ((channel) | (ctlsb) | \ -+ WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) -+ -+/* simple MACROs to get different fields of chanspec */ -+#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) -+#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) -+#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) -+#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) -+#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) -+#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) -+ -+#ifdef WL11N_20MHZONLY -+ -+#define CHSPEC_IS10(chspec) 0 -+#define CHSPEC_IS20(chspec) 1 -+#ifndef CHSPEC_IS40 -+#define CHSPEC_IS40(chspec) 0 -+#endif -+#ifndef CHSPEC_IS80 -+#define CHSPEC_IS80(chspec) 0 -+#endif -+#ifndef CHSPEC_IS160 -+#define CHSPEC_IS160(chspec) 0 -+#endif -+#ifndef CHSPEC_IS8080 -+#define CHSPEC_IS8080(chspec) 0 -+#endif -+ -+#else /* !WL11N_20MHZONLY */ -+ -+#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) -+#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) -+#ifndef CHSPEC_IS40 -+#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) -+#endif -+#ifndef CHSPEC_IS80 -+#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) -+#endif -+#ifndef CHSPEC_IS160 -+#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) -+#endif -+#ifndef CHSPEC_IS8080 -+#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) -+#endif -+ -+#endif /* !WL11N_20MHZONLY */ -+ -+#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) -+#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) -+#define CHSPEC_SB_UPPER(chspec) \ -+ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ -+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -+#define CHSPEC_SB_LOWER(chspec) \ -+ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ -+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -+#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) -+ -+/** -+ * Number of chars needed for wf_chspec_ntoa() destination character buffer. -+ */ -+#define CHANSPEC_STR_LEN 20 -+ -+ -+/* Legacy Chanspec defines -+ * These are the defines for the previous format of the chanspec_t -+ */ -+#define WL_LCHANSPEC_CHAN_MASK 0x00ff -+#define WL_LCHANSPEC_CHAN_SHIFT 0 -+ -+#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 -+#define WL_LCHANSPEC_CTL_SB_SHIFT 8 -+#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 -+#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 -+#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 -+ -+#define WL_LCHANSPEC_BW_MASK 0x0C00 -+#define WL_LCHANSPEC_BW_SHIFT 10 -+#define WL_LCHANSPEC_BW_10 0x0400 -+#define WL_LCHANSPEC_BW_20 0x0800 -+#define WL_LCHANSPEC_BW_40 0x0C00 -+ -+#define WL_LCHANSPEC_BAND_MASK 0xf000 -+#define WL_LCHANSPEC_BAND_SHIFT 12 -+#define WL_LCHANSPEC_BAND_5G 0x1000 -+#define WL_LCHANSPEC_BAND_2G 0x2000 -+ -+#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) -+#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) -+#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) -+#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) -+#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) -+#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) -+#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) -+#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) -+#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) -+ -+#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) -+ -+#endif /* D11AC_IOTYPES */ -+ -+/* -+ * WF_CHAN_FACTOR_* constants are used to calculate channel frequency -+ * given a channel number. -+ * chan_freq = chan_factor * 500Mhz + chan_number * 5 -+ */ -+ -+/** -+ * Channel Factor for the starting frequence of 2.4 GHz channels. -+ * The value corresponds to 2407 MHz. -+ */ -+#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ -+ -+/** -+ * Channel Factor for the starting frequence of 5 GHz channels. -+ * The value corresponds to 5000 MHz. -+ */ -+#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ -+ -+/** -+ * Channel Factor for the starting frequence of 4.9 GHz channels. -+ * The value corresponds to 4000 MHz. -+ */ -+#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ -+ -+/* defined rate in 500kbps */ -+#define WLC_MAXRATE 108 /* in 500kbps units */ -+#define WLC_RATE_1M 2 /* in 500kbps units */ -+#define WLC_RATE_2M 4 /* in 500kbps units */ -+#define WLC_RATE_5M5 11 /* in 500kbps units */ -+#define WLC_RATE_11M 22 /* in 500kbps units */ -+#define WLC_RATE_6M 12 /* in 500kbps units */ -+#define WLC_RATE_9M 18 /* in 500kbps units */ -+#define WLC_RATE_12M 24 /* in 500kbps units */ -+#define WLC_RATE_18M 36 /* in 500kbps units */ -+#define WLC_RATE_24M 48 /* in 500kbps units */ -+#define WLC_RATE_36M 72 /* in 500kbps units */ -+#define WLC_RATE_48M 96 /* in 500kbps units */ -+#define WLC_RATE_54M 108 /* in 500kbps units */ -+ -+#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ -+ -+/** -+ * Convert chanspec to ascii string -+ * -+ * @param chspec chanspec format -+ * @param buf ascii string of chanspec -+ * -+ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes -+ * -+ * @see CHANSPEC_STR_LEN -+ */ -+extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); -+ -+/** -+ * Convert ascii string to chanspec -+ * -+ * @param a pointer to input string -+ * -+ * @return >= 0 if successful or 0 otherwise -+ */ -+extern chanspec_t wf_chspec_aton(const char *a); -+ -+/** -+ * Verify the chanspec fields are valid. -+ * -+ * Verify the chanspec is using a legal set field values, i.e. that the chanspec -+ * specified a band, bw, ctl_sb and channel and that the combination could be -+ * legal given some set of circumstances. -+ * -+ * @param chanspec input chanspec to verify -+ * -+ * @return TRUE if the chanspec is malformed, FALSE if it looks good. -+ */ -+extern bool wf_chspec_malformed(chanspec_t chanspec); -+ -+/** -+ * Verify the chanspec specifies a valid channel according to 802.11. -+ * -+ * @param chanspec input chanspec to verify -+ * -+ * @return TRUE if the chanspec is a valid 802.11 channel -+ */ -+extern bool wf_chspec_valid(chanspec_t chanspec); -+ -+/** -+ * Return the primary (control) channel. -+ * -+ * This function returns the channel number of the primary 20MHz channel. For -+ * 20MHz channels this is just the channel number. For 40MHz or wider channels -+ * it is the primary 20MHz channel specified by the chanspec. -+ * -+ * @param chspec input chanspec -+ * -+ * @return Returns the channel number of the primary 20MHz channel -+ */ -+extern uint8 wf_chspec_ctlchan(chanspec_t chspec); -+ -+/** -+ * Return the primary (control) chanspec. -+ * -+ * This function returns the chanspec of the primary 20MHz channel. For 20MHz -+ * channels this is just the chanspec. For 40MHz or wider channels it is the -+ * chanspec of the primary 20MHZ channel specified by the chanspec. -+ * -+ * @param chspec input chanspec -+ * -+ * @return Returns the chanspec of the primary 20MHz channel -+ */ -+extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); -+ -+/** -+ * Return a channel number corresponding to a frequency. -+ * -+ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. -+ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using -+ * as the primary 20MHz channel. -+ */ -+extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); -+ -+/* -+ * Return the channel number for a given frequency and base frequency. -+ * The returned channel number is relative to the given base frequency. -+ * If the given base frequency is zero, a base frequency of 5 GHz is assumed for -+ * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. -+ * -+ * Frequency is specified in MHz. -+ * The base frequency is specified as (start_factor * 500 kHz). -+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for -+ * 2.4 GHz and 5 GHz bands. -+ * -+ * The returned channel will be in the range [1, 14] in the 2.4 GHz band -+ * and [0, 200] otherwise. -+ * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the -+ * frequency is not a 2.4 GHz channel, or if the frequency is not and even -+ * multiple of 5 MHz from the base frequency to the base plus 1 GHz. -+ * -+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 -+ * -+ * @param freq frequency in MHz -+ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz -+ * -+ * @return Returns a channel number -+ * -+ * @see WF_CHAN_FACTOR_2_4_G -+ * @see WF_CHAN_FACTOR_5_G -+ */ -+extern int wf_mhz2channel(uint freq, uint start_factor); -+ -+/** -+ * Return the center frequency in MHz of the given channel and base frequency. -+ * -+ * Return the center frequency in MHz of the given channel and base frequency. -+ * The channel number is interpreted relative to the given base frequency. -+ * -+ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. -+ * The base frequency is specified as (start_factor * 500 kHz). -+ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for -+ * 2.4 GHz and 5 GHz bands. -+ * The channel range of [1, 14] is only checked for a start_factor of -+ * WF_CHAN_FACTOR_2_4_G (4814). -+ * Odd start_factors produce channels on .5 MHz boundaries, in which case -+ * the answer is rounded down to an integral MHz. -+ * -1 is returned for an out of range channel. -+ * -+ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 -+ * -+ * @param channel input channel number -+ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz -+ * -+ * @return Returns a frequency in MHz -+ * -+ * @see WF_CHAN_FACTOR_2_4_G -+ * @see WF_CHAN_FACTOR_5_G -+ */ -+extern int wf_channel2mhz(uint channel, uint start_factor); -+ -+/** -+ * Convert ctl chan and bw to chanspec -+ * -+ * @param ctl_ch channel -+ * @param bw bandwidth -+ * -+ * @return > 0 if successful or 0 otherwise -+ * -+ */ -+extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); -+ -+#endif /* _bcmwifi_channels_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd/include/bcmwifi_rates.h -new file mode 100644 -index 00000000..9896b236 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/bcmwifi_rates.h -@@ -0,0 +1,306 @@ -+/* -+ * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmwifi_rates.h 252708 2011-04-12 06:45:56Z $ -+ */ -+ -+#ifndef _bcmwifi_rates_h_ -+#define _bcmwifi_rates_h_ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+#define WL_RATESET_SZ_DSSS 4 -+#define WL_RATESET_SZ_OFDM 8 -+#define WL_RATESET_SZ_HT_MCS 8 -+#define WL_RATESET_SZ_VHT_MCS 10 -+ -+#define WL_TX_CHAINS_MAX 3 -+ -+#define WL_RATE_DISABLED (-128) -+ -+ -+typedef enum wl_tx_bw { -+ WL_TX_BW_20, -+ WL_TX_BW_40, -+ WL_TX_BW_80, -+ WL_TX_BW_20IN40, -+ WL_TX_BW_20IN80, -+ WL_TX_BW_40IN80, -+ WL_TX_BW_ALL -+} wl_tx_bw_t; -+ -+ -+ -+typedef enum wl_tx_mode { -+ WL_TX_MODE_NONE, -+ WL_TX_MODE_STBC, -+ WL_TX_MODE_CDD, -+ WL_TX_MODE_SDM -+} wl_tx_mode_t; -+ -+ -+ -+typedef enum wl_tx_chains { -+ WL_TX_CHAINS_1 = 1, -+ WL_TX_CHAINS_2, -+ WL_TX_CHAINS_3 -+} wl_tx_chains_t; -+ -+ -+ -+typedef enum wl_tx_nss { -+ WL_TX_NSS_1 = 1, -+ WL_TX_NSS_2, -+ WL_TX_NSS_3 -+} wl_tx_nss_t; -+ -+ -+typedef enum clm_rates { -+ -+ -+ -+ WL_RATE_1X1_DSSS_1 = 0, -+ WL_RATE_1X1_DSSS_2 = 1, -+ WL_RATE_1X1_DSSS_5_5 = 2, -+ WL_RATE_1X1_DSSS_11 = 3, -+ -+ WL_RATE_1X1_OFDM_6 = 4, -+ WL_RATE_1X1_OFDM_9 = 5, -+ WL_RATE_1X1_OFDM_12 = 6, -+ WL_RATE_1X1_OFDM_18 = 7, -+ WL_RATE_1X1_OFDM_24 = 8, -+ WL_RATE_1X1_OFDM_36 = 9, -+ WL_RATE_1X1_OFDM_48 = 10, -+ WL_RATE_1X1_OFDM_54 = 11, -+ -+ WL_RATE_1X1_MCS0 = 12, -+ WL_RATE_1X1_MCS1 = 13, -+ WL_RATE_1X1_MCS2 = 14, -+ WL_RATE_1X1_MCS3 = 15, -+ WL_RATE_1X1_MCS4 = 16, -+ WL_RATE_1X1_MCS5 = 17, -+ WL_RATE_1X1_MCS6 = 18, -+ WL_RATE_1X1_MCS7 = 19, -+ -+ WL_RATE_1X1_VHT0SS1 = 12, -+ WL_RATE_1X1_VHT1SS1 = 13, -+ WL_RATE_1X1_VHT2SS1 = 14, -+ WL_RATE_1X1_VHT3SS1 = 15, -+ WL_RATE_1X1_VHT4SS1 = 16, -+ WL_RATE_1X1_VHT5SS1 = 17, -+ WL_RATE_1X1_VHT6SS1 = 18, -+ WL_RATE_1X1_VHT7SS1 = 19, -+ WL_RATE_1X1_VHT8SS1 = 20, -+ WL_RATE_1X1_VHT9SS1 = 21, -+ -+ -+ -+ -+ -+ WL_RATE_1X2_DSSS_1 = 22, -+ WL_RATE_1X2_DSSS_2 = 23, -+ WL_RATE_1X2_DSSS_5_5 = 24, -+ WL_RATE_1X2_DSSS_11 = 25, -+ -+ WL_RATE_1X2_CDD_OFDM_6 = 26, -+ WL_RATE_1X2_CDD_OFDM_9 = 27, -+ WL_RATE_1X2_CDD_OFDM_12 = 28, -+ WL_RATE_1X2_CDD_OFDM_18 = 29, -+ WL_RATE_1X2_CDD_OFDM_24 = 30, -+ WL_RATE_1X2_CDD_OFDM_36 = 31, -+ WL_RATE_1X2_CDD_OFDM_48 = 32, -+ WL_RATE_1X2_CDD_OFDM_54 = 33, -+ -+ WL_RATE_1X2_CDD_MCS0 = 34, -+ WL_RATE_1X2_CDD_MCS1 = 35, -+ WL_RATE_1X2_CDD_MCS2 = 36, -+ WL_RATE_1X2_CDD_MCS3 = 37, -+ WL_RATE_1X2_CDD_MCS4 = 38, -+ WL_RATE_1X2_CDD_MCS5 = 39, -+ WL_RATE_1X2_CDD_MCS6 = 40, -+ WL_RATE_1X2_CDD_MCS7 = 41, -+ -+ WL_RATE_1X2_VHT0SS1 = 34, -+ WL_RATE_1X2_VHT1SS1 = 35, -+ WL_RATE_1X2_VHT2SS1 = 36, -+ WL_RATE_1X2_VHT3SS1 = 37, -+ WL_RATE_1X2_VHT4SS1 = 38, -+ WL_RATE_1X2_VHT5SS1 = 39, -+ WL_RATE_1X2_VHT6SS1 = 40, -+ WL_RATE_1X2_VHT7SS1 = 41, -+ WL_RATE_1X2_VHT8SS1 = 42, -+ WL_RATE_1X2_VHT9SS1 = 43, -+ -+ -+ WL_RATE_2X2_STBC_MCS0 = 44, -+ WL_RATE_2X2_STBC_MCS1 = 45, -+ WL_RATE_2X2_STBC_MCS2 = 46, -+ WL_RATE_2X2_STBC_MCS3 = 47, -+ WL_RATE_2X2_STBC_MCS4 = 48, -+ WL_RATE_2X2_STBC_MCS5 = 49, -+ WL_RATE_2X2_STBC_MCS6 = 50, -+ WL_RATE_2X2_STBC_MCS7 = 51, -+ -+ WL_RATE_2X2_STBC_VHT0SS1 = 44, -+ WL_RATE_2X2_STBC_VHT1SS1 = 45, -+ WL_RATE_2X2_STBC_VHT2SS1 = 46, -+ WL_RATE_2X2_STBC_VHT3SS1 = 47, -+ WL_RATE_2X2_STBC_VHT4SS1 = 48, -+ WL_RATE_2X2_STBC_VHT5SS1 = 49, -+ WL_RATE_2X2_STBC_VHT6SS1 = 50, -+ WL_RATE_2X2_STBC_VHT7SS1 = 51, -+ WL_RATE_2X2_STBC_VHT8SS1 = 52, -+ WL_RATE_2X2_STBC_VHT9SS1 = 53, -+ -+ WL_RATE_2X2_SDM_MCS8 = 54, -+ WL_RATE_2X2_SDM_MCS9 = 55, -+ WL_RATE_2X2_SDM_MCS10 = 56, -+ WL_RATE_2X2_SDM_MCS11 = 57, -+ WL_RATE_2X2_SDM_MCS12 = 58, -+ WL_RATE_2X2_SDM_MCS13 = 59, -+ WL_RATE_2X2_SDM_MCS14 = 60, -+ WL_RATE_2X2_SDM_MCS15 = 61, -+ -+ WL_RATE_2X2_VHT0SS2 = 54, -+ WL_RATE_2X2_VHT1SS2 = 55, -+ WL_RATE_2X2_VHT2SS2 = 56, -+ WL_RATE_2X2_VHT3SS2 = 57, -+ WL_RATE_2X2_VHT4SS2 = 58, -+ WL_RATE_2X2_VHT5SS2 = 59, -+ WL_RATE_2X2_VHT6SS2 = 60, -+ WL_RATE_2X2_VHT7SS2 = 61, -+ WL_RATE_2X2_VHT8SS2 = 62, -+ WL_RATE_2X2_VHT9SS2 = 63, -+ -+ -+ -+ -+ -+ WL_RATE_1X3_DSSS_1 = 64, -+ WL_RATE_1X3_DSSS_2 = 65, -+ WL_RATE_1X3_DSSS_5_5 = 66, -+ WL_RATE_1X3_DSSS_11 = 67, -+ -+ WL_RATE_1X3_CDD_OFDM_6 = 68, -+ WL_RATE_1X3_CDD_OFDM_9 = 69, -+ WL_RATE_1X3_CDD_OFDM_12 = 70, -+ WL_RATE_1X3_CDD_OFDM_18 = 71, -+ WL_RATE_1X3_CDD_OFDM_24 = 72, -+ WL_RATE_1X3_CDD_OFDM_36 = 73, -+ WL_RATE_1X3_CDD_OFDM_48 = 74, -+ WL_RATE_1X3_CDD_OFDM_54 = 75, -+ -+ WL_RATE_1X3_CDD_MCS0 = 76, -+ WL_RATE_1X3_CDD_MCS1 = 77, -+ WL_RATE_1X3_CDD_MCS2 = 78, -+ WL_RATE_1X3_CDD_MCS3 = 79, -+ WL_RATE_1X3_CDD_MCS4 = 80, -+ WL_RATE_1X3_CDD_MCS5 = 81, -+ WL_RATE_1X3_CDD_MCS6 = 82, -+ WL_RATE_1X3_CDD_MCS7 = 83, -+ -+ WL_RATE_1X3_VHT0SS1 = 76, -+ WL_RATE_1X3_VHT1SS1 = 77, -+ WL_RATE_1X3_VHT2SS1 = 78, -+ WL_RATE_1X3_VHT3SS1 = 79, -+ WL_RATE_1X3_VHT4SS1 = 80, -+ WL_RATE_1X3_VHT5SS1 = 81, -+ WL_RATE_1X3_VHT6SS1 = 82, -+ WL_RATE_1X3_VHT7SS1 = 83, -+ WL_RATE_1X3_VHT8SS1 = 84, -+ WL_RATE_1X3_VHT9SS1 = 85, -+ -+ -+ WL_RATE_2X3_STBC_MCS0 = 86, -+ WL_RATE_2X3_STBC_MCS1 = 87, -+ WL_RATE_2X3_STBC_MCS2 = 88, -+ WL_RATE_2X3_STBC_MCS3 = 89, -+ WL_RATE_2X3_STBC_MCS4 = 90, -+ WL_RATE_2X3_STBC_MCS5 = 91, -+ WL_RATE_2X3_STBC_MCS6 = 92, -+ WL_RATE_2X3_STBC_MCS7 = 93, -+ -+ WL_RATE_2X3_STBC_VHT0SS1 = 86, -+ WL_RATE_2X3_STBC_VHT1SS1 = 87, -+ WL_RATE_2X3_STBC_VHT2SS1 = 88, -+ WL_RATE_2X3_STBC_VHT3SS1 = 89, -+ WL_RATE_2X3_STBC_VHT4SS1 = 90, -+ WL_RATE_2X3_STBC_VHT5SS1 = 91, -+ WL_RATE_2X3_STBC_VHT6SS1 = 92, -+ WL_RATE_2X3_STBC_VHT7SS1 = 93, -+ WL_RATE_2X3_STBC_VHT8SS1 = 94, -+ WL_RATE_2X3_STBC_VHT9SS1 = 95, -+ -+ WL_RATE_2X3_SDM_MCS8 = 96, -+ WL_RATE_2X3_SDM_MCS9 = 97, -+ WL_RATE_2X3_SDM_MCS10 = 98, -+ WL_RATE_2X3_SDM_MCS11 = 99, -+ WL_RATE_2X3_SDM_MCS12 = 100, -+ WL_RATE_2X3_SDM_MCS13 = 101, -+ WL_RATE_2X3_SDM_MCS14 = 102, -+ WL_RATE_2X3_SDM_MCS15 = 103, -+ -+ WL_RATE_2X3_VHT0SS2 = 96, -+ WL_RATE_2X3_VHT1SS2 = 97, -+ WL_RATE_2X3_VHT2SS2 = 98, -+ WL_RATE_2X3_VHT3SS2 = 99, -+ WL_RATE_2X3_VHT4SS2 = 100, -+ WL_RATE_2X3_VHT5SS2 = 101, -+ WL_RATE_2X3_VHT6SS2 = 102, -+ WL_RATE_2X3_VHT7SS2 = 103, -+ WL_RATE_2X3_VHT8SS2 = 104, -+ WL_RATE_2X3_VHT9SS2 = 105, -+ -+ -+ WL_RATE_3X3_SDM_MCS16 = 106, -+ WL_RATE_3X3_SDM_MCS17 = 107, -+ WL_RATE_3X3_SDM_MCS18 = 108, -+ WL_RATE_3X3_SDM_MCS19 = 109, -+ WL_RATE_3X3_SDM_MCS20 = 110, -+ WL_RATE_3X3_SDM_MCS21 = 111, -+ WL_RATE_3X3_SDM_MCS22 = 112, -+ WL_RATE_3X3_SDM_MCS23 = 113, -+ -+ WL_RATE_3X3_VHT0SS3 = 106, -+ WL_RATE_3X3_VHT1SS3 = 107, -+ WL_RATE_3X3_VHT2SS3 = 108, -+ WL_RATE_3X3_VHT3SS3 = 109, -+ WL_RATE_3X3_VHT4SS3 = 110, -+ WL_RATE_3X3_VHT5SS3 = 111, -+ WL_RATE_3X3_VHT6SS3 = 112, -+ WL_RATE_3X3_VHT7SS3 = 113, -+ WL_RATE_3X3_VHT8SS3 = 114, -+ WL_RATE_3X3_VHT9SS3 = 115, -+ -+ -+ WL_NUMRATES = 116 -+} clm_rates_t; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h -new file mode 100644 -index 00000000..11fff555 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h -@@ -0,0 +1,136 @@ -+/* -+ * Definitions for ioctls to access DHD iovars. -+ * Based on wlioctl.h (for Broadcom 802.11abg driver). -+ * (Moves towards generic ioctls for BCM drivers/iovars.) -+ * -+ * Definitions subject to change without notice. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhdioctl.h 354894 2012-09-04 12:34:07Z $ -+ */ -+ -+#ifndef _dhdioctl_h_ -+#define _dhdioctl_h_ -+ -+#include <typedefs.h> -+ -+ -+/* require default structure packing */ -+#define BWL_DEFAULT_PACKING -+#include <packed_section_start.h> -+ -+ -+/* Linux network driver ioctl encoding */ -+typedef struct dhd_ioctl { -+ uint cmd; /* common ioctl definition */ -+ void *buf; /* pointer to user buffer */ -+ uint len; /* length of user buffer */ -+ bool set; /* get or set request (optional) */ -+ uint used; /* bytes read or written (optional) */ -+ uint needed; /* bytes needed (optional) */ -+ uint driver; /* to identify target driver */ -+} dhd_ioctl_t; -+ -+/* Underlying BUS definition */ -+enum { -+ BUS_TYPE_USB = 0, /* for USB dongles */ -+ BUS_TYPE_SDIO /* for SDIO dongles */ -+}; -+ -+/* per-driver magic numbers */ -+#define DHD_IOCTL_MAGIC 0x00444944 -+ -+/* bump this number if you change the ioctl interface */ -+#define DHD_IOCTL_VERSION 1 -+ -+#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ -+#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ -+ -+/* common ioctl definitions */ -+#define DHD_GET_MAGIC 0 -+#define DHD_GET_VERSION 1 -+#define DHD_GET_VAR 2 -+#define DHD_SET_VAR 3 -+ -+/* message levels */ -+#define DHD_ERROR_VAL 0x0001 -+#define DHD_TRACE_VAL 0x0002 -+#define DHD_INFO_VAL 0x0004 -+#define DHD_DATA_VAL 0x0008 -+#define DHD_CTL_VAL 0x0010 -+#define DHD_TIMER_VAL 0x0020 -+#define DHD_HDRS_VAL 0x0040 -+#define DHD_BYTES_VAL 0x0080 -+#define DHD_INTR_VAL 0x0100 -+#define DHD_LOG_VAL 0x0200 -+#define DHD_GLOM_VAL 0x0400 -+#define DHD_EVENT_VAL 0x0800 -+#define DHD_BTA_VAL 0x1000 -+#if 0 && (NDISVER >= 0x0630) && 1 -+#define DHD_SCAN_VAL 0x2000 -+#else -+#define DHD_ISCAN_VAL 0x2000 -+#endif -+#define DHD_ARPOE_VAL 0x4000 -+#define DHD_REORDER_VAL 0x8000 -+#define DHD_WL_VAL 0x10000 -+#define DHD_WL_VAL2 0x20000 -+ -+#ifdef SDTEST -+/* For pktgen iovar */ -+typedef struct dhd_pktgen { -+ uint version; /* To allow structure change tracking */ -+ uint freq; /* Max ticks between tx/rx attempts */ -+ uint count; /* Test packets to send/rcv each attempt */ -+ uint print; /* Print counts every <print> attempts */ -+ uint total; /* Total packets (or bursts) */ -+ uint minlen; /* Minimum length of packets to send */ -+ uint maxlen; /* Maximum length of packets to send */ -+ uint numsent; /* Count of test packets sent */ -+ uint numrcvd; /* Count of test packets received */ -+ uint numfail; /* Count of test send failures */ -+ uint mode; /* Test mode (type of test packets) */ -+ uint stop; /* Stop after this many tx failures */ -+} dhd_pktgen_t; -+ -+/* Version in case structure changes */ -+#define DHD_PKTGEN_VERSION 2 -+ -+/* Type of test packets to use */ -+#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ -+#define DHD_PKTGEN_SEND 2 /* Send discard packets */ -+#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ -+#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ -+#endif /* SDTEST */ -+ -+/* Enter idle immediately (no timeout) */ -+#define DHD_IDLE_IMMEDIATE (-1) -+ -+/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ -+#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ -+#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ -+ -+ -+/* require default structure packing */ -+#include <packed_section_end.h> -+ -+#endif /* _dhdioctl_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h -new file mode 100644 -index 00000000..7f5a9710 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/epivers.h -@@ -0,0 +1,56 @@ -+/* -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $ -+ * -+*/ -+ -+#ifndef _epivers_h_ -+#define _epivers_h_ -+ -+#define EPI_MAJOR_VERSION 1 -+ -+#define EPI_MINOR_VERSION 28 -+ -+#define EPI_RC_NUMBER 27 -+ -+#define EPI_INCREMENTAL_NUMBER 1 -+ -+#define EPI_BUILD_NUMBER 0 -+ -+#define EPI_VERSION 1, 28, 27, 1 -+ -+#define EPI_VERSION_NUM 0x011c1b01 -+ -+#define EPI_VERSION_DEV 1.28.27 -+ -+/* Driver Version String, ASCII, 32 chars max */ -+#ifdef BCMINTERNAL -+#define EPI_VERSION_STR "1.28.27.1 (r BCMINT)" -+#else -+#ifdef WLTEST -+#define EPI_VERSION_STR "1.28.27.1 (r WLTEST)" -+#else -+#define EPI_VERSION_STR "1.28.27.1 (r)" -+#endif -+#endif /* BCMINTERNAL */ -+ -+#endif /* _epivers_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h -new file mode 100644 -index 00000000..c41def6c ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/hndpmu.h -@@ -0,0 +1,36 @@ -+/* -+ * HND SiliconBackplane PMU support. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: hndpmu.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _hndpmu_h_ -+#define _hndpmu_h_ -+ -+ -+extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on); -+extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); -+ -+extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); -+ -+#endif /* _hndpmu_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h -new file mode 100644 -index 00000000..90d97992 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h -@@ -0,0 +1,88 @@ -+/* -+ * HNDRTE arm trap handling. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $ -+ */ -+ -+#ifndef _hndrte_armtrap_h -+#define _hndrte_armtrap_h -+ -+ -+/* ARM trap handling */ -+ -+/* Trap types defined by ARM (see arminc.h) */ -+ -+/* Trap locations in lo memory */ -+#define TRAP_STRIDE 4 -+#define FIRST_TRAP TR_RST -+#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) -+ -+#if defined(__ARM_ARCH_4T__) -+#define MAX_TRAP_TYPE (TR_FIQ + 1) -+#elif defined(__ARM_ARCH_7M__) -+#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS) -+#endif /* __ARM_ARCH_7M__ */ -+ -+/* The trap structure is defined here as offsets for assembly */ -+#define TR_TYPE 0x00 -+#define TR_EPC 0x04 -+#define TR_CPSR 0x08 -+#define TR_SPSR 0x0c -+#define TR_REGS 0x10 -+#define TR_REG(n) (TR_REGS + (n) * 4) -+#define TR_SP TR_REG(13) -+#define TR_LR TR_REG(14) -+#define TR_PC TR_REG(15) -+ -+#define TRAP_T_SIZE 80 -+ -+#ifndef _LANGUAGE_ASSEMBLY -+ -+#include <typedefs.h> -+ -+typedef struct _trap_struct { -+ uint32 type; -+ uint32 epc; -+ uint32 cpsr; -+ uint32 spsr; -+ uint32 r0; /* a1 */ -+ uint32 r1; /* a2 */ -+ uint32 r2; /* a3 */ -+ uint32 r3; /* a4 */ -+ uint32 r4; /* v1 */ -+ uint32 r5; /* v2 */ -+ uint32 r6; /* v3 */ -+ uint32 r7; /* v4 */ -+ uint32 r8; /* v5 */ -+ uint32 r9; /* sb/v6 */ -+ uint32 r10; /* sl/v7 */ -+ uint32 r11; /* fp/v8 */ -+ uint32 r12; /* ip */ -+ uint32 r13; /* sp */ -+ uint32 r14; /* lr */ -+ uint32 pc; /* r15 */ -+} trap_t; -+ -+#endif /* !_LANGUAGE_ASSEMBLY */ -+ -+#endif /* _hndrte_armtrap_h */ -diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h -new file mode 100644 -index 00000000..57abbbd5 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h -@@ -0,0 +1,67 @@ -+/* -+ * Console support for hndrte. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: hndrte_cons.h 300516 2011-12-04 17:39:44Z $ -+ */ -+#ifndef _HNDRTE_CONS_H -+#define _HNDRTE_CONS_H -+ -+#include <typedefs.h> -+ -+#define CBUF_LEN (128) -+ -+#define LOG_BUF_LEN 1024 -+ -+typedef struct { -+ uint32 buf; /* Can't be pointer on (64-bit) hosts */ -+ uint buf_size; -+ uint idx; -+ char *_buf_compat; /* redundant pointer for backward compat. */ -+} hndrte_log_t; -+ -+typedef struct { -+ /* Virtual UART -+ * When there is no UART (e.g. Quickturn), the host should write a complete -+ * input line directly into cbuf and then write the length into vcons_in. -+ * This may also be used when there is a real UART (at risk of conflicting with -+ * the real UART). vcons_out is currently unused. -+ */ -+ volatile uint vcons_in; -+ volatile uint vcons_out; -+ -+ /* Output (logging) buffer -+ * Console output is written to a ring buffer log_buf at index log_idx. -+ * The host may read the output when it sees log_idx advance. -+ * Output will be lost if the output wraps around faster than the host polls. -+ */ -+ hndrte_log_t log; -+ -+ /* Console input line buffer -+ * Characters are read one at a time into cbuf until <CR> is received, then -+ * the buffer is processed as a command line. Also used for virtual UART. -+ */ -+ uint cbuf_idx; -+ char cbuf[CBUF_LEN]; -+} hndrte_cons_t; -+ -+#endif /* _HNDRTE_CONS_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h -new file mode 100644 -index 00000000..66640c3b ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/hndsoc.h -@@ -0,0 +1,235 @@ -+/* -+ * Broadcom HND chip & on-chip-interconnect-related definitions. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: hndsoc.h 309193 2012-01-19 00:03:57Z $ -+ */ -+ -+#ifndef _HNDSOC_H -+#define _HNDSOC_H -+ -+/* Include the soci specific files */ -+#include <sbconfig.h> -+#include <aidmp.h> -+ -+/* -+ * SOC Interconnect Address Map. -+ * All regions may not exist on all chips. -+ */ -+#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ -+#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ -+#define SI_PCI_MEM_SZ (64 * 1024 * 1024) -+#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ -+#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ -+#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ -+ -+#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ -+ -+#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ -+#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ -+#define SI_MAXCORES 16 /* Max cores (this is arbitrary, for software -+ * convenience and could be changed if we -+ * make any larger chips -+ */ -+ -+#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ -+#define SI_FASTRAM_SWAPPED 0x19800000 -+ -+#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ -+#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ -+#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ -+#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ -+#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ -+#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ -+#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ -+#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ -+#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ -+#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ -+#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ -+ -+#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ -+#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ -+#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ -+#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 -+ * (2 ZettaBytes), low 32 bits -+ */ -+#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 -+ * (2 ZettaBytes), high 32 bits -+ */ -+ -+/* core codes */ -+#define NODEV_CORE_ID 0x700 /* Invalid coreid */ -+#define CC_CORE_ID 0x800 /* chipcommon core */ -+#define ILINE20_CORE_ID 0x801 /* iline20 core */ -+#define SRAM_CORE_ID 0x802 /* sram core */ -+#define SDRAM_CORE_ID 0x803 /* sdram core */ -+#define PCI_CORE_ID 0x804 /* pci core */ -+#define MIPS_CORE_ID 0x805 /* mips core */ -+#define ENET_CORE_ID 0x806 /* enet mac core */ -+#define CODEC_CORE_ID 0x807 /* v90 codec core */ -+#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ -+#define ADSL_CORE_ID 0x809 /* ADSL core */ -+#define ILINE100_CORE_ID 0x80a /* iline100 core */ -+#define IPSEC_CORE_ID 0x80b /* ipsec core */ -+#define UTOPIA_CORE_ID 0x80c /* utopia core */ -+#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ -+#define SOCRAM_CORE_ID 0x80e /* internal memory core */ -+#define MEMC_CORE_ID 0x80f /* memc sdram core */ -+#define OFDM_CORE_ID 0x810 /* OFDM phy core */ -+#define EXTIF_CORE_ID 0x811 /* external interface core */ -+#define D11_CORE_ID 0x812 /* 802.11 MAC core */ -+#define APHY_CORE_ID 0x813 /* 802.11a phy core */ -+#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ -+#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ -+#define MIPS33_CORE_ID 0x816 /* mips3302 core */ -+#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ -+#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ -+#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ -+#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ -+#define SDIOH_CORE_ID 0x81b /* sdio host core */ -+#define ROBO_CORE_ID 0x81c /* roboswitch core */ -+#define ATA100_CORE_ID 0x81d /* parallel ATA core */ -+#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ -+#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ -+#define PCIE_CORE_ID 0x820 /* pci express core */ -+#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ -+#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ -+#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ -+#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ -+#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ -+#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ -+#define PMU_CORE_ID 0x827 /* PMU core */ -+#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ -+#define SDIOD_CORE_ID 0x829 /* SDIO device core */ -+#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ -+#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ -+#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ -+#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ -+#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ -+#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ -+#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ -+#define SC_CORE_ID 0x831 /* shared common core */ -+#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ -+#define SPIH_CORE_ID 0x833 /* SPI host core */ -+#define I2S_CORE_ID 0x834 /* I2S core */ -+#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ -+#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ -+ -+#define ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ -+#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ -+#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ -+#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ -+#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ -+#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ -+#define EROM_CORE_ID 0x366 /* EROM core ID */ -+#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ -+#define DEF_AI_COMP 0xfff /* Default component, in ai chips it maps all -+ * unused address ranges -+ */ -+ -+#define CC_4706_CORE_ID 0x500 /* chipcommon core */ -+#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ -+#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ -+#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ -+#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ -+#define ALTA_CORE_ID 0x534 /* I2S core */ -+#define DDR23_PHY_CORE_ID 0x5dd -+ -+#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ -+#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ -+#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 -+ * (2 ZettaBytes), high 32 bits -+ */ -+#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ -+#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ -+#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ -+ -+/* There are TWO constants on all HND chips: SI_ENUM_BASE above, -+ * and chipcommon being the first core: -+ */ -+#define SI_CC_IDX 0 -+ -+/* SOC Interconnect types (aka chip types) */ -+#define SOCI_SB 0 -+#define SOCI_AI 1 -+#define SOCI_UBUS 2 -+ -+/* Common core control flags */ -+#define SICF_BIST_EN 0x8000 -+#define SICF_PME_EN 0x4000 -+#define SICF_CORE_BITS 0x3ffc -+#define SICF_FGC 0x0002 -+#define SICF_CLOCK_EN 0x0001 -+ -+/* Common core status flags */ -+#define SISF_BIST_DONE 0x8000 -+#define SISF_BIST_ERROR 0x4000 -+#define SISF_GATED_CLK 0x2000 -+#define SISF_DMA64 0x1000 -+#define SISF_CORE_BITS 0x0fff -+ -+/* A register that is common to all cores to -+ * communicate w/PMU regarding clock control. -+ */ -+#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */ -+ -+/* clk_ctl_st register */ -+#define CCS_FORCEALP 0x00000001 /* force ALP request */ -+#define CCS_FORCEHT 0x00000002 /* force HT request */ -+#define CCS_FORCEILP 0x00000004 /* force ILP request */ -+#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */ -+#define CCS_HTAREQ 0x00000010 /* HT Avail Request */ -+#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */ -+#define CCS_HQCLKREQ 0x00000040 /* HQ Clock Required */ -+#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ -+#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */ -+#define CCS_ERSRC_REQ_SHIFT 8 -+#define CCS_ALPAVAIL 0x00010000 /* ALP is available */ -+#define CCS_HTAVAIL 0x00020000 /* HT is available */ -+#define CCS_BP_ON_APL 0x00040000 /* RO: Backplane is running on ALP clock */ -+#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ -+#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ -+#define CCS_ERSRC_STS_SHIFT 24 -+ -+#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ -+#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ -+ -+/* Not really related to SOC Interconnect, but a couple of software -+ * conventions for the use the flash space: -+ */ -+ -+/* Minumum amount of flash we support */ -+#define FLASH_MIN 0x00020000 /* Minimum flash size */ -+ -+/* A boot/binary may have an embedded block that describes its size */ -+#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */ -+#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */ -+#define BISZ_MAGIC_IDX 0 /* Word 0: magic */ -+#define BISZ_TXTST_IDX 1 /* 1: text start */ -+#define BISZ_TXTEND_IDX 2 /* 2: text end */ -+#define BISZ_DATAST_IDX 3 /* 3: data start */ -+#define BISZ_DATAEND_IDX 4 /* 4: data end */ -+#define BISZ_BSSST_IDX 5 /* 5: bss start */ -+#define BISZ_BSSEND_IDX 6 /* 6: bss end */ -+#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */ -+ -+#endif /* _HNDSOC_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h -new file mode 100644 -index 00000000..d2f3a987 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h -@@ -0,0 +1,425 @@ -+/* -+ * Linux OS Independent Layer -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: linux_osl.h 354452 2012-08-31 04:59:17Z $ -+ */ -+ -+#ifndef _linux_osl_h_ -+#define _linux_osl_h_ -+ -+#include <typedefs.h> -+ -+ -+extern void * osl_os_open_image(char * filename); -+extern int osl_os_get_image_block(char * buf, int len, void * image); -+extern void osl_os_close_image(void * image); -+extern int osl_os_image_size(void *image); -+ -+ -+#ifdef BCMDRIVER -+ -+ -+extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); -+extern void osl_detach(osl_t *osh); -+ -+ -+extern uint32 g_assert_type; -+ -+ -+#if defined(BCMASSERT_LOG) -+ #define ASSERT(exp) \ -+ do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) -+extern void osl_assert(const char *exp, const char *file, int line); -+#else -+ #ifdef __GNUC__ -+ #define GCC_VERSION \ -+ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -+ #if GCC_VERSION > 30100 -+ #define ASSERT(exp) do {} while (0) -+ #else -+ -+ #define ASSERT(exp) -+ #endif -+ #endif -+#endif -+ -+ -+#define OSL_DELAY(usec) osl_delay(usec) -+extern void osl_delay(uint usec); -+ -+#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ -+ osl_pcmcia_read_attr((osh), (offset), (buf), (size)) -+#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ -+ osl_pcmcia_write_attr((osh), (offset), (buf), (size)) -+extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); -+extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); -+ -+ -+#define OSL_PCI_READ_CONFIG(osh, offset, size) \ -+ osl_pci_read_config((osh), (offset), (size)) -+#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ -+ osl_pci_write_config((osh), (offset), (size), (val)) -+extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); -+extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); -+ -+ -+#define OSL_PCI_BUS(osh) osl_pci_bus(osh) -+#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) -+extern uint osl_pci_bus(osl_t *osh); -+extern uint osl_pci_slot(osl_t *osh); -+extern struct pci_dev *osl_pci_device(osl_t *osh); -+ -+ -+typedef struct { -+ bool pkttag; -+ uint pktalloced; -+ bool mmbus; -+ pktfree_cb_fn_t tx_fn; -+ void *tx_ctx; -+ void *unused[3]; -+} osl_pubinfo_t; -+ -+#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ -+ do { \ -+ ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ -+ ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ -+ } while (0) -+ -+ -+ -+#define BUS_SWAP32(v) (v) -+ -+ #define MALLOC(osh, size) osl_malloc((osh), (size)) -+ #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) -+ #define MALLOCED(osh) osl_malloced((osh)) -+ extern void *osl_malloc(osl_t *osh, uint size); -+ extern void osl_mfree(osl_t *osh, void *addr, uint size); -+ extern uint osl_malloced(osl_t *osh); -+ -+#define NATIVE_MALLOC(osh, size) kmalloc(size, GFP_ATOMIC) -+#define NATIVE_MFREE(osh, addr, size) kfree(addr) -+ -+#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) -+extern uint osl_malloc_failed(osl_t *osh); -+ -+ -+#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() -+#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ -+ osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) -+#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ -+ osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) -+extern uint osl_dma_consistent_align(void); -+extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, ulong *pap); -+extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa); -+ -+ -+#define DMA_TX 1 -+#define DMA_RX 2 -+ -+ -+#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ -+ osl_dma_unmap((osh), (pa), (size), (direction)) -+extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction); -+extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction); -+ -+ -+#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0) -+ -+ -+ #include <bcmsdh.h> -+ #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (uintptr)(r), sizeof(*(r)), (v))) -+ #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (uintptr)(r), sizeof(*(r)))) -+ -+ #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ -+ mmap_op else bus_op -+ #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ -+ mmap_op : bus_op -+ -+#define OSL_ERROR(bcmerror) osl_error(bcmerror) -+extern int osl_error(int bcmerror); -+ -+ -+#define PKTBUFSZ 2048 -+ -+ -+#include <linuxver.h> -+#include <linux/kernel.h> -+#include <linux/string.h> -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) -+#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) -+#else -+#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ -+#define printf(fmt, args...) printk(fmt , ## args) -+#include <linux/kernel.h> -+#include <linux/string.h> -+ -+#define bcopy(src, dst, len) memcpy((dst), (src), (len)) -+#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -+#define bzero(b, len) memset((b), '\0', (len)) -+ -+ -+ -+#define R_REG(osh, r) (\ -+ SELECT_BUS_READ(osh, \ -+ ({ \ -+ __typeof(*(r)) __osl_v; \ -+ BCM_REFERENCE(osh); \ -+ switch (sizeof(*(r))) { \ -+ case sizeof(uint8): __osl_v = \ -+ readb((volatile uint8*)(r)); break; \ -+ case sizeof(uint16): __osl_v = \ -+ readw((volatile uint16*)(r)); break; \ -+ case sizeof(uint32): __osl_v = \ -+ readl((volatile uint32*)(r)); break; \ -+ } \ -+ __osl_v; \ -+ }), \ -+ OSL_READ_REG(osh, r)) \ -+) -+ -+#define W_REG(osh, r, v) do { \ -+ BCM_REFERENCE(osh); \ -+ SELECT_BUS_WRITE(osh, \ -+ switch (sizeof(*(r))) { \ -+ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ -+ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ -+ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ -+ }, \ -+ (OSL_WRITE_REG(osh, r, v))); \ -+ } while (0) -+ -+#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -+#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) -+ -+ -+#define bcopy(src, dst, len) memcpy((dst), (src), (len)) -+#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) -+#define bzero(b, len) memset((b), '\0', (len)) -+ -+ -+#define OSL_UNCACHED(va) ((void *)va) -+#define OSL_CACHED(va) ((void *)va) -+ -+#define OSL_PREF_RANGE_LD(va, sz) -+#define OSL_PREF_RANGE_ST(va, sz) -+ -+ -+#if defined(__i386__) -+#define OSL_GETCYCLES(x) rdtscl((x)) -+#else -+#define OSL_GETCYCLES(x) ((x) = 0) -+#endif -+ -+ -+#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) -+ -+ -+#if !defined(CONFIG_MMC_MSM7X00A) -+#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size)) -+#else -+#define REG_MAP(pa, size) (void *)(0) -+#endif -+#define REG_UNMAP(va) iounmap((va)) -+ -+ -+#define R_SM(r) *(r) -+#define W_SM(r, v) (*(r) = (v)) -+#define BZERO_SM(r, len) memset((r), '\0', (len)) -+ -+ -+#include <linuxver.h> -+ -+ -+#define PKTGET(osh, len, send) osl_pktget((osh), (len)) -+#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) -+#define PKTLIST_DUMP(osh, buf) -+#define PKTDBG_TRACE(osh, pkt, bit) -+#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) -+#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) -+#endif -+#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) -+#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len) -+#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) -+#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail)) -+#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next) -+#define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)) -+#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len)) -+#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes)) -+#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes)) -+#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) -+#define PKTALLOCED(osh) ((osl_pubinfo_t *)(osh))->pktalloced -+#define PKTSETPOOL(osh, skb, x, y) do {} while (0) -+#define PKTPOOL(osh, skb) FALSE -+#define PKTSHRINK(osh, m) (m) -+ -+#ifdef CTFPOOL -+#define CTFPOOL_REFILL_THRESH 3 -+typedef struct ctfpool { -+ void *head; -+ spinlock_t lock; -+ uint max_obj; -+ uint curr_obj; -+ uint obj_size; -+ uint refills; -+ uint fast_allocs; -+ uint fast_frees; -+ uint slow_allocs; -+} ctfpool_t; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -+#define FASTBUF (1 << 16) -+#define CTFBUF (1 << 17) -+#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF) -+#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)) -+#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= CTFBUF) -+#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~CTFBUF)) -+#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & FASTBUF) -+#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & CTFBUF) -+#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) -+#else -+#define FASTBUF (1 << 0) -+#define CTFBUF (1 << 1) -+#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= FASTBUF) -+#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)) -+#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= CTFBUF) -+#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~CTFBUF)) -+#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) & FASTBUF) -+#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) & CTFBUF) -+#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) -+#endif -+ -+#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) -+#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) -+ -+extern void *osl_ctfpool_add(osl_t *osh); -+extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); -+extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); -+extern void osl_ctfpool_cleanup(osl_t *osh); -+extern void osl_ctfpool_stats(osl_t *osh, void *b); -+#endif -+ -+ -+#ifdef HNDCTF -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -+#define SKIPCT (1 << 18) -+#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len |= SKIPCT) -+#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)) -+#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len & SKIPCT) -+#else -+#define SKIPCT (1 << 2) -+#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused |= SKIPCT) -+#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)) -+#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused & SKIPCT) -+#endif -+#else -+#define PKTSETSKIPCT(osh, skb) -+#define PKTCLRSKIPCT(osh, skb) -+#define PKTSKIPCT(osh, skb) -+#endif -+ -+extern void osl_pktfree(osl_t *osh, void *skb, bool send); -+extern void *osl_pktget_static(osl_t *osh, uint len); -+extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); -+ -+extern void *osl_pkt_frmnative(osl_t *osh, void *skb); -+extern void *osl_pktget(osl_t *osh, uint len); -+extern void *osl_pktdup(osl_t *osh, void *skb); -+extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); -+#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) -+#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) -+ -+#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) -+#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) -+#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) -+#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) -+#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) -+#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ -+ ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) -+ -+#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) -+ -+#define DMA_MAP(osh, va, size, direction, p, dmah) \ -+ osl_dma_map((osh), (va), (size), (direction)) -+ -+#ifdef PKTC -+ -+struct chain_node { -+ struct sk_buff *link; -+ unsigned int flags:3, pkts:9, bytes:20; -+}; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) -+#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->tstamp)) -+#else -+#define CHAIN_NODE(skb) ((struct chain_node*)&(((struct sk_buff*)skb)->stamp)) -+#endif -+ -+#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) -+#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) -+#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) -+#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c) & ((1 << 9) - 1)) -+#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l) & ((1 << 20) - 1)) -+#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) -+#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) -+#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) -+#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) -+#define PKTISCHAINED(skb) (PKTCLINK(skb) != NULL) -+#define FOREACH_CHAINED_PKT(skb, nskb) \ -+ for (; (skb) != NULL; (skb) = (nskb)) \ -+ if ((nskb) = PKTCLINK(skb), PKTSETCLINK((skb), NULL), 1) -+#define PKTCFREE(osh, skb, send) \ -+do { \ -+ void *nskb; \ -+ ASSERT((skb) != NULL); \ -+ FOREACH_CHAINED_PKT((skb), nskb) { \ -+ PKTFREE((osh), (skb), (send)); \ -+ } \ -+} while (0) -+#endif -+ -+#else -+ -+ -+ -+ #define ASSERT(exp) do {} while (0) -+ -+ -+#define MALLOC(o, l) malloc(l) -+#define MFREE(o, p, l) free(p) -+#include <stdlib.h> -+ -+ -+#include <string.h> -+ -+ -+#include <stdio.h> -+ -+ -+extern void bcopy(const void *src, void *dst, size_t len); -+extern int bcmp(const void *b1, const void *b2, size_t len); -+extern void bzero(void *b, size_t len); -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h -new file mode 100644 -index 00000000..f242aad4 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/linuxver.h -@@ -0,0 +1,630 @@ -+/* -+ * Linux-specific abstractions to gain some independence from linux kernel versions. -+ * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: linuxver.h 353905 2012-08-29 07:33:08Z $ -+ */ -+ -+#ifndef _linuxver_h_ -+#define _linuxver_h_ -+ -+#include <linux/version.h> -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -+#include <linux/config.h> -+#else -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) -+#include <generated/autoconf.h> -+#else -+#include <linux/autoconf.h> -+#endif -+#endif -+#include <linux/module.h> -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) -+ -+#ifdef __UNDEF_NO_VERSION__ -+#undef __NO_VERSION__ -+#else -+#define __NO_VERSION__ -+#endif -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) -+#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") -+#define module_param_string(_name_, _string_, _size_, _perm_) \ -+ MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) -+#endif -+ -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) -+#include <linux/malloc.h> -+#else -+#include <linux/slab.h> -+#endif -+ -+#include <linux/types.h> -+#include <linux/init.h> -+#include <linux/mm.h> -+#include <linux/string.h> -+#include <linux/pci.h> -+#include <linux/interrupt.h> -+#include <linux/netdevice.h> -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+#include <linux/semaphore.h> -+#else -+#include <asm/semaphore.h> -+#endif -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) -+#undef IP_TOS -+#endif -+#include <asm/io.h> -+ -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) -+#include <linux/workqueue.h> -+#else -+#include <linux/tqueue.h> -+#ifndef work_struct -+#define work_struct tq_struct -+#endif -+#ifndef INIT_WORK -+#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) -+#endif -+#ifndef schedule_work -+#define schedule_work(_work) schedule_task((_work)) -+#endif -+#ifndef flush_scheduled_work -+#define flush_scheduled_work() flush_scheduled_tasks() -+#endif -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+#define DAEMONIZE(a) daemonize(a); \ -+ allow_signal(SIGKILL); \ -+ allow_signal(SIGTERM); -+#else -+#define RAISE_RX_SOFTIRQ() \ -+ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -+#define DAEMONIZE(a) daemonize(); \ -+ do { if (a) \ -+ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ -+ } while (0); -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -+#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) -+#else -+#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) -+#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ -+ (RHEL_MAJOR == 5)) -+ -+typedef void (*work_func_t)(void *work); -+#endif -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -+ -+#ifndef IRQ_NONE -+typedef void irqreturn_t; -+#define IRQ_NONE -+#define IRQ_HANDLED -+#define IRQ_RETVAL(x) -+#endif -+#else -+typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) -+#define IRQF_SHARED SA_SHIRQ -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) -+#ifdef CONFIG_NET_RADIO -+#define CONFIG_WIRELESS_EXT -+#endif -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) -+#define MOD_INC_USE_COUNT -+#define MOD_DEC_USE_COUNT -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) -+#include <linux/sched.h> -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -+#include <net/lib80211.h> -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -+#include <linux/ieee80211.h> -+#else -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) -+#include <net/ieee80211.h> -+#endif -+#endif -+ -+ -+#ifndef __exit -+#define __exit -+#endif -+#ifndef __devexit -+#define __devexit -+#endif -+#ifndef __devinit -+#define __devinit __init -+#endif -+#ifndef __devinitdata -+#define __devinitdata -+#endif -+#ifndef __devexit_p -+#define __devexit_p(x) x -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) -+ -+#define pci_get_drvdata(dev) (dev)->sysdata -+#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) -+ -+ -+ -+struct pci_device_id { -+ unsigned int vendor, device; -+ unsigned int subvendor, subdevice; -+ unsigned int class, class_mask; -+ unsigned long driver_data; -+}; -+ -+struct pci_driver { -+ struct list_head node; -+ char *name; -+ const struct pci_device_id *id_table; -+ int (*probe)(struct pci_dev *dev, -+ const struct pci_device_id *id); -+ void (*remove)(struct pci_dev *dev); -+ void (*suspend)(struct pci_dev *dev); -+ void (*resume)(struct pci_dev *dev); -+}; -+ -+#define MODULE_DEVICE_TABLE(type, name) -+#define PCI_ANY_ID (~0) -+ -+ -+#define pci_module_init pci_register_driver -+extern int pci_register_driver(struct pci_driver *drv); -+extern void pci_unregister_driver(struct pci_driver *drv); -+ -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) -+#define pci_module_init pci_register_driver -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) -+#ifdef MODULE -+#define module_init(x) int init_module(void) { return x(); } -+#define module_exit(x) void cleanup_module(void) { x(); } -+#else -+#define module_init(x) __initcall(x); -+#define module_exit(x) __exitcall(x); -+#endif -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) -+#define WL_USE_NETDEV_OPS -+#else -+#undef WL_USE_NETDEV_OPS -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) -+#define WL_CONFIG_RFKILL -+#else -+#undef WL_CONFIG_RFKILL -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) -+#define list_for_each(pos, head) \ -+ for (pos = (head)->next; pos != (head); pos = pos->next) -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) -+#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) -+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) -+#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) -+#define pci_enable_device(dev) do { } while (0) -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) -+#define net_device device -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) -+ -+ -+ -+#ifndef PCI_DMA_TODEVICE -+#define PCI_DMA_TODEVICE 1 -+#define PCI_DMA_FROMDEVICE 2 -+#endif -+ -+typedef u32 dma_addr_t; -+ -+ -+static inline int get_order(unsigned long size) -+{ -+ int order; -+ -+ size = (size-1) >> (PAGE_SHIFT-1); -+ order = -1; -+ do { -+ size >>= 1; -+ order++; -+ } while (size); -+ return order; -+} -+ -+static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, -+ dma_addr_t *dma_handle) -+{ -+ void *ret; -+ int gfp = GFP_ATOMIC | GFP_DMA; -+ -+ ret = (void *)__get_free_pages(gfp, get_order(size)); -+ -+ if (ret != NULL) { -+ memset(ret, 0, size); -+ *dma_handle = virt_to_bus(ret); -+ } -+ return ret; -+} -+static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, -+ void *vaddr, dma_addr_t dma_handle) -+{ -+ free_pages((unsigned long)vaddr, get_order(size)); -+} -+#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) -+#define pci_unmap_single(cookie, address, size, dir) -+ -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) -+ -+#define dev_kfree_skb_any(a) dev_kfree_skb(a) -+#define netif_down(dev) do { (dev)->start = 0; } while (0) -+ -+ -+#ifndef _COMPAT_NETDEVICE_H -+ -+ -+ -+#define dev_kfree_skb_irq(a) dev_kfree_skb(a) -+#define netif_wake_queue(dev) \ -+ do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) -+#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) -+ -+static inline void netif_start_queue(struct net_device *dev) -+{ -+ dev->tbusy = 0; -+ dev->interrupt = 0; -+ dev->start = 1; -+} -+ -+#define netif_queue_stopped(dev) (dev)->tbusy -+#define netif_running(dev) (dev)->start -+ -+#endif -+ -+#define netif_device_attach(dev) netif_start_queue(dev) -+#define netif_device_detach(dev) netif_stop_queue(dev) -+ -+ -+#define tasklet_struct tq_struct -+static inline void tasklet_schedule(struct tasklet_struct *tasklet) -+{ -+ queue_task(tasklet, &tq_immediate); -+ mark_bh(IMMEDIATE_BH); -+} -+ -+static inline void tasklet_init(struct tasklet_struct *tasklet, -+ void (*func)(unsigned long), -+ unsigned long data) -+{ -+ tasklet->next = NULL; -+ tasklet->sync = 0; -+ tasklet->routine = (void (*)(void *))func; -+ tasklet->data = (void *)data; -+} -+#define tasklet_kill(tasklet) { do {} while (0); } -+ -+ -+#define del_timer_sync(timer) del_timer(timer) -+ -+#else -+ -+#define netif_down(dev) -+ -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) -+ -+ -+#define PREPARE_TQUEUE(_tq, _routine, _data) \ -+ do { \ -+ (_tq)->routine = _routine; \ -+ (_tq)->data = _data; \ -+ } while (0) -+ -+ -+#define INIT_TQUEUE(_tq, _routine, _data) \ -+ do { \ -+ INIT_LIST_HEAD(&(_tq)->list); \ -+ (_tq)->sync = 0; \ -+ PREPARE_TQUEUE((_tq), (_routine), (_data)); \ -+ } while (0) -+ -+#endif -+ -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) -+#define PCI_SAVE_STATE(a, b) pci_save_state(a) -+#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) -+#else -+#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) -+#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) -+static inline int -+pci_save_state(struct pci_dev *dev, u32 *buffer) -+{ -+ int i; -+ if (buffer) { -+ for (i = 0; i < 16; i++) -+ pci_read_config_dword(dev, i * 4, &buffer[i]); -+ } -+ return 0; -+} -+ -+static inline int -+pci_restore_state(struct pci_dev *dev, u32 *buffer) -+{ -+ int i; -+ -+ if (buffer) { -+ for (i = 0; i < 16; i++) -+ pci_write_config_dword(dev, i * 4, buffer[i]); -+ } -+ -+ else { -+ for (i = 0; i < 6; i ++) -+ pci_write_config_dword(dev, -+ PCI_BASE_ADDRESS_0 + (i * 4), -+ pci_resource_start(dev, i)); -+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); -+ } -+ return 0; -+} -+#endif -+ -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) -+#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) -+#endif -+ -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) -+#ifndef SET_MODULE_OWNER -+#define SET_MODULE_OWNER(dev) do {} while (0) -+#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -+#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -+#else -+#define OLD_MOD_INC_USE_COUNT do {} while (0) -+#define OLD_MOD_DEC_USE_COUNT do {} while (0) -+#endif -+#else -+#ifndef SET_MODULE_OWNER -+#define SET_MODULE_OWNER(dev) do {} while (0) -+#endif -+#ifndef MOD_INC_USE_COUNT -+#define MOD_INC_USE_COUNT do {} while (0) -+#endif -+#ifndef MOD_DEC_USE_COUNT -+#define MOD_DEC_USE_COUNT do {} while (0) -+#endif -+#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT -+#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT -+#endif -+ -+#ifndef SET_NETDEV_DEV -+#define SET_NETDEV_DEV(net, pdev) do {} while (0) -+#endif -+ -+#ifndef HAVE_FREE_NETDEV -+#define free_netdev(dev) kfree(dev) -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -+ -+#define af_packet_priv data -+#endif -+ -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) -+#define DRV_SUSPEND_STATE_TYPE pm_message_t -+#else -+#define DRV_SUSPEND_STATE_TYPE uint32 -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -+#define CHECKSUM_HW CHECKSUM_PARTIAL -+#endif -+ -+typedef struct { -+ void *parent; -+ struct task_struct *p_task; -+ long thr_pid; -+ int prio; -+ struct semaphore sema; -+ int terminated; -+ struct completion completed; -+} tsk_ctl_t; -+ -+ -+ -+ -+#ifdef DHD_DEBUG -+#define DBG_THR(x) printk x -+#else -+#define DBG_THR(x) -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) -+#else -+#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) -+#endif -+ -+ -+#define PROC_START(thread_func, owner, tsk_ctl, flags) \ -+{ \ -+ sema_init(&((tsk_ctl)->sema), 0); \ -+ init_completion(&((tsk_ctl)->completed)); \ -+ (tsk_ctl)->parent = owner; \ -+ (tsk_ctl)->terminated = FALSE; \ -+ (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \ -+ DBG_THR(("%s thr:%lx created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ -+ if ((tsk_ctl)->thr_pid > 0) \ -+ wait_for_completion(&((tsk_ctl)->completed)); \ -+ DBG_THR(("%s thr:%lx started\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ -+} -+ -+#ifdef USE_KTHREAD_API -+#define PROC_START2(thread_func, owner, tsk_ctl, flags, name) \ -+{ \ -+ sema_init(&((tsk_ctl)->sema), 0); \ -+ init_completion(&((tsk_ctl)->completed)); \ -+ (tsk_ctl)->parent = owner; \ -+ (tsk_ctl)->terminated = FALSE; \ -+ (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ -+ (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ -+ DBG_THR(("%s thr:%lx created\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ -+} -+#endif -+ -+#define PROC_STOP(tsk_ctl) \ -+{ \ -+ (tsk_ctl)->terminated = TRUE; \ -+ smp_wmb(); \ -+ up(&((tsk_ctl)->sema)); \ -+ wait_for_completion(&((tsk_ctl)->completed)); \ -+ DBG_THR(("%s thr:%lx terminated OK\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \ -+ (tsk_ctl)->thr_pid = -1; \ -+} -+ -+ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -+#define KILL_PROC(nr, sig) \ -+{ \ -+struct task_struct *tsk; \ -+struct pid *pid; \ -+pid = find_get_pid((pid_t)nr); \ -+tsk = pid_task(pid, PIDTYPE_PID); \ -+if (tsk) send_sig(sig, tsk, 1); \ -+} -+#else -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ -+ KERNEL_VERSION(2, 6, 30)) -+#define KILL_PROC(pid, sig) \ -+{ \ -+ struct task_struct *tsk; \ -+ tsk = find_task_by_vpid(pid); \ -+ if (tsk) send_sig(sig, tsk, 1); \ -+} -+#else -+#define KILL_PROC(pid, sig) \ -+{ \ -+ kill_proc(pid, sig, 1); \ -+} -+#endif -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+#include <linux/time.h> -+#include <linux/wait.h> -+#else -+#include <linux/sched.h> -+ -+#define __wait_event_interruptible_timeout(wq, condition, ret) \ -+do { \ -+ wait_queue_t __wait; \ -+ init_waitqueue_entry(&__wait, current); \ -+ \ -+ add_wait_queue(&wq, &__wait); \ -+ for (;;) { \ -+ set_current_state(TASK_INTERRUPTIBLE); \ -+ if (condition) \ -+ break; \ -+ if (!signal_pending(current)) { \ -+ ret = schedule_timeout(ret); \ -+ if (!ret) \ -+ break; \ -+ continue; \ -+ } \ -+ ret = -ERESTARTSYS; \ -+ break; \ -+ } \ -+ current->state = TASK_RUNNING; \ -+ remove_wait_queue(&wq, &__wait); \ -+} while (0) -+ -+#define wait_event_interruptible_timeout(wq, condition, timeout) \ -+({ \ -+ long __ret = timeout; \ -+ if (!(condition)) \ -+ __wait_event_interruptible_timeout(wq, condition, __ret); \ -+ __ret; \ -+}) -+ -+#endif -+ -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) -+#define DEV_PRIV(dev) (dev->priv) -+#else -+#define DEV_PRIV(dev) netdev_priv(dev) -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -+#define WL_ISR(i, d, p) wl_isr((i), (d)) -+#else -+#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -+#define netdev_priv(dev) dev->priv -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h -new file mode 100644 -index 00000000..c1eca68a ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/miniopt.h -@@ -0,0 +1,77 @@ -+/* -+ * Command line options parser. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * $Id: miniopt.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+ -+#ifndef MINI_OPT_H -+#define MINI_OPT_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* ---- Include Files ---------------------------------------------------- */ -+/* ---- Constants and Types ---------------------------------------------- */ -+ -+#define MINIOPT_MAXKEY 128 /* Max options */ -+typedef struct miniopt { -+ -+ /* These are persistent after miniopt_init() */ -+ const char* name; /* name for prompt in error strings */ -+ const char* flags; /* option chars that take no args */ -+ bool longflags; /* long options may be flags */ -+ bool opt_end; /* at end of options (passed a "--") */ -+ -+ /* These are per-call to miniopt() */ -+ -+ int consumed; /* number of argv entries cosumed in -+ * the most recent call to miniopt() -+ */ -+ bool positional; -+ bool good_int; /* 'val' member is the result of a sucessful -+ * strtol conversion of the option value -+ */ -+ char opt; -+ char key[MINIOPT_MAXKEY]; -+ char* valstr; /* positional param, or value for the option, -+ * or null if the option had -+ * no accompanying value -+ */ -+ uint uval; /* strtol translation of valstr */ -+ int val; /* strtol translation of valstr */ -+} miniopt_t; -+ -+void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); -+int miniopt(miniopt_t *t, char **argv); -+ -+ -+/* ---- Variable Externs ------------------------------------------------- */ -+/* ---- Function Prototypes ---------------------------------------------- */ -+ -+ -+#ifdef __cplusplus -+ } -+#endif -+ -+#endif /* MINI_OPT_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h -new file mode 100644 -index 00000000..7c5fd810 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/msgtrace.h -@@ -0,0 +1,74 @@ -+/* -+ * Trace messages sent over HBUS -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: msgtrace.h 281527 2011-09-02 17:12:53Z $ -+ */ -+ -+#ifndef _MSGTRACE_H -+#define _MSGTRACE_H -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+ -+/* This marks the start of a packed structure section. */ -+#include <packed_section_start.h> -+ -+#define MSGTRACE_VERSION 1 -+ -+/* Message trace header */ -+typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { -+ uint8 version; -+ uint8 spare; -+ uint16 len; /* Len of the trace */ -+ uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost -+ * because of DMA error or a bus reset (ex: SDIO Func2) -+ */ -+ uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ -+ uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ -+} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; -+ -+#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) -+ -+/* The hbus driver generates traces when sending a trace message. This causes endless traces. -+ * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put. -+ * This prevents endless traces but generates hasardous lost of traces only in bus device code. -+ * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing -+ * hbus error traces. hbus error trace should not generates endless traces. -+ */ -+extern bool msgtrace_hbus_trace; -+ -+typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, -+ uint16 hdrlen, uint8 *buf, uint16 buflen); -+extern void msgtrace_start(void); -+extern void msgtrace_stop(void); -+extern void msgtrace_sent(void); -+extern void msgtrace_put(char *buf, int count); -+extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send); -+extern bool msgtrace_event_enabled(void); -+ -+/* This marks the end of a packed structure section. */ -+#include <packed_section_end.h> -+ -+#endif /* _MSGTRACE_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h -new file mode 100644 -index 00000000..ca171d8a ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/osl.h -@@ -0,0 +1,88 @@ -+/* -+ * OS Abstraction Layer -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: osl.h 320905 2012-03-13 15:33:25Z $ -+ */ -+ -+#ifndef _osl_h_ -+#define _osl_h_ -+ -+ -+typedef struct osl_info osl_t; -+typedef struct osl_dmainfo osldma_t; -+ -+#define OSL_PKTTAG_SZ 32 -+ -+ -+typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); -+ -+ -+typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); -+typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); -+ -+ -+#include <linux_osl.h> -+ -+#ifndef PKTDBG_TRACE -+#define PKTDBG_TRACE(osh, pkt, bit) -+#endif -+ -+#define PKTCTFMAP(osh, p) -+ -+ -+ -+#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) -+ -+#ifndef AND_REG -+#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) -+#endif -+ -+#ifndef OR_REG -+#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) -+#endif -+ -+#if !defined(OSL_SYSUPTIME) -+#define OSL_SYSUPTIME() (0) -+#define OSL_SYSUPTIME_SUPPORT FALSE -+#else -+#define OSL_SYSUPTIME_SUPPORT TRUE -+#endif -+ -+#if !defined(PKTC) -+#define PKTCCNT(skb) (0) -+#define PKTCLEN(skb) (0) -+#define PKTCFLAGS(skb) (0) -+#define PKTCSETCNT(skb, c) -+#define PKTCSETLEN(skb, l) -+#define PKTCSETFLAG(skb, fb) -+#define PKTCCLRFLAG(skb, fb) -+#define PKTCLINK(skb) PKTLINK(skb) -+#define PKTSETCLINK(skb, x) PKTSETLINK((skb), (x)) -+#define PKTISCHAINED(skb) FALSE -+#define FOREACH_CHAINED_PKT(skb, nskb) \ -+ for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) -+#define PKTCFREE PKTFREE -+#endif -+ -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h -new file mode 100644 -index 00000000..24ff4672 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/packed_section_end.h -@@ -0,0 +1,53 @@ -+/* -+ * Declare directives for structure packing. No padding will be provided -+ * between the members of packed structures, and therefore, there is no -+ * guarantee that structure members will be aligned. -+ * -+ * Declaring packed structures is compiler specific. In order to handle all -+ * cases, packed structures should be delared as: -+ * -+ * #include <packed_section_start.h> -+ * -+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { -+ * some_struct_members; -+ * } BWL_POST_PACKED_STRUCT foobar_t; -+ * -+ * #include <packed_section_end.h> -+ * -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * $Id: packed_section_end.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+ -+ -+#ifdef BWL_PACKED_SECTION -+ #undef BWL_PACKED_SECTION -+#else -+ #error "BWL_PACKED_SECTION is NOT defined!" -+#endif -+ -+ -+ -+ -+ -+#undef BWL_PRE_PACKED_STRUCT -+#undef BWL_POST_PACKED_STRUCT -diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h -new file mode 100644 -index 00000000..7fce0ddf ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/packed_section_start.h -@@ -0,0 +1,60 @@ -+/* -+ * Declare directives for structure packing. No padding will be provided -+ * between the members of packed structures, and therefore, there is no -+ * guarantee that structure members will be aligned. -+ * -+ * Declaring packed structures is compiler specific. In order to handle all -+ * cases, packed structures should be delared as: -+ * -+ * #include <packed_section_start.h> -+ * -+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { -+ * some_struct_members; -+ * } BWL_POST_PACKED_STRUCT foobar_t; -+ * -+ * #include <packed_section_end.h> -+ * -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * $Id: packed_section_start.h 286783 2011-09-29 06:18:57Z $ -+ */ -+ -+ -+ -+#ifdef BWL_PACKED_SECTION -+ #error "BWL_PACKED_SECTION is already defined!" -+#else -+ #define BWL_PACKED_SECTION -+#endif -+ -+ -+ -+ -+ -+#if defined(__GNUC__) || defined(__lint) -+ #define BWL_PRE_PACKED_STRUCT -+ #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) -+#elif defined(__CC_ARM) -+ #define BWL_PRE_PACKED_STRUCT __packed -+ #define BWL_POST_PACKED_STRUCT -+#else -+ #error "Unknown compiler!" -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h -new file mode 100644 -index 00000000..5f7df6a7 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/pcicfg.h -@@ -0,0 +1,90 @@ -+/* -+ * pcicfg.h: PCI configuration constants and structures. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: pcicfg.h 309193 2012-01-19 00:03:57Z $ -+ */ -+ -+#ifndef _h_pcicfg_ -+#define _h_pcicfg_ -+ -+ -+#define PCI_CFG_VID 0 -+#define PCI_CFG_DID 2 -+#define PCI_CFG_CMD 4 -+#define PCI_CFG_STAT 6 -+#define PCI_CFG_REV 8 -+#define PCI_CFG_PROGIF 9 -+#define PCI_CFG_SUBCL 0xa -+#define PCI_CFG_BASECL 0xb -+#define PCI_CFG_CLSZ 0xc -+#define PCI_CFG_LATTIM 0xd -+#define PCI_CFG_HDR 0xe -+#define PCI_CFG_BIST 0xf -+#define PCI_CFG_BAR0 0x10 -+#define PCI_CFG_BAR1 0x14 -+#define PCI_CFG_BAR2 0x18 -+#define PCI_CFG_BAR3 0x1c -+#define PCI_CFG_BAR4 0x20 -+#define PCI_CFG_BAR5 0x24 -+#define PCI_CFG_CIS 0x28 -+#define PCI_CFG_SVID 0x2c -+#define PCI_CFG_SSID 0x2e -+#define PCI_CFG_ROMBAR 0x30 -+#define PCI_CFG_CAPPTR 0x34 -+#define PCI_CFG_INT 0x3c -+#define PCI_CFG_PIN 0x3d -+#define PCI_CFG_MINGNT 0x3e -+#define PCI_CFG_MAXLAT 0x3f -+#define PCI_BAR0_WIN 0x80 -+#define PCI_BAR1_WIN 0x84 -+#define PCI_SPROM_CONTROL 0x88 -+#define PCI_BAR1_CONTROL 0x8c -+#define PCI_INT_STATUS 0x90 -+#define PCI_INT_MASK 0x94 -+#define PCI_TO_SB_MB 0x98 -+#define PCI_BACKPLANE_ADDR 0xa0 -+#define PCI_BACKPLANE_DATA 0xa4 -+#define PCI_CLK_CTL_ST 0xa8 -+#define PCI_BAR0_WIN2 0xac -+#define PCI_GPIO_IN 0xb0 -+#define PCI_GPIO_OUT 0xb4 -+#define PCI_GPIO_OUTEN 0xb8 -+ -+#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) -+#define PCI_BAR0_SPROM_OFFSET (4 * 1024) -+#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) -+#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) -+ -+#define PCIE2_BAR0_WIN2 0x70 -+#define PCIE2_BAR0_CORE2_WIN 0x74 -+#define PCIE2_BAR0_CORE2_WIN2 0x78 -+ -+#define PCI_BAR0_WINSZ (16 * 1024) -+ -+#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) -+#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) -+#define PCI_16KBB0_WINSZ (16 * 1024) -+ -+ -+#define PCI_CONFIG_SPACE_SIZE 256 -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h -new file mode 100644 -index 00000000..dc648eef ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h -@@ -0,0 +1,2243 @@ -+/* -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * Fundamental types and constants relating to 802.11 -+ * -+ * $Id: 802.11.h 346820 2012-07-24 13:53:12Z $ -+ */ -+ -+#ifndef _802_11_H_ -+#define _802_11_H_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+#ifndef _NET_ETHERNET_H_ -+#include <proto/ethernet.h> -+#endif -+ -+#include <proto/wpa.h> -+ -+ -+#include <packed_section_start.h> -+ -+ -+#define DOT11_TU_TO_US 1024 -+ -+ -+#define DOT11_A3_HDR_LEN 24 -+#define DOT11_A4_HDR_LEN 30 -+#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN -+#define DOT11_FCS_LEN 4 -+#define DOT11_ICV_LEN 4 -+#define DOT11_ICV_AES_LEN 8 -+#define DOT11_QOS_LEN 2 -+#define DOT11_HTC_LEN 4 -+ -+#define DOT11_KEY_INDEX_SHIFT 6 -+#define DOT11_IV_LEN 4 -+#define DOT11_IV_TKIP_LEN 8 -+#define DOT11_IV_AES_OCB_LEN 4 -+#define DOT11_IV_AES_CCM_LEN 8 -+#define DOT11_IV_MAX_LEN 8 -+ -+ -+#define DOT11_MAX_MPDU_BODY_LEN 2304 -+ -+#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ -+ DOT11_QOS_LEN + \ -+ DOT11_IV_AES_CCM_LEN + \ -+ DOT11_MAX_MPDU_BODY_LEN + \ -+ DOT11_ICV_LEN + \ -+ DOT11_FCS_LEN) -+ -+#define DOT11_MAX_SSID_LEN 32 -+ -+ -+#define DOT11_DEFAULT_RTS_LEN 2347 -+#define DOT11_MAX_RTS_LEN 2347 -+ -+ -+#define DOT11_MIN_FRAG_LEN 256 -+#define DOT11_MAX_FRAG_LEN 2346 -+#define DOT11_DEFAULT_FRAG_LEN 2346 -+ -+ -+#define DOT11_MIN_BEACON_PERIOD 1 -+#define DOT11_MAX_BEACON_PERIOD 0xFFFF -+ -+ -+#define DOT11_MIN_DTIM_PERIOD 1 -+#define DOT11_MAX_DTIM_PERIOD 0xFF -+ -+ -+#define DOT11_LLC_SNAP_HDR_LEN 8 -+#define DOT11_OUI_LEN 3 -+BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { -+ uint8 dsap; -+ uint8 ssap; -+ uint8 ctl; -+ uint8 oui[DOT11_OUI_LEN]; -+ uint16 type; -+} BWL_POST_PACKED_STRUCT; -+ -+ -+#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_header { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr a1; -+ struct ether_addr a2; -+ struct ether_addr a3; -+ uint16 seq; -+ struct ether_addr a4; -+} BWL_POST_PACKED_STRUCT; -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr ra; -+ struct ether_addr ta; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_RTS_LEN 16 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr ra; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_CTS_LEN 10 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr ra; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_ACK_LEN 10 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr bssid; -+ struct ether_addr ta; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_PS_POLL_LEN 16 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr ra; -+ struct ether_addr bssid; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_CS_END_LEN 16 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { -+ uint8 category; -+ uint8 OUI[3]; -+ uint8 type; -+ uint8 subtype; -+ uint8 data[1040]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { -+ uint8 category; -+ uint8 OUI[3]; -+ uint8 type; -+ uint8 subtype; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; -+#define DOT11_ACTION_VS_HDR_LEN 6 -+ -+#define BCM_ACTION_OUI_BYTE0 0x00 -+#define BCM_ACTION_OUI_BYTE1 0x90 -+#define BCM_ACTION_OUI_BYTE2 0x4c -+ -+ -+#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 -+#define DOT11_BA_CTL_POLICY_NOACK 0x0001 -+#define DOT11_BA_CTL_POLICY_MASK 0x0001 -+ -+#define DOT11_BA_CTL_MTID 0x0002 -+#define DOT11_BA_CTL_COMPRESSED 0x0004 -+ -+#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 -+#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 -+ -+#define DOT11_BA_CTL_TID_MASK 0xF000 -+#define DOT11_BA_CTL_TID_SHIFT 12 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr ra; -+ struct ether_addr ta; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_CTL_HDR_LEN 16 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_bar { -+ uint16 bar_control; -+ uint16 seqnum; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_BAR_LEN 4 -+ -+#define DOT11_BA_BITMAP_LEN 128 -+#define DOT11_BA_CMP_BITMAP_LEN 8 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ba { -+ uint16 ba_control; -+ uint16 seqnum; -+ uint8 bitmap[DOT11_BA_BITMAP_LEN]; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_BA_LEN 4 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_management_header { -+ uint16 fc; -+ uint16 durid; -+ struct ether_addr da; -+ struct ether_addr sa; -+ struct ether_addr bssid; -+ uint16 seq; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_MGMT_HDR_LEN 24 -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { -+ uint32 timestamp[2]; -+ uint16 beacon_interval; -+ uint16 capability; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_BCN_PRB_LEN 12 -+#define DOT11_BCN_PRB_FIXED_LEN 12 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_auth { -+ uint16 alg; -+ uint16 seq; -+ uint16 status; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_AUTH_FIXED_LEN 6 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { -+ uint16 capability; -+ uint16 listen; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_ASSOC_REQ_FIXED_LEN 4 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { -+ uint16 capability; -+ uint16 listen; -+ struct ether_addr ap; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_REASSOC_REQ_FIXED_LEN 10 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { -+ uint16 capability; -+ uint16 status; -+ uint16 aid; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_ASSOC_RESP_FIXED_LEN 6 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_measure { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_ACTION_MEASURE_LEN 3 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { -+ uint8 category; -+ uint8 action; -+ uint8 ch_width; -+} BWL_POST_PACKED_STRUCT; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { -+ uint8 category; -+ uint8 action; -+ uint8 control; -+} BWL_POST_PACKED_STRUCT; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { -+ uint8 category; -+ uint8 action; -+ uint16 id; -+} BWL_POST_PACKED_STRUCT; -+ -+#define SM_PWRSAVE_ENABLE 1 -+#define SM_PWRSAVE_MODE 2 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { -+ uint8 id; -+ uint8 len; -+ uint8 power; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_power_cnst dot11_power_cnst_t; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_power_cap { -+ uint8 min; -+ uint8 max; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_power_cap dot11_power_cap_t; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { -+ uint8 id; -+ uint8 len; -+ uint8 tx_pwr; -+ uint8 margin; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_tpc_rep dot11_tpc_rep_t; -+#define DOT11_MNG_IE_TPC_REPORT_LEN 2 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { -+ uint8 id; -+ uint8 len; -+ uint8 first_channel; -+ uint8 num_channels; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_supp_channels dot11_supp_channels_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_extch { -+ uint8 id; -+ uint8 len; -+ uint8 extch; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_extch dot11_extch_ie_t; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { -+ uint8 id; -+ uint8 len; -+ uint8 oui[3]; -+ uint8 type; -+ uint8 extch; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; -+ -+#define BRCM_EXTCH_IE_LEN 5 -+#define BRCM_EXTCH_IE_TYPE 53 -+#define DOT11_EXTCH_IE_LEN 1 -+#define DOT11_EXT_CH_MASK 0x03 -+#define DOT11_EXT_CH_UPPER 0x01 -+#define DOT11_EXT_CH_LOWER 0x03 -+#define DOT11_EXT_CH_NONE 0x00 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { -+ uint8 category; -+ uint8 action; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_ACTION_FRMHDR_LEN 2 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { -+ uint8 id; -+ uint8 len; -+ uint8 mode; -+ uint8 channel; -+ uint8 count; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_channel_switch dot11_chan_switch_ie_t; -+ -+#define DOT11_SWITCH_IE_LEN 3 -+ -+#define DOT11_CSA_MODE_ADVISORY 0 -+#define DOT11_CSA_MODE_NO_TX 1 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { -+ uint8 category; -+ uint8 action; -+ dot11_chan_switch_ie_t chan_switch_ie; -+ dot11_brcm_extch_ie_t extch_ie; -+} BWL_POST_PACKED_STRUCT; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_csa_body { -+ uint8 mode; -+ uint8 reg; -+ uint8 channel; -+ uint8 count; -+} BWL_POST_PACKED_STRUCT; -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { -+ uint8 id; -+ uint8 len; -+ struct dot11_csa_body b; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_ext_csa dot11_ext_csa_ie_t; -+#define DOT11_EXT_CSA_IE_LEN 4 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { -+ uint8 category; -+ uint8 action; -+ dot11_ext_csa_ie_t chan_switch_ie; -+} BWL_POST_PACKED_STRUCT; -+ -+BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { -+ uint8 category; -+ uint8 action; -+ struct dot11_csa_body b; -+} BWL_POST_PACKED_STRUCT; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { -+ uint8 id; -+ uint8 len; -+ uint8 info; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_obss_coex dot11_obss_coex_t; -+#define DOT11_OBSS_COEXINFO_LEN 1 -+ -+#define DOT11_OBSS_COEX_INFO_REQ 0x01 -+#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 -+#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { -+ uint8 id; -+ uint8 len; -+ uint8 regclass; -+ uint8 chanlist[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; -+#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { -+ uint8 id; -+ uint8 len; -+ uint8 cap[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_extcap_ie dot11_extcap_ie_t; -+ -+#define DOT11_EXTCAP_LEN_MAX 7 -+#define DOT11_EXTCAP_LEN_COEX 1 -+#define DOT11_EXTCAP_LEN_BT 3 -+#define DOT11_EXTCAP_LEN_IW 4 -+#define DOT11_EXTCAP_LEN_SI 6 -+ -+#define DOT11_EXTCAP_LEN_TDLS 5 -+BWL_PRE_PACKED_STRUCT struct dot11_extcap { -+ uint8 extcap[DOT11_EXTCAP_LEN_TDLS]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_extcap dot11_extcap_t; -+ -+ -+#define TDLS_CAP_TDLS 37 -+#define TDLS_CAP_PU_BUFFER_STA 28 -+#define TDLS_CAP_PEER_PSM 20 -+#define TDLS_CAP_CH_SW 30 -+#define TDLS_CAP_PROH 38 -+#define TDLS_CAP_CH_SW_PROH 39 -+ -+#define TDLS_CAP_MAX_BIT 39 -+ -+ -+ -+#define DOT11_MEASURE_TYPE_BASIC 0 -+#define DOT11_MEASURE_TYPE_CCA 1 -+#define DOT11_MEASURE_TYPE_RPI 2 -+#define DOT11_MEASURE_TYPE_CHLOAD 3 -+#define DOT11_MEASURE_TYPE_NOISE 4 -+#define DOT11_MEASURE_TYPE_BEACON 5 -+#define DOT11_MEASURE_TYPE_FRAME 6 -+#define DOT11_MEASURE_TYPE_STATS 7 -+#define DOT11_MEASURE_TYPE_LCI 8 -+#define DOT11_MEASURE_TYPE_TXSTREAM 9 -+#define DOT11_MEASURE_TYPE_PAUSE 255 -+ -+ -+#define DOT11_MEASURE_MODE_PARALLEL (1<<0) -+#define DOT11_MEASURE_MODE_ENABLE (1<<1) -+#define DOT11_MEASURE_MODE_REQUEST (1<<2) -+#define DOT11_MEASURE_MODE_REPORT (1<<3) -+#define DOT11_MEASURE_MODE_DUR (1<<4) -+ -+#define DOT11_MEASURE_MODE_LATE (1<<0) -+#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) -+#define DOT11_MEASURE_MODE_REFUSED (1<<2) -+ -+#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) -+#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) -+#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) -+#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) -+#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) -+ -+BWL_PRE_PACKED_STRUCT struct dot11_meas_req { -+ uint8 id; -+ uint8 len; -+ uint8 token; -+ uint8 mode; -+ uint8 type; -+ uint8 channel; -+ uint8 start_time[8]; -+ uint16 duration; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_meas_req dot11_meas_req_t; -+#define DOT11_MNG_IE_MREQ_LEN 14 -+ -+#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { -+ uint8 id; -+ uint8 len; -+ uint8 token; -+ uint8 mode; -+ uint8 type; -+ BWL_PRE_PACKED_STRUCT union -+ { -+ BWL_PRE_PACKED_STRUCT struct { -+ uint8 channel; -+ uint8 start_time[8]; -+ uint16 duration; -+ uint8 map; -+ } BWL_POST_PACKED_STRUCT basic; -+ uint8 data[1]; -+ } BWL_POST_PACKED_STRUCT rep; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_meas_rep dot11_meas_rep_t; -+ -+ -+#define DOT11_MNG_IE_MREP_FIXED_LEN 3 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { -+ uint8 channel; -+ uint8 start_time[8]; -+ uint16 duration; -+ uint8 map; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; -+#define DOT11_MEASURE_BASIC_REP_LEN 12 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_quiet { -+ uint8 id; -+ uint8 len; -+ uint8 count; -+ uint8 period; -+ uint16 duration; -+ uint16 offset; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_quiet dot11_quiet_t; -+ -+BWL_PRE_PACKED_STRUCT struct chan_map_tuple { -+ uint8 channel; -+ uint8 map; -+} BWL_POST_PACKED_STRUCT; -+typedef struct chan_map_tuple chan_map_tuple_t; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { -+ uint8 id; -+ uint8 len; -+ uint8 eaddr[ETHER_ADDR_LEN]; -+ uint8 interval; -+ chan_map_tuple_t map[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; -+ -+ -+#define WME_OUI "\x00\x50\xf2" -+#define WME_OUI_LEN 3 -+#define WME_OUI_TYPE 2 -+#define WME_TYPE 2 -+#define WME_SUBTYPE_IE 0 -+#define WME_SUBTYPE_PARAM_IE 1 -+#define WME_SUBTYPE_TSPEC 2 -+#define WME_VER 1 -+ -+ -+#define AC_BE 0 -+#define AC_BK 1 -+#define AC_VI 2 -+#define AC_VO 3 -+#define AC_COUNT 4 -+ -+typedef uint8 ac_bitmap_t; -+ -+#define AC_BITMAP_NONE 0x0 -+#define AC_BITMAP_ALL 0xf -+#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) -+#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) -+#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) -+ -+ -+BWL_PRE_PACKED_STRUCT struct wme_ie { -+ uint8 oui[3]; -+ uint8 type; -+ uint8 subtype; -+ uint8 version; -+ uint8 qosinfo; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wme_ie wme_ie_t; -+#define WME_IE_LEN 7 -+ -+BWL_PRE_PACKED_STRUCT struct edcf_acparam { -+ uint8 ACI; -+ uint8 ECW; -+ uint16 TXOP; -+} BWL_POST_PACKED_STRUCT; -+typedef struct edcf_acparam edcf_acparam_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wme_param_ie { -+ uint8 oui[3]; -+ uint8 type; -+ uint8 subtype; -+ uint8 version; -+ uint8 qosinfo; -+ uint8 rsvd; -+ edcf_acparam_t acparam[AC_COUNT]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wme_param_ie wme_param_ie_t; -+#define WME_PARAM_IE_LEN 24 -+ -+ -+#define WME_QI_AP_APSD_MASK 0x80 -+#define WME_QI_AP_APSD_SHIFT 7 -+#define WME_QI_AP_COUNT_MASK 0x0f -+#define WME_QI_AP_COUNT_SHIFT 0 -+ -+ -+#define WME_QI_STA_MAXSPLEN_MASK 0x60 -+#define WME_QI_STA_MAXSPLEN_SHIFT 5 -+#define WME_QI_STA_APSD_ALL_MASK 0xf -+#define WME_QI_STA_APSD_ALL_SHIFT 0 -+#define WME_QI_STA_APSD_BE_MASK 0x8 -+#define WME_QI_STA_APSD_BE_SHIFT 3 -+#define WME_QI_STA_APSD_BK_MASK 0x4 -+#define WME_QI_STA_APSD_BK_SHIFT 2 -+#define WME_QI_STA_APSD_VI_MASK 0x2 -+#define WME_QI_STA_APSD_VI_SHIFT 1 -+#define WME_QI_STA_APSD_VO_MASK 0x1 -+#define WME_QI_STA_APSD_VO_SHIFT 0 -+ -+ -+#define EDCF_AIFSN_MIN 1 -+#define EDCF_AIFSN_MAX 15 -+#define EDCF_AIFSN_MASK 0x0f -+#define EDCF_ACM_MASK 0x10 -+#define EDCF_ACI_MASK 0x60 -+#define EDCF_ACI_SHIFT 5 -+#define EDCF_AIFSN_SHIFT 12 -+ -+ -+#define EDCF_ECW_MIN 0 -+#define EDCF_ECW_MAX 15 -+#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) -+#define EDCF_ECWMIN_MASK 0x0f -+#define EDCF_ECWMAX_MASK 0xf0 -+#define EDCF_ECWMAX_SHIFT 4 -+ -+ -+#define EDCF_TXOP_MIN 0 -+#define EDCF_TXOP_MAX 65535 -+#define EDCF_TXOP2USEC(txop) ((txop) << 5) -+ -+ -+#define NON_EDCF_AC_BE_ACI_STA 0x02 -+ -+ -+#define EDCF_AC_BE_ACI_STA 0x03 -+#define EDCF_AC_BE_ECW_STA 0xA4 -+#define EDCF_AC_BE_TXOP_STA 0x0000 -+#define EDCF_AC_BK_ACI_STA 0x27 -+#define EDCF_AC_BK_ECW_STA 0xA4 -+#define EDCF_AC_BK_TXOP_STA 0x0000 -+#define EDCF_AC_VI_ACI_STA 0x42 -+#define EDCF_AC_VI_ECW_STA 0x43 -+#define EDCF_AC_VI_TXOP_STA 0x005e -+#define EDCF_AC_VO_ACI_STA 0x62 -+#define EDCF_AC_VO_ECW_STA 0x32 -+#define EDCF_AC_VO_TXOP_STA 0x002f -+ -+ -+#define EDCF_AC_BE_ACI_AP 0x03 -+#define EDCF_AC_BE_ECW_AP 0x64 -+#define EDCF_AC_BE_TXOP_AP 0x0000 -+#define EDCF_AC_BK_ACI_AP 0x27 -+#define EDCF_AC_BK_ECW_AP 0xA4 -+#define EDCF_AC_BK_TXOP_AP 0x0000 -+#define EDCF_AC_VI_ACI_AP 0x41 -+#define EDCF_AC_VI_ECW_AP 0x43 -+#define EDCF_AC_VI_TXOP_AP 0x005e -+#define EDCF_AC_VO_ACI_AP 0x61 -+#define EDCF_AC_VO_ECW_AP 0x32 -+#define EDCF_AC_VO_TXOP_AP 0x002f -+ -+ -+BWL_PRE_PACKED_STRUCT struct edca_param_ie { -+ uint8 qosinfo; -+ uint8 rsvd; -+ edcf_acparam_t acparam[AC_COUNT]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct edca_param_ie edca_param_ie_t; -+#define EDCA_PARAM_IE_LEN 18 -+ -+ -+BWL_PRE_PACKED_STRUCT struct qos_cap_ie { -+ uint8 qosinfo; -+} BWL_POST_PACKED_STRUCT; -+typedef struct qos_cap_ie qos_cap_ie_t; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { -+ uint8 id; -+ uint8 length; -+ uint16 station_count; -+ uint8 channel_utilization; -+ uint16 aac; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; -+#define BSS_LOAD_IE_SIZE 7 -+ -+ -+#define FIXED_MSDU_SIZE 0x8000 -+#define MSDU_SIZE_MASK 0x7fff -+ -+ -+ -+#define INTEGER_SHIFT 13 -+#define FRACTION_MASK 0x1FFF -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_management_notification { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint8 status; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+#define DOT11_MGMT_NOTIFICATION_LEN 4 -+ -+ -+BWL_PRE_PACKED_STRUCT struct ti_ie { -+ uint8 ti_type; -+ uint32 ti_val; -+} BWL_POST_PACKED_STRUCT; -+typedef struct ti_ie ti_ie_t; -+#define TI_TYPE_REASSOC_DEADLINE 1 -+#define TI_TYPE_KEY_LIFETIME 2 -+ -+ -+#define WME_ADDTS_REQUEST 0 -+#define WME_ADDTS_RESPONSE 1 -+#define WME_DELTS_REQUEST 2 -+ -+ -+#define WME_ADMISSION_ACCEPTED 0 -+#define WME_INVALID_PARAMETERS 1 -+#define WME_ADMISSION_REFUSED 3 -+ -+ -+#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) -+ -+ -+#define DOT11_OPEN_SYSTEM 0 -+#define DOT11_SHARED_KEY 1 -+#define DOT11_FAST_BSS 2 -+#define DOT11_CHALLENGE_LEN 128 -+ -+ -+#define FC_PVER_MASK 0x3 -+#define FC_PVER_SHIFT 0 -+#define FC_TYPE_MASK 0xC -+#define FC_TYPE_SHIFT 2 -+#define FC_SUBTYPE_MASK 0xF0 -+#define FC_SUBTYPE_SHIFT 4 -+#define FC_TODS 0x100 -+#define FC_TODS_SHIFT 8 -+#define FC_FROMDS 0x200 -+#define FC_FROMDS_SHIFT 9 -+#define FC_MOREFRAG 0x400 -+#define FC_MOREFRAG_SHIFT 10 -+#define FC_RETRY 0x800 -+#define FC_RETRY_SHIFT 11 -+#define FC_PM 0x1000 -+#define FC_PM_SHIFT 12 -+#define FC_MOREDATA 0x2000 -+#define FC_MOREDATA_SHIFT 13 -+#define FC_WEP 0x4000 -+#define FC_WEP_SHIFT 14 -+#define FC_ORDER 0x8000 -+#define FC_ORDER_SHIFT 15 -+ -+ -+#define SEQNUM_SHIFT 4 -+#define SEQNUM_MAX 0x1000 -+#define FRAGNUM_MASK 0xF -+ -+ -+ -+ -+#define FC_TYPE_MNG 0 -+#define FC_TYPE_CTL 1 -+#define FC_TYPE_DATA 2 -+ -+ -+#define FC_SUBTYPE_ASSOC_REQ 0 -+#define FC_SUBTYPE_ASSOC_RESP 1 -+#define FC_SUBTYPE_REASSOC_REQ 2 -+#define FC_SUBTYPE_REASSOC_RESP 3 -+#define FC_SUBTYPE_PROBE_REQ 4 -+#define FC_SUBTYPE_PROBE_RESP 5 -+#define FC_SUBTYPE_BEACON 8 -+#define FC_SUBTYPE_ATIM 9 -+#define FC_SUBTYPE_DISASSOC 10 -+#define FC_SUBTYPE_AUTH 11 -+#define FC_SUBTYPE_DEAUTH 12 -+#define FC_SUBTYPE_ACTION 13 -+#define FC_SUBTYPE_ACTION_NOACK 14 -+ -+ -+#define FC_SUBTYPE_CTL_WRAPPER 7 -+#define FC_SUBTYPE_BLOCKACK_REQ 8 -+#define FC_SUBTYPE_BLOCKACK 9 -+#define FC_SUBTYPE_PS_POLL 10 -+#define FC_SUBTYPE_RTS 11 -+#define FC_SUBTYPE_CTS 12 -+#define FC_SUBTYPE_ACK 13 -+#define FC_SUBTYPE_CF_END 14 -+#define FC_SUBTYPE_CF_END_ACK 15 -+ -+ -+#define FC_SUBTYPE_DATA 0 -+#define FC_SUBTYPE_DATA_CF_ACK 1 -+#define FC_SUBTYPE_DATA_CF_POLL 2 -+#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 -+#define FC_SUBTYPE_NULL 4 -+#define FC_SUBTYPE_CF_ACK 5 -+#define FC_SUBTYPE_CF_POLL 6 -+#define FC_SUBTYPE_CF_ACK_POLL 7 -+#define FC_SUBTYPE_QOS_DATA 8 -+#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 -+#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 -+#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 -+#define FC_SUBTYPE_QOS_NULL 12 -+#define FC_SUBTYPE_QOS_CF_POLL 14 -+#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 -+ -+ -+#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) -+#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) -+#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) -+#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) -+ -+ -+#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) -+ -+#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) -+ -+#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) -+#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) -+ -+#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) -+#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) -+#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) -+#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) -+#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) -+#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) -+#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) -+#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) -+#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) -+#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) -+#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) -+#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) -+ -+#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) -+#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) -+#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) -+#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) -+#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) -+#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) -+#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) -+#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) -+#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) -+ -+#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) -+#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) -+#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) -+#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) -+#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) -+ -+ -+ -+ -+#define QOS_PRIO_SHIFT 0 -+#define QOS_PRIO_MASK 0x0007 -+#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) -+ -+ -+#define QOS_TID_SHIFT 0 -+#define QOS_TID_MASK 0x000f -+#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) -+ -+ -+#define QOS_EOSP_SHIFT 4 -+#define QOS_EOSP_MASK 0x0010 -+#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) -+ -+ -+#define QOS_ACK_NORMAL_ACK 0 -+#define QOS_ACK_NO_ACK 1 -+#define QOS_ACK_NO_EXP_ACK 2 -+#define QOS_ACK_BLOCK_ACK 3 -+#define QOS_ACK_SHIFT 5 -+#define QOS_ACK_MASK 0x0060 -+#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) -+ -+ -+#define QOS_AMSDU_SHIFT 7 -+#define QOS_AMSDU_MASK 0x0080 -+ -+ -+ -+ -+ -+ -+#define DOT11_MNG_AUTH_ALGO_LEN 2 -+#define DOT11_MNG_AUTH_SEQ_LEN 2 -+#define DOT11_MNG_BEACON_INT_LEN 2 -+#define DOT11_MNG_CAP_LEN 2 -+#define DOT11_MNG_AP_ADDR_LEN 6 -+#define DOT11_MNG_LISTEN_INT_LEN 2 -+#define DOT11_MNG_REASON_LEN 2 -+#define DOT11_MNG_AID_LEN 2 -+#define DOT11_MNG_STATUS_LEN 2 -+#define DOT11_MNG_TIMESTAMP_LEN 8 -+ -+ -+#define DOT11_AID_MASK 0x3fff -+ -+ -+#define DOT11_RC_RESERVED 0 -+#define DOT11_RC_UNSPECIFIED 1 -+#define DOT11_RC_AUTH_INVAL 2 -+#define DOT11_RC_DEAUTH_LEAVING 3 -+#define DOT11_RC_INACTIVITY 4 -+#define DOT11_RC_BUSY 5 -+#define DOT11_RC_INVAL_CLASS_2 6 -+#define DOT11_RC_INVAL_CLASS_3 7 -+#define DOT11_RC_DISASSOC_LEAVING 8 -+#define DOT11_RC_NOT_AUTH 9 -+#define DOT11_RC_BAD_PC 10 -+#define DOT11_RC_BAD_CHANNELS 11 -+ -+ -+ -+#define DOT11_RC_UNSPECIFIED_QOS 32 -+#define DOT11_RC_INSUFFCIENT_BW 33 -+#define DOT11_RC_EXCESSIVE_FRAMES 34 -+#define DOT11_RC_TX_OUTSIDE_TXOP 35 -+#define DOT11_RC_LEAVING_QBSS 36 -+#define DOT11_RC_BAD_MECHANISM 37 -+#define DOT11_RC_SETUP_NEEDED 38 -+#define DOT11_RC_TIMEOUT 39 -+ -+#define DOT11_RC_MAX 23 -+ -+#define DOT11_RC_TDLS_PEER_UNREACH 25 -+#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 -+ -+ -+#define DOT11_SC_SUCCESS 0 -+#define DOT11_SC_FAILURE 1 -+#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 -+ -+#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 -+#define DOT11_SC_TDLS_SEC_DISABLED 5 -+#define DOT11_SC_LIFETIME_REJ 6 -+#define DOT11_SC_NOT_SAME_BSS 7 -+#define DOT11_SC_CAP_MISMATCH 10 -+#define DOT11_SC_REASSOC_FAIL 11 -+#define DOT11_SC_ASSOC_FAIL 12 -+#define DOT11_SC_AUTH_MISMATCH 13 -+#define DOT11_SC_AUTH_SEQ 14 -+#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 -+#define DOT11_SC_AUTH_TIMEOUT 16 -+#define DOT11_SC_ASSOC_BUSY_FAIL 17 -+#define DOT11_SC_ASSOC_RATE_MISMATCH 18 -+#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 -+#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 -+#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 -+#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 -+#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 -+#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 -+#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 -+#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 -+#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 -+#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 -+#define DOT11_SC_ASSOC_TRY_LATER 30 -+#define DOT11_SC_ASSOC_MFP_VIOLATION 31 -+ -+#define DOT11_SC_DECLINED 37 -+#define DOT11_SC_INVALID_PARAMS 38 -+#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 -+#define DOT11_SC_INVALID_AKMP 43 -+#define DOT11_SC_INVALID_RSNIE_CAP 45 -+#define DOT11_SC_DLS_NOT_ALLOWED 48 -+#define DOT11_SC_INVALID_PMKID 53 -+#define DOT11_SC_INVALID_MDID 54 -+#define DOT11_SC_INVALID_FTIE 55 -+ -+#define DOT11_SC_UNEXP_MSG 70 -+#define DOT11_SC_INVALID_SNONCE 71 -+#define DOT11_SC_INVALID_RSNIE 72 -+ -+ -+#define DOT11_MNG_DS_PARAM_LEN 1 -+#define DOT11_MNG_IBSS_PARAM_LEN 2 -+ -+ -+#define DOT11_MNG_TIM_FIXED_LEN 3 -+#define DOT11_MNG_TIM_DTIM_COUNT 0 -+#define DOT11_MNG_TIM_DTIM_PERIOD 1 -+#define DOT11_MNG_TIM_BITMAP_CTL 2 -+#define DOT11_MNG_TIM_PVB 3 -+ -+ -+#define TLV_TAG_OFF 0 -+#define TLV_LEN_OFF 1 -+#define TLV_HDR_LEN 2 -+#define TLV_BODY_OFF 2 -+ -+ -+#define DOT11_MNG_SSID_ID 0 -+#define DOT11_MNG_RATES_ID 1 -+#define DOT11_MNG_FH_PARMS_ID 2 -+#define DOT11_MNG_DS_PARMS_ID 3 -+#define DOT11_MNG_CF_PARMS_ID 4 -+#define DOT11_MNG_TIM_ID 5 -+#define DOT11_MNG_IBSS_PARMS_ID 6 -+#define DOT11_MNG_COUNTRY_ID 7 -+#define DOT11_MNG_HOPPING_PARMS_ID 8 -+#define DOT11_MNG_HOPPING_TABLE_ID 9 -+#define DOT11_MNG_REQUEST_ID 10 -+#define DOT11_MNG_QBSS_LOAD_ID 11 -+#define DOT11_MNG_EDCA_PARAM_ID 12 -+#define DOT11_MNG_CHALLENGE_ID 16 -+#define DOT11_MNG_PWR_CONSTRAINT_ID 32 -+#define DOT11_MNG_PWR_CAP_ID 33 -+#define DOT11_MNG_TPC_REQUEST_ID 34 -+#define DOT11_MNG_TPC_REPORT_ID 35 -+#define DOT11_MNG_SUPP_CHANNELS_ID 36 -+#define DOT11_MNG_CHANNEL_SWITCH_ID 37 -+#define DOT11_MNG_MEASURE_REQUEST_ID 38 -+#define DOT11_MNG_MEASURE_REPORT_ID 39 -+#define DOT11_MNG_QUIET_ID 40 -+#define DOT11_MNG_IBSS_DFS_ID 41 -+#define DOT11_MNG_ERP_ID 42 -+#define DOT11_MNG_TS_DELAY_ID 43 -+#define DOT11_MNG_HT_CAP 45 -+#define DOT11_MNG_QOS_CAP_ID 46 -+#define DOT11_MNG_NONERP_ID 47 -+#define DOT11_MNG_RSN_ID 48 -+#define DOT11_MNG_EXT_RATES_ID 50 -+#define DOT11_MNG_AP_CHREP_ID 51 -+#define DOT11_MNG_NBR_REP_ID 52 -+#define DOT11_MNG_MDIE_ID 54 -+#define DOT11_MNG_FTIE_ID 55 -+#define DOT11_MNG_FT_TI_ID 56 -+#define DOT11_MNG_REGCLASS_ID 59 -+#define DOT11_MNG_EXT_CSA_ID 60 -+#define DOT11_MNG_HT_ADD 61 -+#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 -+#define DOT11_MNG_WAPI_ID 68 -+#define DOT11_MNG_TIME_ADVERTISE_ID 69 -+#define DOT11_MNG_RRM_CAP_ID 70 -+#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 -+#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 -+#define DOT11_MNG_HT_OBSS_ID 74 -+#define DOT11_MNG_CHANNEL_USAGE 97 -+#define DOT11_MNG_TIME_ZONE_ID 98 -+#define DOT11_MNG_LINK_IDENTIFIER_ID 101 -+#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 -+#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 -+#define DOT11_MNG_PTI_CONTROL_ID 105 -+#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 -+#define DOT11_MNG_INTERWORKING_ID 107 -+#define DOT11_MNG_ADVERTISEMENT_ID 108 -+#define DOT11_MNG_EXP_BW_REQ_ID 109 -+#define DOT11_MNG_QOS_MAP_ID 110 -+#define DOT11_MNG_ROAM_CONSORT_ID 111 -+#define DOT11_MNG_EMERGCY_ALERT_ID 112 -+#define DOT11_MNG_EXT_CAP_ID 127 -+#define DOT11_MNG_VHT_CAP_ID 191 -+#define DOT11_MNG_VHT_OPERATION_ID 192 -+ -+#define DOT11_MNG_WPA_ID 221 -+#define DOT11_MNG_PROPR_ID 221 -+ -+#define DOT11_MNG_VS_ID 221 -+ -+ -+#define DOT11_RATE_BASIC 0x80 -+#define DOT11_RATE_MASK 0x7F -+ -+ -+#define DOT11_MNG_ERP_LEN 1 -+#define DOT11_MNG_NONERP_PRESENT 0x01 -+#define DOT11_MNG_USE_PROTECTION 0x02 -+#define DOT11_MNG_BARKER_PREAMBLE 0x04 -+ -+#define DOT11_MGN_TS_DELAY_LEN 4 -+#define TS_DELAY_FIELD_SIZE 4 -+ -+ -+#define DOT11_CAP_ESS 0x0001 -+#define DOT11_CAP_IBSS 0x0002 -+#define DOT11_CAP_POLLABLE 0x0004 -+#define DOT11_CAP_POLL_RQ 0x0008 -+#define DOT11_CAP_PRIVACY 0x0010 -+#define DOT11_CAP_SHORT 0x0020 -+#define DOT11_CAP_PBCC 0x0040 -+#define DOT11_CAP_AGILITY 0x0080 -+#define DOT11_CAP_SPECTRUM 0x0100 -+#define DOT11_CAP_SHORTSLOT 0x0400 -+#define DOT11_CAP_RRM 0x1000 -+#define DOT11_CAP_CCK_OFDM 0x2000 -+ -+ -+ -+#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 -+ -+#define DOT11_EXT_CAP_SPSMP 6 -+ -+#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT 19 -+ -+#define DOT11_EXT_CAP_IW 31 -+ -+#define DOT11_EXT_CAP_SI 41 -+#define DOT11_EXT_CAP_SI_MASK 0x0E -+ -+ -+#define DOT11_ACTION_HDR_LEN 2 -+#define DOT11_ACTION_CAT_OFF 0 -+#define DOT11_ACTION_ACT_OFF 1 -+ -+ -+#define DOT11_ACTION_CAT_ERR_MASK 0x80 -+#define DOT11_ACTION_CAT_MASK 0x7F -+#define DOT11_ACTION_CAT_SPECT_MNG 0 -+#define DOT11_ACTION_CAT_QOS 1 -+#define DOT11_ACTION_CAT_DLS 2 -+#define DOT11_ACTION_CAT_BLOCKACK 3 -+#define DOT11_ACTION_CAT_PUBLIC 4 -+#define DOT11_ACTION_CAT_RRM 5 -+#define DOT11_ACTION_CAT_FBT 6 -+#define DOT11_ACTION_CAT_HT 7 -+#define DOT11_ACTION_CAT_SA_QUERY 8 -+#define DOT11_ACTION_CAT_PDPA 9 -+#define DOT11_ACTION_CAT_BSSMGMT 10 -+#define DOT11_ACTION_NOTIFICATION 17 -+#define DOT11_ACTION_CAT_VSP 126 -+#define DOT11_ACTION_CAT_VS 127 -+ -+ -+#define DOT11_SM_ACTION_M_REQ 0 -+#define DOT11_SM_ACTION_M_REP 1 -+#define DOT11_SM_ACTION_TPC_REQ 2 -+#define DOT11_SM_ACTION_TPC_REP 3 -+#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 -+#define DOT11_SM_ACTION_EXT_CSA 5 -+ -+ -+#define DOT11_ACTION_ID_HT_CH_WIDTH 0 -+#define DOT11_ACTION_ID_HT_MIMO_PS 1 -+ -+ -+#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 -+#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 -+ -+ -+#define DOT11_BA_ACTION_ADDBA_REQ 0 -+#define DOT11_BA_ACTION_ADDBA_RESP 1 -+#define DOT11_BA_ACTION_DELBA 2 -+ -+ -+#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 -+#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 -+#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 -+#define DOT11_ADDBA_PARAM_TID_MASK 0x003c -+#define DOT11_ADDBA_PARAM_TID_SHIFT 2 -+#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 -+#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 -+ -+#define DOT11_ADDBA_POLICY_DELAYED 0 -+#define DOT11_ADDBA_POLICY_IMMEDIATE 1 -+ -+ -+#define DOT11_FT_ACTION_FT_RESERVED 0 -+#define DOT11_FT_ACTION_FT_REQ 1 -+#define DOT11_FT_ACTION_FT_RES 2 -+#define DOT11_FT_ACTION_FT_CON 3 -+#define DOT11_FT_ACTION_FT_ACK 4 -+ -+ -+#define DOT11_DLS_ACTION_REQ 0 -+#define DOT11_DLS_ACTION_RESP 1 -+#define DOT11_DLS_ACTION_TD 2 -+ -+ -+#define DOT11_WNM_ACTION_EVENT_REQ 0 -+#define DOT11_WNM_ACTION_EVENT_REP 1 -+#define DOT11_WNM_ACTION_DIAG_REQ 2 -+#define DOT11_WNM_ACTION_DIAG_REP 3 -+#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 -+#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 -+#define DOT11_WNM_ACTION_BSS_TRANS_QURY 6 -+#define DOT11_WNM_ACTION_BSS_TRANS_REQ 7 -+#define DOT11_WNM_ACTION_BSS_TRANS_RESP 8 -+#define DOT11_WNM_ACTION_FMS_REQ 9 -+#define DOT11_WNM_ACTION_FMS_RESP 10 -+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 -+#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 -+#define DOT11_WNM_ACTION_TFS_REQ 13 -+#define DOT11_WNM_ACTION_TFS_RESP 14 -+#define DOT11_WNM_ACTION_TFS_NOTIFY 15 -+#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 -+#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 -+#define DOT11_WNM_ACTION_TIM_BCAST_REQ 18 -+#define DOT11_WNM_ACTION_TIM_BCAST_RESP 19 -+#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 -+#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 -+#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 -+#define DOT11_WNM_ACTION_DMS_REQ 23 -+#define DOT11_WNM_ACTION_DMS_RESP 24 -+#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 -+#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 -+#define DOT11_WNM_ACTION_NOTFCTN_RES 27 -+ -+#define DOT11_MNG_COUNTRY_ID_LEN 3 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_dls_req { -+ uint8 category; -+ uint8 action; -+ struct ether_addr da; -+ struct ether_addr sa; -+ uint16 cap; -+ uint16 timeout; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_dls_req dot11_dls_req_t; -+#define DOT11_DLS_REQ_LEN 18 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { -+ uint8 category; -+ uint8 action; -+ uint16 status; -+ struct ether_addr da; -+ struct ether_addr sa; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_dls_resp dot11_dls_resp_t; -+#define DOT11_DLS_RESP_LEN 16 -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint8 reason; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_bss_trans_query dot11_bss_trans_query_t; -+#define DOT11_BSS_TRANS_QUERY_LEN 4 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint8 reqmode; -+ uint16 disassoc_tmr; -+ uint8 validity_intrvl; -+ uint8 data[1]; -+ -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_bss_trans_req dot11_bss_trans_req_t; -+#define DOT11_BSS_TRANS_REQ_LEN 7 -+ -+#define DOT11_BSS_TERM_DUR_LEN 12 -+ -+ -+ -+#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL 0x01 -+#define DOT11_BSS_TRNS_REQMODE_ABRIDGED 0x02 -+#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT 0x04 -+#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL 0x08 -+#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT 0x10 -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint8 status; -+ uint8 term_delay; -+ uint8 data[1]; -+ -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_bss_trans_res dot11_bss_trans_res_t; -+#define DOT11_BSS_TRANS_RES_LEN 5 -+ -+ -+#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT 0 -+#define DOT11_BSS_TRNS_RES_STATUS_REJECT 1 -+#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN 2 -+#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP 3 -+#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED 4 -+#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ 5 -+#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED 6 -+#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS 7 -+#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS 8 -+ -+ -+ -+#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY 0x0003 -+#define DOT11_NBR_RPRT_BSSID_INFO_SEC 0x0004 -+#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE 0x0008 -+#define DOT11_NBR_RPRT_BSSID_INFO_CAP 0x03f0 -+ -+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT 0x0010 -+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS 0x0020 -+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD 0x0040 -+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT 0x0080 -+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA 0x0100 -+#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA 0x0200 -+ -+ -+#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID 3 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_addba_req { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint16 addba_param_set; -+ uint16 timeout; -+ uint16 start_seqnum; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_addba_req dot11_addba_req_t; -+#define DOT11_ADDBA_REQ_LEN 9 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint16 status; -+ uint16 addba_param_set; -+ uint16 timeout; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_addba_resp dot11_addba_resp_t; -+#define DOT11_ADDBA_RESP_LEN 9 -+ -+ -+#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 -+#define DOT11_DELBA_PARAM_INIT_SHIFT 11 -+#define DOT11_DELBA_PARAM_TID_MASK 0xf000 -+#define DOT11_DELBA_PARAM_TID_SHIFT 12 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_delba { -+ uint8 category; -+ uint8 action; -+ uint16 delba_param_set; -+ uint16 reason; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_delba dot11_delba_t; -+#define DOT11_DELBA_LEN 6 -+ -+ -+#define SA_QUERY_REQUEST 0 -+#define SA_QUERY_RESPONSE 1 -+ -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ft_req { -+ uint8 category; -+ uint8 action; -+ uint8 sta_addr[ETHER_ADDR_LEN]; -+ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_ft_req dot11_ft_req_t; -+#define DOT11_FT_REQ_FIXED_LEN 14 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ft_res { -+ uint8 category; -+ uint8 action; -+ uint8 sta_addr[ETHER_ADDR_LEN]; -+ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; -+ uint16 status; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_ft_res dot11_ft_res_t; -+#define DOT11_FT_RES_FIXED_LEN 16 -+ -+ -+ -+ -+ -+ -+#define DOT11_RRM_CAP_LEN 5 -+BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { -+ uint8 cap[DOT11_RRM_CAP_LEN]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; -+ -+ -+#define DOT11_RRM_CAP_LINK 0 -+#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 -+#define DOT11_RRM_CAP_PARALLEL 2 -+#define DOT11_RRM_CAP_REPEATED 3 -+#define DOT11_RRM_CAP_BCN_PASSIVE 4 -+#define DOT11_RRM_CAP_BCN_ACTIVE 5 -+#define DOT11_RRM_CAP_BCN_TABLE 6 -+#define DOT11_RRM_CAP_BCN_REP_COND 7 -+#define DOT11_RRM_CAP_AP_CHANREP 16 -+ -+ -+ -+#define DOT11_OP_CLASS_NONE 255 -+ -+ -+ -+#define DOT11_RM_ACTION_RM_REQ 0 -+#define DOT11_RM_ACTION_RM_REP 1 -+#define DOT11_RM_ACTION_LM_REQ 2 -+#define DOT11_RM_ACTION_LM_REP 3 -+#define DOT11_RM_ACTION_NR_REQ 4 -+#define DOT11_RM_ACTION_NR_REP 5 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_rm_action { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_rm_action dot11_rm_action_t; -+#define DOT11_RM_ACTION_LEN 3 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_rmreq { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint16 reps; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_rmreq dot11_rmreq_t; -+#define DOT11_RMREQ_LEN 5 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { -+ uint8 id; -+ uint8 len; -+ uint8 token; -+ uint8 mode; -+ uint8 type; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_rm_ie dot11_rm_ie_t; -+#define DOT11_RM_IE_LEN 5 -+ -+ -+#define DOT11_RMREQ_MODE_PARALLEL 1 -+#define DOT11_RMREQ_MODE_ENABLE 2 -+#define DOT11_RMREQ_MODE_REQUEST 4 -+#define DOT11_RMREQ_MODE_REPORT 8 -+#define DOT11_RMREQ_MODE_DURMAND 0x10 -+ -+ -+#define DOT11_RMREP_MODE_LATE 1 -+#define DOT11_RMREP_MODE_INCAPABLE 2 -+#define DOT11_RMREP_MODE_REFUSED 4 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { -+ uint8 id; -+ uint8 len; -+ uint8 token; -+ uint8 mode; -+ uint8 type; -+ uint8 reg; -+ uint8 channel; -+ uint16 interval; -+ uint16 duration; -+ uint8 bcn_mode; -+ struct ether_addr bssid; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; -+#define DOT11_RMREQ_BCN_LEN 18 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { -+ uint8 reg; -+ uint8 channel; -+ uint32 starttime[2]; -+ uint16 duration; -+ uint8 frame_info; -+ uint8 rcpi; -+ uint8 rsni; -+ struct ether_addr bssid; -+ uint8 antenna_id; -+ uint32 parent_tsf; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; -+#define DOT11_RMREP_BCN_LEN 26 -+ -+ -+#define DOT11_RMREQ_BCN_PASSIVE 0 -+#define DOT11_RMREQ_BCN_ACTIVE 1 -+#define DOT11_RMREQ_BCN_TABLE 2 -+ -+ -+#define DOT11_RMREQ_BCN_SSID_ID 0 -+#define DOT11_RMREQ_BCN_REPINFO_ID 1 -+#define DOT11_RMREQ_BCN_REPDET_ID 2 -+#define DOT11_RMREQ_BCN_REQUEST_ID 10 -+#define DOT11_RMREQ_BCN_APCHREP_ID 51 -+ -+ -+#define DOT11_RMREQ_BCN_REPDET_FIXED 0 -+#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 -+#define DOT11_RMREQ_BCN_REPDET_ALL 2 -+ -+ -+#define DOT11_RMREP_BCN_FRM_BODY 1 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr { -+ struct ether_addr bssid; -+ uint32 bssid_info; -+ uint8 reg; -+ uint8 channel; -+ uint8 phytype; -+ uchar sub_elements[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t; -+#define DOT11_RMREP_NBR_LEN 13 -+ -+ -+#define DOT11_BSSTYPE_INFRASTRUCTURE 0 -+#define DOT11_BSSTYPE_INDEPENDENT 1 -+#define DOT11_BSSTYPE_ANY 2 -+#define DOT11_SCANTYPE_ACTIVE 0 -+#define DOT11_SCANTYPE_PASSIVE 1 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_lmreq { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ uint8 txpwr; -+ uint8 maxtxpwr; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_lmreq dot11_lmreq_t; -+#define DOT11_LMREQ_LEN 5 -+ -+BWL_PRE_PACKED_STRUCT struct dot11_lmrep { -+ uint8 category; -+ uint8 action; -+ uint8 token; -+ dot11_tpc_rep_t tpc; -+ uint8 rxant; -+ uint8 txant; -+ uint8 rcpi; -+ uint8 rsni; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_lmrep dot11_lmrep_t; -+#define DOT11_LMREP_LEN 11 -+ -+ -+#define PREN_PREAMBLE 24 -+#define PREN_MM_EXT 12 -+#define PREN_PREAMBLE_EXT 4 -+ -+ -+#define RIFS_11N_TIME 2 -+ -+ -+ -+#define HT_SIG1_MCS_MASK 0x00007F -+#define HT_SIG1_CBW 0x000080 -+#define HT_SIG1_HT_LENGTH 0xFFFF00 -+ -+ -+#define HT_SIG2_SMOOTHING 0x000001 -+#define HT_SIG2_NOT_SOUNDING 0x000002 -+#define HT_SIG2_RESERVED 0x000004 -+#define HT_SIG2_AGGREGATION 0x000008 -+#define HT_SIG2_STBC_MASK 0x000030 -+#define HT_SIG2_STBC_SHIFT 4 -+#define HT_SIG2_FEC_CODING 0x000040 -+#define HT_SIG2_SHORT_GI 0x000080 -+#define HT_SIG2_ESS_MASK 0x000300 -+#define HT_SIG2_ESS_SHIFT 8 -+#define HT_SIG2_CRC 0x03FC00 -+#define HT_SIG2_TAIL 0x1C0000 -+ -+ -+#define APHY_SLOT_TIME 9 -+#define APHY_SIFS_TIME 16 -+#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) -+#define APHY_PREAMBLE_TIME 16 -+#define APHY_SIGNAL_TIME 4 -+#define APHY_SYMBOL_TIME 4 -+#define APHY_SERVICE_NBITS 16 -+#define APHY_TAIL_NBITS 6 -+#define APHY_CWMIN 15 -+ -+ -+#define BPHY_SLOT_TIME 20 -+#define BPHY_SIFS_TIME 10 -+#define BPHY_DIFS_TIME 50 -+#define BPHY_PLCP_TIME 192 -+#define BPHY_PLCP_SHORT_TIME 96 -+#define BPHY_CWMIN 31 -+ -+ -+#define DOT11_OFDM_SIGNAL_EXTENSION 6 -+ -+#define PHY_CWMAX 1023 -+ -+#define DOT11_MAXNUMFRAGS 16 -+ -+ -+ -+typedef int vht_group_id_t; -+ -+ -+ -+#define VHT_SIGA1_CONST_MASK 0x800004 -+ -+#define VHT_SIGA1_20MHZ_VAL 0x000000 -+#define VHT_SIGA1_40MHZ_VAL 0x000001 -+#define VHT_SIGA1_80MHZ_VAL 0x000002 -+#define VHT_SIGA1_160MHZ_VAL 0x000003 -+ -+#define VHT_SIGA1_STBC 0x000008 -+ -+#define VHT_SIGA1_GID_MAX_GID 0x3f -+#define VHT_SIGA1_GID_SHIFT 4 -+#define VHT_SIGA1_GID_TO_AP 0x00 -+#define VHT_SIGA1_GID_NOT_TO_AP 0x3f -+ -+#define VHT_SIGA1_NSTS_SHIFT 10 -+#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 -+ -+#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 -+ -+ -+#define VHT_SIGA2_GI_NONE 0x000000 -+#define VHT_SIGA2_GI_SHORT 0x000001 -+#define VHT_SIGA2_GI_W_MOD10 0x000002 -+#define VHT_SIGA2_CODING_LDPC 0x000004 -+#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 -+#define VHT_SIGA2_MCS_SHIFT 4 -+ -+#define VHT_SIGA2_B9_RESERVED 0x000200 -+#define VHT_SIGA2_TAIL_MASK 0xfc0000 -+#define VHT_SIGA2_TAIL_VALUE 0x000000 -+ -+#define VHT_SIGA2_SVC_BITS 16 -+#define VHT_SIGA2_TAIL_BITS 6 -+ -+ -+ -+typedef struct d11cnt { -+ uint32 txfrag; -+ uint32 txmulti; -+ uint32 txfail; -+ uint32 txretry; -+ uint32 txretrie; -+ uint32 rxdup; -+ uint32 txrts; -+ uint32 txnocts; -+ uint32 txnoack; -+ uint32 rxfrag; -+ uint32 rxmulti; -+ uint32 rxcrc; -+ uint32 txfrmsnt; -+ uint32 rxundec; -+} d11cnt_t; -+ -+ -+#define BRCM_PROP_OUI "\x00\x90\x4C" -+ -+ -+ -+#define BRCM_OUI "\x00\x10\x18" -+ -+ -+BWL_PRE_PACKED_STRUCT struct brcm_ie { -+ uint8 id; -+ uint8 len; -+ uint8 oui[3]; -+ uint8 ver; -+ uint8 assoc; -+ uint8 flags; -+ uint8 flags1; -+ uint16 amsdu_mtu_pref; -+} BWL_POST_PACKED_STRUCT; -+typedef struct brcm_ie brcm_ie_t; -+#define BRCM_IE_LEN 11 -+#define BRCM_IE_VER 2 -+#define BRCM_IE_LEGACY_AES_VER 1 -+ -+ -+#define BRF_LZWDS 0x4 -+#define BRF_BLOCKACK 0x8 -+ -+ -+#define BRF1_AMSDU 0x1 -+#define BRF1_WMEPS 0x4 -+#define BRF1_PSOFIX 0x8 -+#define BRF1_RX_LARGE_AGG 0x10 -+#define BRF1_RFAWARE_DCS 0x20 -+#define BRF1_SOFTAP 0x40 -+ -+ -+BWL_PRE_PACKED_STRUCT struct vndr_ie { -+ uchar id; -+ uchar len; -+ uchar oui [3]; -+ uchar data [1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct vndr_ie vndr_ie_t; -+ -+#define VNDR_IE_HDR_LEN 2 -+#define VNDR_IE_MIN_LEN 3 -+#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) -+#define VNDR_IE_MAX_LEN 256 -+ -+ -+#define MCSSET_LEN 16 -+#define MAX_MCS_NUM (128) -+ -+BWL_PRE_PACKED_STRUCT struct ht_cap_ie { -+ uint16 cap; -+ uint8 params; -+ uint8 supp_mcs[MCSSET_LEN]; -+ uint16 ext_htcap; -+ uint32 txbf_cap; -+ uint8 as_cap; -+} BWL_POST_PACKED_STRUCT; -+typedef struct ht_cap_ie ht_cap_ie_t; -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { -+ uint8 id; -+ uint8 len; -+ uint8 oui[3]; -+ uint8 type; -+ ht_cap_ie_t cap_ie; -+} BWL_POST_PACKED_STRUCT; -+typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; -+ -+#define HT_PROP_IE_OVERHEAD 4 -+#define HT_CAP_IE_LEN 26 -+#define HT_CAP_IE_TYPE 51 -+ -+#define HT_CAP_LDPC_CODING 0x0001 -+#define HT_CAP_40MHZ 0x0002 -+#define HT_CAP_MIMO_PS_MASK 0x000C -+#define HT_CAP_MIMO_PS_SHIFT 0x0002 -+#define HT_CAP_MIMO_PS_OFF 0x0003 -+#define HT_CAP_MIMO_PS_RTS 0x0001 -+#define HT_CAP_MIMO_PS_ON 0x0000 -+#define HT_CAP_GF 0x0010 -+#define HT_CAP_SHORT_GI_20 0x0020 -+#define HT_CAP_SHORT_GI_40 0x0040 -+#define HT_CAP_TX_STBC 0x0080 -+#define HT_CAP_RX_STBC_MASK 0x0300 -+#define HT_CAP_RX_STBC_SHIFT 8 -+#define HT_CAP_DELAYED_BA 0x0400 -+#define HT_CAP_MAX_AMSDU 0x0800 -+ -+#define HT_CAP_DSSS_CCK 0x1000 -+#define HT_CAP_PSMP 0x2000 -+#define HT_CAP_40MHZ_INTOLERANT 0x4000 -+#define HT_CAP_LSIG_TXOP 0x8000 -+ -+#define HT_CAP_RX_STBC_NO 0x0 -+#define HT_CAP_RX_STBC_ONE_STREAM 0x1 -+#define HT_CAP_RX_STBC_TWO_STREAM 0x2 -+#define HT_CAP_RX_STBC_THREE_STREAM 0x3 -+ -+#define VHT_MAX_MPDU 11454 -+#define VHT_MPDU_MSDU_DELTA 56 -+ -+#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) -+ -+#define HT_MAX_AMSDU 7935 -+#define HT_MIN_AMSDU 3835 -+ -+#define HT_PARAMS_RX_FACTOR_MASK 0x03 -+#define HT_PARAMS_DENSITY_MASK 0x1C -+#define HT_PARAMS_DENSITY_SHIFT 2 -+ -+ -+#define AMPDU_MAX_MPDU_DENSITY 7 -+#define AMPDU_DENSITY_NONE 0 -+#define AMPDU_DENSITY_1over4_US 1 -+#define AMPDU_DENSITY_1over2_US 2 -+#define AMPDU_DENSITY_1_US 3 -+#define AMPDU_DENSITY_2_US 4 -+#define AMPDU_DENSITY_4_US 5 -+#define AMPDU_DENSITY_8_US 6 -+#define AMPDU_DENSITY_16_US 7 -+#define AMPDU_RX_FACTOR_8K 0 -+#define AMPDU_RX_FACTOR_16K 1 -+#define AMPDU_RX_FACTOR_32K 2 -+#define AMPDU_RX_FACTOR_64K 3 -+#define AMPDU_RX_FACTOR_BASE 8*1024 -+ -+#define AMPDU_DELIMITER_LEN 4 -+#define AMPDU_DELIMITER_LEN_MAX 63 -+ -+#define HT_CAP_EXT_PCO 0x0001 -+#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 -+#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 -+#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 -+#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 -+#define HT_CAP_EXT_HTC 0x0400 -+#define HT_CAP_EXT_RD_RESP 0x0800 -+ -+BWL_PRE_PACKED_STRUCT struct ht_add_ie { -+ uint8 ctl_ch; -+ uint8 byte1; -+ uint16 opmode; -+ uint16 misc_bits; -+ uint8 basic_mcs[MCSSET_LEN]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct ht_add_ie ht_add_ie_t; -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { -+ uint8 id; -+ uint8 len; -+ uint8 oui[3]; -+ uint8 type; -+ ht_add_ie_t add_ie; -+} BWL_POST_PACKED_STRUCT; -+typedef struct ht_prop_add_ie ht_prop_add_ie_t; -+ -+#define HT_ADD_IE_LEN 22 -+#define HT_ADD_IE_TYPE 52 -+ -+ -+#define HT_BW_ANY 0x04 -+#define HT_RIFS_PERMITTED 0x08 -+ -+ -+#define HT_OPMODE_MASK 0x0003 -+#define HT_OPMODE_SHIFT 0 -+#define HT_OPMODE_PURE 0x0000 -+#define HT_OPMODE_OPTIONAL 0x0001 -+#define HT_OPMODE_HT20IN40 0x0002 -+#define HT_OPMODE_MIXED 0x0003 -+#define HT_OPMODE_NONGF 0x0004 -+#define DOT11N_TXBURST 0x0008 -+#define DOT11N_OBSS_NONHT 0x0010 -+ -+ -+#define HT_BASIC_STBC_MCS 0x007f -+#define HT_DUAL_STBC_PROT 0x0080 -+#define HT_SECOND_BCN 0x0100 -+#define HT_LSIG_TXOP 0x0200 -+#define HT_PCO_ACTIVE 0x0400 -+#define HT_PCO_PHASE 0x0800 -+#define HT_DUALCTS_PROTECTION 0x0080 -+ -+ -+#define DOT11N_2G_TXBURST_LIMIT 6160 -+#define DOT11N_5G_TXBURST_LIMIT 3080 -+ -+ -+#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ -+ >> HT_OPMODE_SHIFT) -+#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ -+ == HT_OPMODE_MIXED) -+#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ -+ == HT_OPMODE_HT20IN40) -+#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ -+ == HT_OPMODE_OPTIONAL) -+#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ -+ HT_MIXEDMODE_PRESENT((add_ie))) -+#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ -+ == HT_OPMODE_NONGF) -+#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ -+ == DOT11N_TXBURST) -+#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ -+ == DOT11N_OBSS_NONHT) -+ -+BWL_PRE_PACKED_STRUCT struct obss_params { -+ uint16 passive_dwell; -+ uint16 active_dwell; -+ uint16 bss_widthscan_interval; -+ uint16 passive_total; -+ uint16 active_total; -+ uint16 chanwidth_transition_dly; -+ uint16 activity_threshold; -+} BWL_POST_PACKED_STRUCT; -+typedef struct obss_params obss_params_t; -+ -+BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { -+ uint8 id; -+ uint8 len; -+ obss_params_t obss_params; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_obss_ie dot11_obss_ie_t; -+#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) -+ -+ -+#define HT_CTRL_LA_TRQ 0x00000002 -+#define HT_CTRL_LA_MAI 0x0000003C -+#define HT_CTRL_LA_MAI_SHIFT 2 -+#define HT_CTRL_LA_MAI_MRQ 0x00000004 -+#define HT_CTRL_LA_MAI_MSI 0x00000038 -+#define HT_CTRL_LA_MFSI 0x000001C0 -+#define HT_CTRL_LA_MFSI_SHIFT 6 -+#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 -+#define HT_CTRL_LA_MFB_ASELC_SH 9 -+#define HT_CTRL_LA_ASELC_CMD 0x00000C00 -+#define HT_CTRL_LA_ASELC_DATA 0x0000F000 -+#define HT_CTRL_CAL_POS 0x00030000 -+#define HT_CTRL_CAL_SEQ 0x000C0000 -+#define HT_CTRL_CSI_STEERING 0x00C00000 -+#define HT_CTRL_CSI_STEER_SHIFT 22 -+#define HT_CTRL_CSI_STEER_NFB 0 -+#define HT_CTRL_CSI_STEER_CSI 1 -+#define HT_CTRL_CSI_STEER_NCOM 2 -+#define HT_CTRL_CSI_STEER_COM 3 -+#define HT_CTRL_NDP_ANNOUNCE 0x01000000 -+#define HT_CTRL_AC_CONSTRAINT 0x40000000 -+#define HT_CTRL_RDG_MOREPPDU 0x80000000 -+ -+#define HT_OPMODE_OPTIONAL 0x0001 -+#define HT_OPMODE_HT20IN40 0x0002 -+#define HT_OPMODE_MIXED 0x0003 -+#define HT_OPMODE_NONGF 0x0004 -+#define DOT11N_TXBURST 0x0008 -+#define DOT11N_OBSS_NONHT 0x0010 -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct vht_cap_ie { -+ uint32 vht_cap_info; -+ -+ uint16 rx_mcs_map; -+ uint16 rx_max_rate; -+ uint16 tx_mcs_map; -+ uint16 tx_max_rate; -+} BWL_POST_PACKED_STRUCT; -+typedef struct vht_cap_ie vht_cap_ie_t; -+ -+#define VHT_CAP_IE_LEN 12 -+ -+#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 -+#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c -+#define VHT_CAP_INFO_LDPC 0x00000010 -+#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 -+ -+#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 -+#define VHT_CAP_INFO_TX_STBC 0x00000080 -+ -+#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 -+#define VHT_CAP_INFO_RX_STBC_SHIFT 8 -+#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 -+#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 -+#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 -+#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 -+ -+#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 -+#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 -+#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 -+#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 -+#define VHT_CAP_INFO_TXOPPS 0x00200000 -+#define VHT_CAP_INFO_HTCVHT 0x00400000 -+#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 -+#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 -+ -+#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 -+#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 -+ -+ -+#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff -+#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 -+ -+#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff -+#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 -+ -+#define VHT_CAP_MCS_MAP_0_7 0 -+#define VHT_CAP_MCS_MAP_0_8 1 -+#define VHT_CAP_MCS_MAP_0_9 2 -+#define VHT_CAP_MCS_MAP_NONE 3 -+ -+#define VHT_CAP_MCS_MAP_NSS_MAX 8 -+ -+ -+typedef enum vht_cap_chan_width { -+ VHT_CAP_CHAN_WIDTH_20_40 = 0x00, -+ VHT_CAP_CHAN_WIDTH_80 = 0x04, -+ VHT_CAP_CHAN_WIDTH_160 = 0x08 -+} vht_cap_chan_width_t; -+ -+ -+typedef enum vht_cap_max_mpdu_len { -+ VHT_CAP_MPDU_MAX_4K = 0x00, -+ VHT_CAP_MPDU_MAX_8K = 0x01, -+ VHT_CAP_MPDU_MAX_11K = 0x02 -+} vht_cap_max_mpdu_len_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct vht_op_ie { -+ uint8 chan_width; -+ uint8 chan1; -+ uint8 chan2; -+ uint16 supp_mcs; -+} BWL_POST_PACKED_STRUCT; -+typedef struct vht_op_ie vht_op_ie_t; -+ -+#define VHT_OP_IE_LEN 5 -+ -+typedef enum vht_op_chan_width { -+ VHT_OP_CHAN_WIDTH_20_40 = 0, -+ VHT_OP_CHAN_WIDTH_80 = 1, -+ VHT_OP_CHAN_WIDTH_160 = 2, -+ VHT_OP_CHAN_WIDTH_80_80 = 3 -+} vht_op_chan_width_t; -+ -+ -+#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1)*2) -+#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ -+ (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & 0x3) -+#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ -+ ((mcsMap) |= (((numMcs) & 0x3) << VHT_MCS_MAP_GET_SS_IDX(nss))) -+ -+ -+#define WPA_OUI "\x00\x50\xF2" -+#define WPA_OUI_LEN 3 -+#define WPA_OUI_TYPE 1 -+#define WPA_VERSION 1 -+#define WPA2_OUI "\x00\x0F\xAC" -+#define WPA2_OUI_LEN 3 -+#define WPA2_VERSION 1 -+#define WPA2_VERSION_LEN 2 -+ -+ -+#define WPS_OUI "\x00\x50\xF2" -+#define WPS_OUI_LEN 3 -+#define WPS_OUI_TYPE 4 -+ -+ -+ -+#ifdef P2P_IE_OVRD -+#define WFA_OUI MAC_OUI -+#else -+#define WFA_OUI "\x50\x6F\x9A" -+#endif -+#define WFA_OUI_LEN 3 -+#ifdef P2P_IE_OVRD -+#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P -+#else -+#define WFA_OUI_TYPE_P2P 9 -+#endif -+ -+#define WFA_OUI_TYPE_TPC 8 -+#ifdef WLTDLS -+#define WFA_OUI_TYPE_WFD 10 -+#endif -+ -+ -+#define RSN_AKM_NONE 0 -+#define RSN_AKM_UNSPECIFIED 1 -+#define RSN_AKM_PSK 2 -+#define RSN_AKM_FBT_1X 3 -+#define RSN_AKM_FBT_PSK 4 -+#define RSN_AKM_MFP_1X 5 -+#define RSN_AKM_MFP_PSK 6 -+#define RSN_AKM_TPK 7 -+ -+ -+#define DOT11_MAX_DEFAULT_KEYS 4 -+#define DOT11_MAX_KEY_SIZE 32 -+#define DOT11_MAX_IV_SIZE 16 -+#define DOT11_EXT_IV_FLAG (1<<5) -+#define DOT11_WPA_KEY_RSC_LEN 8 -+ -+#define WEP1_KEY_SIZE 5 -+#define WEP1_KEY_HEX_SIZE 10 -+#define WEP128_KEY_SIZE 13 -+#define WEP128_KEY_HEX_SIZE 26 -+#define TKIP_MIC_SIZE 8 -+#define TKIP_EOM_SIZE 7 -+#define TKIP_EOM_FLAG 0x5a -+#define TKIP_KEY_SIZE 32 -+#define TKIP_MIC_AUTH_TX 16 -+#define TKIP_MIC_AUTH_RX 24 -+#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX -+#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX -+#define AES_KEY_SIZE 16 -+#define AES_MIC_SIZE 8 -+#define BIP_KEY_SIZE 16 -+ -+ -+#define WCN_OUI "\x00\x50\xf2" -+#define WCN_TYPE 4 -+ -+ -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { -+ uint8 id; -+ uint8 len; -+ uint16 mdid; -+ uint8 cap; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_mdid_ie dot11_mdid_ie_t; -+ -+#define FBT_MDID_CAP_OVERDS 0x01 -+#define FBT_MDID_CAP_RRP 0x02 -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { -+ uint8 id; -+ uint8 len; -+ uint16 mic_control; -+ uint8 mic[16]; -+ uint8 anonce[32]; -+ uint8 snonce[32]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_ft_ie dot11_ft_ie_t; -+ -+#define TIE_TYPE_RESERVED 0 -+#define TIE_TYPE_REASSOC_DEADLINE 1 -+#define TIE_TYPE_KEY_LIEFTIME 2 -+#define TIE_TYPE_ASSOC_COMEBACK 3 -+BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { -+ uint8 id; -+ uint8 len; -+ uint8 type; -+ uint32 value; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_timeout_ie dot11_timeout_ie_t; -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { -+ uint8 id; -+ uint8 len; -+ uint16 key_info; -+ uint8 key_len; -+ uint8 rsc[8]; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct dot11_gtk_ie dot11_gtk_ie_t; -+ -+#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" -+#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" -+ -+ -+ -+#define WMM_OUI "\x00\x50\xF2" -+#define WMM_OUI_LEN 3 -+#define WMM_OUI_TYPE 2 -+#define WMM_VERSION 1 -+#define WMM_VERSION_LEN 1 -+ -+ -+#define WMM_OUI_SUBTYPE_PARAMETER 1 -+#define WMM_PARAMETER_IE_LEN 24 -+ -+ -+BWL_PRE_PACKED_STRUCT struct link_id_ie { -+ uint8 id; -+ uint8 len; -+ struct ether_addr bssid; -+ struct ether_addr tdls_init_mac; -+ struct ether_addr tdls_resp_mac; -+} BWL_POST_PACKED_STRUCT; -+typedef struct link_id_ie link_id_ie_t; -+#define TDLS_LINK_ID_IE_LEN 18 -+ -+ -+BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { -+ uint8 id; -+ uint8 len; -+ uint32 offset; -+ uint32 interval; -+ uint32 awake_win_slots; -+ uint32 max_wake_win; -+ uint16 idle_cnt; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wakeup_sch_ie wakeup_sch_ie_t; -+#define TDLS_WAKEUP_SCH_IE_LEN 18 -+ -+ -+BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { -+ uint8 id; -+ uint8 len; -+ uint16 switch_time; -+ uint16 switch_timeout; -+} BWL_POST_PACKED_STRUCT; -+typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; -+#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 -+ -+ -+BWL_PRE_PACKED_STRUCT struct pti_control_ie { -+ uint8 id; -+ uint8 len; -+ uint8 tid; -+ uint16 seq_control; -+} BWL_POST_PACKED_STRUCT; -+typedef struct pti_control_ie pti_control_ie_t; -+#define TDLS_PTI_CONTROL_IE_LEN 3 -+ -+ -+BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { -+ uint8 id; -+ uint8 len; -+ uint8 status; -+} BWL_POST_PACKED_STRUCT; -+typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; -+#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 -+#define TDLS_PU_BUFFER_STATUS_AC_BK 1 -+#define TDLS_PU_BUFFER_STATUS_AC_BE 2 -+#define TDLS_PU_BUFFER_STATUS_AC_VI 4 -+#define TDLS_PU_BUFFER_STATUS_AC_VO 8 -+ -+ -+#include <packed_section_end.h> -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h -new file mode 100644 -index 00000000..3ee5a748 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h -@@ -0,0 +1,45 @@ -+/* -+ * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer) -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: 802.11_bta.h 294267 2011-11-04 23:41:52Z $ -+*/ -+ -+#ifndef _802_11_BTA_H_ -+#define _802_11_BTA_H_ -+ -+#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58" -+ -+/* BT-AMP 802.11 PAL Protocols */ -+#define BTA_PROT_L2CAP 1 -+#define BTA_PROT_ACTIVITY_REPORT 2 -+#define BTA_PROT_SECURITY 3 -+#define BTA_PROT_LINK_SUPERVISION_REQUEST 4 -+#define BTA_PROT_LINK_SUPERVISION_REPLY 5 -+ -+/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */ -+#define BTA_TYPE_ID_MAC_ADDRESS 1 -+#define BTA_TYPE_ID_PREFERRED_CHANNELS 2 -+#define BTA_TYPE_ID_CONNECTED_CHANNELS 3 -+#define BTA_TYPE_ID_CAPABILITIES 4 -+#define BTA_TYPE_ID_VERSION 5 -+#endif /* _802_11_bta_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h -new file mode 100644 -index 00000000..f391e68c ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h -@@ -0,0 +1,131 @@ -+/* -+ * 802.11e protocol header file -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: 802.11e.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _802_11e_H_ -+#define _802_11e_H_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+/* This marks the start of a packed structure section. */ -+#include <packed_section_start.h> -+ -+ -+/* WME Traffic Specification (TSPEC) element */ -+#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ -+#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ -+ -+#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ -+#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ -+#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ -+#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ -+ -+BWL_PRE_PACKED_STRUCT struct tsinfo { -+ uint8 octets[3]; -+} BWL_POST_PACKED_STRUCT; -+ -+typedef struct tsinfo tsinfo_t; -+ -+/* 802.11e TSPEC IE */ -+typedef BWL_PRE_PACKED_STRUCT struct tspec { -+ uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ -+ uint8 type; /* WME_TYPE */ -+ uint8 subtype; /* WME_SUBTYPE_TSPEC */ -+ uint8 version; /* WME_VERSION */ -+ tsinfo_t tsinfo; /* TS Info bit field */ -+ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ -+ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ -+ uint32 min_srv_interval; /* Minimum Service Interval (us) */ -+ uint32 max_srv_interval; /* Maximum Service Interval (us) */ -+ uint32 inactivity_interval; /* Inactivity Interval (us) */ -+ uint32 suspension_interval; /* Suspension Interval (us) */ -+ uint32 srv_start_time; /* Service Start Time (us) */ -+ uint32 min_data_rate; /* Minimum Data Rate (bps) */ -+ uint32 mean_data_rate; /* Mean Data Rate (bps) */ -+ uint32 peak_data_rate; /* Peak Data Rate (bps) */ -+ uint32 max_burst_size; /* Maximum Burst Size (bytes) */ -+ uint32 delay_bound; /* Delay Bound (us) */ -+ uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ -+ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ -+ uint16 medium_time; /* Medium Time (32 us/s periods) */ -+} BWL_POST_PACKED_STRUCT tspec_t; -+ -+#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ -+ -+/* ts_info */ -+/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ -+#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ -+#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ -+#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ -+#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ -+#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ -+#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ -+#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ -+#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ -+#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ -+#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ -+#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ -+#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ -+/* TS info. user priority mask */ -+#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) -+ -+/* Macro to get/set bit(s) field in TSINFO */ -+#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) -+#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ -+ TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) -+#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) -+#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ -+ TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) -+ -+#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ -+ ((id) << TS_INFO_TID_SHIFT)) -+#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ -+ ((prio) << TS_INFO_USER_PRIO_SHIFT)) -+ -+/* 802.11e QBSS Load IE */ -+#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ -+#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ -+ -+#define CAC_ADDTS_RESP_TIMEOUT 300 /* default ADDTS response timeout in ms */ -+ -+/* 802.11e ADDTS status code */ -+#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ -+#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ -+#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ -+#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ -+ -+/* 802.11e DELTS status code */ -+#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ -+#define DOT11E_STATUS_END_TS 37 /* END TS */ -+#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ -+#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ -+ -+ -+/* This marks the end of a packed structure section. */ -+#include <packed_section_end.h> -+ -+#endif /* _802_11e_CAC_H_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h -new file mode 100644 -index 00000000..116a226b ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h -@@ -0,0 +1,48 @@ -+/* -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * Fundamental types and constants relating to 802.1D -+ * -+ * $Id: 802.1d.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _802_1_D_ -+#define _802_1_D_ -+ -+ -+#define PRIO_8021D_NONE 2 -+#define PRIO_8021D_BK 1 -+#define PRIO_8021D_BE 0 -+#define PRIO_8021D_EE 3 -+#define PRIO_8021D_CL 4 -+#define PRIO_8021D_VI 5 -+#define PRIO_8021D_VO 6 -+#define PRIO_8021D_NC 7 -+#define MAXPRIO 7 -+#define NUMPRIO (MAXPRIO + 1) -+ -+#define ALLPRIO -1 -+ -+ -+#define PRIO2PREC(prio) \ -+ (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h -new file mode 100644 -index 00000000..e54b2e38 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h -@@ -0,0 +1,82 @@ -+/* -+ * Broadcom Ethernettype protocol definitions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bcmeth.h 294352 2011-11-06 19:23:00Z $ -+ */ -+ -+ -+ -+#ifndef _BCMETH_H_ -+#define _BCMETH_H_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+ -+#include <packed_section_start.h> -+ -+ -+ -+ -+ -+ -+ -+#define BCMILCP_SUBTYPE_RATE 1 -+#define BCMILCP_SUBTYPE_LINK 2 -+#define BCMILCP_SUBTYPE_CSA 3 -+#define BCMILCP_SUBTYPE_LARQ 4 -+#define BCMILCP_SUBTYPE_VENDOR 5 -+#define BCMILCP_SUBTYPE_FLH 17 -+ -+#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 -+#define BCMILCP_SUBTYPE_CERT 32770 -+#define BCMILCP_SUBTYPE_SES 32771 -+ -+ -+#define BCMILCP_BCM_SUBTYPE_RESERVED 0 -+#define BCMILCP_BCM_SUBTYPE_EVENT 1 -+#define BCMILCP_BCM_SUBTYPE_SES 2 -+ -+ -+#define BCMILCP_BCM_SUBTYPE_DPT 4 -+ -+#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 -+#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 -+ -+ -+typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr -+{ -+ uint16 subtype; -+ uint16 length; -+ uint8 version; -+ uint8 oui[3]; -+ -+ uint16 usr_subtype; -+} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; -+ -+ -+ -+#include <packed_section_end.h> -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h -new file mode 100644 -index 00000000..c4397074 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h -@@ -0,0 +1,368 @@ -+/* -+ * Broadcom Event protocol definitions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * Dependencies: proto/bcmeth.h -+ * -+ * $Id: bcmevent.h 374275 2012-12-12 11:44:18Z $ -+ * -+ */ -+ -+/* -+ * Broadcom Ethernet Events protocol defines -+ * -+ */ -+ -+#ifndef _BCMEVENT_H_ -+#define _BCMEVENT_H_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+/* This marks the start of a packed structure section. */ -+#include <packed_section_start.h> -+ -+#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ -+#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ -+ -+/* flags */ -+#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ -+#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ -+#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ -+#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ -+#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ -+ -+/* these fields are stored in network order */ -+ -+/* version 1 */ -+typedef BWL_PRE_PACKED_STRUCT struct -+{ -+ uint16 version; -+ uint16 flags; /* see flags below */ -+ uint32 event_type; /* Message (see below) */ -+ uint32 status; /* Status code (see below) */ -+ uint32 reason; /* Reason code (if applicable) */ -+ uint32 auth_type; /* WLC_E_AUTH */ -+ uint32 datalen; /* data buf */ -+ struct ether_addr addr; /* Station address (if applicable) */ -+ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ -+} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; -+ -+/* the current version */ -+typedef BWL_PRE_PACKED_STRUCT struct -+{ -+ uint16 version; -+ uint16 flags; /* see flags below */ -+ uint32 event_type; /* Message (see below) */ -+ uint32 status; /* Status code (see below) */ -+ uint32 reason; /* Reason code (if applicable) */ -+ uint32 auth_type; /* WLC_E_AUTH */ -+ uint32 datalen; /* data buf */ -+ struct ether_addr addr; /* Station address (if applicable) */ -+ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ -+ uint8 ifidx; /* destination OS i/f index */ -+ uint8 bsscfgidx; /* source bsscfg index */ -+} BWL_POST_PACKED_STRUCT wl_event_msg_t; -+ -+/* used by driver msgs */ -+typedef BWL_PRE_PACKED_STRUCT struct bcm_event { -+ struct ether_header eth; -+ bcmeth_hdr_t bcm_hdr; -+ wl_event_msg_t event; -+ /* data portion follows */ -+} BWL_POST_PACKED_STRUCT bcm_event_t; -+ -+#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) -+ -+/* Event messages */ -+#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ -+#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ -+#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ -+#define WLC_E_AUTH 3 /* 802.11 AUTH request */ -+#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ -+#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ -+#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ -+#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ -+#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ -+#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ -+#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ -+#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ -+#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ -+#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ -+#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ -+#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ -+#define WLC_E_LINK 16 /* generic link indication */ -+#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ -+#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ -+#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ -+#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ -+#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ -+#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ -+#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ -+#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ -+#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ -+#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ -+#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ -+#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ -+#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ -+#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ -+#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ -+#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ -+#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ -+#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ -+#define WLC_E_RESET_COMPLETE 35 -+#define WLC_E_JOIN_START 36 -+#define WLC_E_ROAM_START 37 -+#define WLC_E_ASSOC_START 38 -+#define WLC_E_IBSS_ASSOC 39 -+#define WLC_E_RADIO 40 -+#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ -+#define WLC_E_PROBREQ_MSG 44 /* probe request received */ -+#define WLC_E_SCAN_CONFIRM_IND 45 -+#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ -+#define WLC_E_COUNTRY_CODE_CHANGED 47 -+#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ -+#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ -+#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ -+#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ -+#define WLC_E_TRACE 52 -+#ifdef WLBTAMP -+#define WLC_E_BTA_HCI_EVENT 53 /* BT-AMP HCI event */ -+#endif -+#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ -+#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ -+#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ -+#define WLC_E_PFN_SCAN_COMPLETE 57 /* PFN completed scan of network list */ -+#define WLC_E_EXTLOG_MSG 58 -+#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ -+#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ -+#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ -+#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ -+#define WLC_E_CHANNEL_ADOPTED 63 -+#define WLC_E_AP_STARTED 64 /* AP started */ -+#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ -+#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ -+#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ -+#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ -+#define WLC_E_ESCAN_RESULT 69 /* escan result event */ -+#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ -+#define WLC_E_PROBRESP_MSG 71 /* probe response received */ -+#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ -+#define WLC_E_DCS_REQUEST 73 -+ -+#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ -+ -+#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH -+ * wl_event_rx_frame_data_t header -+ */ -+#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ -+#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ -+#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ -+#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ -+#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ -+#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ -+#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ -+#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ -+#define WLC_E_GTK_PLUMBED 84 -+#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ -+#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ -+#define WLC_E_ASSOC_REQ_IE 87 -+#define WLC_E_ASSOC_RESP_IE 88 -+#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ -+#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ -+#define WLC_E_AUTH_REQ 91 /* authentication request received */ -+#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected or disconnected peer */ -+#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ -+#define WLC_E_SERVICE_FOUND 102 /* desired service found */ -+#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ -+#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ -+#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ -+#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ -+#define WLC_E_LAST 107 /* highest val + 1 for range checking */ -+ -+ -+/* Table of event name strings for UIs and debugging dumps */ -+typedef struct { -+ uint event; -+ const char *name; -+} bcmevent_name_t; -+ -+extern const bcmevent_name_t bcmevent_names[]; -+extern const int bcmevent_names_size; -+ -+/* Event status codes */ -+#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ -+#define WLC_E_STATUS_FAIL 1 /* operation failed */ -+#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ -+#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ -+#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ -+#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ -+#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ -+#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ -+#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ -+#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ -+#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ -+#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ -+#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ -+#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ -+#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ -+#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ -+ -+/* roam reason codes */ -+#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ -+#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ -+#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ -+#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ -+#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ -+#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ -+#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ -+ -+/* Roam codes used primarily by CCX */ -+#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ -+#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ -+#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ -+#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ -+ -+ -+#define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition request by AP */ -+ -+/* prune reason codes */ -+#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ -+#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ -+#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ -+#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ -+#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ -+#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ -+#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ -+#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ -+#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ -+#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ -+#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ -+#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ -+#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ -+#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ -+#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ -+ -+/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ -+#define WLC_E_SUP_OTHER 0 /* Other reason */ -+#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ -+#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ -+#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ -+#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ -+#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ -+#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ -+#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ -+#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ -+#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ -+#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ -+#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ -+#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ -+#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ -+#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ -+#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ -+ -+/* Event data for events that include frames received over the air */ -+/* WLC_E_PROBRESP_MSG -+ * WLC_E_P2P_PROBREQ_MSG -+ * WLC_E_ACTION_FRAME_RX -+ */ -+typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { -+ uint16 version; -+ uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ -+ int32 rssi; -+ uint32 mactime; -+ uint32 rate; -+} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; -+ -+#define BCM_RX_FRAME_DATA_VERSION 1 -+ -+/* WLC_E_IF event data */ -+typedef struct wl_event_data_if { -+ uint8 ifidx; /* RTE virtual device index (for dongle) */ -+ uint8 opcode; /* see I/F opcode */ -+ uint8 reserved; -+ uint8 bssidx; /* bsscfg index */ -+ uint8 role; /* see I/F role */ -+} wl_event_data_if_t; -+ -+/* opcode in WLC_E_IF event */ -+#define WLC_E_IF_ADD 1 /* bsscfg add */ -+#define WLC_E_IF_DEL 2 /* bsscfg delete */ -+#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ -+ -+/* I/F role code in WLC_E_IF event */ -+#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ -+#define WLC_E_IF_ROLE_AP 1 /* Access Point */ -+#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ -+#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ -+#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ -+#ifdef WLBTAMP -+#define WLC_E_IF_ROLE_BTA_CREATOR 5 /* BT-AMP Creator */ -+#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6 /* BT-AMP Acceptor */ -+#endif -+ -+/* Reason codes for LINK */ -+#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ -+#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ -+#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ -+#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ -+ -+/* reason codes for WLC_E_OVERLAY_REQ event */ -+#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ -+#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ -+ -+/* reason codes for WLC_E_TDLS_PEER_EVENT event */ -+#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ -+#define WLC_E_TDLS_PEER_CONNECTED 1 -+#define WLC_E_TDLS_PEER_DISCONNECTED 2 -+ -+/* GAS event data */ -+typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { -+ uint16 channel; /* channel of GAS protocol */ -+ uint8 dialog_token; /* GAS dialog token */ -+ uint8 fragment_id; /* fragment id */ -+ uint16 status_code; /* status code on GAS completion */ -+ uint16 data_len; /* length of data to follow */ -+ uint8 data[1]; /* variable length specified by data_len */ -+} BWL_POST_PACKED_STRUCT wl_event_gas_t; -+ -+/* service discovery TLV */ -+typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { -+ uint16 length; /* length of response_data */ -+ uint8 protocol; /* service protocol type */ -+ uint8 transaction_id; /* service transaction id */ -+ uint8 status_code; /* status code */ -+ uint8 data[1]; /* response data */ -+} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; -+ -+/* service discovery event data */ -+typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { -+ uint16 channel; /* channel */ -+ uint8 count; /* number of tlvs */ -+ wl_sd_tlv_t tlv[1]; /* service discovery TLV */ -+} BWL_POST_PACKED_STRUCT wl_event_sd_t; -+ -+/* This marks the end of a packed structure section. */ -+#include <packed_section_end.h> -+ -+#endif /* _BCMEVENT_H_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h -new file mode 100644 -index 00000000..d5c3b76d ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h -@@ -0,0 +1,210 @@ -+/* -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * Fundamental constants relating to IP Protocol -+ * -+ * $Id: bcmip.h 290206 2011-10-17 19:13:51Z $ -+ */ -+ -+#ifndef _bcmip_h_ -+#define _bcmip_h_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+ -+#include <packed_section_start.h> -+ -+ -+ -+#define IP_VER_OFFSET 0x0 -+#define IP_VER_MASK 0xf0 -+#define IP_VER_SHIFT 4 -+#define IP_VER_4 4 -+#define IP_VER_6 6 -+ -+#define IP_VER(ip_body) \ -+ ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) -+ -+#define IP_PROT_ICMP 0x1 -+#define IP_PROT_IGMP 0x2 -+#define IP_PROT_TCP 0x6 -+#define IP_PROT_UDP 0x11 -+#define IP_PROT_ICMP6 0x3a -+ -+ -+#define IPV4_VER_HL_OFFSET 0 -+#define IPV4_TOS_OFFSET 1 -+#define IPV4_PKTLEN_OFFSET 2 -+#define IPV4_PKTFLAG_OFFSET 6 -+#define IPV4_PROT_OFFSET 9 -+#define IPV4_CHKSUM_OFFSET 10 -+#define IPV4_SRC_IP_OFFSET 12 -+#define IPV4_DEST_IP_OFFSET 16 -+#define IPV4_OPTIONS_OFFSET 20 -+ -+ -+#define IPV4_VER_MASK 0xf0 -+#define IPV4_VER_SHIFT 4 -+ -+#define IPV4_HLEN_MASK 0x0f -+#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) -+ -+#define IPV4_ADDR_LEN 4 -+ -+#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ -+ ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) -+ -+#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ -+ ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) -+ -+#define IPV4_TOS_DSCP_MASK 0xfc -+#define IPV4_TOS_DSCP_SHIFT 2 -+ -+#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) -+ -+#define IPV4_TOS_PREC_MASK 0xe0 -+#define IPV4_TOS_PREC_SHIFT 5 -+ -+#define IPV4_TOS_LOWDELAY 0x10 -+#define IPV4_TOS_THROUGHPUT 0x8 -+#define IPV4_TOS_RELIABILITY 0x4 -+ -+#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) -+ -+#define IPV4_FRAG_RESV 0x8000 -+#define IPV4_FRAG_DONT 0x4000 -+#define IPV4_FRAG_MORE 0x2000 -+#define IPV4_FRAG_OFFSET_MASK 0x1fff -+ -+#define IPV4_ADDR_STR_LEN 16 -+ -+ -+BWL_PRE_PACKED_STRUCT struct ipv4_addr { -+ uint8 addr[IPV4_ADDR_LEN]; -+} BWL_POST_PACKED_STRUCT; -+ -+BWL_PRE_PACKED_STRUCT struct ipv4_hdr { -+ uint8 version_ihl; -+ uint8 tos; -+ uint16 tot_len; -+ uint16 id; -+ uint16 frag; -+ uint8 ttl; -+ uint8 prot; -+ uint16 hdr_chksum; -+ uint8 src_ip[IPV4_ADDR_LEN]; -+ uint8 dst_ip[IPV4_ADDR_LEN]; -+} BWL_POST_PACKED_STRUCT; -+ -+ -+#define IPV6_PAYLOAD_LEN_OFFSET 4 -+#define IPV6_NEXT_HDR_OFFSET 6 -+#define IPV6_HOP_LIMIT_OFFSET 7 -+#define IPV6_SRC_IP_OFFSET 8 -+#define IPV6_DEST_IP_OFFSET 24 -+ -+ -+#define IPV6_TRAFFIC_CLASS(ipv6_body) \ -+ (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ -+ ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) -+ -+#define IPV6_FLOW_LABEL(ipv6_body) \ -+ (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ -+ (((uint8 *)(ipv6_body))[2] << 8) | \ -+ (((uint8 *)(ipv6_body))[3])) -+ -+#define IPV6_PAYLOAD_LEN(ipv6_body) \ -+ ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ -+ ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) -+ -+#define IPV6_NEXT_HDR(ipv6_body) \ -+ (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) -+ -+#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) -+ -+#define IPV6_ADDR_LEN 16 -+ -+ -+#define IP_TOS46(ip_body) \ -+ (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ -+ IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) -+ -+ -+#define IPV6_EXTHDR_HOP 0 -+#define IPV6_EXTHDR_ROUTING 43 -+#define IPV6_EXTHDR_FRAGMENT 44 -+#define IPV6_EXTHDR_AUTH 51 -+#define IPV6_EXTHDR_NONE 59 -+#define IPV6_EXTHDR_DEST 60 -+ -+#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ -+ ((prot) == IPV6_EXTHDR_ROUTING) || \ -+ ((prot) == IPV6_EXTHDR_FRAGMENT) || \ -+ ((prot) == IPV6_EXTHDR_AUTH) || \ -+ ((prot) == IPV6_EXTHDR_NONE) || \ -+ ((prot) == IPV6_EXTHDR_DEST)) -+ -+#define IPV6_MIN_HLEN 40 -+ -+#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) -+ -+BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { -+ uint8 nexthdr; -+ uint8 hdrlen; -+} BWL_POST_PACKED_STRUCT; -+ -+BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { -+ uint8 nexthdr; -+ uint8 rsvd; -+ uint16 frag_off; -+ uint32 ident; -+} BWL_POST_PACKED_STRUCT; -+ -+static INLINE int32 -+ipv6_exthdr_len(uint8 *h, uint8 *proto) -+{ -+ uint16 len = 0, hlen; -+ struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; -+ -+ while (IPV6_EXTHDR(eh->nexthdr)) { -+ if (eh->nexthdr == IPV6_EXTHDR_NONE) -+ return -1; -+ else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) -+ hlen = 8; -+ else if (eh->nexthdr == IPV6_EXTHDR_AUTH) -+ hlen = (eh->hdrlen + 2) << 2; -+ else -+ hlen = IPV6_EXTHDR_LEN(eh); -+ -+ len += hlen; -+ eh = (struct ipv6_exthdr *)(h + len); -+ } -+ -+ *proto = eh->nexthdr; -+ return len; -+} -+ -+ -+#include <packed_section_end.h> -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h -new file mode 100644 -index 00000000..8617985d ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h -@@ -0,0 +1,441 @@ -+/* -+ * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface) -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: bt_amp_hci.h 294267 2011-11-04 23:41:52Z $ -+*/ -+ -+#ifndef _bt_amp_hci_h -+#define _bt_amp_hci_h -+ -+/* This marks the start of a packed structure section. */ -+#include <packed_section_start.h> -+ -+ -+/* AMP HCI CMD packet format */ -+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd { -+ uint16 opcode; -+ uint8 plen; -+ uint8 parms[1]; -+} BWL_POST_PACKED_STRUCT amp_hci_cmd_t; -+ -+#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms) -+#define HCI_CMD_DATA_SIZE 255 -+ -+/* AMP HCI CMD opcode layout */ -+#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF)) -+#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F)) -+#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF) -+ -+/* AMP HCI command opcodes */ -+#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001) -+#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002) -+#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003) -+#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009) -+#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A) -+#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B) -+#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035) -+#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036) -+#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037) -+#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038) -+#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039) -+#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A) -+#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B) -+#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C) -+#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067) -+#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069) -+#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A) -+#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B) -+#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003) -+#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015) -+#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016) -+#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036) -+#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037) -+#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F) -+#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061) -+#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062) -+#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063) -+#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064) -+#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065) -+#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001) -+#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002) -+#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005) -+#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A) -+ -+/* AMP HCI command parameters */ -+typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms { -+ uint8 plh; -+ uint8 offset[2]; /* length so far */ -+ uint8 max_remote[2]; -+} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms { -+ uint8 plh; -+ uint8 offset[2]; -+ uint8 len[2]; -+ uint8 frag[1]; -+} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms { -+ uint8 plh; -+ uint8 key_length; -+ uint8 key_type; -+ uint8 key[1]; -+} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms { -+ uint8 plh; -+ uint8 reason; -+} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms { -+ uint8 plh; -+ uint8 txflow[16]; -+ uint8 rxflow[16]; -+} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec { -+ uint8 id; -+ uint8 service_type; -+ uint8 max_sdu[2]; -+ uint8 sdu_ia_time[4]; -+ uint8 access_latency[4]; -+ uint8 flush_timeout[4]; -+} BWL_POST_PACKED_STRUCT ext_flow_spec_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms { -+ uint8 plh; -+ uint8 tx_fs_ID; -+} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms { -+ uint8 llh[2]; -+ uint8 txflow[16]; -+ uint8 rxflow[16]; -+} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct plh_pad { -+ uint8 plh; -+ uint8 pad; -+} BWL_POST_PACKED_STRUCT plh_pad_t; -+ -+typedef BWL_PRE_PACKED_STRUCT union hci_handle { -+ uint16 bredr; -+ plh_pad_t amp; -+} BWL_POST_PACKED_STRUCT hci_handle_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms { -+ hci_handle_t handle; -+ uint8 timeout[2]; -+} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms { -+ uint8 llh[2]; -+ uint8 befto[4]; -+} BWL_POST_PACKED_STRUCT befto_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms { -+ uint8 plh; -+ uint8 srm; -+} BWL_POST_PACKED_STRUCT srm_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms { -+ uint8 ld_aware; -+ uint8 ld[2]; -+ uint8 ld_opts; -+ uint8 l_opts; -+} BWL_POST_PACKED_STRUCT ld_cmd_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms { -+ uint8 llh[2]; -+ uint8 packet_type; -+} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t; -+ -+/* Generic AMP extended flow spec service types */ -+#define EFS_SVCTYPE_NO_TRAFFIC 0 -+#define EFS_SVCTYPE_BEST_EFFORT 1 -+#define EFS_SVCTYPE_GUARANTEED 2 -+ -+/* AMP HCI event packet format */ -+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event { -+ uint8 ecode; -+ uint8 plen; -+ uint8 parms[1]; -+} BWL_POST_PACKED_STRUCT amp_hci_event_t; -+ -+#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms) -+ -+/* AMP HCI event codes */ -+#define HCI_Command_Complete 0x0E -+#define HCI_Command_Status 0x0F -+#define HCI_Flush_Occurred 0x11 -+#define HCI_Enhanced_Flush_Complete 0x39 -+#define HCI_Physical_Link_Complete 0x40 -+#define HCI_Channel_Select 0x41 -+#define HCI_Disconnect_Physical_Link_Complete 0x42 -+#define HCI_Logical_Link_Complete 0x45 -+#define HCI_Disconnect_Logical_Link_Complete 0x46 -+#define HCI_Flow_Spec_Modify_Complete 0x47 -+#define HCI_Number_of_Completed_Data_Blocks 0x48 -+#define HCI_Short_Range_Mode_Change_Complete 0x4C -+#define HCI_Status_Change_Event 0x4D -+#define HCI_Vendor_Specific 0xFF -+ -+/* AMP HCI event mask bit positions */ -+#define HCI_Physical_Link_Complete_Event_Mask 0x0001 -+#define HCI_Channel_Select_Event_Mask 0x0002 -+#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004 -+#define HCI_Logical_Link_Complete_Event_Mask 0x0020 -+#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040 -+#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080 -+#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100 -+#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000 -+#define HCI_Status_Change_Event_Mask 0x2000 -+#define HCI_All_Event_Mask 0x31e7 -+/* AMP HCI event parameters */ -+typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms { -+ uint8 status; -+ uint8 cmdpkts; -+ uint16 opcode; -+} BWL_POST_PACKED_STRUCT cmd_status_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms { -+ uint8 cmdpkts; -+ uint16 opcode; -+ uint8 parms[1]; -+} BWL_POST_PACKED_STRUCT cmd_complete_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms { -+ uint16 handle; -+} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms { -+ uint8 status; -+ uint8 plh; -+} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms { -+ uint8 status; -+ uint8 plh; -+ uint16 len; -+ uint8 frag[1]; -+} BWL_POST_PACKED_STRUCT read_local_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms { -+ uint8 status; -+ uint8 AMP_status; -+ uint32 bandwidth; -+ uint32 gbandwidth; -+ uint32 latency; -+ uint32 PDU_size; -+ uint8 ctrl_type; -+ uint16 PAL_cap; -+ uint16 AMP_ASSOC_len; -+ uint32 max_flush_timeout; -+ uint32 be_flush_timeout; -+} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms { -+ uint8 status; -+ uint16 llh; -+ uint8 plh; -+ uint8 tx_fs_ID; -+} BWL_POST_PACKED_STRUCT log_link_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms { -+ uint8 status; -+ uint16 llh; -+ uint8 reason; -+} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms { -+ uint8 status; -+ uint8 plh; -+ uint8 tx_fs_ID; -+} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms { -+ uint8 status; -+ uint16 llh; -+} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms { -+ uint8 status; -+ uint8 plh; -+} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms { -+ uint8 status; -+ uint8 plh; -+ uint8 reason; -+} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms { -+ uint8 status; -+ hci_handle_t handle; -+ uint16 timeout; -+} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms { -+ uint8 status; -+ uint16 timeout; -+} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms { -+ uint8 status; -+ uint16 ACL_pkt_len; -+ uint16 data_block_len; -+ uint16 data_block_num; -+} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct data_blocks { -+ uint16 handle; -+ uint16 pkts; -+ uint16 blocks; -+} BWL_POST_PACKED_STRUCT data_blocks_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms { -+ uint16 num_blocks; -+ uint8 num_handles; -+ data_blocks_t completed[1]; -+} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms { -+ uint8 status; -+ uint32 befto; -+} BWL_POST_PACKED_STRUCT befto_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms { -+ uint8 status; -+ uint8 plh; -+ uint8 srm; -+} BWL_POST_PACKED_STRUCT srm_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms { -+ uint8 status; -+ uint8 llh[2]; -+ uint16 counter; -+} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms { -+ uint8 status; -+ uint8 llh[2]; -+} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms { -+ uint8 status; -+ hci_handle_t handle; -+ uint8 link_quality; -+} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms { -+ uint8 status; -+ uint8 ld_aware; -+ uint8 ld[2]; -+ uint8 ld_opts; -+ uint8 l_opts; -+} BWL_POST_PACKED_STRUCT ld_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms { -+ uint16 handle; -+} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms { -+ uint8 len; -+ uint8 parms[1]; -+} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms { -+ uint8 status; -+ uint8 hci_version; -+ uint16 hci_revision; -+ uint8 pal_version; -+ uint16 mfg_name; -+ uint16 pal_subversion; -+} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t; -+ -+#define MAX_SUPPORTED_CMD_BYTE 64 -+typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms { -+ uint8 status; -+ uint8 cmd[MAX_SUPPORTED_CMD_BYTE]; -+} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms { -+ uint8 status; -+ uint8 amp_status; -+} BWL_POST_PACKED_STRUCT status_change_evt_parms_t; -+ -+/* AMP HCI error codes */ -+#define HCI_SUCCESS 0x00 -+#define HCI_ERR_ILLEGAL_COMMAND 0x01 -+#define HCI_ERR_NO_CONNECTION 0x02 -+#define HCI_ERR_MEMORY_FULL 0x07 -+#define HCI_ERR_CONNECTION_TIMEOUT 0x08 -+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09 -+#define HCI_ERR_CONNECTION_EXISTS 0x0B -+#define HCI_ERR_CONNECTION_DISALLOWED 0x0C -+#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10 -+#define HCI_ERR_UNSUPPORTED_VALUE 0x11 -+#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12 -+#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16 -+#define HCI_ERR_UNSPECIFIED 0x1F -+#define HCI_ERR_UNIT_KEY_USED 0x26 -+#define HCI_ERR_QOS_REJECTED 0x2D -+#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30 -+#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39 -+#define HCI_ERR_CHANNEL_MOVE 0xFF -+ -+/* AMP HCI ACL Data packet format */ -+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data { -+ uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */ -+ uint16 dlen; /* data total length */ -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t; -+ -+#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data) -+ -+#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14) -+#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12) -+ -+#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff) -+#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12) -+ -+/* AMP Activity Report packet formats */ -+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report { -+ uint8 ScheduleKnown; -+ uint8 NumReports; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple { -+ uint32 StartTime; -+ uint32 Duration; -+ uint32 Periodicity; -+} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t; -+ -+#define HCI_AR_SCHEDULE_KNOWN 0x01 -+ -+ -+/* This marks the end of a packed structure section. */ -+#include <packed_section_end.h> -+ -+#endif /* _bt_amp_hci_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h -new file mode 100644 -index 00000000..8936d164 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/eapol.h -@@ -0,0 +1,193 @@ -+/* -+ * 802.1x EAPOL definitions -+ * -+ * See -+ * IEEE Std 802.1X-2001 -+ * IEEE 802.1X RADIUS Usage Guidelines -+ * -+ * Copyright (C) 2002 Broadcom Corporation -+ * -+ * $Id: eapol.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _eapol_h_ -+#define _eapol_h_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+/* This marks the start of a packed structure section. */ -+#include <packed_section_start.h> -+ -+#include <bcmcrypto/aeskeywrap.h> -+ -+/* EAPOL for 802.3/Ethernet */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ struct ether_header eth; /* 802.3/Ethernet header */ -+ unsigned char version; /* EAPOL protocol version */ -+ unsigned char type; /* EAPOL type */ -+ unsigned short length; /* Length of body */ -+ unsigned char body[1]; /* Body (optional) */ -+} BWL_POST_PACKED_STRUCT eapol_header_t; -+ -+#define EAPOL_HEADER_LEN 18 -+ -+typedef struct { -+ unsigned char version; /* EAPOL protocol version */ -+ unsigned char type; /* EAPOL type */ -+ unsigned short length; /* Length of body */ -+} eapol_hdr_t; -+ -+#define EAPOL_HDR_LEN 4 -+ -+/* EAPOL version */ -+#define WPA2_EAPOL_VERSION 2 -+#define WPA_EAPOL_VERSION 1 -+#define LEAP_EAPOL_VERSION 1 -+#define SES_EAPOL_VERSION 1 -+ -+/* EAPOL types */ -+#define EAP_PACKET 0 -+#define EAPOL_START 1 -+#define EAPOL_LOGOFF 2 -+#define EAPOL_KEY 3 -+#define EAPOL_ASF 4 -+ -+/* EAPOL-Key types */ -+#define EAPOL_RC4_KEY 1 -+#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ -+#define EAPOL_WPA_KEY 254 /* WPA */ -+ -+/* RC4 EAPOL-Key header field sizes */ -+#define EAPOL_KEY_REPLAY_LEN 8 -+#define EAPOL_KEY_IV_LEN 16 -+#define EAPOL_KEY_SIG_LEN 16 -+ -+/* RC4 EAPOL-Key */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ unsigned char type; /* Key Descriptor Type */ -+ unsigned short length; /* Key Length (unaligned) */ -+ unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ -+ unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ -+ unsigned char index; /* Key Flags & Index */ -+ unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ -+ unsigned char key[1]; /* Key (optional) */ -+} BWL_POST_PACKED_STRUCT eapol_key_header_t; -+ -+#define EAPOL_KEY_HEADER_LEN 44 -+ -+/* RC4 EAPOL-Key flags */ -+#define EAPOL_KEY_FLAGS_MASK 0x80 -+#define EAPOL_KEY_BROADCAST 0 -+#define EAPOL_KEY_UNICAST 0x80 -+ -+/* RC4 EAPOL-Key index */ -+#define EAPOL_KEY_INDEX_MASK 0x7f -+ -+/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ -+#define EAPOL_WPA_KEY_REPLAY_LEN 8 -+#define EAPOL_WPA_KEY_NONCE_LEN 32 -+#define EAPOL_WPA_KEY_IV_LEN 16 -+#define EAPOL_WPA_KEY_RSC_LEN 8 -+#define EAPOL_WPA_KEY_ID_LEN 8 -+#define EAPOL_WPA_KEY_MIC_LEN 16 -+#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) -+#define EAPOL_WPA_MAX_KEY_SIZE 32 -+ -+/* WPA EAPOL-Key */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ unsigned char type; /* Key Descriptor Type */ -+ unsigned short key_info; /* Key Information (unaligned) */ -+ unsigned short key_len; /* Key Length (unaligned) */ -+ unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ -+ unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ -+ unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ -+ unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ -+ unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ -+ unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ -+ unsigned short data_len; /* Key Data Length */ -+ unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ -+} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; -+ -+#define EAPOL_WPA_KEY_LEN 95 -+ -+/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ -+#define WPA_KEY_DESC_V1 0x01 -+#define WPA_KEY_DESC_V2 0x02 -+#define WPA_KEY_DESC_V3 0x03 -+#define WPA_KEY_PAIRWISE 0x08 -+#define WPA_KEY_INSTALL 0x40 -+#define WPA_KEY_ACK 0x80 -+#define WPA_KEY_MIC 0x100 -+#define WPA_KEY_SECURE 0x200 -+#define WPA_KEY_ERROR 0x400 -+#define WPA_KEY_REQ 0x800 -+ -+#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 -+ -+/* WPA-only KEY KEY_INFO bits */ -+#define WPA_KEY_INDEX_0 0x00 -+#define WPA_KEY_INDEX_1 0x10 -+#define WPA_KEY_INDEX_2 0x20 -+#define WPA_KEY_INDEX_3 0x30 -+#define WPA_KEY_INDEX_MASK 0x30 -+#define WPA_KEY_INDEX_SHIFT 0x04 -+ -+/* 802.11i/WPA2-only KEY KEY_INFO bits */ -+#define WPA_KEY_ENCRYPTED_DATA 0x1000 -+ -+/* Key Data encapsulation */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint8 type; -+ uint8 length; -+ uint8 oui[3]; -+ uint8 subtype; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; -+ -+#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 -+ -+#define WPA2_KEY_DATA_SUBTYPE_GTK 1 -+#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 -+#define WPA2_KEY_DATA_SUBTYPE_MAC 3 -+#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 -+#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 -+ -+/* GTK encapsulation */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint8 flags; -+ uint8 reserved; -+ uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; -+} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; -+ -+#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 -+ -+#define WPA2_GTK_INDEX_MASK 0x03 -+#define WPA2_GTK_INDEX_SHIFT 0x00 -+ -+#define WPA2_GTK_TRANSMIT 0x04 -+ -+/* IGTK encapsulation */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint16 key_id; -+ uint8 ipn[6]; -+ uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; -+} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; -+ -+#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 -+ -+/* STAKey encapsulation */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint8 reserved[2]; -+ uint8 mac[ETHER_ADDR_LEN]; -+ uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; -+} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; -+ -+#define WPA2_KEY_DATA_PAD 0xdd -+ -+ -+/* This marks the end of a packed structure section. */ -+#include <packed_section_end.h> -+ -+#endif /* _eapol_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h -new file mode 100644 -index 00000000..e4551856 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h -@@ -0,0 +1,162 @@ -+/* -+ * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: ethernet.h 309193 2012-01-19 00:03:57Z $ -+ */ -+ -+#ifndef _NET_ETHERNET_H_ -+#define _NET_ETHERNET_H_ -+ -+#ifndef _TYPEDEFS_H_ -+#include "typedefs.h" -+#endif -+ -+ -+#include <packed_section_start.h> -+ -+ -+ -+#define ETHER_ADDR_LEN 6 -+ -+ -+#define ETHER_TYPE_LEN 2 -+ -+ -+#define ETHER_CRC_LEN 4 -+ -+ -+#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) -+ -+ -+#define ETHER_MIN_LEN 64 -+ -+ -+#define ETHER_MIN_DATA 46 -+ -+ -+#define ETHER_MAX_LEN 1518 -+ -+ -+#define ETHER_MAX_DATA 1500 -+ -+ -+#define ETHER_TYPE_MIN 0x0600 -+#define ETHER_TYPE_IP 0x0800 -+#define ETHER_TYPE_ARP 0x0806 -+#define ETHER_TYPE_8021Q 0x8100 -+#define ETHER_TYPE_IPV6 0x86dd -+#define ETHER_TYPE_BRCM 0x886c -+#define ETHER_TYPE_802_1X 0x888e -+#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 -+#define ETHER_TYPE_WAI 0x88b4 -+#define ETHER_TYPE_89_0D 0x890d -+ -+#define ETHER_TYPE_IPV6 0x86dd -+ -+ -+#define ETHER_BRCM_SUBTYPE_LEN 4 -+ -+ -+#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) -+#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) -+#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) -+ -+ -+#define ETHER_IS_VALID_LEN(foo) \ -+ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) -+ -+#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ -+ ((uint8 *)ea)[0] = 0x01; \ -+ ((uint8 *)ea)[1] = 0x00; \ -+ ((uint8 *)ea)[2] = 0x5e; \ -+ ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ -+ ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ -+ ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ -+} -+ -+#ifndef __INCif_etherh -+ -+BWL_PRE_PACKED_STRUCT struct ether_header { -+ uint8 ether_dhost[ETHER_ADDR_LEN]; -+ uint8 ether_shost[ETHER_ADDR_LEN]; -+ uint16 ether_type; -+} BWL_POST_PACKED_STRUCT; -+ -+ -+BWL_PRE_PACKED_STRUCT struct ether_addr { -+ uint8 octet[ETHER_ADDR_LEN]; -+} BWL_POST_PACKED_STRUCT; -+#endif -+ -+ -+#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) -+#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) -+#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) -+#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) -+ -+ -+#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) -+ -+ -+#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) -+ -+ -+ -+#define ether_cmp(a, b) (!(((short*)(a))[0] == ((short*)(b))[0]) | \ -+ !(((short*)(a))[1] == ((short*)(b))[1]) | \ -+ !(((short*)(a))[2] == ((short*)(b))[2])) -+ -+ -+#define ether_copy(s, d) { \ -+ ((short*)(d))[0] = ((const short*)(s))[0]; \ -+ ((short*)(d))[1] = ((const short*)(s))[1]; \ -+ ((short*)(d))[2] = ((const short*)(s))[2]; } -+ -+ -+static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; -+static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; -+ -+#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \ -+ ((uint8 *)(ea))[1] & \ -+ ((uint8 *)(ea))[2] & \ -+ ((uint8 *)(ea))[3] & \ -+ ((uint8 *)(ea))[4] & \ -+ ((uint8 *)(ea))[5]) == 0xff) -+#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \ -+ ((uint8 *)(ea))[1] | \ -+ ((uint8 *)(ea))[2] | \ -+ ((uint8 *)(ea))[3] | \ -+ ((uint8 *)(ea))[4] | \ -+ ((uint8 *)(ea))[5]) == 0) -+ -+#define ETHER_MOVE_HDR(d, s) \ -+do { \ -+ struct ether_header t; \ -+ t = *(struct ether_header *)(s); \ -+ *(struct ether_header *)(d) = t; \ -+} while (0) -+ -+ -+#include <packed_section_end.h> -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h -new file mode 100644 -index 00000000..1bfe73bc ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h -@@ -0,0 +1,564 @@ -+/* -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) -+ * -+ * $Id: p2p.h 326276 2012-04-06 23:16:42Z $ -+ */ -+ -+#ifndef _P2P_H_ -+#define _P2P_H_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+#include <wlioctl.h> -+#include <proto/802.11.h> -+ -+ -+#include <packed_section_start.h> -+ -+ -+ -+#define P2P_OUI WFA_OUI -+#define P2P_VER WFA_OUI_TYPE_P2P -+ -+#define P2P_IE_ID 0xdd -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { -+ uint8 id; -+ uint8 len; -+ uint8 OUI[3]; -+ uint8 oui_type; -+ uint8 subelts[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_ie wifi_p2p_ie_t; -+ -+#define P2P_IE_FIXED_LEN 6 -+ -+#define P2P_ATTR_ID_OFF 0 -+#define P2P_ATTR_LEN_OFF 1 -+#define P2P_ATTR_DATA_OFF 3 -+ -+#define P2P_ATTR_ID_LEN 1 -+#define P2P_ATTR_LEN_LEN 2 -+#define P2P_ATTR_HDR_LEN 3 -+ -+ -+#define P2P_SEID_STATUS 0 -+#define P2P_SEID_MINOR_RC 1 -+#define P2P_SEID_P2P_INFO 2 -+#define P2P_SEID_DEV_ID 3 -+#define P2P_SEID_INTENT 4 -+#define P2P_SEID_CFG_TIMEOUT 5 -+#define P2P_SEID_CHANNEL 6 -+#define P2P_SEID_GRP_BSSID 7 -+#define P2P_SEID_XT_TIMING 8 -+#define P2P_SEID_INTINTADDR 9 -+#define P2P_SEID_P2P_MGBTY 10 -+#define P2P_SEID_CHAN_LIST 11 -+#define P2P_SEID_ABSENCE 12 -+#define P2P_SEID_DEV_INFO 13 -+#define P2P_SEID_GROUP_INFO 14 -+#define P2P_SEID_GROUP_ID 15 -+#define P2P_SEID_P2P_IF 16 -+#define P2P_SEID_OP_CHANNEL 17 -+#define P2P_SEID_INVITE_FLAGS 18 -+#define P2P_SEID_VNDR 221 -+ -+#define P2P_SE_VS_ID_SERVICES 0x1b -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 dev; -+ uint8 group; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; -+ -+ -+#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 -+#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 -+#define P2P_CAPSE_DEV_CONCURRENT 0x4 -+#define P2P_CAPSE_DEV_INFRA_MAN 0x8 -+#define P2P_CAPSE_DEV_LIMIT 0x10 -+#define P2P_CAPSE_INVITE_PROC 0x20 -+ -+ -+#define P2P_CAPSE_GRP_OWNER 0x1 -+#define P2P_CAPSE_PERSIST_GRP 0x2 -+#define P2P_CAPSE_GRP_LIMIT 0x4 -+#define P2P_CAPSE_GRP_INTRA_BSS 0x8 -+#define P2P_CAPSE_GRP_X_CONNECT 0x10 -+#define P2P_CAPSE_GRP_PERSISTENT 0x20 -+#define P2P_CAPSE_GRP_FORMATION 0x40 -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 intent; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 go_tmo; -+ uint8 client_tmo; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 country[3]; -+ uint8 op_class; -+ uint8 channel; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 mac[6]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 mac[6]; -+ uint8 ssid[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 mac[6]; -+ uint8 ifaddrs; -+ uint8 ifaddr[1][6]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 status; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; -+ -+ -+#define P2P_STATSE_SUCCESS 0 -+ -+#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 -+ -+#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL -+ -+#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 -+ -+#define P2P_STATSE_FAIL_LIMIT_REACHED 3 -+ -+#define P2P_STATSE_FAIL_INVALID_PARAMS 4 -+ -+#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 -+ -+#define P2P_STATSE_FAIL_PROTO_ERROR 6 -+ -+#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 -+ -+#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 -+ -+#define P2P_STATSE_FAIL_INTENT 9 -+ -+#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 -+ -+#define P2P_STATSE_FAIL_USER_REJECT 11 -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 avail[2]; -+ uint8 interval[2]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; -+ -+#define P2P_EXT_MIN 10 -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 mac[6]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 band; -+ uint8 channel; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { -+ uint8 band; -+ uint8 num_channels; -+ uint8 channels[WL_NUMCHANNELS]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; -+#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 country[3]; -+ uint8 num_entries; -+ wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; -+ -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { -+ uint16 cat_id; -+ uint8 OUI[3]; -+ uint8 oui_type; -+ uint16 sub_cat_id; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 mac[6]; -+ uint16 wps_cfg_meths; -+ uint8 pri_devtype[8]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; -+ -+#define P2P_DEV_TYPE_LEN 8 -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { -+ uint8 len; -+ uint8 devaddr[ETHER_ADDR_LEN]; -+ uint8 ifaddr[ETHER_ADDR_LEN]; -+ uint8 devcap; -+ uint8 cfg_meths[2]; -+ uint8 pridt[P2P_DEV_TYPE_LEN]; -+ uint8 secdts; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ struct ether_addr addr; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 mg_bitmap; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; -+ -+#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 country[3]; -+ uint8 op_class; -+ uint8 channel; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 flags; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { -+ uint8 category; -+ uint8 OUI[3]; -+ uint8 type; -+ uint8 subtype; -+ uint8 dialog_token; -+ uint8 elts[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; -+#define P2P_AF_CATEGORY 0x7f -+ -+#define P2P_AF_FIXED_LEN 7 -+ -+ -+#define P2P_AF_NOTICE_OF_ABSENCE 0 -+#define P2P_AF_PRESENCE_REQ 1 -+#define P2P_AF_PRESENCE_RSP 2 -+#define P2P_AF_GO_DISC_REQ 3 -+ -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { -+ uint8 category; -+ uint8 action; -+ uint8 oui[3]; -+ uint8 oui_type; -+ uint8 subtype; -+ uint8 dialog_token; -+ uint8 elts[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; -+#define P2P_PUB_AF_FIXED_LEN 8 -+#define P2P_PUB_AF_CATEGORY 0x04 -+#define P2P_PUB_AF_ACTION 0x09 -+ -+ -+#define P2P_PAF_GON_REQ 0 -+#define P2P_PAF_GON_RSP 1 -+#define P2P_PAF_GON_CONF 2 -+#define P2P_PAF_INVITE_REQ 3 -+#define P2P_PAF_INVITE_RSP 4 -+#define P2P_PAF_DEVDIS_REQ 5 -+#define P2P_PAF_DEVDIS_RSP 6 -+#define P2P_PAF_PROVDIS_REQ 7 -+#define P2P_PAF_PROVDIS_RSP 8 -+#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ -+ -+#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ -+#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP -+#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { -+ uint8 cnt_type; -+ uint32 duration; -+ uint32 interval; -+ uint32 start; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { -+ uint8 eltId; -+ uint8 len[2]; -+ uint8 index; -+ uint8 ops_ctw_parms; -+ wifi_p2p_noa_desc_t desc[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; -+ -+#define P2P_NOA_SE_FIXED_LEN 5 -+ -+ -+#define P2P_NOA_DESC_CNT_RESERVED 0 -+#define P2P_NOA_DESC_CNT_REPEAT 255 -+#define P2P_NOA_DESC_TYPE_PREFERRED 1 -+#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 -+ -+ -+#define P2P_NOA_CTW_MASK 0x7f -+#define P2P_NOA_OPS_MASK 0x80 -+#define P2P_NOA_OPS_SHIFT 7 -+ -+#define P2P_CTW_MIN 10 -+ -+ -+#define P2PSD_ACTION_CATEGORY 0x04 -+ -+#define P2PSD_ACTION_ID_GAS_IREQ 0x0a -+ -+#define P2PSD_ACTION_ID_GAS_IRESP 0x0b -+ -+#define P2PSD_ACTION_ID_GAS_CREQ 0x0c -+ -+#define P2PSD_ACTION_ID_GAS_CRESP 0x0d -+ -+#define P2PSD_AD_EID 0x6c -+ -+#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 -+ -+#define P2PSD_ADP_PROTO_ID 0x00 -+ -+#define P2PSD_GAS_OUI P2P_OUI -+ -+#define P2PSD_GAS_OUI_SUBTYPE P2P_VER -+ -+#define P2PSD_GAS_NQP_INFOID 0xDDDD -+ -+#define P2PSD_GAS_COMEBACKDEALY 0x00 -+ -+ -+ -+typedef enum p2psd_svc_protype { -+ SVC_RPOTYPE_ALL = 0, -+ SVC_RPOTYPE_BONJOUR = 1, -+ SVC_RPOTYPE_UPNP = 2, -+ SVC_RPOTYPE_WSD = 3, -+ SVC_RPOTYPE_VENDOR = 255 -+} p2psd_svc_protype_t; -+ -+ -+typedef enum { -+ P2PSD_RESP_STATUS_SUCCESS = 0, -+ P2PSD_RESP_STATUS_PROTYPE_NA = 1, -+ P2PSD_RESP_STATUS_DATA_NA = 2, -+ P2PSD_RESP_STATUS_BAD_REQUEST = 3 -+} p2psd_resp_status_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { -+ uint8 llm_pamebi; -+ uint8 adp_id; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { -+ uint8 id; -+ uint8 len; -+ wifi_p2psd_adp_tpl_t adp_tpl; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { -+ uint8 oui_subtype; -+ uint16 svc_updi; -+ uint8 svc_tlvs[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { -+ uint16 len; -+ uint8 svc_prot; -+ uint8 svc_tscid; -+ uint8 query_data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { -+ uint16 info_id; -+ uint16 len; -+ uint8 oui[3]; -+ uint8 qreq_vsc[1]; -+ -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { -+ wifi_p2psd_adp_ie_t adp_ie; -+ uint16 qreq_len; -+ uint8 qreq_frm[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { -+ uint16 len; -+ uint8 svc_prot; -+ uint8 svc_tscid; -+ uint8 status; -+ uint8 query_data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { -+ uint16 info_id; -+ uint16 len; -+ uint8 oui[3]; -+ uint8 qresp_vsc[1]; -+ -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { -+ uint16 status; -+ uint16 cb_delay; -+ wifi_p2psd_adp_ie_t adp_ie; -+ uint16 qresp_len; -+ uint8 qresp_frm[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { -+ uint16 status; -+ uint8 fragment_id; -+ uint16 cb_delay; -+ wifi_p2psd_adp_ie_t adp_ie; -+ uint16 qresp_len; -+ uint8 qresp_frm[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; -+ -+ -+BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { -+ uint8 category; -+ uint8 action; -+ uint8 dialog_token; -+ uint8 query_data[1]; -+} BWL_POST_PACKED_STRUCT; -+typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; -+ -+ -+#include <packed_section_end.h> -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h -new file mode 100644 -index 00000000..a4900edd ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h -@@ -0,0 +1,75 @@ -+/* -+ * SD-SPI Protocol Standard -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sdspi.h 241182 2011-02-17 21:50:03Z $ -+ */ -+#ifndef _SD_SPI_H -+#define _SD_SPI_H -+ -+#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ -+#define SPI_START_S 31 -+#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ -+#define SPI_DIR_S 30 -+#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ -+#define SPI_CMD_INDEX_S 24 -+#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ -+#define SPI_RW_S 23 -+#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ -+#define SPI_FUNC_S 20 -+#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ -+#define SPI_RAW_S 19 -+#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ -+#define SPI_STUFF_S 18 -+#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ -+#define SPI_BLKMODE_S 19 -+#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ -+#define SPI_OPCODE_S 18 -+#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ -+#define SPI_ADDR_S 1 -+#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ -+#define SPI_STUFF0_S 0 -+ -+#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ -+#define SPI_RSP_START_S 7 -+#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ -+#define SPI_RSP_PARAM_ERR_S 6 -+#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ -+#define SPI_RSP_RFU5_S 5 -+#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ -+#define SPI_RSP_FUNC_ERR_S 4 -+#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ -+#define SPI_RSP_CRC_ERR_S 3 -+#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ -+#define SPI_RSP_ILL_CMD_S 2 -+#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ -+#define SPI_RSP_RFU1_S 1 -+#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ -+#define SPI_RSP_IDLE_S 0 -+ -+/* SD-SPI Protocol Definitions */ -+#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ -+#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ -+#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ -+#define SDSPI_START_BIT_MASK 0x80 -+ -+#endif /* _SD_SPI_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h -new file mode 100644 -index 00000000..9c94985c ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/vlan.h -@@ -0,0 +1,69 @@ -+/* -+ * 802.1Q VLAN protocol definitions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: vlan.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _vlan_h_ -+#define _vlan_h_ -+ -+#ifndef _TYPEDEFS_H_ -+#include <typedefs.h> -+#endif -+ -+ -+#include <packed_section_start.h> -+ -+#define VLAN_VID_MASK 0xfff -+#define VLAN_CFI_SHIFT 12 -+#define VLAN_PRI_SHIFT 13 -+ -+#define VLAN_PRI_MASK 7 -+ -+#define VLAN_TAG_LEN 4 -+#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) -+ -+#define VLAN_TPID 0x8100 -+ -+struct ethervlan_header { -+ uint8 ether_dhost[ETHER_ADDR_LEN]; -+ uint8 ether_shost[ETHER_ADDR_LEN]; -+ uint16 vlan_type; -+ uint16 vlan_tag; -+ uint16 ether_type; -+}; -+ -+#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) -+ -+ -+ -+#include <packed_section_end.h> -+ -+#define ETHERVLAN_MOVE_HDR(d, s) \ -+do { \ -+ struct ethervlan_header t; \ -+ t = *(struct ethervlan_header *)(s); \ -+ *(struct ethervlan_header *)(d) = t; \ -+} while (0) -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h -new file mode 100644 -index 00000000..5b640ec3 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h -@@ -0,0 +1,173 @@ -+/* -+ * Fundamental types and constants relating to WPA -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wpa.h 261155 2011-05-23 23:51:32Z $ -+ */ -+ -+#ifndef _proto_wpa_h_ -+#define _proto_wpa_h_ -+ -+#include <typedefs.h> -+#include <proto/ethernet.h> -+ -+ -+ -+#include <packed_section_start.h> -+ -+ -+ -+ -+#define DOT11_RC_INVALID_WPA_IE 13 -+#define DOT11_RC_MIC_FAILURE 14 -+#define DOT11_RC_4WH_TIMEOUT 15 -+#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 -+#define DOT11_RC_WPA_IE_MISMATCH 17 -+#define DOT11_RC_INVALID_MC_CIPHER 18 -+#define DOT11_RC_INVALID_UC_CIPHER 19 -+#define DOT11_RC_INVALID_AKMP 20 -+#define DOT11_RC_BAD_WPA_VERSION 21 -+#define DOT11_RC_INVALID_WPA_CAP 22 -+#define DOT11_RC_8021X_AUTH_FAIL 23 -+ -+#define WPA2_PMKID_LEN 16 -+ -+ -+typedef BWL_PRE_PACKED_STRUCT struct -+{ -+ uint8 tag; -+ uint8 length; -+ uint8 oui[3]; -+ uint8 oui_type; -+ BWL_PRE_PACKED_STRUCT struct { -+ uint8 low; -+ uint8 high; -+ } BWL_POST_PACKED_STRUCT version; -+} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; -+#define WPA_IE_OUITYPE_LEN 4 -+#define WPA_IE_FIXED_LEN 8 -+#define WPA_IE_TAG_FIXED_LEN 6 -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint8 tag; -+ uint8 length; -+ BWL_PRE_PACKED_STRUCT struct { -+ uint8 low; -+ uint8 high; -+ } BWL_POST_PACKED_STRUCT version; -+} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; -+#define WPA_RSN_IE_FIXED_LEN 4 -+#define WPA_RSN_IE_TAG_FIXED_LEN 2 -+typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; -+ -+ -+typedef BWL_PRE_PACKED_STRUCT struct -+{ -+ uint8 oui[3]; -+ uint8 type; -+} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; -+#define WPA_SUITE_LEN 4 -+ -+ -+typedef BWL_PRE_PACKED_STRUCT struct -+{ -+ BWL_PRE_PACKED_STRUCT struct { -+ uint8 low; -+ uint8 high; -+ } BWL_POST_PACKED_STRUCT count; -+ wpa_suite_t list[1]; -+} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; -+#define WPA_IE_SUITE_COUNT_LEN 2 -+typedef BWL_PRE_PACKED_STRUCT struct -+{ -+ BWL_PRE_PACKED_STRUCT struct { -+ uint8 low; -+ uint8 high; -+ } BWL_POST_PACKED_STRUCT count; -+ wpa_pmkid_t list[1]; -+} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; -+ -+ -+#define WPA_CIPHER_NONE 0 -+#define WPA_CIPHER_WEP_40 1 -+#define WPA_CIPHER_TKIP 2 -+#define WPA_CIPHER_AES_OCB 3 -+#define WPA_CIPHER_AES_CCM 4 -+#define WPA_CIPHER_WEP_104 5 -+#define WPA_CIPHER_BIP 6 -+#define WPA_CIPHER_TPK 7 -+ -+ -+#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ -+ (cipher) == WPA_CIPHER_WEP_40 || \ -+ (cipher) == WPA_CIPHER_WEP_104 || \ -+ (cipher) == WPA_CIPHER_TKIP || \ -+ (cipher) == WPA_CIPHER_AES_OCB || \ -+ (cipher) == WPA_CIPHER_AES_CCM || \ -+ (cipher) == WPA_CIPHER_TPK) -+ -+ -+ -+#define WPA_TKIP_CM_DETECT 60 -+#define WPA_TKIP_CM_BLOCK 60 -+ -+ -+#define RSN_CAP_LEN 2 -+ -+ -+#define RSN_CAP_PREAUTH 0x0001 -+#define RSN_CAP_NOPAIRWISE 0x0002 -+#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C -+#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 -+#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 -+#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 -+#define RSN_CAP_1_REPLAY_CNTR 0 -+#define RSN_CAP_2_REPLAY_CNTRS 1 -+#define RSN_CAP_4_REPLAY_CNTRS 2 -+#define RSN_CAP_16_REPLAY_CNTRS 3 -+#ifdef MFP -+#define RSN_CAP_MFPR 0x0040 -+#define RSN_CAP_MFPC 0x0080 -+#endif -+ -+ -+#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS -+#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS -+#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT -+#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK -+ -+ -+#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) -+ -+ -+#define WPA_CAP_LEN RSN_CAP_LEN -+#define WPA_PMKID_CNT_LEN 2 -+ -+#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH -+ -+#define WPA2_PMKID_COUNT_LEN 2 -+ -+ -+ -+#include <packed_section_end.h> -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h -new file mode 100644 -index 00000000..a605d012 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h -@@ -0,0 +1,2380 @@ -+/* -+ * SiliconBackplane Chipcommon core hardware definitions. -+ * -+ * The chipcommon core provides chip identification, SB control, -+ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, -+ * GPIO interface, extbus, and support for serial and parallel flashes. -+ * -+ * $Id: sbchipc.h 347614 2012-07-27 10:24:51Z $ -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ */ -+ -+#ifndef _SBCHIPC_H -+#define _SBCHIPC_H -+ -+#ifndef _LANGUAGE_ASSEMBLY -+ -+ -+#ifndef PAD -+#define _PADLINE(line) pad ## line -+#define _XSTR(line) _PADLINE(line) -+#define PAD _XSTR(__LINE__) -+#endif -+ -+typedef struct eci_prerev35 { -+ uint32 eci_output; -+ uint32 eci_control; -+ uint32 eci_inputlo; -+ uint32 eci_inputmi; -+ uint32 eci_inputhi; -+ uint32 eci_inputintpolaritylo; -+ uint32 eci_inputintpolaritymi; -+ uint32 eci_inputintpolarityhi; -+ uint32 eci_intmasklo; -+ uint32 eci_intmaskmi; -+ uint32 eci_intmaskhi; -+ uint32 eci_eventlo; -+ uint32 eci_eventmi; -+ uint32 eci_eventhi; -+ uint32 eci_eventmasklo; -+ uint32 eci_eventmaskmi; -+ uint32 eci_eventmaskhi; -+ uint32 PAD[3]; -+} eci_prerev35_t; -+ -+typedef struct eci_rev35 { -+ uint32 eci_outputlo; -+ uint32 eci_outputhi; -+ uint32 eci_controllo; -+ uint32 eci_controlhi; -+ uint32 eci_inputlo; -+ uint32 eci_inputhi; -+ uint32 eci_inputintpolaritylo; -+ uint32 eci_inputintpolarityhi; -+ uint32 eci_intmasklo; -+ uint32 eci_intmaskhi; -+ uint32 eci_eventlo; -+ uint32 eci_eventhi; -+ uint32 eci_eventmasklo; -+ uint32 eci_eventmaskhi; -+ uint32 eci_auxtx; -+ uint32 eci_auxrx; -+ uint32 eci_datatag; -+ uint32 eci_uartescvalue; -+ uint32 eci_autobaudctr; -+ uint32 eci_uartfifolevel; -+} eci_rev35_t; -+ -+typedef struct flash_config { -+ uint32 PAD[19]; -+ -+ uint32 flashstrconfig; -+} flash_config_t; -+ -+typedef volatile struct { -+ uint32 chipid; -+ uint32 capabilities; -+ uint32 corecontrol; -+ uint32 bist; -+ -+ -+ uint32 otpstatus; -+ uint32 otpcontrol; -+ uint32 otpprog; -+ uint32 otplayout; -+ -+ -+ uint32 intstatus; -+ uint32 intmask; -+ -+ -+ uint32 chipcontrol; -+ uint32 chipstatus; -+ -+ -+ uint32 jtagcmd; -+ uint32 jtagir; -+ uint32 jtagdr; -+ uint32 jtagctrl; -+ -+ -+ uint32 flashcontrol; -+ uint32 flashaddress; -+ uint32 flashdata; -+ uint32 otplayoutextension; -+ -+ -+ uint32 broadcastaddress; -+ uint32 broadcastdata; -+ -+ -+ uint32 gpiopullup; -+ uint32 gpiopulldown; -+ uint32 gpioin; -+ uint32 gpioout; -+ uint32 gpioouten; -+ uint32 gpiocontrol; -+ uint32 gpiointpolarity; -+ uint32 gpiointmask; -+ -+ -+ uint32 gpioevent; -+ uint32 gpioeventintmask; -+ -+ -+ uint32 watchdog; -+ -+ -+ uint32 gpioeventintpolarity; -+ -+ -+ uint32 gpiotimerval; -+ uint32 gpiotimeroutmask; -+ -+ -+ uint32 clockcontrol_n; -+ uint32 clockcontrol_sb; -+ uint32 clockcontrol_pci; -+ uint32 clockcontrol_m2; -+ uint32 clockcontrol_m3; -+ uint32 clkdiv; -+ uint32 gpiodebugsel; -+ uint32 capabilities_ext; -+ -+ -+ uint32 pll_on_delay; -+ uint32 fref_sel_delay; -+ uint32 slow_clk_ctl; -+ uint32 PAD; -+ -+ -+ uint32 system_clk_ctl; -+ uint32 clkstatestretch; -+ uint32 PAD[2]; -+ -+ -+ uint32 bp_addrlow; -+ uint32 bp_addrhigh; -+ uint32 bp_data; -+ uint32 PAD; -+ uint32 bp_indaccess; -+ -+ uint32 gsioctrl; -+ uint32 gsioaddress; -+ uint32 gsiodata; -+ -+ -+ uint32 clkdiv2; -+ -+ uint32 otpcontrol1; -+ uint32 fabid; -+ -+ -+ uint32 eromptr; -+ -+ -+ uint32 pcmcia_config; -+ uint32 pcmcia_memwait; -+ uint32 pcmcia_attrwait; -+ uint32 pcmcia_iowait; -+ uint32 ide_config; -+ uint32 ide_memwait; -+ uint32 ide_attrwait; -+ uint32 ide_iowait; -+ uint32 prog_config; -+ uint32 prog_waitcount; -+ uint32 flash_config; -+ uint32 flash_waitcount; -+ uint32 SECI_config; -+ uint32 SECI_status; -+ uint32 SECI_statusmask; -+ uint32 SECI_rxnibchanged; -+ -+ uint32 PAD[20]; -+ -+ -+ uint32 sromcontrol; -+ uint32 sromaddress; -+ uint32 sromdata; -+ uint32 PAD[1]; -+ -+ uint32 nflashctrl; -+ uint32 nflashconf; -+ uint32 nflashcoladdr; -+ uint32 nflashrowaddr; -+ uint32 nflashdata; -+ uint32 nflashwaitcnt0; -+ uint32 PAD[2]; -+ -+ uint32 seci_uart_data; -+ uint32 seci_uart_bauddiv; -+ uint32 seci_uart_fcr; -+ uint32 seci_uart_lcr; -+ uint32 seci_uart_mcr; -+ uint32 seci_uart_lsr; -+ uint32 seci_uart_msr; -+ uint32 seci_uart_baudadj; -+ -+ uint32 clk_ctl_st; -+ uint32 hw_war; -+ uint32 PAD[70]; -+ -+ -+ uint8 uart0data; -+ uint8 uart0imr; -+ uint8 uart0fcr; -+ uint8 uart0lcr; -+ uint8 uart0mcr; -+ uint8 uart0lsr; -+ uint8 uart0msr; -+ uint8 uart0scratch; -+ uint8 PAD[248]; -+ -+ uint8 uart1data; -+ uint8 uart1imr; -+ uint8 uart1fcr; -+ uint8 uart1lcr; -+ uint8 uart1mcr; -+ uint8 uart1lsr; -+ uint8 uart1msr; -+ uint8 uart1scratch; -+ uint32 PAD[126]; -+ -+ -+ -+ uint32 pmucontrol; -+ uint32 pmucapabilities; -+ uint32 pmustatus; -+ uint32 res_state; -+ uint32 res_pending; -+ uint32 pmutimer; -+ uint32 min_res_mask; -+ uint32 max_res_mask; -+ uint32 res_table_sel; -+ uint32 res_dep_mask; -+ uint32 res_updn_timer; -+ uint32 res_timer; -+ uint32 clkstretch; -+ uint32 pmuwatchdog; -+ uint32 gpiosel; -+ uint32 gpioenable; -+ uint32 res_req_timer_sel; -+ uint32 res_req_timer; -+ uint32 res_req_mask; -+ uint32 PAD; -+ uint32 chipcontrol_addr; -+ uint32 chipcontrol_data; -+ uint32 regcontrol_addr; -+ uint32 regcontrol_data; -+ uint32 pllcontrol_addr; -+ uint32 pllcontrol_data; -+ uint32 pmustrapopt; -+ uint32 pmu_xtalfreq; -+ uint32 retention_ctl; -+ uint32 PAD[3]; -+ uint32 retention_grpidx; -+ uint32 retention_grpctl; -+ uint32 PAD[94]; -+ uint16 sromotp[512]; -+#ifdef NFLASH_SUPPORT -+ -+ uint32 nand_revision; -+ uint32 nand_cmd_start; -+ uint32 nand_cmd_addr_x; -+ uint32 nand_cmd_addr; -+ uint32 nand_cmd_end_addr; -+ uint32 nand_cs_nand_select; -+ uint32 nand_cs_nand_xor; -+ uint32 PAD; -+ uint32 nand_spare_rd0; -+ uint32 nand_spare_rd4; -+ uint32 nand_spare_rd8; -+ uint32 nand_spare_rd12; -+ uint32 nand_spare_wr0; -+ uint32 nand_spare_wr4; -+ uint32 nand_spare_wr8; -+ uint32 nand_spare_wr12; -+ uint32 nand_acc_control; -+ uint32 PAD; -+ uint32 nand_config; -+ uint32 PAD; -+ uint32 nand_timing_1; -+ uint32 nand_timing_2; -+ uint32 nand_semaphore; -+ uint32 PAD; -+ uint32 nand_devid; -+ uint32 nand_devid_x; -+ uint32 nand_block_lock_status; -+ uint32 nand_intfc_status; -+ uint32 nand_ecc_corr_addr_x; -+ uint32 nand_ecc_corr_addr; -+ uint32 nand_ecc_unc_addr_x; -+ uint32 nand_ecc_unc_addr; -+ uint32 nand_read_error_count; -+ uint32 nand_corr_stat_threshold; -+ uint32 PAD[2]; -+ uint32 nand_read_addr_x; -+ uint32 nand_read_addr; -+ uint32 nand_page_program_addr_x; -+ uint32 nand_page_program_addr; -+ uint32 nand_copy_back_addr_x; -+ uint32 nand_copy_back_addr; -+ uint32 nand_block_erase_addr_x; -+ uint32 nand_block_erase_addr; -+ uint32 nand_inv_read_addr_x; -+ uint32 nand_inv_read_addr; -+ uint32 PAD[2]; -+ uint32 nand_blk_wr_protect; -+ uint32 PAD[3]; -+ uint32 nand_acc_control_cs1; -+ uint32 nand_config_cs1; -+ uint32 nand_timing_1_cs1; -+ uint32 nand_timing_2_cs1; -+ uint32 PAD[20]; -+ uint32 nand_spare_rd16; -+ uint32 nand_spare_rd20; -+ uint32 nand_spare_rd24; -+ uint32 nand_spare_rd28; -+ uint32 nand_cache_addr; -+ uint32 nand_cache_data; -+ uint32 nand_ctrl_config; -+ uint32 nand_ctrl_status; -+#endif -+ uint32 gci_corecaps0; -+ uint32 gci_corecaps1; -+ uint32 gci_corecaps2; -+ uint32 gci_corectrl; -+ uint32 gci_corestat; -+ uint32 PAD[11]; -+ uint32 gci_indirect_addr; -+ uint32 PAD[111]; -+ uint32 gci_chipctrl; -+} chipcregs_t; -+ -+#endif -+ -+ -+#define CC_CHIPID 0 -+#define CC_CAPABILITIES 4 -+#define CC_CHIPST 0x2c -+#define CC_EROMPTR 0xfc -+ -+#define CC_OTPST 0x10 -+#define CC_JTAGCMD 0x30 -+#define CC_JTAGIR 0x34 -+#define CC_JTAGDR 0x38 -+#define CC_JTAGCTRL 0x3c -+#define CC_GPIOPU 0x58 -+#define CC_GPIOPD 0x5c -+#define CC_GPIOIN 0x60 -+#define CC_GPIOOUT 0x64 -+#define CC_GPIOOUTEN 0x68 -+#define CC_GPIOCTRL 0x6c -+#define CC_GPIOPOL 0x70 -+#define CC_GPIOINTM 0x74 -+#define CC_WATCHDOG 0x80 -+#define CC_CLKC_N 0x90 -+#define CC_CLKC_M0 0x94 -+#define CC_CLKC_M1 0x98 -+#define CC_CLKC_M2 0x9c -+#define CC_CLKC_M3 0xa0 -+#define CC_CLKDIV 0xa4 -+#define CC_SYS_CLK_CTL 0xc0 -+#define CC_CLK_CTL_ST SI_CLK_CTL_ST -+#define PMU_CTL 0x600 -+#define PMU_CAP 0x604 -+#define PMU_ST 0x608 -+#define PMU_RES_STATE 0x60c -+#define PMU_TIMER 0x614 -+#define PMU_MIN_RES_MASK 0x618 -+#define PMU_MAX_RES_MASK 0x61c -+#define CC_CHIPCTL_ADDR 0x650 -+#define CC_CHIPCTL_DATA 0x654 -+#define PMU_REG_CONTROL_ADDR 0x658 -+#define PMU_REG_CONTROL_DATA 0x65C -+#define PMU_PLL_CONTROL_ADDR 0x660 -+#define PMU_PLL_CONTROL_DATA 0x664 -+#define CC_SROM_OTP 0x800 -+#define CC_GCI_INDIRECT_ADDR_REG 0xC40 -+#define CC_GCI_CHIP_CTRL_REG 0xE00 -+#define CC_GCI_CC_OFFSET_2 2 -+#define CC_GCI_CC_OFFSET_5 5 -+ -+#ifdef NFLASH_SUPPORT -+ -+#define CC_NAND_REVISION 0xC00 -+#define CC_NAND_CMD_START 0xC04 -+#define CC_NAND_CMD_ADDR 0xC0C -+#define CC_NAND_SPARE_RD_0 0xC20 -+#define CC_NAND_SPARE_RD_4 0xC24 -+#define CC_NAND_SPARE_RD_8 0xC28 -+#define CC_NAND_SPARE_RD_C 0xC2C -+#define CC_NAND_CONFIG 0xC48 -+#define CC_NAND_DEVID 0xC60 -+#define CC_NAND_DEVID_EXT 0xC64 -+#define CC_NAND_INTFC_STATUS 0xC6C -+#endif -+ -+ -+#define CID_ID_MASK 0x0000ffff -+#define CID_REV_MASK 0x000f0000 -+#define CID_REV_SHIFT 16 -+#define CID_PKG_MASK 0x00f00000 -+#define CID_PKG_SHIFT 20 -+#define CID_CC_MASK 0x0f000000 -+#define CID_CC_SHIFT 24 -+#define CID_TYPE_MASK 0xf0000000 -+#define CID_TYPE_SHIFT 28 -+ -+ -+#define CC_CAP_UARTS_MASK 0x00000003 -+#define CC_CAP_MIPSEB 0x00000004 -+#define CC_CAP_UCLKSEL 0x00000018 -+#define CC_CAP_UINTCLK 0x00000008 -+#define CC_CAP_UARTGPIO 0x00000020 -+#define CC_CAP_EXTBUS_MASK 0x000000c0 -+#define CC_CAP_EXTBUS_NONE 0x00000000 -+#define CC_CAP_EXTBUS_FULL 0x00000040 -+#define CC_CAP_EXTBUS_PROG 0x00000080 -+#define CC_CAP_FLASH_MASK 0x00000700 -+#define CC_CAP_PLL_MASK 0x00038000 -+#define CC_CAP_PWR_CTL 0x00040000 -+#define CC_CAP_OTPSIZE 0x00380000 -+#define CC_CAP_OTPSIZE_SHIFT 19 -+#define CC_CAP_OTPSIZE_BASE 5 -+#define CC_CAP_JTAGP 0x00400000 -+#define CC_CAP_ROM 0x00800000 -+#define CC_CAP_BKPLN64 0x08000000 -+#define CC_CAP_PMU 0x10000000 -+#define CC_CAP_ECI 0x20000000 -+#define CC_CAP_SROM 0x40000000 -+#define CC_CAP_NFLASH 0x80000000 -+ -+#define CC_CAP2_SECI 0x00000001 -+#define CC_CAP2_GSIO 0x00000002 -+ -+ -+#define CC_CAP_EXT_SECI_PRESENT 0x00000001 -+ -+ -+#define PLL_NONE 0x00000000 -+#define PLL_TYPE1 0x00010000 -+#define PLL_TYPE2 0x00020000 -+#define PLL_TYPE3 0x00030000 -+#define PLL_TYPE4 0x00008000 -+#define PLL_TYPE5 0x00018000 -+#define PLL_TYPE6 0x00028000 -+#define PLL_TYPE7 0x00038000 -+ -+ -+#define ILP_CLOCK 32000 -+ -+ -+#define ALP_CLOCK 20000000 -+ -+ -+#define HT_CLOCK 80000000 -+ -+ -+#define CC_UARTCLKO 0x00000001 -+#define CC_SE 0x00000002 -+#define CC_ASYNCGPIO 0x00000004 -+#define CC_UARTCLKEN 0x00000008 -+ -+ -+#define CHIPCTRL_4321A0_DEFAULT 0x3a4 -+#define CHIPCTRL_4321A1_DEFAULT 0x0a4 -+#define CHIPCTRL_4321_PLL_DOWN 0x800000 -+ -+ -+#define OTPS_OL_MASK 0x000000ff -+#define OTPS_OL_MFG 0x00000001 -+#define OTPS_OL_OR1 0x00000002 -+#define OTPS_OL_OR2 0x00000004 -+#define OTPS_OL_GU 0x00000008 -+#define OTPS_GUP_MASK 0x00000f00 -+#define OTPS_GUP_SHIFT 8 -+#define OTPS_GUP_HW 0x00000100 -+#define OTPS_GUP_SW 0x00000200 -+#define OTPS_GUP_CI 0x00000400 -+#define OTPS_GUP_FUSE 0x00000800 -+#define OTPS_READY 0x00001000 -+#define OTPS_RV(x) (1 << (16 + (x))) -+#define OTPS_RV_MASK 0x0fff0000 -+#define OTPS_PROGOK 0x40000000 -+ -+ -+#define OTPC_PROGSEL 0x00000001 -+#define OTPC_PCOUNT_MASK 0x0000000e -+#define OTPC_PCOUNT_SHIFT 1 -+#define OTPC_VSEL_MASK 0x000000f0 -+#define OTPC_VSEL_SHIFT 4 -+#define OTPC_TMM_MASK 0x00000700 -+#define OTPC_TMM_SHIFT 8 -+#define OTPC_ODM 0x00000800 -+#define OTPC_PROGEN 0x80000000 -+ -+ -+#define OTPC_40NM_PROGSEL_SHIFT 0 -+#define OTPC_40NM_PCOUNT_SHIFT 1 -+#define OTPC_40NM_PCOUNT_WR 0xA -+#define OTPC_40NM_PCOUNT_V1X 0xB -+#define OTPC_40NM_REGCSEL_SHIFT 5 -+#define OTPC_40NM_REGCSEL_DEF 0x4 -+#define OTPC_40NM_PROGIN_SHIFT 8 -+#define OTPC_40NM_R2X_SHIFT 10 -+#define OTPC_40NM_ODM_SHIFT 11 -+#define OTPC_40NM_DF_SHIFT 15 -+#define OTPC_40NM_VSEL_SHIFT 16 -+#define OTPC_40NM_VSEL_WR 0xA -+#define OTPC_40NM_VSEL_V1X 0xA -+#define OTPC_40NM_VSEL_R1X 0x5 -+#define OTPC_40NM_COFAIL_SHIFT 30 -+ -+#define OTPC1_CPCSEL_SHIFT 0 -+#define OTPC1_CPCSEL_DEF 6 -+#define OTPC1_TM_SHIFT 8 -+#define OTPC1_TM_WR 0x84 -+#define OTPC1_TM_V1X 0x84 -+#define OTPC1_TM_R1X 0x4 -+ -+ -+#define OTPP_COL_MASK 0x000000ff -+#define OTPP_COL_SHIFT 0 -+#define OTPP_ROW_MASK 0x0000ff00 -+#define OTPP_ROW_SHIFT 8 -+#define OTPP_OC_MASK 0x0f000000 -+#define OTPP_OC_SHIFT 24 -+#define OTPP_READERR 0x10000000 -+#define OTPP_VALUE_MASK 0x20000000 -+#define OTPP_VALUE_SHIFT 29 -+#define OTPP_START_BUSY 0x80000000 -+#define OTPP_READ 0x40000000 -+ -+ -+#define OTPL_HWRGN_OFF_MASK 0x00000FFF -+#define OTPL_HWRGN_OFF_SHIFT 0 -+#define OTPL_WRAP_REVID_MASK 0x00F80000 -+#define OTPL_WRAP_REVID_SHIFT 19 -+#define OTPL_WRAP_TYPE_MASK 0x00070000 -+#define OTPL_WRAP_TYPE_SHIFT 16 -+#define OTPL_WRAP_TYPE_65NM 0 -+#define OTPL_WRAP_TYPE_40NM 1 -+ -+ -+#define OTP_CISFORMAT_NEW 0x80000000 -+ -+ -+#define OTPPOC_READ 0 -+#define OTPPOC_BIT_PROG 1 -+#define OTPPOC_VERIFY 3 -+#define OTPPOC_INIT 4 -+#define OTPPOC_SET 5 -+#define OTPPOC_RESET 6 -+#define OTPPOC_OCST 7 -+#define OTPPOC_ROW_LOCK 8 -+#define OTPPOC_PRESCN_TEST 9 -+ -+ -+#define OTPPOC_READ_40NM 0 -+#define OTPPOC_PROG_ENABLE_40NM 1 -+#define OTPPOC_PROG_DISABLE_40NM 2 -+#define OTPPOC_VERIFY_40NM 3 -+#define OTPPOC_WORD_VERIFY_1_40NM 4 -+#define OTPPOC_ROW_LOCK_40NM 5 -+#define OTPPOC_STBY_40NM 6 -+#define OTPPOC_WAKEUP_40NM 7 -+#define OTPPOC_WORD_VERIFY_0_40NM 8 -+#define OTPPOC_PRESCN_TEST_40NM 9 -+#define OTPPOC_BIT_PROG_40NM 10 -+#define OTPPOC_WORDPROG_40NM 11 -+#define OTPPOC_BURNIN_40NM 12 -+#define OTPPOC_AUTORELOAD_40NM 13 -+#define OTPPOC_OVST_READ_40NM 14 -+#define OTPPOC_OVST_PROG_40NM 15 -+ -+ -+#define OTPLAYOUTEXT_FUSE_MASK 0x3FF -+ -+ -+ -+#define JTAGM_CREV_OLD 10 -+#define JTAGM_CREV_IRP 22 -+#define JTAGM_CREV_RTI 28 -+ -+ -+#define JCMD_START 0x80000000 -+#define JCMD_BUSY 0x80000000 -+#define JCMD_STATE_MASK 0x60000000 -+#define JCMD_STATE_TLR 0x00000000 -+#define JCMD_STATE_PIR 0x20000000 -+#define JCMD_STATE_PDR 0x40000000 -+#define JCMD_STATE_RTI 0x60000000 -+#define JCMD0_ACC_MASK 0x0000f000 -+#define JCMD0_ACC_IRDR 0x00000000 -+#define JCMD0_ACC_DR 0x00001000 -+#define JCMD0_ACC_IR 0x00002000 -+#define JCMD0_ACC_RESET 0x00003000 -+#define JCMD0_ACC_IRPDR 0x00004000 -+#define JCMD0_ACC_PDR 0x00005000 -+#define JCMD0_IRW_MASK 0x00000f00 -+#define JCMD_ACC_MASK 0x000f0000 -+#define JCMD_ACC_IRDR 0x00000000 -+#define JCMD_ACC_DR 0x00010000 -+#define JCMD_ACC_IR 0x00020000 -+#define JCMD_ACC_RESET 0x00030000 -+#define JCMD_ACC_IRPDR 0x00040000 -+#define JCMD_ACC_PDR 0x00050000 -+#define JCMD_ACC_PIR 0x00060000 -+#define JCMD_ACC_IRDR_I 0x00070000 -+#define JCMD_ACC_DR_I 0x00080000 -+#define JCMD_IRW_MASK 0x00001f00 -+#define JCMD_IRW_SHIFT 8 -+#define JCMD_DRW_MASK 0x0000003f -+ -+ -+#define JCTRL_FORCE_CLK 4 -+#define JCTRL_EXT_EN 2 -+#define JCTRL_EN 1 -+ -+ -+#define CLKD_SFLASH 0x0f000000 -+#define CLKD_SFLASH_SHIFT 24 -+#define CLKD_OTP 0x000f0000 -+#define CLKD_OTP_SHIFT 16 -+#define CLKD_JTAG 0x00000f00 -+#define CLKD_JTAG_SHIFT 8 -+#define CLKD_UART 0x000000ff -+ -+#define CLKD2_SROM 0x00000003 -+ -+ -+#define CI_GPIO 0x00000001 -+#define CI_EI 0x00000002 -+#define CI_TEMP 0x00000004 -+#define CI_SIRQ 0x00000008 -+#define CI_ECI 0x00000010 -+#define CI_PMU 0x00000020 -+#define CI_UART 0x00000040 -+#define CI_WDRESET 0x80000000 -+ -+ -+#define SCC_SS_MASK 0x00000007 -+#define SCC_SS_LPO 0x00000000 -+#define SCC_SS_XTAL 0x00000001 -+#define SCC_SS_PCI 0x00000002 -+#define SCC_LF 0x00000200 -+#define SCC_LP 0x00000400 -+#define SCC_FS 0x00000800 -+#define SCC_IP 0x00001000 -+#define SCC_XC 0x00002000 -+#define SCC_XP 0x00004000 -+#define SCC_CD_MASK 0xffff0000 -+#define SCC_CD_SHIFT 16 -+ -+ -+#define SYCC_IE 0x00000001 -+#define SYCC_AE 0x00000002 -+#define SYCC_FP 0x00000004 -+#define SYCC_AR 0x00000008 -+#define SYCC_HR 0x00000010 -+#define SYCC_CD_MASK 0xffff0000 -+#define SYCC_CD_SHIFT 16 -+ -+ -+#define BPIA_BYTEEN 0x0000000f -+#define BPIA_SZ1 0x00000001 -+#define BPIA_SZ2 0x00000003 -+#define BPIA_SZ4 0x00000007 -+#define BPIA_SZ8 0x0000000f -+#define BPIA_WRITE 0x00000100 -+#define BPIA_START 0x00000200 -+#define BPIA_BUSY 0x00000200 -+#define BPIA_ERROR 0x00000400 -+ -+ -+#define CF_EN 0x00000001 -+#define CF_EM_MASK 0x0000000e -+#define CF_EM_SHIFT 1 -+#define CF_EM_FLASH 0 -+#define CF_EM_SYNC 2 -+#define CF_EM_PCMCIA 4 -+#define CF_DS 0x00000010 -+#define CF_BS 0x00000020 -+#define CF_CD_MASK 0x000000c0 -+#define CF_CD_SHIFT 6 -+#define CF_CD_DIV2 0x00000000 -+#define CF_CD_DIV3 0x00000040 -+#define CF_CD_DIV4 0x00000080 -+#define CF_CE 0x00000100 -+#define CF_SB 0x00000200 -+ -+ -+#define PM_W0_MASK 0x0000003f -+#define PM_W1_MASK 0x00001f00 -+#define PM_W1_SHIFT 8 -+#define PM_W2_MASK 0x001f0000 -+#define PM_W2_SHIFT 16 -+#define PM_W3_MASK 0x1f000000 -+#define PM_W3_SHIFT 24 -+ -+ -+#define PA_W0_MASK 0x0000003f -+#define PA_W1_MASK 0x00001f00 -+#define PA_W1_SHIFT 8 -+#define PA_W2_MASK 0x001f0000 -+#define PA_W2_SHIFT 16 -+#define PA_W3_MASK 0x1f000000 -+#define PA_W3_SHIFT 24 -+ -+ -+#define PI_W0_MASK 0x0000003f -+#define PI_W1_MASK 0x00001f00 -+#define PI_W1_SHIFT 8 -+#define PI_W2_MASK 0x001f0000 -+#define PI_W2_SHIFT 16 -+#define PI_W3_MASK 0x1f000000 -+#define PI_W3_SHIFT 24 -+ -+ -+#define PW_W0_MASK 0x0000001f -+#define PW_W1_MASK 0x00001f00 -+#define PW_W1_SHIFT 8 -+#define PW_W2_MASK 0x001f0000 -+#define PW_W2_SHIFT 16 -+#define PW_W3_MASK 0x1f000000 -+#define PW_W3_SHIFT 24 -+ -+#define PW_W0 0x0000000c -+#define PW_W1 0x00000a00 -+#define PW_W2 0x00020000 -+#define PW_W3 0x01000000 -+ -+ -+#define FW_W0_MASK 0x0000003f -+#define FW_W1_MASK 0x00001f00 -+#define FW_W1_SHIFT 8 -+#define FW_W2_MASK 0x001f0000 -+#define FW_W2_SHIFT 16 -+#define FW_W3_MASK 0x1f000000 -+#define FW_W3_SHIFT 24 -+ -+ -+#define SRC_START 0x80000000 -+#define SRC_BUSY 0x80000000 -+#define SRC_OPCODE 0x60000000 -+#define SRC_OP_READ 0x00000000 -+#define SRC_OP_WRITE 0x20000000 -+#define SRC_OP_WRDIS 0x40000000 -+#define SRC_OP_WREN 0x60000000 -+#define SRC_OTPSEL 0x00000010 -+#define SRC_LOCK 0x00000008 -+#define SRC_SIZE_MASK 0x00000006 -+#define SRC_SIZE_1K 0x00000000 -+#define SRC_SIZE_4K 0x00000002 -+#define SRC_SIZE_16K 0x00000004 -+#define SRC_SIZE_SHIFT 1 -+#define SRC_PRESENT 0x00000001 -+ -+ -+#define PCTL_ILP_DIV_MASK 0xffff0000 -+#define PCTL_ILP_DIV_SHIFT 16 -+#define PCTL_PLL_PLLCTL_UPD 0x00000400 -+#define PCTL_NOILP_ON_WAIT 0x00000200 -+#define PCTL_HT_REQ_EN 0x00000100 -+#define PCTL_ALP_REQ_EN 0x00000080 -+#define PCTL_XTALFREQ_MASK 0x0000007c -+#define PCTL_XTALFREQ_SHIFT 2 -+#define PCTL_ILP_DIV_EN 0x00000002 -+#define PCTL_LPO_SEL 0x00000001 -+ -+ -+#define CSTRETCH_HT 0xffff0000 -+#define CSTRETCH_ALP 0x0000ffff -+ -+ -+#define GPIO_ONTIME_SHIFT 16 -+ -+ -+#define CN_N1_MASK 0x3f -+#define CN_N2_MASK 0x3f00 -+#define CN_N2_SHIFT 8 -+#define CN_PLLC_MASK 0xf0000 -+#define CN_PLLC_SHIFT 16 -+ -+ -+#define CC_M1_MASK 0x3f -+#define CC_M2_MASK 0x3f00 -+#define CC_M2_SHIFT 8 -+#define CC_M3_MASK 0x3f0000 -+#define CC_M3_SHIFT 16 -+#define CC_MC_MASK 0x1f000000 -+#define CC_MC_SHIFT 24 -+ -+ -+#define CC_F6_2 0x02 -+#define CC_F6_3 0x03 -+#define CC_F6_4 0x05 -+#define CC_F6_5 0x09 -+#define CC_F6_6 0x11 -+#define CC_F6_7 0x21 -+ -+#define CC_F5_BIAS 5 -+ -+#define CC_MC_BYPASS 0x08 -+#define CC_MC_M1 0x04 -+#define CC_MC_M1M2 0x02 -+#define CC_MC_M1M2M3 0x01 -+#define CC_MC_M1M3 0x11 -+ -+ -+#define CC_T2_BIAS 2 -+#define CC_T2M2_BIAS 3 -+ -+#define CC_T2MC_M1BYP 1 -+#define CC_T2MC_M2BYP 2 -+#define CC_T2MC_M3BYP 4 -+ -+ -+#define CC_T6_MMASK 1 -+#define CC_T6_M0 120000000 -+#define CC_T6_M1 100000000 -+#define SB2MIPS_T6(sb) (2 * (sb)) -+ -+ -+#define CC_CLOCK_BASE1 24000000 -+#define CC_CLOCK_BASE2 12500000 -+ -+ -+#define CLKC_5350_N 0x0311 -+#define CLKC_5350_M 0x04020009 -+ -+ -+#define FLASH_NONE 0x000 -+#define SFLASH_ST 0x100 -+#define SFLASH_AT 0x200 -+#define NFLASH 0x300 -+#define PFLASH 0x700 -+ -+ -+#define CC_CFG_EN 0x0001 -+#define CC_CFG_EM_MASK 0x000e -+#define CC_CFG_EM_ASYNC 0x0000 -+#define CC_CFG_EM_SYNC 0x0002 -+#define CC_CFG_EM_PCMCIA 0x0004 -+#define CC_CFG_EM_IDE 0x0006 -+#define CC_CFG_DS 0x0010 -+#define CC_CFG_CD_MASK 0x00e0 -+#define CC_CFG_CE 0x0100 -+#define CC_CFG_SB 0x0200 -+#define CC_CFG_IS 0x0400 -+ -+ -+#define CC_EB_BASE 0x1a000000 -+#define CC_EB_PCMCIA_MEM 0x1a000000 -+#define CC_EB_PCMCIA_IO 0x1a200000 -+#define CC_EB_PCMCIA_CFG 0x1a400000 -+#define CC_EB_IDE 0x1a800000 -+#define CC_EB_PCMCIA1_MEM 0x1a800000 -+#define CC_EB_PCMCIA1_IO 0x1aa00000 -+#define CC_EB_PCMCIA1_CFG 0x1ac00000 -+#define CC_EB_PROGIF 0x1b000000 -+ -+ -+ -+#define SFLASH_OPCODE 0x000000ff -+#define SFLASH_ACTION 0x00000700 -+#define SFLASH_CS_ACTIVE 0x00001000 -+#define SFLASH_START 0x80000000 -+#define SFLASH_BUSY SFLASH_START -+ -+ -+#define SFLASH_ACT_OPONLY 0x0000 -+#define SFLASH_ACT_OP1D 0x0100 -+#define SFLASH_ACT_OP3A 0x0200 -+#define SFLASH_ACT_OP3A1D 0x0300 -+#define SFLASH_ACT_OP3A4D 0x0400 -+#define SFLASH_ACT_OP3A4X4D 0x0500 -+#define SFLASH_ACT_OP3A1X4D 0x0700 -+ -+ -+#define SFLASH_ST_WREN 0x0006 -+#define SFLASH_ST_WRDIS 0x0004 -+#define SFLASH_ST_RDSR 0x0105 -+#define SFLASH_ST_WRSR 0x0101 -+#define SFLASH_ST_READ 0x0303 -+#define SFLASH_ST_PP 0x0302 -+#define SFLASH_ST_SE 0x02d8 -+#define SFLASH_ST_BE 0x00c7 -+#define SFLASH_ST_DP 0x00b9 -+#define SFLASH_ST_RES 0x03ab -+#define SFLASH_ST_CSA 0x1000 -+#define SFLASH_ST_SSE 0x0220 -+ -+#define SFLASH_MXIC_RDID 0x0390 -+#define SFLASH_MXIC_MFID 0xc2 -+ -+ -+#define SFLASH_ST_WIP 0x01 -+#define SFLASH_ST_WEL 0x02 -+#define SFLASH_ST_BP_MASK 0x1c -+#define SFLASH_ST_BP_SHIFT 2 -+#define SFLASH_ST_SRWD 0x80 -+ -+ -+#define SFLASH_AT_READ 0x07e8 -+#define SFLASH_AT_PAGE_READ 0x07d2 -+#define SFLASH_AT_BUF1_READ -+#define SFLASH_AT_BUF2_READ -+#define SFLASH_AT_STATUS 0x01d7 -+#define SFLASH_AT_BUF1_WRITE 0x0384 -+#define SFLASH_AT_BUF2_WRITE 0x0387 -+#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 -+#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 -+#define SFLASH_AT_BUF1_PROGRAM 0x0288 -+#define SFLASH_AT_BUF2_PROGRAM 0x0289 -+#define SFLASH_AT_PAGE_ERASE 0x0281 -+#define SFLASH_AT_BLOCK_ERASE 0x0250 -+#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 -+#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 -+#define SFLASH_AT_BUF1_LOAD 0x0253 -+#define SFLASH_AT_BUF2_LOAD 0x0255 -+#define SFLASH_AT_BUF1_COMPARE 0x0260 -+#define SFLASH_AT_BUF2_COMPARE 0x0261 -+#define SFLASH_AT_BUF1_REPROGRAM 0x0258 -+#define SFLASH_AT_BUF2_REPROGRAM 0x0259 -+ -+ -+#define SFLASH_AT_READY 0x80 -+#define SFLASH_AT_MISMATCH 0x40 -+#define SFLASH_AT_ID_MASK 0x38 -+#define SFLASH_AT_ID_SHIFT 3 -+ -+ -+#define GSIO_START 0x80000000 -+#define GSIO_BUSY GSIO_START -+ -+ -+ -+#define UART_RX 0 -+#define UART_TX 0 -+#define UART_DLL 0 -+#define UART_IER 1 -+#define UART_DLM 1 -+#define UART_IIR 2 -+#define UART_FCR 2 -+#define UART_LCR 3 -+#define UART_MCR 4 -+#define UART_LSR 5 -+#define UART_MSR 6 -+#define UART_SCR 7 -+#define UART_LCR_DLAB 0x80 -+#define UART_LCR_WLEN8 0x03 -+#define UART_MCR_OUT2 0x08 -+#define UART_MCR_LOOP 0x10 -+#define UART_LSR_RX_FIFO 0x80 -+#define UART_LSR_TDHR 0x40 -+#define UART_LSR_THRE 0x20 -+#define UART_LSR_BREAK 0x10 -+#define UART_LSR_FRAMING 0x08 -+#define UART_LSR_PARITY 0x04 -+#define UART_LSR_OVERRUN 0x02 -+#define UART_LSR_RXRDY 0x01 -+#define UART_FCR_FIFO_ENABLE 1 -+ -+ -+#define UART_IIR_FIFO_MASK 0xc0 -+#define UART_IIR_INT_MASK 0xf -+#define UART_IIR_MDM_CHG 0x0 -+#define UART_IIR_NOINT 0x1 -+#define UART_IIR_THRE 0x2 -+#define UART_IIR_RCVD_DATA 0x4 -+#define UART_IIR_RCVR_STATUS 0x6 -+#define UART_IIR_CHAR_TIME 0xc -+ -+ -+#define UART_IER_EDSSI 8 -+#define UART_IER_ELSI 4 -+#define UART_IER_ETBEI 2 -+#define UART_IER_ERBFI 1 -+ -+ -+#define PST_EXTLPOAVAIL 0x0100 -+#define PST_WDRESET 0x0080 -+#define PST_INTPEND 0x0040 -+#define PST_SBCLKST 0x0030 -+#define PST_SBCLKST_ILP 0x0010 -+#define PST_SBCLKST_ALP 0x0020 -+#define PST_SBCLKST_HT 0x0030 -+#define PST_ALPAVAIL 0x0008 -+#define PST_HTAVAIL 0x0004 -+#define PST_RESINIT 0x0003 -+ -+ -+#define PCAP_REV_MASK 0x000000ff -+#define PCAP_RC_MASK 0x00001f00 -+#define PCAP_RC_SHIFT 8 -+#define PCAP_TC_MASK 0x0001e000 -+#define PCAP_TC_SHIFT 13 -+#define PCAP_PC_MASK 0x001e0000 -+#define PCAP_PC_SHIFT 17 -+#define PCAP_VC_MASK 0x01e00000 -+#define PCAP_VC_SHIFT 21 -+#define PCAP_CC_MASK 0x1e000000 -+#define PCAP_CC_SHIFT 25 -+#define PCAP5_PC_MASK 0x003e0000 -+#define PCAP5_PC_SHIFT 17 -+#define PCAP5_VC_MASK 0x07c00000 -+#define PCAP5_VC_SHIFT 22 -+#define PCAP5_CC_MASK 0xf8000000 -+#define PCAP5_CC_SHIFT 27 -+ -+ -+ -+#define PRRT_TIME_MASK 0x03ff -+#define PRRT_INTEN 0x0400 -+#define PRRT_REQ_ACTIVE 0x0800 -+#define PRRT_ALP_REQ 0x1000 -+#define PRRT_HT_REQ 0x2000 -+#define PRRT_HQ_REQ 0x4000 -+ -+ -+#define PMURES_BIT(bit) (1 << (bit)) -+ -+ -+#define PMURES_MAX_RESNUM 30 -+ -+ -+#define PMU_CHIPCTL0 0 -+ -+ -+#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 -+#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) -+ -+#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 -+#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 -+ -+ -+#define PMU_CHIPCTL1 1 -+#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 -+ -+#define PMU_CC1_IF_TYPE_MASK 0x00000030 -+#define PMU_CC1_IF_TYPE_RMII 0x00000000 -+#define PMU_CC1_IF_TYPE_MII 0x00000010 -+#define PMU_CC1_IF_TYPE_RGMII 0x00000020 -+ -+#define PMU_CC1_SW_TYPE_MASK 0x000000c0 -+#define PMU_CC1_SW_TYPE_EPHY 0x00000000 -+#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 -+#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 -+#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 -+ -+ -+#define PMU_CHIPCTL2 2 -+ -+ -+#define PMU_CHIPCTL3 3 -+ -+#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 -+#define PMU_CC3_ENABLE_RF_SHIFT 22 -+#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 -+ -+ -+ -+ -+ -+#define PMU0_PLL0_PLLCTL0 0 -+#define PMU0_PLL0_PC0_PDIV_MASK 1 -+#define PMU0_PLL0_PC0_PDIV_FREQ 25000 -+#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 -+#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 -+#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 -+ -+ -+#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 -+#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 -+#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 -+#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 -+#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 -+#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 -+#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 -+#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 -+ -+ -+#define PMU0_PLL0_PLLCTL1 1 -+#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 -+#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 -+#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 -+#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 -+#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 -+ -+ -+#define PMU0_PLL0_PLLCTL2 2 -+#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf -+#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 -+ -+ -+ -+#define PMU1_PLL0_PLLCTL0 0 -+#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 -+#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 -+#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 -+#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 -+ -+ -+#define PMU1_PLL0_PLLCTL1 1 -+#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff -+#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 -+#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 -+#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 -+#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 -+#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 -+#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 -+#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 -+#define PMU1_PLL0_PC1_M4DIV_BY_9 9 -+#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 -+#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 -+ -+#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 -+#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) -+#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) -+ -+ -+#define PMU1_PLL0_PLLCTL2 2 -+#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff -+#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 -+#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc -+#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 -+#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 -+#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 -+#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 -+#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 -+#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 -+#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 -+#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 -+#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 -+#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 -+#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 -+#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 -+ -+ -+#define PMU1_PLL0_PLLCTL3 3 -+#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff -+#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 -+ -+ -+#define PMU1_PLL0_PLLCTL4 4 -+ -+ -+#define PMU1_PLL0_PLLCTL5 5 -+#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 -+#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 -+ -+ -+#define PMU2_PHY_PLL_PLLCTL 4 -+#define PMU2_SI_PLL_PLLCTL 10 -+ -+ -+ -+ -+#define PMU2_PLL_PLLCTL0 0 -+#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 -+#define PMU2_PLL_PC0_P1DIV_SHIFT 20 -+#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 -+#define PMU2_PLL_PC0_P2DIV_SHIFT 24 -+ -+ -+#define PMU2_PLL_PLLCTL1 1 -+#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff -+#define PMU2_PLL_PC1_M1DIV_SHIFT 0 -+#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 -+#define PMU2_PLL_PC1_M2DIV_SHIFT 8 -+#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 -+#define PMU2_PLL_PC1_M3DIV_SHIFT 16 -+#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 -+#define PMU2_PLL_PC1_M4DIV_SHIFT 24 -+ -+ -+#define PMU2_PLL_PLLCTL2 2 -+#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff -+#define PMU2_PLL_PC2_M5DIV_SHIFT 0 -+#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 -+#define PMU2_PLL_PC2_M6DIV_SHIFT 8 -+#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 -+#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 -+#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 -+#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 -+ -+ -+#define PMU2_PLL_PLLCTL3 3 -+#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff -+#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 -+ -+ -+#define PMU2_PLL_PLLCTL4 4 -+ -+ -+#define PMU2_PLL_PLLCTL5 5 -+#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 -+#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 -+#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 -+#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 -+#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 -+#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 -+#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 -+#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 -+#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 -+#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 -+#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 -+#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 -+ -+ -+#define PMU5_PLL_P1P2_OFF 0 -+#define PMU5_PLL_P1_MASK 0x0f000000 -+#define PMU5_PLL_P1_SHIFT 24 -+#define PMU5_PLL_P2_MASK 0x00f00000 -+#define PMU5_PLL_P2_SHIFT 20 -+#define PMU5_PLL_M14_OFF 1 -+#define PMU5_PLL_MDIV_MASK 0x000000ff -+#define PMU5_PLL_MDIV_WIDTH 8 -+#define PMU5_PLL_NM5_OFF 2 -+#define PMU5_PLL_NDIV_MASK 0xfff00000 -+#define PMU5_PLL_NDIV_SHIFT 20 -+#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 -+#define PMU5_PLL_NDIV_MODE_SHIFT 17 -+#define PMU5_PLL_FMAB_OFF 3 -+#define PMU5_PLL_MRAT_MASK 0xf0000000 -+#define PMU5_PLL_MRAT_SHIFT 28 -+#define PMU5_PLL_ABRAT_MASK 0x08000000 -+#define PMU5_PLL_ABRAT_SHIFT 27 -+#define PMU5_PLL_FDIV_MASK 0x07ffffff -+#define PMU5_PLL_PLLCTL_OFF 4 -+#define PMU5_PLL_PCHI_OFF 5 -+#define PMU5_PLL_PCHI_MASK 0x0000003f -+ -+ -+#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF -+#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 -+#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 -+ -+ -+#define PMU5_MAINPLL_CPU 1 -+#define PMU5_MAINPLL_MEM 2 -+#define PMU5_MAINPLL_SI 3 -+ -+ -+#define PMU4706_MAINPLL_PLL0 0 -+#define PMU6_4706_PROCPLL_OFF 4 -+#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 -+#define PMU6_4706_PROC_P2DIV_SHIFT 16 -+#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 -+#define PMU6_4706_PROC_P1DIV_SHIFT 12 -+#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 -+#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 -+#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 -+#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 -+ -+#define PMU7_PLL_PLLCTL7 7 -+#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 -+#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 -+#define PMU7_PLL_CTL7_M4DIV_BY_6 6 -+#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc -+#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 -+#define PMU7_PLL_PLLCTL8 8 -+#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff -+#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 -+#define PMU7_PLL_CTL8_M5DIV_BY_8 8 -+#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc -+#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 -+#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 -+#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 -+#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc -+#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 -+#define PMU7_PLL_PLLCTL11 11 -+#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 -+#define PMU7_PLL_PLLCTL11_VAL 0x22222200 -+ -+ -+#define PMU15_PLL_PLLCTL0 0 -+#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 -+#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 -+#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC -+#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 -+#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 -+#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 -+#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 -+#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 -+#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 -+#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 -+#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 -+#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 -+#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 -+#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 -+ -+#define PMU15_PLL_PLLCTL1 1 -+#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 -+#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 -+#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 -+#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 -+#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 -+#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 -+#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 -+#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 -+#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 -+#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 -+#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 -+#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 -+#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 -+#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 -+ -+#define PMU15_PLL_PLLCTL2 2 -+#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 -+#define PMU15_PLL_PC2_CTEN_SHIFT 0 -+ -+#define PMU15_PLL_PLLCTL3 3 -+#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 -+#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 -+#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 -+#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 -+#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 -+#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 -+#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 -+#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 -+#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 -+#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 -+#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 -+#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 -+#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 -+#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 -+#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 -+#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 -+#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 -+#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 -+ -+#define PMU15_PLL_PLLCTL4 4 -+#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 -+#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 -+#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 -+#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 -+#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 -+#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 -+#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 -+#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 -+#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 -+#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 -+#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 -+#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 -+#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 -+#define PMU15_PLL_PC4_DINPOL_SHIFT 20 -+#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 -+#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 -+#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 -+#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 -+#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 -+#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 -+#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 -+#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 -+#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 -+#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 -+#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 -+#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 -+ -+#define PMU15_PLL_PLLCTL5 5 -+#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF -+#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 -+#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 -+#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 -+#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 -+#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 -+ -+#define PMU15_PLL_PLLCTL6 6 -+#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF -+#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 -+#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 -+#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 -+#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 -+#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 -+ -+#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 -+#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 -+#define PMU15_ARM_96MHZ 96000000 -+#define PMU15_ARM_98MHZ 98400000 -+#define PMU15_ARM_97MHZ 97000000 -+ -+ -+#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 -+#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 -+ -+#define PMU17_PLLCTL2_NDIV_MODE_INT 0 -+#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 -+#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 -+#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 -+ -+#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 -+#define PMU17_PLLCTL0_BBPLL_DRST 3 -+#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 -+ -+ -+#define PMU4716_MAINPLL_PLL0 12 -+ -+ -+#define PMU5356_MAINPLL_PLL0 0 -+#define PMU5357_MAINPLL_PLL0 0 -+ -+ -+#define RES4716_PROC_PLL_ON 0x00000040 -+#define RES4716_PROC_HT_AVAIL 0x00000080 -+ -+ -+#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 -+ -+ -+ -+#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 -+#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 -+ -+ -+#define RES5354_EXT_SWITCHER_PWM 0 -+#define RES5354_BB_SWITCHER_PWM 1 -+#define RES5354_BB_SWITCHER_BURST 2 -+#define RES5354_BB_EXT_SWITCHER_BURST 3 -+#define RES5354_ILP_REQUEST 4 -+#define RES5354_RADIO_SWITCHER_PWM 5 -+#define RES5354_RADIO_SWITCHER_BURST 6 -+#define RES5354_ROM_SWITCH 7 -+#define RES5354_PA_REF_LDO 8 -+#define RES5354_RADIO_LDO 9 -+#define RES5354_AFE_LDO 10 -+#define RES5354_PLL_LDO 11 -+#define RES5354_BG_FILTBYP 12 -+#define RES5354_TX_FILTBYP 13 -+#define RES5354_RX_FILTBYP 14 -+#define RES5354_XTAL_PU 15 -+#define RES5354_XTAL_EN 16 -+#define RES5354_BB_PLL_FILTBYP 17 -+#define RES5354_RF_PLL_FILTBYP 18 -+#define RES5354_BB_PLL_PU 19 -+ -+ -+#define CCTRL5357_EXTPA (1<<14) -+#define CCTRL5357_ANT_MUX_2o3 (1<<15) -+#define CCTRL5357_NFLASH (1<<16) -+ -+ -+#define CCTRL43217_EXTPA_C0 (1<<13) -+#define CCTRL43217_EXTPA_C1 (1<<8) -+ -+ -+#define RES4328_EXT_SWITCHER_PWM 0 -+#define RES4328_BB_SWITCHER_PWM 1 -+#define RES4328_BB_SWITCHER_BURST 2 -+#define RES4328_BB_EXT_SWITCHER_BURST 3 -+#define RES4328_ILP_REQUEST 4 -+#define RES4328_RADIO_SWITCHER_PWM 5 -+#define RES4328_RADIO_SWITCHER_BURST 6 -+#define RES4328_ROM_SWITCH 7 -+#define RES4328_PA_REF_LDO 8 -+#define RES4328_RADIO_LDO 9 -+#define RES4328_AFE_LDO 10 -+#define RES4328_PLL_LDO 11 -+#define RES4328_BG_FILTBYP 12 -+#define RES4328_TX_FILTBYP 13 -+#define RES4328_RX_FILTBYP 14 -+#define RES4328_XTAL_PU 15 -+#define RES4328_XTAL_EN 16 -+#define RES4328_BB_PLL_FILTBYP 17 -+#define RES4328_RF_PLL_FILTBYP 18 -+#define RES4328_BB_PLL_PU 19 -+ -+ -+#define RES4325_BUCK_BOOST_BURST 0 -+#define RES4325_CBUCK_BURST 1 -+#define RES4325_CBUCK_PWM 2 -+#define RES4325_CLDO_CBUCK_BURST 3 -+#define RES4325_CLDO_CBUCK_PWM 4 -+#define RES4325_BUCK_BOOST_PWM 5 -+#define RES4325_ILP_REQUEST 6 -+#define RES4325_ABUCK_BURST 7 -+#define RES4325_ABUCK_PWM 8 -+#define RES4325_LNLDO1_PU 9 -+#define RES4325_OTP_PU 10 -+#define RES4325_LNLDO3_PU 11 -+#define RES4325_LNLDO4_PU 12 -+#define RES4325_XTAL_PU 13 -+#define RES4325_ALP_AVAIL 14 -+#define RES4325_RX_PWRSW_PU 15 -+#define RES4325_TX_PWRSW_PU 16 -+#define RES4325_RFPLL_PWRSW_PU 17 -+#define RES4325_LOGEN_PWRSW_PU 18 -+#define RES4325_AFE_PWRSW_PU 19 -+#define RES4325_BBPLL_PWRSW_PU 20 -+#define RES4325_HT_AVAIL 21 -+ -+ -+#define RES4325B0_CBUCK_LPOM 1 -+#define RES4325B0_CBUCK_BURST 2 -+#define RES4325B0_CBUCK_PWM 3 -+#define RES4325B0_CLDO_PU 4 -+ -+ -+#define RES4325C1_LNLDO2_PU 12 -+ -+ -+#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 -+#define CST4325_DEFCIS_SEL 0 -+#define CST4325_SPROM_SEL 1 -+#define CST4325_OTP_SEL 2 -+#define CST4325_OTP_PWRDN 3 -+#define CST4325_SDIO_USB_MODE_MASK 0x00000004 -+#define CST4325_SDIO_USB_MODE_SHIFT 2 -+#define CST4325_RCAL_VALID_MASK 0x00000008 -+#define CST4325_RCAL_VALID_SHIFT 3 -+#define CST4325_RCAL_VALUE_MASK 0x000001f0 -+#define CST4325_RCAL_VALUE_SHIFT 4 -+#define CST4325_PMUTOP_2B_MASK 0x00000200 -+#define CST4325_PMUTOP_2B_SHIFT 9 -+ -+#define RES4329_RESERVED0 0 -+#define RES4329_CBUCK_LPOM 1 -+#define RES4329_CBUCK_BURST 2 -+#define RES4329_CBUCK_PWM 3 -+#define RES4329_CLDO_PU 4 -+#define RES4329_PALDO_PU 5 -+#define RES4329_ILP_REQUEST 6 -+#define RES4329_RESERVED7 7 -+#define RES4329_RESERVED8 8 -+#define RES4329_LNLDO1_PU 9 -+#define RES4329_OTP_PU 10 -+#define RES4329_RESERVED11 11 -+#define RES4329_LNLDO2_PU 12 -+#define RES4329_XTAL_PU 13 -+#define RES4329_ALP_AVAIL 14 -+#define RES4329_RX_PWRSW_PU 15 -+#define RES4329_TX_PWRSW_PU 16 -+#define RES4329_RFPLL_PWRSW_PU 17 -+#define RES4329_LOGEN_PWRSW_PU 18 -+#define RES4329_AFE_PWRSW_PU 19 -+#define RES4329_BBPLL_PWRSW_PU 20 -+#define RES4329_HT_AVAIL 21 -+ -+#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 -+#define CST4329_DEFCIS_SEL 0 -+#define CST4329_SPROM_SEL 1 -+#define CST4329_OTP_SEL 2 -+#define CST4329_OTP_PWRDN 3 -+#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 -+#define CST4329_SPI_SDIO_MODE_SHIFT 2 -+ -+ -+#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 -+#define CST4312_DEFCIS_SEL 0 -+#define CST4312_SPROM_SEL 1 -+#define CST4312_OTP_SEL 2 -+#define CST4312_OTP_BAD 3 -+ -+ -+#define RES4312_SWITCHER_BURST 0 -+#define RES4312_SWITCHER_PWM 1 -+#define RES4312_PA_REF_LDO 2 -+#define RES4312_CORE_LDO_BURST 3 -+#define RES4312_CORE_LDO_PWM 4 -+#define RES4312_RADIO_LDO 5 -+#define RES4312_ILP_REQUEST 6 -+#define RES4312_BG_FILTBYP 7 -+#define RES4312_TX_FILTBYP 8 -+#define RES4312_RX_FILTBYP 9 -+#define RES4312_XTAL_PU 10 -+#define RES4312_ALP_AVAIL 11 -+#define RES4312_BB_PLL_FILTBYP 12 -+#define RES4312_RF_PLL_FILTBYP 13 -+#define RES4312_HT_AVAIL 14 -+ -+ -+#define RES4322_RF_LDO 0 -+#define RES4322_ILP_REQUEST 1 -+#define RES4322_XTAL_PU 2 -+#define RES4322_ALP_AVAIL 3 -+#define RES4322_SI_PLL_ON 4 -+#define RES4322_HT_SI_AVAIL 5 -+#define RES4322_PHY_PLL_ON 6 -+#define RES4322_HT_PHY_AVAIL 7 -+#define RES4322_OTP_PU 8 -+ -+ -+#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 -+#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 -+#define CST4322_SPROM_OTP_SEL_SHIFT 6 -+#define CST4322_NO_SPROM_OTP 0 -+#define CST4322_SPROM_PRESENT 1 -+#define CST4322_OTP_PRESENT 2 -+#define CST4322_PCI_OR_USB 0x00000100 -+#define CST4322_BOOT_MASK 0x00000600 -+#define CST4322_BOOT_SHIFT 9 -+#define CST4322_BOOT_FROM_SRAM 0 -+#define CST4322_BOOT_FROM_ROM 1 -+#define CST4322_BOOT_FROM_FLASH 2 -+#define CST4322_BOOT_FROM_INVALID 3 -+#define CST4322_ILP_DIV_EN 0x00000800 -+#define CST4322_FLASH_TYPE_MASK 0x00001000 -+#define CST4322_FLASH_TYPE_SHIFT 12 -+#define CST4322_FLASH_TYPE_SHIFT_ST 0 -+#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 -+#define CST4322_ARM_TAP_SEL 0x00002000 -+#define CST4322_RES_INIT_MODE_MASK 0x0000c000 -+#define CST4322_RES_INIT_MODE_SHIFT 14 -+#define CST4322_RES_INIT_MODE_ILPAVAIL 0 -+#define CST4322_RES_INIT_MODE_ILPREQ 1 -+#define CST4322_RES_INIT_MODE_ALPAVAIL 2 -+#define CST4322_RES_INIT_MODE_HTAVAIL 3 -+#define CST4322_PCIPLLCLK_GATING 0x00010000 -+#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 -+#define CST4322_PCI_CARDBUS_MODE 0x00040000 -+ -+ -+#define CCTRL43224_GPIO_TOGGLE 0x8000 -+#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 -+#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 -+ -+ -+#define RES43236_REGULATOR 0 -+#define RES43236_ILP_REQUEST 1 -+#define RES43236_XTAL_PU 2 -+#define RES43236_ALP_AVAIL 3 -+#define RES43236_SI_PLL_ON 4 -+#define RES43236_HT_SI_AVAIL 5 -+ -+ -+#define CCTRL43236_BT_COEXIST (1<<0) -+#define CCTRL43236_SECI (1<<1) -+#define CCTRL43236_EXT_LNA (1<<2) -+#define CCTRL43236_ANT_MUX_2o3 (1<<3) -+#define CCTRL43236_GSIO (1<<4) -+ -+ -+#define CST43236_SFLASH_MASK 0x00000040 -+#define CST43236_OTP_SEL_MASK 0x00000080 -+#define CST43236_OTP_SEL_SHIFT 7 -+#define CST43236_HSIC_MASK 0x00000100 -+#define CST43236_BP_CLK 0x00000200 -+#define CST43236_BOOT_MASK 0x00001800 -+#define CST43236_BOOT_SHIFT 11 -+#define CST43236_BOOT_FROM_SRAM 0 -+#define CST43236_BOOT_FROM_ROM 1 -+#define CST43236_BOOT_FROM_FLASH 2 -+#define CST43236_BOOT_FROM_INVALID 3 -+ -+ -+#define RES43237_REGULATOR 0 -+#define RES43237_ILP_REQUEST 1 -+#define RES43237_XTAL_PU 2 -+#define RES43237_ALP_AVAIL 3 -+#define RES43237_SI_PLL_ON 4 -+#define RES43237_HT_SI_AVAIL 5 -+ -+ -+#define CCTRL43237_BT_COEXIST (1<<0) -+#define CCTRL43237_SECI (1<<1) -+#define CCTRL43237_EXT_LNA (1<<2) -+#define CCTRL43237_ANT_MUX_2o3 (1<<3) -+#define CCTRL43237_GSIO (1<<4) -+ -+ -+#define CST43237_SFLASH_MASK 0x00000040 -+#define CST43237_OTP_SEL_MASK 0x00000080 -+#define CST43237_OTP_SEL_SHIFT 7 -+#define CST43237_HSIC_MASK 0x00000100 -+#define CST43237_BP_CLK 0x00000200 -+#define CST43237_BOOT_MASK 0x00001800 -+#define CST43237_BOOT_SHIFT 11 -+#define CST43237_BOOT_FROM_SRAM 0 -+#define CST43237_BOOT_FROM_ROM 1 -+#define CST43237_BOOT_FROM_FLASH 2 -+#define CST43237_BOOT_FROM_INVALID 3 -+ -+ -+#define RES43239_OTP_PU 9 -+#define RES43239_MACPHY_CLKAVAIL 23 -+#define RES43239_HT_AVAIL 24 -+ -+ -+#define CST43239_SPROM_MASK 0x00000002 -+#define CST43239_SFLASH_MASK 0x00000004 -+#define CST43239_RES_INIT_MODE_SHIFT 7 -+#define CST43239_RES_INIT_MODE_MASK 0x000001f0 -+#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) -+#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) -+#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) -+#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) -+ -+ -+#define RES4324_OTP_PU 10 -+#define RES4324_HT_AVAIL 29 -+#define RES4324_MACPHY_CLKAVAIL 30 -+ -+ -+#define CST4324_SPROM_MASK 0x00000080 -+#define CST4324_SFLASH_MASK 0x00400000 -+#define CST4324_RES_INIT_MODE_SHIFT 10 -+#define CST4324_RES_INIT_MODE_MASK 0x00000c00 -+#define CST4324_CHIPMODE_MASK 0x7 -+#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) -+#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) -+ -+ -+#define RES4331_REGULATOR 0 -+#define RES4331_ILP_REQUEST 1 -+#define RES4331_XTAL_PU 2 -+#define RES4331_ALP_AVAIL 3 -+#define RES4331_SI_PLL_ON 4 -+#define RES4331_HT_SI_AVAIL 5 -+ -+ -+#define CCTRL4331_BT_COEXIST (1<<0) -+#define CCTRL4331_SECI (1<<1) -+#define CCTRL4331_EXT_LNA_G (1<<2) -+#define CCTRL4331_SPROM_GPIO13_15 (1<<3) -+#define CCTRL4331_EXTPA_EN (1<<4) -+#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) -+#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) -+#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) -+#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) -+#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) -+#define CCTRL4331_PCIE_AUXCLKEN (1<<10) -+#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) -+#define CCTRL4331_EXTPA_EN2 (1<<12) -+#define CCTRL4331_EXT_LNA_A (1<<13) -+#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) -+#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) -+#define CCTRL4331_EXTPA_ANA_EN (1<<24) -+ -+ -+#define CST4331_XTAL_FREQ 0x00000001 -+#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 -+#define CST4331_SPROM_OTP_SEL_SHIFT 1 -+#define CST4331_SPROM_PRESENT 0x00000002 -+#define CST4331_OTP_PRESENT 0x00000004 -+#define CST4331_LDO_RF 0x00000008 -+#define CST4331_LDO_PAR 0x00000010 -+ -+ -+#define RES4315_CBUCK_LPOM 1 -+#define RES4315_CBUCK_BURST 2 -+#define RES4315_CBUCK_PWM 3 -+#define RES4315_CLDO_PU 4 -+#define RES4315_PALDO_PU 5 -+#define RES4315_ILP_REQUEST 6 -+#define RES4315_LNLDO1_PU 9 -+#define RES4315_OTP_PU 10 -+#define RES4315_LNLDO2_PU 12 -+#define RES4315_XTAL_PU 13 -+#define RES4315_ALP_AVAIL 14 -+#define RES4315_RX_PWRSW_PU 15 -+#define RES4315_TX_PWRSW_PU 16 -+#define RES4315_RFPLL_PWRSW_PU 17 -+#define RES4315_LOGEN_PWRSW_PU 18 -+#define RES4315_AFE_PWRSW_PU 19 -+#define RES4315_BBPLL_PWRSW_PU 20 -+#define RES4315_HT_AVAIL 21 -+ -+ -+#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 -+#define CST4315_DEFCIS_SEL 0x00000000 -+#define CST4315_SPROM_SEL 0x00000001 -+#define CST4315_OTP_SEL 0x00000002 -+#define CST4315_OTP_PWRDN 0x00000003 -+#define CST4315_SDIO_MODE 0x00000004 -+#define CST4315_RCAL_VALID 0x00000008 -+#define CST4315_RCAL_VALUE_MASK 0x000001f0 -+#define CST4315_RCAL_VALUE_SHIFT 4 -+#define CST4315_PALDO_EXTPNP 0x00000200 -+#define CST4315_CBUCK_MODE_MASK 0x00000c00 -+#define CST4315_CBUCK_MODE_BURST 0x00000400 -+#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 -+ -+ -+#define RES4319_CBUCK_LPOM 1 -+#define RES4319_CBUCK_BURST 2 -+#define RES4319_CBUCK_PWM 3 -+#define RES4319_CLDO_PU 4 -+#define RES4319_PALDO_PU 5 -+#define RES4319_ILP_REQUEST 6 -+#define RES4319_LNLDO1_PU 9 -+#define RES4319_OTP_PU 10 -+#define RES4319_LNLDO2_PU 12 -+#define RES4319_XTAL_PU 13 -+#define RES4319_ALP_AVAIL 14 -+#define RES4319_RX_PWRSW_PU 15 -+#define RES4319_TX_PWRSW_PU 16 -+#define RES4319_RFPLL_PWRSW_PU 17 -+#define RES4319_LOGEN_PWRSW_PU 18 -+#define RES4319_AFE_PWRSW_PU 19 -+#define RES4319_BBPLL_PWRSW_PU 20 -+#define RES4319_HT_AVAIL 21 -+ -+ -+#define CST4319_SPI_CPULESSUSB 0x00000001 -+#define CST4319_SPI_CLK_POL 0x00000002 -+#define CST4319_SPI_CLK_PH 0x00000008 -+#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 -+#define CST4319_SPROM_OTP_SEL_SHIFT 6 -+#define CST4319_DEFCIS_SEL 0x00000000 -+#define CST4319_SPROM_SEL 0x00000040 -+#define CST4319_OTP_SEL 0x00000080 -+#define CST4319_OTP_PWRDN 0x000000c0 -+#define CST4319_SDIO_USB_MODE 0x00000100 -+#define CST4319_REMAP_SEL_MASK 0x00000600 -+#define CST4319_ILPDIV_EN 0x00000800 -+#define CST4319_XTAL_PD_POL 0x00001000 -+#define CST4319_LPO_SEL 0x00002000 -+#define CST4319_RES_INIT_MODE 0x0000c000 -+#define CST4319_PALDO_EXTPNP 0x00010000 -+#define CST4319_CBUCK_MODE_MASK 0x00060000 -+#define CST4319_CBUCK_MODE_BURST 0x00020000 -+#define CST4319_CBUCK_MODE_LPBURST 0x00060000 -+#define CST4319_RCAL_VALID 0x01000000 -+#define CST4319_RCAL_VALUE_MASK 0x3e000000 -+#define CST4319_RCAL_VALUE_SHIFT 25 -+ -+#define PMU1_PLL0_CHIPCTL0 0 -+#define PMU1_PLL0_CHIPCTL1 1 -+#define PMU1_PLL0_CHIPCTL2 2 -+#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 -+#define CCTL_4319USB_XTAL_SEL_SHIFT 19 -+#define CCTL_4319USB_48MHZ_PLL_SEL 1 -+#define CCTL_4319USB_24MHZ_PLL_SEL 2 -+ -+ -+#define RES4336_CBUCK_LPOM 0 -+#define RES4336_CBUCK_BURST 1 -+#define RES4336_CBUCK_LP_PWM 2 -+#define RES4336_CBUCK_PWM 3 -+#define RES4336_CLDO_PU 4 -+#define RES4336_DIS_INT_RESET_PD 5 -+#define RES4336_ILP_REQUEST 6 -+#define RES4336_LNLDO_PU 7 -+#define RES4336_LDO3P3_PU 8 -+#define RES4336_OTP_PU 9 -+#define RES4336_XTAL_PU 10 -+#define RES4336_ALP_AVAIL 11 -+#define RES4336_RADIO_PU 12 -+#define RES4336_BG_PU 13 -+#define RES4336_VREG1p4_PU_PU 14 -+#define RES4336_AFE_PWRSW_PU 15 -+#define RES4336_RX_PWRSW_PU 16 -+#define RES4336_TX_PWRSW_PU 17 -+#define RES4336_BB_PWRSW_PU 18 -+#define RES4336_SYNTH_PWRSW_PU 19 -+#define RES4336_MISC_PWRSW_PU 20 -+#define RES4336_LOGEN_PWRSW_PU 21 -+#define RES4336_BBPLL_PWRSW_PU 22 -+#define RES4336_MACPHY_CLKAVAIL 23 -+#define RES4336_HT_AVAIL 24 -+#define RES4336_RSVD 25 -+ -+ -+#define CST4336_SPI_MODE_MASK 0x00000001 -+#define CST4336_SPROM_PRESENT 0x00000002 -+#define CST4336_OTP_PRESENT 0x00000004 -+#define CST4336_ARMREMAP_0 0x00000008 -+#define CST4336_ILPDIV_EN_MASK 0x00000010 -+#define CST4336_ILPDIV_EN_SHIFT 4 -+#define CST4336_XTAL_PD_POL_MASK 0x00000020 -+#define CST4336_XTAL_PD_POL_SHIFT 5 -+#define CST4336_LPO_SEL_MASK 0x00000040 -+#define CST4336_LPO_SEL_SHIFT 6 -+#define CST4336_RES_INIT_MODE_MASK 0x00000180 -+#define CST4336_RES_INIT_MODE_SHIFT 7 -+#define CST4336_CBUCK_MODE_MASK 0x00000600 -+#define CST4336_CBUCK_MODE_SHIFT 9 -+ -+ -+#define PCTL_4336_SERIAL_ENAB (1 << 24) -+ -+ -+#define RES4330_CBUCK_LPOM 0 -+#define RES4330_CBUCK_BURST 1 -+#define RES4330_CBUCK_LP_PWM 2 -+#define RES4330_CBUCK_PWM 3 -+#define RES4330_CLDO_PU 4 -+#define RES4330_DIS_INT_RESET_PD 5 -+#define RES4330_ILP_REQUEST 6 -+#define RES4330_LNLDO_PU 7 -+#define RES4330_LDO3P3_PU 8 -+#define RES4330_OTP_PU 9 -+#define RES4330_XTAL_PU 10 -+#define RES4330_ALP_AVAIL 11 -+#define RES4330_RADIO_PU 12 -+#define RES4330_BG_PU 13 -+#define RES4330_VREG1p4_PU_PU 14 -+#define RES4330_AFE_PWRSW_PU 15 -+#define RES4330_RX_PWRSW_PU 16 -+#define RES4330_TX_PWRSW_PU 17 -+#define RES4330_BB_PWRSW_PU 18 -+#define RES4330_SYNTH_PWRSW_PU 19 -+#define RES4330_MISC_PWRSW_PU 20 -+#define RES4330_LOGEN_PWRSW_PU 21 -+#define RES4330_BBPLL_PWRSW_PU 22 -+#define RES4330_MACPHY_CLKAVAIL 23 -+#define RES4330_HT_AVAIL 24 -+#define RES4330_5gRX_PWRSW_PU 25 -+#define RES4330_5gTX_PWRSW_PU 26 -+#define RES4330_5g_LOGEN_PWRSW_PU 27 -+ -+ -+#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) -+#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) -+#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) -+#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) -+#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) -+#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) -+#define CST4330_OTP_PRESENT 0x00000010 -+#define CST4330_LPO_AUTODET_EN 0x00000020 -+#define CST4330_ARMREMAP_0 0x00000040 -+#define CST4330_SPROM_PRESENT 0x00000080 -+#define CST4330_ILPDIV_EN 0x00000100 -+#define CST4330_LPO_SEL 0x00000200 -+#define CST4330_RES_INIT_MODE_SHIFT 10 -+#define CST4330_RES_INIT_MODE_MASK 0x00000c00 -+#define CST4330_CBUCK_MODE_SHIFT 12 -+#define CST4330_CBUCK_MODE_MASK 0x00003000 -+#define CST4330_CBUCK_POWER_OK 0x00004000 -+#define CST4330_BB_PLL_LOCKED 0x00008000 -+#define SOCDEVRAM_BP_ADDR 0x1E000000 -+#define SOCDEVRAM_ARM_ADDR 0x00800000 -+ -+ -+#define PCTL_4330_SERIAL_ENAB (1 << 24) -+ -+ -+#define CCTRL_4330_GPIO_SEL 0x00000001 -+#define CCTRL_4330_ERCX_SEL 0x00000002 -+#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 -+#define CCTRL_4330_JTAG_DISABLE 0x00000008 -+ -+#define PMU_VREG0_ADDR 0 -+#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 -+#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 -+ -+ -+#define RES4334_LPLDO_PU 0 -+#define RES4334_RESET_PULLDN_DIS 1 -+#define RES4334_PMU_BG_PU 2 -+#define RES4334_HSIC_LDO_PU 3 -+#define RES4334_CBUCK_LPOM_PU 4 -+#define RES4334_CBUCK_PFM_PU 5 -+#define RES4334_CLDO_PU 6 -+#define RES4334_LPLDO2_LVM 7 -+#define RES4334_LNLDO_PU 8 -+#define RES4334_LDO3P3_PU 9 -+#define RES4334_OTP_PU 10 -+#define RES4334_XTAL_PU 11 -+#define RES4334_WL_PWRSW_PU 12 -+#define RES4334_LQ_AVAIL 13 -+#define RES4334_LOGIC_RET 14 -+#define RES4334_MEM_SLEEP 15 -+#define RES4334_MACPHY_RET 16 -+#define RES4334_WL_CORE_READY 17 -+#define RES4334_ILP_REQ 18 -+#define RES4334_ALP_AVAIL 19 -+#define RES4334_MISC_PWRSW_PU 20 -+#define RES4334_SYNTH_PWRSW_PU 21 -+#define RES4334_RX_PWRSW_PU 22 -+#define RES4334_RADIO_PU 23 -+#define RES4334_WL_PMU_PU 24 -+#define RES4334_VCO_LDO_PU 25 -+#define RES4334_AFE_LDO_PU 26 -+#define RES4334_RX_LDO_PU 27 -+#define RES4334_TX_LDO_PU 28 -+#define RES4334_HT_AVAIL 29 -+#define RES4334_MACPHY_CLK_AVAIL 30 -+ -+ -+#define CST4334_CHIPMODE_MASK 7 -+#define CST4334_SDIO_MODE 0x00000000 -+#define CST4334_SPI_MODE 0x00000004 -+#define CST4334_HSIC_MODE 0x00000006 -+#define CST4334_BLUSB_MODE 0x00000007 -+#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) -+#define CST4334_OTP_PRESENT 0x00000010 -+#define CST4334_LPO_AUTODET_EN 0x00000020 -+#define CST4334_ARMREMAP_0 0x00000040 -+#define CST4334_SPROM_PRESENT 0x00000080 -+#define CST4334_ILPDIV_EN_MASK 0x00000100 -+#define CST4334_ILPDIV_EN_SHIFT 8 -+#define CST4334_LPO_SEL_MASK 0x00000200 -+#define CST4334_LPO_SEL_SHIFT 9 -+#define CST4334_RES_INIT_MODE_MASK 0x00000C00 -+#define CST4334_RES_INIT_MODE_SHIFT 10 -+ -+ -+#define PCTL_4334_GPIO3_ENAB (1 << 3) -+ -+ -+#define CCTRL4334_HSIC_LDO_PU (1 << 23) -+ -+ -+#define CCTRL1_4324_GPIO_SEL (1 << 0) -+#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) -+ -+ -+ -+#define RES4313_BB_PU_RSRC 0 -+#define RES4313_ILP_REQ_RSRC 1 -+#define RES4313_XTAL_PU_RSRC 2 -+#define RES4313_ALP_AVAIL_RSRC 3 -+#define RES4313_RADIO_PU_RSRC 4 -+#define RES4313_BG_PU_RSRC 5 -+#define RES4313_VREG1P4_PU_RSRC 6 -+#define RES4313_AFE_PWRSW_RSRC 7 -+#define RES4313_RX_PWRSW_RSRC 8 -+#define RES4313_TX_PWRSW_RSRC 9 -+#define RES4313_BB_PWRSW_RSRC 10 -+#define RES4313_SYNTH_PWRSW_RSRC 11 -+#define RES4313_MISC_PWRSW_RSRC 12 -+#define RES4313_BB_PLL_PWRSW_RSRC 13 -+#define RES4313_HT_AVAIL_RSRC 14 -+#define RES4313_MACPHY_CLK_AVAIL_RSRC 15 -+ -+ -+#define CST4313_SPROM_PRESENT 1 -+#define CST4313_OTP_PRESENT 2 -+#define CST4313_SPROM_OTP_SEL_MASK 0x00000002 -+#define CST4313_SPROM_OTP_SEL_SHIFT 0 -+ -+ -+#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 -+ -+ -+#define RES4314_LPLDO_PU 0 -+#define RES4314_PMU_SLEEP_DIS 1 -+#define RES4314_PMU_BG_PU 2 -+#define RES4314_CBUCK_LPOM_PU 3 -+#define RES4314_CBUCK_PFM_PU 4 -+#define RES4314_CLDO_PU 5 -+#define RES4314_LPLDO2_LVM 6 -+#define RES4314_WL_PMU_PU 7 -+#define RES4314_LNLDO_PU 8 -+#define RES4314_LDO3P3_PU 9 -+#define RES4314_OTP_PU 10 -+#define RES4314_XTAL_PU 11 -+#define RES4314_WL_PWRSW_PU 12 -+#define RES4314_LQ_AVAIL 13 -+#define RES4314_LOGIC_RET 14 -+#define RES4314_MEM_SLEEP 15 -+#define RES4314_MACPHY_RET 16 -+#define RES4314_WL_CORE_READY 17 -+#define RES4314_ILP_REQ 18 -+#define RES4314_ALP_AVAIL 19 -+#define RES4314_MISC_PWRSW_PU 20 -+#define RES4314_SYNTH_PWRSW_PU 21 -+#define RES4314_RX_PWRSW_PU 22 -+#define RES4314_RADIO_PU 23 -+#define RES4314_VCO_LDO_PU 24 -+#define RES4314_AFE_LDO_PU 25 -+#define RES4314_RX_LDO_PU 26 -+#define RES4314_TX_LDO_PU 27 -+#define RES4314_HT_AVAIL 28 -+#define RES4314_MACPHY_CLK_AVAIL 29 -+ -+ -+#define CST4314_OTP_ENABLED 0x00200000 -+ -+ -+#define RES43228_NOT_USED 0 -+#define RES43228_ILP_REQUEST 1 -+#define RES43228_XTAL_PU 2 -+#define RES43228_ALP_AVAIL 3 -+#define RES43228_PLL_EN 4 -+#define RES43228_HT_PHY_AVAIL 5 -+ -+ -+#define CST43228_ILP_DIV_EN 0x1 -+#define CST43228_OTP_PRESENT 0x2 -+#define CST43228_SERDES_REFCLK_PADSEL 0x4 -+#define CST43228_SDIO_MODE 0x8 -+#define CST43228_SDIO_OTP_PRESENT 0x10 -+#define CST43228_SDIO_RESET 0x20 -+ -+ -+#define CST4706_PKG_OPTION (1<<0) -+#define CST4706_SFLASH_PRESENT (1<<1) -+#define CST4706_SFLASH_TYPE (1<<2) -+#define CST4706_MIPS_BENDIAN (1<<3) -+#define CST4706_PCIE1_DISABLE (1<<5) -+ -+ -+#define FLSTRCF4706_MASK 0x000000ff -+#define FLSTRCF4706_SF1 0x00000001 -+#define FLSTRCF4706_PF1 0x00000002 -+#define FLSTRCF4706_SF1_TYPE 0x00000004 -+#define FLSTRCF4706_NF1 0x00000008 -+#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 -+#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 -+#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 -+#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 -+#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 -+#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 -+#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 -+#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 -+ -+ -+#define CCTRL4360_SECI_MODE (1 << 2) -+#define CCTRL4360_BTSWCTRL_MODE (1 << 3) -+#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) -+#define CCTRL4360_BT_LGCY_MODE (1 << 9) -+#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) -+ -+ -+#define RES4360_REGULATOR 0 -+#define RES4360_ILP_AVAIL 1 -+#define RES4360_ILP_REQ 2 -+#define RES4360_XTAL_LDO_PU 3 -+#define RES4360_XTAL_PU 4 -+#define RES4360_ALP_AVAIL 5 -+#define RES4360_BBPLLPWRSW_PU 6 -+#define RES4360_HT_AVAIL 7 -+#define RES4360_OTP_PU 8 -+ -+#define CST4360_XTAL_40MZ 0x00000001 -+#define CST4360_SFLASH 0x00000002 -+#define CST4360_SPROM_PRESENT 0x00000004 -+#define CST4360_SFLASH_TYPE 0x00000004 -+#define CST4360_OTP_ENABLED 0x00000008 -+#define CST4360_REMAP_ROM 0x00000010 -+#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 -+#define CST4360_RSRC_INIT_MODE_SHIFT 5 -+#define CST4360_ILP_DIVEN 0x00000080 -+#define CST4360_MODE_USB 0x00000100 -+#define CST4360_SPROM_SIZE_MASK 0x00000600 -+#define CST4360_SPROM_SIZE_SHIFT 9 -+#define CST4360_BBPLL_LOCK 0x00000800 -+#define CST4360_AVBBPLL_LOCK 0x00001000 -+#define CST4360_USBBBPLL_LOCK 0x00002000 -+ -+#define CCTRL_4360_UART_SEL 0x2 -+ -+ -+#define RES4335_LPLDO_PO 0 -+#define RES4335_PMU_BG_PU 1 -+#define RES4335_PMU_SLEEP 2 -+#define RES4335_RSVD_3 3 -+#define RES4335_CBUCK_LPOM_PU 4 -+#define RES4335_CBUCK_PFM_PU 5 -+#define RES4335_RSVD_6 6 -+#define RES4335_RSVD_7 7 -+#define RES4335_LNLDO_PU 8 -+#define RES4335_XTALLDO_PU 9 -+#define RES4335_LDO3P3_PU 10 -+#define RES4335_OTP_PU 11 -+#define RES4335_XTAL_PU 12 -+#define RES4335_SR_CLK_START 13 -+#define RES4335_LQ_AVAIL 14 -+#define RES4335_LQ_START 15 -+#define RES4335_RSVD_16 16 -+#define RES4335_WL_CORE_RDY 17 -+#define RES4335_ILP_REQ 18 -+#define RES4335_ALP_AVAIL 19 -+#define RES4335_MINI_PMU 20 -+#define RES4335_RADIO_PU 21 -+#define RES4335_SR_CLK_STABLE 22 -+#define RES4335_SR_SAVE_RESTORE 23 -+#define RES4335_SR_PHY_PWRSW 24 -+#define RES4335_SR_VDDM_PWRSW 25 -+#define RES4335_SR_SUBCORE_PWRSW 26 -+#define RES4335_SR_SLEEP 27 -+#define RES4335_HT_START 28 -+#define RES4335_HT_AVAIL 29 -+#define RES4335_MACPHY_CLKAVAIL 30 -+ -+ -+#define CST4335_SPROM_MASK 0x00000020 -+#define CST4335_SFLASH_MASK 0x00000040 -+#define CST4335_RES_INIT_MODE_SHIFT 7 -+#define CST4335_RES_INIT_MODE_MASK 0x00000180 -+#define CST4335_CHIPMODE_MASK 0xF -+#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) -+#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) -+#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) -+#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) -+ -+ -+#define CCTRL1_4335_GPIO_SEL (1 << 0) -+#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) -+ -+ -+#define CR4_RAM_BASE (0x180000) -+ -+ -+ -+ -+#define CC_GCI_CHIPCTRL_00 (0) -+#define CC_GCI_CHIPCTRL_01 (1) -+#define CC_GCI_CHIPCTRL_02 (2) -+#define CC_GCI_CHIPCTRL_03 (3) -+#define CC_GCI_CHIPCTRL_04 (4) -+#define CC_GCI_CHIPCTRL_05 (5) -+#define CC_GCI_CHIPCTRL_06 (6) -+#define CC_GCI_CHIPCTRL_07 (7) -+#define CC_GCI_CHIPCTRL_08 (8) -+ -+#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) -+ -+ -+#define CC4335_PIN_GPIO_00 (0) -+#define CC4335_PIN_GPIO_01 (1) -+#define CC4335_PIN_GPIO_02 (2) -+#define CC4335_PIN_GPIO_03 (3) -+#define CC4335_PIN_GPIO_04 (4) -+#define CC4335_PIN_GPIO_05 (5) -+#define CC4335_PIN_GPIO_06 (6) -+#define CC4335_PIN_GPIO_07 (7) -+#define CC4335_PIN_GPIO_08 (8) -+#define CC4335_PIN_GPIO_09 (9) -+#define CC4335_PIN_GPIO_10 (10) -+#define CC4335_PIN_GPIO_11 (11) -+#define CC4335_PIN_GPIO_12 (12) -+#define CC4335_PIN_GPIO_13 (13) -+#define CC4335_PIN_GPIO_14 (14) -+#define CC4335_PIN_GPIO_15 (15) -+#define CC4335_PIN_SDIO_CLK (16) -+#define CC4335_PIN_SDIO_CMD (17) -+#define CC4335_PIN_SDIO_DATA0 (18) -+#define CC4335_PIN_SDIO_DATA1 (19) -+#define CC4335_PIN_SDIO_DATA2 (20) -+#define CC4335_PIN_SDIO_DATA3 (21) -+#define CC4335_PIN_RF_SW_CTRL_0 (22) -+#define CC4335_PIN_RF_SW_CTRL_1 (23) -+#define CC4335_PIN_RF_SW_CTRL_2 (24) -+#define CC4335_PIN_RF_SW_CTRL_3 (25) -+#define CC4335_PIN_RF_SW_CTRL_4 (26) -+#define CC4335_PIN_RF_SW_CTRL_5 (27) -+#define CC4335_PIN_RF_SW_CTRL_6 (28) -+#define CC4335_PIN_RF_SW_CTRL_7 (29) -+#define CC4335_PIN_RF_SW_CTRL_8 (30) -+#define CC4335_PIN_RF_SW_CTRL_9 (31) -+ -+ -+#define CC4335_FNSEL_HWDEF (0) -+#define CC4335_FNSEL_SAMEASPIN (1) -+#define CC4335_FNSEL_GPIO0 (2) -+#define CC4335_FNSEL_GPIO1 (3) -+#define CC4335_FNSEL_GCI0 (4) -+#define CC4335_FNSEL_GCI1 (5) -+#define CC4335_FNSEL_UART (6) -+#define CC4335_FNSEL_SFLASH (7) -+#define CC4335_FNSEL_SPROM (8) -+#define CC4335_FNSEL_MISC0 (9) -+#define CC4335_FNSEL_MISC1 (10) -+#define CC4335_FNSEL_MISC2 (11) -+#define CC4335_FNSEL_IND (12) -+#define CC4335_FNSEL_PDN (13) -+#define CC4335_FNSEL_PUP (14) -+#define CC4335_FNSEL_TRI (15) -+ -+ -+#define GCIMASK(pos) (((uint32)0xF) << pos) -+ -+ -+#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) -+ -+ -+#define MUXENAB4335_UART_MASK (0x0000000f) -+ -+ -+ -+#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) & CST4360_MODE_USB) -+ -+ -+#define PMU_MAX_TRANSITION_DLY 15000 -+ -+ -+#define PMURES_UP_TRANSITION 2 -+ -+ -+ -+#define SECI_MODE_UART 0x0 -+#define SECI_MODE_SECI 0x1 -+#define SECI_MODE_LEGACY_3WIRE_BT 0x2 -+#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 -+#define SECI_MODE_HALF_SECI 0x4 -+ -+#define SECI_RESET (1 << 0) -+#define SECI_RESET_BAR_UART (1 << 1) -+#define SECI_ENAB_SECI_ECI (1 << 2) -+#define SECI_ENAB_SECIOUT_DIS (1 << 3) -+#define SECI_MODE_MASK 0x7 -+#define SECI_MODE_SHIFT 4 -+#define SECI_UPD_SECI (1 << 7) -+ -+#define SECI_SIGNOFF_0 0xDB -+#define SECI_SIGNOFF_1 0 -+ -+ -+#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) -+#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) -+ -+#define SECI_UART_MSR_CTS_STATE (1 << 0) -+#define SECI_UART_MSR_RTS_STATE (1 << 1) -+#define SECI_UART_SECI_IN_STATE (1 << 2) -+#define SECI_UART_SECI_IN2_STATE (1 << 3) -+ -+ -+#define SECI_UART_LCR_STOP_BITS (1 << 0) -+#define SECI_UART_LCR_PARITY_EN (1 << 1) -+#define SECI_UART_LCR_PARITY (1 << 2) -+#define SECI_UART_LCR_RX_EN (1 << 3) -+#define SECI_UART_LCR_LBRK_CTRL (1 << 4) -+#define SECI_UART_LCR_TXO_EN (1 << 5) -+#define SECI_UART_LCR_RTSO_EN (1 << 6) -+#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) -+#define SECI_UART_LCR_RXCRC_CHK (1 << 8) -+#define SECI_UART_LCR_TXCRC_INV (1 << 9) -+#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) -+#define SECI_UART_LCR_TXCRC_EN (1 << 11) -+ -+#define SECI_UART_MCR_TX_EN (1 << 0) -+#define SECI_UART_MCR_PRTS (1 << 1) -+#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) -+#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) -+#define SECI_UART_MCR_LOOPBK_EN (1 << 4) -+#define SECI_UART_MCR_AUTO_RTS (1 << 5) -+#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) -+#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) -+#define SECI_UART_MCR_XONOFF_RPT (1 << 9) -+ -+ -+ -+ -+#define ECI_BW_20 0x0 -+#define ECI_BW_25 0x1 -+#define ECI_BW_30 0x2 -+#define ECI_BW_35 0x3 -+#define ECI_BW_40 0x4 -+#define ECI_BW_45 0x5 -+#define ECI_BW_50 0x6 -+#define ECI_BW_ALL 0x7 -+ -+ -+#define WLAN_NUM_ANT1 TXANT_0 -+#define WLAN_NUM_ANT2 TXANT_1 -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h -new file mode 100644 -index 00000000..44d68329 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sbconfig.h -@@ -0,0 +1,275 @@ -+/* -+ * Broadcom SiliconBackplane hardware register definitions. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sbconfig.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _SBCONFIG_H -+#define _SBCONFIG_H -+ -+ -+#ifndef PAD -+#define _PADLINE(line) pad ## line -+#define _XSTR(line) _PADLINE(line) -+#define PAD _XSTR(__LINE__) -+#endif -+ -+ -+#define SB_BUS_SIZE 0x10000 -+#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) -+#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) -+ -+ -+#define SBCONFIGOFF 0xf00 -+#define SBCONFIGSIZE 256 -+ -+#define SBIPSFLAG 0x08 -+#define SBTPSFLAG 0x18 -+#define SBTMERRLOGA 0x48 -+#define SBTMERRLOG 0x50 -+#define SBADMATCH3 0x60 -+#define SBADMATCH2 0x68 -+#define SBADMATCH1 0x70 -+#define SBIMSTATE 0x90 -+#define SBINTVEC 0x94 -+#define SBTMSTATELOW 0x98 -+#define SBTMSTATEHIGH 0x9c -+#define SBBWA0 0xa0 -+#define SBIMCONFIGLOW 0xa8 -+#define SBIMCONFIGHIGH 0xac -+#define SBADMATCH0 0xb0 -+#define SBTMCONFIGLOW 0xb8 -+#define SBTMCONFIGHIGH 0xbc -+#define SBBCONFIG 0xc0 -+#define SBBSTATE 0xc8 -+#define SBACTCNFG 0xd8 -+#define SBFLAGST 0xe8 -+#define SBIDLOW 0xf8 -+#define SBIDHIGH 0xfc -+ -+ -+ -+#define SBIMERRLOGA 0xea8 -+#define SBIMERRLOG 0xeb0 -+#define SBTMPORTCONNID0 0xed8 -+#define SBTMPORTLOCK0 0xef8 -+ -+#ifndef _LANGUAGE_ASSEMBLY -+ -+typedef volatile struct _sbconfig { -+ uint32 PAD[2]; -+ uint32 sbipsflag; -+ uint32 PAD[3]; -+ uint32 sbtpsflag; -+ uint32 PAD[11]; -+ uint32 sbtmerrloga; -+ uint32 PAD; -+ uint32 sbtmerrlog; -+ uint32 PAD[3]; -+ uint32 sbadmatch3; -+ uint32 PAD; -+ uint32 sbadmatch2; -+ uint32 PAD; -+ uint32 sbadmatch1; -+ uint32 PAD[7]; -+ uint32 sbimstate; -+ uint32 sbintvec; -+ uint32 sbtmstatelow; -+ uint32 sbtmstatehigh; -+ uint32 sbbwa0; -+ uint32 PAD; -+ uint32 sbimconfiglow; -+ uint32 sbimconfighigh; -+ uint32 sbadmatch0; -+ uint32 PAD; -+ uint32 sbtmconfiglow; -+ uint32 sbtmconfighigh; -+ uint32 sbbconfig; -+ uint32 PAD; -+ uint32 sbbstate; -+ uint32 PAD[3]; -+ uint32 sbactcnfg; -+ uint32 PAD[3]; -+ uint32 sbflagst; -+ uint32 PAD[3]; -+ uint32 sbidlow; -+ uint32 sbidhigh; -+} sbconfig_t; -+ -+#endif -+ -+ -+#define SBIPS_INT1_MASK 0x3f -+#define SBIPS_INT1_SHIFT 0 -+#define SBIPS_INT2_MASK 0x3f00 -+#define SBIPS_INT2_SHIFT 8 -+#define SBIPS_INT3_MASK 0x3f0000 -+#define SBIPS_INT3_SHIFT 16 -+#define SBIPS_INT4_MASK 0x3f000000 -+#define SBIPS_INT4_SHIFT 24 -+ -+ -+#define SBTPS_NUM0_MASK 0x3f -+#define SBTPS_F0EN0 0x40 -+ -+ -+#define SBTMEL_CM 0x00000007 -+#define SBTMEL_CI 0x0000ff00 -+#define SBTMEL_EC 0x0f000000 -+#define SBTMEL_ME 0x80000000 -+ -+ -+#define SBIM_PC 0xf -+#define SBIM_AP_MASK 0x30 -+#define SBIM_AP_BOTH 0x00 -+#define SBIM_AP_TS 0x10 -+#define SBIM_AP_TK 0x20 -+#define SBIM_AP_RSV 0x30 -+#define SBIM_IBE 0x20000 -+#define SBIM_TO 0x40000 -+#define SBIM_BY 0x01800000 -+#define SBIM_RJ 0x02000000 -+ -+ -+#define SBTML_RESET 0x0001 -+#define SBTML_REJ_MASK 0x0006 -+#define SBTML_REJ 0x0002 -+#define SBTML_TMPREJ 0x0004 -+ -+#define SBTML_SICF_SHIFT 16 -+ -+ -+#define SBTMH_SERR 0x0001 -+#define SBTMH_INT 0x0002 -+#define SBTMH_BUSY 0x0004 -+#define SBTMH_TO 0x0020 -+ -+#define SBTMH_SISF_SHIFT 16 -+ -+ -+#define SBBWA_TAB0_MASK 0xffff -+#define SBBWA_TAB1_MASK 0xffff -+#define SBBWA_TAB1_SHIFT 16 -+ -+ -+#define SBIMCL_STO_MASK 0x7 -+#define SBIMCL_RTO_MASK 0x70 -+#define SBIMCL_RTO_SHIFT 4 -+#define SBIMCL_CID_MASK 0xff0000 -+#define SBIMCL_CID_SHIFT 16 -+ -+ -+#define SBIMCH_IEM_MASK 0xc -+#define SBIMCH_TEM_MASK 0x30 -+#define SBIMCH_TEM_SHIFT 4 -+#define SBIMCH_BEM_MASK 0xc0 -+#define SBIMCH_BEM_SHIFT 6 -+ -+ -+#define SBAM_TYPE_MASK 0x3 -+#define SBAM_AD64 0x4 -+#define SBAM_ADINT0_MASK 0xf8 -+#define SBAM_ADINT0_SHIFT 3 -+#define SBAM_ADINT1_MASK 0x1f8 -+#define SBAM_ADINT1_SHIFT 3 -+#define SBAM_ADINT2_MASK 0x1f8 -+#define SBAM_ADINT2_SHIFT 3 -+#define SBAM_ADEN 0x400 -+#define SBAM_ADNEG 0x800 -+#define SBAM_BASE0_MASK 0xffffff00 -+#define SBAM_BASE0_SHIFT 8 -+#define SBAM_BASE1_MASK 0xfffff000 -+#define SBAM_BASE1_SHIFT 12 -+#define SBAM_BASE2_MASK 0xffff0000 -+#define SBAM_BASE2_SHIFT 16 -+ -+ -+#define SBTMCL_CD_MASK 0xff -+#define SBTMCL_CO_MASK 0xf800 -+#define SBTMCL_CO_SHIFT 11 -+#define SBTMCL_IF_MASK 0xfc0000 -+#define SBTMCL_IF_SHIFT 18 -+#define SBTMCL_IM_MASK 0x3000000 -+#define SBTMCL_IM_SHIFT 24 -+ -+ -+#define SBTMCH_BM_MASK 0x3 -+#define SBTMCH_RM_MASK 0x3 -+#define SBTMCH_RM_SHIFT 2 -+#define SBTMCH_SM_MASK 0x30 -+#define SBTMCH_SM_SHIFT 4 -+#define SBTMCH_EM_MASK 0x300 -+#define SBTMCH_EM_SHIFT 8 -+#define SBTMCH_IM_MASK 0xc00 -+#define SBTMCH_IM_SHIFT 10 -+ -+ -+#define SBBC_LAT_MASK 0x3 -+#define SBBC_MAX0_MASK 0xf0000 -+#define SBBC_MAX0_SHIFT 16 -+#define SBBC_MAX1_MASK 0xf00000 -+#define SBBC_MAX1_SHIFT 20 -+ -+ -+#define SBBS_SRD 0x1 -+#define SBBS_HRD 0x2 -+ -+ -+#define SBIDL_CS_MASK 0x3 -+#define SBIDL_AR_MASK 0x38 -+#define SBIDL_AR_SHIFT 3 -+#define SBIDL_SYNCH 0x40 -+#define SBIDL_INIT 0x80 -+#define SBIDL_MINLAT_MASK 0xf00 -+#define SBIDL_MINLAT_SHIFT 8 -+#define SBIDL_MAXLAT 0xf000 -+#define SBIDL_MAXLAT_SHIFT 12 -+#define SBIDL_FIRST 0x10000 -+#define SBIDL_CW_MASK 0xc0000 -+#define SBIDL_CW_SHIFT 18 -+#define SBIDL_TP_MASK 0xf00000 -+#define SBIDL_TP_SHIFT 20 -+#define SBIDL_IP_MASK 0xf000000 -+#define SBIDL_IP_SHIFT 24 -+#define SBIDL_RV_MASK 0xf0000000 -+#define SBIDL_RV_SHIFT 28 -+#define SBIDL_RV_2_2 0x00000000 -+#define SBIDL_RV_2_3 0x10000000 -+ -+ -+#define SBIDH_RC_MASK 0x000f -+#define SBIDH_RCE_MASK 0x7000 -+#define SBIDH_RCE_SHIFT 8 -+#define SBCOREREV(sbidh) \ -+ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK)) -+#define SBIDH_CC_MASK 0x8ff0 -+#define SBIDH_CC_SHIFT 4 -+#define SBIDH_VC_MASK 0xffff0000 -+#define SBIDH_VC_SHIFT 16 -+ -+#define SB_COMMIT 0xfd8 -+ -+ -+#define SB_VEND_BCM 0x4243 -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h -new file mode 100644 -index 00000000..da1f1a10 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sbhnddma.h -@@ -0,0 +1,370 @@ -+/* -+ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface -+ * This supports the following chips: BCM42xx, 44xx, 47xx . -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sbhnddma.h 309193 2012-01-19 00:03:57Z $ -+ */ -+ -+#ifndef _sbhnddma_h_ -+#define _sbhnddma_h_ -+ -+ -+ -+ -+ -+ -+ -+typedef volatile struct { -+ uint32 control; -+ uint32 addr; -+ uint32 ptr; -+ uint32 status; -+} dma32regs_t; -+ -+typedef volatile struct { -+ dma32regs_t xmt; -+ dma32regs_t rcv; -+} dma32regp_t; -+ -+typedef volatile struct { -+ uint32 fifoaddr; -+ uint32 fifodatalow; -+ uint32 fifodatahigh; -+ uint32 pad; -+} dma32diag_t; -+ -+ -+typedef volatile struct { -+ uint32 ctrl; -+ uint32 addr; -+} dma32dd_t; -+ -+ -+#define D32RINGALIGN_BITS 12 -+#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) -+#define D32RINGALIGN (1 << D32RINGALIGN_BITS) -+ -+#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) -+ -+ -+#define XC_XE ((uint32)1 << 0) -+#define XC_SE ((uint32)1 << 1) -+#define XC_LE ((uint32)1 << 2) -+#define XC_FL ((uint32)1 << 4) -+#define XC_MR_MASK 0x000000C0 -+#define XC_MR_SHIFT 6 -+#define XC_PD ((uint32)1 << 11) -+#define XC_AE ((uint32)3 << 16) -+#define XC_AE_SHIFT 16 -+#define XC_BL_MASK 0x001C0000 -+#define XC_BL_SHIFT 18 -+#define XC_PC_MASK 0x00E00000 -+#define XC_PC_SHIFT 21 -+#define XC_PT_MASK 0x03000000 -+#define XC_PT_SHIFT 24 -+ -+ -+#define DMA_MR_1 0 -+#define DMA_MR_2 1 -+ -+ -+ -+#define DMA_BL_16 0 -+#define DMA_BL_32 1 -+#define DMA_BL_64 2 -+#define DMA_BL_128 3 -+#define DMA_BL_256 4 -+#define DMA_BL_512 5 -+#define DMA_BL_1024 6 -+ -+ -+#define DMA_PC_0 0 -+#define DMA_PC_4 1 -+#define DMA_PC_8 2 -+#define DMA_PC_16 3 -+ -+ -+ -+#define DMA_PT_1 0 -+#define DMA_PT_2 1 -+#define DMA_PT_4 2 -+#define DMA_PT_8 3 -+ -+ -+#define XP_LD_MASK 0xfff -+ -+ -+#define XS_CD_MASK 0x0fff -+#define XS_XS_MASK 0xf000 -+#define XS_XS_SHIFT 12 -+#define XS_XS_DISABLED 0x0000 -+#define XS_XS_ACTIVE 0x1000 -+#define XS_XS_IDLE 0x2000 -+#define XS_XS_STOPPED 0x3000 -+#define XS_XS_SUSP 0x4000 -+#define XS_XE_MASK 0xf0000 -+#define XS_XE_SHIFT 16 -+#define XS_XE_NOERR 0x00000 -+#define XS_XE_DPE 0x10000 -+#define XS_XE_DFU 0x20000 -+#define XS_XE_BEBR 0x30000 -+#define XS_XE_BEDA 0x40000 -+#define XS_AD_MASK 0xfff00000 -+#define XS_AD_SHIFT 20 -+ -+ -+#define RC_RE ((uint32)1 << 0) -+#define RC_RO_MASK 0xfe -+#define RC_RO_SHIFT 1 -+#define RC_FM ((uint32)1 << 8) -+#define RC_SH ((uint32)1 << 9) -+#define RC_OC ((uint32)1 << 10) -+#define RC_PD ((uint32)1 << 11) -+#define RC_AE ((uint32)3 << 16) -+#define RC_AE_SHIFT 16 -+#define RC_BL_MASK 0x001C0000 -+#define RC_BL_SHIFT 18 -+#define RC_PC_MASK 0x00E00000 -+#define RC_PC_SHIFT 21 -+#define RC_PT_MASK 0x03000000 -+#define RC_PT_SHIFT 24 -+ -+ -+#define RP_LD_MASK 0xfff -+ -+ -+#define RS_CD_MASK 0x0fff -+#define RS_RS_MASK 0xf000 -+#define RS_RS_SHIFT 12 -+#define RS_RS_DISABLED 0x0000 -+#define RS_RS_ACTIVE 0x1000 -+#define RS_RS_IDLE 0x2000 -+#define RS_RS_STOPPED 0x3000 -+#define RS_RE_MASK 0xf0000 -+#define RS_RE_SHIFT 16 -+#define RS_RE_NOERR 0x00000 -+#define RS_RE_DPE 0x10000 -+#define RS_RE_DFO 0x20000 -+#define RS_RE_BEBW 0x30000 -+#define RS_RE_BEDA 0x40000 -+#define RS_AD_MASK 0xfff00000 -+#define RS_AD_SHIFT 20 -+ -+ -+#define FA_OFF_MASK 0xffff -+#define FA_SEL_MASK 0xf0000 -+#define FA_SEL_SHIFT 16 -+#define FA_SEL_XDD 0x00000 -+#define FA_SEL_XDP 0x10000 -+#define FA_SEL_RDD 0x40000 -+#define FA_SEL_RDP 0x50000 -+#define FA_SEL_XFD 0x80000 -+#define FA_SEL_XFP 0x90000 -+#define FA_SEL_RFD 0xc0000 -+#define FA_SEL_RFP 0xd0000 -+#define FA_SEL_RSD 0xe0000 -+#define FA_SEL_RSP 0xf0000 -+ -+ -+#define CTRL_BC_MASK 0x00001fff -+#define CTRL_AE ((uint32)3 << 16) -+#define CTRL_AE_SHIFT 16 -+#define CTRL_PARITY ((uint32)3 << 18) -+#define CTRL_EOT ((uint32)1 << 28) -+#define CTRL_IOC ((uint32)1 << 29) -+#define CTRL_EOF ((uint32)1 << 30) -+#define CTRL_SOF ((uint32)1 << 31) -+ -+ -+#define CTRL_CORE_MASK 0x0ff00000 -+ -+ -+ -+ -+typedef volatile struct { -+ uint32 control; -+ uint32 ptr; -+ uint32 addrlow; -+ uint32 addrhigh; -+ uint32 status0; -+ uint32 status1; -+} dma64regs_t; -+ -+typedef volatile struct { -+ dma64regs_t tx; -+ dma64regs_t rx; -+} dma64regp_t; -+ -+typedef volatile struct { -+ uint32 fifoaddr; -+ uint32 fifodatalow; -+ uint32 fifodatahigh; -+ uint32 pad; -+} dma64diag_t; -+ -+ -+typedef volatile struct { -+ uint32 ctrl1; -+ uint32 ctrl2; -+ uint32 addrlow; -+ uint32 addrhigh; -+} dma64dd_t; -+ -+ -+#define D64RINGALIGN_BITS 13 -+#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) -+#define D64RINGALIGN (1 << D64RINGALIGN_BITS) -+ -+#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) -+ -+ -+#define D64_XC_XE 0x00000001 -+#define D64_XC_SE 0x00000002 -+#define D64_XC_LE 0x00000004 -+#define D64_XC_FL 0x00000010 -+#define D64_XC_MR_MASK 0x000000C0 -+#define D64_XC_MR_SHIFT 6 -+#define D64_XC_PD 0x00000800 -+#define D64_XC_AE 0x00030000 -+#define D64_XC_AE_SHIFT 16 -+#define D64_XC_BL_MASK 0x001C0000 -+#define D64_XC_BL_SHIFT 18 -+#define D64_XC_PC_MASK 0x00E00000 -+#define D64_XC_PC_SHIFT 21 -+#define D64_XC_PT_MASK 0x03000000 -+#define D64_XC_PT_SHIFT 24 -+ -+ -+#define D64_XP_LD_MASK 0x00001fff -+ -+ -+#define D64_XS0_CD_MASK 0x00001fff -+#define D64_XS0_XS_MASK 0xf0000000 -+#define D64_XS0_XS_SHIFT 28 -+#define D64_XS0_XS_DISABLED 0x00000000 -+#define D64_XS0_XS_ACTIVE 0x10000000 -+#define D64_XS0_XS_IDLE 0x20000000 -+#define D64_XS0_XS_STOPPED 0x30000000 -+#define D64_XS0_XS_SUSP 0x40000000 -+ -+#define D64_XS1_AD_MASK 0x00001fff -+#define D64_XS1_XE_MASK 0xf0000000 -+#define D64_XS1_XE_SHIFT 28 -+#define D64_XS1_XE_NOERR 0x00000000 -+#define D64_XS1_XE_DPE 0x10000000 -+#define D64_XS1_XE_DFU 0x20000000 -+#define D64_XS1_XE_DTE 0x30000000 -+#define D64_XS1_XE_DESRE 0x40000000 -+#define D64_XS1_XE_COREE 0x50000000 -+ -+ -+#define D64_RC_RE 0x00000001 -+#define D64_RC_RO_MASK 0x000000fe -+#define D64_RC_RO_SHIFT 1 -+#define D64_RC_FM 0x00000100 -+#define D64_RC_SH 0x00000200 -+#define D64_RC_OC 0x00000400 -+#define D64_RC_PD 0x00000800 -+#define D64_RC_AE 0x00030000 -+#define D64_RC_AE_SHIFT 16 -+#define D64_RC_BL_MASK 0x001C0000 -+#define D64_RC_BL_SHIFT 18 -+#define D64_RC_PC_MASK 0x00E00000 -+#define D64_RC_PC_SHIFT 21 -+#define D64_RC_PT_MASK 0x03000000 -+#define D64_RC_PT_SHIFT 24 -+ -+ -+#define DMA_CTRL_PEN (1 << 0) -+#define DMA_CTRL_ROC (1 << 1) -+#define DMA_CTRL_RXMULTI (1 << 2) -+#define DMA_CTRL_UNFRAMED (1 << 3) -+#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) -+#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) -+ -+ -+#define D64_RP_LD_MASK 0x00001fff -+ -+ -+#define D64_RS0_CD_MASK 0x00001fff -+#define D64_RS0_RS_MASK 0xf0000000 -+#define D64_RS0_RS_SHIFT 28 -+#define D64_RS0_RS_DISABLED 0x00000000 -+#define D64_RS0_RS_ACTIVE 0x10000000 -+#define D64_RS0_RS_IDLE 0x20000000 -+#define D64_RS0_RS_STOPPED 0x30000000 -+#define D64_RS0_RS_SUSP 0x40000000 -+ -+#define D64_RS1_AD_MASK 0x0001ffff -+#define D64_RS1_RE_MASK 0xf0000000 -+#define D64_RS1_RE_SHIFT 28 -+#define D64_RS1_RE_NOERR 0x00000000 -+#define D64_RS1_RE_DPO 0x10000000 -+#define D64_RS1_RE_DFU 0x20000000 -+#define D64_RS1_RE_DTE 0x30000000 -+#define D64_RS1_RE_DESRE 0x40000000 -+#define D64_RS1_RE_COREE 0x50000000 -+ -+ -+#define D64_FA_OFF_MASK 0xffff -+#define D64_FA_SEL_MASK 0xf0000 -+#define D64_FA_SEL_SHIFT 16 -+#define D64_FA_SEL_XDD 0x00000 -+#define D64_FA_SEL_XDP 0x10000 -+#define D64_FA_SEL_RDD 0x40000 -+#define D64_FA_SEL_RDP 0x50000 -+#define D64_FA_SEL_XFD 0x80000 -+#define D64_FA_SEL_XFP 0x90000 -+#define D64_FA_SEL_RFD 0xc0000 -+#define D64_FA_SEL_RFP 0xd0000 -+#define D64_FA_SEL_RSD 0xe0000 -+#define D64_FA_SEL_RSP 0xf0000 -+ -+ -+#define D64_CTRL_COREFLAGS 0x0ff00000 -+#define D64_CTRL1_EOT ((uint32)1 << 28) -+#define D64_CTRL1_IOC ((uint32)1 << 29) -+#define D64_CTRL1_EOF ((uint32)1 << 30) -+#define D64_CTRL1_SOF ((uint32)1 << 31) -+ -+ -+#define D64_CTRL2_BC_MASK 0x00007fff -+#define D64_CTRL2_AE 0x00030000 -+#define D64_CTRL2_AE_SHIFT 16 -+#define D64_CTRL2_PARITY 0x00040000 -+ -+ -+#define D64_CTRL_CORE_MASK 0x0ff00000 -+ -+#define D64_RX_FRM_STS_LEN 0x0000ffff -+#define D64_RX_FRM_STS_OVFL 0x00800000 -+#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 -+#define D64_RX_FRM_STS_DATATYPE 0xf0000000 -+ -+ -+typedef volatile struct { -+ uint16 len; -+ uint16 flags; -+} dma_rxh_t; -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h -new file mode 100644 -index 00000000..6ad98b52 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h -@@ -0,0 +1,108 @@ -+/* -+ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sbpcmcia.h 326494 2012-04-09 13:29:57Z $ -+ */ -+ -+#ifndef _SBPCMCIA_H -+#define _SBPCMCIA_H -+ -+ -+ -+ -+#define PCMCIA_FCR (0x700 / 2) -+ -+#define FCR0_OFF 0 -+#define FCR1_OFF (0x40 / 2) -+#define FCR2_OFF (0x80 / 2) -+#define FCR3_OFF (0xc0 / 2) -+ -+#define PCMCIA_FCR0 (0x700 / 2) -+#define PCMCIA_FCR1 (0x740 / 2) -+#define PCMCIA_FCR2 (0x780 / 2) -+#define PCMCIA_FCR3 (0x7c0 / 2) -+ -+ -+ -+#define PCMCIA_COR 0 -+ -+#define COR_RST 0x80 -+#define COR_LEV 0x40 -+#define COR_IRQEN 0x04 -+#define COR_BLREN 0x01 -+#define COR_FUNEN 0x01 -+ -+ -+#define PCICIA_FCSR (2 / 2) -+#define PCICIA_PRR (4 / 2) -+#define PCICIA_SCR (6 / 2) -+#define PCICIA_ESR (8 / 2) -+ -+ -+#define PCM_MEMOFF 0x0000 -+#define F0_MEMOFF 0x1000 -+#define F1_MEMOFF 0x2000 -+#define F2_MEMOFF 0x3000 -+#define F3_MEMOFF 0x4000 -+ -+ -+#define MEM_ADDR0 (0x728 / 2) -+#define MEM_ADDR1 (0x72a / 2) -+#define MEM_ADDR2 (0x72c / 2) -+ -+ -+#define PCMCIA_ADDR0 (0x072e / 2) -+#define PCMCIA_ADDR1 (0x0730 / 2) -+#define PCMCIA_ADDR2 (0x0732 / 2) -+ -+#define MEM_SEG (0x0734 / 2) -+#define SROM_CS (0x0736 / 2) -+#define SROM_DATAL (0x0738 / 2) -+#define SROM_DATAH (0x073a / 2) -+#define SROM_ADDRL (0x073c / 2) -+#define SROM_ADDRH (0x073e / 2) -+#define SROM_INFO2 (0x0772 / 2) -+#define SROM_INFO (0x07be / 2) -+ -+ -+#define SROM_IDLE 0 -+#define SROM_WRITE 1 -+#define SROM_READ 2 -+#define SROM_WEN 4 -+#define SROM_WDS 7 -+#define SROM_DONE 8 -+ -+ -+#define SRI_SZ_MASK 0x03 -+#define SRI_BLANK 0x04 -+#define SRI_OTP 0x80 -+ -+ -+ -+#define SBTML_INT_ACK 0x40000 -+#define SBTML_INT_EN 0x20000 -+ -+ -+#define SBTMH_INT_STATUS 0x40000 -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h -new file mode 100644 -index 00000000..211c4218 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h -@@ -0,0 +1,188 @@ -+/* -+ * SDIO device core hardware definitions. -+ * sdio is a portion of the pcmcia core in core rev 3 - rev 8 -+ * -+ * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sbsdio.h 308945 2012-01-18 02:15:27Z $ -+ */ -+ -+#ifndef _SBSDIO_H -+#define _SBSDIO_H -+ -+#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ -+ -+/* function 1 miscellaneous registers */ -+#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */ -+#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */ -+#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */ -+#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */ -+#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */ -+#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */ -+#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */ -+#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */ -+#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */ -+#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */ -+ -+/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */ -+#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */ -+#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */ -+#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */ -+#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */ -+#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */ -+#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */ -+#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */ -+#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */ -+#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */ -+#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */ -+#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ -+ -+#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ -+#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ -+ -+/* Sdio Core Rev 12 */ -+#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E -+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 -+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 -+#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 -+#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 -+#define SBSDIO_FUNC1_SLEEPCSR 0x1001F -+#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 -+#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 -+#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 -+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 -+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 -+ -+/* SBSDIO_SPROM_CS */ -+#define SBSDIO_SPROM_IDLE 0 -+#define SBSDIO_SPROM_WRITE 1 -+#define SBSDIO_SPROM_READ 2 -+#define SBSDIO_SPROM_WEN 4 -+#define SBSDIO_SPROM_WDS 7 -+#define SBSDIO_SPROM_DONE 8 -+ -+/* SBSDIO_SPROM_INFO */ -+#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ -+#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ -+#define SROM_OTP 0x80 /* OTP present */ -+ -+/* SBSDIO_CHIP_CTRL */ -+#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, -+ * 1: power on oscillator -+ * (for 4318 only) -+ */ -+/* SBSDIO_WATERMARK */ -+#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device -+ * to wait before sending data to host -+ */ -+ -+/* SBSDIO_MESBUSYCTRL */ -+/* When RX FIFO has less entries than this & MBE is set -+ * => busy signal is asserted between data blocks. -+*/ -+#define SBSDIO_MESBUSYCTRL_MASK 0x7f -+ -+/* SBSDIO_DEVICE_CTL */ -+#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when -+ * receiving CMD53 -+ */ -+#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is -+ * synchronous to the sdio clock -+ */ -+#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host -+ * except the chipActive (rev 8) -+ */ -+#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put -+ * external pads in tri-state; requires -+ * sdio bus power cycle to clear (rev 9) -+ */ -+#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */ -+#define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */ -+#define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */ -+#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */ -+#define SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ -+ -+ -+/* SBSDIO_FUNC1_CHIPCLKCSR */ -+#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */ -+#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */ -+#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */ -+#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */ -+#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */ -+#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */ -+#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */ -+#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */ -+/* In rev8, actual avail bits followed original docs */ -+#define SBSDIO_Rev8_HT_AVAIL 0x40 -+#define SBSDIO_Rev8_ALP_AVAIL 0x80 -+#define SBSDIO_CSR_MASK 0x1F -+ -+#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) -+#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) -+#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) -+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) -+#define SBSDIO_CLKAV(regval, alponly) (SBSDIO_ALPAV(regval) && \ -+ (alponly ? 1 : SBSDIO_HTAV(regval))) -+ -+/* SBSDIO_FUNC1_SDIOPULLUP */ -+#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ -+#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ -+#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ -+#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ -+#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ -+ -+/* function 1 OCP space */ -+#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ -+#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 -+#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ -+ -+/* some duplication with sbsdpcmdev.h here */ -+/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ -+#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ -+#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ -+#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ -+#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */ -+ -+/* direct(mapped) cis space */ -+#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */ -+#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */ -+#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */ -+ -+#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */ -+ -+#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple, -+ * link bytes -+ */ -+ -+/* indirect cis access (in sprom) */ -+#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from -+ * 8th byte -+ */ -+ -+#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one -+ * data comamnd -+ */ -+ -+#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ -+ -+#endif /* _SBSDIO_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h -new file mode 100644 -index 00000000..10c7401a ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h -@@ -0,0 +1,295 @@ -+/* -+ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific -+ * device core support -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sbsdpcmdev.h 347614 2012-07-27 10:24:51Z $ -+ */ -+ -+#ifndef _sbsdpcmdev_h_ -+#define _sbsdpcmdev_h_ -+ -+/* cpp contortions to concatenate w/arg prescan */ -+#ifndef PAD -+#define _PADLINE(line) pad ## line -+#define _XSTR(line) _PADLINE(line) -+#define PAD _XSTR(__LINE__) -+#endif /* PAD */ -+ -+ -+typedef volatile struct { -+ dma64regs_t xmt; /* dma tx */ -+ uint32 PAD[2]; -+ dma64regs_t rcv; /* dma rx */ -+ uint32 PAD[2]; -+} dma64p_t; -+ -+/* dma64 sdiod corerev >= 1 */ -+typedef volatile struct { -+ dma64p_t dma64regs[2]; -+ dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ -+ uint32 PAD[92]; -+} sdiodma64_t; -+ -+/* dma32 sdiod corerev == 0 */ -+typedef volatile struct { -+ dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ -+ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ -+ uint32 PAD[108]; -+} sdiodma32_t; -+ -+/* dma32 regs for pcmcia core */ -+typedef volatile struct { -+ dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ -+ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ -+ uint32 PAD[116]; -+} pcmdma32_t; -+ -+/* core registers */ -+typedef volatile struct { -+ uint32 corecontrol; /* CoreControl, 0x000, rev8 */ -+ uint32 corestatus; /* CoreStatus, 0x004, rev8 */ -+ uint32 PAD[1]; -+ uint32 biststatus; /* BistStatus, 0x00c, rev8 */ -+ -+ /* PCMCIA access */ -+ uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ -+ uint16 PAD[1]; -+ uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ -+ uint16 PAD[1]; -+ uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ -+ uint16 PAD[1]; -+ uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ -+ uint16 PAD[1]; -+ -+ /* interrupt */ -+ uint32 intstatus; /* IntStatus, 0x020, rev8 */ -+ uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ -+ uint32 intmask; /* IntSbMask, 0x028, rev8 */ -+ uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ -+ uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ -+ uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ -+ uint32 PAD[2]; -+ uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ -+ uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ -+ uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ -+ uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ -+ -+ /* synchronized access to registers in SDIO clock domain */ -+ uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ -+ uint32 PAD[3]; -+ -+ /* PCMCIA frame control */ -+ uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ -+ uint8 PAD[3]; -+ uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ -+ uint8 PAD[155]; -+ -+ /* interrupt batching control */ -+ uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ -+ uint32 PAD[3]; -+ -+ /* counters */ -+ uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ -+ uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ -+ uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ -+ uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ -+ uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ -+ uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ -+ uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ -+ uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ -+ uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ -+ uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ -+ uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ -+ uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ -+ uint32 PAD[40]; -+ uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ -+ uint32 PAD[7]; -+ -+ /* DMA engines */ -+ volatile union { -+ pcmdma32_t pcm32; -+ sdiodma32_t sdiod32; -+ sdiodma64_t sdiod64; -+ } dma; -+ -+ /* SDIO/PCMCIA CIS region */ -+ char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ -+ -+ /* PCMCIA function control registers */ -+ char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ -+ uint16 PAD[55]; -+ -+ /* PCMCIA backplane access */ -+ uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ -+ uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ -+ uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ -+ uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ -+ uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ -+ uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ -+ uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ -+ uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ -+ uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ -+ uint16 PAD[31]; -+ -+ /* sprom "size" & "blank" info */ -+ uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ -+ uint32 PAD[464]; -+ -+ /* Sonics SiliconBackplane registers */ -+ sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ -+} sdpcmd_regs_t; -+ -+/* corecontrol */ -+#define CC_CISRDY (1 << 0) /* CIS Ready */ -+#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ -+#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ -+#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ -+#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ -+#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ -+ -+/* corestatus */ -+#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ -+#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ -+#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ -+ -+#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ -+#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ -+#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ -+#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ -+ -+/* intstatus */ -+#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ -+#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ -+#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ -+#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ -+#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ -+#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ -+#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ -+#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ -+#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ -+#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ -+#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ -+#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ -+#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ -+#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ -+#define I_PC (1 << 10) /* descriptor error */ -+#define I_PD (1 << 11) /* data error */ -+#define I_DE (1 << 12) /* Descriptor protocol Error */ -+#define I_RU (1 << 13) /* Receive descriptor Underflow */ -+#define I_RO (1 << 14) /* Receive fifo Overflow */ -+#define I_XU (1 << 15) /* Transmit fifo Underflow */ -+#define I_RI (1 << 16) /* Receive Interrupt */ -+#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ -+#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ -+#define I_XI (1 << 24) /* Transmit Interrupt */ -+#define I_RF_TERM (1 << 25) /* Read Frame Terminate */ -+#define I_WF_TERM (1 << 26) /* Write Frame Terminate */ -+#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ -+#define I_SBINT (1 << 28) /* sbintstatus Interrupt */ -+#define I_CHIPACTIVE (1 << 29) /* chip transitioned from doze to active state */ -+#define I_SRESET (1 << 30) /* CCCR RES interrupt */ -+#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ -+#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) /* DMA Errors */ -+#define I_DMA (I_RI | I_XI | I_ERRORS) -+ -+/* sbintstatus */ -+#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ -+#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ -+#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ -+ -+/* sdioaccess */ -+#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ -+#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ -+#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ -+#define SDA_WRITE 0x01000000 /* Write bit */ -+#define SDA_READ 0x00000000 /* Write bit cleared for Read */ -+#define SDA_BUSY 0x80000000 /* Busy bit */ -+ -+/* sdioaccess-accessible register address spaces */ -+#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ -+#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ -+#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ -+#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ -+ -+/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ -+#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ -+#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ -+#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ -+#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ -+#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ -+#define SDA_SBADDRMID 0x00b /* SbAddrMid */ -+#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ -+#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ -+#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ -+#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ -+#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ -+#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ -+#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ -+#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ -+ -+/* SDA_F2WATERMARK */ -+#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ -+ -+/* SDA_SBADDRLOW */ -+#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ -+ -+/* SDA_SBADDRMID */ -+#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ -+ -+/* SDA_SBADDRHIGH */ -+#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ -+ -+/* SDA_FRAMECTRL */ -+#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ -+#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ -+#define SFC_CRC4WOOS (1 << 2) /* HW reports CRC error for write out of sync */ -+#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ -+ -+/* pcmciaframectrl */ -+#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ -+#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ -+ -+/* intrcvlazy */ -+#define IRL_TO_MASK 0x00ffffff /* timeout */ -+#define IRL_FC_MASK 0xff000000 /* frame count */ -+#define IRL_FC_SHIFT 24 /* frame count */ -+ -+/* rx header */ -+typedef volatile struct { -+ uint16 len; -+ uint16 flags; -+} sdpcmd_rxh_t; -+ -+/* rx header flags */ -+#define RXF_CRC 0x0001 /* CRC error detected */ -+#define RXF_WOOS 0x0002 /* write frame out of sync */ -+#define RXF_WF_TERM 0x0004 /* write frame terminated */ -+#define RXF_ABORT 0x0008 /* write frame aborted */ -+#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ -+ -+/* HW frame tag */ -+#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ -+ -+#define SDPCM_HWEXT_LEN 8 -+ -+#endif /* _sbsdpcmdev_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h -new file mode 100644 -index 00000000..852d1151 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sbsocram.h -@@ -0,0 +1,193 @@ -+/* -+ * BCM47XX Sonics SiliconBackplane embedded ram core -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sbsocram.h 271781 2011-07-13 20:00:06Z $ -+ */ -+ -+#ifndef _SBSOCRAM_H -+#define _SBSOCRAM_H -+ -+#ifndef _LANGUAGE_ASSEMBLY -+ -+ -+#ifndef PAD -+#define _PADLINE(line) pad ## line -+#define _XSTR(line) _PADLINE(line) -+#define PAD _XSTR(__LINE__) -+#endif -+ -+ -+typedef volatile struct sbsocramregs { -+ uint32 coreinfo; -+ uint32 bwalloc; -+ uint32 extracoreinfo; -+ uint32 biststat; -+ uint32 bankidx; -+ uint32 standbyctrl; -+ -+ uint32 errlogstatus; -+ uint32 errlogaddr; -+ -+ uint32 cambankidx; -+ uint32 cambankstandbyctrl; -+ uint32 cambankpatchctrl; -+ uint32 cambankpatchtblbaseaddr; -+ uint32 cambankcmdreg; -+ uint32 cambankdatareg; -+ uint32 cambankmaskreg; -+ uint32 PAD[1]; -+ uint32 bankinfo; -+ uint32 PAD[15]; -+ uint32 extmemconfig; -+ uint32 extmemparitycsr; -+ uint32 extmemparityerrdata; -+ uint32 extmemparityerrcnt; -+ uint32 extmemwrctrlandsize; -+ uint32 PAD[84]; -+ uint32 workaround; -+ uint32 pwrctl; -+ uint32 PAD[133]; -+ uint32 sr_control; -+ uint32 sr_status; -+ uint32 sr_address; -+ uint32 sr_data; -+} sbsocramregs_t; -+ -+#endif -+ -+ -+#define SR_COREINFO 0x00 -+#define SR_BWALLOC 0x04 -+#define SR_BISTSTAT 0x0c -+#define SR_BANKINDEX 0x10 -+#define SR_BANKSTBYCTL 0x14 -+#define SR_PWRCTL 0x1e8 -+ -+ -+#define SRCI_PT_MASK 0x00070000 -+#define SRCI_PT_SHIFT 16 -+ -+#define SRCI_PT_OCP_OCP 0 -+#define SRCI_PT_AXI_OCP 1 -+#define SRCI_PT_ARM7AHB_OCP 2 -+#define SRCI_PT_CM3AHB_OCP 3 -+#define SRCI_PT_AXI_AXI 4 -+#define SRCI_PT_AHB_AXI 5 -+ -+#define SRCI_LSS_MASK 0x00f00000 -+#define SRCI_LSS_SHIFT 20 -+#define SRCI_LRS_MASK 0x0f000000 -+#define SRCI_LRS_SHIFT 24 -+ -+ -+#define SRCI_MS0_MASK 0xf -+#define SR_MS0_BASE 16 -+ -+ -+#define SRCI_ROMNB_MASK 0xf000 -+#define SRCI_ROMNB_SHIFT 12 -+#define SRCI_ROMBSZ_MASK 0xf00 -+#define SRCI_ROMBSZ_SHIFT 8 -+#define SRCI_SRNB_MASK 0xf0 -+#define SRCI_SRNB_SHIFT 4 -+#define SRCI_SRBSZ_MASK 0xf -+#define SRCI_SRBSZ_SHIFT 0 -+ -+#define SR_BSZ_BASE 14 -+ -+ -+#define SRSC_SBYOVR_MASK 0x80000000 -+#define SRSC_SBYOVR_SHIFT 31 -+#define SRSC_SBYOVRVAL_MASK 0x60000000 -+#define SRSC_SBYOVRVAL_SHIFT 29 -+#define SRSC_SBYEN_MASK 0x01000000 -+#define SRSC_SBYEN_SHIFT 24 -+ -+ -+#define SRPC_PMU_STBYDIS_MASK 0x00000010 -+#define SRPC_PMU_STBYDIS_SHIFT 4 -+#define SRPC_STBYOVRVAL_MASK 0x00000008 -+#define SRPC_STBYOVRVAL_SHIFT 3 -+#define SRPC_STBYOVR_MASK 0x00000007 -+#define SRPC_STBYOVR_SHIFT 0 -+ -+ -+#define SRECC_NUM_BANKS_MASK 0x000000F0 -+#define SRECC_NUM_BANKS_SHIFT 4 -+#define SRECC_BANKSIZE_MASK 0x0000000F -+#define SRECC_BANKSIZE_SHIFT 0 -+ -+#define SRECC_BANKSIZE(value) (1 << (value)) -+ -+ -+#define SRCBPC_PATCHENABLE 0x80000000 -+ -+#define SRP_ADDRESS 0x0001FFFC -+#define SRP_VALID 0x8000 -+ -+ -+#define SRCMD_WRITE 0x00020000 -+#define SRCMD_READ 0x00010000 -+#define SRCMD_DONE 0x80000000 -+ -+#define SRCMD_DONE_DLY 1000 -+ -+ -+#define SOCRAM_BANKINFO_SZMASK 0x7f -+#define SOCRAM_BANKIDX_ROM_MASK 0x100 -+ -+#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 -+ -+#define SOCRAM_MEMTYPE_RAM 0 -+#define SOCRAM_MEMTYPE_R0M 1 -+#define SOCRAM_MEMTYPE_DEVRAM 2 -+ -+#define SOCRAM_BANKINFO_REG 0x40 -+#define SOCRAM_BANKIDX_REG 0x10 -+#define SOCRAM_BANKINFO_STDBY_MASK 0x400 -+#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 -+ -+ -+#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 -+#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 -+#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 -+#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 -+#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 -+#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 -+#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 -+#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 -+#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 -+#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 -+#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 -+#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 -+ -+ -+#define SOCRAM_DEVRAMBANK_MASK 0xF000 -+#define SOCRAM_DEVRAMBANK_SHIFT 12 -+ -+ -+#define SOCRAM_BANKINFO_SZBASE 8192 -+#define SOCRAM_BANKSIZE_SHIFT 13 -+ -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h -new file mode 100644 -index 00000000..b8eee1ff ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sdio.h -@@ -0,0 +1,617 @@ -+/* -+ * SDIO spec header file -+ * Protocol and standard (common) device definitions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sdio.h 308973 2012-01-18 04:19:34Z $ -+ */ -+ -+#ifndef _SDIO_H -+#define _SDIO_H -+ -+ -+/* CCCR structure for function 0 */ -+typedef volatile struct { -+ uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ -+ uint8 sd_rev; /* RO, sd spec revision */ -+ uint8 io_en; /* I/O enable */ -+ uint8 io_rdy; /* I/O ready reg */ -+ uint8 intr_ctl; /* Master and per function interrupt enable control */ -+ uint8 intr_status; /* RO, interrupt pending status */ -+ uint8 io_abort; /* read/write abort or reset all functions */ -+ uint8 bus_inter; /* bus interface control */ -+ uint8 capability; /* RO, card capability */ -+ -+ uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ -+ uint8 cis_base_mid; -+ uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ -+ -+ /* suspend/resume registers */ -+ uint8 bus_suspend; /* 0xC */ -+ uint8 func_select; /* 0xD */ -+ uint8 exec_flag; /* 0xE */ -+ uint8 ready_flag; /* 0xF */ -+ -+ uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ -+ -+ uint8 power_control; /* 0x12 (SDIO version 1.10) */ -+ -+ uint8 speed_control; /* 0x13 */ -+} sdio_regs_t; -+ -+/* SDIO Device CCCR offsets */ -+#define SDIOD_CCCR_REV 0x00 -+#define SDIOD_CCCR_SDREV 0x01 -+#define SDIOD_CCCR_IOEN 0x02 -+#define SDIOD_CCCR_IORDY 0x03 -+#define SDIOD_CCCR_INTEN 0x04 -+#define SDIOD_CCCR_INTPEND 0x05 -+#define SDIOD_CCCR_IOABORT 0x06 -+#define SDIOD_CCCR_BICTRL 0x07 -+#define SDIOD_CCCR_CAPABLITIES 0x08 -+#define SDIOD_CCCR_CISPTR_0 0x09 -+#define SDIOD_CCCR_CISPTR_1 0x0A -+#define SDIOD_CCCR_CISPTR_2 0x0B -+#define SDIOD_CCCR_BUSSUSP 0x0C -+#define SDIOD_CCCR_FUNCSEL 0x0D -+#define SDIOD_CCCR_EXECFLAGS 0x0E -+#define SDIOD_CCCR_RDYFLAGS 0x0F -+#define SDIOD_CCCR_BLKSIZE_0 0x10 -+#define SDIOD_CCCR_BLKSIZE_1 0x11 -+#define SDIOD_CCCR_POWER_CONTROL 0x12 -+#define SDIOD_CCCR_SPEED_CONTROL 0x13 -+#define SDIOD_CCCR_UHSI_SUPPORT 0x14 -+#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 -+#define SDIOD_CCCR_INTR_EXTN 0x16 -+ -+/* Broadcom extensions (corerev >= 1) */ -+#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 -+#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 -+#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 -+#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 -+#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 -+#define SDIOD_CCCR_BRCM_SEPINT 0xf2 -+ -+/* cccr_sdio_rev */ -+#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ -+#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ -+ -+/* sd_rev */ -+#define SD_REV_PHY_MASK 0x0f /* SD format version number */ -+ -+/* io_en */ -+#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ -+#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ -+ -+/* io_rdys */ -+#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ -+#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ -+ -+/* intr_ctl */ -+#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ -+#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ -+#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ -+ -+/* intr_status */ -+#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ -+#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ -+ -+/* io_abort */ -+#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ -+#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ -+ -+/* bus_inter */ -+#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ -+#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ -+#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ -+#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ -+#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ -+#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ -+ -+/* capability */ -+#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ -+#define SDIO_CAP_LSC 0x40 /* low speed card */ -+#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ -+#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ -+#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ -+#define SDIO_CAP_SRW 0x04 /* support read wait */ -+#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ -+#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ -+ -+/* power_control */ -+#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ -+#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ -+ -+/* speed_control (control device entry into high-speed clocking mode) */ -+#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ -+#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ -+ -+/* for setting bus speed in card: 0x13h */ -+#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) -+#define SDIO_BUS_SPEED_UHSISEL_S 1 -+ -+/* for getting bus speed cap in card: 0x14h */ -+#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) -+#define SDIO_BUS_SPEED_UHSICAP_S 0 -+ -+/* for getting driver type CAP in card: 0x15h */ -+#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) -+#define SDIO_BUS_DRVR_TYPE_CAP_S 0 -+ -+/* for setting driver type selection in card: 0x15h */ -+#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) -+#define SDIO_BUS_DRVR_TYPE_SEL_S 4 -+ -+/* for getting async int support in card: 0x16h */ -+#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) -+#define SDIO_BUS_ASYNCINT_CAP_S 0 -+ -+/* for setting async int selection in card: 0x16h */ -+#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) -+#define SDIO_BUS_ASYNCINT_SEL_S 1 -+ -+/* brcm sepint */ -+#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ -+#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ -+#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ -+ -+/* FBR structure for function 1-7, FBR addresses and register offsets */ -+typedef volatile struct { -+ uint8 devctr; /* device interface, CSA control */ -+ uint8 ext_dev; /* extended standard I/O device type code */ -+ uint8 pwr_sel; /* power selection support */ -+ uint8 PAD[6]; /* reserved */ -+ -+ uint8 cis_low; /* CIS LSB */ -+ uint8 cis_mid; -+ uint8 cis_high; /* CIS MSB */ -+ uint8 csa_low; /* code storage area, LSB */ -+ uint8 csa_mid; -+ uint8 csa_high; /* code storage area, MSB */ -+ uint8 csa_dat_win; /* data access window to function */ -+ -+ uint8 fnx_blk_size[2]; /* block size, little endian */ -+} sdio_fbr_t; -+ -+/* Maximum number of I/O funcs */ -+#define SDIOD_MAX_FUNCS 8 -+#define SDIOD_MAX_IOFUNCS 7 -+ -+/* SDIO Device FBR Start Address */ -+#define SDIOD_FBR_STARTADDR 0x100 -+ -+/* SDIO Device FBR Size */ -+#define SDIOD_FBR_SIZE 0x100 -+ -+/* Macro to calculate FBR register base */ -+#define SDIOD_FBR_BASE(n) ((n) * 0x100) -+ -+/* Function register offsets */ -+#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ -+#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ -+#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ -+ -+/* SDIO Function CIS ptr offset */ -+#define SDIOD_FBR_CISPTR_0 0x09 -+#define SDIOD_FBR_CISPTR_1 0x0A -+#define SDIOD_FBR_CISPTR_2 0x0B -+ -+/* Code Storage Area pointer */ -+#define SDIOD_FBR_CSA_ADDR_0 0x0C -+#define SDIOD_FBR_CSA_ADDR_1 0x0D -+#define SDIOD_FBR_CSA_ADDR_2 0x0E -+#define SDIOD_FBR_CSA_DATA 0x0F -+ -+/* SDIO Function I/O Block Size */ -+#define SDIOD_FBR_BLKSIZE_0 0x10 -+#define SDIOD_FBR_BLKSIZE_1 0x11 -+ -+/* devctr */ -+#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ -+#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ -+#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ -+/* interface codes */ -+#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ -+#define SDIOD_DIC_UART 1 -+#define SDIOD_DIC_BLUETOOTH_A 2 -+#define SDIOD_DIC_BLUETOOTH_B 3 -+#define SDIOD_DIC_GPS 4 -+#define SDIOD_DIC_CAMERA 5 -+#define SDIOD_DIC_PHS 6 -+#define SDIOD_DIC_WLAN 7 -+#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ -+ -+/* pwr_sel */ -+#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ -+#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ -+ -+/* misc defines */ -+#define SDIO_FUNC_0 0 -+#define SDIO_FUNC_1 1 -+#define SDIO_FUNC_2 2 -+#define SDIO_FUNC_3 3 -+#define SDIO_FUNC_4 4 -+#define SDIO_FUNC_5 5 -+#define SDIO_FUNC_6 6 -+#define SDIO_FUNC_7 7 -+ -+#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ -+#define SD_CARD_TYPE_IO 1 /* IO only card */ -+#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ -+#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ -+ -+#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ -+#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ -+ -+/* Card registers: status bit position */ -+#define CARDREG_STATUS_BIT_OUTOFRANGE 31 -+#define CARDREG_STATUS_BIT_COMCRCERROR 23 -+#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 -+#define CARDREG_STATUS_BIT_ERROR 19 -+#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 -+#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 -+#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 -+#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 -+#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 -+ -+ -+ -+#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ -+#define SD_CMD_SEND_OPCOND 1 -+#define SD_CMD_MMC_SET_RCA 3 -+#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ -+#define SD_CMD_SELECT_DESELECT_CARD 7 -+#define SD_CMD_SEND_CSD 9 -+#define SD_CMD_SEND_CID 10 -+#define SD_CMD_STOP_TRANSMISSION 12 -+#define SD_CMD_SEND_STATUS 13 -+#define SD_CMD_GO_INACTIVE_STATE 15 -+#define SD_CMD_SET_BLOCKLEN 16 -+#define SD_CMD_READ_SINGLE_BLOCK 17 -+#define SD_CMD_READ_MULTIPLE_BLOCK 18 -+#define SD_CMD_WRITE_BLOCK 24 -+#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 -+#define SD_CMD_PROGRAM_CSD 27 -+#define SD_CMD_SET_WRITE_PROT 28 -+#define SD_CMD_CLR_WRITE_PROT 29 -+#define SD_CMD_SEND_WRITE_PROT 30 -+#define SD_CMD_ERASE_WR_BLK_START 32 -+#define SD_CMD_ERASE_WR_BLK_END 33 -+#define SD_CMD_ERASE 38 -+#define SD_CMD_LOCK_UNLOCK 42 -+#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ -+#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ -+#define SD_CMD_APP_CMD 55 -+#define SD_CMD_GEN_CMD 56 -+#define SD_CMD_READ_OCR 58 -+#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ -+#define SD_ACMD_SD_STATUS 13 -+#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 -+#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 -+#define SD_ACMD_SD_SEND_OP_COND 41 -+#define SD_ACMD_SET_CLR_CARD_DETECT 42 -+#define SD_ACMD_SEND_SCR 51 -+ -+/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ -+#define SD_IO_OP_READ 0 /* Read_Write: Read */ -+#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ -+#define SD_IO_RW_NORMAL 0 /* no RAW */ -+#define SD_IO_RW_RAW 1 /* RAW */ -+#define SD_IO_BYTE_MODE 0 /* Byte Mode */ -+#define SD_IO_BLOCK_MODE 1 /* BlockMode */ -+#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ -+#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ -+ -+/* build SD_CMD_IO_RW_DIRECT Argument */ -+#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ -+ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ -+ (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) -+ -+/* build SD_CMD_IO_RW_EXTENDED Argument */ -+#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ -+ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ -+ (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) -+ -+/* SDIO response parameters */ -+#define SD_RSP_NO_NONE 0 -+#define SD_RSP_NO_1 1 -+#define SD_RSP_NO_2 2 -+#define SD_RSP_NO_3 3 -+#define SD_RSP_NO_4 4 -+#define SD_RSP_NO_5 5 -+#define SD_RSP_NO_6 6 -+ -+ /* Modified R6 response (to CMD3) */ -+#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 -+#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 -+#define SD_RSP_MR6_ERROR 0x2000 -+ -+ /* Modified R1 in R4 Response (to CMD5) */ -+#define SD_RSP_MR1_SBIT 0x80 -+#define SD_RSP_MR1_PARAMETER_ERROR 0x40 -+#define SD_RSP_MR1_RFU5 0x20 -+#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 -+#define SD_RSP_MR1_COM_CRC_ERROR 0x08 -+#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 -+#define SD_RSP_MR1_RFU1 0x02 -+#define SD_RSP_MR1_IDLE_STATE 0x01 -+ -+ /* R5 response (to CMD52 and CMD53) */ -+#define SD_RSP_R5_COM_CRC_ERROR 0x80 -+#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 -+#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 -+#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 -+#define SD_RSP_R5_ERROR 0x08 -+#define SD_RSP_R5_RFU 0x04 -+#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 -+#define SD_RSP_R5_OUT_OF_RANGE 0x01 -+ -+#define SD_RSP_R5_ERRBITS 0xCB -+ -+ -+/* ------------------------------------------------ -+ * SDIO Commands and responses -+ * -+ * I/O only commands are: -+ * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 -+ * ------------------------------------------------ -+ */ -+ -+/* SDIO Commands */ -+#define SDIOH_CMD_0 0 -+#define SDIOH_CMD_3 3 -+#define SDIOH_CMD_5 5 -+#define SDIOH_CMD_7 7 -+#define SDIOH_CMD_11 11 -+#define SDIOH_CMD_14 14 -+#define SDIOH_CMD_15 15 -+#define SDIOH_CMD_19 19 -+#define SDIOH_CMD_52 52 -+#define SDIOH_CMD_53 53 -+#define SDIOH_CMD_59 59 -+ -+/* SDIO Command Responses */ -+#define SDIOH_RSP_NONE 0 -+#define SDIOH_RSP_R1 1 -+#define SDIOH_RSP_R2 2 -+#define SDIOH_RSP_R3 3 -+#define SDIOH_RSP_R4 4 -+#define SDIOH_RSP_R5 5 -+#define SDIOH_RSP_R6 6 -+ -+/* -+ * SDIO Response Error flags -+ */ -+#define SDIOH_RSP5_ERROR_FLAGS 0xCB -+ -+/* ------------------------------------------------ -+ * SDIO Command structures. I/O only commands are: -+ * -+ * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 -+ * ------------------------------------------------ -+ */ -+ -+#define CMD5_OCR_M BITFIELD_MASK(24) -+#define CMD5_OCR_S 0 -+ -+#define CMD5_S18R_M BITFIELD_MASK(1) -+#define CMD5_S18R_S 24 -+ -+#define CMD7_RCA_M BITFIELD_MASK(16) -+#define CMD7_RCA_S 16 -+ -+#define CMD14_RCA_M BITFIELD_MASK(16) -+#define CMD14_RCA_S 16 -+#define CMD14_SLEEP_M BITFIELD_MASK(1) -+#define CMD14_SLEEP_S 15 -+ -+#define CMD_15_RCA_M BITFIELD_MASK(16) -+#define CMD_15_RCA_S 16 -+ -+#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 -+ */ -+#define CMD52_DATA_S 0 -+#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ -+#define CMD52_REG_ADDR_S 9 -+#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ -+#define CMD52_RAW_S 27 -+#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ -+#define CMD52_FUNCTION_S 28 -+#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ -+#define CMD52_RW_FLAG_S 31 -+ -+ -+#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ -+#define CMD53_BYTE_BLK_CNT_S 0 -+#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ -+#define CMD53_REG_ADDR_S 9 -+#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ -+#define CMD53_OP_CODE_S 26 -+#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ -+#define CMD53_BLK_MODE_S 27 -+#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ -+#define CMD53_FUNCTION_S 28 -+#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ -+#define CMD53_RW_FLAG_S 31 -+ -+/* ------------------------------------------------------ -+ * SDIO Command Response structures for SD1 and SD4 modes -+ * ----------------------------------------------------- -+ */ -+#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ -+#define RSP4_IO_OCR_S 0 -+ -+#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ -+#define RSP4_S18A_S 24 -+ -+#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ -+#define RSP4_STUFF_S 24 -+#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ -+#define RSP4_MEM_PRESENT_S 27 -+#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ -+#define RSP4_NUM_FUNCS_S 28 -+#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ -+#define RSP4_CARD_READY_S 31 -+ -+#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] -+ */ -+#define RSP6_STATUS_S 0 -+#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ -+#define RSP6_IO_RCA_S 16 -+ -+#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ -+#define RSP1_AKE_SEQ_ERROR_S 3 -+#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ -+#define RSP1_APP_CMD_S 5 -+#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ -+#define RSP1_READY_FOR_DATA_S 8 -+#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card -+ * when Cmd was received -+ */ -+#define RSP1_CURR_STATE_S 9 -+#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ -+#define RSP1_EARSE_RESET_S 13 -+#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ -+#define RSP1_CARD_ECC_DISABLE_S 14 -+#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ -+#define RSP1_WP_ERASE_SKIP_S 15 -+#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits -+ * of CSD -+ */ -+#define RSP1_CID_CSD_OVERW_S 16 -+#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ -+#define RSP1_ERROR_S 19 -+#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ -+#define RSP1_CC_ERROR_S 20 -+#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed -+ * to correct data -+ */ -+#define RSP1_CARD_ECC_FAILED_S 21 -+#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ -+#define RSP1_ILLEGAL_CMD_S 22 -+#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed -+ */ -+#define RSP1_COM_CRC_ERROR_S 23 -+#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ -+#define RSP1_LOCK_UNLOCK_FAIL_S 24 -+#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ -+#define RSP1_CARD_LOCKED_S 25 -+#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program -+ * write-protected blocks -+ */ -+#define RSP1_WP_VIOLATION_S 26 -+#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ -+#define RSP1_ERASE_PARAM_S 27 -+#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ -+#define RSP1_ERASE_SEQ_ERR_S 28 -+#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ -+#define RSP1_BLK_LEN_ERR_S 29 -+#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ -+#define RSP1_ADDR_ERR_S 30 -+#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ -+#define RSP1_OUT_OF_RANGE_S 31 -+ -+ -+#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ -+#define RSP5_DATA_S 0 -+#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ -+#define RSP5_FLAGS_S 8 -+#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ -+#define RSP5_STUFF_S 16 -+ -+/* ---------------------------------------------- -+ * SDIO Command Response structures for SPI mode -+ * ---------------------------------------------- -+ */ -+#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ -+#define SPIRSP4_IO_OCR_S 0 -+#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ -+#define SPIRSP4_STUFF_S 16 -+#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ -+#define SPIRSP4_MEM_PRESENT_S 19 -+#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ -+#define SPIRSP4_NUM_FUNCS_S 20 -+#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ -+#define SPIRSP4_CARD_READY_S 23 -+#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ -+#define SPIRSP4_IDLE_STATE_S 24 -+#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ -+#define SPIRSP4_ILLEGAL_CMD_S 26 -+#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ -+#define SPIRSP4_COM_CRC_ERROR_S 27 -+#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error -+ */ -+#define SPIRSP4_FUNC_NUM_ERROR_S 28 -+#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ -+#define SPIRSP4_PARAM_ERROR_S 30 -+#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ -+#define SPIRSP4_START_BIT_S 31 -+ -+#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ -+#define SPIRSP5_DATA_S 16 -+#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ -+#define SPIRSP5_IDLE_STATE_S 24 -+#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ -+#define SPIRSP5_ILLEGAL_CMD_S 26 -+#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ -+#define SPIRSP5_COM_CRC_ERROR_S 27 -+#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error -+ */ -+#define SPIRSP5_FUNC_NUM_ERROR_S 28 -+#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ -+#define SPIRSP5_PARAM_ERROR_S 30 -+#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ -+#define SPIRSP5_START_BIT_S 31 -+ -+/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ -+#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error -+ */ -+#define RSP6STAT_AKE_SEQ_ERROR_S 3 -+#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ -+#define RSP6STAT_APP_CMD_S 5 -+#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data -+ * (buff empty) -+ */ -+#define RSP6STAT_READY_FOR_DATA_S 8 -+#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at -+ * Cmd reception -+ */ -+#define RSP6STAT_CURR_STATE_S 9 -+#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 -+ */ -+#define RSP6STAT_ERROR_S 13 -+#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for -+ * card state Bit 22 -+ */ -+#define RSP6STAT_ILLEGAL_CMD_S 14 -+#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command -+ * failed Bit 23 -+ */ -+#define RSP6STAT_COM_CRC_ERROR_S 15 -+ -+#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ -+#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE -+ -+/* command issue options */ -+#define CMD_OPTION_DEFAULT 0 -+#define CMD_OPTION_TUNING 1 -+#endif /* _SDIO_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h -new file mode 100644 -index 00000000..5517a718 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sdioh.h -@@ -0,0 +1,445 @@ -+/* -+ * SDIO Host Controller Spec header file -+ * Register map and definitions for the Standard Host Controller -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sdioh.h 347633 2012-07-27 11:02:02Z $ -+ */ -+ -+#ifndef _SDIOH_H -+#define _SDIOH_H -+ -+#define SD_SysAddr 0x000 -+#define SD_BlockSize 0x004 -+#define SD_BlockCount 0x006 -+#define SD_Arg0 0x008 -+#define SD_Arg1 0x00A -+#define SD_TransferMode 0x00C -+#define SD_Command 0x00E -+#define SD_Response0 0x010 -+#define SD_Response1 0x012 -+#define SD_Response2 0x014 -+#define SD_Response3 0x016 -+#define SD_Response4 0x018 -+#define SD_Response5 0x01A -+#define SD_Response6 0x01C -+#define SD_Response7 0x01E -+#define SD_BufferDataPort0 0x020 -+#define SD_BufferDataPort1 0x022 -+#define SD_PresentState 0x024 -+#define SD_HostCntrl 0x028 -+#define SD_PwrCntrl 0x029 -+#define SD_BlockGapCntrl 0x02A -+#define SD_WakeupCntrl 0x02B -+#define SD_ClockCntrl 0x02C -+#define SD_TimeoutCntrl 0x02E -+#define SD_SoftwareReset 0x02F -+#define SD_IntrStatus 0x030 -+#define SD_ErrorIntrStatus 0x032 -+#define SD_IntrStatusEnable 0x034 -+#define SD_ErrorIntrStatusEnable 0x036 -+#define SD_IntrSignalEnable 0x038 -+#define SD_ErrorIntrSignalEnable 0x03A -+#define SD_CMD12ErrorStatus 0x03C -+#define SD_Capabilities 0x040 -+#define SD_Capabilities3 0x044 -+#define SD_MaxCurCap 0x048 -+#define SD_MaxCurCap_Reserved 0x04C -+#define SD_ADMA_ErrStatus 0x054 -+#define SD_ADMA_SysAddr 0x58 -+#define SD_SlotInterruptStatus 0x0FC -+#define SD_HostControllerVersion 0x0FE -+#define SD_GPIO_Reg 0x100 -+#define SD_GPIO_OE 0x104 -+#define SD_GPIO_Enable 0x108 -+ -+/* SD specific registers in PCI config space */ -+#define SD_SlotInfo 0x40 -+ -+/* HC 3.0 specific registers and offsets */ -+#define SD3_HostCntrl2 0x03E -+/* preset regsstart and count */ -+#define SD3_PresetValStart 0x060 -+#define SD3_PresetValCount 8 -+/* preset-indiv regs */ -+#define SD3_PresetVal_init 0x060 -+#define SD3_PresetVal_default 0x062 -+#define SD3_PresetVal_HS 0x064 -+#define SD3_PresetVal_SDR12 0x066 -+#define SD3_PresetVal_SDR25 0x068 -+#define SD3_PresetVal_SDR50 0x06a -+#define SD3_PresetVal_SDR104 0x06c -+#define SD3_PresetVal_DDR50 0x06e -+/* SDIO3.0 Revx specific Registers */ -+#define SD3_Tuning_Info_Register 0x0EC -+#define SD3_WL_BT_reset_register 0x0F0 -+ -+ -+/* preset value indices */ -+#define SD3_PRESETVAL_INITIAL_IX 0 -+#define SD3_PRESETVAL_DESPEED_IX 1 -+#define SD3_PRESETVAL_HISPEED_IX 2 -+#define SD3_PRESETVAL_SDR12_IX 3 -+#define SD3_PRESETVAL_SDR25_IX 4 -+#define SD3_PRESETVAL_SDR50_IX 5 -+#define SD3_PRESETVAL_SDR104_IX 6 -+#define SD3_PRESETVAL_DDR50_IX 7 -+ -+/* SD_Capabilities reg (0x040) */ -+#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) -+#define CAP_TO_CLKFREQ_S 0 -+#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) -+#define CAP_TO_CLKUNIT_S 7 -+/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 -+ bits are reserved. going ahead with 8 bits, as it is req for 3.0 -+*/ -+#define CAP_BASECLK_M BITFIELD_MASK(8) -+#define CAP_BASECLK_S 8 -+#define CAP_MAXBLOCK_M BITFIELD_MASK(2) -+#define CAP_MAXBLOCK_S 16 -+#define CAP_ADMA2_M BITFIELD_MASK(1) -+#define CAP_ADMA2_S 19 -+#define CAP_ADMA1_M BITFIELD_MASK(1) -+#define CAP_ADMA1_S 20 -+#define CAP_HIGHSPEED_M BITFIELD_MASK(1) -+#define CAP_HIGHSPEED_S 21 -+#define CAP_DMA_M BITFIELD_MASK(1) -+#define CAP_DMA_S 22 -+#define CAP_SUSPEND_M BITFIELD_MASK(1) -+#define CAP_SUSPEND_S 23 -+#define CAP_VOLT_3_3_M BITFIELD_MASK(1) -+#define CAP_VOLT_3_3_S 24 -+#define CAP_VOLT_3_0_M BITFIELD_MASK(1) -+#define CAP_VOLT_3_0_S 25 -+#define CAP_VOLT_1_8_M BITFIELD_MASK(1) -+#define CAP_VOLT_1_8_S 26 -+#define CAP_64BIT_HOST_M BITFIELD_MASK(1) -+#define CAP_64BIT_HOST_S 28 -+ -+#define SDIO_OCR_READ_FAIL (2) -+ -+ -+#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) -+#define CAP_ASYNCINT_SUP_S 29 -+ -+#define CAP_SLOTTYPE_M BITFIELD_MASK(2) -+#define CAP_SLOTTYPE_S 30 -+ -+#define CAP3_MSBits_OFFSET (32) -+/* note: following are caps MSB32 bits. -+ So the bits start from 0, instead of 32. that is why -+ CAP3_MSBits_OFFSET is subtracted. -+*/ -+#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) -+#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) -+#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) -+#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) -+ -+/* for knowing the clk caps in a single read */ -+#define CAP3_30CLKCAP_M BITFIELD_MASK(3) -+#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) -+#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) -+#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) -+#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) -+#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) -+#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) -+#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) -+ -+#define CAP3_CLK_MULT_M BITFIELD_MASK(8) -+#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) -+ -+#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) -+#define PRESET_DRIVR_SELECT_S 14 -+ -+#define PRESET_CLK_DIV_M BITFIELD_MASK(10) -+#define PRESET_CLK_DIV_S 0 -+ -+/* SD_MaxCurCap reg (0x048) */ -+#define CAP_CURR_3_3_M BITFIELD_MASK(8) -+#define CAP_CURR_3_3_S 0 -+#define CAP_CURR_3_0_M BITFIELD_MASK(8) -+#define CAP_CURR_3_0_S 8 -+#define CAP_CURR_1_8_M BITFIELD_MASK(8) -+#define CAP_CURR_1_8_S 16 -+ -+/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ -+ -+/* SD_BlockSize: Offset 0x004, Size 2 bytes */ -+#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) -+#define BLKSZ_BLKSZ_S 0 -+#define BLKSZ_BNDRY_M BITFIELD_MASK(3) -+#define BLKSZ_BNDRY_S 12 -+ -+/* SD_BlockCount: Offset 0x006, size 2 bytes */ -+ -+/* SD_Arg0: Offset 0x008, size = 4 bytes */ -+/* SD_TransferMode Offset 0x00C, size = 2 bytes */ -+#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) -+#define XFER_DMA_ENABLE_S 0 -+#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) -+#define XFER_BLK_COUNT_EN_S 1 -+#define XFER_CMD_12_EN_M BITFIELD_MASK(1) -+#define XFER_CMD_12_EN_S 2 -+#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) -+#define XFER_DATA_DIRECTION_S 4 -+#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) -+#define XFER_MULTI_BLOCK_S 5 -+ -+/* SD_Command: Offset 0x00E, size = 2 bytes */ -+/* resp_type field */ -+#define RESP_TYPE_NONE 0 -+#define RESP_TYPE_136 1 -+#define RESP_TYPE_48 2 -+#define RESP_TYPE_48_BUSY 3 -+/* type field */ -+#define CMD_TYPE_NORMAL 0 -+#define CMD_TYPE_SUSPEND 1 -+#define CMD_TYPE_RESUME 2 -+#define CMD_TYPE_ABORT 3 -+ -+#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ -+#define CMD_RESP_TYPE_S 0 -+#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ -+#define CMD_CRC_EN_S 3 -+#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ -+#define CMD_INDEX_EN_S 4 -+#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ -+#define CMD_DATA_EN_S 5 -+#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc -+ */ -+#define CMD_TYPE_S 6 -+#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ -+#define CMD_INDEX_S 8 -+ -+/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ -+/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ -+/* SD_PresentState : Offset 0x024, size = 4 bytes */ -+#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ -+#define PRES_CMD_INHIBIT_S 0 -+#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ -+#define PRES_DAT_INHIBIT_S 1 -+#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ -+#define PRES_DAT_BUSY_S 2 -+#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ -+#define PRES_PRESENT_RSVD_S 3 -+#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ -+#define PRES_WRITE_ACTIVE_S 8 -+#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ -+#define PRES_READ_ACTIVE_S 9 -+#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ -+#define PRES_WRITE_DATA_RDY_S 10 -+#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ -+#define PRES_READ_DATA_RDY_S 11 -+#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ -+#define PRES_CARD_PRESENT_S 16 -+#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ -+#define PRES_CARD_STABLE_S 17 -+#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ -+#define PRES_CARD_PRESENT_RAW_S 18 -+#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ -+#define PRES_WRITE_ENABLED_S 19 -+#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ -+#define PRES_DAT_SIGNAL_S 20 -+#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ -+#define PRES_CMD_SIGNAL_S 24 -+ -+/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ -+#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ -+#define HOST_LED_S 0 -+#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ -+#define HOST_DATA_WIDTH_S 1 -+#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ -+#define HOST_DMA_SEL_S 3 -+#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ -+#define HOST_HI_SPEED_EN_S 2 -+ -+/* Host Control2: */ -+#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ -+#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ -+ -+#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ -+#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ -+ -+#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ -+#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ -+ -+#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ -+#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ -+ -+#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ -+#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ -+ -+#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ -+#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ -+ -+#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ -+#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ -+ -+#define HOST_CONTR_VER_2 (1) -+#define HOST_CONTR_VER_3 (2) -+ -+/* misc defines */ -+#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ -+#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ -+ -+/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ -+#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ -+#define PWR_BUS_EN_S 0 -+#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ -+#define PWR_VOLTS_S 1 -+ -+/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ -+#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ -+#define SW_RESET_ALL_S 0 -+#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ -+#define SW_RESET_CMD_S 1 -+#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ -+#define SW_RESET_DAT_S 2 -+ -+/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ -+/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ -+#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ -+#define INTSTAT_CMD_COMPLETE_S 0 -+#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) -+#define INTSTAT_XFER_COMPLETE_S 1 -+#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) -+#define INTSTAT_BLOCK_GAP_EVENT_S 2 -+#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) -+#define INTSTAT_DMA_INT_S 3 -+#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) -+#define INTSTAT_BUF_WRITE_READY_S 4 -+#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) -+#define INTSTAT_BUF_READ_READY_S 5 -+#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) -+#define INTSTAT_CARD_INSERTION_S 6 -+#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) -+#define INTSTAT_CARD_REMOVAL_S 7 -+#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) -+#define INTSTAT_CARD_INT_S 8 -+#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ -+#define INTSTAT_RETUNING_INT_S 12 -+#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ -+#define INTSTAT_ERROR_INT_S 15 -+ -+/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ -+/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ -+#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) -+#define ERRINT_CMD_TIMEOUT_S 0 -+#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) -+#define ERRINT_CMD_CRC_S 1 -+#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) -+#define ERRINT_CMD_ENDBIT_S 2 -+#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) -+#define ERRINT_CMD_INDEX_S 3 -+#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) -+#define ERRINT_DATA_TIMEOUT_S 4 -+#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) -+#define ERRINT_DATA_CRC_S 5 -+#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) -+#define ERRINT_DATA_ENDBIT_S 6 -+#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) -+#define ERRINT_CURRENT_LIMIT_S 7 -+#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) -+#define ERRINT_AUTO_CMD12_S 8 -+#define ERRINT_VENDOR_M BITFIELD_MASK(4) -+#define ERRINT_VENDOR_S 12 -+#define ERRINT_ADMA_M BITFIELD_MASK(1) -+#define ERRINT_ADMA_S 9 -+ -+/* Also provide definitions in "normal" form to allow combined masks */ -+#define ERRINT_CMD_TIMEOUT_BIT 0x0001 -+#define ERRINT_CMD_CRC_BIT 0x0002 -+#define ERRINT_CMD_ENDBIT_BIT 0x0004 -+#define ERRINT_CMD_INDEX_BIT 0x0008 -+#define ERRINT_DATA_TIMEOUT_BIT 0x0010 -+#define ERRINT_DATA_CRC_BIT 0x0020 -+#define ERRINT_DATA_ENDBIT_BIT 0x0040 -+#define ERRINT_CURRENT_LIMIT_BIT 0x0080 -+#define ERRINT_AUTO_CMD12_BIT 0x0100 -+#define ERRINT_ADMA_BIT 0x0200 -+ -+/* Masks to select CMD vs. DATA errors */ -+#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ -+ ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) -+#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ -+ ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) -+#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) -+ -+/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ -+/* SD_ClockCntrl : Offset 0x02C , size = bytes */ -+/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ -+/* SD_IntrStatus : Offset 0x030 , size = bytes */ -+/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ -+/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ -+/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ -+/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ -+/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ -+/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ -+/* SD_Capabilities : Offset 0x040 , size = bytes */ -+/* SD_MaxCurCap : Offset 0x048 , size = bytes */ -+/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ -+/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ -+/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ -+ -+/* SDIO Host Control Register DMA Mode Definitions */ -+#define SDIOH_SDMA_MODE 0 -+#define SDIOH_ADMA1_MODE 1 -+#define SDIOH_ADMA2_MODE 2 -+#define SDIOH_ADMA2_64_MODE 3 -+ -+#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ -+#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ -+#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ -+#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ -+#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ -+#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ -+#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ -+#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ -+ -+/* ADMA2 Descriptor Table Entry for 32-bit Address */ -+typedef struct adma2_dscr_32b { -+ uint32 len_attr; -+ uint32 phys_addr; -+} adma2_dscr_32b_t; -+ -+/* ADMA1 Descriptor Table Entry */ -+typedef struct adma1_dscr { -+ uint32 phys_addr_attr; -+} adma1_dscr_t; -+ -+#endif /* _SDIOH_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h -new file mode 100644 -index 00000000..83f82de2 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h -@@ -0,0 +1,58 @@ -+/* -+ * Structure used by apps whose drivers access SDIO drivers. -+ * Pulled out separately so dhdu and wlu can both use it. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sdiovar.h 241182 2011-02-17 21:50:03Z $ -+ */ -+ -+#ifndef _sdiovar_h_ -+#define _sdiovar_h_ -+ -+#include <typedefs.h> -+ -+/* require default structure packing */ -+#define BWL_DEFAULT_PACKING -+#include <packed_section_start.h> -+ -+typedef struct sdreg { -+ int func; -+ int offset; -+ int value; -+} sdreg_t; -+ -+/* Common msglevel constants */ -+#define SDH_ERROR_VAL 0x0001 /* Error */ -+#define SDH_TRACE_VAL 0x0002 /* Trace */ -+#define SDH_INFO_VAL 0x0004 /* Info */ -+#define SDH_DEBUG_VAL 0x0008 /* Debug */ -+#define SDH_DATA_VAL 0x0010 /* Data */ -+#define SDH_CTRL_VAL 0x0020 /* Control Regs */ -+#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */ -+#define SDH_DMA_VAL 0x0080 /* DMA */ -+ -+#define NUM_PREV_TRANSACTIONS 16 -+ -+ -+#include <packed_section_end.h> -+ -+#endif /* _sdiovar_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h -new file mode 100644 -index 00000000..a797b3d1 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/siutils.h -@@ -0,0 +1,332 @@ -+/* -+ * Misc utility routines for accessing the SOC Interconnects -+ * of Broadcom HNBU chips. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: siutils.h 347614 2012-07-27 10:24:51Z $ -+ */ -+ -+#ifndef _siutils_h_ -+#define _siutils_h_ -+ -+ -+struct si_pub { -+ uint socitype; -+ -+ uint bustype; -+ uint buscoretype; -+ uint buscorerev; -+ uint buscoreidx; -+ int ccrev; -+ uint32 cccaps; -+ uint32 cccaps_ext; -+ int pmurev; -+ uint32 pmucaps; -+ uint boardtype; -+ uint boardrev; -+ uint boardvendor; -+ uint boardflags; -+ uint boardflags2; -+ uint chip; -+ uint chiprev; -+ uint chippkg; -+ uint32 chipst; -+ bool issim; -+ uint socirev; -+ bool pci_pr32414; -+ -+}; -+ -+ -+typedef const struct si_pub si_t; -+ -+ -+ -+#define SI_OSH NULL -+ -+#define BADIDX (SI_MAXCORES + 1) -+ -+ -+#define XTAL 0x1 -+#define PLL 0x2 -+ -+ -+#define CLK_FAST 0 -+#define CLK_DYNAMIC 2 -+ -+ -+#define GPIO_DRV_PRIORITY 0 -+#define GPIO_APP_PRIORITY 1 -+#define GPIO_HI_PRIORITY 2 -+ -+ -+#define GPIO_PULLUP 0 -+#define GPIO_PULLDN 1 -+ -+ -+#define GPIO_REGEVT 0 -+#define GPIO_REGEVT_INTMSK 1 -+#define GPIO_REGEVT_INTPOL 2 -+ -+ -+#define SI_DEVPATH_BUFSZ 16 -+ -+ -+#define SI_DOATTACH 1 -+#define SI_PCIDOWN 2 -+#define SI_PCIUP 3 -+ -+#define ISSIM_ENAB(sih) 0 -+ -+ -+#if defined(BCMPMUCTL) -+#define PMUCTL_ENAB(sih) (BCMPMUCTL) -+#else -+#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) -+#endif -+ -+ -+#if defined(BCMPMUCTL) && BCMPMUCTL -+#define CCCTL_ENAB(sih) (0) -+#define CCPLL_ENAB(sih) (0) -+#else -+#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL) -+#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK) -+#endif -+ -+typedef void (*gpio_handler_t)(uint32 stat, void *arg); -+ -+#define CC_BTCOEX_EN_MASK 0x01 -+ -+#define GPIO_CTRL_EPA_EN_MASK 0x40 -+ -+#define GPIO_CTRL_5_6_EN_MASK 0x60 -+#define GPIO_CTRL_7_6_EN_MASK 0xC0 -+#define GPIO_OUT_7_EN_MASK 0x80 -+ -+ -+ -+#define SI_CR4_CAP (0x04) -+#define SI_CR4_BANKIDX (0x40) -+#define SI_CR4_BANKINFO (0x44) -+ -+#define ARMCR4_TCBBNB_MASK 0xf0 -+#define ARMCR4_TCBBNB_SHIFT 4 -+#define ARMCR4_TCBANB_MASK 0xf -+#define ARMCR4_TCBANB_SHIFT 0 -+ -+#define SICF_CPUHALT (0x0020) -+#define ARMCR4_BSZ_MASK 0x3f -+#define ARMCR4_BSZ_MULT 8192 -+ -+ -+ -+extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, -+ void *sdh, char **vars, uint *varsz); -+extern si_t *si_kattach(osl_t *osh); -+extern void si_detach(si_t *sih); -+extern bool si_pci_war16165(si_t *sih); -+ -+extern uint si_corelist(si_t *sih, uint coreid[]); -+extern uint si_coreid(si_t *sih); -+extern uint si_flag(si_t *sih); -+extern uint si_intflag(si_t *sih); -+extern uint si_coreidx(si_t *sih); -+extern uint si_coreunit(si_t *sih); -+extern uint si_corevendor(si_t *sih); -+extern uint si_corerev(si_t *sih); -+extern void *si_osh(si_t *sih); -+extern void si_setosh(si_t *sih, osl_t *osh); -+extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -+extern void *si_coreregs(si_t *sih); -+extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); -+extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); -+extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -+extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); -+extern bool si_iscoreup(si_t *sih); -+extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); -+extern void *si_setcoreidx(si_t *sih, uint coreidx); -+extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); -+extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); -+extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); -+extern int si_numaddrspaces(si_t *sih); -+extern uint32 si_addrspace(si_t *sih, uint asidx); -+extern uint32 si_addrspacesize(si_t *sih, uint asidx); -+extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); -+extern int si_corebist(si_t *sih); -+extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -+extern void si_core_disable(si_t *sih, uint32 bits); -+extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); -+extern bool si_read_pmu_autopll(si_t *sih); -+extern uint32 si_clock(si_t *sih); -+extern uint32 si_alp_clock(si_t *sih); -+extern uint32 si_ilp_clock(si_t *sih); -+extern void si_pci_setup(si_t *sih, uint coremask); -+extern void si_pcmcia_init(si_t *sih); -+extern void si_setint(si_t *sih, int siflag); -+extern bool si_backplane64(si_t *sih); -+extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, -+ void *intrsenabled_fn, void *intr_arg); -+extern void si_deregister_intr_callback(si_t *sih); -+extern void si_clkctl_init(si_t *sih); -+extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); -+extern bool si_clkctl_cc(si_t *sih, uint mode); -+extern int si_clkctl_xtal(si_t *sih, uint what, bool on); -+extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); -+extern void si_btcgpiowar(si_t *sih); -+extern bool si_deviceremoved(si_t *sih); -+extern uint32 si_socram_size(si_t *sih); -+extern uint32 si_socdevram_size(si_t *sih); -+extern uint32 si_socram_srmem_size(si_t *sih); -+extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); -+extern bool si_socdevram_pkg(si_t *sih); -+extern bool si_socdevram_remap_isenb(si_t *sih); -+extern uint32 si_socdevram_remap_size(si_t *sih); -+ -+extern void si_watchdog(si_t *sih, uint ticks); -+extern void si_watchdog_ms(si_t *sih, uint32 ms); -+extern uint32 si_watchdog_msticks(void); -+extern void *si_gpiosetcore(si_t *sih); -+extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); -+extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); -+extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); -+extern uint32 si_gpioin(si_t *sih); -+extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); -+extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); -+extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); -+extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); -+extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); -+extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); -+extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); -+extern uint32 si_gpio_int_enable(si_t *sih, bool enable); -+ -+ -+extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); -+extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); -+extern void si_gpio_handler_process(si_t *sih); -+ -+ -+extern bool si_pci_pmecap(si_t *sih); -+struct osl_info; -+extern bool si_pci_fastpmecap(struct osl_info *osh); -+extern bool si_pci_pmestat(si_t *sih); -+extern void si_pci_pmeclr(si_t *sih); -+extern void si_pci_pmeen(si_t *sih); -+extern void si_pci_pmestatclr(si_t *sih); -+extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); -+ -+extern void si_sdio_init(si_t *sih); -+ -+extern uint16 si_d11_devid(si_t *sih); -+extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, -+ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); -+ -+#define si_eci(sih) 0 -+static INLINE void * si_eci_init(si_t *sih) {return NULL;} -+#define si_eci_notify_bt(sih, type, val) (0) -+#define si_seci(sih) 0 -+#define si_seci_upd(sih, a) do {} while (0) -+static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} -+#define si_seci_down(sih) do {} while (0) -+ -+ -+extern bool si_is_otp_disabled(si_t *sih); -+extern bool si_is_otp_powered(si_t *sih); -+extern void si_otp_power(si_t *sih, bool on); -+ -+ -+extern bool si_is_sprom_available(si_t *sih); -+extern bool si_is_sprom_enabled(si_t *sih); -+extern void si_sprom_enable(si_t *sih, bool enable); -+ -+ -+extern int si_cis_source(si_t *sih); -+#define CIS_DEFAULT 0 -+#define CIS_SROM 1 -+#define CIS_OTP 2 -+ -+ -+#define DEFAULT_FAB 0x0 -+#define CSM_FAB7 0x1 -+#define TSMC_FAB12 0x2 -+#define SMIC_FAB4 0x3 -+extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); -+extern uint16 si_fabid(si_t *sih); -+ -+ -+extern int si_devpath(si_t *sih, char *path, int size); -+ -+extern char *si_getdevpathvar(si_t *sih, const char *name); -+extern int si_getdevpathintvar(si_t *sih, const char *name); -+extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); -+ -+ -+extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); -+extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); -+extern void si_war42780_clkreq(si_t *sih, bool clkreq); -+extern void si_pci_down(si_t *sih); -+extern void si_pci_up(si_t *sih); -+extern void si_pci_sleep(si_t *sih); -+extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); -+extern void si_pcie_power_save_enable(si_t *sih, bool enable); -+extern void si_pcie_extendL1timer(si_t *sih, bool extend); -+extern int si_pci_fixcfg(si_t *sih); -+extern void si_chippkg_set(si_t *sih, uint); -+ -+extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); -+extern void si_chipcontrl_restore(si_t *sih, uint32 val); -+extern uint32 si_chipcontrl_read(si_t *sih); -+extern void si_chipcontrl_epa4331(si_t *sih, bool on); -+extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); -+extern void si_chipcontrl_srom4360(si_t *sih, bool on); -+ -+extern void si_epa_4313war(si_t *sih); -+extern void si_btc_enable_chipcontrol(si_t *sih); -+ -+extern void si_btcombo_p250_4313_war(si_t *sih); -+extern void si_btcombo_43228_war(si_t *sih); -+extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); -+extern uint si_pll_reset(si_t *sih); -+ -+ -+extern bool si_taclear(si_t *sih, bool details); -+ -+ -+ -+extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); -+extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); -+extern void si_pcie_set_request_size(si_t *sih, uint16 size); -+extern uint16 si_pcie_get_request_size(si_t *sih); -+extern uint16 si_pcie_get_ssid(si_t *sih); -+extern uint32 si_pcie_get_bar0(si_t *sih); -+extern int si_pcie_configspace_cache(si_t *sih); -+extern int si_pcie_configspace_restore(si_t *sih); -+extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); -+ -+char *si_getnvramflvar(si_t *sih, const char *name); -+ -+ -+extern uint32 si_tcm_size(si_t *sih); -+ -+extern int si_set_sromctl(si_t *sih, uint32 value); -+extern uint32 si_get_sromctl(si_t *sih); -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h -new file mode 100644 -index 00000000..bf92a565 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/trxhdr.h -@@ -0,0 +1,53 @@ -+/* -+ * TRX image file header format. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: trxhdr.h 260898 2011-05-20 23:11:12Z $ -+ */ -+ -+#ifndef _TRX_HDR_H -+#define _TRX_HDR_H -+ -+#include <typedefs.h> -+ -+#define TRX_MAGIC 0x30524448 /* "HDR0" */ -+#define TRX_VERSION 1 /* Version 1 */ -+#define TRX_MAX_LEN 0x3B0000 /* Max length */ -+#define TRX_NO_HEADER 1 /* Do not write TRX header */ -+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ -+#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ -+#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ -+#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ -+#define TRX_MAX_OFFSET 3 /* Max number of individual files */ -+ -+struct trx_header { -+ uint32 magic; /* "HDR0" */ -+ uint32 len; /* Length of file including header */ -+ uint32 crc32; /* 32-bit CRC from flag_version to end of file */ -+ uint32 flag_version; /* 0:15 flags, 16:31 version */ -+ uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ -+}; -+ -+/* Compatibility */ -+typedef struct trx_header TRXHDR, *PTRXHDR; -+ -+#endif /* _TRX_HDR_H */ -diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h -new file mode 100644 -index 00000000..4eee5bab ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/typedefs.h -@@ -0,0 +1,310 @@ -+/* -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * $Id: typedefs.h 286783 2011-09-29 06:18:57Z $ -+ */ -+ -+#ifndef _TYPEDEFS_H_ -+#define _TYPEDEFS_H_ -+ -+#ifdef SITE_TYPEDEFS -+ -+ -+ -+#include "site_typedefs.h" -+ -+#else -+ -+ -+ -+#ifdef __cplusplus -+ -+#define TYPEDEF_BOOL -+#ifndef FALSE -+#define FALSE false -+#endif -+#ifndef TRUE -+#define TRUE true -+#endif -+ -+#else -+ -+ -+#endif -+ -+#if defined(__x86_64__) -+#define TYPEDEF_UINTPTR -+typedef unsigned long long int uintptr; -+#endif -+ -+ -+ -+ -+ -+#if defined(_NEED_SIZE_T_) -+typedef long unsigned int size_t; -+#endif -+ -+ -+ -+ -+#if defined(__sparc__) -+#define TYPEDEF_ULONG -+#endif -+ -+ -+ -+#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) -+#define TYPEDEF_UINT -+#ifndef TARGETENV_android -+#define TYPEDEF_USHORT -+#define TYPEDEF_ULONG -+#endif -+#ifdef __KERNEL__ -+#include <linux/version.h> -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) -+#define TYPEDEF_BOOL -+#endif -+ -+#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) -+#include <linux/compiler.h> -+#ifdef noinline_for_stack -+#define TYPEDEF_BOOL -+#endif -+#endif -+#endif -+#endif -+ -+ -+ -+ -+ -+#if defined(__GNUC__) && defined(__STRICT_ANSI__) -+#define TYPEDEF_INT64 -+#define TYPEDEF_UINT64 -+#endif -+ -+ -+#if defined(__ICL) -+ -+#define TYPEDEF_INT64 -+ -+#if defined(__STDC__) -+#define TYPEDEF_UINT64 -+#endif -+ -+#endif -+ -+#if !defined(__DJGPP__) -+ -+ -+#if defined(__KERNEL__) -+ -+ -+#if !defined(LINUX_HYBRID) || defined(LINUX_PORT) -+#include <linux/types.h> -+#endif -+ -+#else -+ -+ -+#include <sys/types.h> -+ -+#endif -+ -+#endif -+ -+ -+ -+ -+#define USE_TYPEDEF_DEFAULTS -+ -+#endif -+ -+ -+ -+ -+#ifdef USE_TYPEDEF_DEFAULTS -+#undef USE_TYPEDEF_DEFAULTS -+ -+#ifndef TYPEDEF_BOOL -+typedef unsigned char bool; -+#endif -+ -+ -+ -+#ifndef TYPEDEF_UCHAR -+typedef unsigned char uchar; -+#endif -+ -+#ifndef TYPEDEF_USHORT -+typedef unsigned short ushort; -+#endif -+ -+#ifndef TYPEDEF_UINT -+typedef unsigned int uint; -+#endif -+ -+#ifndef TYPEDEF_ULONG -+typedef unsigned long ulong; -+#endif -+ -+ -+ -+#ifndef TYPEDEF_UINT8 -+typedef unsigned char uint8; -+#endif -+ -+#ifndef TYPEDEF_UINT16 -+typedef unsigned short uint16; -+#endif -+ -+#ifndef TYPEDEF_UINT32 -+typedef unsigned int uint32; -+#endif -+ -+#ifndef TYPEDEF_UINT64 -+typedef unsigned long long uint64; -+#endif -+ -+#ifndef TYPEDEF_UINTPTR -+typedef unsigned int uintptr; -+#endif -+ -+#ifndef TYPEDEF_INT8 -+typedef signed char int8; -+#endif -+ -+#ifndef TYPEDEF_INT16 -+typedef signed short int16; -+#endif -+ -+#ifndef TYPEDEF_INT32 -+typedef signed int int32; -+#endif -+ -+#ifndef TYPEDEF_INT64 -+typedef signed long long int64; -+#endif -+ -+ -+ -+#ifndef TYPEDEF_FLOAT32 -+typedef float float32; -+#endif -+ -+#ifndef TYPEDEF_FLOAT64 -+typedef double float64; -+#endif -+ -+ -+ -+#ifndef TYPEDEF_FLOAT_T -+ -+#if defined(FLOAT32) -+typedef float32 float_t; -+#else -+typedef float64 float_t; -+#endif -+ -+#endif -+ -+ -+ -+#ifndef FALSE -+#define FALSE 0 -+#endif -+ -+#ifndef TRUE -+#define TRUE 1 -+#endif -+ -+#ifndef NULL -+#define NULL 0 -+#endif -+ -+#ifndef OFF -+#define OFF 0 -+#endif -+ -+#ifndef ON -+#define ON 1 -+#endif -+ -+#define AUTO (-1) -+ -+ -+ -+#ifndef PTRSZ -+#define PTRSZ sizeof(char*) -+#endif -+ -+ -+ -+#if defined(__GNUC__) || defined(__lint) -+ #define BWL_COMPILER_GNU -+#elif defined(__CC_ARM) && __CC_ARM -+ #define BWL_COMPILER_ARMCC -+#else -+ #error "Unknown compiler!" -+#endif -+ -+ -+#ifndef INLINE -+ #if defined(BWL_COMPILER_MICROSOFT) -+ #define INLINE __inline -+ #elif defined(BWL_COMPILER_GNU) -+ #define INLINE __inline__ -+ #elif defined(BWL_COMPILER_ARMCC) -+ #define INLINE __inline -+ #else -+ #define INLINE -+ #endif -+#endif -+ -+#undef TYPEDEF_BOOL -+#undef TYPEDEF_UCHAR -+#undef TYPEDEF_USHORT -+#undef TYPEDEF_UINT -+#undef TYPEDEF_ULONG -+#undef TYPEDEF_UINT8 -+#undef TYPEDEF_UINT16 -+#undef TYPEDEF_UINT32 -+#undef TYPEDEF_UINT64 -+#undef TYPEDEF_UINTPTR -+#undef TYPEDEF_INT8 -+#undef TYPEDEF_INT16 -+#undef TYPEDEF_INT32 -+#undef TYPEDEF_INT64 -+#undef TYPEDEF_FLOAT32 -+#undef TYPEDEF_FLOAT64 -+#undef TYPEDEF_FLOAT_T -+ -+#endif -+ -+ -+#define UNUSED_PARAMETER(x) (void)(x) -+ -+ -+#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) -+ -+ -+#include <bcmdefs.h> -+#endif -diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h -new file mode 100644 -index 00000000..6b421b5d ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h -@@ -0,0 +1,233 @@ -+/* -+* Copyright (C) 1999-2012, Broadcom Corporation -+* -+* Unless you and Broadcom execute a separate written software license -+* agreement governing use of this software, this software is licensed to you -+* under the terms of the GNU General Public License version 2 (the "GPL"), -+* available at http://www.broadcom.com/licenses/GPLv2.php, with the -+* following added to such license: -+* -+* As a special exception, the copyright holders of this software give you -+* permission to link this software with independent modules, and to copy and -+* distribute the resulting executable under terms of your choice, provided that -+* you also meet, for each linked independent module, the terms and conditions of -+* the license of that module. An independent module is a module which is not -+* derived from this software. The special exception does not apply to any -+* modifications of the software. -+* -+* Notwithstanding the above, under no circumstances may you combine this -+* software in any way with any other Broadcom software provided under a license -+* other than the GPL, without Broadcom's express prior written consent. -+* $Id: wlfc_proto.h 361006 2012-10-05 07:45:51Z $ -+* -+*/ -+#ifndef __wlfc_proto_definitions_h__ -+#define __wlfc_proto_definitions_h__ -+ -+ /* Use TLV to convey WLFC information. -+ --------------------------------------------------------------------------- -+ | Type | Len | value | Description -+ --------------------------------------------------------------------------- -+ | 1 | 1 | (handle) | MAC OPEN -+ --------------------------------------------------------------------------- -+ | 2 | 1 | (handle) | MAC CLOSE -+ --------------------------------------------------------------------------- -+ | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn -+ --------------------------------------------------------------------------- -+ | 4 | 4 | see pkttag comments | TXSTATUS -+ --------------------------------------------------------------------------- -+ | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] -+ --------------------------------------------------------------------------- -+ | 6 | 8 | (handle, ifid, MAC) | MAC ADD -+ --------------------------------------------------------------------------- -+ | 7 | 8 | (handle, ifid, MAC) | MAC DEL -+ --------------------------------------------------------------------------- -+ | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. -+ --------------------------------------------------------------------------- -+ | 9 | 1 | (interface ID) | Interface OPEN -+ --------------------------------------------------------------------------- -+ | 10 | 1 | (interface ID) | Interface CLOSE -+ --------------------------------------------------------------------------- -+ | 11 | 8 | fifo credit returns map | FIFO credits back to the host -+ | | | | -+ | | | | -------------------------------------- -+ | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | -+ | | | | -------------------------------------- -+ | | | | -+ --------------------------------------------------------------------------- -+ | 12 | 2 | MAC handle, | Host provides a bitmap of pending -+ | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. -+ | | | | [host->firmware] -+ --------------------------------------------------------------------------- -+ | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific -+ | | | | MAC destination. -+ --------------------------------------------------------------------------- -+ | 15 | 1 | interface ID | NIC period start -+ --------------------------------------------------------------------------- -+ | 16 | 1 | interface ID | NIC period end -+ --------------------------------------------------------------------------- -+ | 17 | 3 | (ifid, txs) | Action frame tx status -+ --------------------------------------------------------------------------- -+ | 255 | N/A | N/A | FILLER - This is a special type -+ | | | | that has no length or value. -+ | | | | Typically used for padding. -+ --------------------------------------------------------------------------- -+ */ -+ -+#define WLFC_CTL_TYPE_MAC_OPEN 1 -+#define WLFC_CTL_TYPE_MAC_CLOSE 2 -+#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 -+#define WLFC_CTL_TYPE_TXSTATUS 4 -+#define WLFC_CTL_TYPE_PKTTAG 5 -+ -+#define WLFC_CTL_TYPE_MACDESC_ADD 6 -+#define WLFC_CTL_TYPE_MACDESC_DEL 7 -+#define WLFC_CTL_TYPE_RSSI 8 -+ -+#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 -+#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 -+ -+#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 -+ -+#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 -+#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 -+#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 -+ -+#define WLFC_CTL_TYPE_NIC_PRD_START 15 -+#define WLFC_CTL_TYPE_NIC_PRD_END 16 -+#define WLFC_CTL_TYPE_AF_TXS 17 -+#define WLFC_CTL_TYPE_TRANS_ID 18 -+#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 -+ -+#define WLFC_CTL_TYPE_FILLER 255 -+ -+#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */ -+ -+#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */ -+#define WLFC_CTL_VALUE_LEN_RSSI 1 -+ -+#define WLFC_CTL_VALUE_LEN_INTERFACE 1 -+#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 -+ -+#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 -+#define WLFC_CTL_VALUE_LEN_PKTTAG 4 -+ -+/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ -+#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 -+ -+#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ -+#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ -+ -+#define WLFC_CTL_VALUE_LEN_NIC_PRD_START 1 -+#define WLFC_CTL_VALUE_LEN_NIC_PRD_END 1 -+#define WLFC_CTL_VALUE_LEN_AF_TXS 3 -+ -+ -+#define WLFC_PKTID_GEN_MASK 0x80000000 -+#define WLFC_PKTID_GEN_SHIFT 31 -+ -+#define WLFC_PKTID_GEN(x) (((x) & WLFC_PKTID_GEN_MASK) >> WLFC_PKTID_GEN_SHIFT) -+#define WLFC_PKTID_SETGEN(x, gen) (x) = ((x) & ~WLFC_PKTID_GEN_MASK) | \ -+ (((gen) << WLFC_PKTID_GEN_SHIFT) & WLFC_PKTID_GEN_MASK) -+ -+#define WLFC_PKTFLAG_PKTFROMHOST 0x01 -+#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 -+ -+#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ -+#define WL_TXSTATUS_FLAGS_SHIFT 27 -+ -+#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ -+ ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ -+ (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) -+#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ -+ WL_TXSTATUS_FLAGS_MASK) -+ -+#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ -+#define WL_TXSTATUS_FIFO_SHIFT 24 -+ -+#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ -+ ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ -+ (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) -+#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) -+ -+#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ -+#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ -+ ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) -+#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) -+ -+/* 32 STA should be enough??, 6 bits; Must be power of 2 */ -+#define WLFC_MAC_DESC_TABLE_SIZE 32 -+#define WLFC_MAX_IFNUM 16 -+#define WLFC_MAC_DESC_ID_INVALID 0xff -+ -+/* b[7:5] -reuse guard, b[4:0] -value */ -+#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) -+ -+#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \ -+ (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) -+ -+#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \ -+ ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) -+ -+#define WL_TXSTATUS_GENERATION_MASK 1 -+#define WL_TXSTATUS_GENERATION_SHIFT 31 -+ -+#define WLFC_PKTFLAG_SET_GENERATION(x, gen) ((x) = \ -+ ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ -+ (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) -+ -+#define WLFC_PKTFLAG_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ -+ WL_TXSTATUS_GENERATION_MASK) -+ -+#define WLFC_MAX_PENDING_DATALEN 120 -+ -+/* host is free to discard the packet */ -+#define WLFC_CTL_PKTFLAG_DISCARD 0 -+/* D11 suppressed a packet */ -+#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 -+/* WL firmware suppressed a packet because MAC is -+ already in PSMode (short time window) -+*/ -+#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 -+/* Firmware tossed this packet */ -+#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 -+ -+#define WLFC_D11_STATUS_INTERPRET(txs) \ -+ (((txs)->status.suppr_ind != 0) ? WLFC_CTL_PKTFLAG_D11SUPPRESS : WLFC_CTL_PKTFLAG_DISCARD) -+ -+#ifdef PROP_TXSTATUS_DEBUG -+#define WLFC_DBGMESG(x) printf x -+/* wlfc-breadcrumb */ -+#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \ -+ {printf("WLFC: %s():%d:caller:%p\n", \ -+ __FUNCTION__, __LINE__, __builtin_return_address(0));}} while (0) -+#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \ -+ banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0) -+#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s)) -+#else -+#define WLFC_DBGMESG(x) -+#define WLFC_BREADCRUMB(x) -+#define WLFC_PRINTMAC(banner, ea) -+#define WLFC_WHEREIS(s) -+#endif -+ -+/* AMPDU host reorder packet flags */ -+#define WLHOST_REORDERDATA_MAXFLOWS 256 -+#define WLHOST_REORDERDATA_LEN 10 -+#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ -+ -+#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 -+#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 -+#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 -+#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 -+#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 -+ -+#define WLHOST_REORDERDATA_DEL_FLOW 0x01 -+#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 -+#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 -+#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 -+#define WLHOST_REORDERDATA_NEW_HOLE 0x10 -+/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ -+#define WLFC_CTL_TRANS_ID_LEN 6 -+ -+#endif /* __wlfc_proto_definitions_h__ */ -diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h -new file mode 100644 -index 00000000..c8c19950 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h -@@ -0,0 +1,5052 @@ -+/* -+ * Custom OID/ioctl definitions for -+ * Broadcom 802.11abg Networking Device Driver -+ * -+ * Definitions subject to change without notice. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wlioctl.h 366141 2012-11-01 01:55:06Z $ -+ */ -+ -+#ifndef _wlioctl_h_ -+#define _wlioctl_h_ -+ -+#include <typedefs.h> -+#include <proto/ethernet.h> -+#include <proto/bcmeth.h> -+#include <proto/bcmevent.h> -+#include <proto/802.11.h> -+#include <bcmwifi_channels.h> -+#include <bcmwifi_rates.h> -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+#include <bcm_mpool_pub.h> -+#include <bcmcdc.h> -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* LINUX_POSTMOGRIFY_REMOVAL: undefined during compile phase, so its -+ * a no-op for most cases. For hybrid and other open source releases, -+ * its defined during a second pass and mogrified out for distribution. -+ */ -+ -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+ -+#ifndef INTF_NAME_SIZ -+#define INTF_NAME_SIZ 16 -+#endif -+ -+/* Used to send ioctls over the transport pipe */ -+typedef struct remote_ioctl { -+ cdc_ioctl_t msg; -+ uint data_len; -+ char intf_name[INTF_NAME_SIZ]; -+} rem_ioctl_t; -+#define REMOTE_SIZE sizeof(rem_ioctl_t) -+ -+#define ACTION_FRAME_SIZE 1800 -+ -+typedef struct wl_action_frame { -+ struct ether_addr da; -+ uint16 len; -+ uint32 packetId; -+ uint8 data[ACTION_FRAME_SIZE]; -+} wl_action_frame_t; -+ -+#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) -+ -+typedef struct ssid_info -+{ -+ uint8 ssid_len; /* the length of SSID */ -+ uint8 ssid[32]; /* SSID string */ -+} ssid_info_t; -+ -+typedef struct wl_af_params { -+ uint32 channel; -+ int32 dwell_time; -+ struct ether_addr BSSID; -+ wl_action_frame_t action_frame; -+} wl_af_params_t; -+ -+#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) -+ -+#define MFP_TEST_FLAG_NORMAL 0 -+#define MFP_TEST_FLAG_ANY_KEY 1 -+typedef struct wl_sa_query { -+ uint32 flag; -+ uint8 action; -+ uint16 id; -+ struct ether_addr da; -+} wl_sa_query_t; -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* require default structure packing */ -+#define BWL_DEFAULT_PACKING -+#include <packed_section_start.h> -+ -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+/* Legacy structure to help keep backward compatible wl tool and tray app */ -+ -+#define LEGACY_WL_BSS_INFO_VERSION 107 /* older version of wl_bss_info struct */ -+ -+typedef struct wl_bss_info_107 { -+ uint32 version; /* version field */ -+ uint32 length; /* byte length of data in this record, -+ * starting at version and including IEs -+ */ -+ struct ether_addr BSSID; -+ uint16 beacon_period; /* units are Kusec */ -+ uint16 capability; /* Capability information */ -+ uint8 SSID_len; -+ uint8 SSID[32]; -+ struct { -+ uint count; /* # rates in this set */ -+ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ -+ } rateset; /* supported rates */ -+ uint8 channel; /* Channel no. */ -+ uint16 atim_window; /* units are Kusec */ -+ uint8 dtim_period; /* DTIM period */ -+ int16 RSSI; /* receive signal strength (in dBm) */ -+ int8 phy_noise; /* noise (in dBm) */ -+ uint32 ie_length; /* byte length of Information Elements */ -+ /* variable length Information Elements */ -+} wl_bss_info_107_t; -+ -+/* -+ * Per-BSS information structure. -+ */ -+ -+#define LEGACY2_WL_BSS_INFO_VERSION 108 /* old version of wl_bss_info struct */ -+ -+/* BSS info structure -+ * Applications MUST CHECK ie_offset field and length field to access IEs and -+ * next bss_info structure in a vector (in wl_scan_results_t) -+ */ -+typedef struct wl_bss_info_108 { -+ uint32 version; /* version field */ -+ uint32 length; /* byte length of data in this record, -+ * starting at version and including IEs -+ */ -+ struct ether_addr BSSID; -+ uint16 beacon_period; /* units are Kusec */ -+ uint16 capability; /* Capability information */ -+ uint8 SSID_len; -+ uint8 SSID[32]; -+ struct { -+ uint count; /* # rates in this set */ -+ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ -+ } rateset; /* supported rates */ -+ chanspec_t chanspec; /* chanspec for bss */ -+ uint16 atim_window; /* units are Kusec */ -+ uint8 dtim_period; /* DTIM period */ -+ int16 RSSI; /* receive signal strength (in dBm) */ -+ int8 phy_noise; /* noise (in dBm) */ -+ -+ uint8 n_cap; /* BSS is 802.11N Capable */ -+ uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */ -+ uint8 ctl_ch; /* 802.11N BSS control channel number */ -+ uint32 reserved32[1]; /* Reserved for expansion of BSS properties */ -+ uint8 flags; /* flags */ -+ uint8 reserved[3]; /* Reserved for expansion of BSS properties */ -+ uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ -+ -+ uint16 ie_offset; /* offset at which IEs start, from beginning */ -+ uint32 ie_length; /* byte length of Information Elements */ -+ /* Add new fields here */ -+ /* variable length Information Elements */ -+} wl_bss_info_108_t; -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */ -+ -+/* BSS info structure -+ * Applications MUST CHECK ie_offset field and length field to access IEs and -+ * next bss_info structure in a vector (in wl_scan_results_t) -+ */ -+typedef struct wl_bss_info { -+ uint32 version; /* version field */ -+ uint32 length; /* byte length of data in this record, -+ * starting at version and including IEs -+ */ -+ struct ether_addr BSSID; -+ uint16 beacon_period; /* units are Kusec */ -+ uint16 capability; /* Capability information */ -+ uint8 SSID_len; -+ uint8 SSID[32]; -+ struct { -+ uint count; /* # rates in this set */ -+ uint8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ -+ } rateset; /* supported rates */ -+ chanspec_t chanspec; /* chanspec for bss */ -+ uint16 atim_window; /* units are Kusec */ -+ uint8 dtim_period; /* DTIM period */ -+ int16 RSSI; /* receive signal strength (in dBm) */ -+ int8 phy_noise; /* noise (in dBm) */ -+ -+ uint8 n_cap; /* BSS is 802.11N Capable */ -+ uint32 nbss_cap; /* 802.11N+AC BSS Capabilities */ -+ uint8 ctl_ch; /* 802.11N BSS control channel number */ -+ uint8 padding1[3]; /* explicit struct alignment padding */ -+ uint16 vht_rxmcsmap; /* VHT rx mcs map */ -+ uint16 vht_txmcsmap; /* VHT tx mcs map */ -+ uint8 flags; /* flags */ -+ uint8 vht_cap; /* BSS is vht capable */ -+ uint8 reserved[2]; /* Reserved for expansion of BSS properties */ -+ uint8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ -+ -+ uint16 ie_offset; /* offset at which IEs start, from beginning */ -+ uint32 ie_length; /* byte length of Information Elements */ -+ int16 SNR; /* average SNR of during frame reception */ -+ /* Add new fields here */ -+ /* variable length Information Elements */ -+} wl_bss_info_t; -+ -+/* bss_info_cap_t flags */ -+#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ -+#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ -+#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info was received on channel (vs offchannel) */ -+ -+/* bssinfo flag for nbss_cap */ -+#define VHT_BI_SGI_80MHZ 0x00000100 -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+ -+typedef struct wl_bsscfg { -+ uint32 wsec; -+ uint32 WPA_auth; -+ uint32 wsec_index; -+ uint32 associated; -+ uint32 BSS; -+ uint32 phytest_on; -+ struct ether_addr prev_BSSID; -+ struct ether_addr BSSID; -+ uint32 targetbss_wpa2_flags; -+ uint32 assoc_type; -+ uint32 assoc_state; -+} wl_bsscfg_t; -+ -+typedef struct wl_bss_config { -+ uint32 atim_window; -+ uint32 beacon_period; -+ uint32 chanspec; -+} wl_bss_config_t; -+ -+#define DLOAD_HANDLER_VER 1 /* Downloader version */ -+#define DLOAD_FLAG_VER_MASK 0xf000 /* Downloader version mask */ -+#define DLOAD_FLAG_VER_SHIFT 12 /* Downloader version shift */ -+ -+#define DL_CRC_NOT_INUSE 0x0001 -+ -+/* generic download types & flags */ -+enum { -+ DL_TYPE_UCODE = 1, -+ DL_TYPE_CLM = 2 -+}; -+ -+/* ucode type values */ -+enum { -+ UCODE_FW, -+ INIT_VALS, -+ BS_INIT_VALS -+}; -+ -+struct wl_dload_data { -+ uint16 flag; -+ uint16 dload_type; -+ uint32 len; -+ uint32 crc; -+ uint8 data[1]; -+}; -+typedef struct wl_dload_data wl_dload_data_t; -+ -+struct wl_ucode_info { -+ uint32 ucode_type; -+ uint32 num_chunks; -+ uint32 chunk_len; -+ uint32 chunk_num; -+ uint8 data_chunk[1]; -+}; -+typedef struct wl_ucode_info wl_ucode_info_t; -+ -+struct wl_clm_dload_info { -+ uint32 ds_id; -+ uint32 clm_total_len; -+ uint32 num_chunks; -+ uint32 chunk_len; -+ uint32 chunk_offset; -+ uint8 data_chunk[1]; -+}; -+typedef struct wl_clm_dload_info wl_clm_dload_info_t; -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+typedef struct wlc_ssid { -+ uint32 SSID_len; -+ uchar SSID[32]; -+} wlc_ssid_t; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+ -+#define MAX_PREFERRED_AP_NUM 5 -+typedef struct wlc_fastssidinfo { -+ uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; -+ wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; -+} wlc_fastssidinfo_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct wnm_url { -+ uint8 len; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT wnm_url_t; -+ -+typedef struct chan_scandata { -+ uint8 txpower; -+ uint8 pad; -+ chanspec_t channel; /* Channel num, bw, ctrl_sb and band */ -+ uint32 channel_mintime; -+ uint32 channel_maxtime; -+} chan_scandata_t; -+ -+typedef enum wl_scan_type { -+ EXTDSCAN_FOREGROUND_SCAN, -+ EXTDSCAN_BACKGROUND_SCAN, -+ EXTDSCAN_FORCEDBACKGROUND_SCAN -+} wl_scan_type_t; -+ -+#define WLC_EXTDSCAN_MAX_SSID 5 -+ -+typedef struct wl_extdscan_params { -+ int8 nprobes; /* 0, passive, otherwise active */ -+ int8 split_scan; /* split scan */ -+ int8 band; /* band */ -+ int8 pad; -+ wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /* ssid list */ -+ uint32 tx_rate; /* in 500ksec units */ -+ wl_scan_type_t scan_type; /* enum */ -+ int32 channel_num; -+ chan_scandata_t channel_list[1]; /* list of chandata structs */ -+} wl_extdscan_params_t; -+ -+#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) -+ -+#define WL_BSSTYPE_INFRA 1 -+#define WL_BSSTYPE_INDEP 0 -+#define WL_BSSTYPE_ANY 2 -+ -+/* Bitmask for scan_type */ -+#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ -+#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ -+#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ -+ -+#define WL_SCAN_PARAMS_SSID_MAX 10 -+ -+typedef struct wl_scan_params { -+ wlc_ssid_t ssid; /* default: {0, ""} */ -+ struct ether_addr bssid; /* default: bcast */ -+ int8 bss_type; /* default: any, -+ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT -+ */ -+ uint8 scan_type; /* flags, 0 use default */ -+ int32 nprobes; /* -1 use default, number of probes per channel */ -+ int32 active_time; /* -1 use default, dwell time per channel for -+ * active scanning -+ */ -+ int32 passive_time; /* -1 use default, dwell time per channel -+ * for passive scanning -+ */ -+ int32 home_time; /* -1 use default, dwell time for the home channel -+ * between channel scans -+ */ -+ int32 channel_num; /* count of channels and ssids that follow -+ * -+ * low half is count of channels in channel_list, 0 -+ * means default (use all available channels) -+ * -+ * high half is entries in wlc_ssid_t array that -+ * follows channel_list, aligned for int32 (4 bytes) -+ * meaning an odd channel count implies a 2-byte pad -+ * between end of channel_list and first ssid -+ * -+ * if ssid count is zero, single ssid in the fixed -+ * parameter portion is assumed, otherwise ssid in -+ * the fixed portion is ignored -+ */ -+ uint16 channel_list[1]; /* list of chanspecs */ -+} wl_scan_params_t; -+ -+/* size of wl_scan_params not including variable length array */ -+#define WL_SCAN_PARAMS_FIXED_SIZE 64 -+ -+/* masks for channel and ssid count */ -+#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff -+#define WL_SCAN_PARAMS_NSSID_SHIFT 16 -+ -+#define WL_SCAN_ACTION_START 1 -+#define WL_SCAN_ACTION_CONTINUE 2 -+#define WL_SCAN_ACTION_ABORT 3 -+ -+#define ISCAN_REQ_VERSION 1 -+ -+/* incremental scan struct */ -+typedef struct wl_iscan_params { -+ uint32 version; -+ uint16 action; -+ uint16 scan_duration; -+ wl_scan_params_t params; -+} wl_iscan_params_t; -+ -+/* 3 fields + size of wl_scan_params, not including variable length array */ -+#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+typedef struct wl_scan_results { -+ uint32 buflen; -+ uint32 version; -+ uint32 count; -+ wl_bss_info_t bss_info[1]; -+} wl_scan_results_t; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+/* size of wl_scan_results not including variable length array */ -+#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) -+ -+/* wl_iscan_results status values */ -+#define WL_SCAN_RESULTS_SUCCESS 0 -+#define WL_SCAN_RESULTS_PARTIAL 1 -+#define WL_SCAN_RESULTS_PENDING 2 -+#define WL_SCAN_RESULTS_ABORTED 3 -+#define WL_SCAN_RESULTS_NO_MEM 4 -+ -+/* Used in EXT_STA */ -+#define DNGL_RXCTXT_SIZE 45 -+ -+ -+#define ESCAN_REQ_VERSION 1 -+ -+typedef struct wl_escan_params { -+ uint32 version; -+ uint16 action; -+ uint16 sync_id; -+ wl_scan_params_t params; -+} wl_escan_params_t; -+ -+#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) -+ -+typedef struct wl_escan_result { -+ uint32 buflen; -+ uint32 version; -+ uint16 sync_id; -+ uint16 bss_count; -+ wl_bss_info_t bss_info[1]; -+} wl_escan_result_t; -+ -+#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) -+ -+/* incremental scan results struct */ -+typedef struct wl_iscan_results { -+ uint32 status; -+ wl_scan_results_t results; -+} wl_iscan_results_t; -+ -+/* size of wl_iscan_results not including variable length array */ -+#define WL_ISCAN_RESULTS_FIXED_SIZE \ -+ (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) -+ -+typedef struct wl_probe_params { -+ wlc_ssid_t ssid; -+ struct ether_addr bssid; -+ struct ether_addr mac; -+} wl_probe_params_t; -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+#define WL_MAXRATES_IN_SET 16 /* max # of rates in a rateset */ -+typedef struct wl_rateset { -+ uint32 count; /* # rates in this set */ -+ uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ -+} wl_rateset_t; -+ -+typedef struct wl_rateset_args { -+ uint32 count; /* # rates in this set */ -+ uint8 rates[WL_MAXRATES_IN_SET]; /* rates in 500kbps units w/hi bit set if basic */ -+ uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ -+} wl_rateset_args_t; -+ -+/* uint32 list */ -+typedef struct wl_uint32_list { -+ /* in - # of elements, out - # of entries */ -+ uint32 count; -+ /* variable length uint32 list */ -+ uint32 element[1]; -+} wl_uint32_list_t; -+ -+/* used for association with a specific BSSID and chanspec list */ -+typedef struct wl_assoc_params { -+ struct ether_addr bssid; /* 00:00:00:00:00:00: broadcast scan */ -+ uint16 bssid_cnt; /* 0: use chanspec_num, and the single bssid, -+ * otherwise count of chanspecs in chanspec_list -+ * AND paired bssids following chanspec_list -+ */ -+ int32 chanspec_num; /* 0: all available channels, -+ * otherwise count of chanspecs in chanspec_list -+ */ -+ chanspec_t chanspec_list[1]; /* list of chanspecs */ -+} wl_assoc_params_t; -+#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) -+ -+/* used for reassociation/roam to a specific BSSID and channel */ -+typedef wl_assoc_params_t wl_reassoc_params_t; -+#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE -+ -+/* used for association to a specific BSSID and channel */ -+typedef wl_assoc_params_t wl_join_assoc_params_t; -+#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE -+ -+/* used for join with or without a specific bssid and channel list */ -+typedef struct wl_join_params { -+ wlc_ssid_t ssid; -+ wl_assoc_params_t params; /* optional field, but it must include the fixed portion -+ * of the wl_assoc_params_t struct when it does present. -+ */ -+} wl_join_params_t; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ -+ WL_ASSOC_PARAMS_FIXED_SIZE) -+/* scan params for extended join */ -+typedef struct wl_join_scan_params { -+ uint8 scan_type; /* 0 use default, active or passive scan */ -+ int32 nprobes; /* -1 use default, number of probes per channel */ -+ int32 active_time; /* -1 use default, dwell time per channel for -+ * active scanning -+ */ -+ int32 passive_time; /* -1 use default, dwell time per channel -+ * for passive scanning -+ */ -+ int32 home_time; /* -1 use default, dwell time for the home channel -+ * between channel scans -+ */ -+} wl_join_scan_params_t; -+ -+/* extended join params */ -+typedef struct wl_extjoin_params { -+ wlc_ssid_t ssid; /* {0, ""}: wildcard scan */ -+ wl_join_scan_params_t scan; -+ wl_join_assoc_params_t assoc; /* optional field, but it must include the fixed portion -+ * of the wl_join_assoc_params_t struct when it does -+ * present. -+ */ -+} wl_extjoin_params_t; -+#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ -+ WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) -+ -+/* All builds use the new 11ac ratespec/chanspec */ -+#undef D11AC_IOTYPES -+#define D11AC_IOTYPES -+ -+#ifndef D11AC_IOTYPES -+ -+/* defines used by the nrate iovar */ -+#define NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ -+#define NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ -+#define NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ -+#define NRATE_STF_SHIFT 8 /* stf mode shift */ -+#define NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ -+#define NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ -+#define NRATE_SGI_MASK 0x00800000 /* sgi mode */ -+#define NRATE_SGI_SHIFT 23 /* sgi mode */ -+#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ -+#define NRATE_LDPC_SHIFT 22 /* ldpc shift */ -+ -+#define NRATE_STF_SISO 0 /* stf mode SISO */ -+#define NRATE_STF_CDD 1 /* stf mode CDD */ -+#define NRATE_STF_STBC 2 /* stf mode STBC */ -+#define NRATE_STF_SDM 3 /* stf mode SDM */ -+ -+#else /* D11AC_IOTYPES */ -+ -+/* WL_RSPEC defines for rate information */ -+#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ -+#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ -+#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ -+#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ -+#define WL_RSPEC_TXEXP_MASK 0x00000300 -+#define WL_RSPEC_TXEXP_SHIFT 8 -+#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ -+#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ -+#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ -+#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ -+#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ -+#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ -+#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ -+#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override both rate & mode */ -+ -+/* WL_RSPEC_ENCODING field defs */ -+#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ -+#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ -+#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ -+ -+/* WL_RSPEC_BW field defs */ -+#define WL_RSPEC_BW_UNSPECIFIED 0 -+#define WL_RSPEC_BW_20MHZ 0x00010000 -+#define WL_RSPEC_BW_40MHZ 0x00020000 -+#define WL_RSPEC_BW_80MHZ 0x00030000 -+#define WL_RSPEC_BW_160MHZ 0x00040000 -+ -+/* Legacy defines for the nrate iovar */ -+#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ -+#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ -+#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ -+#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ -+#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ -+#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ -+#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ -+#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ -+ -+#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ -+#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ -+#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ -+#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ -+ -+#endif /* D11AC_IOTYPES */ -+ -+#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ -+#define ANTENNA_NUM_2 2 -+#define ANTENNA_NUM_3 3 -+#define ANTENNA_NUM_4 4 -+ -+#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ -+#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ -+#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */ -+#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ -+#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ -+#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ -+#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ -+ -+#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ -+ -+typedef struct { -+ uint8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ -+ uint8 num_antcfg; /* number of available antenna configurations */ -+} wlc_antselcfg_t; -+ -+#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ -+ -+#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ -+#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ -+ -+#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ -+#define IBSS_HI 25 /* Hi in-bss congestion percentage */ -+#define OBSS_MED 12 -+#define OBSS_HI 25 -+#define INTERFER_MED 5 -+#define INTERFER_HI 10 -+ -+#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ -+#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ -+#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ -+#define CCA_FLAGS_PREFER_1_6_11 0x10 -+#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ -+ -+#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ -+#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ -+#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ -+#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ -+#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ -+ -+typedef struct { -+ uint32 duration; /* millisecs spent sampling this channel */ -+ uint32 congest_ibss; /* millisecs in our bss (presumably this traffic will */ -+ /* move if cur bss moves channels) */ -+ uint32 congest_obss; /* traffic not in our bss */ -+ uint32 interference; /* millisecs detecting a non 802.11 interferer. */ -+ uint32 timestamp; /* second timestamp */ -+} cca_congest_t; -+ -+typedef struct { -+ chanspec_t chanspec; /* Which channel? */ -+ uint8 num_secs; /* How many secs worth of data */ -+ cca_congest_t secs[1]; /* Data */ -+} cca_congest_channel_req_t; -+ -+/* interference source detection and identification mode */ -+#define ITFR_MODE_DISABLE 0 /* disable feature */ -+#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ -+#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ -+ -+/* interference sources */ -+enum interference_source { -+ ITFR_NONE = 0, /* interference */ -+ ITFR_PHONE, /* wireless phone */ -+ ITFR_VIDEO_CAMERA, /* wireless video camera */ -+ ITFR_MICROWAVE_OVEN, /* microwave oven */ -+ ITFR_BABY_MONITOR, /* wireless baby monitor */ -+ ITFR_BLUETOOTH, /* bluetooth */ -+ ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /* wireless camera or baby monitor */ -+ ITFR_BLUETOOTH_OR_BABY_MONITOR, /* bluetooth or baby monitor */ -+ ITFR_VIDEO_CAMERA_OR_PHONE, /* video camera or phone */ -+ ITFR_UNIDENTIFIED /* interference from unidentified source */ -+}; -+ -+/* structure for interference source report */ -+typedef struct { -+ uint32 flags; /* flags. bit definitions below */ -+ uint32 source; /* last detected interference source */ -+ uint32 timestamp; /* second timestamp on interferenced flag change */ -+} interference_source_rep_t; -+ -+/* bit definitions for flags in interference source report */ -+#define ITFR_INTERFERENCED 1 /* interference detected */ -+#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ -+#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+#define WLC_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+ -+typedef struct wl_country { -+ char country_abbrev[WLC_CNTRY_BUF_SZ]; /* nul-terminated country code used in -+ * the Country IE -+ */ -+ int32 rev; /* revision specifier for ccode -+ * on set, -1 indicates unspecified. -+ * on get, rev >= 0 -+ */ -+ char ccode[WLC_CNTRY_BUF_SZ]; /* nul-terminated built-in country code. -+ * variable length, but fixed size in -+ * struct allows simple allocation for -+ * expected country strings <= 3 chars. -+ */ -+} wl_country_t; -+ -+typedef struct wl_channels_in_country { -+ uint32 buflen; -+ uint32 band; -+ char country_abbrev[WLC_CNTRY_BUF_SZ]; -+ uint32 count; -+ uint32 channel[1]; -+} wl_channels_in_country_t; -+ -+typedef struct wl_country_list { -+ uint32 buflen; -+ uint32 band_set; -+ uint32 band; -+ uint32 count; -+ char country_abbrev[1]; -+} wl_country_list_t; -+ -+#define WL_NUM_RPI_BINS 8 -+#define WL_RM_TYPE_BASIC 1 -+#define WL_RM_TYPE_CCA 2 -+#define WL_RM_TYPE_RPI 3 -+ -+#define WL_RM_FLAG_PARALLEL (1<<0) -+ -+#define WL_RM_FLAG_LATE (1<<1) -+#define WL_RM_FLAG_INCAPABLE (1<<2) -+#define WL_RM_FLAG_REFUSED (1<<3) -+ -+typedef struct wl_rm_req_elt { -+ int8 type; -+ int8 flags; -+ chanspec_t chanspec; -+ uint32 token; /* token for this measurement */ -+ uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ -+ uint32 tsf_l; /* TSF low 32-bits */ -+ uint32 dur; /* TUs */ -+} wl_rm_req_elt_t; -+ -+typedef struct wl_rm_req { -+ uint32 token; /* overall measurement set token */ -+ uint32 count; /* number of measurement requests */ -+ void *cb; /* completion callback function: may be NULL */ -+ void *cb_arg; /* arg to completion callback function */ -+ wl_rm_req_elt_t req[1]; /* variable length block of requests */ -+} wl_rm_req_t; -+#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) -+ -+typedef struct wl_rm_rep_elt { -+ int8 type; -+ int8 flags; -+ chanspec_t chanspec; -+ uint32 token; /* token for this measurement */ -+ uint32 tsf_h; /* TSF high 32-bits of Measurement start time */ -+ uint32 tsf_l; /* TSF low 32-bits */ -+ uint32 dur; /* TUs */ -+ uint32 len; /* byte length of data block */ -+ uint8 data[1]; /* variable length data block */ -+} wl_rm_rep_elt_t; -+#define WL_RM_REP_ELT_FIXED_LEN 24 /* length excluding data block */ -+ -+#define WL_RPI_REP_BIN_NUM 8 -+typedef struct wl_rm_rpi_rep { -+ uint8 rpi[WL_RPI_REP_BIN_NUM]; -+ int8 rpi_max[WL_RPI_REP_BIN_NUM]; -+} wl_rm_rpi_rep_t; -+ -+typedef struct wl_rm_rep { -+ uint32 token; /* overall measurement set token */ -+ uint32 len; /* length of measurement report block */ -+ wl_rm_rep_elt_t rep[1]; /* variable length block of reports */ -+} wl_rm_rep_t; -+#define WL_RM_REP_FIXED_LEN 8 -+ -+ -+typedef enum sup_auth_status { -+ /* Basic supplicant authentication states */ -+ WLC_SUP_DISCONNECTED = 0, -+ WLC_SUP_CONNECTING, -+ WLC_SUP_IDREQUIRED, -+ WLC_SUP_AUTHENTICATING, -+ WLC_SUP_AUTHENTICATED, -+ WLC_SUP_KEYXCHANGE, -+ WLC_SUP_KEYED, -+ WLC_SUP_TIMEOUT, -+ WLC_SUP_LAST_BASIC_STATE, -+ -+ /* Extended supplicant authentication states */ -+ /* Waiting to receive handshake msg M1 */ -+ WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, -+ /* Preparing to send handshake msg M2 */ -+ WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, -+ /* Waiting to receive handshake msg M3 */ -+ WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, -+ WLC_SUP_KEYXCHANGE_PREP_M4, /* Preparing to send handshake msg M4 */ -+ WLC_SUP_KEYXCHANGE_WAIT_G1, /* Waiting to receive handshake msg G1 */ -+ WLC_SUP_KEYXCHANGE_PREP_G2 /* Preparing to send handshake msg G2 */ -+} sup_auth_status_t; -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* Enumerate crypto algorithms */ -+#define CRYPTO_ALGO_OFF 0 -+#define CRYPTO_ALGO_WEP1 1 -+#define CRYPTO_ALGO_TKIP 2 -+#define CRYPTO_ALGO_WEP128 3 -+#define CRYPTO_ALGO_AES_CCM 4 -+#define CRYPTO_ALGO_AES_OCB_MSDU 5 -+#define CRYPTO_ALGO_AES_OCB_MPDU 6 -+#if !defined(BCMEXTCCX) -+#define CRYPTO_ALGO_NALG 7 -+#else -+#define CRYPTO_ALGO_CKIP 7 -+#define CRYPTO_ALGO_CKIP_MMH 8 -+#define CRYPTO_ALGO_WEP_MMH 9 -+#define CRYPTO_ALGO_NALG 10 -+#endif -+#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ -+ -+#define WSEC_GEN_MIC_ERROR 0x0001 -+#define WSEC_GEN_REPLAY 0x0002 -+#define WSEC_GEN_ICV_ERROR 0x0004 -+#define WSEC_GEN_MFP_ACT_ERROR 0x0008 -+#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 -+#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 -+ -+#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ -+#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ -+#if defined(BCMEXTCCX) -+#define WL_CKIP_KP (1 << 4) /* CMIC */ -+#define WL_CKIP_MMH (1 << 5) /* CKIP */ -+#else -+#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ -+#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ -+#endif -+#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ -+ -+typedef struct wl_wsec_key { -+ uint32 index; /* key index */ -+ uint32 len; /* key length */ -+ uint8 data[DOT11_MAX_KEY_SIZE]; /* key data */ -+ uint32 pad_1[18]; -+ uint32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ -+ uint32 flags; /* misc flags */ -+ uint32 pad_2[2]; -+ int pad_3; -+ int iv_initialized; /* has IV been initialized already? */ -+ int pad_4; -+ /* Rx IV */ -+ struct { -+ uint32 hi; /* upper 32 bits of IV */ -+ uint16 lo; /* lower 16 bits of IV */ -+ } rxiv; -+ uint32 pad_5[2]; -+ struct ether_addr ea; /* per station */ -+} wl_wsec_key_t; -+ -+#define WSEC_MIN_PSK_LEN 8 -+#define WSEC_MAX_PSK_LEN 64 -+ -+/* Flag for key material needing passhash'ing */ -+#define WSEC_PASSPHRASE (1<<0) -+ -+/* receptacle for WLC_SET_WSEC_PMK parameter */ -+typedef struct { -+ ushort key_len; /* octets in key material */ -+ ushort flags; /* key handling qualification */ -+ uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */ -+} wsec_pmk_t; -+ -+/* wireless security bitvec */ -+#define WEP_ENABLED 0x0001 -+#define TKIP_ENABLED 0x0002 -+#define AES_ENABLED 0x0004 -+#define WSEC_SWFLAG 0x0008 -+#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */ -+ -+/* wsec macros for operating on the above definitions */ -+#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) -+#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) -+#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) -+ -+#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) -+#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) -+ -+#ifdef MFP -+#define MFP_CAPABLE 0x0200 -+#define MFP_REQUIRED 0x0400 -+#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ -+#endif /* MFP */ -+ -+/* WPA authentication mode bitvec */ -+#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ -+#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ -+#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ -+#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ -+#if defined(BCMEXTCCX) -+#define WPA_AUTH_CCKM 0x0008 /* CCKM */ -+#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ -+#endif -+/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ -+#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ -+#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ -+#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ -+#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ -+#define WPA2_AUTH_MFP 0x1000 /* MFP (11w) in contrast to CCX */ -+#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ -+#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ -+#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ -+ -+/* pmkid */ -+#define MAXPMKID 16 -+ -+typedef struct _pmkid { -+ struct ether_addr BSSID; -+ uint8 PMKID[WPA2_PMKID_LEN]; -+} pmkid_t; -+ -+typedef struct _pmkid_list { -+ uint32 npmkid; -+ pmkid_t pmkid[1]; -+} pmkid_list_t; -+ -+typedef struct _pmkid_cand { -+ struct ether_addr BSSID; -+ uint8 preauth; -+} pmkid_cand_t; -+ -+typedef struct _pmkid_cand_list { -+ uint32 npmkid_cand; -+ pmkid_cand_t pmkid_cand[1]; -+} pmkid_cand_list_t; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+typedef struct wl_assoc_info { -+ uint32 req_len; -+ uint32 resp_len; -+ uint32 flags; -+ struct dot11_assoc_req req; -+ struct ether_addr reassoc_bssid; /* used in reassoc's */ -+ struct dot11_assoc_resp resp; -+} wl_assoc_info_t; -+ -+/* flags */ -+#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ -+ -+typedef struct wl_led_info { -+ uint32 index; /* led index */ -+ uint32 behavior; -+ uint8 activehi; -+} wl_led_info_t; -+ -+ -+/* srom read/write struct passed through ioctl */ -+typedef struct { -+ uint byteoff; /* byte offset */ -+ uint nbytes; /* number of bytes */ -+ uint16 buf[1]; -+} srom_rw_t; -+ -+/* similar cis (srom or otp) struct [iovar: may not be aligned] */ -+typedef struct { -+ uint32 source; /* cis source */ -+ uint32 byteoff; /* byte offset */ -+ uint32 nbytes; /* number of bytes */ -+ /* data follows here */ -+} cis_rw_t; -+ -+#define WLC_CIS_DEFAULT 0 /* built-in default */ -+#define WLC_CIS_SROM 1 /* source is sprom */ -+#define WLC_CIS_OTP 2 /* source is otp */ -+ -+/* R_REG and W_REG struct passed through ioctl */ -+typedef struct { -+ uint32 byteoff; /* byte offset of the field in d11regs_t */ -+ uint32 val; /* read/write value of the field */ -+ uint32 size; /* sizeof the field */ -+ uint band; /* band (optional) */ -+} rw_reg_t; -+ -+/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */ -+/* PCL - Power Control Loop */ -+/* current gain setting is replaced by user input */ -+#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ -+#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ -+/* current gain setting is maintained */ -+#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ -+ -+typedef struct { -+ uint16 auto_ctrl; /* WL_ATTEN_XX */ -+ uint16 bb; /* Baseband attenuation */ -+ uint16 radio; /* Radio attenuation */ -+ uint16 txctl1; /* Radio TX_CTL1 value */ -+} atten_t; -+ -+/* Per-AC retry parameters */ -+struct wme_tx_params_s { -+ uint8 short_retry; -+ uint8 short_fallback; -+ uint8 long_retry; -+ uint8 long_fallback; -+ uint16 max_rate; /* In units of 512 Kbps */ -+}; -+ -+typedef struct wme_tx_params_s wme_tx_params_t; -+ -+#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) -+ -+/* defines used by poweridx iovar - it controls power in a-band */ -+/* current gain setting is maintained */ -+#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ -+#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ -+#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ -+#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ -+/* value >= 0 causes -+ * - input to be set to that value -+ * - PCL to be off -+ */ -+ -+/* Used to get specific link/ac parameters */ -+typedef struct { -+ int ac; -+ uint8 val; -+ struct ether_addr ea; -+} link_val_t; -+ -+#define BCM_MAC_STATUS_INDICATION (0x40010200L) -+ -+typedef struct { -+ uint16 ver; /* version of this struct */ -+ uint16 len; /* length in bytes of this structure */ -+ uint16 cap; /* sta's advertised capabilities */ -+ uint32 flags; /* flags defined below */ -+ uint32 idle; /* time since data pkt rx'd from sta */ -+ struct ether_addr ea; /* Station address */ -+ wl_rateset_t rateset; /* rateset in use */ -+ uint32 in; /* seconds elapsed since associated */ -+ uint32 listen_interval_inms; /* Min Listen interval in ms for this STA */ -+ uint32 tx_pkts; /* # of packets transmitted */ -+ uint32 tx_failures; /* # of packets failed */ -+ uint32 rx_ucast_pkts; /* # of unicast packets received */ -+ uint32 rx_mcast_pkts; /* # of multicast packets received */ -+ uint32 tx_rate; /* Rate of last successful tx frame */ -+ uint32 rx_rate; /* Rate of last successful rx frame */ -+ uint32 rx_decrypt_succeeds; /* # of packet decrypted successfully */ -+ uint32 rx_decrypt_failures; /* # of packet decrypted unsuccessfully */ -+} sta_info_t; -+ -+#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_pkts) -+ -+#define WL_STA_VER 3 -+ -+/* Flags for sta_info_t indicating properties of STA */ -+#define WL_STA_BRCM 0x1 /* Running a Broadcom driver */ -+#define WL_STA_WME 0x2 /* WMM association */ -+#define WL_STA_UNUSED 0x4 -+#define WL_STA_AUTHE 0x8 /* Authenticated */ -+#define WL_STA_ASSOC 0x10 /* Associated */ -+#define WL_STA_AUTHO 0x20 /* Authorized */ -+#define WL_STA_WDS 0x40 /* Wireless Distribution System */ -+#define WL_STA_WDS_LINKUP 0x80 /* WDS traffic/probes flowing properly */ -+#define WL_STA_PS 0x100 /* STA is in power save mode from AP's viewpoint */ -+#define WL_STA_APSD_BE 0x200 /* APSD delv/trigger for AC_BE is default enabled */ -+#define WL_STA_APSD_BK 0x400 /* APSD delv/trigger for AC_BK is default enabled */ -+#define WL_STA_APSD_VI 0x800 /* APSD delv/trigger for AC_VI is default enabled */ -+#define WL_STA_APSD_VO 0x1000 /* APSD delv/trigger for AC_VO is default enabled */ -+#define WL_STA_N_CAP 0x2000 /* STA 802.11n capable */ -+#define WL_STA_SCBSTATS 0x4000 /* Per STA debug stats */ -+ -+#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ -+ -+/* Values for TX Filter override mode */ -+#define WLC_TXFILTER_OVERRIDE_DISABLED 0 -+#define WLC_TXFILTER_OVERRIDE_ENABLED 1 -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* Used to get specific STA parameters */ -+typedef struct { -+ uint32 val; -+ struct ether_addr ea; -+} scb_val_t; -+ -+/* Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ -+typedef struct { -+ uint32 code; -+ scb_val_t ioctl_args; -+} authops_t; -+ -+/* channel encoding */ -+typedef struct channel_info { -+ int hw_channel; -+ int target_channel; -+ int scan_channel; -+} channel_info_t; -+ -+/* For ioctls that take a list of MAC addresses */ -+struct maclist { -+ uint count; /* number of MAC addresses */ -+ struct ether_addr ea[1]; /* variable length array of MAC addresses */ -+}; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+/* get pkt count struct passed through ioctl */ -+typedef struct get_pktcnt { -+ uint rx_good_pkt; -+ uint rx_bad_pkt; -+ uint tx_good_pkt; -+ uint tx_bad_pkt; -+ uint rx_ocast_good_pkt; /* unicast packets destined for others */ -+} get_pktcnt_t; -+ -+/* NINTENDO2 */ -+#define LQ_IDX_MIN 0 -+#define LQ_IDX_MAX 1 -+#define LQ_IDX_AVG 2 -+#define LQ_IDX_SUM 2 -+#define LQ_IDX_LAST 3 -+#define LQ_STOP_MONITOR 0 -+#define LQ_START_MONITOR 1 -+ -+/* Get averages RSSI, Rx PHY rate and SNR values */ -+typedef struct { -+ int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */ -+ int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */ -+ int isvalid; /* Flag indicating whether above data is valid */ -+} wl_lq_t; /* Link Quality */ -+ -+typedef enum wl_wakeup_reason_type { -+ LCD_ON = 1, -+ LCD_OFF, -+ DRC1_WAKE, -+ DRC2_WAKE, -+ REASON_LAST -+} wl_wr_type_t; -+ -+typedef struct { -+/* Unique filter id */ -+ uint32 id; -+ -+/* stores the reason for the last wake up */ -+ uint8 reason; -+} wl_wr_t; -+ -+/* Get MAC specific rate histogram command */ -+typedef struct { -+ struct ether_addr ea; /* MAC Address */ -+ uint8 ac_cat; /* Access Category */ -+ uint8 num_pkts; /* Number of packet entries to be averaged */ -+} wl_mac_ratehisto_cmd_t; /* MAC Specific Rate Histogram command */ -+ -+/* Get MAC rate histogram response */ -+typedef struct { -+ uint32 rate[WLC_MAXRATE + 1]; /* Rates */ -+ uint32 mcs[WL_RATESET_SZ_HT_MCS * WL_TX_CHAINS_MAX]; /* MCS counts */ -+ uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /* VHT counts */ -+ uint32 tsf_timer[2][2]; /* Start and End time for 8bytes value */ -+} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */ -+ -+/* Values for TX Filter override mode */ -+#define WLC_TXFILTER_OVERRIDE_DISABLED 0 -+#define WLC_TXFILTER_OVERRIDE_ENABLED 1 -+ -+#define WL_IOCTL_ACTION_GET 0x0 -+#define WL_IOCTL_ACTION_SET 0x1 -+#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e -+#define WL_IOCTL_ACTION_OVL_RSV 0x20 -+#define WL_IOCTL_ACTION_OVL 0x40 -+#define WL_IOCTL_ACTION_MASK 0x7e -+#define WL_IOCTL_ACTION_OVL_SHIFT 1 -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* Linux network driver ioctl encoding */ -+typedef struct wl_ioctl { -+ uint cmd; /* common ioctl definition */ -+ void *buf; /* pointer to user buffer */ -+ uint len; /* length of user buffer */ -+ uint8 set; /* 1=set IOCTL; 0=query IOCTL */ -+ uint used; /* bytes read or written (optional) */ -+ uint needed; /* bytes needed (optional) */ -+} wl_ioctl_t; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+ -+/* reference to wl_ioctl_t struct used by usermode driver */ -+#define ioctl_subtype set /* subtype param */ -+#define ioctl_pid used /* pid param */ -+#define ioctl_status needed /* status param */ -+ -+/* -+ * Structure for passing hardware and software -+ * revision info up from the driver. -+ */ -+typedef struct wlc_rev_info { -+ uint vendorid; /* PCI vendor id */ -+ uint deviceid; /* device id of chip */ -+ uint radiorev; /* radio revision */ -+ uint chiprev; /* chip revision */ -+ uint corerev; /* core revision */ -+ uint boardid; /* board identifier (usu. PCI sub-device id) */ -+ uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ -+ uint boardrev; /* board revision */ -+ uint driverrev; /* driver version */ -+ uint ucoderev; /* microcode version */ -+ uint bus; /* bus type */ -+ uint chipnum; /* chip number */ -+ uint phytype; /* phy type */ -+ uint phyrev; /* phy revision */ -+ uint anarev; /* anacore rev */ -+ uint chippkg; /* chip package info */ -+} wlc_rev_info_t; -+ -+#define WL_REV_INFO_LEGACY_LENGTH 48 -+ -+#define WL_BRAND_MAX 10 -+typedef struct wl_instance_info { -+ uint instance; -+ char brand[WL_BRAND_MAX]; -+} wl_instance_info_t; -+ -+/* structure to change size of tx fifo */ -+typedef struct wl_txfifo_sz { -+ uint16 magic; -+ uint16 fifo; -+ uint16 size; -+} wl_txfifo_sz_t; -+/* magic pattern used for mismatch driver and wl */ -+#define WL_TXFIFO_SZ_MAGIC 0xa5a5 -+ -+/* Transfer info about an IOVar from the driver */ -+/* Max supported IOV name size in bytes, + 1 for nul termination */ -+#define WLC_IOV_NAME_LEN 30 -+typedef struct wlc_iov_trx_s { -+ uint8 module; -+ uint8 type; -+ char name[WLC_IOV_NAME_LEN]; -+} wlc_iov_trx_t; -+ -+/* check this magic number */ -+#define WLC_IOCTL_MAGIC 0x14e46c77 -+ -+/* bump this number if you change the ioctl interface */ -+#ifdef D11AC_IOTYPES -+#define WLC_IOCTL_VERSION 2 -+#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 -+#else -+#define WLC_IOCTL_VERSION 1 -+#endif /* D11AC_IOTYPES */ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ -+#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ -+#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ -+#if defined(LCNCONF) || defined(LCN40CONF) -+#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ -+#else -+#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ -+#endif -+ -+/* common ioctl definitions */ -+#define WLC_GET_MAGIC 0 -+#define WLC_GET_VERSION 1 -+#define WLC_UP 2 -+#define WLC_DOWN 3 -+#define WLC_GET_LOOP 4 -+#define WLC_SET_LOOP 5 -+#define WLC_DUMP 6 -+#define WLC_GET_MSGLEVEL 7 -+#define WLC_SET_MSGLEVEL 8 -+#define WLC_GET_PROMISC 9 -+#define WLC_SET_PROMISC 10 -+/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ -+#define WLC_GET_RATE 12 -+#define WLC_GET_MAX_RATE 13 -+#define WLC_GET_INSTANCE 14 -+/* #define WLC_GET_FRAG 15 */ /* no longer supported */ -+/* #define WLC_SET_FRAG 16 */ /* no longer supported */ -+/* #define WLC_GET_RTS 17 */ /* no longer supported */ -+/* #define WLC_SET_RTS 18 */ /* no longer supported */ -+#define WLC_GET_INFRA 19 -+#define WLC_SET_INFRA 20 -+#define WLC_GET_AUTH 21 -+#define WLC_SET_AUTH 22 -+#define WLC_GET_BSSID 23 -+#define WLC_SET_BSSID 24 -+#define WLC_GET_SSID 25 -+#define WLC_SET_SSID 26 -+#define WLC_RESTART 27 -+#define WLC_TERMINATED 28 -+/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ -+#define WLC_GET_CHANNEL 29 -+#define WLC_SET_CHANNEL 30 -+#define WLC_GET_SRL 31 -+#define WLC_SET_SRL 32 -+#define WLC_GET_LRL 33 -+#define WLC_SET_LRL 34 -+#define WLC_GET_PLCPHDR 35 -+#define WLC_SET_PLCPHDR 36 -+#define WLC_GET_RADIO 37 -+#define WLC_SET_RADIO 38 -+#define WLC_GET_PHYTYPE 39 -+#define WLC_DUMP_RATE 40 -+#define WLC_SET_RATE_PARAMS 41 -+#define WLC_GET_FIXRATE 42 -+#define WLC_SET_FIXRATE 43 -+/* #define WLC_GET_WEP 42 */ /* no longer supported */ -+/* #define WLC_SET_WEP 43 */ /* no longer supported */ -+#define WLC_GET_KEY 44 -+#define WLC_SET_KEY 45 -+#define WLC_GET_REGULATORY 46 -+#define WLC_SET_REGULATORY 47 -+#define WLC_GET_PASSIVE_SCAN 48 -+#define WLC_SET_PASSIVE_SCAN 49 -+#define WLC_SCAN 50 -+#define WLC_SCAN_RESULTS 51 -+#define WLC_DISASSOC 52 -+#define WLC_REASSOC 53 -+#define WLC_GET_ROAM_TRIGGER 54 -+#define WLC_SET_ROAM_TRIGGER 55 -+#define WLC_GET_ROAM_DELTA 56 -+#define WLC_SET_ROAM_DELTA 57 -+#define WLC_GET_ROAM_SCAN_PERIOD 58 -+#define WLC_SET_ROAM_SCAN_PERIOD 59 -+#define WLC_EVM 60 /* diag */ -+#define WLC_GET_TXANT 61 -+#define WLC_SET_TXANT 62 -+#define WLC_GET_ANTDIV 63 -+#define WLC_SET_ANTDIV 64 -+/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ -+/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ -+#define WLC_GET_CLOSED 67 -+#define WLC_SET_CLOSED 68 -+#define WLC_GET_MACLIST 69 -+#define WLC_SET_MACLIST 70 -+#define WLC_GET_RATESET 71 -+#define WLC_SET_RATESET 72 -+/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ -+#define WLC_LONGTRAIN 74 -+#define WLC_GET_BCNPRD 75 -+#define WLC_SET_BCNPRD 76 -+#define WLC_GET_DTIMPRD 77 -+#define WLC_SET_DTIMPRD 78 -+#define WLC_GET_SROM 79 -+#define WLC_SET_SROM 80 -+#define WLC_GET_WEP_RESTRICT 81 -+#define WLC_SET_WEP_RESTRICT 82 -+#define WLC_GET_COUNTRY 83 -+#define WLC_SET_COUNTRY 84 -+#define WLC_GET_PM 85 -+#define WLC_SET_PM 86 -+#define WLC_GET_WAKE 87 -+#define WLC_SET_WAKE 88 -+/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ -+#define WLC_GET_FORCELINK 90 /* ndis only */ -+#define WLC_SET_FORCELINK 91 /* ndis only */ -+#define WLC_FREQ_ACCURACY 92 /* diag */ -+#define WLC_CARRIER_SUPPRESS 93 /* diag */ -+#define WLC_GET_PHYREG 94 -+#define WLC_SET_PHYREG 95 -+#define WLC_GET_RADIOREG 96 -+#define WLC_SET_RADIOREG 97 -+#define WLC_GET_REVINFO 98 -+#define WLC_GET_UCANTDIV 99 -+#define WLC_SET_UCANTDIV 100 -+#define WLC_R_REG 101 -+#define WLC_W_REG 102 -+/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ -+/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ -+#define WLC_GET_MACMODE 105 -+#define WLC_SET_MACMODE 106 -+#define WLC_GET_MONITOR 107 -+#define WLC_SET_MONITOR 108 -+#define WLC_GET_GMODE 109 -+#define WLC_SET_GMODE 110 -+#define WLC_GET_LEGACY_ERP 111 -+#define WLC_SET_LEGACY_ERP 112 -+#define WLC_GET_RX_ANT 113 -+#define WLC_GET_CURR_RATESET 114 /* current rateset */ -+#define WLC_GET_SCANSUPPRESS 115 -+#define WLC_SET_SCANSUPPRESS 116 -+#define WLC_GET_AP 117 -+#define WLC_SET_AP 118 -+#define WLC_GET_EAP_RESTRICT 119 -+#define WLC_SET_EAP_RESTRICT 120 -+#define WLC_SCB_AUTHORIZE 121 -+#define WLC_SCB_DEAUTHORIZE 122 -+#define WLC_GET_WDSLIST 123 -+#define WLC_SET_WDSLIST 124 -+#define WLC_GET_ATIM 125 -+#define WLC_SET_ATIM 126 -+#define WLC_GET_RSSI 127 -+#define WLC_GET_PHYANTDIV 128 -+#define WLC_SET_PHYANTDIV 129 -+#define WLC_AP_RX_ONLY 130 -+#define WLC_GET_TX_PATH_PWR 131 -+#define WLC_SET_TX_PATH_PWR 132 -+#define WLC_GET_WSEC 133 -+#define WLC_SET_WSEC 134 -+#define WLC_GET_PHY_NOISE 135 -+#define WLC_GET_BSS_INFO 136 -+#define WLC_GET_PKTCNTS 137 -+#define WLC_GET_LAZYWDS 138 -+#define WLC_SET_LAZYWDS 139 -+#define WLC_GET_BANDLIST 140 -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+#define WLC_GET_BAND 141 -+#define WLC_SET_BAND 142 -+#define WLC_SCB_DEAUTHENTICATE 143 -+#define WLC_GET_SHORTSLOT 144 -+#define WLC_GET_SHORTSLOT_OVERRIDE 145 -+#define WLC_SET_SHORTSLOT_OVERRIDE 146 -+#define WLC_GET_SHORTSLOT_RESTRICT 147 -+#define WLC_SET_SHORTSLOT_RESTRICT 148 -+#define WLC_GET_GMODE_PROTECTION 149 -+#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 -+#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 -+#define WLC_UPGRADE 152 -+/* #define WLC_GET_MRATE 153 */ /* no longer supported */ -+/* #define WLC_SET_MRATE 154 */ /* no longer supported */ -+#define WLC_GET_IGNORE_BCNS 155 -+#define WLC_SET_IGNORE_BCNS 156 -+#define WLC_GET_SCB_TIMEOUT 157 -+#define WLC_SET_SCB_TIMEOUT 158 -+#define WLC_GET_ASSOCLIST 159 -+#define WLC_GET_CLK 160 -+#define WLC_SET_CLK 161 -+#define WLC_GET_UP 162 -+#define WLC_OUT 163 -+#define WLC_GET_WPA_AUTH 164 -+#define WLC_SET_WPA_AUTH 165 -+#define WLC_GET_UCFLAGS 166 -+#define WLC_SET_UCFLAGS 167 -+#define WLC_GET_PWRIDX 168 -+#define WLC_SET_PWRIDX 169 -+#define WLC_GET_TSSI 170 -+#define WLC_GET_SUP_RATESET_OVERRIDE 171 -+#define WLC_SET_SUP_RATESET_OVERRIDE 172 -+/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ -+/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ -+/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ -+/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ -+/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ -+#define WLC_GET_PROTECTION_CONTROL 178 -+#define WLC_SET_PROTECTION_CONTROL 179 -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+#define WLC_GET_PHYLIST 180 -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ -+#define WLC_DECRYPT_STATUS 182 /* ndis only */ -+#define WLC_GET_KEY_SEQ 183 -+#define WLC_GET_SCAN_CHANNEL_TIME 184 -+#define WLC_SET_SCAN_CHANNEL_TIME 185 -+#define WLC_GET_SCAN_UNASSOC_TIME 186 -+#define WLC_SET_SCAN_UNASSOC_TIME 187 -+#define WLC_GET_SCAN_HOME_TIME 188 -+#define WLC_SET_SCAN_HOME_TIME 189 -+#define WLC_GET_SCAN_NPROBES 190 -+#define WLC_SET_SCAN_NPROBES 191 -+#define WLC_GET_PRB_RESP_TIMEOUT 192 -+#define WLC_SET_PRB_RESP_TIMEOUT 193 -+#define WLC_GET_ATTEN 194 -+#define WLC_SET_ATTEN 195 -+#define WLC_GET_SHMEM 196 /* diag */ -+#define WLC_SET_SHMEM 197 /* diag */ -+/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ -+/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ -+#define WLC_SET_WSEC_TEST 200 -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+#define WLC_TKIP_COUNTERMEASURES 202 -+#define WLC_GET_PIOMODE 203 -+#define WLC_SET_PIOMODE 204 -+#define WLC_SET_ASSOC_PREFER 205 -+#define WLC_GET_ASSOC_PREFER 206 -+#define WLC_SET_ROAM_PREFER 207 -+#define WLC_GET_ROAM_PREFER 208 -+#define WLC_SET_LED 209 -+#define WLC_GET_LED 210 -+#define WLC_GET_INTERFERENCE_MODE 211 -+#define WLC_SET_INTERFERENCE_MODE 212 -+#define WLC_GET_CHANNEL_QA 213 -+#define WLC_START_CHANNEL_QA 214 -+#define WLC_GET_CHANNEL_SEL 215 -+#define WLC_START_CHANNEL_SEL 216 -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+#define WLC_GET_VALID_CHANNELS 217 -+#define WLC_GET_FAKEFRAG 218 -+#define WLC_SET_FAKEFRAG 219 -+#define WLC_GET_PWROUT_PERCENTAGE 220 -+#define WLC_SET_PWROUT_PERCENTAGE 221 -+#define WLC_SET_BAD_FRAME_PREEMPT 222 -+#define WLC_GET_BAD_FRAME_PREEMPT 223 -+#define WLC_SET_LEAP_LIST 224 -+#define WLC_GET_LEAP_LIST 225 -+#define WLC_GET_CWMIN 226 -+#define WLC_SET_CWMIN 227 -+#define WLC_GET_CWMAX 228 -+#define WLC_SET_CWMAX 229 -+#define WLC_GET_WET 230 -+#define WLC_SET_WET 231 -+#define WLC_GET_PUB 232 -+/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ -+/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ -+#define WLC_GET_KEY_PRIMARY 235 -+#define WLC_SET_KEY_PRIMARY 236 -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+ -+/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ -+#define WLC_GET_ACI_ARGS 238 -+#define WLC_SET_ACI_ARGS 239 -+#define WLC_UNSET_CALLBACK 240 -+#define WLC_SET_CALLBACK 241 -+#define WLC_GET_RADAR 242 -+#define WLC_SET_RADAR 243 -+#define WLC_SET_SPECT_MANAGMENT 244 -+#define WLC_GET_SPECT_MANAGMENT 245 -+#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ -+#define WLC_WDS_GET_WPA_SUP 247 -+#define WLC_SET_CS_SCAN_TIMER 248 -+#define WLC_GET_CS_SCAN_TIMER 249 -+#define WLC_MEASURE_REQUEST 250 -+#define WLC_INIT 251 -+#define WLC_SEND_QUIET 252 -+#define WLC_KEEPALIVE 253 -+#define WLC_SEND_PWR_CONSTRAINT 254 -+#define WLC_UPGRADE_STATUS 255 -+#define WLC_CURRENT_PWR 256 -+#define WLC_GET_SCAN_PASSIVE_TIME 257 -+#define WLC_SET_SCAN_PASSIVE_TIME 258 -+#define WLC_LEGACY_LINK_BEHAVIOR 259 -+#define WLC_GET_CHANNELS_IN_COUNTRY 260 -+#define WLC_GET_COUNTRY_LIST 261 -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+#define WLC_GET_VAR 262 /* get value of named variable */ -+#define WLC_SET_VAR 263 /* set named variable to value */ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+#define WLC_NVRAM_GET 264 /* deprecated */ -+#define WLC_NVRAM_SET 265 -+#define WLC_NVRAM_DUMP 266 -+#define WLC_REBOOT 267 -+#define WLC_SET_WSEC_PMK 268 -+#define WLC_GET_AUTH_MODE 269 -+#define WLC_SET_AUTH_MODE 270 -+#define WLC_GET_WAKEENTRY 271 -+#define WLC_SET_WAKEENTRY 272 -+#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ -+#define WLC_NVOTPW 274 -+#define WLC_OTPW 275 -+#define WLC_IOV_BLOCK_GET 276 -+#define WLC_IOV_MODULES_GET 277 -+#define WLC_SOFT_RESET 278 -+#define WLC_GET_ALLOW_MODE 279 -+#define WLC_SET_ALLOW_MODE 280 -+#define WLC_GET_DESIRED_BSSID 281 -+#define WLC_SET_DESIRED_BSSID 282 -+#define WLC_DISASSOC_MYAP 283 -+#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ -+#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ -+#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ -+#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ -+#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ -+#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ -+#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ -+#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ -+#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ -+#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ -+#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ -+#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ -+#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ -+#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ -+#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ -+#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ -+#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ -+#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ -+#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ -+#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ -+#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ -+#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ -+#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ -+#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ -+/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ -+#define WLC_GET_CMD 309 -+/* #define WLC_LAST 310 */ /* Never used - can be reused */ -+#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ -+#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ -+/* #define WLC_GET_WAI_RESTRICT 313 */ /* for WAPI, deprecated use iovar instead */ -+/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */ -+/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */ -+#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ -+#define WLC_GET_NAT_STATE 317 -+#define WLC_LAST 318 -+ -+#ifndef EPICTRL_COOKIE -+#define EPICTRL_COOKIE 0xABADCEDE -+#endif -+ -+/* vx wlc ioctl's offset */ -+#define CMN_IOCTL_OFF 0x180 -+ -+/* -+ * custom OID support -+ * -+ * 0xFF - implementation specific OID -+ * 0xE4 - first byte of Broadcom PCI vendor ID -+ * 0x14 - second byte of Broadcom PCI vendor ID -+ * 0xXX - the custom OID number -+ */ -+ -+/* begin 0x1f values beyond the start of the ET driver range. */ -+#define WL_OID_BASE 0xFFE41420 -+ -+/* NDIS overrides */ -+#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) -+#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) -+#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) -+#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) -+#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) -+#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) -+#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) -+ -+/* EXT_STA Dongle suuport */ -+#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) -+#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) -+#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) -+#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) -+#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) -+#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) -+#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) -+#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) -+#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) -+#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) -+#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) -+#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) -+#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) -+#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) -+#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) -+ -+/* NAT filter driver support */ -+#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) -+#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) -+ -+#define WL_DECRYPT_STATUS_SUCCESS 1 -+#define WL_DECRYPT_STATUS_FAILURE 2 -+#define WL_DECRYPT_STATUS_UNKNOWN 3 -+ -+/* allows user-mode app to poll the status of USB image upgrade */ -+#define WLC_UPGRADE_SUCCESS 0 -+#define WLC_UPGRADE_PENDING 1 -+ -+#ifdef CONFIG_USBRNDIS_RETAIL -+/* struct passed in for WLC_NDCONFIG_ITEM */ -+typedef struct { -+ char *name; -+ void *param; -+} ndconfig_item_t; -+#endif -+ -+ -+/* WLC_GET_AUTH, WLC_SET_AUTH values */ -+#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ -+#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ -+#ifdef BCM4330_CHIP -+#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ -+#else -+/* BCM4334(Phoenex branch) value changed to 3 */ -+#define WL_AUTH_OPEN_SHARED 3 /* try open, then shared if open failed w/rc 13 */ -+#endif -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* Bit masks for radio disabled status - returned by WL_GET_RADIO */ -+#define WL_RADIO_SW_DISABLE (1<<0) -+#define WL_RADIO_HW_DISABLE (1<<1) -+#define WL_RADIO_MPC_DISABLE (1<<2) -+#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */ -+ -+#define WL_SPURAVOID_OFF 0 -+#define WL_SPURAVOID_ON1 1 -+#define WL_SPURAVOID_ON2 2 -+ -+/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ -+#define WL_TXPWR_OVERRIDE (1U<<31) -+#define WL_TXPWR_NEG (1U<<30) -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[0] ... */ -+ -+#define WL_PHY_PAVAR_VER 1 /* pavars version */ -+ -+typedef struct wl_po { -+ uint16 phy_type; /* Phy type */ -+ uint16 band; -+ uint16 cckpo; -+ uint32 ofdmpo; -+ uint16 mcspo[8]; -+} wl_po_t; -+ -+/* a large TX Power as an init value to factor out of MIN() calculations, -+ * keep low enough to fit in an int8, units are .25 dBm -+ */ -+#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ -+ -+/* "diag" iovar argument and error code */ -+#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ -+#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ -+#define WL_DIAG_MEMORY 3 /* d11 memory test */ -+#define WL_DIAG_LED 4 /* LED test */ -+#define WL_DIAG_REG 5 /* d11/phy register test */ -+#define WL_DIAG_SROM 6 /* srom read/crc test */ -+#define WL_DIAG_DMA 7 /* DMA test */ -+#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ -+ -+#define WL_DIAGERR_SUCCESS 0 -+#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ -+#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ -+#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ -+#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ -+#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ -+#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ -+#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ -+#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ -+#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ -+#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ -+ -+#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ -+#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ -+ -+/* band types */ -+#define WLC_BAND_AUTO 0 /* auto-select */ -+#define WLC_BAND_5G 1 /* 5 Ghz */ -+#define WLC_BAND_2G 2 /* 2.4 Ghz */ -+#define WLC_BAND_ALL 3 /* all bands */ -+ -+/* band range returned by band_range iovar */ -+#define WL_CHAN_FREQ_RANGE_2G 0 -+#define WL_CHAN_FREQ_RANGE_5GL 1 -+#define WL_CHAN_FREQ_RANGE_5GM 2 -+#define WL_CHAN_FREQ_RANGE_5GH 3 -+ -+#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 -+#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 -+#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 -+#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 -+ -+#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* phy types (returned by WLC_GET_PHYTPE) */ -+#define WLC_PHY_TYPE_A 0 -+#define WLC_PHY_TYPE_B 1 -+#define WLC_PHY_TYPE_G 2 -+#define WLC_PHY_TYPE_N 4 -+#define WLC_PHY_TYPE_LP 5 -+#define WLC_PHY_TYPE_SSN 6 -+#define WLC_PHY_TYPE_HT 7 -+#define WLC_PHY_TYPE_LCN 8 -+#define WLC_PHY_TYPE_LCN40 10 -+#define WLC_PHY_TYPE_AC 11 -+#define WLC_PHY_TYPE_NULL 0xf -+ -+/* Values for PM */ -+#define PM_OFF 0 -+#define PM_MAX 1 -+#define PM_FAST 2 -+#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+/* MAC list modes */ -+#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ -+#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ -+#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ -+ -+/* -+ * 54g modes (basic bits may still be overridden) -+ * -+ * GMODE_LEGACY_B Rateset: 1b, 2b, 5.5, 11 -+ * Preamble: Long -+ * Shortslot: Off -+ * GMODE_AUTO Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 -+ * Extended Rateset: 6, 9, 12, 48 -+ * Preamble: Long -+ * Shortslot: Auto -+ * GMODE_ONLY Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54 -+ * Extended Rateset: 6b, 9, 12b, 48 -+ * Preamble: Short required -+ * Shortslot: Auto -+ * GMODE_B_DEFERRED Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 -+ * Extended Rateset: 6, 9, 12, 48 -+ * Preamble: Long -+ * Shortslot: On -+ * GMODE_PERFORMANCE Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54 -+ * Preamble: Short required -+ * Shortslot: On and required -+ * GMODE_LRS Rateset: 1b, 2b, 5.5b, 11b -+ * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54 -+ * Preamble: Long -+ * Shortslot: Auto -+ */ -+#define GMODE_LEGACY_B 0 -+#define GMODE_AUTO 1 -+#define GMODE_ONLY 2 -+#define GMODE_B_DEFERRED 3 -+#define GMODE_PERFORMANCE 4 -+#define GMODE_LRS 5 -+#define GMODE_MAX 6 -+ -+/* values for PLCPHdr_override */ -+#define WLC_PLCP_AUTO -1 -+#define WLC_PLCP_SHORT 0 -+#define WLC_PLCP_LONG 1 -+ -+/* values for g_protection_override and n_protection_override */ -+#define WLC_PROTECTION_AUTO -1 -+#define WLC_PROTECTION_OFF 0 -+#define WLC_PROTECTION_ON 1 -+#define WLC_PROTECTION_MMHDR_ONLY 2 -+#define WLC_PROTECTION_CTS_ONLY 3 -+ -+/* values for g_protection_control and n_protection_control */ -+#define WLC_PROTECTION_CTL_OFF 0 -+#define WLC_PROTECTION_CTL_LOCAL 1 -+#define WLC_PROTECTION_CTL_OVERLAP 2 -+ -+/* values for n_protection */ -+#define WLC_N_PROTECTION_OFF 0 -+#define WLC_N_PROTECTION_OPTIONAL 1 -+#define WLC_N_PROTECTION_20IN40 2 -+#define WLC_N_PROTECTION_MIXEDMODE 3 -+ -+/* values for n_preamble_type */ -+#define WLC_N_PREAMBLE_MIXEDMODE 0 -+#define WLC_N_PREAMBLE_GF 1 -+#define WLC_N_PREAMBLE_GF_BRCM 2 -+ -+/* values for band specific 40MHz capabilities (deprecated) */ -+#define WLC_N_BW_20ALL 0 -+#define WLC_N_BW_40ALL 1 -+#define WLC_N_BW_20IN2G_40IN5G 2 -+ -+#define WLC_BW_20MHZ_BIT (1<<0) -+#define WLC_BW_40MHZ_BIT (1<<1) -+#define WLC_BW_80MHZ_BIT (1<<2) -+ -+/* Bandwidth capabilities */ -+#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) -+#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -+#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) -+#define WLC_BW_CAP_UNRESTRICTED 0xFF -+ -+#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) -+#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) -+#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) -+ -+/* values to force tx/rx chain */ -+#define WLC_N_TXRX_CHAIN0 0 -+#define WLC_N_TXRX_CHAIN1 1 -+ -+/* bitflags for SGI support (sgi_rx iovar) */ -+#define WLC_N_SGI_20 0x01 -+#define WLC_N_SGI_40 0x02 -+#define WLC_VHT_SGI_80 0x04 -+ -+/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ -+#define WLC_SGI_ALL 0x02 -+ -+#define LISTEN_INTERVAL 10 -+/* interference mitigation options */ -+#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ -+#define INTERFERE_NONE 0 /* off */ -+#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ -+#define WLAN_MANUAL 2 /* ACI: no auto detection */ -+#define WLAN_AUTO 3 /* ACI: auto detect */ -+#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ -+#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ -+ -+/* AP environment */ -+#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ -+#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ -+#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ -+#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ -+ -+typedef struct wl_aci_args { -+ int enter_aci_thresh; /* Trigger level to start detecting ACI */ -+ int exit_aci_thresh; /* Trigger level to exit ACI mode */ -+ int usec_spin; /* microsecs to delay between rssi samples */ -+ int glitch_delay; /* interval between ACI scans when glitch count is consistently high */ -+ uint16 nphy_adcpwr_enter_thresh; /* ADC power to enter ACI mitigation mode */ -+ uint16 nphy_adcpwr_exit_thresh; /* ADC power to exit ACI mitigation mode */ -+ uint16 nphy_repeat_ctr; /* Number of tries per channel to compute power */ -+ uint16 nphy_num_samples; /* Number of samples to compute power on one channel */ -+ uint16 nphy_undetect_window_sz; /* num of undetects to exit ACI Mitigation mode */ -+ uint16 nphy_b_energy_lo_aci; /* low ACI power energy threshold for bphy */ -+ uint16 nphy_b_energy_md_aci; /* mid ACI power energy threshold for bphy */ -+ uint16 nphy_b_energy_hi_aci; /* high ACI power energy threshold for bphy */ -+ uint16 nphy_noise_noassoc_glitch_th_up; /* wl interference 4 */ -+ uint16 nphy_noise_noassoc_glitch_th_dn; -+ uint16 nphy_noise_assoc_glitch_th_up; -+ uint16 nphy_noise_assoc_glitch_th_dn; -+ uint16 nphy_noise_assoc_aci_glitch_th_up; -+ uint16 nphy_noise_assoc_aci_glitch_th_dn; -+ uint16 nphy_noise_assoc_enter_th; -+ uint16 nphy_noise_noassoc_enter_th; -+ uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; -+ uint16 nphy_noise_noassoc_crsidx_incr; -+ uint16 nphy_noise_assoc_crsidx_incr; -+ uint16 nphy_noise_crsidx_decr; -+} wl_aci_args_t; -+ -+#define TRIGGER_NOW 0 -+#define TRIGGER_CRS 0x01 -+#define TRIGGER_CRSDEASSERT 0x02 -+#define TRIGGER_GOODFCS 0x04 -+#define TRIGGER_BADFCS 0x08 -+#define TRIGGER_BADPLCP 0x10 -+#define TRIGGER_CRSGLITCH 0x20 -+#define WL_ACI_ARGS_LEGACY_LENGTH 16 /* bytes of pre NPHY aci args */ -+#define WL_SAMPLECOLLECT_T_VERSION 2 /* version of wl_samplecollect_args_t struct */ -+typedef struct wl_samplecollect_args { -+ /* version 0 fields */ -+ uint8 coll_us; -+ int cores; -+ /* add'l version 1 fields */ -+ uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */ -+ uint16 length; /* length of entire structure */ -+ int8 trigger; -+ uint16 timeout; -+ uint16 mode; -+ uint32 pre_dur; -+ uint32 post_dur; -+ uint8 gpio_sel; -+ bool downsamp; -+ bool be_deaf; -+ bool agc; /* loop from init gain and going down */ -+ bool filter; /* override high pass corners to lowest */ -+ /* add'l version 2 fields */ -+ uint8 trigger_state; -+ uint8 module_sel1; -+ uint8 module_sel2; -+ uint16 nsamps; -+} wl_samplecollect_args_t; -+ -+#define WL_SAMPLEDATA_HEADER_TYPE 1 -+#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ -+#define WL_SAMPLEDATA_TYPE 2 -+#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ -+#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ -+#define WL_SAMPLEDATA_T_VERSION 1 /* version of wl_samplecollect_args_t struct */ -+/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ -+#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 -+ -+typedef struct wl_sampledata { -+ uint16 version; /* structure version */ -+ uint16 size; /* size of structure */ -+ uint16 tag; /* Header/Data */ -+ uint16 length; /* data length */ -+ uint32 flag; /* bit def */ -+} wl_sampledata_t; -+ -+/* wl_radar_args_t */ -+typedef struct { -+ int npulses; /* required number of pulses at n * t_int */ -+ int ncontig; /* required number of pulses at t_int */ -+ int min_pw; /* minimum pulse width (20 MHz clocks) */ -+ int max_pw; /* maximum pulse width (20 MHz clocks) */ -+ uint16 thresh0; /* Radar detection, thresh 0 */ -+ uint16 thresh1; /* Radar detection, thresh 1 */ -+ uint16 blank; /* Radar detection, blank control */ -+ uint16 fmdemodcfg; /* Radar detection, fmdemod config */ -+ int npulses_lp; /* Radar detection, minimum long pulses */ -+ int min_pw_lp; /* Minimum pulsewidth for long pulses */ -+ int max_pw_lp; /* Maximum pulsewidth for long pulses */ -+ int min_fm_lp; /* Minimum fm for long pulses */ -+ int max_span_lp; /* Maximum deltat for long pulses */ -+ int min_deltat; /* Minimum spacing between pulses */ -+ int max_deltat; /* Maximum spacing between pulses */ -+ uint16 autocorr; /* Radar detection, autocorr on or off */ -+ uint16 st_level_time; /* Radar detection, start_timing level */ -+ uint16 t2_min; /* minimum clocks needed to remain in state 2 */ -+ uint32 version; /* version */ -+ uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */ -+ int npulses_fra; /* Radar detection, minimum French pulses set */ -+ int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */ -+ int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */ -+ uint16 percal_mask; /* defines which period cal is masked from radar detection */ -+ int quant; /* quantization resolution to pulse positions */ -+ uint32 min_burst_intv_lp; /* minimum burst to burst interval for bin3 radar */ -+ uint32 max_burst_intv_lp; /* maximum burst to burst interval for bin3 radar */ -+ int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */ -+ int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */ -+ uint16 feature_mask; /* 16-bit mask to specify enabled features */ -+} wl_radar_args_t; -+ -+#define WL_RADAR_ARGS_VERSION 2 -+ -+typedef struct { -+ uint32 version; /* version */ -+ uint16 thresh0_20_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ -+ uint16 thresh1_20_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ -+ uint16 thresh0_40_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ -+ uint16 thresh1_40_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ -+ uint16 thresh0_80_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ -+ uint16 thresh1_80_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ -+ uint16 thresh0_160_lo; /* Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ -+ uint16 thresh1_160_lo; /* Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ -+ uint16 thresh0_20_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ -+ uint16 thresh1_20_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ -+ uint16 thresh0_40_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ -+ uint16 thresh1_40_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ -+ uint16 thresh0_80_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ -+ uint16 thresh1_80_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ -+ uint16 thresh0_160_hi; /* Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ -+ uint16 thresh1_160_hi; /* Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ -+} wl_radar_thr_t; -+ -+#define WL_RADAR_THR_VERSION 2 -+#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ -+ -+/* radar iovar SET defines */ -+#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ -+#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ -+#define WL_RADAR_SIMULATED 2 /* force radar detector to declare -+ * detection once -+ */ -+#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ -+#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */ -+#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */ -+#define WL_ANT_IDX_1 0 /* antenna index 1 */ -+#define WL_ANT_IDX_2 1 /* antenna index 2 */ -+ -+#ifndef WL_RSSI_ANT_MAX -+#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ -+#elif WL_RSSI_ANT_MAX != 4 -+#error "WL_RSSI_ANT_MAX does not match" -+#endif -+ -+/* RSSI per antenna */ -+typedef struct { -+ uint32 version; /* version field */ -+ uint32 count; /* number of valid antenna rssi */ -+ int8 rssi_ant[WL_RSSI_ANT_MAX]; /* rssi per antenna */ -+} wl_rssi_ant_t; -+ -+/* dfs_status iovar-related defines */ -+ -+/* cac - channel availability check, -+ * ism - in-service monitoring -+ * csa - channel switching announcement -+ */ -+ -+/* cac state values */ -+#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ -+#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ -+#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ -+#define WL_DFS_CACSTATE_CSA 3 /* csa */ -+#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ -+#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ -+#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ -+#define WL_DFS_CACSTATES 7 /* this many states exist */ -+ -+/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */ -+typedef struct { -+ uint state; /* noted by WL_DFS_CACSTATE_XX. */ -+ uint duration; /* time spent in ms in state. */ -+ /* as dfs enters ISM state, it removes the operational channel from quiet channel -+ * list and notes the channel in channel_cleared. set to 0 if no channel is cleared -+ */ -+ chanspec_t chanspec_cleared; -+ /* chanspec cleared used to be a uint, add another to uint16 to maintain size */ -+ uint16 pad; -+} wl_dfs_status_t; -+ -+#define NUM_PWRCTRL_RATES 12 -+ -+typedef struct { -+ uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /* User set target */ -+ uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /* reg and local power limit */ -+ uint8 txpwr_local_max; /* local max according to the AP */ -+ uint8 txpwr_local_constraint; /* local constraint according to the AP */ -+ uint8 txpwr_chan_reg_max; /* Regulatory max for this channel */ -+ uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /* Latest target for 2.4 and 5 Ghz */ -+ uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ -+ uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /* On G phy, OFDM power offset */ -+ uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /* Max CCK power for this band (SROM) */ -+ uint8 txpwr_bphy_ofdm_max; /* Max OFDM power for this band (SROM) */ -+ uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /* Max power for A band (SROM) */ -+ int8 txpwr_antgain[2]; /* Ant gain for each band - from SROM */ -+ uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ -+} tx_power_legacy_t; -+ -+#define WL_TX_POWER_RATES_LEGACY 45 -+#define WL_TX_POWER_MCS20_FIRST 12 -+#define WL_TX_POWER_MCS20_NUM 16 -+#define WL_TX_POWER_MCS40_FIRST 28 -+#define WL_TX_POWER_MCS40_NUM 17 -+ -+typedef struct { -+ uint32 flags; -+ chanspec_t chanspec; /* txpwr report for this channel */ -+ chanspec_t local_chanspec; /* channel on which we are associated */ -+ uint8 local_max; /* local max according to the AP */ -+ uint8 local_constraint; /* local constraint according to the AP */ -+ int8 antgain[2]; /* Ant gain for each band - from SROM */ -+ uint8 rf_cores; /* count of RF Cores being reported */ -+ uint8 est_Pout[4]; /* Latest tx power out estimate per RF -+ * chain without adjustment -+ */ -+ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ -+ uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /* User limit */ -+ uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */ -+ uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /* Max power board can support (SROM) */ -+ uint8 target[WL_TX_POWER_RATES_LEGACY]; /* Latest target power */ -+} tx_power_legacy2_t; -+ -+/* TX Power index defines */ -+#define WL_NUM_RATES_CCK 4 /* 1, 2, 5.5, 11 Mbps */ -+#define WL_NUM_RATES_OFDM 8 /* 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ -+#define WL_NUM_RATES_MCS_1STREAM 8 /* MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ -+#define WL_NUM_RATES_EXTRA_VHT 2 /* Additional VHT 11AC rates */ -+#define WL_NUM_RATES_VHT 10 -+#define WL_NUM_RATES_MCS32 1 -+ -+#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK -+#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM -+#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM -+#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM -+#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32 -+#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK -+#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM -+#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM -+#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM -+#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32 -+ -+#define WL_NUM_2x2_ELEMENTS 4 -+#define WL_NUM_3x3_ELEMENTS 6 -+ -+typedef struct txppr { -+ /* start of 20MHz tx power limits */ -+ uint8 b20_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ -+ uint8 b20_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ -+ -+ uint8 b20_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b20_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ -+ uint8 b20_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b20_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ -+ -+ uint8 b20_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b20_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ -+ uint8 b20_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b20_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ -+ uint8 b20_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ -+ -+ uint8 b20_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ -+ uint8 b20_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ -+ uint8 b20_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ -+ uint8 b20_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ -+ uint8 b20_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ -+ uint8 b20_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ -+ uint8 b20_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ -+ uint8 b20_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ -+ -+ /* start of 40MHz tx power limits */ -+ uint8 b40_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ -+ uint8 b40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ -+ -+ uint8 b40_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ -+ uint8 b40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ -+ -+ uint8 b40_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ -+ uint8 b40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ -+ uint8 b40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ -+ -+ uint8 b40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ -+ uint8 b40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ -+ uint8 b40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ -+ uint8 b40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ -+ uint8 b40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ -+ uint8 b40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ -+ uint8 b40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ -+ uint8 b40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ -+ -+ /* start of 20in40MHz tx power limits */ -+ uint8 b20in40_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20in40_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ -+ uint8 b20in40_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ -+ -+ uint8 b20in40_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20in40_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b20in40_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ -+ uint8 b20in40_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b20in40_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ -+ -+ uint8 b20in40_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20in40_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* 20 in 40 MHz Legacy OFDM CDD */ -+ uint8 b20in40_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ -+ uint8 b20in40_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b20in40_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ -+ uint8 b20in40_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ -+ -+ uint8 b20in40_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ -+ uint8 b20in40_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ -+ uint8 b20in40_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ -+ uint8 b20in40_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ -+ uint8 b20in40_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ -+ uint8 b20in40_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ -+ uint8 b20in40_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ -+ uint8 b20in40_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ -+ -+ /* start of 80MHz tx power limits */ -+ uint8 b80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ -+ uint8 b80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ -+ -+ uint8 b80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ -+ uint8 b80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ -+ -+ uint8 b80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ -+ uint8 b80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ -+ uint8 b80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ -+ -+ uint8 b80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ -+ uint8 b80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ -+ uint8 b80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ -+ uint8 b80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ -+ uint8 b80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ -+ uint8 b80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ -+ uint8 b80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ -+ uint8 b80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ -+ -+ /* start of 20in80MHz tx power limits */ -+ uint8 b20in80_1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ -+ uint8 b20in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ -+ -+ uint8 b20in80_1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b20in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ -+ uint8 b20in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b20in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ -+ -+ uint8 b20in80_1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b20in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b20in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ -+ uint8 b20in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b20in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ -+ uint8 b20in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ -+ -+ uint8 b20in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ -+ uint8 b20in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ -+ uint8 b20in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ -+ uint8 b20in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ -+ uint8 b20in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ -+ uint8 b20in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ -+ uint8 b20in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ -+ uint8 b20in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ -+ -+ /* start of 40in80MHz tx power limits */ -+ uint8 b40in80_dummy1x1dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b40in80_1x1ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM transmission */ -+ uint8 b40in80_1x1mcs0[WL_NUM_RATES_MCS_1STREAM]; /* SISO MCS 0-7 */ -+ -+ uint8 b40in80_dummy1x2dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b40in80_1x2cdd_ofdm[WL_NUM_RATES_OFDM]; /* Legacy OFDM CDD transmission */ -+ uint8 b40in80_1x2cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* CDD MCS 0-7 */ -+ uint8 b40in80_2x2stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b40in80_2x2sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* MCS 8-15 */ -+ -+ uint8 b40in80_dummy1x3dsss[WL_NUM_RATES_CCK]; /* Legacy CCK/DSSS */ -+ uint8 b40in80_1x3cdd_ofdm[WL_NUM_RATES_OFDM]; /* MHz Legacy OFDM CDD */ -+ uint8 b40in80_1x3cdd_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* 1 Nsts to 3 Tx Chain */ -+ uint8 b40in80_2x3stbc_mcs0[WL_NUM_RATES_MCS_1STREAM]; /* STBC MCS 0-7 */ -+ uint8 b40in80_2x3sdm_mcs8[WL_NUM_RATES_MCS_1STREAM]; /* 2 Nsts to 3 Tx Chain */ -+ uint8 b40in80_3x3sdm_mcs16[WL_NUM_RATES_MCS_1STREAM]; /* 3 Nsts to 3 Tx Chain */ -+ -+ uint8 b40in80_1x1vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1 */ -+ uint8 b40in80_1x2cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD1 */ -+ uint8 b40in80_2x2stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC */ -+ uint8 b40in80_2x2sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2 */ -+ uint8 b40in80_1x3cdd_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_CDD2 */ -+ uint8 b40in80_2x3stbc_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS1_STBC_SPEXP1 */ -+ uint8 b40in80_2x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS2_SPEXP1 */ -+ uint8 b40in80_3x3sdm_vht[WL_NUM_RATES_EXTRA_VHT]; /* VHT8_9SS3 */ -+ -+ uint8 mcs32; /* C_CHECK - THIS NEEDS TO BE REMOVED THROUGHOUT THE CODE */ -+} txppr_t; -+ -+/* 20MHz */ -+#define WL_TX_POWER_CCK_FIRST OFFSETOF(txppr_t, b20_1x1dsss) -+#define WL_TX_POWER_OFDM20_FIRST OFFSETOF(txppr_t, b20_1x1ofdm) -+#define WL_TX_POWER_MCS20_SISO_FIRST OFFSETOF(txppr_t, b20_1x1mcs0) -+#define WL_TX_POWER_20_S1x1_FIRST OFFSETOF(txppr_t, b20_1x1mcs0) -+ -+#define WL_TX_POWER_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20_1x2dsss) -+#define WL_TX_POWER_OFDM20_CDD_FIRST OFFSETOF(txppr_t, b20_1x2cdd_ofdm) -+#define WL_TX_POWER_MCS20_CDD_FIRST OFFSETOF(txppr_t, b20_1x2cdd_mcs0) -+#define WL_TX_POWER_20_S1x2_FIRST OFFSETOF(txppr_t, b20_1x2cdd_mcs0) -+#define WL_TX_POWER_MCS20_STBC_FIRST OFFSETOF(txppr_t, b20_2x2stbc_mcs0) -+#define WL_TX_POWER_MCS20_SDM_FIRST OFFSETOF(txppr_t, b20_2x2sdm_mcs8) -+#define WL_TX_POWER_20_S2x2_FIRST OFFSETOF(txppr_t, b20_2x2sdm_mcs8) -+ -+#define WL_TX_POWER_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3dsss) -+#define WL_TX_POWER_OFDM20_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3cdd_ofdm) -+#define WL_TX_POWER_20_S1x3_FIRST OFFSETOF(txppr_t, b20_1x3cdd_mcs0) -+#define WL_TX_POWER_20_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20_2x3stbc_mcs0) -+#define WL_TX_POWER_20_S2x3_FIRST OFFSETOF(txppr_t, b20_2x3sdm_mcs8) -+#define WL_TX_POWER_20_S3x3_FIRST OFFSETOF(txppr_t, b20_3x3sdm_mcs16) -+ -+#define WL_TX_POWER_20_S1X1_VHT OFFSETOF(txppr_t, b20_1x1vht) -+#define WL_TX_POWER_20_S1X2_CDD_VHT OFFSETOF(txppr_t, b20_1x2cdd_vht) -+#define WL_TX_POWER_20_S2X2_STBC_VHT OFFSETOF(txppr_t, b20_2x2stbc_vht) -+#define WL_TX_POWER_20_S2X2_VHT OFFSETOF(txppr_t, b20_2x2sdm_vht) -+#define WL_TX_POWER_20_S1X3_CDD_VHT OFFSETOF(txppr_t, b20_1x3cdd_vht) -+#define WL_TX_POWER_20_S2X3_STBC_VHT OFFSETOF(txppr_t, b20_2x3stbc_vht) -+#define WL_TX_POWER_20_S2X3_VHT OFFSETOF(txppr_t, b20_2x3sdm_vht) -+#define WL_TX_POWER_20_S3X3_VHT OFFSETOF(txppr_t, b20_3x3sdm_vht) -+ -+/* 40MHz */ -+#define WL_TX_POWER_40_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b40_dummy1x1dsss) -+#define WL_TX_POWER_OFDM40_FIRST OFFSETOF(txppr_t, b40_1x1ofdm) -+#define WL_TX_POWER_MCS40_SISO_FIRST OFFSETOF(txppr_t, b40_1x1mcs0) -+#define WL_TX_POWER_40_S1x1_FIRST OFFSETOF(txppr_t, b40_1x1mcs0) -+ -+#define WL_TX_POWER_40_DUMMY_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b40_dummy1x2dsss) -+#define WL_TX_POWER_OFDM40_CDD_FIRST OFFSETOF(txppr_t, b40_1x2cdd_ofdm) -+#define WL_TX_POWER_MCS40_CDD_FIRST OFFSETOF(txppr_t, b40_1x2cdd_mcs0) -+#define WL_TX_POWER_40_S1x2_FIRST OFFSETOF(txppr_t, b40_1x2cdd_mcs0) -+#define WL_TX_POWER_MCS40_STBC_FIRST OFFSETOF(txppr_t, b40_2x2stbc_mcs0) -+#define WL_TX_POWER_MCS40_SDM_FIRST OFFSETOF(txppr_t, b40_2x2sdm_mcs8) -+#define WL_TX_POWER_40_S2x2_FIRST OFFSETOF(txppr_t, b40_2x2sdm_mcs8) -+ -+#define WL_TX_POWER_40_DUMMY_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40_dummy1x3dsss) -+#define WL_TX_POWER_OFDM40_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40_1x3cdd_ofdm) -+#define WL_TX_POWER_40_S1x3_FIRST OFFSETOF(txppr_t, b40_1x3cdd_mcs0) -+#define WL_TX_POWER_40_STBC_S2x3_FIRST OFFSETOF(txppr_t, b40_2x3stbc_mcs0) -+#define WL_TX_POWER_40_S2x3_FIRST OFFSETOF(txppr_t, b40_2x3sdm_mcs8) -+#define WL_TX_POWER_40_S3x3_FIRST OFFSETOF(txppr_t, b40_3x3sdm_mcs16) -+ -+#define WL_TX_POWER_40_S1X1_VHT OFFSETOF(txppr_t, b40_1x1vht) -+#define WL_TX_POWER_40_S1X2_CDD_VHT OFFSETOF(txppr_t, b40_1x2cdd_vht) -+#define WL_TX_POWER_40_S2X2_STBC_VHT OFFSETOF(txppr_t, b40_2x2stbc_vht) -+#define WL_TX_POWER_40_S2X2_VHT OFFSETOF(txppr_t, b40_2x2sdm_vht) -+#define WL_TX_POWER_40_S1X3_CDD_VHT OFFSETOF(txppr_t, b40_1x3cdd_vht) -+#define WL_TX_POWER_40_S2X3_STBC_VHT OFFSETOF(txppr_t, b40_2x3stbc_vht) -+#define WL_TX_POWER_40_S2X3_VHT OFFSETOF(txppr_t, b40_2x3sdm_vht) -+#define WL_TX_POWER_40_S3X3_VHT OFFSETOF(txppr_t, b40_3x3sdm_vht) -+ -+/* 20 in 40MHz */ -+#define WL_TX_POWER_20UL_CCK_FIRST OFFSETOF(txppr_t, b20in40_1x1dsss) -+#define WL_TX_POWER_20UL_OFDM_FIRST OFFSETOF(txppr_t, b20in40_1x1ofdm) -+#define WL_TX_POWER_20UL_S1x1_FIRST OFFSETOF(txppr_t, b20in40_1x1mcs0) -+ -+#define WL_TX_POWER_CCK_20U_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20in40_1x2dsss) -+#define WL_TX_POWER_20UL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b20in40_1x2cdd_ofdm) -+#define WL_TX_POWER_20UL_S1x2_FIRST OFFSETOF(txppr_t, b20in40_1x2cdd_mcs0) -+#define WL_TX_POWER_20UL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b20in40_2x2stbc_mcs0) -+#define WL_TX_POWER_20UL_S2x2_FIRST OFFSETOF(txppr_t, b20in40_2x2sdm_mcs8) -+ -+#define WL_TX_POWER_CCK_20U_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3dsss) -+#define WL_TX_POWER_20UL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3cdd_ofdm) -+#define WL_TX_POWER_20UL_S1x3_FIRST OFFSETOF(txppr_t, b20in40_1x3cdd_mcs0) -+#define WL_TX_POWER_20UL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20in40_2x3stbc_mcs0) -+#define WL_TX_POWER_20UL_S2x3_FIRST OFFSETOF(txppr_t, b20in40_2x3sdm_mcs8) -+#define WL_TX_POWER_20UL_S3x3_FIRST OFFSETOF(txppr_t, b20in40_3x3sdm_mcs16) -+ -+#define WL_TX_POWER_20UL_S1X1_VHT OFFSETOF(txppr_t, b20in40_1x1vht) -+#define WL_TX_POWER_20UL_S1X2_CDD_VHT OFFSETOF(txppr_t, b20in40_1x2cdd_vht) -+#define WL_TX_POWER_20UL_S2X2_STBC_VHT OFFSETOF(txppr_t, b20in40_2x2stbc_vht) -+#define WL_TX_POWER_20UL_S2X2_VHT OFFSETOF(txppr_t, b20in40_2x2sdm_vht) -+#define WL_TX_POWER_20UL_S1X3_CDD_VHT OFFSETOF(txppr_t, b20in40_1x3cdd_vht) -+#define WL_TX_POWER_20UL_S2X3_STBC_VHT OFFSETOF(txppr_t, b20in40_2x3stbc_vht) -+#define WL_TX_POWER_20UL_S2X3_VHT OFFSETOF(txppr_t, b20in40_2x3sdm_vht) -+#define WL_TX_POWER_20UL_S3X3_VHT OFFSETOF(txppr_t, b20in40_3x3sdm_vht) -+ -+/* 80MHz */ -+#define WL_TX_POWER_80_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b80_dummy1x1dsss) -+#define WL_TX_POWER_OFDM80_FIRST OFFSETOF(txppr_t, b80_1x1ofdm) -+#define WL_TX_POWER_MCS80_SISO_FIRST OFFSETOF(txppr_t, b80_1x1mcs0) -+#define WL_TX_POWER_80_S1x1_FIRST OFFSETOF(txppr_t, b80_1x1mcs0) -+ -+#define WL_TX_POWER_80_DUMMY_CCK_CDD_S1x2_FIRST OFFSETOF(txppr_t, b80_dummy1x2dsss) -+#define WL_TX_POWER_OFDM80_CDD_FIRST OFFSETOF(txppr_t, b80_1x2cdd_ofdm) -+#define WL_TX_POWER_MCS80_CDD_FIRST OFFSETOF(txppr_t, b80_1x2cdd_mcs0) -+#define WL_TX_POWER_80_S1x2_FIRST OFFSETOF(txppr_t, b80_1x2cdd_mcs0) -+#define WL_TX_POWER_MCS80_STBC_FIRST OFFSETOF(txppr_t, b80_2x2stbc_mcs0) -+#define WL_TX_POWER_MCS80_SDM_FIRST OFFSETOF(txppr_t, b80_2x2sdm_mcs8) -+#define WL_TX_POWER_80_S2x2_FIRST OFFSETOF(txppr_t, b80_2x2sdm_mcs8) -+ -+#define WL_TX_POWER_80_DUMMY_CCK_CDD_S1x3_FIRST OFFSETOF(txppr_t, b80_dummy1x3dsss) -+#define WL_TX_POWER_OFDM80_CDD_S1x3_FIRST OFFSETOF(txppr_t, b80_1x3cdd_ofdm) -+#define WL_TX_POWER_80_S1x3_FIRST OFFSETOF(txppr_t, b80_1x3cdd_mcs0) -+#define WL_TX_POWER_80_STBC_S2x3_FIRST OFFSETOF(txppr_t, b80_2x3stbc_mcs0) -+#define WL_TX_POWER_80_S2x3_FIRST OFFSETOF(txppr_t, b80_2x3sdm_mcs8) -+#define WL_TX_POWER_80_S3x3_FIRST OFFSETOF(txppr_t, b80_3x3sdm_mcs16) -+ -+#define WL_TX_POWER_80_S1X1_VHT OFFSETOF(txppr_t, b80_1x1vht) -+#define WL_TX_POWER_80_S1X2_CDD_VHT OFFSETOF(txppr_t, b80_1x2cdd_vht) -+#define WL_TX_POWER_80_S2X2_STBC_VHT OFFSETOF(txppr_t, b80_2x2stbc_vht) -+#define WL_TX_POWER_80_S2X2_VHT OFFSETOF(txppr_t, b80_2x2sdm_vht) -+#define WL_TX_POWER_80_S1X3_CDD_VHT OFFSETOF(txppr_t, b80_1x3cdd_vht) -+#define WL_TX_POWER_80_S2X3_STBC_VHT OFFSETOF(txppr_t, b80_2x3stbc_vht) -+#define WL_TX_POWER_80_S2X3_VHT OFFSETOF(txppr_t, b80_2x3sdm_vht) -+#define WL_TX_POWER_80_S3X3_VHT OFFSETOF(txppr_t, b80_3x3sdm_vht) -+ -+/* 20 in 80MHz */ -+#define WL_TX_POWER_20UUL_CCK_FIRST OFFSETOF(txppr_t, b20in80_1x1dsss) -+#define WL_TX_POWER_20UUL_OFDM_FIRST OFFSETOF(txppr_t, b20in80_1x1ofdm) -+#define WL_TX_POWER_20UUL_S1x1_FIRST OFFSETOF(txppr_t, b20in80_1x1mcs0) -+ -+#define WL_TX_POWER_CCK_20UU_CDD_S1x2_FIRST OFFSETOF(txppr_t, b20in80_1x2dsss) -+#define WL_TX_POWER_20UUL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b20in80_1x2cdd_ofdm) -+#define WL_TX_POWER_20UUL_S1x2_FIRST OFFSETOF(txppr_t, b20in80_1x2cdd_mcs0) -+#define WL_TX_POWER_20UUL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b20in80_2x2stbc_mcs0) -+#define WL_TX_POWER_20UUL_S2x2_FIRST OFFSETOF(txppr_t, b20in80_2x2sdm_mcs8) -+ -+#define WL_TX_POWER_CCK_20UU_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3dsss) -+#define WL_TX_POWER_20UUL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3cdd_ofdm) -+#define WL_TX_POWER_20UUL_S1x3_FIRST OFFSETOF(txppr_t, b20in80_1x3cdd_mcs0) -+#define WL_TX_POWER_20UUL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b20in80_2x3stbc_mcs0) -+#define WL_TX_POWER_20UUL_S2x3_FIRST OFFSETOF(txppr_t, b20in80_2x3sdm_mcs8) -+#define WL_TX_POWER_20UUL_S3x3_FIRST OFFSETOF(txppr_t, b20in80_3x3sdm_mcs16) -+ -+#define WL_TX_POWER_20UUL_S1X1_VHT OFFSETOF(txppr_t, b20in80_1x1vht) -+#define WL_TX_POWER_20UUL_S1X2_CDD_VHT OFFSETOF(txppr_t, b20in80_1x2cdd_vht) -+#define WL_TX_POWER_20UUL_S2X2_STBC_VHT OFFSETOF(txppr_t, b20in80_2x2stbc_vht) -+#define WL_TX_POWER_20UUL_S2X2_VHT OFFSETOF(txppr_t, b20in80_2x2sdm_vht) -+#define WL_TX_POWER_20UUL_S1X3_CDD_VHT OFFSETOF(txppr_t, b20in80_1x3cdd_vht) -+#define WL_TX_POWER_20UUL_S2X3_STBC_VHT OFFSETOF(txppr_t, b20in80_2x3stbc_vht) -+#define WL_TX_POWER_20UUL_S2X3_VHT OFFSETOF(txppr_t, b20in80_2x3sdm_vht) -+#define WL_TX_POWER_20UUL_S3X3_VHT OFFSETOF(txppr_t, b20in80_3x3sdm_vht) -+ -+/* 40 in 80MHz */ -+#define WL_TX_POWER_40UUL_DUMMY_CCK_FIRST OFFSETOF(txppr_t, b40in80_dummy1x1dsss) -+#define WL_TX_POWER_40UUL_OFDM_FIRST OFFSETOF(txppr_t, b40in80_1x1ofdm) -+#define WL_TX_POWER_40UUL_S1x1_FIRST OFFSETOF(txppr_t, b40in80_1x1mcs0) -+ -+#define WL_TX_POWER_CCK_40UU_DUMMY_CDD_S1x2_FIRST OFFSETOF(txppr_t, b40in80_dummy1x2dsss) -+#define WL_TX_POWER_40UUL_OFDM_CDD_FIRST OFFSETOF(txppr_t, b40in80_1x2cdd_ofdm) -+#define WL_TX_POWER_40UUL_S1x2_FIRST OFFSETOF(txppr_t, b40in80_1x2cdd_mcs0) -+#define WL_TX_POWER_40UUL_STBC_S2x2_FIRST OFFSETOF(txppr_t, b40in80_2x2stbc_mcs0) -+#define WL_TX_POWER_40UUL_S2x2_FIRST OFFSETOF(txppr_t, b40in80_2x2sdm_mcs8) -+ -+#define WL_TX_POWER_CCK_40UU_DUMMY_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40in80_dummy1x3dsss) -+#define WL_TX_POWER_40UUL_OFDM_CDD_S1x3_FIRST OFFSETOF(txppr_t, b40in80_1x3cdd_ofdm) -+#define WL_TX_POWER_40UUL_S1x3_FIRST OFFSETOF(txppr_t, b40in80_1x3cdd_mcs0) -+#define WL_TX_POWER_40UUL_STBC_S2x3_FIRST OFFSETOF(txppr_t, b40in80_2x3stbc_mcs0) -+#define WL_TX_POWER_40UUL_S2x3_FIRST OFFSETOF(txppr_t, b40in80_2x3sdm_mcs8) -+#define WL_TX_POWER_40UUL_S3x3_FIRST OFFSETOF(txppr_t, b40in80_3x3sdm_mcs16) -+ -+#define WL_TX_POWER_40UUL_S1X1_VHT OFFSETOF(txppr_t, b40in80_1x1vht) -+#define WL_TX_POWER_40UUL_S1X2_CDD_VHT OFFSETOF(txppr_t, b40in80_1x2cdd_vht) -+#define WL_TX_POWER_40UUL_S2X2_STBC_VHT OFFSETOF(txppr_t, b40in80_2x2stbc_vht) -+#define WL_TX_POWER_40UUL_S2X2_VHT OFFSETOF(txppr_t, b40in80_2x2sdm_vht) -+#define WL_TX_POWER_40UUL_S1X3_CDD_VHT OFFSETOF(txppr_t, b40in80_1x3cdd_vht) -+#define WL_TX_POWER_40UUL_S2X3_STBC_VHT OFFSETOF(txppr_t, b40in80_2x3stbc_vht) -+#define WL_TX_POWER_40UUL_S2X3_VHT OFFSETOF(txppr_t, b40in80_2x3sdm_vht) -+#define WL_TX_POWER_40UUL_S3X3_VHT OFFSETOF(txppr_t, b40in80_3x3sdm_vht) -+ -+#define WL_TX_POWER_MCS_32 OFFSETOF(txppr_t, mcs32) /* C_CHECK remove later */ -+ -+#define WL_TX_POWER_RATES sizeof(struct txppr) -+ -+/* sslpnphy specifics */ -+#define WL_TX_POWER_MCS20_SISO_FIRST_SSN WL_TX_POWER_MCS20_SISO_FIRST -+#define WL_TX_POWER_MCS40_SISO_FIRST_SSN WL_TX_POWER_MCS40_SISO_FIRST -+ -+/* tx_power_t.flags bits */ -+#define WL_TX_POWER_F_ENABLED 1 -+#define WL_TX_POWER_F_HW 2 -+#define WL_TX_POWER_F_MIMO 4 -+#define WL_TX_POWER_F_SISO 8 -+#define WL_TX_POWER_F_HT 0x10 -+ -+typedef struct { -+ uint16 ver; /* version of this struct */ -+ uint16 len; /* length in bytes of this structure */ -+ uint32 flags; -+ chanspec_t chanspec; /* txpwr report for this channel */ -+ chanspec_t local_chanspec; /* channel on which we are associated */ -+ uint8 ppr[WL_TX_POWER_RATES]; /* Latest target power */ -+} wl_txppr_t; -+ -+#define WL_TXPPR_VERSION 0 -+#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) -+#define TX_POWER_T_VERSION 43 -+ -+/* Defines used with channel_bandwidth for curpower */ -+#define WL_BW_20MHZ 0 -+#define WL_BW_40MHZ 1 -+#define WL_BW_80MHZ 2 -+ -+/* tx_power_t.flags bits */ -+#ifdef PPR_API -+#define WL_TX_POWER2_F_ENABLED 1 -+#define WL_TX_POWER2_F_HW 2 -+#define WL_TX_POWER2_F_MIMO 4 -+#define WL_TX_POWER2_F_SISO 8 -+#define WL_TX_POWER2_F_HT 0x10 -+#else -+#define WL_TX_POWER_F_ENABLED 1 -+#define WL_TX_POWER_F_HW 2 -+#define WL_TX_POWER_F_MIMO 4 -+#define WL_TX_POWER_F_SISO 8 -+#define WL_TX_POWER_F_HT 0x10 -+#endif -+typedef struct { -+ uint32 flags; -+ chanspec_t chanspec; /* txpwr report for this channel */ -+ chanspec_t local_chanspec; /* channel on which we are associated */ -+ uint8 local_max; /* local max according to the AP */ -+ uint8 local_constraint; /* local constraint according to the AP */ -+ int8 antgain[2]; /* Ant gain for each band - from SROM */ -+ uint8 rf_cores; /* count of RF Cores being reported */ -+ uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ -+ uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain -+ * without adjustment -+ */ -+ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ -+ uint8 tx_power_max[4]; /* Maximum target power among all rates */ -+ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ -+ uint8 user_limit[WL_TX_POWER_RATES]; /* User limit */ -+ int8 board_limit[WL_TX_POWER_RATES]; /* Max power board can support (SROM) */ -+ int8 target[WL_TX_POWER_RATES]; /* Latest target power */ -+ int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */ -+ int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */ -+ int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */ -+ int8 sar; /* SAR limit for display by wl executable */ -+ int8 channel_bandwidth; /* 20, 40 or 80 MHz bandwidth? */ -+ uint8 version; /* Version of the data format wlu <--> driver */ -+ uint8 display_core; /* Displayed curpower core */ -+#ifdef PPR_API -+} tx_power_new_t; -+#else -+} tx_power_t; -+#endif -+ -+typedef struct tx_inst_power { -+ uint8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ -+ uint8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ -+} tx_inst_power_t; -+ -+ -+typedef struct { -+ uint32 flags; -+ chanspec_t chanspec; /* txpwr report for this channel */ -+ chanspec_t local_chanspec; /* channel on which we are associated */ -+ uint8 local_max; /* local max according to the AP */ -+ uint8 local_constraint; /* local constraint according to the AP */ -+ int8 antgain[2]; /* Ant gain for each band - from SROM */ -+ uint8 rf_cores; /* count of RF Cores being reported */ -+ uint8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ -+ uint8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain -+ * without adjustment -+ */ -+ uint8 est_Pout_cck; /* Latest CCK tx power out estimate */ -+ uint8 tx_power_max[4]; /* Maximum target power among all rates */ -+ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */ -+ txppr_t user_limit; /* User limit */ -+ txppr_t reg_limit; /* Regulatory power limit */ -+ txppr_t board_limit; /* Max power board can support (SROM) */ -+ txppr_t target; /* Latest target power */ -+} wl_txpwr_t; -+ -+#define WL_NUM_TXCHAIN_MAX 4 -+typedef struct wl_txchain_pwr_offsets { -+ int8 offset[WL_NUM_TXCHAIN_MAX]; /* quarter dBm signed offset for each chain */ -+} wl_txchain_pwr_offsets_t; -+ -+/* 802.11h measurement types */ -+#define WLC_MEASURE_TPC 1 -+#define WLC_MEASURE_CHANNEL_BASIC 2 -+#define WLC_MEASURE_CHANNEL_CCA 3 -+#define WLC_MEASURE_CHANNEL_RPI 4 -+ -+/* regulatory enforcement levels */ -+#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ -+#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ -+#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ -+#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ -+/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE -+ * adoption is done regardless of capability spectrum_management -+ */ -+#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ -+ -+#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ -+#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ -+#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ -+#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ -+#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ -+#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ -+#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ -+ -+/* BTC mode used by "btc_mode" iovar */ -+#define WL_BTC_DISABLE 0 /* disable BT coexistence */ -+#define WL_BTC_FULLTDM 1 /* full TDM COEX */ -+#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ -+#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ -+#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ -+#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ -+#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ -+#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ -+#define WL_INF_BTC_DISABLE 0 -+#define WL_INF_BTC_ENABLE 1 -+#define WL_INF_BTC_AUTO 3 -+ -+/* BTC wire used by "btc_wire" iovar */ -+#define WL_BTC_DEFWIRE 0 /* use default wire setting */ -+#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ -+#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ -+#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ -+ -+/* BTC flags: BTC configuration that can be set by host */ -+#define WL_BTC_FLAG_PREMPT (1 << 0) -+#define WL_BTC_FLAG_BT_DEF (1 << 1) -+#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) -+#define WL_BTC_FLAG_SIM_RSP (1 << 3) -+#define WL_BTC_FLAG_PS_PROTECT (1 << 4) -+#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) -+#define WL_BTC_FLAG_ECI (1 << 6) -+#define WL_BTC_FLAG_LIGHT (1 << 7) -+#define WL_BTC_FLAG_PARALLEL (1 << 8) -+ -+/* Message levels */ -+#define WL_ERROR_VAL 0x00000001 -+#define WL_TRACE_VAL 0x00000002 -+#define WL_PRHDRS_VAL 0x00000004 -+#define WL_PRPKT_VAL 0x00000008 -+#define WL_INFORM_VAL 0x00000010 -+#define WL_TMP_VAL 0x00000020 -+#define WL_OID_VAL 0x00000040 -+#define WL_RATE_VAL 0x00000080 -+#define WL_ASSOC_VAL 0x00000100 -+#define WL_PRUSR_VAL 0x00000200 -+#define WL_PS_VAL 0x00000400 -+#define WL_TXPWR_VAL 0x00000800 /* retired in TOT on 6/10/2009 */ -+#define WL_PORT_VAL 0x00001000 -+#define WL_DUAL_VAL 0x00002000 -+#define WL_WSEC_VAL 0x00004000 -+#define WL_WSEC_DUMP_VAL 0x00008000 -+#define WL_LOG_VAL 0x00010000 -+#define WL_NRSSI_VAL 0x00020000 /* retired in TOT on 6/10/2009 */ -+#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */ -+#define WL_REGULATORY_VAL 0x00080000 -+#define WL_PHYCAL_VAL 0x00100000 /* retired in TOT on 6/10/2009 */ -+#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */ -+#define WL_MPC_VAL 0x00400000 -+#define WL_APSTA_VAL 0x00800000 -+#define WL_DFS_VAL 0x01000000 -+#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */ -+#define WL_ACI_VAL 0x04000000 -+#define WL_MBSS_VAL 0x04000000 -+#define WL_CAC_VAL 0x08000000 -+#define WL_AMSDU_VAL 0x10000000 -+#define WL_AMPDU_VAL 0x20000000 -+#define WL_FFPLD_VAL 0x40000000 -+ -+/* wl_msg_level is full. For new bits take the next one and AND with -+ * wl_msg_level2 in wl_dbg.h -+ */ -+#define WL_DPT_VAL 0x00000001 -+#define WL_SCAN_VAL 0x00000002 -+#define WL_WOWL_VAL 0x00000004 -+#define WL_COEX_VAL 0x00000008 -+#define WL_RTDC_VAL 0x00000010 -+#define WL_PROTO_VAL 0x00000020 -+#define WL_BTA_VAL 0x00000040 -+#define WL_CHANINT_VAL 0x00000080 -+#define WL_THERMAL_VAL 0x00000100 /* retired in TOT on 6/10/2009 */ -+#define WL_P2P_VAL 0x00000200 -+#define WL_ITFR_VAL 0x00000400 -+#define WL_MCHAN_VAL 0x00000800 -+#define WL_TDLS_VAL 0x00001000 -+#define WL_MCNX_VAL 0x00002000 -+#define WL_PROT_VAL 0x00004000 -+#define WL_PSTA_VAL 0x00008000 -+#define WL_TBTT_VAL 0x00010000 -+#define WL_NIC_VAL 0x00020000 -+#define WL_PWRSEL_VAL 0x00040000 -+/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier -+ * rather than a message-type of its own -+ */ -+#define WL_TIMESTAMP_VAL 0x80000000 -+ -+/* max # of leds supported by GPIO (gpio pin# == led index#) */ -+#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ -+ -+/* led per-pin behaviors */ -+#define WL_LED_OFF 0 /* always off */ -+#define WL_LED_ON 1 /* always on */ -+#define WL_LED_ACTIVITY 2 /* activity */ -+#define WL_LED_RADIO 3 /* radio enabled */ -+#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ -+#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ -+#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ -+#define WL_LED_WI1 7 -+#define WL_LED_WI2 8 -+#define WL_LED_WI3 9 -+#define WL_LED_ASSOC 10 /* associated state indicator */ -+#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ -+#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ -+#define WL_LED_WI4 13 -+#define WL_LED_WI5 14 -+#define WL_LED_BLINKSLOW 15 /* blink slow */ -+#define WL_LED_BLINKMED 16 /* blink med */ -+#define WL_LED_BLINKFAST 17 /* blink fast */ -+#define WL_LED_BLINKCUSTOM 18 /* blink custom */ -+#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ -+#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ -+ /* keep on for 300 sec */ -+#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ -+#define WL_LED_NUMBEHAVIOR 22 -+ -+/* led behavior numeric value format */ -+#define WL_LED_BEH_MASK 0x7f /* behavior mask */ -+#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ -+ -+/* maximum channels returned by the get valid channels iovar */ -+#define WL_NUMCHANNELS 64 -+ -+/* max number of chanspecs (used by the iovar to calc. buf space) */ -+#define WL_NUMCHANSPECS 110 -+ -+/* WDS link local endpoint WPA role */ -+#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ -+#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ -+#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ -+ -+/* number of bytes needed to define a 128-bit mask for MAC event reporting */ -+#define WL_EVENTING_MASK_LEN 16 -+ -+/* -+ * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, -+ * a one-byte length, and a variable length value. RSSI type tuple must be present -+ * in the array. -+ * -+ * Types are defined in "join preference types" section. -+ * -+ * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple -+ * and must be set to zero. -+ * -+ * Values are defined below. -+ * -+ * 1. RSSI - 2 octets -+ * offset 0: reserved -+ * offset 1: reserved -+ * -+ * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) -+ * offset 0: reserved -+ * offset 1: # of tuples -+ * offset 2: tuple 1 -+ * offset 14: tuple 2 -+ * ... -+ * offset 2 + 12 * (n - 1) octets: tuple n -+ * -+ * struct wpa_cfg_tuple { -+ * uint8 akm[DOT11_OUI_LEN+1]; akm suite -+ * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite -+ * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite -+ * }; -+ * -+ * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. -+ * -+ * 3. BAND - 2 octets -+ * offset 0: reserved -+ * offset 1: see "band preference" and "band types" -+ * -+ * 4. BAND RSSI - 2 octets -+ * offset 0: band types -+ * offset 1: +ve RSSI boost balue in dB -+ */ -+ -+/* join preference types */ -+#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ -+#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ -+#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ -+#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ -+#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ -+ -+/* band preference */ -+#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ -+ -+/* any multicast cipher suite */ -+#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" -+ -+struct tsinfo_arg { -+ uint8 octets[3]; -+}; -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+#define NFIFO 6 /* # tx/rx fifopairs */ -+ -+#define WL_CNT_T_VERSION 8 /* current version of wl_cnt_t struct */ -+ -+typedef struct { -+ uint16 version; /* see definition of WL_CNT_T_VERSION */ -+ uint16 length; /* length of entire structure */ -+ -+ /* transmit stat counters */ -+ uint32 txframe; /* tx data frames */ -+ uint32 txbyte; /* tx data bytes */ -+ uint32 txretrans; /* tx mac retransmits */ -+ uint32 txerror; /* tx data errors (derived: sum of others) */ -+ uint32 txctl; /* tx management frames */ -+ uint32 txprshort; /* tx short preamble frames */ -+ uint32 txserr; /* tx status errors */ -+ uint32 txnobuf; /* tx out of buffers errors */ -+ uint32 txnoassoc; /* tx discard because we're not associated */ -+ uint32 txrunt; /* tx runt frames */ -+ uint32 txchit; /* tx header cache hit (fastpath) */ -+ uint32 txcmiss; /* tx header cache miss (slowpath) */ -+ -+ /* transmit chip error counters */ -+ uint32 txuflo; /* tx fifo underflows */ -+ uint32 txphyerr; /* tx phy errors (indicated in tx status) */ -+ uint32 txphycrs; -+ -+ /* receive stat counters */ -+ uint32 rxframe; /* rx data frames */ -+ uint32 rxbyte; /* rx data bytes */ -+ uint32 rxerror; /* rx data errors (derived: sum of others) */ -+ uint32 rxctl; /* rx management frames */ -+ uint32 rxnobuf; /* rx out of buffers errors */ -+ uint32 rxnondata; /* rx non data frames in the data channel errors */ -+ uint32 rxbadds; /* rx bad DS errors */ -+ uint32 rxbadcm; /* rx bad control or management frames */ -+ uint32 rxfragerr; /* rx fragmentation errors */ -+ uint32 rxrunt; /* rx runt frames */ -+ uint32 rxgiant; /* rx giant frames */ -+ uint32 rxnoscb; /* rx no scb error */ -+ uint32 rxbadproto; /* rx invalid frames */ -+ uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ -+ uint32 rxbadda; /* rx frames tossed for invalid da */ -+ uint32 rxfilter; /* rx frames filtered out */ -+ -+ /* receive chip error counters */ -+ uint32 rxoflo; /* rx fifo overflow errors */ -+ uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ -+ -+ uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ -+ uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ -+ uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ -+ -+ /* misc counters */ -+ uint32 dmade; /* tx/rx dma descriptor errors */ -+ uint32 dmada; /* tx/rx dma data errors */ -+ uint32 dmape; /* tx/rx dma descriptor protocol errors */ -+ uint32 reset; /* reset count */ -+ uint32 tbtt; /* cnts the TBTT int's */ -+ uint32 txdmawar; -+ uint32 pkt_callback_reg_fail; /* callbacks register failure */ -+ -+ /* MAC counters: 32-bit version of d11.h's macstat_t */ -+ uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, -+ * Control Management (includes retransmissions) -+ */ -+ uint32 txrtsfrm; /* number of RTS sent out by the MAC */ -+ uint32 txctsfrm; /* number of CTS sent out by the MAC */ -+ uint32 txackfrm; /* number of ACK frames sent out */ -+ uint32 txdnlfrm; /* Not used */ -+ uint32 txbcnfrm; /* beacons transmitted */ -+ uint32 txfunfl[8]; /* per-fifo tx underflows */ -+ uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS -+ * or BCN) -+ */ -+ uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for -+ * driver enqueued frames -+ */ -+ uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ -+ uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ -+ uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not -+ * data/control/management -+ */ -+ uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ -+ uint32 rxbadplcp; /* parity check of the PLCP header failed */ -+ uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ -+ uint32 rxstrt; /* Number of received frames with a good PLCP -+ * (i.e. passing parity check) -+ */ -+ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ -+ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ -+ uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ -+ uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ -+ uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ -+ uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ -+ uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ -+ uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ -+ uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ -+ uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ -+ uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ -+ uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ -+ uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ -+ uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC -+ * (unlikely to see these) -+ */ -+ uint32 rxbeaconmbss; /* beacons received from member of BSS */ -+ uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from -+ * other BSS (WDS FRAME) -+ */ -+ uint32 rxbeaconobss; /* beacons received from other BSS */ -+ uint32 rxrsptmout; /* Number of response timeouts for transmitted frames -+ * expecting a response -+ */ -+ uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ -+ uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ -+ uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ -+ uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ -+ uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ -+ uint32 pmqovfl; /* Number of PMQ overflows */ -+ uint32 rxcgprqfrm; /* Number of received Probe requests that made it into -+ * the PRQ fifo -+ */ -+ uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ -+ uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did -+ * not get ACK -+ */ -+ uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ -+ uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ -+ * fifo because a probe response could not be sent out within -+ * the time limit defined in M_PRS_MAXTIME -+ */ -+ uint32 rxnack; /* obsolete */ -+ uint32 frmscons; /* obsolete */ -+ uint32 txnack; /* obsolete */ -+ uint32 txglitch_nack; /* obsolete */ -+ uint32 txburst; /* obsolete */ -+ -+ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ -+ uint32 txfrag; /* dot11TransmittedFragmentCount */ -+ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ -+ uint32 txfail; /* dot11FailedCount */ -+ uint32 txretry; /* dot11RetryCount */ -+ uint32 txretrie; /* dot11MultipleRetryCount */ -+ uint32 rxdup; /* dot11FrameduplicateCount */ -+ uint32 txrts; /* dot11RTSSuccessCount */ -+ uint32 txnocts; /* dot11RTSFailureCount */ -+ uint32 txnoack; /* dot11ACKFailureCount */ -+ uint32 rxfrag; /* dot11ReceivedFragmentCount */ -+ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ -+ uint32 rxcrc; /* dot11FCSErrorCount */ -+ uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ -+ uint32 rxundec; /* dot11WEPUndecryptableCount */ -+ -+ /* WPA2 counters (see rxundec for DecryptFailureCount) */ -+ uint32 tkipmicfaill; /* TKIPLocalMICFailures */ -+ uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ -+ uint32 tkipreplay; /* TKIPReplays */ -+ uint32 ccmpfmterr; /* CCMPFormatErrors */ -+ uint32 ccmpreplay; /* CCMPReplays */ -+ uint32 ccmpundec; /* CCMPDecryptErrors */ -+ uint32 fourwayfail; /* FourWayHandshakeFailures */ -+ uint32 wepundec; /* dot11WEPUndecryptableCount */ -+ uint32 wepicverr; /* dot11WEPICVErrorCount */ -+ uint32 decsuccess; /* DecryptSuccessCount */ -+ uint32 tkipicverr; /* TKIPICVErrorCount */ -+ uint32 wepexcluded; /* dot11WEPExcludedCount */ -+ -+ uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ -+ uint32 psmwds; /* Count PSM watchdogs */ -+ uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ -+ -+ /* MBSS counters, AP only */ -+ uint32 prq_entries_handled; /* PRQ entries read in */ -+ uint32 prq_undirected_entries; /* which were bcast bss & ssid */ -+ uint32 prq_bad_entries; /* which could not be translated to info */ -+ uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ -+ uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ -+ uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ -+ uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ -+ -+ /* per-rate receive stat counters */ -+ uint32 rx1mbps; /* packets rx at 1Mbps */ -+ uint32 rx2mbps; /* packets rx at 2Mbps */ -+ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ -+ uint32 rx6mbps; /* packets rx at 6Mbps */ -+ uint32 rx9mbps; /* packets rx at 9Mbps */ -+ uint32 rx11mbps; /* packets rx at 11Mbps */ -+ uint32 rx12mbps; /* packets rx at 12Mbps */ -+ uint32 rx18mbps; /* packets rx at 18Mbps */ -+ uint32 rx24mbps; /* packets rx at 24Mbps */ -+ uint32 rx36mbps; /* packets rx at 36Mbps */ -+ uint32 rx48mbps; /* packets rx at 48Mbps */ -+ uint32 rx54mbps; /* packets rx at 54Mbps */ -+ uint32 rx108mbps; /* packets rx at 108mbps */ -+ uint32 rx162mbps; /* packets rx at 162mbps */ -+ uint32 rx216mbps; /* packets rx at 216 mbps */ -+ uint32 rx270mbps; /* packets rx at 270 mbps */ -+ uint32 rx324mbps; /* packets rx at 324 mbps */ -+ uint32 rx378mbps; /* packets rx at 378 mbps */ -+ uint32 rx432mbps; /* packets rx at 432 mbps */ -+ uint32 rx486mbps; /* packets rx at 486 mbps */ -+ uint32 rx540mbps; /* packets rx at 540 mbps */ -+ -+ /* pkteng rx frame stats */ -+ uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ -+ uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ -+ -+ uint32 rfdisable; /* count of radio disables */ -+ uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ -+ -+ uint32 txexptime; /* Tx frames suppressed due to timer expiration */ -+ -+ uint32 txmpdu_sgi; /* count for sgi transmit */ -+ uint32 rxmpdu_sgi; /* count for sgi received */ -+ uint32 txmpdu_stbc; /* count for stbc transmit */ -+ uint32 rxmpdu_stbc; /* count for stbc received */ -+ -+ uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ -+ -+ /* WPA2 counters (see rxundec for DecryptFailureCount) */ -+ uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ -+ uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ -+ uint32 tkipreplay_mcst; /* TKIPReplays */ -+ uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ -+ uint32 ccmpreplay_mcst; /* CCMPReplays */ -+ uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ -+ uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ -+ uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ -+ uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ -+ uint32 decsuccess_mcst; /* DecryptSuccessCount */ -+ uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ -+ uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ -+ -+ uint32 dma_hang; /* count for dma hang */ -+ uint32 reinit; /* count for reinit */ -+ -+ uint32 pstatxucast; /* count of ucast frames xmitted on all psta assoc */ -+ uint32 pstatxnoassoc; /* count of txnoassoc frames xmitted on all psta assoc */ -+ uint32 pstarxucast; /* count of ucast frames received on all psta assoc */ -+ uint32 pstarxbcmc; /* count of bcmc frames received on all psta */ -+ uint32 pstatxbcmc; /* count of bcmc frames transmitted on all psta */ -+ -+ uint32 cso_passthrough; /* hw cso required but passthrough */ -+} wl_cnt_t; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+typedef struct { -+ uint16 version; /* see definition of WL_CNT_T_VERSION */ -+ uint16 length; /* length of entire structure */ -+ -+ /* transmit stat counters */ -+ uint32 txframe; /* tx data frames */ -+ uint32 txbyte; /* tx data bytes */ -+ uint32 txretrans; /* tx mac retransmits */ -+ uint32 txerror; /* tx data errors (derived: sum of others) */ -+ uint32 txctl; /* tx management frames */ -+ uint32 txprshort; /* tx short preamble frames */ -+ uint32 txserr; /* tx status errors */ -+ uint32 txnobuf; /* tx out of buffers errors */ -+ uint32 txnoassoc; /* tx discard because we're not associated */ -+ uint32 txrunt; /* tx runt frames */ -+ uint32 txchit; /* tx header cache hit (fastpath) */ -+ uint32 txcmiss; /* tx header cache miss (slowpath) */ -+ -+ /* transmit chip error counters */ -+ uint32 txuflo; /* tx fifo underflows */ -+ uint32 txphyerr; /* tx phy errors (indicated in tx status) */ -+ uint32 txphycrs; -+ -+ /* receive stat counters */ -+ uint32 rxframe; /* rx data frames */ -+ uint32 rxbyte; /* rx data bytes */ -+ uint32 rxerror; /* rx data errors (derived: sum of others) */ -+ uint32 rxctl; /* rx management frames */ -+ uint32 rxnobuf; /* rx out of buffers errors */ -+ uint32 rxnondata; /* rx non data frames in the data channel errors */ -+ uint32 rxbadds; /* rx bad DS errors */ -+ uint32 rxbadcm; /* rx bad control or management frames */ -+ uint32 rxfragerr; /* rx fragmentation errors */ -+ uint32 rxrunt; /* rx runt frames */ -+ uint32 rxgiant; /* rx giant frames */ -+ uint32 rxnoscb; /* rx no scb error */ -+ uint32 rxbadproto; /* rx invalid frames */ -+ uint32 rxbadsrcmac; /* rx frames with Invalid Src Mac */ -+ uint32 rxbadda; /* rx frames tossed for invalid da */ -+ uint32 rxfilter; /* rx frames filtered out */ -+ -+ /* receive chip error counters */ -+ uint32 rxoflo; /* rx fifo overflow errors */ -+ uint32 rxuflo[NFIFO]; /* rx dma descriptor underflow errors */ -+ -+ uint32 d11cnt_txrts_off; /* d11cnt txrts value when reset d11cnt */ -+ uint32 d11cnt_rxcrc_off; /* d11cnt rxcrc value when reset d11cnt */ -+ uint32 d11cnt_txnocts_off; /* d11cnt txnocts value when reset d11cnt */ -+ -+ /* misc counters */ -+ uint32 dmade; /* tx/rx dma descriptor errors */ -+ uint32 dmada; /* tx/rx dma data errors */ -+ uint32 dmape; /* tx/rx dma descriptor protocol errors */ -+ uint32 reset; /* reset count */ -+ uint32 tbtt; /* cnts the TBTT int's */ -+ uint32 txdmawar; -+ uint32 pkt_callback_reg_fail; /* callbacks register failure */ -+ -+ /* MAC counters: 32-bit version of d11.h's macstat_t */ -+ uint32 txallfrm; /* total number of frames sent, incl. Data, ACK, RTS, CTS, -+ * Control Management (includes retransmissions) -+ */ -+ uint32 txrtsfrm; /* number of RTS sent out by the MAC */ -+ uint32 txctsfrm; /* number of CTS sent out by the MAC */ -+ uint32 txackfrm; /* number of ACK frames sent out */ -+ uint32 txdnlfrm; /* Not used */ -+ uint32 txbcnfrm; /* beacons transmitted */ -+ uint32 txfunfl[8]; /* per-fifo tx underflows */ -+ uint32 txtplunfl; /* Template underflows (mac was too slow to transmit ACK/CTS -+ * or BCN) -+ */ -+ uint32 txphyerror; /* Transmit phy error, type of error is reported in tx-status for -+ * driver enqueued frames -+ */ -+ uint32 rxfrmtoolong; /* Received frame longer than legal limit (2346 bytes) */ -+ uint32 rxfrmtooshrt; /* Received frame did not contain enough bytes for its frame type */ -+ uint32 rxinvmachdr; /* Either the protocol version != 0 or frame type not -+ * data/control/management -+ */ -+ uint32 rxbadfcs; /* number of frames for which the CRC check failed in the MAC */ -+ uint32 rxbadplcp; /* parity check of the PLCP header failed */ -+ uint32 rxcrsglitch; /* PHY was able to correlate the preamble but not the header */ -+ uint32 rxstrt; /* Number of received frames with a good PLCP -+ * (i.e. passing parity check) -+ */ -+ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ -+ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ -+ uint32 rxcfrmucast; /* number of received CNTRL frames with good FCS and matching RA */ -+ uint32 rxrtsucast; /* number of unicast RTS addressed to the MAC (good FCS) */ -+ uint32 rxctsucast; /* number of unicast CTS addressed to the MAC (good FCS) */ -+ uint32 rxackucast; /* number of ucast ACKS received (good FCS) */ -+ uint32 rxdfrmocast; /* number of received DATA frames (good FCS and not matching RA) */ -+ uint32 rxmfrmocast; /* number of received MGMT frames (good FCS and not matching RA) */ -+ uint32 rxcfrmocast; /* number of received CNTRL frame (good FCS and not matching RA) */ -+ uint32 rxrtsocast; /* number of received RTS not addressed to the MAC */ -+ uint32 rxctsocast; /* number of received CTS not addressed to the MAC */ -+ uint32 rxdfrmmcast; /* number of RX Data multicast frames received by the MAC */ -+ uint32 rxmfrmmcast; /* number of RX Management multicast frames received by the MAC */ -+ uint32 rxcfrmmcast; /* number of RX Control multicast frames received by the MAC -+ * (unlikely to see these) -+ */ -+ uint32 rxbeaconmbss; /* beacons received from member of BSS */ -+ uint32 rxdfrmucastobss; /* number of unicast frames addressed to the MAC from -+ * other BSS (WDS FRAME) -+ */ -+ uint32 rxbeaconobss; /* beacons received from other BSS */ -+ uint32 rxrsptmout; /* Number of response timeouts for transmitted frames -+ * expecting a response -+ */ -+ uint32 bcntxcancl; /* transmit beacons canceled due to receipt of beacon (IBSS) */ -+ uint32 rxf0ovfl; /* Number of receive fifo 0 overflows */ -+ uint32 rxf1ovfl; /* Number of receive fifo 1 overflows (obsolete) */ -+ uint32 rxf2ovfl; /* Number of receive fifo 2 overflows (obsolete) */ -+ uint32 txsfovfl; /* Number of transmit status fifo overflows (obsolete) */ -+ uint32 pmqovfl; /* Number of PMQ overflows */ -+ uint32 rxcgprqfrm; /* Number of received Probe requests that made it into -+ * the PRQ fifo -+ */ -+ uint32 rxcgprsqovfl; /* Rx Probe Request Que overflow in the AP */ -+ uint32 txcgprsfail; /* Tx Probe Response Fail. AP sent probe response but did -+ * not get ACK -+ */ -+ uint32 txcgprssuc; /* Tx Probe Response Success (ACK was received) */ -+ uint32 prs_timeout; /* Number of probe requests that were dropped from the PRQ -+ * fifo because a probe response could not be sent out within -+ * the time limit defined in M_PRS_MAXTIME -+ */ -+ uint32 rxnack; -+ uint32 frmscons; -+ uint32 txnack; -+ uint32 txglitch_nack; /* obsolete */ -+ uint32 txburst; /* obsolete */ -+ -+ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ -+ uint32 txfrag; /* dot11TransmittedFragmentCount */ -+ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ -+ uint32 txfail; /* dot11FailedCount */ -+ uint32 txretry; /* dot11RetryCount */ -+ uint32 txretrie; /* dot11MultipleRetryCount */ -+ uint32 rxdup; /* dot11FrameduplicateCount */ -+ uint32 txrts; /* dot11RTSSuccessCount */ -+ uint32 txnocts; /* dot11RTSFailureCount */ -+ uint32 txnoack; /* dot11ACKFailureCount */ -+ uint32 rxfrag; /* dot11ReceivedFragmentCount */ -+ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ -+ uint32 rxcrc; /* dot11FCSErrorCount */ -+ uint32 txfrmsnt; /* dot11TransmittedFrameCount (bogus MIB?) */ -+ uint32 rxundec; /* dot11WEPUndecryptableCount */ -+ -+ /* WPA2 counters (see rxundec for DecryptFailureCount) */ -+ uint32 tkipmicfaill; /* TKIPLocalMICFailures */ -+ uint32 tkipcntrmsr; /* TKIPCounterMeasuresInvoked */ -+ uint32 tkipreplay; /* TKIPReplays */ -+ uint32 ccmpfmterr; /* CCMPFormatErrors */ -+ uint32 ccmpreplay; /* CCMPReplays */ -+ uint32 ccmpundec; /* CCMPDecryptErrors */ -+ uint32 fourwayfail; /* FourWayHandshakeFailures */ -+ uint32 wepundec; /* dot11WEPUndecryptableCount */ -+ uint32 wepicverr; /* dot11WEPICVErrorCount */ -+ uint32 decsuccess; /* DecryptSuccessCount */ -+ uint32 tkipicverr; /* TKIPICVErrorCount */ -+ uint32 wepexcluded; /* dot11WEPExcludedCount */ -+ -+ uint32 rxundec_mcst; /* dot11WEPUndecryptableCount */ -+ -+ /* WPA2 counters (see rxundec for DecryptFailureCount) */ -+ uint32 tkipmicfaill_mcst; /* TKIPLocalMICFailures */ -+ uint32 tkipcntrmsr_mcst; /* TKIPCounterMeasuresInvoked */ -+ uint32 tkipreplay_mcst; /* TKIPReplays */ -+ uint32 ccmpfmterr_mcst; /* CCMPFormatErrors */ -+ uint32 ccmpreplay_mcst; /* CCMPReplays */ -+ uint32 ccmpundec_mcst; /* CCMPDecryptErrors */ -+ uint32 fourwayfail_mcst; /* FourWayHandshakeFailures */ -+ uint32 wepundec_mcst; /* dot11WEPUndecryptableCount */ -+ uint32 wepicverr_mcst; /* dot11WEPICVErrorCount */ -+ uint32 decsuccess_mcst; /* DecryptSuccessCount */ -+ uint32 tkipicverr_mcst; /* TKIPICVErrorCount */ -+ uint32 wepexcluded_mcst; /* dot11WEPExcludedCount */ -+ -+ uint32 txchanrej; /* Tx frames suppressed due to channel rejection */ -+ uint32 txexptime; /* Tx frames suppressed due to timer expiration */ -+ uint32 psmwds; /* Count PSM watchdogs */ -+ uint32 phywatchdog; /* Count Phy watchdogs (triggered by ucode) */ -+ -+ /* MBSS counters, AP only */ -+ uint32 prq_entries_handled; /* PRQ entries read in */ -+ uint32 prq_undirected_entries; /* which were bcast bss & ssid */ -+ uint32 prq_bad_entries; /* which could not be translated to info */ -+ uint32 atim_suppress_count; /* TX suppressions on ATIM fifo */ -+ uint32 bcn_template_not_ready; /* Template marked in use on send bcn ... */ -+ uint32 bcn_template_not_ready_done; /* ...but "DMA done" interrupt rcvd */ -+ uint32 late_tbtt_dpc; /* TBTT DPC did not happen in time */ -+ -+ /* per-rate receive stat counters */ -+ uint32 rx1mbps; /* packets rx at 1Mbps */ -+ uint32 rx2mbps; /* packets rx at 2Mbps */ -+ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ -+ uint32 rx6mbps; /* packets rx at 6Mbps */ -+ uint32 rx9mbps; /* packets rx at 9Mbps */ -+ uint32 rx11mbps; /* packets rx at 11Mbps */ -+ uint32 rx12mbps; /* packets rx at 12Mbps */ -+ uint32 rx18mbps; /* packets rx at 18Mbps */ -+ uint32 rx24mbps; /* packets rx at 24Mbps */ -+ uint32 rx36mbps; /* packets rx at 36Mbps */ -+ uint32 rx48mbps; /* packets rx at 48Mbps */ -+ uint32 rx54mbps; /* packets rx at 54Mbps */ -+ uint32 rx108mbps; /* packets rx at 108mbps */ -+ uint32 rx162mbps; /* packets rx at 162mbps */ -+ uint32 rx216mbps; /* packets rx at 216 mbps */ -+ uint32 rx270mbps; /* packets rx at 270 mbps */ -+ uint32 rx324mbps; /* packets rx at 324 mbps */ -+ uint32 rx378mbps; /* packets rx at 378 mbps */ -+ uint32 rx432mbps; /* packets rx at 432 mbps */ -+ uint32 rx486mbps; /* packets rx at 486 mbps */ -+ uint32 rx540mbps; /* packets rx at 540 mbps */ -+ -+ /* pkteng rx frame stats */ -+ uint32 pktengrxducast; /* unicast frames rxed by the pkteng code */ -+ uint32 pktengrxdmcast; /* multicast frames rxed by the pkteng code */ -+ -+ uint32 rfdisable; /* count of radio disables */ -+ uint32 bphy_rxcrsglitch; /* PHY count of bphy glitches */ -+ -+ uint32 txmpdu_sgi; /* count for sgi transmit */ -+ uint32 rxmpdu_sgi; /* count for sgi received */ -+ uint32 txmpdu_stbc; /* count for stbc transmit */ -+ uint32 rxmpdu_stbc; /* count for stbc received */ -+} wl_cnt_ver_six_t; -+ -+#define WL_DELTA_STATS_T_VERSION 1 /* current version of wl_delta_stats_t struct */ -+ -+typedef struct { -+ uint16 version; /* see definition of WL_DELTA_STATS_T_VERSION */ -+ uint16 length; /* length of entire structure */ -+ -+ /* transmit stat counters */ -+ uint32 txframe; /* tx data frames */ -+ uint32 txbyte; /* tx data bytes */ -+ uint32 txretrans; /* tx mac retransmits */ -+ uint32 txfail; /* tx failures */ -+ -+ /* receive stat counters */ -+ uint32 rxframe; /* rx data frames */ -+ uint32 rxbyte; /* rx data bytes */ -+ -+ /* per-rate receive stat counters */ -+ uint32 rx1mbps; /* packets rx at 1Mbps */ -+ uint32 rx2mbps; /* packets rx at 2Mbps */ -+ uint32 rx5mbps5; /* packets rx at 5.5Mbps */ -+ uint32 rx6mbps; /* packets rx at 6Mbps */ -+ uint32 rx9mbps; /* packets rx at 9Mbps */ -+ uint32 rx11mbps; /* packets rx at 11Mbps */ -+ uint32 rx12mbps; /* packets rx at 12Mbps */ -+ uint32 rx18mbps; /* packets rx at 18Mbps */ -+ uint32 rx24mbps; /* packets rx at 24Mbps */ -+ uint32 rx36mbps; /* packets rx at 36Mbps */ -+ uint32 rx48mbps; /* packets rx at 48Mbps */ -+ uint32 rx54mbps; /* packets rx at 54Mbps */ -+ uint32 rx108mbps; /* packets rx at 108mbps */ -+ uint32 rx162mbps; /* packets rx at 162mbps */ -+ uint32 rx216mbps; /* packets rx at 216 mbps */ -+ uint32 rx270mbps; /* packets rx at 270 mbps */ -+ uint32 rx324mbps; /* packets rx at 324 mbps */ -+ uint32 rx378mbps; /* packets rx at 378 mbps */ -+ uint32 rx432mbps; /* packets rx at 432 mbps */ -+ uint32 rx486mbps; /* packets rx at 486 mbps */ -+ uint32 rx540mbps; /* packets rx at 540 mbps */ -+} wl_delta_stats_t; -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ -+ -+typedef struct { -+ uint32 packets; -+ uint32 bytes; -+} wl_traffic_stats_t; -+ -+typedef struct { -+ uint16 version; /* see definition of WL_WME_CNT_VERSION */ -+ uint16 length; /* length of entire structure */ -+ -+ wl_traffic_stats_t tx[AC_COUNT]; /* Packets transmitted */ -+ wl_traffic_stats_t tx_failed[AC_COUNT]; /* Packets dropped or failed to transmit */ -+ wl_traffic_stats_t rx[AC_COUNT]; /* Packets received */ -+ wl_traffic_stats_t rx_failed[AC_COUNT]; /* Packets failed to receive */ -+ -+ wl_traffic_stats_t forward[AC_COUNT]; /* Packets forwarded by AP */ -+ -+ wl_traffic_stats_t tx_expired[AC_COUNT]; /* packets dropped due to lifetime expiry */ -+ -+} wl_wme_cnt_t; -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+struct wl_msglevel2 { -+ uint32 low; -+ uint32 high; -+}; -+ -+typedef struct wl_mkeep_alive_pkt { -+ uint16 version; /* Version for mkeep_alive */ -+ uint16 length; /* length of fixed parameters in the structure */ -+ uint32 period_msec; -+ uint16 len_bytes; -+ uint8 keep_alive_id; /* 0 - 3 for N = 4 */ -+ uint8 data[1]; -+} wl_mkeep_alive_pkt_t; -+ -+#define WL_MKEEP_ALIVE_VERSION 1 -+#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) -+#define WL_MKEEP_ALIVE_PRECISION 500 -+ -+#ifdef WLBA -+ -+#define WLC_BA_CNT_VERSION 1 /* current version of wlc_ba_cnt_t */ -+ -+/* block ack related stats */ -+typedef struct wlc_ba_cnt { -+ uint16 version; /* WLC_BA_CNT_VERSION */ -+ uint16 length; /* length of entire structure */ -+ -+ /* transmit stat counters */ -+ uint32 txpdu; /* pdus sent */ -+ uint32 txsdu; /* sdus sent */ -+ uint32 txfc; /* tx side flow controlled packets */ -+ uint32 txfci; /* tx side flow control initiated */ -+ uint32 txretrans; /* retransmitted pdus */ -+ uint32 txbatimer; /* ba resend due to timer */ -+ uint32 txdrop; /* dropped packets */ -+ uint32 txaddbareq; /* addba req sent */ -+ uint32 txaddbaresp; /* addba resp sent */ -+ uint32 txdelba; /* delba sent */ -+ uint32 txba; /* ba sent */ -+ uint32 txbar; /* bar sent */ -+ uint32 txpad[4]; /* future */ -+ -+ /* receive side counters */ -+ uint32 rxpdu; /* pdus recd */ -+ uint32 rxqed; /* pdus buffered before sending up */ -+ uint32 rxdup; /* duplicate pdus */ -+ uint32 rxnobuf; /* pdus discarded due to no buf */ -+ uint32 rxaddbareq; /* addba req recd */ -+ uint32 rxaddbaresp; /* addba resp recd */ -+ uint32 rxdelba; /* delba recd */ -+ uint32 rxba; /* ba recd */ -+ uint32 rxbar; /* bar recd */ -+ uint32 rxinvba; /* invalid ba recd */ -+ uint32 rxbaholes; /* ba recd with holes */ -+ uint32 rxunexp; /* unexpected packets */ -+ uint32 rxpad[4]; /* future */ -+} wlc_ba_cnt_t; -+#endif /* WLBA */ -+ -+/* structure for per-tid ampdu control */ -+struct ampdu_tid_control { -+ uint8 tid; /* tid */ -+ uint8 enable; /* enable/disable */ -+}; -+ -+/* structure for identifying ea/tid for sending addba/delba */ -+struct ampdu_ea_tid { -+ struct ether_addr ea; /* Station address */ -+ uint8 tid; /* tid */ -+}; -+/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ -+struct ampdu_retry_tid { -+ uint8 tid; /* tid */ -+ uint8 retry; /* retry value */ -+}; -+ -+/* Different discovery modes for dpt */ -+#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ -+#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ -+#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ -+ -+/* different path selection values */ -+#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ -+#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ -+#define DPT_PATHSEL_APPATH 2 /* always use AP path */ -+ -+/* different ops for deny list */ -+#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ -+#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ -+ -+/* different ops for manual end point */ -+#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ -+#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ -+#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ -+ -+/* structure for dpt iovars */ -+typedef struct dpt_iovar { -+ struct ether_addr ea; /* Station address */ -+ uint8 mode; /* mode: depends on iovar */ -+ uint32 pad; /* future */ -+} dpt_iovar_t; -+ -+/* flags to indicate DPT status */ -+#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ -+#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ -+#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ -+ -+#define DPT_FNAME_LEN 48 /* Max length of friendly name */ -+ -+typedef struct dpt_status { -+ uint8 status; /* flags to indicate status */ -+ uint8 fnlen; /* length of friendly name */ -+ uchar name[DPT_FNAME_LEN]; /* friendly name */ -+ uint32 rssi; /* RSSI of the link */ -+ sta_info_t sta; /* sta info */ -+} dpt_status_t; -+ -+/* structure for dpt list */ -+typedef struct dpt_list { -+ uint32 num; /* number of entries in struct */ -+ dpt_status_t status[1]; /* per station info */ -+} dpt_list_t; -+ -+/* structure for dpt friendly name */ -+typedef struct dpt_fname { -+ uint8 len; /* length of friendly name */ -+ uchar name[DPT_FNAME_LEN]; /* friendly name */ -+} dpt_fname_t; -+ -+#define BDD_FNAME_LEN 32 /* Max length of friendly name */ -+typedef struct bdd_fname { -+ uint8 len; /* length of friendly name */ -+ uchar name[BDD_FNAME_LEN]; /* friendly name */ -+} bdd_fname_t; -+ -+/* structure for addts arguments */ -+/* For ioctls that take a list of TSPEC */ -+struct tslist { -+ int count; /* number of tspecs */ -+ struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */ -+}; -+ -+#ifdef WLTDLS -+/* different ops for manual end point */ -+#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ -+#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ -+#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ -+#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ -+#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ -+#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ -+#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ -+ -+/* structure for tdls iovars */ -+typedef struct tdls_iovar { -+ struct ether_addr ea; /* Station address */ -+ uint8 mode; /* mode: depends on iovar */ -+ chanspec_t chanspec; -+ uint32 pad; /* future */ -+} tdls_iovar_t; -+ -+/* modes */ -+#define TDLS_WFD_IE_TX 0 -+#define TDLS_WFD_IE_RX 1 -+#define TDLS_WFD_IE_SIZE 255 -+/* structure for tdls wfd ie */ -+typedef struct tdls_wfd_ie_iovar { -+ struct ether_addr ea; /* Station address */ -+ uint8 mode; -+ uint8 length; -+ uint8 data[TDLS_WFD_IE_SIZE]; -+} tdls_wfd_ie_iovar_t; -+#endif /* WLTDLS */ -+ -+/* structure for addts/delts arguments */ -+typedef struct tspec_arg { -+ uint16 version; /* see definition of TSPEC_ARG_VERSION */ -+ uint16 length; /* length of entire structure */ -+ uint flag; /* bit field */ -+ /* TSPEC Arguments */ -+ struct tsinfo_arg tsinfo; /* TS Info bit field */ -+ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ -+ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ -+ uint min_srv_interval; /* Minimum Service Interval (us) */ -+ uint max_srv_interval; /* Maximum Service Interval (us) */ -+ uint inactivity_interval; /* Inactivity Interval (us) */ -+ uint suspension_interval; /* Suspension Interval (us) */ -+ uint srv_start_time; /* Service Start Time (us) */ -+ uint min_data_rate; /* Minimum Data Rate (bps) */ -+ uint mean_data_rate; /* Mean Data Rate (bps) */ -+ uint peak_data_rate; /* Peak Data Rate (bps) */ -+ uint max_burst_size; /* Maximum Burst Size (bytes) */ -+ uint delay_bound; /* Delay Bound (us) */ -+ uint min_phy_rate; /* Minimum PHY Rate (bps) */ -+ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */ -+ uint16 medium_time; /* Medium Time (32 us/s periods) */ -+ uint8 dialog_token; /* dialog token */ -+} tspec_arg_t; -+ -+/* tspec arg for desired station */ -+typedef struct tspec_per_sta_arg { -+ struct ether_addr ea; -+ struct tspec_arg ts; -+} tspec_per_sta_arg_t; -+ -+/* structure for max bandwidth for each access category */ -+typedef struct wme_max_bandwidth { -+ uint32 ac[AC_COUNT]; /* max bandwidth for each access category */ -+} wme_max_bandwidth_t; -+ -+#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) -+ -+/* current version of wl_tspec_arg_t struct */ -+#define TSPEC_ARG_VERSION 2 /* current version of wl_tspec_arg_t struct */ -+#define TSPEC_ARG_LENGTH 55 /* argument length from tsinfo to medium_time */ -+#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /* default dialog token */ -+#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /* default surplus bw */ -+ -+ -+#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 -+#define WLC_WOWL_MAX_KEEPALIVE 2 -+ -+/* define for flag */ -+#define TSPEC_PENDING 0 /* TSPEC pending */ -+#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ -+#define TSPEC_REJECTED 2 /* TSPEC rejected */ -+#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ -+#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ -+ -+ -+/* Software feature flag defines used by wlfeatureflag */ -+#ifdef WLAFTERBURNER -+#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ -+#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ -+#endif /* WLAFTERBURNER */ -+#define WL_SWFL_NOHWRADIO 0x0004 -+#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */ -+#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */ -+ -+#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ -+ -+/* Packet lifetime configuration per ac */ -+typedef struct wl_lifetime { -+ uint32 ac; /* access class */ -+ uint32 lifetime; /* Packet lifetime value in ms */ -+} wl_lifetime_t; -+ -+/* Channel Switch Announcement param */ -+typedef struct wl_chan_switch { -+ uint8 mode; /* value 0 or 1 */ -+ uint8 count; /* count # of beacons before switching */ -+ chanspec_t chspec; /* chanspec */ -+ uint8 reg; /* regulatory class */ -+} wl_chan_switch_t; -+ -+/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. -+ * -+ * (-100 < value < 0) value is used directly as a roaming trigger in dBm -+ * (0 <= value) value specifies a logical roaming trigger level from -+ * the list below -+ * -+ * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never -+ * the logical roam trigger value. -+ */ -+#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ -+#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ -+#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ -+#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ -+#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ -+ -+#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ -+ -+/* Preferred Network Offload (PNO, formerly PFN) defines */ -+#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ -+ -+enum { -+ PFN_LIST_ORDER, -+ PFN_RSSI -+}; -+ -+enum { -+ DISABLE, -+ ENABLE -+}; -+ -+enum { -+ OFF_ADAPT, -+ SMART_ADAPT, -+ STRICT_ADAPT, -+ SLOW_ADAPT -+}; -+ -+#define SORT_CRITERIA_BIT 0 -+#define AUTO_NET_SWITCH_BIT 1 -+#define ENABLE_BKGRD_SCAN_BIT 2 -+#define IMMEDIATE_SCAN_BIT 3 -+#define AUTO_CONNECT_BIT 4 -+#define ENABLE_BD_SCAN_BIT 5 -+#define ENABLE_ADAPTSCAN_BIT 6 -+#define IMMEDIATE_EVENT_BIT 8 -+#define SUPPRESS_SSID_BIT 9 -+#define ENABLE_NET_OFFLOAD_BIT 10 -+ -+#define SORT_CRITERIA_MASK 0x0001 -+#define AUTO_NET_SWITCH_MASK 0x0002 -+#define ENABLE_BKGRD_SCAN_MASK 0x0004 -+#define IMMEDIATE_SCAN_MASK 0x0008 -+#define AUTO_CONNECT_MASK 0x0010 -+ -+#define ENABLE_BD_SCAN_MASK 0x0020 -+#define ENABLE_ADAPTSCAN_MASK 0x00c0 -+#define IMMEDIATE_EVENT_MASK 0x0100 -+#define SUPPRESS_SSID_MASK 0x0200 -+#define ENABLE_NET_OFFLOAD_MASK 0x0400 -+ -+#define PFN_VERSION 2 -+#define PFN_SCANRESULT_VERSION 1 -+#define MAX_PFN_LIST_COUNT 16 -+ -+#define PFN_COMPLETE 1 -+#define PFN_INCOMPLETE 0 -+ -+#define DEFAULT_BESTN 2 -+#define DEFAULT_MSCAN 0 -+#define DEFAULT_REPEAT 10 -+#define DEFAULT_EXP 2 -+ -+/* PFN network info structure */ -+typedef struct wl_pfn_subnet_info { -+ struct ether_addr BSSID; -+ uint8 channel; /* channel number only */ -+ uint8 SSID_len; -+ uint8 SSID[32]; -+} wl_pfn_subnet_info_t; -+ -+typedef struct wl_pfn_net_info { -+ wl_pfn_subnet_info_t pfnsubnet; -+ int16 RSSI; /* receive signal strength (in dBm) */ -+ uint16 timestamp; /* age in seconds */ -+} wl_pfn_net_info_t; -+ -+typedef struct wl_pfn_scanresults { -+ uint32 version; -+ uint32 status; -+ uint32 count; -+ wl_pfn_net_info_t netinfo[1]; -+} wl_pfn_scanresults_t; -+ -+/* PFN data structure */ -+typedef struct wl_pfn_param { -+ int32 version; /* PNO parameters version */ -+ int32 scan_freq; /* Scan frequency */ -+ int32 lost_network_timeout; /* Timeout in sec. to declare -+ * discovered network as lost -+ */ -+ int16 flags; /* Bit field to control features -+ * of PFN such as sort criteria auto -+ * enable switch and background scan -+ */ -+ int16 rssi_margin; /* Margin to avoid jitter for choosing a -+ * PFN based on RSSI sort criteria -+ */ -+ uint8 bestn; /* number of best networks in each scan */ -+ uint8 mscan; /* number of scans recorded */ -+ uint8 repeat; /* Minimum number of scan intervals -+ *before scan frequency changes in adaptive scan -+ */ -+ uint8 exp; /* Exponent of 2 for maximum scan interval */ -+ int32 slow_freq; /* slow scan period */ -+} wl_pfn_param_t; -+ -+typedef struct wl_pfn_bssid { -+ struct ether_addr macaddr; -+ /* Bit4: suppress_lost, Bit3: suppress_found */ -+ uint16 flags; -+} wl_pfn_bssid_t; -+#define WL_PFN_SUPPRESSFOUND_MASK 0x08 -+#define WL_PFN_SUPPRESSLOST_MASK 0x10 -+ -+typedef struct wl_pfn_cfg { -+ uint32 reporttype; -+ int32 channel_num; -+ uint16 channel_list[WL_NUMCHANNELS]; -+} wl_pfn_cfg_t; -+#define WL_PFN_REPORT_ALLNET 0 -+#define WL_PFN_REPORT_SSIDNET 1 -+#define WL_PFN_REPORT_BSSIDNET 2 -+ -+typedef struct wl_pfn { -+ wlc_ssid_t ssid; /* ssid name and its length */ -+ int32 flags; /* bit2: hidden */ -+ int32 infra; /* BSS Vs IBSS */ -+ int32 auth; /* Open Vs Closed */ -+ int32 wpa_auth; /* WPA type */ -+ int32 wsec; /* wsec value */ -+} wl_pfn_t; -+#define WL_PFN_HIDDEN_BIT 2 -+#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ -+#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ -+#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ -+#define WL_PFN_HIDDEN_MASK 0x4 -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* TCP Checksum Offload defines */ -+#define TOE_TX_CSUM_OL 0x00000001 -+#define TOE_RX_CSUM_OL 0x00000002 -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+/* TCP Checksum Offload error injection for testing */ -+#define TOE_ERRTEST_TX_CSUM 0x00000001 -+#define TOE_ERRTEST_RX_CSUM 0x00000002 -+#define TOE_ERRTEST_RX_CSUM2 0x00000004 -+ -+struct toe_ol_stats_t { -+ /* Num of tx packets that don't need to be checksummed */ -+ uint32 tx_summed; -+ -+ /* Num of tx packets where checksum is filled by offload engine */ -+ uint32 tx_iph_fill; -+ uint32 tx_tcp_fill; -+ uint32 tx_udp_fill; -+ uint32 tx_icmp_fill; -+ -+ /* Num of rx packets where toe finds out if checksum is good or bad */ -+ uint32 rx_iph_good; -+ uint32 rx_iph_bad; -+ uint32 rx_tcp_good; -+ uint32 rx_tcp_bad; -+ uint32 rx_udp_good; -+ uint32 rx_udp_bad; -+ uint32 rx_icmp_good; -+ uint32 rx_icmp_bad; -+ -+ /* Num of tx packets in which csum error is injected */ -+ uint32 tx_tcp_errinj; -+ uint32 tx_udp_errinj; -+ uint32 tx_icmp_errinj; -+ -+ /* Num of rx packets in which csum error is injected */ -+ uint32 rx_tcp_errinj; -+ uint32 rx_udp_errinj; -+ uint32 rx_icmp_errinj; -+}; -+ -+/* ARP Offload feature flags for arp_ol iovar */ -+#define ARP_OL_AGENT 0x00000001 -+#define ARP_OL_SNOOP 0x00000002 -+#define ARP_OL_HOST_AUTO_REPLY 0x00000004 -+#define ARP_OL_PEER_AUTO_REPLY 0x00000008 -+ -+/* ARP Offload error injection */ -+#define ARP_ERRTEST_REPLY_PEER 0x1 -+#define ARP_ERRTEST_REPLY_HOST 0x2 -+ -+#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ -+#define ND_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ -+ -+/* Arp offload statistic counts */ -+struct arp_ol_stats_t { -+ uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ -+ uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ -+ -+ uint32 arp_table_entries; /* ARP table entries */ -+ uint32 arp_table_overflow; /* ARP table additions skipped due to overflow */ -+ -+ uint32 host_request; /* ARP requests from host */ -+ uint32 host_reply; /* ARP replies from host */ -+ uint32 host_service; /* ARP requests from host serviced by ARP Agent */ -+ -+ uint32 peer_request; /* ARP requests received from network */ -+ uint32 peer_request_drop; /* ARP requests from network that were dropped */ -+ uint32 peer_reply; /* ARP replies received from network */ -+ uint32 peer_reply_drop; /* ARP replies from network that were dropped */ -+ uint32 peer_service; /* ARP request from host serviced by ARP Agent */ -+}; -+ -+/* NS offload statistic counts */ -+struct nd_ol_stats_t { -+ uint32 host_ip_entries; /* Host IP table addresses (more than one if multihomed) */ -+ uint32 host_ip_overflow; /* Host IP table additions skipped due to overflow */ -+ uint32 peer_request; /* NS requests received from network */ -+ uint32 peer_request_drop; /* NS requests from network that were dropped */ -+ uint32 peer_reply_drop; /* NA replies from network that were dropped */ -+ uint32 peer_service; /* NS request from host serviced by firmware */ -+}; -+ -+/* -+ * Keep-alive packet offloading. -+ */ -+ -+/* NAT keep-alive packets format: specifies the re-transmission period, the packet -+ * length, and packet contents. -+ */ -+typedef struct wl_keep_alive_pkt { -+ uint32 period_msec; /* Retransmission period (0 to disable packet re-transmits) */ -+ uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ -+ uint8 data[1]; /* Variable length packet to transmit. Contents should include -+ * entire ethernet packet (enet header, IP header, UDP header, -+ * and UDP payload) in network byte order. -+ */ -+} wl_keep_alive_pkt_t; -+ -+#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) -+ -+/* -+ * Dongle pattern matching filter. -+ */ -+ -+/* Packet filter types. Currently, only pattern matching is supported. */ -+typedef enum wl_pkt_filter_type { -+ WL_PKT_FILTER_TYPE_PATTERN_MATCH /* Pattern matching filter */ -+} wl_pkt_filter_type_t; -+ -+#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t -+ -+/* Pattern matching filter. Specifies an offset within received packets to -+ * start matching, the pattern to match, the size of the pattern, and a bitmask -+ * that indicates which bits within the pattern should be matched. -+ */ -+typedef struct wl_pkt_filter_pattern { -+ uint32 offset; /* Offset within received packet to start pattern matching. -+ * Offset '0' is the first byte of the ethernet header. -+ */ -+ uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ -+ uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts -+ * at offset 0. Pattern immediately follows mask. -+ */ -+} wl_pkt_filter_pattern_t; -+ -+/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ -+typedef struct wl_pkt_filter { -+ uint32 id; /* Unique filter id, specified by app. */ -+ uint32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ -+ uint32 negate_match; /* Negate the result of filter matches */ -+ union { /* Filter definitions */ -+ wl_pkt_filter_pattern_t pattern; /* Pattern matching filter */ -+ } u; -+} wl_pkt_filter_t; -+ -+#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) -+#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) -+ -+/* IOVAR "pkt_filter_enable" parameter. */ -+typedef struct wl_pkt_filter_enable { -+ uint32 id; /* Unique filter id */ -+ uint32 enable; /* Enable/disable bool */ -+} wl_pkt_filter_enable_t; -+ -+/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ -+typedef struct wl_pkt_filter_list { -+ uint32 num; /* Number of installed packet filters */ -+ wl_pkt_filter_t filter[1]; /* Variable array of packet filters. */ -+} wl_pkt_filter_list_t; -+ -+#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) -+ -+/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ -+typedef struct wl_pkt_filter_stats { -+ uint32 num_pkts_matched; /* # filter matches for specified filter id */ -+ uint32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */ -+ uint32 num_pkts_discarded; /* # packets discarded by dongle for all filters */ -+} wl_pkt_filter_stats_t; -+ -+/* Sequential Commands ioctl */ -+typedef struct wl_seq_cmd_ioctl { -+ uint32 cmd; /* common ioctl definition */ -+ uint32 len; /* length of user buffer */ -+} wl_seq_cmd_ioctl_t; -+ -+#define WL_SEQ_CMD_ALIGN_BYTES 4 -+ -+/* These are the set of get IOCTLs that should be allowed when using -+ * IOCTL sequence commands. These are issued implicitly by wl.exe each time -+ * it is invoked. We never want to buffer these, or else wl.exe will stop working. -+ */ -+#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ -+ (((cmd) == WLC_GET_MAGIC) || \ -+ ((cmd) == WLC_GET_VERSION) || \ -+ ((cmd) == WLC_GET_AP) || \ -+ ((cmd) == WLC_GET_INSTANCE)) -+ -+/* -+ * Packet engine interface -+ */ -+ -+#define WL_PKTENG_PER_TX_START 0x01 -+#define WL_PKTENG_PER_TX_STOP 0x02 -+#define WL_PKTENG_PER_RX_START 0x04 -+#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 -+#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 -+#define WL_PKTENG_PER_RX_STOP 0x08 -+#define WL_PKTENG_PER_MASK 0xff -+ -+#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ -+ -+typedef struct wl_pkteng { -+ uint32 flags; -+ uint32 delay; /* Inter-packet delay */ -+ uint32 nframes; /* Number of frames */ -+ uint32 length; /* Packet length */ -+ uint8 seqno; /* Enable/disable sequence no. */ -+ struct ether_addr dest; /* Destination address */ -+ struct ether_addr src; /* Source address */ -+} wl_pkteng_t; -+ -+#define NUM_80211b_RATES 4 -+#define NUM_80211ag_RATES 8 -+#define NUM_80211n_RATES 32 -+#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) -+typedef struct wl_pkteng_stats { -+ uint32 lostfrmcnt; /* RX PER test: no of frames lost (skip seqno) */ -+ int32 rssi; /* RSSI */ -+ int32 snr; /* signal to noise ratio */ -+ uint16 rxpktcnt[NUM_80211_RATES+1]; -+} wl_pkteng_stats_t; -+ -+ -+#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ -+#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ -+#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ -+#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ -+#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ -+#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ -+#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ -+#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ -+#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ -+#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ -+#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ -+#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ -+#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ -+#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ -+#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ -+#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ -+ -+#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ -+ -+#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ -+#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ -+ -+typedef struct { -+ uint32 masksize; /* Size of the mask in #of bytes */ -+ uint32 offset; /* Offset to start looking for the packet in # of bytes */ -+ uint32 patternoffset; /* Offset of start of pattern in the structure */ -+ uint32 patternsize; /* Size of the pattern itself in #of bytes */ -+ uint32 id; /* id */ -+ uint32 reasonsize; /* Size of the wakeup reason code */ -+ uint32 flags; /* Flags to tell the pattern type and other properties */ -+ /* Mask follows the structure above */ -+ /* Pattern follows the mask is at 'patternoffset' from the start */ -+} wl_wowl_pattern_t; -+ -+typedef struct { -+ uint count; -+ wl_wowl_pattern_t pattern[1]; -+} wl_wowl_pattern_list_t; -+ -+typedef struct { -+ uint8 pci_wakeind; /* Whether PCI PMECSR PMEStatus bit was set */ -+ uint16 ucode_wakeind; /* What wakeup-event indication was set by ucode */ -+} wl_wowl_wakeind_t; -+ -+ -+/* per AC rate control related data structure */ -+typedef struct wl_txrate_class { -+ uint8 init_rate; -+ uint8 min_rate; -+ uint8 max_rate; -+} wl_txrate_class_t; -+ -+ -+ -+/* Overlap BSS Scan parameters default, minimum, maximum */ -+#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ -+#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ -+#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ -+#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ -+#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ -+#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ -+#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ -+#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ -+#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ -+#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 -+#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 -+#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 -+#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ -+#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ -+#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ -+#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ -+#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ -+#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ -+#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ -+#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ -+#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ -+ -+/* structure for Overlap BSS scan arguments */ -+typedef struct wl_obss_scan_arg { -+ int16 passive_dwell; -+ int16 active_dwell; -+ int16 bss_widthscan_interval; -+ int16 passive_total; -+ int16 active_total; -+ int16 chanwidth_transition_delay; -+ int16 activity_threshold; -+} wl_obss_scan_arg_t; -+ -+#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) -+#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ -+ -+#define WL_COEX_INFO_MASK 0x07 -+#define WL_COEX_INFO_REQ 0x01 -+#define WL_COEX_40MHZ_INTOLERANT 0x02 -+#define WL_COEX_WIDTH20 0x04 -+ -+#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ -+ -+#define MAX_RSSI_LEVELS 8 -+ -+/* RSSI event notification configuration. */ -+typedef struct wl_rssi_event { -+ uint32 rate_limit_msec; /* # of events posted to application will be limited to -+ * one per specified period (0 to disable rate limit). -+ */ -+ uint8 num_rssi_levels; /* Number of entries in rssi_levels[] below */ -+ int8 rssi_levels[MAX_RSSI_LEVELS]; /* Variable number of RSSI levels. An event -+ * will be posted each time the RSSI of received -+ * beacons/packets crosses a level. -+ */ -+} wl_rssi_event_t; -+ -+typedef struct wl_action_obss_coex_req { -+ uint8 info; -+ uint8 num; -+ uint8 ch_list[1]; -+} wl_action_obss_coex_req_t; -+ -+ -+/* IOVar parameter block for small MAC address array with type indicator */ -+#define WL_IOV_MAC_PARAM_LEN 4 -+ -+#define WL_IOV_PKTQ_LOG_PRECS 16 -+ -+typedef struct { -+ uint32 num_addrs; -+ char addr_type[WL_IOV_MAC_PARAM_LEN]; -+ struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; -+} wl_iov_mac_params_t; -+ -+ -+/* Parameter block for PKTQ_LOG statistics */ -+typedef struct { -+ uint32 requested; /* packets requested to be stored */ -+ uint32 stored; /* packets stored */ -+ uint32 saved; /* packets saved, -+ because a lowest priority queue has given away one packet -+ */ -+ uint32 selfsaved; /* packets saved, -+ because an older packet from the same queue has been dropped -+ */ -+ uint32 full_dropped; /* packets dropped, -+ because pktq is full with higher precedence packets -+ */ -+ uint32 dropped; /* packets dropped because pktq per that precedence is full */ -+ uint32 sacrificed; /* packets dropped, -+ in order to save one from a queue of a highest priority -+ */ -+ uint32 busy; /* packets droped because of hardware/transmission error */ -+ uint32 retry; /* packets re-sent because they were not received */ -+ uint32 ps_retry; /* packets retried again prior to moving power save mode */ -+ uint32 retry_drop; /* packets finally dropped after retry limit */ -+ uint32 max_avail; /* the high-water mark of the queue capacity for packets - -+ goes to zero as queue fills -+ */ -+ uint32 max_used; /* the high-water mark of the queue utilisation for packets - -+ increases with use ('inverse' of max_avail) -+ */ -+ uint32 queue_capacity; /* the maximum capacity of the queue */ -+} pktq_log_counters_v01_t; -+ -+#define sacrified sacrificed -+ -+typedef struct { -+ uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; -+ pktq_log_counters_v01_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; -+ char headings[1]; -+} pktq_log_format_v01_t; -+ -+ -+typedef struct { -+ uint32 version; -+ wl_iov_mac_params_t params; -+ union { -+ pktq_log_format_v01_t v01; -+ } pktq_log; -+} wl_iov_pktq_log_t; -+ -+ -+/* **** EXTLOG **** */ -+#define EXTLOG_CUR_VER 0x0100 -+ -+#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ -+ -+/* log modules (bitmap) */ -+#define LOG_MODULE_COMMON 0x0001 -+#define LOG_MODULE_ASSOC 0x0002 -+#define LOG_MODULE_EVENT 0x0004 -+#define LOG_MODULE_MAX 3 /* Update when adding module */ -+ -+/* log levels */ -+#define WL_LOG_LEVEL_DISABLE 0 -+#define WL_LOG_LEVEL_ERR 1 -+#define WL_LOG_LEVEL_WARN 2 -+#define WL_LOG_LEVEL_INFO 3 -+#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ -+ -+/* flag */ -+#define LOG_FLAG_EVENT 1 -+ -+/* log arg_type */ -+#define LOG_ARGTYPE_NULL 0 -+#define LOG_ARGTYPE_STR 1 /* %s */ -+#define LOG_ARGTYPE_INT 2 /* %d */ -+#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ -+#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ -+ -+typedef struct wlc_extlog_cfg { -+ int max_number; -+ uint16 module; /* bitmap */ -+ uint8 level; -+ uint8 flag; -+ uint16 version; -+} wlc_extlog_cfg_t; -+ -+typedef struct log_record { -+ uint32 time; -+ uint16 module; -+ uint16 id; -+ uint8 level; -+ uint8 sub_unit; -+ uint8 seq_num; -+ int32 arg; -+ char str[MAX_ARGSTR_LEN]; -+} log_record_t; -+ -+typedef struct wlc_extlog_req { -+ uint32 from_last; -+ uint32 num; -+} wlc_extlog_req_t; -+ -+typedef struct wlc_extlog_results { -+ uint16 version; -+ uint16 record_len; -+ uint32 num; -+ log_record_t logs[1]; -+} wlc_extlog_results_t; -+ -+typedef struct log_idstr { -+ uint16 id; -+ uint16 flag; -+ uint8 arg_type; -+ const char *fmt_str; -+} log_idstr_t; -+ -+#define FMTSTRF_USER 1 -+ -+/* flat ID definitions -+ * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will -+ * affect backward compatibility with pre-existing apps -+ */ -+typedef enum { -+ FMTSTR_DRIVER_UP_ID = 0, -+ FMTSTR_DRIVER_DOWN_ID = 1, -+ FMTSTR_SUSPEND_MAC_FAIL_ID = 2, -+ FMTSTR_NO_PROGRESS_ID = 3, -+ FMTSTR_RFDISABLE_ID = 4, -+ FMTSTR_REG_PRINT_ID = 5, -+ FMTSTR_EXPTIME_ID = 6, -+ FMTSTR_JOIN_START_ID = 7, -+ FMTSTR_JOIN_COMPLETE_ID = 8, -+ FMTSTR_NO_NETWORKS_ID = 9, -+ FMTSTR_SECURITY_MISMATCH_ID = 10, -+ FMTSTR_RATE_MISMATCH_ID = 11, -+ FMTSTR_AP_PRUNED_ID = 12, -+ FMTSTR_KEY_INSERTED_ID = 13, -+ FMTSTR_DEAUTH_ID = 14, -+ FMTSTR_DISASSOC_ID = 15, -+ FMTSTR_LINK_UP_ID = 16, -+ FMTSTR_LINK_DOWN_ID = 17, -+ FMTSTR_RADIO_HW_OFF_ID = 18, -+ FMTSTR_RADIO_HW_ON_ID = 19, -+ FMTSTR_EVENT_DESC_ID = 20, -+ FMTSTR_PNP_SET_POWER_ID = 21, -+ FMTSTR_RADIO_SW_OFF_ID = 22, -+ FMTSTR_RADIO_SW_ON_ID = 23, -+ FMTSTR_PWD_MISMATCH_ID = 24, -+ FMTSTR_FATAL_ERROR_ID = 25, -+ FMTSTR_AUTH_FAIL_ID = 26, -+ FMTSTR_ASSOC_FAIL_ID = 27, -+ FMTSTR_IBSS_FAIL_ID = 28, -+ FMTSTR_EXTAP_FAIL_ID = 29, -+ FMTSTR_MAX_ID -+} log_fmtstr_id_t; -+ -+#ifdef DONGLEOVERLAYS -+typedef struct { -+ uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */ -+ uint32 offset; /* offset into overlay region to write code */ -+ uint32 len; /* overlay code len */ -+ /* overlay code follows this struct */ -+} wl_ioctl_overlay_t; -+ -+#define OVERLAY_IDX_MASK 0x000000ff -+#define OVERLAY_IDX_SHIFT 0 -+#define OVERLAY_FLAGS_MASK 0xffffff00 -+#define OVERLAY_FLAGS_SHIFT 8 -+/* overlay written to device memory immediately after loading the base image */ -+#define OVERLAY_FLAG_POSTLOAD 0x100 -+/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ -+#define OVERLAY_FLAG_DEFER_DL 0x200 -+/* overlay downloaded prior to the host going to sleep */ -+#define OVERLAY_FLAG_PRESLEEP 0x400 -+ -+#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 -+#endif /* DONGLEOVERLAYS */ -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* no default structure packing */ -+#include <packed_section_end.h> -+ -+/* require strict packing */ -+#include <packed_section_start.h> -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+ -+/* Structures and constants used for "vndr_ie" IOVar interface */ -+#define VNDR_IE_CMD_LEN 4 /* length of the set command string: -+ * "add", "del" (+ NUL) -+ */ -+ -+/* 802.11 Mgmt Packet flags */ -+#define VNDR_IE_BEACON_FLAG 0x1 -+#define VNDR_IE_PRBRSP_FLAG 0x2 -+#define VNDR_IE_ASSOCRSP_FLAG 0x4 -+#define VNDR_IE_AUTHRSP_FLAG 0x8 -+#define VNDR_IE_PRBREQ_FLAG 0x10 -+#define VNDR_IE_ASSOCREQ_FLAG 0x20 -+#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ -+#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ -+ -+#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ -+ vndr_ie_t vndr_ie_data; /* vendor IE data */ -+} BWL_POST_PACKED_STRUCT vndr_ie_info_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ int iecount; /* number of entries in the vndr_ie_list[] array */ -+ vndr_ie_info_t vndr_ie_list[1]; /* variable size list of vndr_ie_info_t structs */ -+} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ char cmd[VNDR_IE_CMD_LEN]; /* vndr_ie IOVar set command : "add", "del" + NUL */ -+ vndr_ie_buf_t vndr_ie_buffer; /* buffer containing Vendor IE list information */ -+} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; -+ -+/* tag_ID/length/value_buffer tuple */ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint8 id; -+ uint8 len; -+ uint8 data[1]; -+} BWL_POST_PACKED_STRUCT tlv_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ -+ tlv_t ie_data; /* IE data */ -+} BWL_POST_PACKED_STRUCT ie_info_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ int iecount; /* number of entries in the ie_list[] array */ -+ ie_info_t ie_list[1]; /* variable size list of ie_info_t structs */ -+} BWL_POST_PACKED_STRUCT ie_buf_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ char cmd[VNDR_IE_CMD_LEN]; /* ie IOVar set command : "add" + NUL */ -+ ie_buf_t ie_buffer; /* buffer containing IE list information */ -+} BWL_POST_PACKED_STRUCT ie_setbuf_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct { -+ uint32 pktflag; /* bitmask indicating which packet(s) contain this IE */ -+ uint8 id; /* IE type */ -+} BWL_POST_PACKED_STRUCT ie_getbuf_t; -+ -+/* structures used to define format of wps ie data from probe requests */ -+/* passed up to applications via iovar "prbreq_wpsie" */ -+typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr { -+ struct ether_addr staAddr; -+ uint16 ieLen; -+} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { -+ sta_prbreq_wps_ie_hdr_t hdr; -+ uint8 ieData[1]; -+} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; -+ -+typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { -+ uint32 totLen; -+ uint8 ieDataList[1]; -+} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; -+ -+ -+#ifdef WLMEDIA_TXFAILEVENT -+typedef BWL_PRE_PACKED_STRUCT struct { -+ char dest[ETHER_ADDR_LEN]; /* destination MAC */ -+ uint8 prio; /* Packet Priority */ -+ uint8 flags; /* Flags */ -+ uint32 tsf_l; /* TSF timer low */ -+ uint32 tsf_h; /* TSF timer high */ -+ uint16 rates; /* Main Rates */ -+ uint16 txstatus; /* TX Status */ -+} BWL_POST_PACKED_STRUCT txfailinfo_t; -+#endif /* WLMEDIA_TXFAILEVENT */ -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+ -+/* no strict structure packing */ -+#include <packed_section_end.h> -+ -+#ifndef LINUX_POSTMOGRIFY_REMOVAL -+/* Global ASSERT Logging */ -+#define ASSERTLOG_CUR_VER 0x0100 -+#define MAX_ASSRTSTR_LEN 64 -+ -+typedef struct assert_record { -+ uint32 time; -+ uint8 seq_num; -+ char str[MAX_ASSRTSTR_LEN]; -+} assert_record_t; -+ -+typedef struct assertlog_results { -+ uint16 version; -+ uint16 record_len; -+ uint32 num; -+ assert_record_t logs[1]; -+} assertlog_results_t; -+ -+#define LOGRRC_FIX_LEN 8 -+#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) -+ -+ -+/* channel interference measurement (chanim) related defines */ -+ -+/* chanim mode */ -+#define CHANIM_DISABLE 0 /* disabled */ -+#define CHANIM_DETECT 1 /* detection only */ -+#define CHANIM_EXT 2 /* external state machine */ -+#define CHANIM_ACT 3 /* full internal state machine, detect + act */ -+#define CHANIM_MODE_MAX 4 -+ -+/* define for apcs reason code */ -+#define APCS_INIT 0 -+#define APCS_IOCTL 1 -+#define APCS_CHANIM 2 -+#define APCS_CSTIMER 3 -+#define APCS_BTA 4 -+ -+/* number of ACS record entries */ -+#define CHANIM_ACS_RECORD 10 -+ -+/* CHANIM */ -+#define CCASTATS_TXDUR 0 -+#define CCASTATS_INBSS 1 -+#define CCASTATS_OBSS 2 -+#define CCASTATS_NOCTG 3 -+#define CCASTATS_NOPKT 4 -+#define CCASTATS_DOZE 5 -+#define CCASTATS_TXOP 6 -+#define CCASTATS_GDTXDUR 7 -+#define CCASTATS_BDTXDUR 8 -+#define CCASTATS_MAX 9 -+ -+/* chanim acs record */ -+typedef struct { -+ bool valid; -+ uint8 trigger; -+ chanspec_t selected_chspc; -+ int8 bgnoise; -+ uint32 glitch_cnt; -+ uint8 ccastats; -+ uint timestamp; -+} chanim_acs_record_t; -+ -+typedef struct { -+ chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; -+ uint8 count; -+ uint timestamp; -+} wl_acs_record_t; -+ -+typedef struct chanim_stats { -+ uint32 glitchcnt; /* normalized as per second count */ -+ uint32 badplcp; /* normalized as per second count */ -+ uint8 ccastats[CCASTATS_MAX]; /* normalized as 0-255 */ -+ int8 bgnoise; /* background noise level (in dBm) */ -+ chanspec_t chanspec; -+ uint32 timestamp; -+} chanim_stats_t; -+ -+#define WL_CHANIM_STATS_VERSION 1 -+#define WL_CHANIM_COUNT_ALL 0xff -+#define WL_CHANIM_COUNT_ONE 0x1 -+ -+typedef struct { -+ uint32 buflen; -+ uint32 version; -+ uint32 count; -+ chanim_stats_t stats[1]; -+} wl_chanim_stats_t; -+ -+#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) -+ -+/* Noise measurement metrics. */ -+#define NOISE_MEASURE_KNOISE 0x1 -+ -+/* scb probe parameter */ -+typedef struct { -+ uint32 scb_timeout; -+ uint32 scb_activity_time; -+ uint32 scb_max_probe; -+} wl_scb_probe_t; -+ -+/* ap tpc modes */ -+#define AP_TPC_OFF 0 -+#define AP_TPC_BSS_PWR 1 /* BSS power control */ -+#define AP_TPC_AP_PWR 2 /* AP power control */ -+#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ -+#define AP_TPC_MAX_LINK_MARGIN 127 -+ -+/* ap tpc modes */ -+#define AP_TPC_OFF 0 -+#define AP_TPC_BSS_PWR 1 /* BSS power control */ -+#define AP_TPC_AP_PWR 2 /* AP power control */ -+#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ -+#define AP_TPC_MAX_LINK_MARGIN 127 -+ -+/* structure/defines for selective mgmt frame (smf) stats support */ -+ -+#define SMFS_VERSION 1 -+/* selected mgmt frame (smf) stats element */ -+typedef struct wl_smfs_elem { -+ uint32 count; -+ uint16 code; /* SC or RC code */ -+} wl_smfs_elem_t; -+ -+typedef struct wl_smf_stats { -+ uint32 version; -+ uint16 length; /* reserved for future usage */ -+ uint8 type; -+ uint8 codetype; -+ uint32 ignored_cnt; -+ uint32 malformed_cnt; -+ uint32 count_total; /* count included the interested group */ -+ wl_smfs_elem_t elem[1]; -+} wl_smf_stats_t; -+ -+#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); -+ -+enum { -+ SMFS_CODETYPE_SC, -+ SMFS_CODETYPE_RC -+}; -+ -+/* reuse two number in the sc/rc space */ -+#define SMFS_CODE_MALFORMED 0xFFFE -+#define SMFS_CODE_IGNORED 0xFFFD -+ -+typedef enum smfs_type { -+ SMFS_TYPE_AUTH, -+ SMFS_TYPE_ASSOC, -+ SMFS_TYPE_REASSOC, -+ SMFS_TYPE_DISASSOC_TX, -+ SMFS_TYPE_DISASSOC_RX, -+ SMFS_TYPE_DEAUTH_TX, -+ SMFS_TYPE_DEAUTH_RX, -+ SMFS_TYPE_MAX -+} smfs_type_t; -+ -+#ifdef PHYMON -+ -+#define PHYMON_VERSION 1 -+ -+typedef struct wl_phycal_core_state { -+ /* Tx IQ/LO calibration coeffs */ -+ int16 tx_iqlocal_a; -+ int16 tx_iqlocal_b; -+ int8 tx_iqlocal_ci; -+ int8 tx_iqlocal_cq; -+ int8 tx_iqlocal_di; -+ int8 tx_iqlocal_dq; -+ int8 tx_iqlocal_ei; -+ int8 tx_iqlocal_eq; -+ int8 tx_iqlocal_fi; -+ int8 tx_iqlocal_fq; -+ -+ /* Rx IQ calibration coeffs */ -+ int16 rx_iqcal_a; -+ int16 rx_iqcal_b; -+ -+ uint8 tx_iqlocal_pwridx; /* Tx Power Index for Tx IQ/LO calibration */ -+ uint32 papd_epsilon_table[64]; /* PAPD epsilon table */ -+ int16 papd_epsilon_offset; /* PAPD epsilon offset */ -+ uint8 curr_tx_pwrindex; /* Tx power index */ -+ int8 idle_tssi; /* Idle TSSI */ -+ int8 est_tx_pwr; /* Estimated Tx Power (dB) */ -+ int8 est_rx_pwr; /* Estimated Rx Power (dB) from RSSI */ -+ uint16 rx_gaininfo; /* Rx gain applied on last Rx pkt */ -+ uint16 init_gaincode; /* initgain required for ACI */ -+ int8 estirr_tx; -+ int8 estirr_rx; -+ -+} wl_phycal_core_state_t; -+ -+typedef struct wl_phycal_state { -+ int version; -+ int8 num_phy_cores; /* number of cores */ -+ int8 curr_temperature; /* on-chip temperature sensor reading */ -+ chanspec_t chspec; /* channspec for this state */ -+ bool aci_state; /* ACI state: ON/OFF */ -+ uint16 crsminpower; /* crsminpower required for ACI */ -+ uint16 crsminpowerl; /* crsminpowerl required for ACI */ -+ uint16 crsminpoweru; /* crsminpoweru required for ACI */ -+ wl_phycal_core_state_t phycal_core[1]; -+} wl_phycal_state_t; -+ -+#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) -+#endif /* PHYMON */ -+ -+/* discovery state */ -+typedef struct wl_p2p_disc_st { -+ uint8 state; /* see state */ -+ chanspec_t chspec; /* valid in listen state */ -+ uint16 dwell; /* valid in listen state, in ms */ -+} wl_p2p_disc_st_t; -+ -+/* state */ -+#define WL_P2P_DISC_ST_SCAN 0 -+#define WL_P2P_DISC_ST_LISTEN 1 -+#define WL_P2P_DISC_ST_SEARCH 2 -+ -+/* scan request */ -+typedef struct wl_p2p_scan { -+ uint8 type; /* 'S' for WLC_SCAN, 'E' for "escan" */ -+ uint8 reserved[3]; -+ /* scan or escan parms... */ -+} wl_p2p_scan_t; -+ -+/* i/f request */ -+typedef struct wl_p2p_if { -+ struct ether_addr addr; -+ uint8 type; /* see i/f type */ -+ chanspec_t chspec; /* for p2p_ifadd GO */ -+} wl_p2p_if_t; -+ -+/* i/f type */ -+#define WL_P2P_IF_CLIENT 0 -+#define WL_P2P_IF_GO 1 -+#define WL_P2P_IF_DYNBCN_GO 2 -+#define WL_P2P_IF_DEV 3 -+ -+/* i/f query */ -+typedef struct wl_p2p_ifq { -+ uint bsscfgidx; -+ char ifname[BCM_MSG_IFNAME_MAX]; -+} wl_p2p_ifq_t; -+ -+/* OppPS & CTWindow */ -+typedef struct wl_p2p_ops { -+ uint8 ops; /* 0: disable 1: enable */ -+ uint8 ctw; /* >= 10 */ -+} wl_p2p_ops_t; -+ -+/* absence and presence request */ -+typedef struct wl_p2p_sched_desc { -+ uint32 start; -+ uint32 interval; -+ uint32 duration; -+ uint32 count; /* see count */ -+} wl_p2p_sched_desc_t; -+ -+/* count */ -+#define WL_P2P_SCHED_RSVD 0 -+#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ -+ -+typedef struct wl_p2p_sched { -+ uint8 type; /* see schedule type */ -+ uint8 action; /* see schedule action */ -+ uint8 option; /* see schedule option */ -+ wl_p2p_sched_desc_t desc[1]; -+} wl_p2p_sched_t; -+#define WL_P2P_SCHED_FIXED_LEN 3 -+ -+/* schedule type */ -+#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ -+#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ -+ -+/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ -+#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ -+#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ -+/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ -+#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ -+/* schedule option - WL_P2P_SCHED_TYPE_XXX */ -+#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ -+ -+/* schedule option - WL_P2P_SCHED_TYPE_ABS */ -+#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ -+#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ -+/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ -+#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with -+ * start being an offset of the 'current' TSF -+ */ -+ -+/* feature flags */ -+#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ -+#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe -+ * requests -+ */ -+#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ -+ -+#ifdef WLNIC -+/* nic_cnx iovar */ -+typedef struct wl_nic_cnx { -+ uint8 opcode; -+ struct ether_addr addr; -+ /* the following are valid for WL_NIC_CNX_CONN */ -+ uint8 SSID_len; -+ uint8 SSID[32]; -+ struct ether_addr abssid; -+ uint8 join_period; -+} wl_nic_cnx_t; -+ -+/* opcode */ -+#define WL_NIC_CNX_ADD 0 /* add NIC connection */ -+#define WL_NIC_CNX_DEL 1 /* delete NIC connection */ -+#define WL_NIC_CNX_IDX 2 /* query NIC connection index */ -+#define WL_NIC_CNX_CONN 3 /* join/create network */ -+#define WL_NIC_CNX_DIS 4 /* disconnect from network */ -+ -+/* nic_cfg iovar */ -+typedef struct wl_nic_cfg { -+ uint8 version; -+ uint8 beacon_mode; -+ uint16 beacon_interval; -+ uint8 diluted_beacon_period; -+ uint8 repeat_EQC; -+ uint8 scan_length; -+ uint8 scan_interval; -+ uint8 scan_probability; -+ uint8 awake_window_length; -+ int8 TSF_correction; -+ uint8 ASID; -+ uint8 channel_usage_mode; -+} wl_nic_cfg_t; -+ -+/* version */ -+#define WL_NIC_CFG_VER 1 -+ -+/* beacon_mode */ -+#define WL_NIC_BCN_NORM 0 -+#define WL_NIC_BCN_DILUTED 1 -+ -+/* channel_usage_mode */ -+#define WL_NIC_CHAN_STATIC 0 -+#define WL_NIC_CHAN_CYCLE 1 -+ -+/* nic_cfg iovar */ -+typedef struct wl_nic_frm { -+ uint8 type; -+ struct ether_addr da; -+ uint8 body[1]; -+} wl_nic_frm_t; -+ -+/* type */ -+#define WL_NIC_FRM_MYNET 1 -+#define WL_NIC_FRM_ACTION 2 -+ -+/* i/f query */ -+typedef struct wl_nic_ifq { -+ uint bsscfgidx; -+ char ifname[BCM_MSG_IFNAME_MAX]; -+} wl_nic_ifq_t; -+ -+/* data mode */ -+/* nic_dm iovar */ -+typedef struct wl_nic_dm { -+ uint8 enab; -+ chanspec_t chspec; -+} wl_nic_dm_t; -+#endif /* WLNIC */ -+ -+/* RFAWARE def */ -+#define BCM_ACTION_RFAWARE 0x77 -+#define BCM_ACTION_RFAWARE_DCS 0x01 -+ -+/* DCS reason code define */ -+#define BCM_DCS_IOVAR 0x1 -+#define BCM_DCS_UNKNOWN 0xFF -+ -+typedef struct wl_bcmdcs_data { -+ uint reason; -+ chanspec_t chspec; -+} wl_bcmdcs_data_t; -+ -+/* n-mode support capability */ -+/* 2x2 includes both 1x1 & 2x2 devices -+ * reserved #define 2 for future when we want to separate 1x1 & 2x2 and -+ * control it independently -+ */ -+#define WL_11N_2x2 1 -+#define WL_11N_3x3 3 -+#define WL_11N_4x4 4 -+ -+/* define 11n feature disable flags */ -+#define WLFEATURE_DISABLE_11N 0x00000001 -+#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 -+#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 -+#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 -+#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 -+#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 -+#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 -+#define WLFEATURE_DISABLE_11N_GF 0x00000080 -+ -+/* Proxy STA modes */ -+#define PSTA_MODE_DISABLED 0 -+#define PSTA_MODE_PROXY 1 -+#define PSTA_MODE_REPEATER 2 -+ -+ -+/* NAT configuration */ -+typedef struct { -+ uint32 ipaddr; /* interface ip address */ -+ uint32 ipaddr_mask; /* interface ip address mask */ -+ uint32 ipaddr_gateway; /* gateway ip address */ -+ uint8 mac_gateway[6]; /* gateway mac address */ -+ uint32 ipaddr_dns; /* DNS server ip address, valid only for public if */ -+ uint8 mac_dns[6]; /* DNS server mac address, valid only for public if */ -+ uint8 GUID[38]; /* interface GUID */ -+} nat_if_info_t; -+ -+typedef struct { -+ uint op; /* operation code */ -+ bool pub_if; /* set for public if, clear for private if */ -+ nat_if_info_t if_info; /* interface info */ -+} nat_cfg_t; -+ -+/* op code in nat_cfg */ -+#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ -+#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ -+#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ -+ -+/* NAT state */ -+#define NAT_STATE_ENABLED 1 /* NAT is enabled */ -+#define NAT_STATE_DISABLED 2 /* NAT is disabled */ -+ -+typedef struct { -+ int state; /* NAT state returned */ -+} nat_state_t; -+ -+#ifdef PROP_TXSTATUS -+/* Bit definitions for tlv iovar */ -+/* -+ * enable RSSI signals: -+ * WLFC_CTL_TYPE_RSSI -+ */ -+#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 -+ -+/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: -+ * -+ * WLFC_CTL_TYPE_MAC_OPEN -+ * WLFC_CTL_TYPE_MAC_CLOSE -+ * -+ * WLFC_CTL_TYPE_INTERFACE_OPEN -+ * WLFC_CTL_TYPE_INTERFACE_CLOSE -+ * -+ * WLFC_CTL_TYPE_MACDESC_ADD -+ * WLFC_CTL_TYPE_MACDESC_DEL -+ * -+ */ -+#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 -+ -+/* enable (status, fifo_credit, mac_credit) signals -+ * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT -+ * WLFC_CTL_TYPE_TXSTATUS -+ * WLFC_CTL_TYPE_FIFO_CREDITBACK -+ */ -+#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 -+ -+#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 -+#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 -+#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 -+#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 -+#endif /* PROP_TXSTATUS */ -+ -+#define BTA_STATE_LOG_SZ 64 -+ -+/* BTAMP Statemachine states */ -+enum { -+ HCIReset = 1, -+ HCIReadLocalAMPInfo, -+ HCIReadLocalAMPASSOC, -+ HCIWriteRemoteAMPASSOC, -+ HCICreatePhysicalLink, -+ HCIAcceptPhysicalLinkRequest, -+ HCIDisconnectPhysicalLink, -+ HCICreateLogicalLink, -+ HCIAcceptLogicalLink, -+ HCIDisconnectLogicalLink, -+ HCILogicalLinkCancel, -+ HCIAmpStateChange, -+ HCIWriteLogicalLinkAcceptTimeout -+}; -+ -+typedef struct flush_txfifo { -+ uint32 txfifobmp; -+ uint32 hwtxfifoflush; -+ struct ether_addr ea; -+} flush_txfifo_t; -+ -+#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ -+#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ -+#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ -+#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ -+ -+enum { -+ SPATIAL_MODE_2G_IDX = 0, -+ SPATIAL_MODE_5G_LOW_IDX, -+ SPATIAL_MODE_5G_MID_IDX, -+ SPATIAL_MODE_5G_HIGH_IDX, -+ SPATIAL_MODE_5G_UPPER_IDX, -+ SPATIAL_MODE_MAX_IDX -+}; -+ -+/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ -+typedef struct wl_mempool_stats { -+ int num; /* Number of memory pools */ -+ bcm_mp_stats_t s[1]; /* Variable array of memory pool stats. */ -+} wl_mempool_stats_t; -+ -+ -+/* D0 Coalescing */ -+#define IPV4_ARP_FILTER 0x0001 -+#define IPV4_NETBT_FILTER 0x0002 -+#define IPV4_LLMNR_FILTER 0x0004 -+#define IPV4_SSDP_FILTER 0x0008 -+#define IPV4_WSD_FILTER 0x0010 -+#define IPV6_NETBT_FILTER 0x0200 -+#define IPV6_LLMNR_FILTER 0x0400 -+#define IPV6_SSDP_FILTER 0x0800 -+#define IPV6_WSD_FILTER 0x1000 -+ -+/* Network Offload Engine */ -+#define NWOE_OL_ENABLE 0x00000001 -+ -+typedef struct { -+ uint32 ipaddr; -+ uint32 ipaddr_netmask; -+ uint32 ipaddr_gateway; -+} nwoe_ifconfig_t; -+ -+/* -+ * Traffic management structures/defines. -+ */ -+ -+/* Traffic management bandwidth parameters */ -+#define TRF_MGMT_MAX_PRIORITIES 3 -+ -+#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ -+#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Only support traffic clasification */ -+#define TRF_MGMT_FLAG_DISABLE_PRIORITY_TAGGING 0x0004 /* Don't override packet's priority */ -+ -+/* Traffic management priority classes */ -+typedef enum trf_mgmt_priority_class { -+ trf_mgmt_priority_low = 0, /* Maps to 802.1p BO */ -+ trf_mgmt_priority_medium = 1, /* Maps to 802.1p BE */ -+ trf_mgmt_priority_high = 2, /* Maps to 802.1p VI */ -+ trf_mgmt_priority_invalid = (trf_mgmt_priority_high + 1) -+} trf_mgmt_priority_class_t; -+ -+/* Traffic management configuration parameters */ -+typedef struct trf_mgmt_config { -+ uint32 trf_mgmt_enabled; /* 0 - disabled, 1 - enabled */ -+ uint32 flags; /* See TRF_MGMT_FLAG_xxx defines */ -+ uint32 host_ip_addr; /* My IP address to determine subnet */ -+ uint32 host_subnet_mask; /* My subnet mask */ -+ uint32 downlink_bandwidth; /* In units of kbps */ -+ uint32 uplink_bandwidth; /* In units of kbps */ -+ uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed tx bandwidth */ -+ uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /* Minimum guaranteed rx bandwidth */ -+} trf_mgmt_config_t; -+ -+/* Traffic management filter */ -+typedef struct trf_mgmt_filter { -+ struct ether_addr dst_ether_addr; /* His L2 address */ -+ uint32 dst_ip_addr; /* His IP address */ -+ uint16 dst_port; /* His L4 port */ -+ uint16 src_port; /* My L4 port */ -+ uint16 prot; /* L4 protocol (only TCP or UDP) */ -+ uint16 flags; /* TBD. For now, this must be zero. */ -+ trf_mgmt_priority_class_t priority; /* Priority for filtered packets */ -+} trf_mgmt_filter_t; -+ -+/* Traffic management filter list (variable length) */ -+typedef struct trf_mgmt_filter_list { -+ uint32 num_filters; -+ trf_mgmt_filter_t filter[1]; -+} trf_mgmt_filter_list_t; -+ -+/* Traffic management global info used for all queues */ -+typedef struct trf_mgmt_global_info { -+ uint32 maximum_bytes_per_second; -+ uint32 maximum_bytes_per_sampling_period; -+ uint32 total_bytes_consumed_per_second; -+ uint32 total_bytes_consumed_per_sampling_period; -+ uint32 total_unused_bytes_per_sampling_period; -+} trf_mgmt_global_info_t; -+ -+/* Traffic management shaping info per priority queue */ -+typedef struct trf_mgmt_shaping_info { -+ uint32 gauranteed_bandwidth_percentage; -+ uint32 guaranteed_bytes_per_second; -+ uint32 guaranteed_bytes_per_sampling_period; -+ uint32 num_bytes_produced_per_second; -+ uint32 num_bytes_consumed_per_second; -+ uint32 num_queued_packets; /* Number of packets in queue */ -+ uint32 num_queued_bytes; /* Number of bytes in queue */ -+} trf_mgmt_shaping_info_t; -+ -+/* Traffic management shaping info array */ -+typedef struct trf_mgmt_shaping_info_array { -+ trf_mgmt_global_info_t tx_global_shaping_info; -+ trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; -+ trf_mgmt_global_info_t rx_global_shaping_info; -+ trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; -+} trf_mgmt_shaping_info_array_t; -+ -+ -+/* Traffic management statistical counters */ -+typedef struct trf_mgmt_stats { -+ uint32 num_processed_packets; /* Number of packets processed */ -+ uint32 num_processed_bytes; /* Number of bytes processed */ -+ uint32 num_discarded_packets; /* Number of packets discarded from queue */ -+} trf_mgmt_stats_t; -+ -+/* Traffic management statisics array */ -+typedef struct trf_mgmt_stats_array { -+ trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; -+ trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; -+} trf_mgmt_stats_array_t; -+ -+typedef struct powersel_params { -+ /* LPC Params exposed via IOVAR */ -+ int32 tp_ratio_thresh; /* Throughput ratio threshold */ -+ uint8 rate_stab_thresh; /* Thresh for rate stability based on nupd */ -+ uint8 pwr_stab_thresh; /* Number of successes before power step down */ -+ uint8 pwr_sel_exp_time; /* Time lapse for expiry of database */ -+} powersel_params_t; -+ -+#endif /* LINUX_POSTMOGRIFY_REMOVAL */ -+#endif /* _wlioctl_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c -new file mode 100644 -index 00000000..93990d9b ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/linux_osl.c -@@ -0,0 +1,1126 @@ -+/* -+ * Linux OS Independent Layer -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: linux_osl.c 373382 2012-12-07 07:59:52Z $ -+ */ -+ -+#define LINUX_PORT -+ -+#include <typedefs.h> -+#include <bcmendian.h> -+#include <linuxver.h> -+#include <bcmdefs.h> -+#include <osl.h> -+#include <bcmutils.h> -+#include <linux/delay.h> -+#include <pcicfg.h> -+ -+ -+#include <linux/fs.h> -+ -+#define PCI_CFG_RETRY 10 -+ -+#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ -+#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ -+ -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+#define DHD_SKB_HDRSIZE 336 -+#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) -+#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) -+#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) -+ -+#define STATIC_BUF_MAX_NUM 16 -+#define STATIC_BUF_SIZE (PAGE_SIZE*2) -+#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) -+ -+typedef struct bcm_static_buf { -+ struct semaphore static_sem; -+ unsigned char *buf_ptr; -+ unsigned char buf_use[STATIC_BUF_MAX_NUM]; -+} bcm_static_buf_t; -+ -+static bcm_static_buf_t *bcm_static_buf = 0; -+ -+#define STATIC_PKT_MAX_NUM 8 -+#if defined(ENHANCED_STATIC_BUF) -+#define STATIC_PKT_4PAGE_NUM 1 -+#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE -+#else -+#define STATIC_PKT_4PAGE_NUM 0 -+#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE -+#endif -+ -+typedef struct bcm_static_pkt { -+ struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM]; -+ struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM]; -+#ifdef ENHANCED_STATIC_BUF -+ struct sk_buff *skb_16k; -+#endif -+ struct semaphore osl_pkt_sem; -+ unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM]; -+} bcm_static_pkt_t; -+ -+static bcm_static_pkt_t *bcm_static_skb = 0; -+#endif -+ -+typedef struct bcm_mem_link { -+ struct bcm_mem_link *prev; -+ struct bcm_mem_link *next; -+ uint size; -+ int line; -+ void *osh; -+ char file[BCM_MEM_FILENAME_LEN]; -+} bcm_mem_link_t; -+ -+struct osl_info { -+ osl_pubinfo_t pub; -+#ifdef CTFPOOL -+ ctfpool_t *ctfpool; -+#endif -+ uint magic; -+ void *pdev; -+ atomic_t malloced; -+ uint failed; -+ uint bustype; -+ bcm_mem_link_t *dbgmem_list; -+ spinlock_t dbgmem_lock; -+ spinlock_t pktalloc_lock; -+}; -+ -+ -+ -+ -+uint32 g_assert_type = FALSE; -+ -+static int16 linuxbcmerrormap[] = -+{ 0, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -E2BIG, -+ -E2BIG, -+ -EBUSY, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EFAULT, -+ -ENOMEM, -+ -EOPNOTSUPP, -+ -EMSGSIZE, -+ -EINVAL, -+ -EPERM, -+ -ENOMEM, -+ -EINVAL, -+ -ERANGE, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EINVAL, -+ -EIO, -+ -ENODEV, -+ -EINVAL, -+ -EIO, -+ -EIO, -+ -ENODEV, -+ -EINVAL, -+ -ENODATA, -+ -+ -+ -+#if BCME_LAST != -42 -+#error "You need to add a OS error translation in the linuxbcmerrormap \ -+ for new error code defined in bcmutils.h" -+#endif -+}; -+ -+ -+int -+osl_error(int bcmerror) -+{ -+ if (bcmerror > 0) -+ bcmerror = 0; -+ else if (bcmerror < BCME_LAST) -+ bcmerror = BCME_ERROR; -+ -+ -+ return linuxbcmerrormap[-bcmerror]; -+} -+ -+extern uint8* dhd_os_prealloc(void *osh, int section, int size); -+ -+osl_t * -+osl_attach(void *pdev, uint bustype, bool pkttag) -+{ -+ osl_t *osh; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ gfp_t flags; -+ -+ flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; -+ osh = kmalloc(sizeof(osl_t), flags); -+#else -+ osh = kmalloc(sizeof(osl_t), GFP_ATOMIC); -+#endif -+ -+ ASSERT(osh); -+ -+ bzero(osh, sizeof(osl_t)); -+ -+ -+ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); -+ -+ osh->magic = OS_HANDLE_MAGIC; -+ atomic_set(&osh->malloced, 0); -+ osh->failed = 0; -+ osh->dbgmem_list = NULL; -+ spin_lock_init(&(osh->dbgmem_lock)); -+ osh->pdev = pdev; -+ osh->pub.pkttag = pkttag; -+ osh->bustype = bustype; -+ -+ switch (bustype) { -+ case PCI_BUS: -+ case SI_BUS: -+ case PCMCIA_BUS: -+ osh->pub.mmbus = TRUE; -+ break; -+ case JTAG_BUS: -+ case SDIO_BUS: -+ case USB_BUS: -+ case SPI_BUS: -+ case RPC_BUS: -+ osh->pub.mmbus = FALSE; -+ break; -+ default: -+ ASSERT(FALSE); -+ break; -+ } -+ -+#if defined(CONFIG_DHD_USE_STATIC_BUF) -+ if (!bcm_static_buf) { -+ if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+ -+ STATIC_BUF_TOTAL_LEN))) { -+ printk("can not alloc static buf!\n"); -+ } -+ else -+ printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); -+ -+ -+ sema_init(&bcm_static_buf->static_sem, 1); -+ -+ bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; -+ } -+ -+ if (!bcm_static_skb) { -+ int i; -+ void *skb_buff_ptr = 0; -+ bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); -+ skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); -+ -+ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)* -+ (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM)); -+ for (i = 0; i < (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM); i++) -+ bcm_static_skb->pkt_use[i] = 0; -+ -+ sema_init(&bcm_static_skb->osl_pkt_sem, 1); -+ } -+#endif -+ -+ spin_lock_init(&(osh->pktalloc_lock)); -+ -+ return osh; -+} -+ -+void -+osl_detach(osl_t *osh) -+{ -+ if (osh == NULL) -+ return; -+ -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ if (bcm_static_buf) { -+ bcm_static_buf = 0; -+ } -+ if (bcm_static_skb) { -+ bcm_static_skb = 0; -+ } -+#endif -+ -+ ASSERT(osh->magic == OS_HANDLE_MAGIC); -+ kfree(osh); -+} -+ -+static struct sk_buff *osl_alloc_skb(unsigned int len) -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) -+ gfp_t flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; -+ -+ return __dev_alloc_skb(len, flags); -+#else -+ return dev_alloc_skb(len); -+#endif -+} -+ -+#ifdef CTFPOOL -+ -+#ifdef CTFPOOL_SPINLOCK -+#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) -+#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) -+#else -+#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) -+#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) -+#endif -+ -+void * -+osl_ctfpool_add(osl_t *osh) -+{ -+ struct sk_buff *skb; -+#ifdef CTFPOOL_SPINLOCK -+ unsigned long flags; -+#endif -+ -+ if ((osh == NULL) || (osh->ctfpool == NULL)) -+ return NULL; -+ -+ CTFPOOL_LOCK(osh->ctfpool, flags); -+ ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); -+ -+ -+ if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { -+ CTFPOOL_UNLOCK(osh->ctfpool, flags); -+ return NULL; -+ } -+ -+ -+ skb = osl_alloc_skb(osh->ctfpool->obj_size); -+ if (skb == NULL) { -+ printf("%s: skb alloc of len %d failed\n", __FUNCTION__, -+ osh->ctfpool->obj_size); -+ CTFPOOL_UNLOCK(osh->ctfpool, flags); -+ return NULL; -+ } -+ -+ -+ skb->next = (struct sk_buff *)osh->ctfpool->head; -+ osh->ctfpool->head = skb; -+ osh->ctfpool->fast_frees++; -+ osh->ctfpool->curr_obj++; -+ -+ -+ CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; -+ -+ -+ PKTFAST(osh, skb) = FASTBUF; -+ -+ CTFPOOL_UNLOCK(osh->ctfpool, flags); -+ -+ return skb; -+} -+ -+ -+void -+osl_ctfpool_replenish(osl_t *osh, uint thresh) -+{ -+ if ((osh == NULL) || (osh->ctfpool == NULL)) -+ return; -+ -+ -+ while ((osh->ctfpool->refills > 0) && (thresh--)) { -+ osl_ctfpool_add(osh); -+ osh->ctfpool->refills--; -+ } -+} -+ -+ -+int32 -+osl_ctfpool_init(osl_t *osh, uint numobj, uint size) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ gfp_t flags; -+ -+ flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; -+ osh->ctfpool = kmalloc(sizeof(ctfpool_t), flags); -+#else -+ osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC); -+#endif -+ ASSERT(osh->ctfpool); -+ bzero(osh->ctfpool, sizeof(ctfpool_t)); -+ -+ osh->ctfpool->max_obj = numobj; -+ osh->ctfpool->obj_size = size; -+ -+ spin_lock_init(&osh->ctfpool->lock); -+ -+ while (numobj--) { -+ if (!osl_ctfpool_add(osh)) -+ return -1; -+ osh->ctfpool->fast_frees--; -+ } -+ -+ return 0; -+} -+ -+ -+void -+osl_ctfpool_cleanup(osl_t *osh) -+{ -+ struct sk_buff *skb, *nskb; -+#ifdef CTFPOOL_SPINLOCK -+ unsigned long flags; -+#endif -+ -+ if ((osh == NULL) || (osh->ctfpool == NULL)) -+ return; -+ -+ CTFPOOL_LOCK(osh->ctfpool, flags); -+ -+ skb = osh->ctfpool->head; -+ -+ while (skb != NULL) { -+ nskb = skb->next; -+ dev_kfree_skb(skb); -+ skb = nskb; -+ osh->ctfpool->curr_obj--; -+ } -+ -+ ASSERT(osh->ctfpool->curr_obj == 0); -+ osh->ctfpool->head = NULL; -+ CTFPOOL_UNLOCK(osh->ctfpool, flags); -+ -+ kfree(osh->ctfpool); -+ osh->ctfpool = NULL; -+} -+ -+void -+osl_ctfpool_stats(osl_t *osh, void *b) -+{ -+ struct bcmstrbuf *bb; -+ -+ if ((osh == NULL) || (osh->ctfpool == NULL)) -+ return; -+ -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ if (bcm_static_buf) { -+ bcm_static_buf = 0; -+ } -+ if (bcm_static_skb) { -+ bcm_static_skb = 0; -+ } -+#endif -+ -+ bb = b; -+ -+ ASSERT((osh != NULL) && (bb != NULL)); -+ -+ bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", -+ osh->ctfpool->max_obj, osh->ctfpool->obj_size, -+ osh->ctfpool->curr_obj, osh->ctfpool->refills); -+ bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", -+ osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, -+ osh->ctfpool->slow_allocs); -+} -+ -+static inline struct sk_buff * -+osl_pktfastget(osl_t *osh, uint len) -+{ -+ struct sk_buff *skb; -+#ifdef CTFPOOL_SPINLOCK -+ unsigned long flags; -+#endif -+ -+ -+ if (osh->ctfpool == NULL) -+ return NULL; -+ -+ CTFPOOL_LOCK(osh->ctfpool, flags); -+ if (osh->ctfpool->head == NULL) { -+ ASSERT(osh->ctfpool->curr_obj == 0); -+ osh->ctfpool->slow_allocs++; -+ CTFPOOL_UNLOCK(osh->ctfpool, flags); -+ return NULL; -+ } -+ -+ ASSERT(len <= osh->ctfpool->obj_size); -+ -+ -+ skb = (struct sk_buff *)osh->ctfpool->head; -+ osh->ctfpool->head = (void *)skb->next; -+ -+ osh->ctfpool->fast_allocs++; -+ osh->ctfpool->curr_obj--; -+ ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); -+ CTFPOOL_UNLOCK(osh->ctfpool, flags); -+ -+ -+ skb->next = skb->prev = NULL; -+ skb->data = skb->head + 16; -+ skb->tail = skb->head + 16; -+ -+ skb->len = 0; -+ skb->cloned = 0; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) -+ skb->list = NULL; -+#endif -+ atomic_set(&skb->users, 1); -+ -+ return skb; -+} -+#endif -+ -+struct sk_buff * BCMFASTPATH -+osl_pkt_tonative(osl_t *osh, void *pkt) -+{ -+#ifndef WL_UMK -+ struct sk_buff *nskb; -+ unsigned long flags; -+#endif -+ -+ if (osh->pub.pkttag) -+ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); -+ -+#ifndef WL_UMK -+ -+ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { -+ spin_lock_irqsave(&osh->pktalloc_lock, flags); -+ osh->pub.pktalloced--; -+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); -+ } -+#endif -+ return (struct sk_buff *)pkt; -+} -+ -+ -+void * BCMFASTPATH -+osl_pkt_frmnative(osl_t *osh, void *pkt) -+{ -+#ifndef WL_UMK -+ struct sk_buff *nskb; -+ unsigned long flags; -+#endif -+ -+ if (osh->pub.pkttag) -+ bzero((void*)((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ); -+ -+#ifndef WL_UMK -+ -+ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { -+ spin_lock_irqsave(&osh->pktalloc_lock, flags); -+ osh->pub.pktalloced++; -+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); -+ } -+#endif -+ return (void *)pkt; -+} -+ -+ -+void * BCMFASTPATH -+osl_pktget(osl_t *osh, uint len) -+{ -+ struct sk_buff *skb; -+ unsigned long flags; -+ -+#ifdef CTFPOOL -+ -+ skb = osl_pktfastget(osh, len); -+ if ((skb != NULL) || ((skb = osl_alloc_skb(len)) != NULL)) { -+#else -+ if ((skb = osl_alloc_skb(len))) { -+#endif -+ skb_put(skb, len); -+ skb->priority = 0; -+ -+ -+ spin_lock_irqsave(&osh->pktalloc_lock, flags); -+ osh->pub.pktalloced++; -+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); -+ } -+ -+ return ((void*) skb); -+} -+ -+#ifdef CTFPOOL -+static inline void -+osl_pktfastfree(osl_t *osh, struct sk_buff *skb) -+{ -+ ctfpool_t *ctfpool; -+#ifdef CTFPOOL_SPINLOCK -+ unsigned long flags; -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) -+ skb->tstamp.tv.sec = 0; -+#else -+ skb->stamp.tv_sec = 0; -+#endif -+ -+ -+ skb->dev = NULL; -+ skb->dst = NULL; -+ memset(skb->cb, 0, sizeof(skb->cb)); -+ skb->ip_summed = 0; -+ skb->destructor = NULL; -+ -+ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); -+ ASSERT(ctfpool != NULL); -+ -+ -+ CTFPOOL_LOCK(ctfpool, flags); -+ skb->next = (struct sk_buff *)ctfpool->head; -+ ctfpool->head = (void *)skb; -+ -+ ctfpool->fast_frees++; -+ ctfpool->curr_obj++; -+ -+ ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); -+ CTFPOOL_UNLOCK(ctfpool, flags); -+} -+#endif -+ -+ -+void BCMFASTPATH -+osl_pktfree(osl_t *osh, void *p, bool send) -+{ -+ struct sk_buff *skb, *nskb; -+ unsigned long flags; -+ -+ skb = (struct sk_buff*) p; -+ -+ if (send && osh->pub.tx_fn) -+ osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); -+ -+ PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); -+ -+ -+ while (skb) { -+ nskb = skb->next; -+ skb->next = NULL; -+ -+ -+ -+#ifdef CTFPOOL -+ if ((PKTISFAST(osh, skb)) && (atomic_read(&skb->users) == 1)) -+ osl_pktfastfree(osh, skb); -+ else { -+#else -+ { -+#endif -+ -+ if (skb->destructor) -+ -+ dev_kfree_skb_any(skb); -+ else -+ -+ dev_kfree_skb(skb); -+ } -+ spin_lock_irqsave(&osh->pktalloc_lock, flags); -+ osh->pub.pktalloced--; -+ spin_unlock_irqrestore(&osh->pktalloc_lock, flags); -+ skb = nskb; -+ } -+} -+ -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+void* -+osl_pktget_static(osl_t *osh, uint len) -+{ -+ int i = 0; -+ struct sk_buff *skb; -+ -+ -+ if (len > DHD_SKB_MAX_BUFSIZE) { -+ printk("osl_pktget_static: Do we really need this big skb??" -+ " len=%d\n", len); -+ return osl_pktget(osh, len); -+ } -+ -+ down(&bcm_static_skb->osl_pkt_sem); -+ -+ if (len <= DHD_SKB_1PAGE_BUFSIZE) { -+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { -+ if (bcm_static_skb->pkt_use[i] == 0) -+ break; -+ } -+ -+ if (i != STATIC_PKT_MAX_NUM) { -+ bcm_static_skb->pkt_use[i] = 1; -+ -+ skb = bcm_static_skb->skb_4k[i]; -+ skb->tail = skb->data + len; -+ skb->len = len; -+ -+ up(&bcm_static_skb->osl_pkt_sem); -+ return skb; -+ } -+ } -+ -+ if (len <= DHD_SKB_2PAGE_BUFSIZE) { -+ -+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { -+ if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] -+ == 0) -+ break; -+ } -+ -+ if (i != STATIC_PKT_MAX_NUM) { -+ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1; -+ skb = bcm_static_skb->skb_8k[i]; -+ skb->tail = skb->data + len; -+ skb->len = len; -+ -+ up(&bcm_static_skb->osl_pkt_sem); -+ return skb; -+ } -+ } -+ -+#if defined(ENHANCED_STATIC_BUF) -+ if (bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] == 0) { -+ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1; -+ -+ skb = bcm_static_skb->skb_16k; -+ skb->tail = skb->data + len; -+ skb->len = len; -+ -+ up(&bcm_static_skb->osl_pkt_sem); -+ return skb; -+ } -+#endif -+ -+ up(&bcm_static_skb->osl_pkt_sem); -+ printk("osl_pktget_static: all static pkt in use!\n"); -+ return osl_pktget(osh, len); -+} -+ -+void -+osl_pktfree_static(osl_t *osh, void *p, bool send) -+{ -+ int i; -+ if (!bcm_static_skb) { -+ osl_pktfree(osh, p, send); -+ return; -+ } -+ -+ down(&bcm_static_skb->osl_pkt_sem); -+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { -+ if (p == bcm_static_skb->skb_4k[i]) { -+ bcm_static_skb->pkt_use[i] = 0; -+ up(&bcm_static_skb->osl_pkt_sem); -+ return; -+ } -+ } -+ -+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { -+ if (p == bcm_static_skb->skb_8k[i]) { -+ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0; -+ up(&bcm_static_skb->osl_pkt_sem); -+ return; -+ } -+ } -+#ifdef ENHANCED_STATIC_BUF -+ if (p == bcm_static_skb->skb_16k) { -+ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM*2] = 0; -+ up(&bcm_static_skb->osl_pkt_sem); -+ return; -+ } -+#endif -+ up(&bcm_static_skb->osl_pkt_sem); -+ -+ osl_pktfree(osh, p, send); -+ return; -+} -+#endif -+ -+uint32 -+osl_pci_read_config(osl_t *osh, uint offset, uint size) -+{ -+ uint val = 0; -+ uint retry = PCI_CFG_RETRY; -+ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ -+ -+ ASSERT(size == 4); -+ -+ do { -+ pci_read_config_dword(osh->pdev, offset, &val); -+ if (val != 0xffffffff) -+ break; -+ } while (retry--); -+ -+ -+ return (val); -+} -+ -+void -+osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) -+{ -+ uint retry = PCI_CFG_RETRY; -+ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ -+ -+ ASSERT(size == 4); -+ -+ do { -+ pci_write_config_dword(osh->pdev, offset, val); -+ if (offset != PCI_BAR0_WIN) -+ break; -+ if (osl_pci_read_config(osh, offset, size) == val) -+ break; -+ } while (retry--); -+ -+} -+ -+ -+uint -+osl_pci_bus(osl_t *osh) -+{ -+ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); -+ -+ return ((struct pci_dev *)osh->pdev)->bus->number; -+} -+ -+ -+uint -+osl_pci_slot(osl_t *osh) -+{ -+ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); -+ -+ return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); -+} -+ -+ -+struct pci_dev * -+osl_pci_device(osl_t *osh) -+{ -+ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); -+ -+ return osh->pdev; -+} -+ -+static void -+osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) -+{ -+} -+ -+void -+osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) -+{ -+ osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); -+} -+ -+void -+osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) -+{ -+ osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); -+} -+ -+void * -+osl_malloc(osl_t *osh, uint size) -+{ -+ void *addr; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ gfp_t flags; -+#endif -+ -+ -+ if (osh) -+ ASSERT(osh->magic == OS_HANDLE_MAGIC); -+ -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ if (bcm_static_buf) -+ { -+ int i = 0; -+ if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) -+ { -+ down(&bcm_static_buf->static_sem); -+ -+ for (i = 0; i < STATIC_BUF_MAX_NUM; i++) -+ { -+ if (bcm_static_buf->buf_use[i] == 0) -+ break; -+ } -+ -+ if (i == STATIC_BUF_MAX_NUM) -+ { -+ up(&bcm_static_buf->static_sem); -+ printk("all static buff in use!\n"); -+ goto original; -+ } -+ -+ bcm_static_buf->buf_use[i] = 1; -+ up(&bcm_static_buf->static_sem); -+ -+ bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); -+ if (osh) -+ atomic_add(size, &osh->malloced); -+ -+ return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); -+ } -+ } -+original: -+#endif -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; -+ if ((addr = kmalloc(size, flags)) == NULL) { -+#else -+ if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) { -+#endif -+ if (osh) -+ osh->failed++; -+ return (NULL); -+ } -+ if (osh) -+ atomic_add(size, &osh->malloced); -+ -+ return (addr); -+} -+ -+void -+osl_mfree(osl_t *osh, void *addr, uint size) -+{ -+#ifdef CONFIG_DHD_USE_STATIC_BUF -+ if (bcm_static_buf) -+ { -+ if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr -+ <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) -+ { -+ int buf_idx = 0; -+ -+ buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; -+ -+ down(&bcm_static_buf->static_sem); -+ bcm_static_buf->buf_use[buf_idx] = 0; -+ up(&bcm_static_buf->static_sem); -+ -+ if (osh) { -+ ASSERT(osh->magic == OS_HANDLE_MAGIC); -+ atomic_sub(size, &osh->malloced); -+ } -+ return; -+ } -+ } -+#endif -+ if (osh) { -+ ASSERT(osh->magic == OS_HANDLE_MAGIC); -+ atomic_sub(size, &osh->malloced); -+ } -+ kfree(addr); -+} -+ -+uint -+osl_malloced(osl_t *osh) -+{ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ return (atomic_read(&osh->malloced)); -+} -+ -+uint -+osl_malloc_failed(osl_t *osh) -+{ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ return (osh->failed); -+} -+ -+ -+uint -+osl_dma_consistent_align(void) -+{ -+ return (PAGE_SIZE); -+} -+ -+void* -+osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, ulong *pap) -+{ -+ uint16 align = (1 << align_bits); -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ -+ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) -+ size += align; -+ *alloced = size; -+ -+ return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap)); -+} -+ -+void -+osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa) -+{ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ -+ pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); -+} -+ -+uint BCMFASTPATH -+osl_dma_map(osl_t *osh, void *va, uint size, int direction) -+{ -+ int dir; -+ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; -+ return (pci_map_single(osh->pdev, va, size, dir)); -+} -+ -+void BCMFASTPATH -+osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction) -+{ -+ int dir; -+ -+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); -+ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; -+ pci_unmap_single(osh->pdev, (uint32)pa, size, dir); -+} -+ -+#if defined(BCMASSERT_LOG) -+void -+osl_assert(const char *exp, const char *file, int line) -+{ -+ char tempbuf[256]; -+ const char *basename; -+ -+ basename = strrchr(file, '/'); -+ /* skip the '/' */ -+ if (basename) -+ basename++; -+ -+ if (!basename) -+ basename = file; -+ -+ snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", -+ exp, basename, line); -+ -+ printk("%s", tempbuf); -+ -+ -+} -+#endif -+ -+void -+osl_delay(uint usec) -+{ -+ uint d; -+ -+ while (usec > 0) { -+ d = MIN(usec, 1000); -+ udelay(d); -+ usec -= d; -+ } -+} -+ -+ -+ -+void * -+osl_pktdup(osl_t *osh, void *skb) -+{ -+ void * p; -+ unsigned long irqflags; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ gfp_t flags; -+#endif -+ -+ -+ PKTCTFMAP(osh, skb); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -+ flags = (in_atomic() || in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL; -+ if ((p = skb_clone((struct sk_buff *)skb, flags)) == NULL) -+#else -+ if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL) -+#endif -+ return NULL; -+ -+#ifdef CTFPOOL -+ if (PKTISFAST(osh, skb)) { -+ ctfpool_t *ctfpool; -+ -+ -+ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); -+ ASSERT(ctfpool != NULL); -+ PKTCLRFAST(osh, p); -+ PKTCLRFAST(osh, skb); -+ ctfpool->refills++; -+ } -+#endif -+ -+ -+ if (osh->pub.pkttag) -+ bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ); -+ -+ -+ spin_lock_irqsave(&osh->pktalloc_lock, irqflags); -+ osh->pub.pktalloced++; -+ spin_unlock_irqrestore(&osh->pktalloc_lock, irqflags); -+ return (p); -+} -+ -+ -+ -+ -+ -+ -+ -+void * -+osl_os_open_image(char *filename) -+{ -+ struct file *fp; -+ -+ fp = filp_open(filename, O_RDONLY, 0); -+ -+ if (IS_ERR(fp)) -+ fp = NULL; -+ -+ return fp; -+} -+ -+int -+osl_os_get_image_block(char *buf, int len, void *image) -+{ -+ struct file *fp = (struct file *)image; -+ int rdlen; -+ -+ if (!image) -+ return 0; -+ -+ rdlen = kernel_read(fp, fp->f_pos, buf, len); -+ if (rdlen > 0) -+ fp->f_pos += rdlen; -+ -+ return rdlen; -+} -+ -+void -+osl_os_close_image(void *image) -+{ -+ if (image) -+ filp_close((struct file *)image, NULL); -+} -diff --git a/drivers/net/wireless/bcmdhd/sbutils.c b/drivers/net/wireless/bcmdhd/sbutils.c -new file mode 100644 -index 00000000..68cfcb27 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/sbutils.c -@@ -0,0 +1,1001 @@ -+/* -+ * Misc utility routines for accessing chip-specific features -+ * of the SiliconBackplane-based Broadcom chips. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: sbutils.c 310902 2012-01-26 19:45:33Z $ -+ */ -+ -+#include <bcm_cfg.h> -+#include <typedefs.h> -+#include <bcmdefs.h> -+#include <osl.h> -+#include <bcmutils.h> -+#include <siutils.h> -+#include <bcmdevs.h> -+#include <hndsoc.h> -+#include <sbchipc.h> -+#include <pcicfg.h> -+#include <sbpcmcia.h> -+ -+#include "siutils_priv.h" -+ -+ -+/* local prototypes */ -+static uint _sb_coreidx(si_info_t *sii, uint32 sba); -+static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, -+ uint ncores); -+static uint32 _sb_coresba(si_info_t *sii); -+static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); -+ -+#define SET_SBREG(sii, r, mask, val) \ -+ W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) -+#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF) -+ -+/* sonicsrev */ -+#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) -+#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) -+ -+#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) -+#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) -+#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) -+#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) -+ -+static uint32 -+sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) -+{ -+ uint8 tmp; -+ uint32 val, intr_val = 0; -+ -+ -+ /* -+ * compact flash only has 11 bits address, while we needs 12 bits address. -+ * MEM_SEG will be OR'd with other 11 bits address in hardware, -+ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). -+ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special -+ */ -+ if (PCMCIA(sii)) { -+ INTR_OFF(sii, intr_val); -+ tmp = 1; -+ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); -+ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ -+ } -+ -+ val = R_REG(sii->osh, sbr); -+ -+ if (PCMCIA(sii)) { -+ tmp = 0; -+ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); -+ INTR_RESTORE(sii, intr_val); -+ } -+ -+ return (val); -+} -+ -+static void -+sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) -+{ -+ uint8 tmp; -+ volatile uint32 dummy; -+ uint32 intr_val = 0; -+ -+ -+ /* -+ * compact flash only has 11 bits address, while we needs 12 bits address. -+ * MEM_SEG will be OR'd with other 11 bits address in hardware, -+ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). -+ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special -+ */ -+ if (PCMCIA(sii)) { -+ INTR_OFF(sii, intr_val); -+ tmp = 1; -+ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); -+ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ -+ } -+ -+ if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { -+ dummy = R_REG(sii->osh, sbr); -+ BCM_REFERENCE(dummy); -+ W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); -+ dummy = R_REG(sii->osh, sbr); -+ BCM_REFERENCE(dummy); -+ W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); -+ } else -+ W_REG(sii->osh, sbr, v); -+ -+ if (PCMCIA(sii)) { -+ tmp = 0; -+ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); -+ INTR_RESTORE(sii, intr_val); -+ } -+} -+ -+uint -+sb_coreid(si_t *sih) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); -+} -+ -+uint -+sb_intflag(si_t *sih) -+{ -+ si_info_t *sii; -+ void *corereg; -+ sbconfig_t *sb; -+ uint origidx, intflag, intr_val = 0; -+ -+ sii = SI_INFO(sih); -+ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ corereg = si_setcore(sih, CC_CORE_ID, 0); -+ ASSERT(corereg != NULL); -+ sb = REGS2SB(corereg); -+ intflag = R_SBREG(sii, &sb->sbflagst); -+ sb_setcoreidx(sih, origidx); -+ INTR_RESTORE(sii, intr_val); -+ -+ return intflag; -+} -+ -+uint -+sb_flag(si_t *sih) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; -+} -+ -+void -+sb_setint(si_t *sih, int siflag) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ uint32 vec; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ if (siflag == -1) -+ vec = 0; -+ else -+ vec = 1 << siflag; -+ W_SBREG(sii, &sb->sbintvec, vec); -+} -+ -+/* return core index of the core with address 'sba' */ -+static uint -+_sb_coreidx(si_info_t *sii, uint32 sba) -+{ -+ uint i; -+ -+ for (i = 0; i < sii->numcores; i ++) -+ if (sba == sii->coresba[i]) -+ return i; -+ return BADIDX; -+} -+ -+/* return core address of the current core */ -+static uint32 -+_sb_coresba(si_info_t *sii) -+{ -+ uint32 sbaddr; -+ -+ -+ switch (BUSTYPE(sii->pub.bustype)) { -+ case SI_BUS: { -+ sbconfig_t *sb = REGS2SB(sii->curmap); -+ sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); -+ break; -+ } -+ -+ case PCI_BUS: -+ sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); -+ break; -+ -+ case PCMCIA_BUS: { -+ uint8 tmp = 0; -+ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); -+ sbaddr = (uint32)tmp << 12; -+ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); -+ sbaddr |= (uint32)tmp << 16; -+ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); -+ sbaddr |= (uint32)tmp << 24; -+ break; -+ } -+ -+ case SPI_BUS: -+ case SDIO_BUS: -+ sbaddr = (uint32)(uintptr)sii->curmap; -+ break; -+ -+ -+ default: -+ sbaddr = BADCOREADDR; -+ break; -+ } -+ -+ return sbaddr; -+} -+ -+uint -+sb_corevendor(si_t *sih) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); -+} -+ -+uint -+sb_corerev(si_t *sih) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ uint sbidh; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ sbidh = R_SBREG(sii, &sb->sbidhigh); -+ -+ return (SBCOREREV(sbidh)); -+} -+ -+/* set core-specific control flags */ -+void -+sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ uint32 w; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ ASSERT((val & ~mask) == 0); -+ -+ /* mask and set */ -+ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | -+ (val << SBTML_SICF_SHIFT); -+ W_SBREG(sii, &sb->sbtmstatelow, w); -+} -+ -+/* set/clear core-specific control flags */ -+uint32 -+sb_core_cflags(si_t *sih, uint32 mask, uint32 val) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ uint32 w; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ ASSERT((val & ~mask) == 0); -+ -+ /* mask and set */ -+ if (mask || val) { -+ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | -+ (val << SBTML_SICF_SHIFT); -+ W_SBREG(sii, &sb->sbtmstatelow, w); -+ } -+ -+ /* return the new value -+ * for write operation, the following readback ensures the completion of write opration. -+ */ -+ return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); -+} -+ -+/* set/clear core-specific status flags */ -+uint32 -+sb_core_sflags(si_t *sih, uint32 mask, uint32 val) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ uint32 w; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ ASSERT((val & ~mask) == 0); -+ ASSERT((mask & ~SISF_CORE_BITS) == 0); -+ -+ /* mask and set */ -+ if (mask || val) { -+ w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | -+ (val << SBTMH_SISF_SHIFT); -+ W_SBREG(sii, &sb->sbtmstatehigh, w); -+ } -+ -+ /* return the new value */ -+ return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); -+} -+ -+bool -+sb_iscoreup(si_t *sih) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ return ((R_SBREG(sii, &sb->sbtmstatelow) & -+ (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == -+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); -+} -+ -+/* -+ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, -+ * switch back to the original core, and return the new value. -+ * -+ * When using the silicon backplane, no fidleing with interrupts or core switches are needed. -+ * -+ * Also, when using pci/pcie, we can optimize away the core switching for pci registers -+ * and (on newer pci cores) chipcommon registers. -+ */ -+uint -+sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -+{ -+ uint origidx = 0; -+ uint32 *r = NULL; -+ uint w; -+ uint intr_val = 0; -+ bool fast = FALSE; -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ ASSERT(GOODIDX(coreidx)); -+ ASSERT(regoff < SI_CORE_SIZE); -+ ASSERT((val & ~mask) == 0); -+ -+ if (coreidx >= SI_MAXCORES) -+ return 0; -+ -+ if (BUSTYPE(sii->pub.bustype) == SI_BUS) { -+ /* If internal bus, we can always get at everything */ -+ fast = TRUE; -+ /* map if does not exist */ -+ if (!sii->regs[coreidx]) { -+ sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx], -+ SI_CORE_SIZE); -+ ASSERT(GOODREGS(sii->regs[coreidx])); -+ } -+ r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff); -+ } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { -+ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ -+ -+ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { -+ /* Chipc registers are mapped at 12KB */ -+ -+ fast = TRUE; -+ r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff); -+ } else if (sii->pub.buscoreidx == coreidx) { -+ /* pci registers are at either in the last 2KB of an 8KB window -+ * or, in pcie and pci rev 13 at 8KB -+ */ -+ fast = TRUE; -+ if (SI_FAST(sii)) -+ r = (uint32 *)((char *)sii->curmap + -+ PCI_16KB0_PCIREGS_OFFSET + regoff); -+ else -+ r = (uint32 *)((char *)sii->curmap + -+ ((regoff >= SBCONFIGOFF) ? -+ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + -+ regoff); -+ } -+ } -+ -+ if (!fast) { -+ INTR_OFF(sii, intr_val); -+ -+ /* save current core index */ -+ origidx = si_coreidx(&sii->pub); -+ -+ /* switch core */ -+ r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff); -+ } -+ ASSERT(r != NULL); -+ -+ /* mask and set */ -+ if (mask || val) { -+ if (regoff >= SBCONFIGOFF) { -+ w = (R_SBREG(sii, r) & ~mask) | val; -+ W_SBREG(sii, r, w); -+ } else { -+ w = (R_REG(sii->osh, r) & ~mask) | val; -+ W_REG(sii->osh, r, w); -+ } -+ } -+ -+ /* readback */ -+ if (regoff >= SBCONFIGOFF) -+ w = R_SBREG(sii, r); -+ else { -+ if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) && -+ (coreidx == SI_CC_IDX) && -+ (regoff == OFFSETOF(chipcregs_t, watchdog))) { -+ w = val; -+ } else -+ w = R_REG(sii->osh, r); -+ } -+ -+ if (!fast) { -+ /* restore core index */ -+ if (origidx != coreidx) -+ sb_setcoreidx(&sii->pub, origidx); -+ -+ INTR_RESTORE(sii, intr_val); -+ } -+ -+ return (w); -+} -+ -+/* Scan the enumeration space to find all cores starting from the given -+ * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' -+ * is the default core address at chip POR time and 'regs' is the virtual -+ * address that the default core is mapped at. 'ncores' is the number of -+ * cores expected on bus 'sbba'. It returns the total number of cores -+ * starting from bus 'sbba', inclusive. -+ */ -+#define SB_MAXBUSES 2 -+static uint -+_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores) -+{ -+ uint next; -+ uint ncc = 0; -+ uint i; -+ -+ if (bus >= SB_MAXBUSES) { -+ SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus)); -+ return 0; -+ } -+ SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores)); -+ -+ /* Scan all cores on the bus starting from core 0. -+ * Core addresses must be contiguous on each bus. -+ */ -+ for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { -+ sii->coresba[next] = sbba + (i * SI_CORE_SIZE); -+ -+ /* keep and reuse the initial register mapping */ -+ if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (sii->coresba[next] == sba)) { -+ SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); -+ sii->regs[next] = regs; -+ } -+ -+ /* change core to 'next' and read its coreid */ -+ sii->curmap = _sb_setcoreidx(sii, next); -+ sii->curidx = next; -+ -+ sii->coreid[next] = sb_coreid(&sii->pub); -+ -+ /* core specific processing... */ -+ /* chipc provides # cores */ -+ if (sii->coreid[next] == CC_CORE_ID) { -+ chipcregs_t *cc = (chipcregs_t *)sii->curmap; -+ uint32 ccrev = sb_corerev(&sii->pub); -+ -+ /* determine numcores - this is the total # cores in the chip */ -+ if (((ccrev == 4) || (ccrev >= 6))) -+ numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> -+ CID_CC_SHIFT; -+ else { -+ /* Older chips */ -+ uint chip = CHIPID(sii->pub.chip); -+ -+ if (chip == BCM4306_CHIP_ID) /* < 4306c0 */ -+ numcores = 6; -+ else if (chip == BCM4704_CHIP_ID) -+ numcores = 9; -+ else if (chip == BCM5365_CHIP_ID) -+ numcores = 7; -+ else { -+ SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", -+ chip)); -+ ASSERT(0); -+ numcores = 1; -+ } -+ } -+ SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, -+ sii->pub.issim ? "QT" : "")); -+ } -+ /* scan bridged SB(s) and add results to the end of the list */ -+ else if (sii->coreid[next] == OCP_CORE_ID) { -+ sbconfig_t *sb = REGS2SB(sii->curmap); -+ uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); -+ uint nsbcc; -+ -+ sii->numcores = next + 1; -+ -+ if ((nsbba & 0xfff00000) != SI_ENUM_BASE) -+ continue; -+ nsbba &= 0xfffff000; -+ if (_sb_coreidx(sii, nsbba) != BADIDX) -+ continue; -+ -+ nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; -+ nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); -+ if (sbba == SI_ENUM_BASE) -+ numcores -= nsbcc; -+ ncc += nsbcc; -+ } -+ } -+ -+ SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba)); -+ -+ sii->numcores = i + ncc; -+ return sii->numcores; -+} -+ -+/* scan the sb enumerated space to identify all cores */ -+void -+sb_scan(si_t *sih, void *regs, uint devid) -+{ -+ si_info_t *sii; -+ uint32 origsba; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; -+ -+ /* Save the current core info and validate it later till we know -+ * for sure what is good and what is bad. -+ */ -+ origsba = _sb_coresba(sii); -+ -+ /* scan all SB(s) starting from SI_ENUM_BASE */ -+ sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); -+} -+ -+/* -+ * This function changes logical "focus" to the indicated core; -+ * must be called with interrupts off. -+ * Moreover, callers should keep interrupts off during switching out of and back to d11 core -+ */ -+void * -+sb_setcoreidx(si_t *sih, uint coreidx) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ if (coreidx >= sii->numcores) -+ return (NULL); -+ -+ /* -+ * If the user has provided an interrupt mask enabled function, -+ * then assert interrupts are disabled before switching the core. -+ */ -+ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); -+ -+ sii->curmap = _sb_setcoreidx(sii, coreidx); -+ sii->curidx = coreidx; -+ -+ return (sii->curmap); -+} -+ -+/* This function changes the logical "focus" to the indicated core. -+ * Return the current core's virtual address. -+ */ -+static void * -+_sb_setcoreidx(si_info_t *sii, uint coreidx) -+{ -+ uint32 sbaddr = sii->coresba[coreidx]; -+ void *regs; -+ -+ switch (BUSTYPE(sii->pub.bustype)) { -+ case SI_BUS: -+ /* map new one */ -+ if (!sii->regs[coreidx]) { -+ sii->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); -+ ASSERT(GOODREGS(sii->regs[coreidx])); -+ } -+ regs = sii->regs[coreidx]; -+ break; -+ -+ case PCI_BUS: -+ /* point bar0 window */ -+ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); -+ regs = sii->curmap; -+ break; -+ -+ case PCMCIA_BUS: { -+ uint8 tmp = (sbaddr >> 12) & 0x0f; -+ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); -+ tmp = (sbaddr >> 16) & 0xff; -+ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); -+ tmp = (sbaddr >> 24) & 0xff; -+ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); -+ regs = sii->curmap; -+ break; -+ } -+ case SPI_BUS: -+ case SDIO_BUS: -+ /* map new one */ -+ if (!sii->regs[coreidx]) { -+ sii->regs[coreidx] = (void *)(uintptr)sbaddr; -+ ASSERT(GOODREGS(sii->regs[coreidx])); -+ } -+ regs = sii->regs[coreidx]; -+ break; -+ -+ -+ default: -+ ASSERT(0); -+ regs = NULL; -+ break; -+ } -+ -+ return regs; -+} -+ -+/* Return the address of sbadmatch0/1/2/3 register */ -+static volatile uint32 * -+sb_admatch(si_info_t *sii, uint asidx) -+{ -+ sbconfig_t *sb; -+ volatile uint32 *addrm; -+ -+ sb = REGS2SB(sii->curmap); -+ -+ switch (asidx) { -+ case 0: -+ addrm = &sb->sbadmatch0; -+ break; -+ -+ case 1: -+ addrm = &sb->sbadmatch1; -+ break; -+ -+ case 2: -+ addrm = &sb->sbadmatch2; -+ break; -+ -+ case 3: -+ addrm = &sb->sbadmatch3; -+ break; -+ -+ default: -+ SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx)); -+ return 0; -+ } -+ -+ return (addrm); -+} -+ -+/* Return the number of address spaces in current core */ -+int -+sb_numaddrspaces(si_t *sih) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ sb = REGS2SB(sii->curmap); -+ -+ /* + 1 because of enumeration space */ -+ return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; -+} -+ -+/* Return the address of the nth address space in the current core */ -+uint32 -+sb_addrspace(si_t *sih, uint asidx) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); -+} -+ -+/* Return the size of the nth address space in the current core */ -+uint32 -+sb_addrspacesize(si_t *sih, uint asidx) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); -+} -+ -+ -+/* do buffered registers update */ -+void -+sb_commit(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ -+ sii = SI_INFO(sih); -+ -+ origidx = sii->curidx; -+ ASSERT(GOODIDX(origidx)); -+ -+ INTR_OFF(sii, intr_val); -+ -+ /* switch over to chipcommon core if there is one, else use pci */ -+ if (sii->pub.ccrev != NOREV) { -+ chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ ASSERT(ccregs != NULL); -+ -+ /* do the buffer registers update */ -+ W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); -+ W_REG(sii->osh, &ccregs->broadcastdata, 0x0); -+ } else -+ ASSERT(0); -+ -+ /* restore core index */ -+ sb_setcoreidx(sih, origidx); -+ INTR_RESTORE(sii, intr_val); -+} -+ -+void -+sb_core_disable(si_t *sih, uint32 bits) -+{ -+ si_info_t *sii; -+ volatile uint32 dummy; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ -+ ASSERT(GOODREGS(sii->curmap)); -+ sb = REGS2SB(sii->curmap); -+ -+ /* if core is already in reset, just return */ -+ if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) -+ return; -+ -+ /* if clocks are not enabled, put into reset and return */ -+ if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) -+ goto disable; -+ -+ /* set target reject and spin until busy is clear (preserve core-specific bits) */ -+ OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); -+ dummy = R_SBREG(sii, &sb->sbtmstatelow); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+ SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); -+ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) -+ SI_ERROR(("%s: target state still busy\n", __FUNCTION__)); -+ -+ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { -+ OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); -+ dummy = R_SBREG(sii, &sb->sbimstate); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+ SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); -+ } -+ -+ /* set reset and reject while enabling the clocks */ -+ W_SBREG(sii, &sb->sbtmstatelow, -+ (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | -+ SBTML_REJ | SBTML_RESET)); -+ dummy = R_SBREG(sii, &sb->sbtmstatelow); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(10); -+ -+ /* don't forget to clear the initiator reject bit */ -+ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) -+ AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); -+ -+disable: -+ /* leave reset and reject asserted */ -+ W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); -+ OSL_DELAY(1); -+} -+ -+/* reset and re-enable a core -+ * inputs: -+ * bits - core specific bits that are set during and after reset sequence -+ * resetbits - core specific bits that are set only during reset sequence -+ */ -+void -+sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -+{ -+ si_info_t *sii; -+ sbconfig_t *sb; -+ volatile uint32 dummy; -+ -+ sii = SI_INFO(sih); -+ ASSERT(GOODREGS(sii->curmap)); -+ sb = REGS2SB(sii->curmap); -+ -+ /* -+ * Must do the disable sequence first to work for arbitrary current core state. -+ */ -+ sb_core_disable(sih, (bits | resetbits)); -+ -+ /* -+ * Now do the initialization sequence. -+ */ -+ -+ /* set reset while enabling the clock and forcing them on throughout the core */ -+ W_SBREG(sii, &sb->sbtmstatelow, -+ (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | -+ SBTML_RESET)); -+ dummy = R_SBREG(sii, &sb->sbtmstatelow); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+ -+ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { -+ W_SBREG(sii, &sb->sbtmstatehigh, 0); -+ } -+ if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { -+ AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); -+ } -+ -+ /* clear reset and allow it to propagate throughout the core */ -+ W_SBREG(sii, &sb->sbtmstatelow, -+ ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); -+ dummy = R_SBREG(sii, &sb->sbtmstatelow); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+ -+ /* leave clock enabled */ -+ W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); -+ dummy = R_SBREG(sii, &sb->sbtmstatelow); -+ BCM_REFERENCE(dummy); -+ OSL_DELAY(1); -+} -+ -+/* -+ * Set the initiator timeout for the "master core". -+ * The master core is defined to be the core in control -+ * of the chip and so it issues accesses to non-memory -+ * locations (Because of dma *any* core can access memeory). -+ * -+ * The routine uses the bus to decide who is the master: -+ * SI_BUS => mips -+ * JTAG_BUS => chipc -+ * PCI_BUS => pci or pcie -+ * PCMCIA_BUS => pcmcia -+ * SDIO_BUS => pcmcia -+ * -+ * This routine exists so callers can disable initiator -+ * timeouts so accesses to very slow devices like otp -+ * won't cause an abort. The routine allows arbitrary -+ * settings of the service and request timeouts, though. -+ * -+ * Returns the timeout state before changing it or -1 -+ * on error. -+ */ -+ -+#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) -+ -+uint32 -+sb_set_initiator_to(si_t *sih, uint32 to, uint idx) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ uint32 tmp, ret = 0xffffffff; -+ sbconfig_t *sb; -+ -+ sii = SI_INFO(sih); -+ -+ if ((to & ~TO_MASK) != 0) -+ return ret; -+ -+ /* Figure out the master core */ -+ if (idx == BADIDX) { -+ switch (BUSTYPE(sii->pub.bustype)) { -+ case PCI_BUS: -+ idx = sii->pub.buscoreidx; -+ break; -+ case JTAG_BUS: -+ idx = SI_CC_IDX; -+ break; -+ case PCMCIA_BUS: -+ case SDIO_BUS: -+ idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); -+ break; -+ case SI_BUS: -+ idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); -+ break; -+ default: -+ ASSERT(0); -+ } -+ if (idx == BADIDX) -+ return ret; -+ } -+ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ sb = REGS2SB(sb_setcoreidx(sih, idx)); -+ -+ tmp = R_SBREG(sii, &sb->sbimconfiglow); -+ ret = tmp & TO_MASK; -+ W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); -+ -+ sb_commit(sih); -+ sb_setcoreidx(sih, origidx); -+ INTR_RESTORE(sii, intr_val); -+ return ret; -+} -+ -+uint32 -+sb_base(uint32 admatch) -+{ -+ uint32 base; -+ uint type; -+ -+ type = admatch & SBAM_TYPE_MASK; -+ ASSERT(type < 3); -+ -+ base = 0; -+ -+ if (type == 0) { -+ base = admatch & SBAM_BASE0_MASK; -+ } else if (type == 1) { -+ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ -+ base = admatch & SBAM_BASE1_MASK; -+ } else if (type == 2) { -+ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ -+ base = admatch & SBAM_BASE2_MASK; -+ } -+ -+ return (base); -+} -+ -+uint32 -+sb_size(uint32 admatch) -+{ -+ uint32 size; -+ uint type; -+ -+ type = admatch & SBAM_TYPE_MASK; -+ ASSERT(type < 3); -+ -+ size = 0; -+ -+ if (type == 0) { -+ size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); -+ } else if (type == 1) { -+ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ -+ size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); -+ } else if (type == 2) { -+ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ -+ size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); -+ } -+ -+ return (size); -+} -diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c -new file mode 100644 -index 00000000..fef3cbd2 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/siutils.c -@@ -0,0 +1,2466 @@ -+/* -+ * Misc utility routines for accessing chip-specific features -+ * of the SiliconBackplane-based Broadcom chips. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: siutils.c 347632 2012-07-27 11:00:35Z $ -+ */ -+ -+#include <bcm_cfg.h> -+#include <typedefs.h> -+#include <bcmdefs.h> -+#include <osl.h> -+#include <bcmutils.h> -+#include <siutils.h> -+#include <bcmdevs.h> -+#include <hndsoc.h> -+#include <sbchipc.h> -+#include <pcicfg.h> -+#include <sbpcmcia.h> -+#include <sbsocram.h> -+#include <bcmsdh.h> -+#include <sdio.h> -+#include <sbsdio.h> -+#include <sbhnddma.h> -+#include <sbsdpcmdev.h> -+#include <bcmsdpcm.h> -+#include <hndpmu.h> -+ -+#include "siutils_priv.h" -+ -+/* local prototypes */ -+static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, -+ uint bustype, void *sdh, char **vars, uint *varsz); -+static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); -+static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, -+ uint *origidx, void *regs); -+ -+ -+ -+/* global variable to indicate reservation/release of gpio's */ -+static uint32 si_gpioreservation = 0; -+ -+/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ -+ -+int do_4360_pcie2_war = 0; -+ -+/* -+ * Allocate a si handle. -+ * devid - pci device id (used to determine chip#) -+ * osh - opaque OS handle -+ * regs - virtual address of initial core registers -+ * bustype - pci/pcmcia/sb/sdio/etc -+ * vars - pointer to a pointer area for "environment" variables -+ * varsz - pointer to int to return the size of the vars -+ */ -+si_t * -+si_attach(uint devid, osl_t *osh, void *regs, -+ uint bustype, void *sdh, char **vars, uint *varsz) -+{ -+ si_info_t *sii; -+ -+ /* alloc si_info_t */ -+ if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) { -+ SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); -+ return (NULL); -+ } -+ -+ if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { -+ MFREE(osh, sii, sizeof(si_info_t)); -+ return (NULL); -+ } -+ sii->vars = vars ? *vars : NULL; -+ sii->varsz = varsz ? *varsz : 0; -+ -+ return (si_t *)sii; -+} -+ -+/* global kernel resource */ -+static si_info_t ksii; -+ -+static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ -+ -+/* generic kernel variant of si_attach() */ -+si_t * -+si_kattach(osl_t *osh) -+{ -+ static bool ksii_attached = FALSE; -+ -+ if (!ksii_attached) { -+ void *regs; -+ regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); -+ -+ if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, -+ SI_BUS, NULL, -+ osh != SI_OSH ? &ksii.vars : NULL, -+ osh != SI_OSH ? &ksii.varsz : NULL) == NULL) { -+ SI_ERROR(("si_kattach: si_doattach failed\n")); -+ REG_UNMAP(regs); -+ return NULL; -+ } -+ REG_UNMAP(regs); -+ -+ /* save ticks normalized to ms for si_watchdog_ms() */ -+ if (PMUCTL_ENAB(&ksii.pub)) { -+ /* based on 32KHz ILP clock */ -+ wd_msticks = 32; -+ } else { -+ wd_msticks = ALP_CLOCK / 1000; -+ } -+ -+ ksii_attached = TRUE; -+ SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n", -+ ksii.pub.ccrev, wd_msticks)); -+ } -+ -+ return &ksii.pub; -+} -+ -+ -+static bool -+si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) -+{ -+ /* need to set memseg flag for CF card first before any sb registers access */ -+ if (BUSTYPE(bustype) == PCMCIA_BUS) -+ sii->memseg = TRUE; -+ -+ -+ if (BUSTYPE(bustype) == SDIO_BUS) { -+ int err; -+ uint8 clkset; -+ -+ /* Try forcing SDIO core to do ALPAvail request only */ -+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); -+ if (!err) { -+ uint8 clkval; -+ -+ /* If register supported, wait for ALPAvail and then force ALP */ -+ clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); -+ if ((clkval & ~SBSDIO_AVBITS) == clkset) { -+ SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, -+ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), -+ PMU_MAX_TRANSITION_DLY); -+ if (!SBSDIO_ALPAV(clkval)) { -+ SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", -+ clkval)); -+ return FALSE; -+ } -+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, -+ clkset, &err); -+ OSL_DELAY(65); -+ } -+ } -+ -+ /* Also, disable the extra SDIO pull-ups */ -+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); -+ } -+ -+ -+ return TRUE; -+} -+ -+static bool -+si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, -+ uint *origidx, void *regs) -+{ -+ bool pci, pcie, pcie_gen2 = FALSE; -+ uint i; -+ uint pciidx, pcieidx, pcirev, pcierev; -+ -+ cc = si_setcoreidx(&sii->pub, SI_CC_IDX); -+ ASSERT((uintptr)cc); -+ -+ /* get chipcommon rev */ -+ sii->pub.ccrev = (int)si_corerev(&sii->pub); -+ -+ /* get chipcommon chipstatus */ -+ if (sii->pub.ccrev >= 11) -+ sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); -+ -+ /* get chipcommon capabilites */ -+ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); -+ /* get chipcommon extended capabilities */ -+ -+ if (sii->pub.ccrev >= 35) -+ sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); -+ -+ /* get pmu rev and caps */ -+ if (sii->pub.cccaps & CC_CAP_PMU) { -+ sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); -+ sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; -+ } -+ -+ SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", -+ sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, -+ sii->pub.pmucaps)); -+ -+ /* figure out bus/orignal core idx */ -+ sii->pub.buscoretype = NODEV_CORE_ID; -+ sii->pub.buscorerev = (uint)NOREV; -+ sii->pub.buscoreidx = BADIDX; -+ -+ pci = pcie = FALSE; -+ pcirev = pcierev = (uint)NOREV; -+ pciidx = pcieidx = BADIDX; -+ -+ for (i = 0; i < sii->numcores; i++) { -+ uint cid, crev; -+ -+ si_setcoreidx(&sii->pub, i); -+ cid = si_coreid(&sii->pub); -+ crev = si_corerev(&sii->pub); -+ -+ /* Display cores found */ -+ SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", -+ i, cid, crev, sii->coresba[i], sii->regs[i])); -+ -+ if (BUSTYPE(bustype) == PCI_BUS) { -+ if (cid == PCI_CORE_ID) { -+ pciidx = i; -+ pcirev = crev; -+ pci = TRUE; -+ } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { -+ pcieidx = i; -+ pcierev = crev; -+ pcie = TRUE; -+ if (cid == PCIE2_CORE_ID) -+ pcie_gen2 = TRUE; -+ } -+ } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && -+ (cid == PCMCIA_CORE_ID)) { -+ sii->pub.buscorerev = crev; -+ sii->pub.buscoretype = cid; -+ sii->pub.buscoreidx = i; -+ } -+ else if (((BUSTYPE(bustype) == SDIO_BUS) || -+ (BUSTYPE(bustype) == SPI_BUS)) && -+ ((cid == PCMCIA_CORE_ID) || -+ (cid == SDIOD_CORE_ID))) { -+ sii->pub.buscorerev = crev; -+ sii->pub.buscoretype = cid; -+ sii->pub.buscoreidx = i; -+ } -+ -+ /* find the core idx before entering this func. */ -+ if ((savewin && (savewin == sii->coresba[i])) || -+ (regs == sii->regs[i])) -+ *origidx = i; -+ } -+ -+ if (pci) { -+ sii->pub.buscoretype = PCI_CORE_ID; -+ sii->pub.buscorerev = pcirev; -+ sii->pub.buscoreidx = pciidx; -+ } else if (pcie) { -+ if (pcie_gen2) -+ sii->pub.buscoretype = PCIE2_CORE_ID; -+ else -+ sii->pub.buscoretype = PCIE_CORE_ID; -+ sii->pub.buscorerev = pcierev; -+ sii->pub.buscoreidx = pcieidx; -+ } -+ -+ SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, -+ sii->pub.buscorerev)); -+ -+ if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) && -+ (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3)) -+ OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL); -+ -+ -+ /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was -+ * already running. -+ */ -+ if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { -+ if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || -+ si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) -+ si_core_disable(&sii->pub, 0); -+ } -+ -+ /* return to the original core */ -+ si_setcoreidx(&sii->pub, *origidx); -+ -+ return TRUE; -+} -+ -+ -+ -+ -+static si_info_t * -+si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, -+ uint bustype, void *sdh, char **vars, uint *varsz) -+{ -+ struct si_pub *sih = &sii->pub; -+ uint32 w, savewin; -+ chipcregs_t *cc; -+ char *pvars = NULL; -+ uint origidx; -+ -+ ASSERT(GOODREGS(regs)); -+ -+ bzero((uchar*)sii, sizeof(si_info_t)); -+ -+ savewin = 0; -+ -+ sih->buscoreidx = BADIDX; -+ -+ sii->curmap = regs; -+ sii->sdh = sdh; -+ sii->osh = osh; -+ -+ -+ -+ /* find Chipcommon address */ -+ if (bustype == PCI_BUS) { -+ savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); -+ if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) -+ savewin = SI_ENUM_BASE; -+ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); -+ if (!regs) -+ return NULL; -+ cc = (chipcregs_t *)regs; -+ } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { -+ cc = (chipcregs_t *)sii->curmap; -+ } else { -+ cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); -+ } -+ -+ sih->bustype = bustype; -+ if (bustype != BUSTYPE(bustype)) { -+ SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", -+ bustype, BUSTYPE(bustype))); -+ return NULL; -+ } -+ -+ /* bus/core/clk setup for register access */ -+ if (!si_buscore_prep(sii, bustype, devid, sdh)) { -+ SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); -+ return NULL; -+ } -+ -+ /* ChipID recognition. -+ * We assume we can read chipid at offset 0 from the regs arg. -+ * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), -+ * some way of recognizing them needs to be added here. -+ */ -+ if (!cc) { -+ SI_ERROR(("%s: chipcommon register space is null \n", __FUNCTION__)); -+ return NULL; -+ } -+ w = R_REG(osh, &cc->chipid); -+ sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; -+ /* Might as wll fill in chip id rev & pkg */ -+ sih->chip = w & CID_ID_MASK; -+ sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; -+ sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; -+ -+ if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && -+ (sih->chippkg != BCM4329_289PIN_PKG_ID)) { -+ sih->chippkg = BCM4329_182PIN_PKG_ID; -+ } -+ sih->issim = IS_SIM(sih->chippkg); -+ -+ /* scan for cores */ -+ if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { -+ SI_MSG(("Found chip type SB (0x%08x)\n", w)); -+ sb_scan(&sii->pub, regs, devid); -+ } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { -+ SI_MSG(("Found chip type AI (0x%08x)\n", w)); -+ /* pass chipc address instead of original core base */ -+ ai_scan(&sii->pub, (void *)(uintptr)cc, devid); -+ } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { -+ SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); -+ /* pass chipc address instead of original core base */ -+ ub_scan(&sii->pub, (void *)(uintptr)cc, devid); -+ } else { -+ SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); -+ return NULL; -+ } -+ /* no cores found, bail out */ -+ if (sii->numcores == 0) { -+ SI_ERROR(("si_doattach: could not find any cores\n")); -+ return NULL; -+ } -+ /* bus/core/clk setup */ -+ origidx = SI_CC_IDX; -+ if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { -+ SI_ERROR(("si_doattach: si_buscore_setup failed\n")); -+ goto exit; -+ } -+ -+ if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK) -+ >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT | -+ CST4322_SPROM_PRESENT))) { -+ SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__)); -+ return NULL; -+ } -+ -+ /* assume current core is CC */ -+ if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || -+ CHIPID(sih->chip) == BCM43235_CHIP_ID || -+ CHIPID(sih->chip) == BCM43234_CHIP_ID || -+ CHIPID(sih->chip) == BCM43238_CHIP_ID) && -+ (CHIPREV(sii->pub.chiprev) <= 2))) { -+ -+ if ((cc->chipstatus & CST43236_BP_CLK) != 0) { -+ uint clkdiv; -+ clkdiv = R_REG(osh, &cc->clkdiv); -+ /* otp_clk_div is even number, 120/14 < 9mhz */ -+ clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); -+ W_REG(osh, &cc->clkdiv, clkdiv); -+ SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); -+ } -+ OSL_DELAY(10); -+ } -+ -+ if (bustype == PCI_BUS) { -+ -+ } -+ -+ pvars = NULL; -+ BCM_REFERENCE(pvars); -+ -+ -+ -+ if (sii->pub.ccrev >= 20) { -+ uint32 gpiopullup = 0, gpiopulldown = 0; -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ ASSERT(cc != NULL); -+ -+ /* 4314/43142 has pin muxing, don't clear gpio bits */ -+ if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || -+ (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { -+ gpiopullup |= 0x402e0; -+ gpiopulldown |= 0x20500; -+ } -+ -+ W_REG(osh, &cc->gpiopullup, gpiopullup); -+ W_REG(osh, &cc->gpiopulldown, gpiopulldown); -+ si_setcoreidx(sih, origidx); -+ } -+ -+ -+ /* clear any previous epidiag-induced target abort */ -+ ASSERT(!si_taclear(sih, FALSE)); -+ -+ return (sii); -+ -+exit: -+ -+ return NULL; -+} -+ -+/* may be called with core in reset */ -+void -+si_detach(si_t *sih) -+{ -+ si_info_t *sii; -+ uint idx; -+ -+ -+ sii = SI_INFO(sih); -+ -+ if (sii == NULL) -+ return; -+ -+ if (BUSTYPE(sih->bustype) == SI_BUS) -+ for (idx = 0; idx < SI_MAXCORES; idx++) -+ if (sii->regs[idx]) { -+ REG_UNMAP(sii->regs[idx]); -+ sii->regs[idx] = NULL; -+ } -+ -+ -+ -+#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) -+ if (sii != &ksii) -+#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ -+ MFREE(sii->osh, sii, sizeof(si_info_t)); -+} -+ -+void * -+si_osh(si_t *sih) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ return sii->osh; -+} -+ -+void -+si_setosh(si_t *sih, osl_t *osh) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ if (sii->osh != NULL) { -+ SI_ERROR(("osh is already set....\n")); -+ ASSERT(!sii->osh); -+ } -+ sii->osh = osh; -+} -+ -+/* register driver interrupt disabling and restoring callback functions */ -+void -+si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, -+ void *intrsenabled_fn, void *intr_arg) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ sii->intr_arg = intr_arg; -+ sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn; -+ sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn; -+ sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn; -+ /* save current core id. when this function called, the current core -+ * must be the core which provides driver functions(il, et, wl, etc.) -+ */ -+ sii->dev_coreid = sii->coreid[sii->curidx]; -+} -+ -+void -+si_deregister_intr_callback(si_t *sih) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ sii->intrsoff_fn = NULL; -+} -+ -+uint -+si_intflag(si_t *sih) -+{ -+ si_info_t *sii = SI_INFO(sih); -+ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_intflag(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return R_REG(sii->osh, ((uint32 *)(uintptr) -+ (sii->oob_router + OOB_STATUSA))); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+uint -+si_flag(si_t *sih) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_flag(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_flag(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_flag(sih); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+void -+si_setint(si_t *sih, int siflag) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ sb_setint(sih, siflag); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ ai_setint(sih, siflag); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ ub_setint(sih, siflag); -+ else -+ ASSERT(0); -+} -+ -+uint -+si_coreid(si_t *sih) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ return sii->coreid[sii->curidx]; -+} -+ -+uint -+si_coreidx(si_t *sih) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ return sii->curidx; -+} -+ -+/* return the core-type instantiation # of the current core */ -+uint -+si_coreunit(si_t *sih) -+{ -+ si_info_t *sii; -+ uint idx; -+ uint coreid; -+ uint coreunit; -+ uint i; -+ -+ sii = SI_INFO(sih); -+ coreunit = 0; -+ -+ idx = sii->curidx; -+ -+ ASSERT(GOODREGS(sii->curmap)); -+ coreid = si_coreid(sih); -+ -+ /* count the cores of our type */ -+ for (i = 0; i < idx; i++) -+ if (sii->coreid[i] == coreid) -+ coreunit++; -+ -+ return (coreunit); -+} -+ -+uint -+si_corevendor(si_t *sih) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_corevendor(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_corevendor(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_corevendor(sih); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+bool -+si_backplane64(si_t *sih) -+{ -+ return ((sih->cccaps & CC_CAP_BKPLN64) != 0); -+} -+ -+uint -+si_corerev(si_t *sih) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_corerev(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_corerev(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_corerev(sih); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+/* return index of coreid or BADIDX if not found */ -+uint -+si_findcoreidx(si_t *sih, uint coreid, uint coreunit) -+{ -+ si_info_t *sii; -+ uint found; -+ uint i; -+ -+ sii = SI_INFO(sih); -+ -+ found = 0; -+ -+ for (i = 0; i < sii->numcores; i++) -+ if (sii->coreid[i] == coreid) { -+ if (found == coreunit) -+ return (i); -+ found++; -+ } -+ -+ return (BADIDX); -+} -+ -+/* return list of found cores */ -+uint -+si_corelist(si_t *sih, uint coreid[]) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ bcopy((uchar*)sii->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); -+ return (sii->numcores); -+} -+ -+/* return current register mapping */ -+void * -+si_coreregs(si_t *sih) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ ASSERT(GOODREGS(sii->curmap)); -+ -+ return (sii->curmap); -+} -+ -+/* -+ * This function changes logical "focus" to the indicated core; -+ * must be called with interrupts off. -+ * Moreover, callers should keep interrupts off during switching out of and back to d11 core -+ */ -+void * -+si_setcore(si_t *sih, uint coreid, uint coreunit) -+{ -+ uint idx; -+ -+ idx = si_findcoreidx(sih, coreid, coreunit); -+ if (!GOODIDX(idx)) -+ return (NULL); -+ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_setcoreidx(sih, idx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_setcoreidx(sih, idx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_setcoreidx(sih, idx); -+ else { -+ ASSERT(0); -+ return NULL; -+ } -+} -+ -+void * -+si_setcoreidx(si_t *sih, uint coreidx) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_setcoreidx(sih, coreidx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_setcoreidx(sih, coreidx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_setcoreidx(sih, coreidx); -+ else { -+ ASSERT(0); -+ return NULL; -+ } -+} -+ -+/* Turn off interrupt as required by sb_setcore, before switch core */ -+void * -+si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) -+{ -+ void *cc; -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ if (SI_FAST(sii)) { -+ /* Overloading the origidx variable to remember the coreid, -+ * this works because the core ids cannot be confused with -+ * core indices. -+ */ -+ *origidx = coreid; -+ if (coreid == CC_CORE_ID) -+ return (void *)CCREGS_FAST(sii); -+ else if (coreid == sih->buscoretype) -+ return (void *)PCIEREGS(sii); -+ } -+ INTR_OFF(sii, *intr_val); -+ *origidx = sii->curidx; -+ cc = si_setcore(sih, coreid, 0); -+ ASSERT(cc != NULL); -+ -+ return cc; -+} -+ -+/* restore coreidx and restore interrupt */ -+void -+si_restore_core(si_t *sih, uint coreid, uint intr_val) -+{ -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) -+ return; -+ -+ si_setcoreidx(sih, coreid); -+ INTR_RESTORE(sii, intr_val); -+} -+ -+int -+si_numaddrspaces(si_t *sih) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_numaddrspaces(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_numaddrspaces(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_numaddrspaces(sih); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+uint32 -+si_addrspace(si_t *sih, uint asidx) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_addrspace(sih, asidx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_addrspace(sih, asidx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_addrspace(sih, asidx); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+uint32 -+si_addrspacesize(si_t *sih, uint asidx) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_addrspacesize(sih, asidx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_addrspacesize(sih, asidx); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_addrspacesize(sih, asidx); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+void -+si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) -+{ -+ /* Only supported for SOCI_AI */ -+ if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ ai_coreaddrspaceX(sih, asidx, addr, size); -+ else -+ *size = 0; -+} -+ -+uint32 -+si_core_cflags(si_t *sih, uint32 mask, uint32 val) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_core_cflags(sih, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_core_cflags(sih, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_core_cflags(sih, mask, val); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+void -+si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ sb_core_cflags_wo(sih, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ ai_core_cflags_wo(sih, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ ub_core_cflags_wo(sih, mask, val); -+ else -+ ASSERT(0); -+} -+ -+uint32 -+si_core_sflags(si_t *sih, uint32 mask, uint32 val) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_core_sflags(sih, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_core_sflags(sih, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_core_sflags(sih, mask, val); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+bool -+si_iscoreup(si_t *sih) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_iscoreup(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_iscoreup(sih); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_iscoreup(sih); -+ else { -+ ASSERT(0); -+ return FALSE; -+ } -+} -+ -+uint -+si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) -+{ -+ /* only for AI back plane chips */ -+ if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return (ai_wrap_reg(sih, offset, mask, val)); -+ return 0; -+} -+ -+uint -+si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ return sb_corereg(sih, coreidx, regoff, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ return ai_corereg(sih, coreidx, regoff, mask, val); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ return ub_corereg(sih, coreidx, regoff, mask, val); -+ else { -+ ASSERT(0); -+ return 0; -+ } -+} -+ -+void -+si_core_disable(si_t *sih, uint32 bits) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ sb_core_disable(sih, bits); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ ai_core_disable(sih, bits); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ ub_core_disable(sih, bits); -+} -+ -+void -+si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -+{ -+ if (CHIPTYPE(sih->socitype) == SOCI_SB) -+ sb_core_reset(sih, bits, resetbits); -+ else if (CHIPTYPE(sih->socitype) == SOCI_AI) -+ ai_core_reset(sih, bits, resetbits); -+ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) -+ ub_core_reset(sih, bits, resetbits); -+} -+ -+/* Run bist on current core. Caller needs to take care of core-specific bist hazards */ -+int -+si_corebist(si_t *sih) -+{ -+ uint32 cflags; -+ int result = 0; -+ -+ /* Read core control flags */ -+ cflags = si_core_cflags(sih, 0, 0); -+ -+ /* Set bist & fgc */ -+ si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); -+ -+ /* Wait for bist done */ -+ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); -+ -+ if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) -+ result = BCME_ERROR; -+ -+ /* Reset core control flags */ -+ si_core_cflags(sih, 0xffff, cflags); -+ -+ return result; -+} -+ -+static uint32 -+factor6(uint32 x) -+{ -+ switch (x) { -+ case CC_F6_2: return 2; -+ case CC_F6_3: return 3; -+ case CC_F6_4: return 4; -+ case CC_F6_5: return 5; -+ case CC_F6_6: return 6; -+ case CC_F6_7: return 7; -+ default: return 0; -+ } -+} -+ -+/* calculate the speed the SI would run at given a set of clockcontrol values */ -+uint32 -+si_clock_rate(uint32 pll_type, uint32 n, uint32 m) -+{ -+ uint32 n1, n2, clock, m1, m2, m3, mc; -+ -+ n1 = n & CN_N1_MASK; -+ n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; -+ -+ if (pll_type == PLL_TYPE6) { -+ if (m & CC_T6_MMASK) -+ return CC_T6_M1; -+ else -+ return CC_T6_M0; -+ } else if ((pll_type == PLL_TYPE1) || -+ (pll_type == PLL_TYPE3) || -+ (pll_type == PLL_TYPE4) || -+ (pll_type == PLL_TYPE7)) { -+ n1 = factor6(n1); -+ n2 += CC_F5_BIAS; -+ } else if (pll_type == PLL_TYPE2) { -+ n1 += CC_T2_BIAS; -+ n2 += CC_T2_BIAS; -+ ASSERT((n1 >= 2) && (n1 <= 7)); -+ ASSERT((n2 >= 5) && (n2 <= 23)); -+ } else if (pll_type == PLL_TYPE5) { -+ return (100000000); -+ } else -+ ASSERT(0); -+ /* PLL types 3 and 7 use BASE2 (25Mhz) */ -+ if ((pll_type == PLL_TYPE3) || -+ (pll_type == PLL_TYPE7)) { -+ clock = CC_CLOCK_BASE2 * n1 * n2; -+ } else -+ clock = CC_CLOCK_BASE1 * n1 * n2; -+ -+ if (clock == 0) -+ return 0; -+ -+ m1 = m & CC_M1_MASK; -+ m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; -+ m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; -+ mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; -+ -+ if ((pll_type == PLL_TYPE1) || -+ (pll_type == PLL_TYPE3) || -+ (pll_type == PLL_TYPE4) || -+ (pll_type == PLL_TYPE7)) { -+ m1 = factor6(m1); -+ if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) -+ m2 += CC_F5_BIAS; -+ else -+ m2 = factor6(m2); -+ m3 = factor6(m3); -+ -+ switch (mc) { -+ case CC_MC_BYPASS: return (clock); -+ case CC_MC_M1: return (clock / m1); -+ case CC_MC_M1M2: return (clock / (m1 * m2)); -+ case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); -+ case CC_MC_M1M3: return (clock / (m1 * m3)); -+ default: return (0); -+ } -+ } else { -+ ASSERT(pll_type == PLL_TYPE2); -+ -+ m1 += CC_T2_BIAS; -+ m2 += CC_T2M2_BIAS; -+ m3 += CC_T2_BIAS; -+ ASSERT((m1 >= 2) && (m1 <= 7)); -+ ASSERT((m2 >= 3) && (m2 <= 10)); -+ ASSERT((m3 >= 2) && (m3 <= 7)); -+ -+ if ((mc & CC_T2MC_M1BYP) == 0) -+ clock /= m1; -+ if ((mc & CC_T2MC_M2BYP) == 0) -+ clock /= m2; -+ if ((mc & CC_T2MC_M3BYP) == 0) -+ clock /= m3; -+ -+ return (clock); -+ } -+} -+ -+ -+/* set chip watchdog reset timer to fire in 'ticks' */ -+void -+si_watchdog(si_t *sih, uint ticks) -+{ -+ uint nb, maxt; -+ -+ if (PMUCTL_ENAB(sih)) { -+ -+ if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && -+ (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { -+ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2); -+ si_setcore(sih, USB20D_CORE_ID, 0); -+ si_core_disable(sih, 1); -+ si_setcore(sih, CC_CORE_ID, 0); -+ } -+ -+ nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); -+ /* The mips compiler uses the sllv instruction, -+ * so we specially handle the 32-bit case. -+ */ -+ if (nb == 32) -+ maxt = 0xffffffff; -+ else -+ maxt = ((1 << nb) - 1); -+ -+ if (ticks == 1) -+ ticks = 2; -+ else if (ticks > maxt) -+ ticks = maxt; -+ -+ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks); -+ } else { -+ maxt = (1 << 28) - 1; -+ if (ticks > maxt) -+ ticks = maxt; -+ -+ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); -+ } -+} -+ -+/* trigger watchdog reset after ms milliseconds */ -+void -+si_watchdog_ms(si_t *sih, uint32 ms) -+{ -+ si_watchdog(sih, wd_msticks * ms); -+} -+ -+uint32 si_watchdog_msticks(void) -+{ -+ return wd_msticks; -+} -+ -+bool -+si_taclear(si_t *sih, bool details) -+{ -+ return FALSE; -+} -+ -+ -+ -+/* return the slow clock source - LPO, XTAL, or PCI */ -+static uint -+si_slowclk_src(si_info_t *sii) -+{ -+ chipcregs_t *cc; -+ -+ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); -+ -+ if (sii->pub.ccrev < 6) { -+ if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && -+ (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & -+ PCI_CFG_GPIO_SCS)) -+ return (SCC_SS_PCI); -+ else -+ return (SCC_SS_XTAL); -+ } else if (sii->pub.ccrev < 10) { -+ cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); -+ return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); -+ } else /* Insta-clock */ -+ return (SCC_SS_XTAL); -+} -+ -+/* return the ILP (slowclock) min or max frequency */ -+static uint -+si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) -+{ -+ uint32 slowclk; -+ uint div; -+ -+ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); -+ -+ /* shouldn't be here unless we've established the chip has dynamic clk control */ -+ ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); -+ -+ slowclk = si_slowclk_src(sii); -+ if (sii->pub.ccrev < 6) { -+ if (slowclk == SCC_SS_PCI) -+ return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64)); -+ else -+ return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32)); -+ } else if (sii->pub.ccrev < 10) { -+ div = 4 * -+ (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); -+ if (slowclk == SCC_SS_LPO) -+ return (max_freq ? LPOMAXFREQ : LPOMINFREQ); -+ else if (slowclk == SCC_SS_XTAL) -+ return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div)); -+ else if (slowclk == SCC_SS_PCI) -+ return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div)); -+ else -+ ASSERT(0); -+ } else { -+ /* Chipc rev 10 is InstaClock */ -+ div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; -+ div = 4 * (div + 1); -+ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); -+ } -+ return (0); -+} -+ -+static void -+si_clkctl_setdelay(si_info_t *sii, void *chipcregs) -+{ -+ chipcregs_t *cc = (chipcregs_t *)chipcregs; -+ uint slowmaxfreq, pll_delay, slowclk; -+ uint pll_on_delay, fref_sel_delay; -+ -+ pll_delay = PLL_DELAY; -+ -+ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay -+ * since the xtal will also be powered down by dynamic clk control logic. -+ */ -+ -+ slowclk = si_slowclk_src(sii); -+ if (slowclk != SCC_SS_XTAL) -+ pll_delay += XTAL_ON_DELAY; -+ -+ /* Starting with 4318 it is ILP that is used for the delays */ -+ slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc); -+ -+ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; -+ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; -+ -+ W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay); -+ W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); -+} -+ -+/* initialize power control delay registers */ -+void -+si_clkctl_init(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx = 0; -+ chipcregs_t *cc; -+ bool fast; -+ -+ if (!CCCTL_ENAB(sih)) -+ return; -+ -+ sii = SI_INFO(sih); -+ fast = SI_FAST(sii); -+ if (!fast) { -+ origidx = sii->curidx; -+ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) -+ return; -+ } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) -+ return; -+ ASSERT(cc != NULL); -+ -+ /* set all Instaclk chip ILP to 1 MHz */ -+ if (sih->ccrev >= 10) -+ SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, -+ (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); -+ -+ si_clkctl_setdelay(sii, (void *)(uintptr)cc); -+ -+ if (!fast) -+ si_setcoreidx(sih, origidx); -+} -+ -+ -+/* change logical "focus" to the gpio core for optimized access */ -+void * -+si_gpiosetcore(si_t *sih) -+{ -+ return (si_setcoreidx(sih, SI_CC_IDX)); -+} -+ -+/* -+ * mask & set gpiocontrol bits. -+ * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. -+ * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated -+ * to some chip-specific purpose. -+ */ -+uint32 -+si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority) -+{ -+ uint regoff; -+ -+ regoff = 0; -+ -+ /* gpios could be shared on router platforms -+ * ignore reservation if it's high priority (e.g., test apps) -+ */ -+ if ((priority != GPIO_HI_PRIORITY) && -+ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { -+ mask = priority ? (si_gpioreservation & mask) : -+ ((si_gpioreservation | mask) & ~(si_gpioreservation)); -+ val &= mask; -+ } -+ -+ regoff = OFFSETOF(chipcregs_t, gpiocontrol); -+ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -+} -+ -+/* mask&set gpio output enable bits */ -+uint32 -+si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority) -+{ -+ uint regoff; -+ -+ regoff = 0; -+ -+ /* gpios could be shared on router platforms -+ * ignore reservation if it's high priority (e.g., test apps) -+ */ -+ if ((priority != GPIO_HI_PRIORITY) && -+ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { -+ mask = priority ? (si_gpioreservation & mask) : -+ ((si_gpioreservation | mask) & ~(si_gpioreservation)); -+ val &= mask; -+ } -+ -+ regoff = OFFSETOF(chipcregs_t, gpioouten); -+ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -+} -+ -+/* mask&set gpio output bits */ -+uint32 -+si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority) -+{ -+ uint regoff; -+ -+ regoff = 0; -+ -+ /* gpios could be shared on router platforms -+ * ignore reservation if it's high priority (e.g., test apps) -+ */ -+ if ((priority != GPIO_HI_PRIORITY) && -+ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { -+ mask = priority ? (si_gpioreservation & mask) : -+ ((si_gpioreservation | mask) & ~(si_gpioreservation)); -+ val &= mask; -+ } -+ -+ regoff = OFFSETOF(chipcregs_t, gpioout); -+ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -+} -+ -+/* reserve one gpio */ -+uint32 -+si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) -+{ -+ /* only cores on SI_BUS share GPIO's and only applcation users need to -+ * reserve/release GPIO -+ */ -+ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { -+ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); -+ return 0xffffffff; -+ } -+ /* make sure only one bit is set */ -+ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { -+ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); -+ return 0xffffffff; -+ } -+ -+ /* already reserved */ -+ if (si_gpioreservation & gpio_bitmask) -+ return 0xffffffff; -+ /* set reservation */ -+ si_gpioreservation |= gpio_bitmask; -+ -+ return si_gpioreservation; -+} -+ -+/* release one gpio */ -+/* -+ * releasing the gpio doesn't change the current value on the GPIO last write value -+ * persists till some one overwrites it -+ */ -+ -+uint32 -+si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) -+{ -+ /* only cores on SI_BUS share GPIO's and only applcation users need to -+ * reserve/release GPIO -+ */ -+ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { -+ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); -+ return 0xffffffff; -+ } -+ /* make sure only one bit is set */ -+ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { -+ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); -+ return 0xffffffff; -+ } -+ -+ /* already released */ -+ if (!(si_gpioreservation & gpio_bitmask)) -+ return 0xffffffff; -+ -+ /* clear reservation */ -+ si_gpioreservation &= ~gpio_bitmask; -+ -+ return si_gpioreservation; -+} -+ -+/* return the current gpioin register value */ -+uint32 -+si_gpioin(si_t *sih) -+{ -+ uint regoff; -+ -+ regoff = OFFSETOF(chipcregs_t, gpioin); -+ return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); -+} -+ -+/* mask&set gpio interrupt polarity bits */ -+uint32 -+si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) -+{ -+ uint regoff; -+ -+ /* gpios could be shared on router platforms */ -+ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { -+ mask = priority ? (si_gpioreservation & mask) : -+ ((si_gpioreservation | mask) & ~(si_gpioreservation)); -+ val &= mask; -+ } -+ -+ regoff = OFFSETOF(chipcregs_t, gpiointpolarity); -+ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -+} -+ -+/* mask&set gpio interrupt mask bits */ -+uint32 -+si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) -+{ -+ uint regoff; -+ -+ /* gpios could be shared on router platforms */ -+ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { -+ mask = priority ? (si_gpioreservation & mask) : -+ ((si_gpioreservation | mask) & ~(si_gpioreservation)); -+ val &= mask; -+ } -+ -+ regoff = OFFSETOF(chipcregs_t, gpiointmask); -+ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); -+} -+ -+/* assign the gpio to an led */ -+uint32 -+si_gpioled(si_t *sih, uint32 mask, uint32 val) -+{ -+ if (sih->ccrev < 16) -+ return 0xffffffff; -+ -+ /* gpio led powersave reg */ -+ return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); -+} -+ -+/* mask&set gpio timer val */ -+uint32 -+si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) -+{ -+ if (sih->ccrev < 16) -+ return 0xffffffff; -+ -+ return (si_corereg(sih, SI_CC_IDX, -+ OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); -+} -+ -+uint32 -+si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) -+{ -+ uint offs; -+ -+ if (sih->ccrev < 20) -+ return 0xffffffff; -+ -+ offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); -+ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); -+} -+ -+uint32 -+si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) -+{ -+ uint offs; -+ -+ if (sih->ccrev < 11) -+ return 0xffffffff; -+ -+ if (regtype == GPIO_REGEVT) -+ offs = OFFSETOF(chipcregs_t, gpioevent); -+ else if (regtype == GPIO_REGEVT_INTMSK) -+ offs = OFFSETOF(chipcregs_t, gpioeventintmask); -+ else if (regtype == GPIO_REGEVT_INTPOL) -+ offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); -+ else -+ return 0xffffffff; -+ -+ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); -+} -+ -+void * -+si_gpio_handler_register(si_t *sih, uint32 event, -+ bool level, gpio_handler_t cb, void *arg) -+{ -+ si_info_t *sii; -+ gpioh_item_t *gi; -+ -+ ASSERT(event); -+ ASSERT(cb != NULL); -+ -+ sii = SI_INFO(sih); -+ if (sih->ccrev < 11) -+ return NULL; -+ -+ if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL) -+ return NULL; -+ -+ bzero(gi, sizeof(gpioh_item_t)); -+ gi->event = event; -+ gi->handler = cb; -+ gi->arg = arg; -+ gi->level = level; -+ -+ gi->next = sii->gpioh_head; -+ sii->gpioh_head = gi; -+ -+ return (void *)(gi); -+} -+ -+void -+si_gpio_handler_unregister(si_t *sih, void *gpioh) -+{ -+ si_info_t *sii; -+ gpioh_item_t *p, *n; -+ -+ sii = SI_INFO(sih); -+ if (sih->ccrev < 11) -+ return; -+ -+ ASSERT(sii->gpioh_head != NULL); -+ if ((void*)sii->gpioh_head == gpioh) { -+ sii->gpioh_head = sii->gpioh_head->next; -+ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); -+ return; -+ } else { -+ p = sii->gpioh_head; -+ n = p->next; -+ while (n) { -+ if ((void*)n == gpioh) { -+ p->next = n->next; -+ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t)); -+ return; -+ } -+ p = n; -+ n = n->next; -+ } -+ } -+ -+ ASSERT(0); /* Not found in list */ -+} -+ -+void -+si_gpio_handler_process(si_t *sih) -+{ -+ si_info_t *sii; -+ gpioh_item_t *h; -+ uint32 level = si_gpioin(sih); -+ uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0); -+ uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0); -+ uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0); -+ -+ sii = SI_INFO(sih); -+ for (h = sii->gpioh_head; h != NULL; h = h->next) { -+ if (h->handler) { -+ uint32 status = (h->level ? level : edge) & h->event; -+ uint32 polarity = (h->level ? levelp : edgep) & h->event; -+ -+ /* polarity bitval is opposite of status bitval */ -+ if (status ^ polarity) -+ h->handler(status, h->arg); -+ } -+ } -+ -+ si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */ -+} -+ -+uint32 -+si_gpio_int_enable(si_t *sih, bool enable) -+{ -+ uint offs; -+ -+ if (sih->ccrev < 11) -+ return 0xffffffff; -+ -+ offs = OFFSETOF(chipcregs_t, intmask); -+ return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); -+} -+ -+ -+/* Return the size of the specified SOCRAM bank */ -+static uint -+socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) -+{ -+ uint banksize, bankinfo; -+ uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); -+ -+ ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); -+ -+ W_REG(sii->osh, ®s->bankidx, bankidx); -+ bankinfo = R_REG(sii->osh, ®s->bankinfo); -+ banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); -+ return banksize; -+} -+ -+void -+si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ sbsocramregs_t *regs; -+ bool wasup; -+ uint corerev; -+ -+ sii = SI_INFO(sih); -+ -+ /* Block ints and save current core */ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ if (!set) -+ *enable = *protect = *remap = 0; -+ -+ /* Switch to SOCRAM core */ -+ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) -+ goto done; -+ -+ /* Get info for determining size */ -+ if (!(wasup = si_iscoreup(sih))) -+ si_core_reset(sih, 0, 0); -+ -+ corerev = si_corerev(sih); -+ if (corerev >= 10) { -+ uint32 extcinfo; -+ uint8 nb; -+ uint8 i; -+ uint32 bankidx, bankinfo; -+ -+ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); -+ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); -+ for (i = 0; i < nb; i++) { -+ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); -+ W_REG(sii->osh, ®s->bankidx, bankidx); -+ bankinfo = R_REG(sii->osh, ®s->bankinfo); -+ if (set) { -+ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; -+ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; -+ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; -+ if (*enable) { -+ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); -+ if (*protect) -+ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); -+ if ((corerev >= 16) && *remap) -+ bankinfo |= -+ (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); -+ } -+ W_REG(sii->osh, ®s->bankinfo, bankinfo); -+ } -+ else if (i == 0) { -+ if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { -+ *enable = 1; -+ if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) -+ *protect = 1; -+ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) -+ *remap = 1; -+ } -+ } -+ } -+ } -+ -+ /* Return to previous state and core */ -+ if (!wasup) -+ si_core_disable(sih, 0); -+ si_setcoreidx(sih, origidx); -+ -+done: -+ INTR_RESTORE(sii, intr_val); -+} -+ -+bool -+si_socdevram_remap_isenb(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ sbsocramregs_t *regs; -+ bool wasup, remap = FALSE; -+ uint corerev; -+ uint32 extcinfo; -+ uint8 nb; -+ uint8 i; -+ uint32 bankidx, bankinfo; -+ -+ sii = SI_INFO(sih); -+ -+ /* Block ints and save current core */ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ /* Switch to SOCRAM core */ -+ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) -+ goto done; -+ -+ /* Get info for determining size */ -+ if (!(wasup = si_iscoreup(sih))) -+ si_core_reset(sih, 0, 0); -+ -+ corerev = si_corerev(sih); -+ if (corerev >= 16) { -+ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); -+ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); -+ for (i = 0; i < nb; i++) { -+ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); -+ W_REG(sii->osh, ®s->bankidx, bankidx); -+ bankinfo = R_REG(sii->osh, ®s->bankinfo); -+ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { -+ remap = TRUE; -+ break; -+ } -+ } -+ } -+ -+ /* Return to previous state and core */ -+ if (!wasup) -+ si_core_disable(sih, 0); -+ si_setcoreidx(sih, origidx); -+ -+done: -+ INTR_RESTORE(sii, intr_val); -+ return remap; -+} -+ -+bool -+si_socdevram_pkg(si_t *sih) -+{ -+ if (si_socdevram_size(sih) > 0) -+ return TRUE; -+ else -+ return FALSE; -+} -+ -+uint32 -+si_socdevram_size(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ uint32 memsize = 0; -+ sbsocramregs_t *regs; -+ bool wasup; -+ uint corerev; -+ -+ sii = SI_INFO(sih); -+ -+ /* Block ints and save current core */ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ /* Switch to SOCRAM core */ -+ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) -+ goto done; -+ -+ /* Get info for determining size */ -+ if (!(wasup = si_iscoreup(sih))) -+ si_core_reset(sih, 0, 0); -+ -+ corerev = si_corerev(sih); -+ if (corerev >= 10) { -+ uint32 extcinfo; -+ uint8 nb; -+ uint8 i; -+ -+ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); -+ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); -+ for (i = 0; i < nb; i++) -+ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); -+ } -+ -+ /* Return to previous state and core */ -+ if (!wasup) -+ si_core_disable(sih, 0); -+ si_setcoreidx(sih, origidx); -+ -+done: -+ INTR_RESTORE(sii, intr_val); -+ -+ return memsize; -+} -+ -+uint32 -+si_socdevram_remap_size(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ uint32 memsize = 0, banksz; -+ sbsocramregs_t *regs; -+ bool wasup; -+ uint corerev; -+ uint32 extcinfo; -+ uint8 nb; -+ uint8 i; -+ uint32 bankidx, bankinfo; -+ -+ sii = SI_INFO(sih); -+ -+ /* Block ints and save current core */ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ /* Switch to SOCRAM core */ -+ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) -+ goto done; -+ -+ /* Get info for determining size */ -+ if (!(wasup = si_iscoreup(sih))) -+ si_core_reset(sih, 0, 0); -+ -+ corerev = si_corerev(sih); -+ if (corerev >= 16) { -+ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); -+ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); -+ -+ /* -+ * FIX: A0 Issue: Max addressable is 512KB, instead 640KB -+ * Only four banks are accessible to ARM -+ */ -+ if ((corerev == 16) && (nb == 5)) -+ nb = 4; -+ -+ for (i = 0; i < nb; i++) { -+ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); -+ W_REG(sii->osh, ®s->bankidx, bankidx); -+ bankinfo = R_REG(sii->osh, ®s->bankinfo); -+ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { -+ banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); -+ memsize += banksz; -+ } else { -+ /* Account only consecutive banks for now */ -+ break; -+ } -+ } -+ } -+ -+ /* Return to previous state and core */ -+ if (!wasup) -+ si_core_disable(sih, 0); -+ si_setcoreidx(sih, origidx); -+ -+done: -+ INTR_RESTORE(sii, intr_val); -+ -+ return memsize; -+} -+ -+/* Return the RAM size of the SOCRAM core */ -+uint32 -+si_socram_size(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ -+ sbsocramregs_t *regs; -+ bool wasup; -+ uint corerev; -+ uint32 coreinfo; -+ uint memsize = 0; -+ -+ sii = SI_INFO(sih); -+ -+ /* Block ints and save current core */ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ /* Switch to SOCRAM core */ -+ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) -+ goto done; -+ -+ /* Get info for determining size */ -+ if (!(wasup = si_iscoreup(sih))) -+ si_core_reset(sih, 0, 0); -+ corerev = si_corerev(sih); -+ coreinfo = R_REG(sii->osh, ®s->coreinfo); -+ -+ /* Calculate size from coreinfo based on rev */ -+ if (corerev == 0) -+ memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); -+ else if (corerev < 3) { -+ memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); -+ memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; -+ } else if ((corerev <= 7) || (corerev == 12)) { -+ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; -+ uint bsz = (coreinfo & SRCI_SRBSZ_MASK); -+ uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; -+ if (lss != 0) -+ nb --; -+ memsize = nb * (1 << (bsz + SR_BSZ_BASE)); -+ if (lss != 0) -+ memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); -+ } else { -+ uint8 i; -+ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; -+ for (i = 0; i < nb; i++) -+ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); -+ } -+ -+ /* Return to previous state and core */ -+ if (!wasup) -+ si_core_disable(sih, 0); -+ si_setcoreidx(sih, origidx); -+ -+done: -+ INTR_RESTORE(sii, intr_val); -+ -+ return memsize; -+} -+ -+ -+/* Return the TCM-RAM size of the ARMCR4 core. */ -+uint32 -+si_tcm_size(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ uint8 *regs; -+ bool wasup; -+ uint32 corecap; -+ uint memsize = 0; -+ uint32 nab = 0; -+ uint32 nbb = 0; -+ uint32 totb = 0; -+ uint32 bxinfo = 0; -+ uint32 idx = 0; -+ uint32 *arm_cap_reg; -+ uint32 *arm_bidx; -+ uint32 *arm_binfo; -+ -+ sii = SI_INFO(sih); -+ -+ /* Block ints and save current core */ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ /* Switch to CR4 core */ -+ if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) -+ goto done; -+ -+ /* Get info for determining size. If in reset, come out of reset, -+ * but remain in halt -+ */ -+ if (!(wasup = si_iscoreup(sih))) -+ si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); -+ -+ arm_cap_reg = (uint32 *)(regs + SI_CR4_CAP); -+ corecap = R_REG(sii->osh, arm_cap_reg); -+ -+ nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; -+ nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; -+ totb = nab + nbb; -+ -+ arm_bidx = (uint32 *)(regs + SI_CR4_BANKIDX); -+ arm_binfo = (uint32 *)(regs + SI_CR4_BANKINFO); -+ for (idx = 0; idx < totb; idx++) { -+ W_REG(sii->osh, arm_bidx, idx); -+ -+ bxinfo = R_REG(sii->osh, arm_binfo); -+ memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; -+ } -+ -+ /* Return to previous state and core */ -+ if (!wasup) -+ si_core_disable(sih, 0); -+ si_setcoreidx(sih, origidx); -+ -+done: -+ INTR_RESTORE(sii, intr_val); -+ -+ return memsize; -+} -+ -+uint32 -+si_socram_srmem_size(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ -+ sbsocramregs_t *regs; -+ bool wasup; -+ uint corerev; -+ uint32 coreinfo; -+ uint memsize = 0; -+ -+ if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { -+ return (32 * 1024); -+ } -+ -+ sii = SI_INFO(sih); -+ -+ /* Block ints and save current core */ -+ INTR_OFF(sii, intr_val); -+ origidx = si_coreidx(sih); -+ -+ /* Switch to SOCRAM core */ -+ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) -+ goto done; -+ -+ /* Get info for determining size */ -+ if (!(wasup = si_iscoreup(sih))) -+ si_core_reset(sih, 0, 0); -+ corerev = si_corerev(sih); -+ coreinfo = R_REG(sii->osh, ®s->coreinfo); -+ -+ /* Calculate size from coreinfo based on rev */ -+ if (corerev >= 16) { -+ uint8 i; -+ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; -+ for (i = 0; i < nb; i++) { -+ W_REG(sii->osh, ®s->bankidx, i); -+ if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) -+ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); -+ } -+ } -+ -+ /* Return to previous state and core */ -+ if (!wasup) -+ si_core_disable(sih, 0); -+ si_setcoreidx(sih, origidx); -+ -+done: -+ INTR_RESTORE(sii, intr_val); -+ -+ return memsize; -+} -+ -+ -+void -+si_btcgpiowar(si_t *sih) -+{ -+ si_info_t *sii; -+ uint origidx; -+ uint intr_val = 0; -+ chipcregs_t *cc; -+ -+ sii = SI_INFO(sih); -+ -+ /* Make sure that there is ChipCommon core present && -+ * UART_TX is strapped to 1 -+ */ -+ if (!(sih->cccaps & CC_CAP_UARTGPIO)) -+ return; -+ -+ /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ -+ INTR_OFF(sii, intr_val); -+ -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ ASSERT(cc != NULL); -+ -+ W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); -+ -+ /* restore the original index */ -+ si_setcoreidx(sih, origidx); -+ -+ INTR_RESTORE(sii, intr_val); -+} -+ -+void -+si_chipcontrl_btshd0_4331(si_t *sih, bool on) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ uint32 val; -+ uint intr_val = 0; -+ -+ sii = SI_INFO(sih); -+ -+ INTR_OFF(sii, intr_val); -+ -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ -+ val = R_REG(sii->osh, &cc->chipcontrol); -+ -+ /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ -+ if (on) { -+ /* Enable bt_shd0 on gpio4: */ -+ val |= (CCTRL4331_BT_SHD0_ON_GPIO4); -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ } else { -+ val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ } -+ -+ /* restore the original index */ -+ si_setcoreidx(sih, origidx); -+ -+ INTR_RESTORE(sii, intr_val); -+} -+ -+void -+si_chipcontrl_restore(si_t *sih, uint32 val) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ si_setcoreidx(sih, origidx); -+} -+ -+uint32 -+si_chipcontrl_read(si_t *sih) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ uint32 val; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ val = R_REG(sii->osh, &cc->chipcontrol); -+ si_setcoreidx(sih, origidx); -+ return val; -+} -+ -+void -+si_chipcontrl_epa4331(si_t *sih, bool on) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ uint32 val; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ -+ val = R_REG(sii->osh, &cc->chipcontrol); -+ -+ if (on) { -+ if (sih->chippkg == 9 || sih->chippkg == 0xb) { -+ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); -+ /* Ext PA Controls for 4331 12x9 Package */ -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ } else { -+ /* Ext PA Controls for 4331 12x12 Package */ -+ if (sih->chiprev > 0) { -+ W_REG(sii->osh, &cc->chipcontrol, val | -+ (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); -+ } else { -+ W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); -+ } -+ } -+ } else { -+ val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ } -+ -+ si_setcoreidx(sih, origidx); -+} -+ -+/* switch muxed pins, on: SROM, off: FEMCTRL */ -+void -+si_chipcontrl_srom4360(si_t *sih, bool on) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ uint32 val; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ -+ val = R_REG(sii->osh, &cc->chipcontrol); -+ -+ if (on) { -+ val &= ~(CCTRL4360_SECI_MODE | -+ CCTRL4360_BTSWCTRL_MODE | -+ CCTRL4360_EXTRA_FEMCTRL_MODE | -+ CCTRL4360_BT_LGCY_MODE | -+ CCTRL4360_CORE2FEMCTRL4_ON); -+ -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ } else { -+ } -+ -+ si_setcoreidx(sih, origidx); -+} -+ -+void -+si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ uint32 val; -+ bool sel_chip; -+ -+ sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || -+ (CHIPID(sih->chip) == BCM43431_CHIP_ID); -+ sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); -+ -+ if (!sel_chip) -+ return; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ -+ val = R_REG(sii->osh, &cc->chipcontrol); -+ -+ if (enter_wowl) { -+ val |= CCTRL4331_EXTPA_EN; -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ } else { -+ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); -+ W_REG(sii->osh, &cc->chipcontrol, val); -+ } -+ si_setcoreidx(sih, origidx); -+} -+ -+uint -+si_pll_reset(si_t *sih) -+{ -+ uint err = 0; -+ -+ return (err); -+} -+ -+/* Enable BT-COEX & Ex-PA for 4313 */ -+void -+si_epa_4313war(si_t *sih) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ -+ /* EPA Fix */ -+ W_REG(sii->osh, &cc->gpiocontrol, -+ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); -+ -+ si_setcoreidx(sih, origidx); -+} -+ -+void -+si_clk_pmu_htavail_set(si_t *sih, bool set_clear) -+{ -+} -+ -+/* WL/BT control for 4313 btcombo boards >= P250 */ -+void -+si_btcombo_p250_4313_war(si_t *sih) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ W_REG(sii->osh, &cc->gpiocontrol, -+ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); -+ -+ W_REG(sii->osh, &cc->gpioouten, -+ R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); -+ -+ si_setcoreidx(sih, origidx); -+} -+void -+si_btc_enable_chipcontrol(si_t *sih) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ -+ /* BT fix */ -+ W_REG(sii->osh, &cc->chipcontrol, -+ R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); -+ -+ si_setcoreidx(sih, origidx); -+} -+void -+si_btcombo_43228_war(si_t *sih) -+{ -+ si_info_t *sii; -+ chipcregs_t *cc; -+ uint origidx; -+ -+ sii = SI_INFO(sih); -+ origidx = si_coreidx(sih); -+ -+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); -+ -+ W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); -+ W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); -+ -+ si_setcoreidx(sih, origidx); -+} -+ -+/* check if the device is removed */ -+bool -+si_deviceremoved(si_t *sih) -+{ -+ uint32 w; -+ si_info_t *sii; -+ -+ sii = SI_INFO(sih); -+ -+ switch (BUSTYPE(sih->bustype)) { -+ case PCI_BUS: -+ ASSERT(sii->osh != NULL); -+ w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32)); -+ if ((w & 0xFFFF) != VENDOR_BROADCOM) -+ return TRUE; -+ break; -+ } -+ return FALSE; -+} -+ -+bool -+si_is_sprom_available(si_t *sih) -+{ -+ if (sih->ccrev >= 31) { -+ si_info_t *sii; -+ uint origidx; -+ chipcregs_t *cc; -+ uint32 sromctrl; -+ -+ if ((sih->cccaps & CC_CAP_SROM) == 0) -+ return FALSE; -+ -+ sii = SI_INFO(sih); -+ origidx = sii->curidx; -+ cc = si_setcoreidx(sih, SI_CC_IDX); -+ sromctrl = R_REG(sii->osh, &cc->sromcontrol); -+ si_setcoreidx(sih, origidx); -+ return (sromctrl & SRC_PRESENT); -+ } -+ -+ switch (CHIPID(sih->chip)) { -+ case BCM4312_CHIP_ID: -+ return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); -+ case BCM4325_CHIP_ID: -+ return (sih->chipst & CST4325_SPROM_SEL) != 0; -+ case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID: -+ case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID: -+ case BCM4342_CHIP_ID: { -+ uint32 spromotp; -+ spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> -+ CST4322_SPROM_OTP_SEL_SHIFT; -+ return (spromotp & CST4322_SPROM_PRESENT) != 0; -+ } -+ case BCM4329_CHIP_ID: -+ return (sih->chipst & CST4329_SPROM_SEL) != 0; -+ case BCM4315_CHIP_ID: -+ return (sih->chipst & CST4315_SPROM_SEL) != 0; -+ case BCM4319_CHIP_ID: -+ return (sih->chipst & CST4319_SPROM_SEL) != 0; -+ case BCM4336_CHIP_ID: -+ case BCM43362_CHIP_ID: -+ return (sih->chipst & CST4336_SPROM_PRESENT) != 0; -+ case BCM4330_CHIP_ID: -+ return (sih->chipst & CST4330_SPROM_PRESENT) != 0; -+ case BCM4313_CHIP_ID: -+ return (sih->chipst & CST4313_SPROM_PRESENT) != 0; -+ case BCM4331_CHIP_ID: -+ case BCM43431_CHIP_ID: -+ return (sih->chipst & CST4331_SPROM_PRESENT) != 0; -+ case BCM43239_CHIP_ID: -+ return ((sih->chipst & CST43239_SPROM_MASK) && -+ !(sih->chipst & CST43239_SFLASH_MASK)); -+ case BCM4324_CHIP_ID: -+ return ((sih->chipst & CST4324_SPROM_MASK) && -+ !(sih->chipst & CST4324_SFLASH_MASK)); -+ case BCM4335_CHIP_ID: -+ return ((sih->chipst & CST4335_SPROM_MASK) && -+ !(sih->chipst & CST4335_SFLASH_MASK)); -+ case BCM43131_CHIP_ID: -+ case BCM43217_CHIP_ID: -+ case BCM43227_CHIP_ID: -+ case BCM43228_CHIP_ID: -+ case BCM43428_CHIP_ID: -+ return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; -+ default: -+ return TRUE; -+ } -+} -+ -+ -+uint32 si_get_sromctl(si_t *sih) -+{ -+ chipcregs_t *cc; -+ uint origidx; -+ uint32 sromctl; -+ osl_t *osh; -+ -+ osh = si_osh(sih); -+ origidx = si_coreidx(sih); -+ cc = si_setcoreidx(sih, SI_CC_IDX); -+ ASSERT((uintptr)cc); -+ -+ sromctl = R_REG(osh, &cc->sromcontrol); -+ -+ /* return to the original core */ -+ si_setcoreidx(sih, origidx); -+ return sromctl; -+} -+ -+int si_set_sromctl(si_t *sih, uint32 value) -+{ -+ chipcregs_t *cc; -+ uint origidx; -+ osl_t *osh; -+ -+ osh = si_osh(sih); -+ origidx = si_coreidx(sih); -+ cc = si_setcoreidx(sih, SI_CC_IDX); -+ ASSERT((uintptr)cc); -+ -+ /* get chipcommon rev */ -+ if (si_corerev(sih) < 32) -+ return BCME_UNSUPPORTED; -+ -+ W_REG(osh, &cc->sromcontrol, value); -+ -+ /* return to the original core */ -+ si_setcoreidx(sih, origidx); -+ return BCME_OK; -+ -+} -diff --git a/drivers/net/wireless/bcmdhd/siutils_priv.h b/drivers/net/wireless/bcmdhd/siutils_priv.h -new file mode 100644 -index 00000000..9a3270f7 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/siutils_priv.h -@@ -0,0 +1,246 @@ -+/* -+ * Include file private to the SOC Interconnect support files. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: siutils_priv.h 309193 2012-01-19 00:03:57Z $ -+ */ -+ -+#ifndef _siutils_priv_h_ -+#define _siutils_priv_h_ -+ -+#define SI_ERROR(args) -+ -+#define SI_MSG(args) -+ -+#ifdef BCMDBG_SI -+#define SI_VMSG(args) printf args -+#else -+#define SI_VMSG(args) -+#endif -+ -+#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) -+ -+typedef uint32 (*si_intrsoff_t)(void *intr_arg); -+typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); -+typedef bool (*si_intrsenabled_t)(void *intr_arg); -+ -+typedef struct gpioh_item { -+ void *arg; -+ bool level; -+ gpio_handler_t handler; -+ uint32 event; -+ struct gpioh_item *next; -+} gpioh_item_t; -+ -+/* misc si info needed by some of the routines */ -+typedef struct si_info { -+ struct si_pub pub; /* back plane public state (must be first field) */ -+ -+ void *osh; /* osl os handle */ -+ void *sdh; /* bcmsdh handle */ -+ -+ uint dev_coreid; /* the core provides driver functions */ -+ void *intr_arg; /* interrupt callback function arg */ -+ si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */ -+ si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */ -+ si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */ -+ -+ void *pch; /* PCI/E core handle */ -+ -+ gpioh_item_t *gpioh_head; /* GPIO event handlers list */ -+ -+ bool memseg; /* flag to toggle MEM_SEG register */ -+ -+ char *vars; -+ uint varsz; -+ -+ void *curmap; /* current regs va */ -+ void *regs[SI_MAXCORES]; /* other regs va */ -+ -+ uint curidx; /* current core index */ -+ uint numcores; /* # discovered cores */ -+ uint coreid[SI_MAXCORES]; /* id of each core */ -+ uint32 coresba[SI_MAXCORES]; /* backplane address of each core */ -+ void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */ -+ uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */ -+ uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */ -+ uint32 coresba2_size[SI_MAXCORES]; /* second address space size */ -+ -+ void *curwrap; /* current wrapper va */ -+ void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ -+ uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ -+ -+ uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */ -+ uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */ -+ uint32 oob_router; /* oob router registers for axi */ -+} si_info_t; -+ -+#define SI_INFO(sih) (si_info_t *)(uintptr)sih -+ -+#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ -+ ISALIGNED((x), SI_CORE_SIZE)) -+#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) -+#define BADCOREADDR 0 -+#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) -+#define NOREV -1 /* Invalid rev */ -+ -+#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ -+ ((si)->pub.buscoretype == PCI_CORE_ID)) -+ -+#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ -+ ((si)->pub.buscoretype == PCIE_CORE_ID)) -+ -+#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ -+ ((si)->pub.buscoretype == PCIE2_CORE_ID)) -+ -+#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) -+ -+#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) -+ -+/* Newer chips can access PCI/PCIE and CC core without requiring to change -+ * PCI BAR0 WIN -+ */ -+#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) -+ -+#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET)) -+#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) -+ -+/* -+ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/ -+ * after core switching to avoid invalid register accesss inside ISR. -+ */ -+#define INTR_OFF(si, intr_val) \ -+ if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ -+ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); } -+#define INTR_RESTORE(si, intr_val) \ -+ if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \ -+ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); } -+ -+/* dynamic clock control defines */ -+#define LPOMINFREQ 25000 /* low power oscillator min */ -+#define LPOMAXFREQ 43000 /* low power oscillator max */ -+#define XTALMINFREQ 19800000 /* 20 MHz - 1% */ -+#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */ -+#define PCIMINFREQ 25000000 /* 25 MHz */ -+#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */ -+ -+#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ -+#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ -+ -+#define PCI_FORCEHT(si) \ -+ (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \ -+ ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \ -+ (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \ -+ (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID))) -+ -+/* GPIO Based LED powersave defines */ -+#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ -+#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ -+ -+#ifndef DEFAULT_GPIOTIMERVAL -+#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) -+#endif -+ -+/* Silicon Backplane externs */ -+extern void sb_scan(si_t *sih, void *regs, uint devid); -+extern uint sb_coreid(si_t *sih); -+extern uint sb_intflag(si_t *sih); -+extern uint sb_flag(si_t *sih); -+extern void sb_setint(si_t *sih, int siflag); -+extern uint sb_corevendor(si_t *sih); -+extern uint sb_corerev(si_t *sih); -+extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -+extern bool sb_iscoreup(si_t *sih); -+extern void *sb_setcoreidx(si_t *sih, uint coreidx); -+extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); -+extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -+extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); -+extern void sb_commit(si_t *sih); -+extern uint32 sb_base(uint32 admatch); -+extern uint32 sb_size(uint32 admatch); -+extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -+extern void sb_core_disable(si_t *sih, uint32 bits); -+extern uint32 sb_addrspace(si_t *sih, uint asidx); -+extern uint32 sb_addrspacesize(si_t *sih, uint asidx); -+extern int sb_numaddrspaces(si_t *sih); -+ -+extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); -+ -+extern bool sb_taclear(si_t *sih, bool details); -+ -+ -+/* Wake-on-wireless-LAN (WOWL) */ -+extern bool sb_pci_pmecap(si_t *sih); -+struct osl_info; -+extern bool sb_pci_fastpmecap(struct osl_info *osh); -+extern bool sb_pci_pmeclr(si_t *sih); -+extern void sb_pci_pmeen(si_t *sih); -+extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); -+ -+/* AMBA Interconnect exported externs */ -+extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, -+ void *sdh, char **vars, uint *varsz); -+extern si_t *ai_kattach(osl_t *osh); -+extern void ai_scan(si_t *sih, void *regs, uint devid); -+ -+extern uint ai_flag(si_t *sih); -+extern void ai_setint(si_t *sih, int siflag); -+extern uint ai_coreidx(si_t *sih); -+extern uint ai_corevendor(si_t *sih); -+extern uint ai_corerev(si_t *sih); -+extern bool ai_iscoreup(si_t *sih); -+extern void *ai_setcoreidx(si_t *sih, uint coreidx); -+extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); -+extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); -+extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); -+extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); -+extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); -+extern void ai_core_disable(si_t *sih, uint32 bits); -+extern int ai_numaddrspaces(si_t *sih); -+extern uint32 ai_addrspace(si_t *sih, uint asidx); -+extern uint32 ai_addrspacesize(si_t *sih, uint asidx); -+extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); -+extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); -+ -+ -+ -+#define ub_scan(a, b, c) do {} while (0) -+#define ub_flag(a) (0) -+#define ub_setint(a, b) do {} while (0) -+#define ub_coreidx(a) (0) -+#define ub_corevendor(a) (0) -+#define ub_corerev(a) (0) -+#define ub_iscoreup(a) (0) -+#define ub_setcoreidx(a, b) (0) -+#define ub_core_cflags(a, b, c) (0) -+#define ub_core_cflags_wo(a, b, c) do {} while (0) -+#define ub_core_sflags(a, b, c) (0) -+#define ub_corereg(a, b, c, d, e) (0) -+#define ub_core_reset(a, b, c) do {} while (0) -+#define ub_core_disable(a, b) do {} while (0) -+#define ub_numaddrspaces(a) (0) -+#define ub_addrspace(a, b) (0) -+#define ub_addrspacesize(a, b) (0) -+#define ub_view(a, b) do {} while (0) -+#define ub_dumpregs(a, b) do {} while (0) -+ -+#endif /* _siutils_priv_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/uamp_api.h b/drivers/net/wireless/bcmdhd/uamp_api.h -new file mode 100644 -index 00000000..673dce08 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/uamp_api.h -@@ -0,0 +1,176 @@ -+/* -+ * Name: uamp_api.h -+ * -+ * Description: Universal AMP API -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: uamp_api.h 294267 2011-11-04 23:41:52Z $ -+ * -+ */ -+#ifndef UAMP_API_H -+#define UAMP_API_H -+ -+ -+#include "typedefs.h" -+ -+ -+/***************************************************************************** -+** Constant and Type Definitions -+****************************************************************************** -+*/ -+ -+#define BT_API -+ -+/* Types. */ -+typedef bool BOOLEAN; -+typedef uint8 UINT8; -+typedef uint16 UINT16; -+ -+ -+/* UAMP identifiers */ -+#define UAMP_ID_1 1 -+#define UAMP_ID_2 2 -+typedef UINT8 tUAMP_ID; -+ -+/* UAMP event ids (used by UAMP_CBACK) */ -+#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */ -+#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */ -+#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */ -+typedef UINT8 tUAMP_EVT; -+ -+ -+/* UAMP Channels */ -+#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */ -+#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */ -+#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */ -+typedef UINT8 tUAMP_CH; -+ -+/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */ -+typedef union { -+ tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */ -+} tUAMP_EVT_DATA; -+ -+ -+/***************************************************************************** -+** -+** Function: UAMP_CBACK -+** -+** Description: Callback for events. Register callback using UAMP_Init. -+** -+** Parameters amp_id: AMP device identifier that generated the event -+** amp_evt: event id -+** p_amp_evt_data: pointer to event-specific data -+** -+****************************************************************************** -+*/ -+typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data); -+ -+/***************************************************************************** -+** external function declarations -+****************************************************************************** -+*/ -+#ifdef __cplusplus -+extern "C" -+{ -+#endif -+ -+/***************************************************************************** -+** -+** Function: UAMP_Init -+** -+** Description: Initialize UAMP driver -+** -+** Parameters p_cback: Callback function for UAMP event notification -+** -+****************************************************************************** -+*/ -+BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback); -+ -+ -+/***************************************************************************** -+** -+** Function: UAMP_Open -+** -+** Description: Open connection to local AMP device. -+** -+** Parameters app_id: Application specific AMP identifer. This value -+** will be included in AMP messages sent to the -+** BTU task, to identify source of the message -+** -+****************************************************************************** -+*/ -+BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id); -+ -+/***************************************************************************** -+** -+** Function: UAMP_Close -+** -+** Description: Close connection to local AMP device. -+** -+** Parameters app_id: Application specific AMP identifer. -+** -+****************************************************************************** -+*/ -+BT_API void UAMP_Close(tUAMP_ID amp_id); -+ -+ -+/***************************************************************************** -+** -+** Function: UAMP_Write -+** -+** Description: Send buffer to AMP device. Frees GKI buffer when done. -+** -+** -+** Parameters: app_id: AMP identifer. -+** p_buf: pointer to buffer to write -+** num_bytes: number of bytes to write -+** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD -+** -+** Returns: number of bytes written -+** -+****************************************************************************** -+*/ -+BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel); -+ -+/***************************************************************************** -+** -+** Function: UAMP_Read -+** -+** Description: Read incoming data from AMP. Call after receiving a -+** UAMP_EVT_RX_READY callback event. -+** -+** Parameters: app_id: AMP identifer. -+** p_buf: pointer to buffer for holding incoming AMP data -+** buf_size: size of p_buf -+** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT -+** -+** Returns: number of bytes read -+** -+****************************************************************************** -+*/ -+BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* UAMP_API_H */ -diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c -new file mode 100644 -index 00000000..26f88e24 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_android.c -@@ -0,0 +1,908 @@ -+/* -+ * Linux cfg80211 driver - Android related functions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_android.c 379859 2013-01-19 13:16:55Z $ -+ */ -+ -+#include <linux/module.h> -+#include <linux/netdevice.h> -+ -+#include <wl_android.h> -+#include <wldev_common.h> -+#include <wlioctl.h> -+#include <bcmutils.h> -+#include <linux_osl.h> -+#include <dhd_dbg.h> -+#include <dngl_stats.h> -+#include <dhd.h> -+#include <bcmsdbus.h> -+#ifdef WL_CFG80211 -+#include <wl_cfg80211.h> -+#endif -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+#include <linux/platform_device.h> -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) -+#include <linux/wlan_plat.h> -+#else -+#include <linux/wifi_tiwlan.h> -+#endif -+#endif /* CONFIG_WIFI_CONTROL_FUNC */ -+ -+/* -+ * Android private command strings, PLEASE define new private commands here -+ * so they can be updated easily in the future (if needed) -+ */ -+ -+#define CMD_START "START" -+#define CMD_STOP "STOP" -+#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" -+#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" -+#define CMD_RSSI "RSSI" -+#define CMD_LINKSPEED "LINKSPEED" -+#define CMD_RXFILTER_START "RXFILTER-START" -+#define CMD_RXFILTER_STOP "RXFILTER-STOP" -+#define CMD_RXFILTER_ADD "RXFILTER-ADD" -+#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" -+#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" -+#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" -+#define CMD_BTCOEXMODE "BTCOEXMODE" -+#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" -+#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" -+#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" -+#define CMD_SETFWPATH "SETFWPATH" -+#define CMD_SETBAND "SETBAND" -+#define CMD_GETBAND "GETBAND" -+#define CMD_COUNTRY "COUNTRY" -+#define CMD_P2P_SET_NOA "P2P_SET_NOA" -+#if !defined WL_ENABLE_P2P_IF -+#define CMD_P2P_GET_NOA "P2P_GET_NOA" -+#endif -+#define CMD_P2P_SET_PS "P2P_SET_PS" -+#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" -+ -+ -+#ifdef PNO_SUPPORT -+#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" -+#define CMD_PNOSETUP_SET "PNOSETUP " -+#define CMD_PNOENABLE_SET "PNOFORCE" -+#define CMD_PNODEBUG_SET "PNODEBUG" -+ -+#define PNO_TLV_PREFIX 'S' -+#define PNO_TLV_VERSION '1' -+#define PNO_TLV_SUBVERSION '2' -+#define PNO_TLV_RESERVED '0' -+#define PNO_TLV_TYPE_SSID_IE 'S' -+#define PNO_TLV_TYPE_TIME 'T' -+#define PNO_TLV_FREQ_REPEAT 'R' -+#define PNO_TLV_FREQ_EXPO_MAX 'M' -+ -+typedef struct cmd_tlv { -+ char prefix; -+ char version; -+ char subver; -+ char reserved; -+} cmd_tlv_t; -+#endif /* PNO_SUPPORT */ -+ -+typedef struct android_wifi_priv_cmd { -+ char *buf; -+ int used_len; -+ int total_len; -+} android_wifi_priv_cmd; -+ -+/** -+ * Extern function declarations (TODO: move them to dhd_linux.h) -+ */ -+void dhd_customer_gpio_wlan_ctrl(int onoff); -+int dhd_dev_reset(struct net_device *dev, uint8 flag); -+int dhd_dev_init_ioctl(struct net_device *dev); -+#ifdef WL_CFG80211 -+int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); -+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command); -+#else -+int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) -+{ return 0; } -+int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) -+{ return 0; } -+int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) -+{ return 0; } -+int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) -+{ return 0; } -+#endif /* WL_CFG80211 */ -+extern int dhd_os_check_if_up(void *dhdp); -+extern void *bcmsdh_get_drvdata(void); -+#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) -+extern int dhd_wlfc_init(dhd_pub_t *dhd); -+extern void dhd_wlfc_deinit(dhd_pub_t *dhd); -+#endif -+ -+extern bool ap_fw_loaded; -+#if defined(CUSTOMER_HW2) -+extern char iface_name[IFNAMSIZ]; -+#endif -+ -+#define WIFI_TURNOFF_DELAY 0 -+/** -+ * Local (static) functions and variables -+ */ -+ -+/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first -+ * time (only) in dhd_open, subsequential wifi on will be handled by -+ * wl_android_wifi_on -+ */ -+static int g_wifi_on = TRUE; -+ -+/** -+ * Local (static) function definitions -+ */ -+static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) -+{ -+ int link_speed; -+ int bytes_written; -+ int error; -+ -+ error = wldev_get_link_speed(net, &link_speed); -+ if (error) -+ return -1; -+ -+ /* Convert Kbps to Android Mbps */ -+ link_speed = link_speed / 1000; -+ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); -+ DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); -+ return bytes_written; -+} -+ -+static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) -+{ -+ wlc_ssid_t ssid = {0}; -+ int rssi; -+ int bytes_written = 0; -+ int error; -+ -+ error = wldev_get_rssi(net, &rssi); -+ if (error) -+ return -1; -+ -+ error = wldev_get_ssid(net, &ssid); -+ if (error) -+ return -1; -+ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { -+ DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); -+ } else { -+ memcpy(command, ssid.SSID, ssid.SSID_len); -+ bytes_written = ssid.SSID_len; -+ } -+ bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi); -+ DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); -+ return bytes_written; -+} -+ -+static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) -+{ -+ int suspend_flag; -+ int ret_now; -+ int ret = 0; -+ -+ suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; -+ -+ if (suspend_flag != 0) -+ suspend_flag = 1; -+ ret_now = net_os_set_suspend_disable(dev, suspend_flag); -+ -+ if (ret_now != suspend_flag) { -+ if (!(ret = net_os_set_suspend(dev, ret_now, 1))) -+ DHD_INFO(("%s: Suspend Flag %d -> %d\n", -+ __FUNCTION__, ret_now, suspend_flag)); -+ else -+ DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); -+ } -+ return ret; -+} -+ -+static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) -+{ -+ int ret = 0; -+ -+#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) -+ int suspend_flag; -+ -+ suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; -+ -+ if (suspend_flag != 0) -+ suspend_flag = 1; -+ -+ if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) -+ DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); -+ else -+ DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); -+#endif -+ return ret; -+} -+ -+static int wl_android_get_band(struct net_device *dev, char *command, int total_len) -+{ -+ uint band; -+ int bytes_written; -+ int error; -+ -+ error = wldev_get_band(dev, &band); -+ if (error) -+ return -1; -+ bytes_written = snprintf(command, total_len, "Band %d", band); -+ return bytes_written; -+} -+ -+#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) -+static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) -+{ -+ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; -+ int res = -1; -+ int nssid = 0; -+ cmd_tlv_t *cmd_tlv_temp; -+ char *str_ptr; -+ int tlv_size_left; -+ int pno_time = 0; -+ int pno_repeat = 0; -+ int pno_freq_expo_max = 0; -+ -+#ifdef PNO_SET_DEBUG -+ int i; -+ char pno_in_example[] = { -+ 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', -+ 'S', '1', '2', '0', -+ 'S', -+ 0x05, -+ 'd', 'l', 'i', 'n', 'k', -+ 'S', -+ 0x04, -+ 'G', 'O', 'O', 'G', -+ 'T', -+ '0', 'B', -+ 'R', -+ '2', -+ 'M', -+ '2', -+ 0x00 -+ }; -+#endif /* PNO_SET_DEBUG */ -+ -+ DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); -+ -+ if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { -+ DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); -+ goto exit_proc; -+ } -+ -+ -+#ifdef PNO_SET_DEBUG -+ memcpy(command, pno_in_example, sizeof(pno_in_example)); -+ for (i = 0; i < sizeof(pno_in_example); i++) -+ printf("%02X ", command[i]); -+ printf("\n"); -+ total_len = sizeof(pno_in_example); -+#endif -+ -+ str_ptr = command + strlen(CMD_PNOSETUP_SET); -+ tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); -+ -+ cmd_tlv_temp = (cmd_tlv_t *)str_ptr; -+ memset(ssids_local, 0, sizeof(ssids_local)); -+ -+ if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && -+ (cmd_tlv_temp->version == PNO_TLV_VERSION) && -+ (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) { -+ -+ str_ptr += sizeof(cmd_tlv_t); -+ tlv_size_left -= sizeof(cmd_tlv_t); -+ -+ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, -+ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { -+ DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); -+ goto exit_proc; -+ } else { -+ if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { -+ DHD_ERROR(("%s scan duration corrupted field size %d\n", -+ __FUNCTION__, tlv_size_left)); -+ goto exit_proc; -+ } -+ str_ptr++; -+ pno_time = simple_strtoul(str_ptr, &str_ptr, 16); -+ DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); -+ -+ if (str_ptr[0] != 0) { -+ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { -+ DHD_ERROR(("%s pno repeat : corrupted field\n", -+ __FUNCTION__)); -+ goto exit_proc; -+ } -+ str_ptr++; -+ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); -+ DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); -+ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { -+ DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", -+ __FUNCTION__)); -+ goto exit_proc; -+ } -+ str_ptr++; -+ pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); -+ DHD_INFO(("%s: pno_freq_expo_max=%d\n", -+ __FUNCTION__, pno_freq_expo_max)); -+ } -+ } -+ } else { -+ DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); -+ goto exit_proc; -+ } -+ -+ res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max); -+ -+exit_proc: -+ return res; -+} -+#endif /* PNO_SUPPORT */ -+ -+static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) -+{ -+ int ret; -+ int bytes_written = 0; -+ -+ ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); -+ if (ret) -+ return 0; -+ bytes_written = sizeof(struct ether_addr); -+ return bytes_written; -+} -+ -+/** -+ * Global function definitions (declared in wl_android.h) -+ */ -+ -+int wl_android_wifi_on(struct net_device *dev) -+{ -+ int ret = 0; -+ int retry = POWERUP_MAX_RETRY; -+ -+ printk("%s in\n", __FUNCTION__); -+ if (!dev) { -+ DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); -+ return -EINVAL; -+ } -+ -+ dhd_net_if_lock(dev); -+ if (!g_wifi_on) { -+ do { -+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); -+ ret = sdioh_start(NULL, 0); -+ if (ret == 0) -+ break; -+ DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", -+ retry+1)); -+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); -+ } while (retry-- >= 0); -+ if (ret != 0) { -+ DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); -+ goto exit; -+ } -+ ret = dhd_dev_reset(dev, FALSE); -+ sdioh_start(NULL, 1); -+ if (!ret) { -+ if (dhd_dev_init_ioctl(dev) < 0) -+ ret = -EFAULT; -+ } -+#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) -+ dhd_wlfc_init(bcmsdh_get_drvdata()); -+#endif -+ g_wifi_on = TRUE; -+ } -+ -+exit: -+ dhd_net_if_unlock(dev); -+ -+ return ret; -+} -+ -+int wl_android_wifi_off(struct net_device *dev) -+{ -+ int ret = 0; -+ -+ printk("%s in\n", __FUNCTION__); -+ if (!dev) { -+ DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); -+ return -EINVAL; -+ } -+ -+ dhd_net_if_lock(dev); -+ if (g_wifi_on) { -+#if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB) -+ dhd_wlfc_deinit(bcmsdh_get_drvdata()); -+#endif -+ ret = dhd_dev_reset(dev, TRUE); -+ sdioh_stop(NULL); -+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); -+ g_wifi_on = FALSE; -+ } -+ dhd_net_if_unlock(dev); -+ -+ return ret; -+} -+ -+static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) -+{ -+ if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) -+ return -1; -+ bcm_strncpy_s(fw_path, sizeof(fw_path), -+ command + strlen(CMD_SETFWPATH) + 1, MOD_PARAM_PATHLEN - 1); -+ if (strstr(fw_path, "apsta") != NULL) { -+ DHD_INFO(("GOT APSTA FIRMWARE\n")); -+ ap_fw_loaded = TRUE; -+ } else { -+ DHD_INFO(("GOT STA FIRMWARE\n")); -+ ap_fw_loaded = FALSE; -+ } -+ return 0; -+} -+ -+int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) -+{ -+#define PRIVATE_COMMAND_MAX_LEN 8192 -+ int ret = 0; -+ char *command = NULL; -+ int bytes_written = 0; -+ android_wifi_priv_cmd priv_cmd; -+ -+ net_os_wake_lock(net); -+ -+ if (!ifr->ifr_data) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { -+ ret = -EFAULT; -+ goto exit; -+ } -+ if (priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) -+ { -+ DHD_ERROR(("%s: too long priavte command\n", __FUNCTION__)); -+ ret = -EINVAL; -+ } -+ command = kmalloc(priv_cmd.total_len, GFP_KERNEL); -+ if (!command) -+ { -+ DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__)); -+ ret = -ENOMEM; -+ goto exit; -+ } -+ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { -+ ret = -EFAULT; -+ goto exit; -+ } -+ -+ DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); -+ -+ if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { -+ DHD_INFO(("%s, Received regular START command\n", __FUNCTION__)); -+ bytes_written = wl_android_wifi_on(net); -+ } -+ else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) { -+ bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len); -+ } -+ -+ if (!g_wifi_on) { -+ DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n", -+ __FUNCTION__, command, ifr->ifr_name)); -+ ret = 0; -+ goto exit; -+ } -+ -+ if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { -+ bytes_written = wl_android_wifi_off(net); -+ } -+ else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { -+ /* TBD: SCAN-ACTIVE */ -+ } -+ else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { -+ /* TBD: SCAN-PASSIVE */ -+ } -+ else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { -+ bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len); -+ } -+ else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { -+ bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len); -+ } -+#ifdef PKT_FILTER_SUPPORT -+ else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { -+ bytes_written = net_os_enable_packet_filter(net, 1); -+ } -+ else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { -+ bytes_written = net_os_enable_packet_filter(net, 0); -+ } -+ else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) { -+ int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; -+ bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); -+ } -+ else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) { -+ int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; -+ bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); -+ } -+#endif /* PKT_FILTER_SUPPORT */ -+ else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { -+ /* TBD: BTCOEXSCAN-START */ -+ } -+ else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { -+ /* TBD: BTCOEXSCAN-STOP */ -+ } -+ else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { -+#ifdef WL_CFG80211 -+ bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command); -+#else -+#ifdef PKT_FILTER_SUPPORT -+ uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0'; -+ -+ if (mode == 1) -+ net_os_enable_packet_filter(net, 0); /* DHCP starts */ -+ else -+ net_os_enable_packet_filter(net, 1); /* DHCP ends */ -+#endif /* PKT_FILTER_SUPPORT */ -+#endif /* WL_CFG80211 */ -+ } -+ else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { -+ bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); -+ } -+ else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { -+ bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); -+ } -+ else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { -+ uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; -+#ifdef WL_HOST_BAND_MGMT -+ if (wl_cfg80211_set_band(net, band) < 0) { -+ bytes_written = -1; -+ goto exit; -+ } -+ if (band == WLC_BAND_AUTO) -+ bytes_written = wldev_set_band(net, band); -+#else -+ bytes_written = wldev_set_band(net, band); -+#endif /* WL_HOST_BAND_MGMT */ -+ } -+ else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { -+ bytes_written = wl_android_get_band(net, command, priv_cmd.total_len); -+ } -+#ifdef WL_CFG80211 -+ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { -+ char *country_code = command + strlen(CMD_COUNTRY) + 1; -+ bytes_written = wldev_set_country(net, country_code, true, true); -+ } -+#endif /* WL_CFG80211 */ -+#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) -+ else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { -+ bytes_written = dhd_dev_pno_reset(net); -+ } -+ else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) { -+ bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len); -+ } -+ else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { -+ uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; -+ bytes_written = dhd_dev_pno_enable(net, pfn_enabled); -+ } -+#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ -+ else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { -+ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); -+ } -+ else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { -+ int skip = strlen(CMD_P2P_SET_NOA) + 1; -+ bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, -+ priv_cmd.total_len - skip); -+ } -+#if !defined WL_ENABLE_P2P_IF -+ else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { -+ bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); -+ } -+#endif /* SUPPORT_GET_NOA */ -+ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { -+ int skip = strlen(CMD_P2P_SET_PS) + 1; -+ bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, -+ priv_cmd.total_len - skip); -+ } -+#ifdef WL_CFG80211 -+ else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE, -+ strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { -+ int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3; -+ bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, -+ priv_cmd.total_len - skip, *(command + skip - 2) - '0'); -+ } -+#endif /* WL_CFG80211 */ -+ else { -+ DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); -+ snprintf(command, 3, "OK"); -+ bytes_written = strlen("OK"); -+ } -+ -+ if (bytes_written >= 0) { -+ if ((bytes_written == 0) && (priv_cmd.total_len > 0)) -+ command[0] = '\0'; -+ if (bytes_written >= priv_cmd.total_len) { -+ DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written)); -+ bytes_written = priv_cmd.total_len; -+ } else { -+ bytes_written++; -+ } -+ priv_cmd.used_len = bytes_written; -+ if (copy_to_user(priv_cmd.buf, command, bytes_written)) { -+ DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); -+ ret = -EFAULT; -+ } -+ } -+ else { -+ ret = bytes_written; -+ } -+ -+exit: -+ net_os_wake_unlock(net); -+ if (command) { -+ kfree(command); -+ } -+ -+ return ret; -+} -+ -+int wl_android_init(void) -+{ -+ int ret = 0; -+ -+ dhd_msg_level |= DHD_ERROR_VAL; -+#ifdef ENABLE_INSMOD_NO_FW_LOAD -+ dhd_download_fw_on_driverload = FALSE; -+#endif /* ENABLE_INSMOD_NO_FW_LOAD */ -+#if defined(CUSTOMER_HW2) -+ if (!iface_name[0]) { -+ memset(iface_name, 0, IFNAMSIZ); -+ bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ); -+ } -+#endif -+ return ret; -+} -+ -+int wl_android_exit(void) -+{ -+ int ret = 0; -+ -+ return ret; -+} -+ -+void wl_android_post_init(void) -+{ -+ if (!dhd_download_fw_on_driverload) { -+ /* Call customer gpio to turn off power with WL_REG_ON signal */ -+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); -+ g_wifi_on = 0; -+ } -+} -+/** -+ * Functions for Android WiFi card detection -+ */ -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+ -+static int g_wifidev_registered = 0; -+static struct semaphore wifi_control_sem; -+static struct wifi_platform_data *wifi_control_data = NULL; -+static struct resource *wifi_irqres = NULL; -+ -+static int wifi_add_dev(void); -+static void wifi_del_dev(void); -+ -+int wl_android_wifictrl_func_add(void) -+{ -+ int ret = 0; -+ sema_init(&wifi_control_sem, 0); -+ -+ ret = wifi_add_dev(); -+ if (ret) { -+ DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); -+ return ret; -+ } -+ g_wifidev_registered = 1; -+ -+ /* Waiting callback after platform_driver_register is done or exit with error */ -+ if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { -+ ret = -EINVAL; -+ DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__)); -+ } -+ -+ return ret; -+} -+ -+void wl_android_wifictrl_func_del(void) -+{ -+ if (g_wifidev_registered) -+ { -+ wifi_del_dev(); -+ g_wifidev_registered = 0; -+ } -+} -+ -+void* wl_android_prealloc(int section, unsigned long size) -+{ -+ void *alloc_ptr = NULL; -+ if (wifi_control_data && wifi_control_data->mem_prealloc) { -+ alloc_ptr = wifi_control_data->mem_prealloc(section, size); -+ if (alloc_ptr) { -+ DHD_INFO(("success alloc section %d\n", section)); -+ if (size != 0L) -+ bzero(alloc_ptr, size); -+ return alloc_ptr; -+ } -+ } -+ -+ DHD_ERROR(("can't alloc section %d\n", section)); -+ return NULL; -+} -+ -+int wifi_get_irq_number(unsigned long *irq_flags_ptr) -+{ -+ if (wifi_irqres) { -+ *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; -+ return (int)wifi_irqres->start; -+ } -+#ifdef CUSTOM_OOB_GPIO_NUM -+ return CUSTOM_OOB_GPIO_NUM; -+#else -+ return -1; -+#endif -+} -+ -+int wifi_set_power(int on, unsigned long msec) -+{ -+ DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); -+ if (wifi_control_data && wifi_control_data->set_power) { -+ wifi_control_data->set_power(on); -+ } -+ if (msec) -+ msleep(msec); -+ return 0; -+} -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) -+int wifi_get_mac_addr(unsigned char *buf) -+{ -+ DHD_ERROR(("%s\n", __FUNCTION__)); -+ if (!buf) -+ return -EINVAL; -+ if (wifi_control_data && wifi_control_data->get_mac_addr) { -+ return wifi_control_data->get_mac_addr(buf); -+ } -+ return -EOPNOTSUPP; -+} -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) -+void *wifi_get_country_code(char *ccode) -+{ -+ DHD_TRACE(("%s\n", __FUNCTION__)); -+ if (!ccode) -+ return NULL; -+ if (wifi_control_data && wifi_control_data->get_country_code) { -+ return wifi_control_data->get_country_code(ccode); -+ } -+ return NULL; -+} -+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ -+ -+static int wifi_set_carddetect(int on) -+{ -+ DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); -+ if (wifi_control_data && wifi_control_data->set_carddetect) { -+ wifi_control_data->set_carddetect(on); -+ } -+ return 0; -+} -+ -+static int wifi_probe(struct platform_device *pdev) -+{ -+ struct wifi_platform_data *wifi_ctrl = -+ (struct wifi_platform_data *)(pdev->dev.platform_data); -+ -+ wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); -+ if (wifi_irqres == NULL) -+ wifi_irqres = platform_get_resource_byname(pdev, -+ IORESOURCE_IRQ, "bcm4329_wlan_irq"); -+ wifi_control_data = wifi_ctrl; -+ wifi_set_power(1, 0); /* Power On */ -+ wifi_set_carddetect(1); /* CardDetect (0->1) */ -+ -+ up(&wifi_control_sem); -+ return 0; -+} -+ -+static int wifi_remove(struct platform_device *pdev) -+{ -+ struct wifi_platform_data *wifi_ctrl = -+ (struct wifi_platform_data *)(pdev->dev.platform_data); -+ -+ DHD_ERROR(("## %s\n", __FUNCTION__)); -+ wifi_control_data = wifi_ctrl; -+ -+ wifi_set_power(0, WIFI_TURNOFF_DELAY); /* Power Off */ -+ wifi_set_carddetect(0); /* CardDetect (1->0) */ -+ -+ up(&wifi_control_sem); -+ return 0; -+} -+ -+static int wifi_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ DHD_TRACE(("##> %s\n", __FUNCTION__)); -+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 -+ bcmsdh_oob_intr_set(0); -+#endif /* (OOB_INTR_ONLY) */ -+ return 0; -+} -+ -+static int wifi_resume(struct platform_device *pdev) -+{ -+ DHD_TRACE(("##> %s\n", __FUNCTION__)); -+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 -+ if (dhd_os_check_if_up(bcmsdh_get_drvdata())) -+ bcmsdh_oob_intr_set(1); -+#endif /* (OOB_INTR_ONLY) */ -+ return 0; -+} -+ -+static struct platform_driver wifi_device = { -+ .probe = wifi_probe, -+ .remove = wifi_remove, -+ .suspend = wifi_suspend, -+ .resume = wifi_resume, -+ .driver = { -+ .name = "bcmdhd_wlan", -+ } -+}; -+ -+static struct platform_driver wifi_device_legacy = { -+ .probe = wifi_probe, -+ .remove = wifi_remove, -+ .suspend = wifi_suspend, -+ .resume = wifi_resume, -+ .driver = { -+ .name = "bcm4329_wlan", -+ } -+}; -+ -+static int wifi_add_dev(void) -+{ -+ int ret; -+ DHD_TRACE(("## Calling platform_driver_register\n")); -+ ret = platform_driver_register(&wifi_device); -+ if (ret) -+ return ret; -+ -+ ret = platform_driver_register(&wifi_device_legacy); -+ return ret; -+} -+ -+static void wifi_del_dev(void) -+{ -+ DHD_TRACE(("## Unregister platform_driver_register\n")); -+ platform_driver_unregister(&wifi_device); -+ platform_driver_unregister(&wifi_device_legacy); -+} -+#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ -diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h -new file mode 100644 -index 00000000..583a1673 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_android.h -@@ -0,0 +1,57 @@ -+/* -+ * Linux cfg80211 driver - Android related functions -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_android.h 307885 2012-01-12 23:30:48Z $ -+ */ -+ -+#include <linux/module.h> -+#include <linux/netdevice.h> -+#include <wldev_common.h> -+ -+/** -+ * Android platform dependent functions, feel free to add Android specific functions here -+ * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd -+ * or cfg, define them as static in wl_android.c -+ */ -+ -+/** -+ * wl_android_init will be called from module init function (dhd_module_init now), similarly -+ * wl_android_exit will be called from module exit function (dhd_module_cleanup now) -+ */ -+int wl_android_init(void); -+int wl_android_exit(void); -+void wl_android_post_init(void); -+int wl_android_wifi_on(struct net_device *dev); -+int wl_android_wifi_off(struct net_device *dev); -+int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); -+ -+#if defined(CONFIG_WIFI_CONTROL_FUNC) -+int wl_android_wifictrl_func_add(void); -+void wl_android_wifictrl_func_del(void); -+void* wl_android_prealloc(int section, unsigned long size); -+ -+int wifi_get_irq_number(unsigned long *irq_flags_ptr); -+int wifi_set_power(int on, unsigned long msec); -+int wifi_get_mac_addr(unsigned char *buf); -+void *wifi_get_country_code(char *ccode); -+#endif /* CONFIG_WIFI_CONTROL_FUNC */ -diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c -new file mode 100644 -index 00000000..193dbe05 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c -@@ -0,0 +1,9750 @@ -+/* -+ * Linux cfg80211 driver -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_cfg80211.c 381665 2013-01-29 02:34:22Z $ -+ */ -+ -+#include <typedefs.h> -+#include <linuxver.h> -+#include <osl.h> -+#include <linux/kernel.h> -+ -+#include <bcmutils.h> -+#include <bcmwifi_channels.h> -+#include <bcmendian.h> -+#include <proto/ethernet.h> -+#include <proto/802.11.h> -+#include <linux/if_arp.h> -+#include <asm/uaccess.h> -+ -+#include <dngl_stats.h> -+#include <dhd.h> -+#include <dhdioctl.h> -+#include <wlioctl.h> -+#include <dhd_cfg80211.h> -+ -+#include <proto/ethernet.h> -+#include <linux/kernel.h> -+#include <linux/kthread.h> -+#include <linux/netdevice.h> -+#include <linux/sched.h> -+#include <linux/etherdevice.h> -+#include <linux/wireless.h> -+#include <linux/ieee80211.h> -+#include <linux/wait.h> -+#include <net/cfg80211.h> -+#include <net/rtnetlink.h> -+#include <wlioctl.h> -+#include <wldev_common.h> -+#include <wl_cfg80211.h> -+#include <wl_cfgp2p.h> -+#include <wl_android.h> -+ -+#ifdef PROP_TXSTATUS -+#include <dhd_wlfc.h> -+#endif -+ -+ -+#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) -+ -+static struct device *cfg80211_parent_dev = NULL; -+struct wl_priv *wlcfg_drv_priv = NULL; -+u32 wl_dbg_level = WL_DBG_ERR; -+ -+#define MAX_WAIT_TIME 1500 -+ -+#ifdef VSDB -+/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */ -+#define DEFAULT_SLEEP_TIME_VSDB 200 -+#define OFF_CHAN_TIME_THRESHOLD_MS 200 -+ -+/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */ -+#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) \ -+ do { \ -+ if (wl_get_drv_status(wl, CONNECTED, wl_to_prmry_ndev(wl)) || \ -+ wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { \ -+ msleep(DEFAULT_SLEEP_TIME_VSDB); \ -+ } \ -+ } while (0) -+#else /* VSDB */ -+/* if not VSDB, do nothing */ -+#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl) -+#endif /* VSDB */ -+ -+#ifdef WL_CFG80211_SYNC_GON -+#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) \ -+ (wl_get_drv_status_all(wl, SENDING_ACT_FRM) || \ -+ wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) -+#else -+#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl) wl_get_drv_status_all(wl, SENDING_ACT_FRM) -+#endif /* WL_CFG80211_SYNC_GON */ -+ -+#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL -+ -+ -+#define DNGL_FUNC(func, parameters) func parameters; -+#define COEX_DHCP -+ -+#define WLAN_EID_SSID 0 -+#define CH_MIN_5G_CHANNEL 34 -+#define CH_MIN_2G_CHANNEL 1 -+ -+/* This is to override regulatory domains defined in cfg80211 module (reg.c) -+ * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN -+ * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). -+ * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels. -+ * All the chnages in world regulatory domain are to be done here. -+ */ -+static const struct ieee80211_regdomain brcm_regdom = { -+ .n_reg_rules = 4, -+ .alpha2 = "99", -+ .reg_rules = { -+ /* IEEE 802.11b/g, channels 1..11 */ -+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), -+ /* If any */ -+ /* IEEE 802.11 channel 14 - Only JP enables -+ * this and for 802.11b only -+ */ -+ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0), -+ /* IEEE 802.11a, channel 36..64 */ -+ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), -+ /* IEEE 802.11a, channel 100..165 */ -+ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } -+}; -+ -+ -+/* Data Element Definitions */ -+#define WPS_ID_CONFIG_METHODS 0x1008 -+#define WPS_ID_REQ_TYPE 0x103A -+#define WPS_ID_DEVICE_NAME 0x1011 -+#define WPS_ID_VERSION 0x104A -+#define WPS_ID_DEVICE_PWD_ID 0x1012 -+#define WPS_ID_REQ_DEV_TYPE 0x106A -+#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053 -+#define WPS_ID_PRIM_DEV_TYPE 0x1054 -+ -+/* Device Password ID */ -+#define DEV_PW_DEFAULT 0x0000 -+#define DEV_PW_USER_SPECIFIED 0x0001, -+#define DEV_PW_MACHINE_SPECIFIED 0x0002 -+#define DEV_PW_REKEY 0x0003 -+#define DEV_PW_PUSHBUTTON 0x0004 -+#define DEV_PW_REGISTRAR_SPECIFIED 0x0005 -+ -+/* Config Methods */ -+#define WPS_CONFIG_USBA 0x0001 -+#define WPS_CONFIG_ETHERNET 0x0002 -+#define WPS_CONFIG_LABEL 0x0004 -+#define WPS_CONFIG_DISPLAY 0x0008 -+#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010 -+#define WPS_CONFIG_INT_NFC_TOKEN 0x0020 -+#define WPS_CONFIG_NFC_INTERFACE 0x0040 -+#define WPS_CONFIG_PUSHBUTTON 0x0080 -+#define WPS_CONFIG_KEYPAD 0x0100 -+#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280 -+#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480 -+#define WPS_CONFIG_VIRT_DISPLAY 0x2008 -+#define WPS_CONFIG_PHY_DISPLAY 0x4008 -+ -+#define PM_BLOCK 1 -+#define PM_ENABLE 0 -+ -+#ifndef RSSI_OFFSET -+#define RSSI_OFFSET 0 -+#endif -+/* -+ * cfg80211_ops api/callback list -+ */ -+static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, -+ const struct ether_addr *sa, const struct ether_addr *bssid, -+ u8 **pheader, u32 *body_len, u8 *pbody); -+static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, -+ struct cfg80211_scan_request *request, -+ struct cfg80211_ssid *this_ssid); -+static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, -+ struct cfg80211_scan_request *request); -+static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); -+static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_ibss_params *params); -+static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, -+ struct net_device *dev); -+static s32 wl_cfg80211_get_station(struct wiphy *wiphy, -+ struct net_device *dev, u8 *mac, -+ struct station_info *sinfo); -+static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, -+ struct net_device *dev, bool enabled, -+ s32 timeout); -+static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_connect_params *sme); -+static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, -+ u16 reason_code); -+static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, -+ enum nl80211_tx_power_setting type, -+ s32 dbm); -+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); -+static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, -+ struct net_device *dev, -+ u8 key_idx, bool unicast, bool multicast); -+static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, bool pairwise, const u8 *mac_addr, -+ struct key_params *params); -+static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, bool pairwise, const u8 *mac_addr); -+static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, bool pairwise, const u8 *mac_addr, -+ void *cookie, void (*callback) (void *cookie, -+ struct key_params *params)); -+static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, -+ struct net_device *dev, u8 key_idx); -+static s32 wl_cfg80211_resume(struct wiphy *wiphy); -+static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, -+ struct net_device *dev, u64 cookie); -+static s32 wl_cfg80211_del_station(struct wiphy *wiphy, -+ struct net_device *ndev, u8* mac_addr); -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) -+static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); -+#else -+static s32 wl_cfg80211_suspend(struct wiphy *wiphy); -+#endif -+static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_pmksa *pmksa); -+static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_pmksa *pmksa); -+static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, -+ struct net_device *dev); -+static s32 wl_notify_escan_complete(struct wl_priv *wl, -+ struct net_device *ndev, bool aborted, bool fw_abort); -+/* -+ * event & event Q handlers for cfg80211 interfaces -+ */ -+static s32 wl_create_event_handler(struct wl_priv *wl); -+static void wl_destroy_event_handler(struct wl_priv *wl); -+static s32 wl_event_handler(void *data); -+static void wl_init_eq(struct wl_priv *wl); -+static void wl_flush_eq(struct wl_priv *wl); -+static unsigned long wl_lock_eq(struct wl_priv *wl); -+static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags); -+static void wl_init_eq_lock(struct wl_priv *wl); -+static void wl_init_event_handler(struct wl_priv *wl); -+static struct wl_event_q *wl_deq_event(struct wl_priv *wl); -+static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type, -+ const wl_event_msg_t *msg, void *data); -+static void wl_put_event(struct wl_event_q *e); -+static void wl_wakeup_event(struct wl_priv *wl); -+static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+static s32 wl_notify_connect_status(struct wl_priv *wl, -+ struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+static s32 wl_notify_roaming_status(struct wl_priv *wl, -+ struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data, bool completed); -+static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+#ifdef WL_SCHED_SCAN -+static s32 -+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+#endif /* WL_SCHED_SCAN */ -+#ifdef PNO_SUPPORT -+static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+#endif /* PNO_SUPPORT */ -+static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, -+ enum wl_status state, bool set); -+/* -+ * register/deregister parent device -+ */ -+static void wl_cfg80211_clear_parent_dev(void); -+ -+/* -+ * ioctl utilites -+ */ -+ -+/* -+ * cfg80211 set_wiphy_params utilities -+ */ -+static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); -+static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold); -+static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); -+ -+/* -+ * wl profile utilities -+ */ -+static s32 wl_update_prof(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data, s32 item); -+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item); -+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev); -+ -+/* -+ * cfg80211 connect utilites -+ */ -+static s32 wl_set_wpa_version(struct net_device *dev, -+ struct cfg80211_connect_params *sme); -+static s32 wl_set_auth_type(struct net_device *dev, -+ struct cfg80211_connect_params *sme); -+static s32 wl_set_set_cipher(struct net_device *dev, -+ struct cfg80211_connect_params *sme); -+static s32 wl_set_key_mgmt(struct net_device *dev, -+ struct cfg80211_connect_params *sme); -+static s32 wl_set_set_sharedkey(struct net_device *dev, -+ struct cfg80211_connect_params *sme); -+static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev); -+static void wl_ch_to_chanspec(int ch, -+ struct wl_join_params *join_params, size_t *join_params_size); -+ -+/* -+ * information element utilities -+ */ -+static void wl_rst_ie(struct wl_priv *wl); -+static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v); -+static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); -+static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); -+static u32 wl_get_ielen(struct wl_priv *wl); -+ -+ -+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev); -+static void wl_free_wdev(struct wl_priv *wl); -+#ifdef CONFIG_CFG80211_INTERNAL_REGDB -+static int -+wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); -+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ -+ -+static s32 wl_inform_bss(struct wl_priv *wl); -+static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done); -+static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done); -+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); -+s32 wl_cfg80211_channel_to_freq(u32 channel); -+ -+#if defined(DHCP_SCAN_SUPPRESS) -+static void wl_cfg80211_work_handler(struct work_struct *work); -+static void wl_cfg80211_scan_supp_timerfunc(ulong data); -+#endif /* DHCP_SCAN_SUPPRESS */ -+ -+static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, const u8 *mac_addr, -+ struct key_params *params); -+/* -+ * key indianess swap utilities -+ */ -+static void swap_key_from_BE(struct wl_wsec_key *key); -+static void swap_key_to_BE(struct wl_wsec_key *key); -+ -+/* -+ * wl_priv memory init/deinit utilities -+ */ -+static s32 wl_init_priv_mem(struct wl_priv *wl); -+static void wl_deinit_priv_mem(struct wl_priv *wl); -+ -+static void wl_delay(u32 ms); -+ -+/* -+ * ibss mode utilities -+ */ -+static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev); -+static __used bool wl_is_ibssstarter(struct wl_priv *wl); -+ -+/* -+ * link up/down , default configuration utilities -+ */ -+static s32 __wl_cfg80211_up(struct wl_priv *wl); -+static s32 __wl_cfg80211_down(struct wl_priv *wl); -+static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e); -+static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev); -+static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e); -+static void wl_link_up(struct wl_priv *wl); -+static void wl_link_down(struct wl_priv *wl); -+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); -+static void wl_init_conf(struct wl_conf *conf); -+ -+/* -+ * iscan handler -+ */ -+static void wl_iscan_timer(unsigned long data); -+static void wl_term_iscan(struct wl_priv *wl); -+static s32 wl_init_scan(struct wl_priv *wl); -+static s32 wl_iscan_thread(void *data); -+static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, -+ u16 action); -+static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request); -+static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan); -+static s32 wl_invoke_iscan(struct wl_priv *wl); -+static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, -+ struct wl_scan_results **bss_list); -+static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted); -+static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan); -+static s32 wl_iscan_done(struct wl_priv *wl); -+static s32 wl_iscan_pending(struct wl_priv *wl); -+static s32 wl_iscan_inprogress(struct wl_priv *wl); -+static s32 wl_iscan_aborted(struct wl_priv *wl); -+ -+/* -+ * find most significant bit set -+ */ -+static __used u32 wl_find_msb(u16 bit16); -+ -+/* -+ * rfkill support -+ */ -+static int wl_setup_rfkill(struct wl_priv *wl, bool setup); -+static int wl_rfkill_set(void *data, bool blocked); -+ -+static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, -+ int nprobes, int *out_params_size); -+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac); -+ -+/* -+ * Some external functions, TODO: move them to dhd_linux.h -+ */ -+int dhd_add_monitor(char *name, struct net_device **new_ndev); -+int dhd_del_monitor(struct net_device *ndev); -+int dhd_monitor_init(void *dhd_pub); -+int dhd_monitor_uninit(void); -+int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); -+ -+ -+ -+#define CHECK_SYS_UP(wlpriv) \ -+do { \ -+ struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \ -+ if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \ -+ WL_INFO(("device is not ready\n")); \ -+ return -EIO; \ -+ } \ -+} while (0) -+ -+ -+#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ -+ (akm) == RSN_AKM_UNSPECIFIED || \ -+ (akm) == RSN_AKM_PSK) -+ -+ -+extern int dhd_wait_pend8021x(struct net_device *dev); -+#ifdef PROP_TXSTATUS_VSDB -+extern int disable_proptx; -+extern int dhd_wlfc_init(dhd_pub_t *dhd); -+extern void dhd_wlfc_deinit(dhd_pub_t *dhd); -+#endif /* PROP_TXSTATUS_VSDB */ -+ -+#if (WL_DBG_LEVEL > 0) -+#define WL_DBG_ESTR_MAX 50 -+static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = { -+ "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND", -+ "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC", -+ "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END", -+ "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM", -+ "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH", -+ "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND", -+ "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", -+ "PFN_NET_LOST", -+ "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", -+ "IBSS_ASSOC", -+ "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT", -+ "PROBREQ_MSG", -+ "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", -+ "EXCEEDED_MEDIUM_TIME", "ICV_ERROR", -+ "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE", -+ "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE", -+ "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG", -+ "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND", -+ "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED", -+ "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT", -+ "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE", -+ "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP", -+ "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE" -+}; -+#endif /* WL_DBG_LEVEL */ -+ -+#define CHAN2G(_channel, _freq, _flags) { \ -+ .band = IEEE80211_BAND_2GHZ, \ -+ .center_freq = (_freq), \ -+ .hw_value = (_channel), \ -+ .flags = (_flags), \ -+ .max_antenna_gain = 0, \ -+ .max_power = 30, \ -+} -+ -+#define CHAN5G(_channel, _flags) { \ -+ .band = IEEE80211_BAND_5GHZ, \ -+ .center_freq = 5000 + (5 * (_channel)), \ -+ .hw_value = (_channel), \ -+ .flags = (_flags), \ -+ .max_antenna_gain = 0, \ -+ .max_power = 30, \ -+} -+ -+#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) -+#define RATETAB_ENT(_rateid, _flags) \ -+ { \ -+ .bitrate = RATE_TO_BASE100KBPS(_rateid), \ -+ .hw_value = (_rateid), \ -+ .flags = (_flags), \ -+ } -+ -+static struct ieee80211_rate __wl_rates[] = { -+ RATETAB_ENT(WLC_RATE_1M, 0), -+ RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), -+ RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), -+ RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), -+ RATETAB_ENT(WLC_RATE_6M, 0), -+ RATETAB_ENT(WLC_RATE_9M, 0), -+ RATETAB_ENT(WLC_RATE_12M, 0), -+ RATETAB_ENT(WLC_RATE_18M, 0), -+ RATETAB_ENT(WLC_RATE_24M, 0), -+ RATETAB_ENT(WLC_RATE_36M, 0), -+ RATETAB_ENT(WLC_RATE_48M, 0), -+ RATETAB_ENT(WLC_RATE_54M, 0) -+}; -+ -+#define wl_a_rates (__wl_rates + 4) -+#define wl_a_rates_size 8 -+#define wl_g_rates (__wl_rates + 0) -+#define wl_g_rates_size 12 -+ -+static struct ieee80211_channel __wl_2ghz_channels[] = { -+ CHAN2G(1, 2412, 0), -+ CHAN2G(2, 2417, 0), -+ CHAN2G(3, 2422, 0), -+ CHAN2G(4, 2427, 0), -+ CHAN2G(5, 2432, 0), -+ CHAN2G(6, 2437, 0), -+ CHAN2G(7, 2442, 0), -+ CHAN2G(8, 2447, 0), -+ CHAN2G(9, 2452, 0), -+ CHAN2G(10, 2457, 0), -+ CHAN2G(11, 2462, 0), -+ CHAN2G(12, 2467, 0), -+ CHAN2G(13, 2472, 0), -+ CHAN2G(14, 2484, 0) -+}; -+ -+static struct ieee80211_channel __wl_5ghz_a_channels[] = { -+ CHAN5G(34, 0), CHAN5G(36, 0), -+ CHAN5G(38, 0), CHAN5G(40, 0), -+ CHAN5G(42, 0), CHAN5G(44, 0), -+ CHAN5G(46, 0), CHAN5G(48, 0), -+ CHAN5G(52, 0), CHAN5G(56, 0), -+ CHAN5G(60, 0), CHAN5G(64, 0), -+ CHAN5G(100, 0), CHAN5G(104, 0), -+ CHAN5G(108, 0), CHAN5G(112, 0), -+ CHAN5G(116, 0), CHAN5G(120, 0), -+ CHAN5G(124, 0), CHAN5G(128, 0), -+ CHAN5G(132, 0), CHAN5G(136, 0), -+ CHAN5G(140, 0), CHAN5G(149, 0), -+ CHAN5G(153, 0), CHAN5G(157, 0), -+ CHAN5G(161, 0), CHAN5G(165, 0) -+}; -+ -+static struct ieee80211_supported_band __wl_band_2ghz = { -+ .band = IEEE80211_BAND_2GHZ, -+ .channels = __wl_2ghz_channels, -+ .n_channels = ARRAY_SIZE(__wl_2ghz_channels), -+ .bitrates = wl_g_rates, -+ .n_bitrates = wl_g_rates_size -+}; -+ -+static struct ieee80211_supported_band __wl_band_5ghz_a = { -+ .band = IEEE80211_BAND_5GHZ, -+ .channels = __wl_5ghz_a_channels, -+ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), -+ .bitrates = wl_a_rates, -+ .n_bitrates = wl_a_rates_size -+}; -+ -+static const u32 __wl_cipher_suites[] = { -+ WLAN_CIPHER_SUITE_WEP40, -+ WLAN_CIPHER_SUITE_WEP104, -+ WLAN_CIPHER_SUITE_TKIP, -+ WLAN_CIPHER_SUITE_CCMP, -+ WLAN_CIPHER_SUITE_AES_CMAC, -+}; -+ -+ -+/* IOCtl version read from targeted driver */ -+static int ioctl_version; -+ -+/* Return a new chanspec given a legacy chanspec -+ * Returns INVCHANSPEC on error -+ */ -+static chanspec_t -+wl_chspec_from_legacy(chanspec_t legacy_chspec) -+{ -+ chanspec_t chspec; -+ -+ /* get the channel number */ -+ chspec = LCHSPEC_CHANNEL(legacy_chspec); -+ -+ /* convert the band */ -+ if (LCHSPEC_IS2G(legacy_chspec)) { -+ chspec |= WL_CHANSPEC_BAND_2G; -+ } else { -+ chspec |= WL_CHANSPEC_BAND_5G; -+ } -+ -+ /* convert the bw and sideband */ -+ if (LCHSPEC_IS20(legacy_chspec)) { -+ chspec |= WL_CHANSPEC_BW_20; -+ } else { -+ chspec |= WL_CHANSPEC_BW_40; -+ if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { -+ chspec |= WL_CHANSPEC_CTL_SB_L; -+ } else { -+ chspec |= WL_CHANSPEC_CTL_SB_U; -+ } -+ } -+ -+ if (wf_chspec_malformed(chspec)) { -+ WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", -+ chspec)); -+ return INVCHANSPEC; -+ } -+ -+ return chspec; -+} -+ -+/* Return a legacy chanspec given a new chanspec -+ * Returns INVCHANSPEC on error -+ */ -+static chanspec_t -+wl_chspec_to_legacy(chanspec_t chspec) -+{ -+ chanspec_t lchspec; -+ -+ if (wf_chspec_malformed(chspec)) { -+ WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", -+ chspec)); -+ return INVCHANSPEC; -+ } -+ -+ /* get the channel number */ -+ lchspec = CHSPEC_CHANNEL(chspec); -+ -+ /* convert the band */ -+ if (CHSPEC_IS2G(chspec)) { -+ lchspec |= WL_LCHANSPEC_BAND_2G; -+ } else { -+ lchspec |= WL_LCHANSPEC_BAND_5G; -+ } -+ -+ /* convert the bw and sideband */ -+ if (CHSPEC_IS20(chspec)) { -+ lchspec |= WL_LCHANSPEC_BW_20; -+ lchspec |= WL_LCHANSPEC_CTL_SB_NONE; -+ } else if (CHSPEC_IS40(chspec)) { -+ lchspec |= WL_LCHANSPEC_BW_40; -+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { -+ lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; -+ } else { -+ lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; -+ } -+ } else { -+ /* cannot express the bandwidth */ -+ char chanbuf[CHANSPEC_STR_LEN]; -+ WL_ERR(( -+ "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " -+ "to pre-11ac format\n", -+ wf_chspec_ntoa(chspec, chanbuf), chspec)); -+ return INVCHANSPEC; -+ } -+ -+ return lchspec; -+} -+ -+/* given a chanspec value, do the endian and chanspec version conversion to -+ * a chanspec_t value -+ * Returns INVCHANSPEC on error -+ */ -+static chanspec_t -+wl_chspec_host_to_driver(chanspec_t chanspec) -+{ -+ if (ioctl_version == 1) { -+ chanspec = wl_chspec_to_legacy(chanspec); -+ if (chanspec == INVCHANSPEC) { -+ return chanspec; -+ } -+ } -+ chanspec = htodchanspec(chanspec); -+ -+ return chanspec; -+} -+ -+/* given a channel value, do the endian and chanspec version conversion to -+ * a chanspec_t value -+ * Returns INVCHANSPEC on error -+ */ -+chanspec_t -+wl_ch_host_to_driver(u16 channel) -+{ -+ -+ chanspec_t chanspec; -+ -+ chanspec = channel & WL_CHANSPEC_CHAN_MASK; -+ -+ if (channel <= CH_MAX_2G_CHANNEL) -+ chanspec |= WL_CHANSPEC_BAND_2G; -+ else -+ chanspec |= WL_CHANSPEC_BAND_5G; -+ -+ chanspec |= WL_CHANSPEC_BW_20; -+ chanspec |= WL_CHANSPEC_CTL_SB_NONE; -+ -+ return wl_chspec_host_to_driver(chanspec); -+} -+ -+/* given a chanspec value from the driver, do the endian and chanspec version conversion to -+ * a chanspec_t value -+ * Returns INVCHANSPEC on error -+ */ -+static chanspec_t -+wl_chspec_driver_to_host(chanspec_t chanspec) -+{ -+ chanspec = dtohchanspec(chanspec); -+ if (ioctl_version == 1) { -+ chanspec = wl_chspec_from_legacy(chanspec); -+ } -+ -+ return chanspec; -+} -+ -+/* There isn't a lot of sense in it, but you can transmit anything you like */ -+static const struct ieee80211_txrx_stypes -+wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { -+ [NL80211_IFTYPE_ADHOC] = { -+ .tx = 0xffff, -+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) -+ }, -+ [NL80211_IFTYPE_STATION] = { -+ .tx = 0xffff, -+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | -+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) -+ }, -+ [NL80211_IFTYPE_AP] = { -+ .tx = 0xffff, -+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | -+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | -+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | -+ BIT(IEEE80211_STYPE_DISASSOC >> 4) | -+ BIT(IEEE80211_STYPE_AUTH >> 4) | -+ BIT(IEEE80211_STYPE_DEAUTH >> 4) | -+ BIT(IEEE80211_STYPE_ACTION >> 4) -+ }, -+ [NL80211_IFTYPE_AP_VLAN] = { -+ /* copy AP */ -+ .tx = 0xffff, -+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | -+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | -+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | -+ BIT(IEEE80211_STYPE_DISASSOC >> 4) | -+ BIT(IEEE80211_STYPE_AUTH >> 4) | -+ BIT(IEEE80211_STYPE_DEAUTH >> 4) | -+ BIT(IEEE80211_STYPE_ACTION >> 4) -+ }, -+ [NL80211_IFTYPE_P2P_CLIENT] = { -+ .tx = 0xffff, -+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | -+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) -+ }, -+ [NL80211_IFTYPE_P2P_GO] = { -+ .tx = 0xffff, -+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | -+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | -+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | -+ BIT(IEEE80211_STYPE_DISASSOC >> 4) | -+ BIT(IEEE80211_STYPE_AUTH >> 4) | -+ BIT(IEEE80211_STYPE_DEAUTH >> 4) | -+ BIT(IEEE80211_STYPE_ACTION >> 4) -+ } -+}; -+ -+static void swap_key_from_BE(struct wl_wsec_key *key) -+{ -+ key->index = htod32(key->index); -+ key->len = htod32(key->len); -+ key->algo = htod32(key->algo); -+ key->flags = htod32(key->flags); -+ key->rxiv.hi = htod32(key->rxiv.hi); -+ key->rxiv.lo = htod16(key->rxiv.lo); -+ key->iv_initialized = htod32(key->iv_initialized); -+} -+ -+static void swap_key_to_BE(struct wl_wsec_key *key) -+{ -+ key->index = dtoh32(key->index); -+ key->len = dtoh32(key->len); -+ key->algo = dtoh32(key->algo); -+ key->flags = dtoh32(key->flags); -+ key->rxiv.hi = dtoh32(key->rxiv.hi); -+ key->rxiv.lo = dtoh16(key->rxiv.lo); -+ key->iv_initialized = dtoh32(key->iv_initialized); -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) -+/* For debug: Dump the contents of the encoded wps ie buffe */ -+static void -+wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc) -+{ -+ #define WPS_IE_FIXED_LEN 6 -+ u16 len; -+ u8 *subel = NULL; -+ u16 subelt_id; -+ u16 subelt_len; -+ u16 val; -+ u8 *valptr = (uint8*) &val; -+ if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) { -+ WL_ERR(("invalid argument : NULL\n")); -+ return; -+ } -+ len = (u16)wps_ie[TLV_LEN_OFF]; -+ -+ if (len > wps_ie_len) { -+ WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len)); -+ return; -+ } -+ WL_DBG(("wps_ie len=%d\n", len)); -+ len -= 4; /* for the WPS IE's OUI, oui_type fields */ -+ subel = wps_ie + WPS_IE_FIXED_LEN; -+ while (len >= 4) { /* must have attr id, attr len fields */ -+ valptr[0] = *subel++; -+ valptr[1] = *subel++; -+ subelt_id = HTON16(val); -+ -+ valptr[0] = *subel++; -+ valptr[1] = *subel++; -+ subelt_len = HTON16(val); -+ -+ len -= 4; /* for the attr id, attr len fields */ -+ len -= subelt_len; /* for the remaining fields in this attribute */ -+ WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", -+ subel, subelt_id, subelt_len)); -+ -+ if (subelt_id == WPS_ID_VERSION) { -+ WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel)); -+ } else if (subelt_id == WPS_ID_REQ_TYPE) { -+ WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel)); -+ } else if (subelt_id == WPS_ID_CONFIG_METHODS) { -+ valptr[0] = *subel; -+ valptr[1] = *(subel + 1); -+ WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val))); -+ } else if (subelt_id == WPS_ID_DEVICE_NAME) { -+ char devname[100]; -+ memcpy(devname, subel, subelt_len); -+ devname[subelt_len] = '\0'; -+ WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", -+ devname, subelt_len)); -+ } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) { -+ valptr[0] = *subel; -+ valptr[1] = *(subel + 1); -+ WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val))); -+ *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false; -+ } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) { -+ valptr[0] = *subel; -+ valptr[1] = *(subel + 1); -+ WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val))); -+ valptr[0] = *(subel + 6); -+ valptr[1] = *(subel + 7); -+ WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val))); -+ } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) { -+ valptr[0] = *subel; -+ valptr[1] = *(subel + 1); -+ WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val))); -+ valptr[0] = *(subel + 6); -+ valptr[1] = *(subel + 7); -+ WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val))); -+ } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) { -+ valptr[0] = *subel; -+ valptr[1] = *(subel + 1); -+ WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS" -+ ": cat=%u\n", HTON16(val))); -+ } else { -+ WL_DBG((" unknown attr 0x%x\n", subelt_id)); -+ } -+ -+ subel += subelt_len; -+ } -+} -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ -+ -+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) -+{ -+ chanspec_t chspec; -+ int err = 0; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_device *dev = wl_to_prmry_ndev(wl); -+ struct ether_addr bssid; -+ struct wl_bss_info *bss = NULL; -+ -+ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { -+ /* STA interface is not associated. So start the new interface on a temp -+ * channel . Later proper channel will be applied by the above framework -+ * via set_channel (cfg80211 API). -+ */ -+ WL_DBG(("Not associated. Return a temp channel. \n")); -+ return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); -+ } -+ -+ -+ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); -+ if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, -+ WL_EXTRA_BUF_MAX, false))) { -+ WL_ERR(("Failed to get associated bss info, use temp channel \n")); -+ chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN); -+ } -+ else { -+ bss = (struct wl_bss_info *) (wl->extra_buf + 4); -+ chspec = bss->chanspec; -+ WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec)); -+ } -+ return chspec; -+} -+ -+static struct net_device* wl_cfg80211_add_monitor_if(char *name) -+{ -+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) -+ WL_INFO(("wl_cfg80211_add_monitor_if: No more support monitor interface\n")); -+ return ERR_PTR(-EOPNOTSUPP); -+#else -+ struct net_device* ndev = NULL; -+ -+ dhd_add_monitor(name, &ndev); -+ WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); -+ return ndev; -+#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ -+} -+ -+static struct net_device * -+wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, -+ enum nl80211_iftype type, u32 *flags, -+ struct vif_params *params) -+{ -+ s32 err; -+ s32 timeout = -1; -+ s32 wlif_type = -1; -+ s32 mode = 0; -+ s32 val = 0; -+ s32 dhd_mode = 0; -+ chanspec_t chspec; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_device *_ndev; -+ struct ether_addr primary_mac; -+ int (*net_attach)(void *dhdp, int ifidx); -+ bool rollback_lock = false; -+#ifdef PROP_TXSTATUS_VSDB -+ s32 up = 1; -+ dhd_pub_t *dhd; -+#endif /* PROP_TXSTATUS_VSDB */ -+ -+ if (!wl) -+ return ERR_PTR(-EINVAL); -+ -+#ifdef PROP_TXSTATUS_VSDB -+ dhd = (dhd_pub_t *)(wl->pub); -+#endif /* PROP_TXSTATUS_VSDB */ -+ -+ -+ /* Use primary I/F for sending cmds down to firmware */ -+ _ndev = wl_to_prmry_ndev(wl); -+ -+ WL_DBG(("if name: %s, type: %d\n", name, type)); -+ switch (type) { -+ case NL80211_IFTYPE_ADHOC: -+ case NL80211_IFTYPE_AP_VLAN: -+ case NL80211_IFTYPE_WDS: -+ case NL80211_IFTYPE_MESH_POINT: -+ WL_ERR(("Unsupported interface type\n")); -+ mode = WL_MODE_IBSS; -+ return NULL; -+ case NL80211_IFTYPE_MONITOR: -+ return wl_cfg80211_add_monitor_if(name); -+ case NL80211_IFTYPE_P2P_CLIENT: -+ case NL80211_IFTYPE_STATION: -+ wlif_type = WL_P2P_IF_CLIENT; -+ mode = WL_MODE_BSS; -+ break; -+ case NL80211_IFTYPE_P2P_GO: -+ case NL80211_IFTYPE_AP: -+ wlif_type = WL_P2P_IF_GO; -+ mode = WL_MODE_AP; -+ break; -+ default: -+ WL_ERR(("Unsupported interface type\n")); -+ return NULL; -+ break; -+ } -+ -+ if (!name) { -+ WL_ERR(("name is NULL\n")); -+ return NULL; -+ } -+ if (wl->p2p_supported && (wlif_type != -1)) { -+ if (wl_get_p2p_status(wl, IF_DELETING)) { -+ /* wait till IF_DEL is complete -+ * release the lock for the unregister to proceed -+ */ -+ if (rtnl_is_locked()) { -+ rtnl_unlock(); -+ rollback_lock = true; -+ } -+ WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n", -+ __func__)); -+ timeout = wait_event_interruptible_timeout(wl->netif_change_event, -+ (wl_get_p2p_status(wl, IF_DELETING) == false), -+ msecs_to_jiffies(MAX_WAIT_TIME)); -+ -+ /* put back the rtnl_lock again */ -+ if (rollback_lock) { -+ rtnl_lock(); -+ rollback_lock = false; -+ } -+ if (timeout > 0) { -+ WL_ERR(("IF DEL is Success\n")); -+ -+ } else { -+ WL_ERR(("timeount < 0, return -EAGAIN\n")); -+ return ERR_PTR(-EAGAIN); -+ } -+ /* It should be now be safe to put this check here since we are sure -+ * by now netdev_notifier (unregister) would have been called -+ */ -+ if (wl->iface_cnt == IFACE_MAX_CNT) -+ return ERR_PTR(-ENOMEM); -+ } -+ -+#ifdef PROP_TXSTATUS_VSDB -+ if (!dhd) -+ return ERR_PTR(-ENODEV); -+#endif /* PROP_TXSTATUS_VSDB */ -+ if (!wl->p2p) -+ return ERR_PTR(-ENODEV); -+ -+ if (wl->p2p && !wl->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { -+ p2p_on(wl) = true; -+ wl_cfgp2p_set_firm_p2p(wl); -+ wl_cfgp2p_init_discovery(wl); -+ get_primary_mac(wl, &primary_mac); -+ wl_cfgp2p_generate_bss_mac(&primary_mac, -+ &wl->p2p->dev_addr, &wl->p2p->int_addr); -+ } -+ -+ memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); -+ strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); -+ -+ wl_notify_escan_complete(wl, _ndev, true, true); -+#ifdef PROP_TXSTATUS_VSDB -+ if (!wl->wlfc_on && !disable_proptx) { -+ dhd->wlfc_enabled = true; -+ dhd_wlfc_init(dhd); -+ err = wldev_ioctl(_ndev, WLC_UP, &up, sizeof(s32), true); -+ if (err < 0) -+ WL_ERR(("WLC_UP return err:%d\n", err)); -+ wl->wlfc_on = true; -+ } -+#endif /* PROP_TXSTATUS_VSDB */ -+ -+ /* In concurrency case, STA may be already associated in a particular channel. -+ * so retrieve the current channel of primary interface and then start the virtual -+ * interface on that. -+ */ -+ chspec = wl_cfg80211_get_shared_freq(wiphy); -+ -+ /* For P2P mode, use P2P-specific driver features to create the -+ * bss: "wl p2p_ifadd" -+ */ -+ wl_set_p2p_status(wl, IF_ADD); -+ if (wlif_type == WL_P2P_IF_GO) -+ wldev_iovar_setint(_ndev, "mpc", 0); -+ err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); -+ -+ if (unlikely(err)) { -+ WL_ERR((" virtual iface add failed (%d) \n", err)); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ timeout = wait_event_interruptible_timeout(wl->netif_change_event, -+ (wl_get_p2p_status(wl, IF_ADD) == false), -+ msecs_to_jiffies(MAX_WAIT_TIME)); -+ if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) { -+ -+ struct wireless_dev *vwdev; -+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); -+ if (unlikely(!vwdev)) { -+ WL_ERR(("Could not allocate wireless device\n")); -+ return ERR_PTR(-ENOMEM); -+ } -+ vwdev->wiphy = wl->wdev->wiphy; -+ WL_INFO((" virtual interface(%s) is created memalloc done \n", -+ wl->p2p->vir_ifname)); -+ vwdev->iftype = type; -+ _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); -+ _ndev->ieee80211_ptr = vwdev; -+ SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy)); -+ vwdev->netdev = _ndev; -+ wl_set_drv_status(wl, READY, _ndev); -+ wl->p2p->vif_created = true; -+ wl_set_mode_by_netdev(wl, _ndev, mode); -+ net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION); -+ if (rtnl_is_locked()) { -+ rtnl_unlock(); -+ rollback_lock = true; -+ } -+ if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) { -+ wl_alloc_netinfo(wl, _ndev, vwdev, mode, PM_ENABLE); -+ val = 1; -+ /* Disable firmware roaming for P2P interface */ -+ wldev_iovar_setint(_ndev, "roam_off", val); -+ WL_ERR((" virtual interface(%s) is " -+ "created net attach done\n", wl->p2p->vir_ifname)); -+ if (mode == WL_MODE_AP) -+ wl_set_drv_status(wl, CONNECTED, _ndev); -+ if (type == NL80211_IFTYPE_P2P_CLIENT) -+ dhd_mode = DHD_FLAG_P2P_GC_MODE; -+ else if (type == NL80211_IFTYPE_P2P_GO) -+ dhd_mode = DHD_FLAG_P2P_GO_MODE; -+ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); -+ } else { -+ /* put back the rtnl_lock again */ -+ if (rollback_lock) -+ rtnl_lock(); -+ goto fail; -+ } -+ /* put back the rtnl_lock again */ -+ if (rollback_lock) -+ rtnl_lock(); -+ return _ndev; -+ -+ } else { -+ wl_clr_p2p_status(wl, IF_ADD); -+ WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname)); -+ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); -+ wl->p2p->vif_created = false; -+#ifdef PROP_TXSTATUS_VSDB -+ if (dhd->wlfc_enabled && wl->wlfc_on) { -+ dhd->wlfc_enabled = false; -+ dhd_wlfc_deinit(dhd); -+ wl->wlfc_on = false; -+ } -+#endif /* PROP_TXSTATUS_VSDB */ -+ } -+ } -+fail: -+ if (wlif_type == WL_P2P_IF_GO) -+ wldev_iovar_setint(_ndev, "mpc", 1); -+ return ERR_PTR(-ENODEV); -+} -+ -+static s32 -+wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) -+{ -+ struct ether_addr p2p_mac; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 timeout = -1; -+ s32 ret = 0; -+ WL_DBG(("Enter\n")); -+ -+ if (wl->p2p_net == dev) { -+ /* Since there is no ifidx corresponding to p2p0, cmds to -+ * firmware should be routed through primary I/F -+ */ -+ dev = wl_to_prmry_ndev(wl); -+ } -+ -+ if (wl->p2p_supported) { -+ memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); -+ -+ /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases -+ */ -+ WL_DBG(("P2P: GO_NEG_PHASE status cleared ")); -+ wl_clr_p2p_status(wl, GO_NEG_PHASE); -+ if (wl->p2p->vif_created) { -+ if (wl_get_drv_status(wl, SCANNING, dev)) { -+ wl_notify_escan_complete(wl, dev, true, true); -+ } -+ wldev_iovar_setint(dev, "mpc", 1); -+ -+ /* for GC */ -+ if (wl_get_drv_status(wl, DISCONNECTING, dev) && -+ (wl_get_mode_by_netdev(wl, dev) != WL_MODE_AP)) { -+ WL_ERR(("Wait for Link Down event for GC !\n")); -+ wait_for_completion_timeout -+ (&wl->iface_disable, msecs_to_jiffies(500)); -+ } -+ wl_set_p2p_status(wl, IF_DELETING); -+ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); -+ -+ /* for GO */ -+ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { -+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); -+ /* disable interface before bsscfg free */ -+ ret = wl_cfgp2p_ifdisable(wl, &p2p_mac); -+ /* if fw doesn't support "ifdis", -+ do not wait for link down of ap mode -+ */ -+ if (ret == 0) { -+ WL_ERR(("Wait for Link Down event for GO !!!\n")); -+ wait_for_completion_timeout(&wl->iface_disable, -+ msecs_to_jiffies(500)); -+ } else { -+ msleep(300); -+ } -+ } -+ wl_cfgp2p_clear_management_ie(wl, wl_cfgp2p_find_idx(wl, dev)); -+ /* delete interface after link down */ -+ ret = wl_cfgp2p_ifdel(wl, &p2p_mac); -+ /* Firmware could not delete the interface so we will not get WLC_E_IF -+ * event for cleaning the dhd virtual nw interace -+ * So lets do it here. Failures from fw will ensure the application to do -+ * ifconfig <inter> down and up sequnce, which will reload the fw -+ * however we should cleanup the linux network virtual interfaces -+ */ -+ /* Request framework to RESET and clean up */ -+ if (ret) { -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ WL_ERR(("Firmware returned an error (%d) from p2p_ifdel" -+ "HANG Notification sent to %s\n", ret, ndev->name)); -+ net_os_send_hang_message(ndev); -+ } -+ /* Wait for IF_DEL operation to be finished in firmware */ -+ timeout = wait_event_interruptible_timeout(wl->netif_change_event, -+ (wl->p2p->vif_created == false), -+ msecs_to_jiffies(MAX_WAIT_TIME)); -+ if (timeout > 0 && (wl->p2p->vif_created == false)) { -+ WL_DBG(("IFDEL operation done\n")); -+ } else { -+ WL_ERR(("IFDEL didn't complete properly\n")); -+ } -+ ret = dhd_del_monitor(dev); -+ } -+ } -+ return ret; -+} -+ -+static s32 -+wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, -+ enum nl80211_iftype type, u32 *flags, -+ struct vif_params *params) -+{ -+ s32 ap = 0; -+ s32 infra = 0; -+ s32 wlif_type; -+ s32 mode = 0; -+ chanspec_t chspec; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+ WL_DBG(("Enter type %d\n", type)); -+ switch (type) { -+ case NL80211_IFTYPE_MONITOR: -+ case NL80211_IFTYPE_WDS: -+ case NL80211_IFTYPE_MESH_POINT: -+ ap = 1; -+ WL_ERR(("type (%d) : currently we do not support this type\n", -+ type)); -+ break; -+ case NL80211_IFTYPE_ADHOC: -+ mode = WL_MODE_IBSS; -+ break; -+ case NL80211_IFTYPE_STATION: -+ case NL80211_IFTYPE_P2P_CLIENT: -+ mode = WL_MODE_BSS; -+ infra = 1; -+ break; -+ case NL80211_IFTYPE_AP: -+ case NL80211_IFTYPE_AP_VLAN: -+ case NL80211_IFTYPE_P2P_GO: -+ mode = WL_MODE_AP; -+ ap = 1; -+ break; -+ default: -+ return -EINVAL; -+ } -+ if (!dhd) -+ return -EINVAL; -+ if (ap) { -+ wl_set_mode_by_netdev(wl, ndev, mode); -+ if (wl->p2p_supported && wl->p2p->vif_created) { -+ WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, -+ p2p_on(wl))); -+ wldev_iovar_setint(ndev, "mpc", 0); -+ wl_notify_escan_complete(wl, ndev, true, true); -+ -+ /* In concurrency case, STA may be already associated in a particular -+ * channel. so retrieve the current channel of primary interface and -+ * then start the virtual interface on that. -+ */ -+ chspec = wl_cfg80211_get_shared_freq(wiphy); -+ -+ wlif_type = WL_P2P_IF_GO; -+ WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", -+ ndev->name, ap, infra, type)); -+ wl_set_p2p_status(wl, IF_CHANGING); -+ wl_clr_p2p_status(wl, IF_CHANGED); -+ wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); -+ wait_event_interruptible_timeout(wl->netif_change_event, -+ (wl_get_p2p_status(wl, IF_CHANGED) == true), -+ msecs_to_jiffies(MAX_WAIT_TIME)); -+ wl_set_mode_by_netdev(wl, ndev, mode); -+ dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE; -+ dhd->op_mode |= DHD_FLAG_P2P_GO_MODE; -+ wl_clr_p2p_status(wl, IF_CHANGING); -+ wl_clr_p2p_status(wl, IF_CHANGED); -+ if (mode == WL_MODE_AP) -+ wl_set_drv_status(wl, CONNECTED, ndev); -+ } else if (ndev == wl_to_prmry_ndev(wl) && -+ !wl_get_drv_status(wl, AP_CREATED, ndev)) { -+ wl_set_drv_status(wl, AP_CREATING, ndev); -+ if (!wl->ap_info && -+ !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { -+ WL_ERR(("struct ap_saved_ie allocation failed\n")); -+ return -ENOMEM; -+ } -+ } else { -+ WL_ERR(("Cannot change the interface for GO or SOFTAP\n")); -+ return -EINVAL; -+ } -+ } else { -+ WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA")); -+ } -+ -+ ndev->ieee80211_ptr->iftype = type; -+ return 0; -+} -+ -+s32 -+wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, -+ void* _net_attach) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ s32 ret = BCME_OK; -+ WL_DBG(("Enter")); -+ if (!ndev) { -+ WL_ERR(("net is NULL\n")); -+ return 0; -+ } -+ if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) { -+ WL_DBG(("IF_ADD event called from dongle, old interface name: %s," -+ "new name: %s\n", ndev->name, wl->p2p->vir_ifname)); -+ /* Assign the net device to CONNECT BSSCFG */ -+ strncpy(ndev->name, wl->p2p->vir_ifname, IFNAMSIZ - 1); -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = ndev; -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx; -+ wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach; -+ ndev->ifindex = idx; -+ wl_clr_p2p_status(wl, IF_ADD); -+ -+ wake_up_interruptible(&wl->netif_change_event); -+ } else { -+ ret = BCME_NOTREADY; -+ } -+ return ret; -+} -+ -+s32 -+wl_cfg80211_notify_ifdel(void) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+ WL_DBG(("Enter \n")); -+ wl_clr_p2p_status(wl, IF_DELETING); -+ wake_up_interruptible(&wl->netif_change_event); -+ return 0; -+} -+ -+s32 -+wl_cfg80211_ifdel_ops(struct net_device *ndev) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ bool rollback_lock = false; -+ s32 index = 0; -+#ifdef PROP_TXSTATUS_VSDB -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+#endif /* PROP_TXSTATUS_VSDB */ -+ if (!ndev || (strlen(ndev->name) == 0)) { -+ WL_ERR(("net is NULL\n")); -+ return 0; -+ } -+ -+ if (p2p_is_on(wl) && wl->p2p->vif_created && -+ wl_get_p2p_status(wl, IF_DELETING)) { -+ if (wl->scan_request && -+ (wl->escan_info.ndev == ndev)) { -+ /* Abort any pending scan requests */ -+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; -+ if (!rtnl_is_locked()) { -+ rtnl_lock(); -+ rollback_lock = true; -+ } -+ WL_DBG(("ESCAN COMPLETED\n")); -+ wl_notify_escan_complete(wl, ndev, true, false); -+ if (rollback_lock) -+ rtnl_unlock(); -+ } -+ WL_ERR(("IF_DEL event called from dongle, net %x, vif name: %s\n", -+ (unsigned int)ndev, wl->p2p->vir_ifname)); -+ -+ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); -+ index = wl_cfgp2p_find_idx(wl, ndev); -+ wl_to_p2p_bss_ndev(wl, index) = NULL; -+ wl_to_p2p_bss_bssidx(wl, index) = WL_INVALID; -+ wl->p2p->vif_created = false; -+ -+ WL_DBG(("index : %d\n", index)); -+#ifdef PROP_TXSTATUS_VSDB -+ if (dhd->wlfc_enabled && wl->wlfc_on) { -+ dhd->wlfc_enabled = false; -+ dhd_wlfc_deinit(dhd); -+ wl->wlfc_on = false; -+ } -+#endif /* PROP_TXSTATUS_VSDB */ -+ wl_clr_drv_status(wl, CONNECTED, ndev); -+ } -+ /* Wake up any waiting thread */ -+ wake_up_interruptible(&wl->netif_change_event); -+ -+ return 0; -+} -+ -+s32 -+wl_cfg80211_is_progress_ifadd(void) -+{ -+ s32 is_progress = 0; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ if (wl_get_p2p_status(wl, IF_ADD)) -+ is_progress = 1; -+ return is_progress; -+} -+ -+s32 -+wl_cfg80211_is_progress_ifchange(void) -+{ -+ s32 is_progress = 0; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ if (wl_get_p2p_status(wl, IF_CHANGING)) -+ is_progress = 1; -+ return is_progress; -+} -+ -+ -+s32 -+wl_cfg80211_notify_ifchange(void) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ if (wl_get_p2p_status(wl, IF_CHANGING)) { -+ wl_set_p2p_status(wl, IF_CHANGED); -+ wake_up_interruptible(&wl->netif_change_event); -+ } -+ return 0; -+} -+ -+/* Find listen channel */ -+static s32 wl_find_listen_channel(struct wl_priv *wl, -+ u8 *ie, u32 ie_len) -+{ -+ wifi_p2p_ie_t *p2p_ie; -+ u8 *end, *pos; -+ s32 listen_channel; -+ -+ p2p_ie = wl_cfgp2p_find_p2pie(ie, ie_len); -+ -+ if (p2p_ie == NULL) -+ return 0; -+ -+ pos = p2p_ie->subelts; -+ end = p2p_ie->subelts + (p2p_ie->len - 4); -+ -+ CFGP2P_DBG((" found p2p ie ! lenth %d \n", -+ p2p_ie->len)); -+ -+ while (pos < end) { -+ uint16 attr_len; -+ if (pos + 2 >= end) { -+ CFGP2P_DBG((" -- Invalid P2P attribute")); -+ return 0; -+ } -+ attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0])); -+ -+ if (pos + 3 + attr_len > end) { -+ CFGP2P_DBG(("P2P: Attribute underflow " -+ "(len=%u left=%d)", -+ attr_len, (int) (end - pos - 3))); -+ return 0; -+ } -+ -+ /* if Listen Channel att id is 6 and the vailue is valid, -+ * return the listen channel -+ */ -+ if (pos[0] == 6) { -+ /* listen channel subel length format -+ * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num) -+ */ -+ listen_channel = pos[1 + 2 + 3 + 1]; -+ -+ if (listen_channel == SOCIAL_CHAN_1 || -+ listen_channel == SOCIAL_CHAN_2 || -+ listen_channel == SOCIAL_CHAN_3) { -+ CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel)); -+ return listen_channel; -+ } -+ } -+ pos += 3 + attr_len; -+ } -+ return 0; -+} -+ -+static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) -+{ -+ u32 n_ssids; -+ u32 n_channels; -+ u16 channel; -+ chanspec_t chanspec; -+ s32 i = 0, j = 0, offset; -+ char *ptr; -+ wlc_ssid_t ssid; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); -+ params->bss_type = DOT11_BSSTYPE_ANY; -+ params->scan_type = 0; -+ params->nprobes = -1; -+ params->active_time = -1; -+ params->passive_time = -1; -+ params->home_time = -1; -+ params->channel_num = 0; -+ memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); -+ -+ WL_SCAN(("Preparing Scan request\n")); -+ WL_SCAN(("nprobes=%d\n", params->nprobes)); -+ WL_SCAN(("active_time=%d\n", params->active_time)); -+ WL_SCAN(("passive_time=%d\n", params->passive_time)); -+ WL_SCAN(("home_time=%d\n", params->home_time)); -+ WL_SCAN(("scan_type=%d\n", params->scan_type)); -+ -+ params->nprobes = htod32(params->nprobes); -+ params->active_time = htod32(params->active_time); -+ params->passive_time = htod32(params->passive_time); -+ params->home_time = htod32(params->home_time); -+ -+ /* if request is null just exit so it will be all channel broadcast scan */ -+ if (!request) -+ return; -+ -+ n_ssids = request->n_ssids; -+ n_channels = request->n_channels; -+ -+ /* Copy channel array if applicable */ -+ WL_SCAN(("### List of channelspecs to scan ###\n")); -+ if (n_channels > 0) { -+ for (i = 0; i < n_channels; i++) { -+ chanspec = 0; -+ channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); -+ /* SKIP DFS channels for Secondary interface */ -+ if ((wl->escan_info.ndev != wl_to_prmry_ndev(wl)) && -+ (request->channels[i]->flags & -+ (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN))) -+ continue; -+ -+ if (request->channels[i]->band == IEEE80211_BAND_2GHZ) { -+#ifdef WL_HOST_BAND_MGMT -+ if (wl->curr_band == WLC_BAND_5G) { -+ WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel)); -+ continue; -+ } -+#endif /* WL_HOST_BAND_MGMT */ -+ chanspec |= WL_CHANSPEC_BAND_2G; -+ } else { -+#ifdef WL_HOST_BAND_MGMT -+ if (wl->curr_band == WLC_BAND_2G) { -+ WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel)); -+ continue; -+ } -+#endif /* WL_HOST_BAND_MGMT */ -+ chanspec |= WL_CHANSPEC_BAND_5G; -+ } -+ -+ chanspec |= WL_CHANSPEC_BW_20; -+ chanspec |= WL_CHANSPEC_CTL_SB_NONE; -+ -+ params->channel_list[j] = channel; -+ params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK; -+ params->channel_list[j] |= chanspec; -+ WL_SCAN(("Chan : %d, Channel spec: %x \n", -+ channel, params->channel_list[j])); -+ params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]); -+ j++; -+ } -+ } else { -+ WL_SCAN(("Scanning all channels\n")); -+ } -+ n_channels = j; -+ /* Copy ssid array if applicable */ -+ WL_SCAN(("### List of SSIDs to scan ###\n")); -+ if (n_ssids > 0) { -+ offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); -+ offset = roundup(offset, sizeof(u32)); -+ ptr = (char*)params + offset; -+ for (i = 0; i < n_ssids; i++) { -+ memset(&ssid, 0, sizeof(wlc_ssid_t)); -+ ssid.SSID_len = request->ssids[i].ssid_len; -+ memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); -+ if (!ssid.SSID_len) -+ WL_SCAN(("%d: Broadcast scan\n", i)); -+ else -+ WL_SCAN(("%d: scan for %s size =%d\n", i, -+ ssid.SSID, ssid.SSID_len)); -+ memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); -+ ptr += sizeof(wlc_ssid_t); -+ } -+ } else { -+ WL_SCAN(("Broadcast scan\n")); -+ } -+ /* Adding mask to channel numbers */ -+ params->channel_num = -+ htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | -+ (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); -+ -+ if (n_channels == 1 && wl_get_drv_status_all(wl, CONNECTED)) { -+ params->active_time = WL_SCAN_CONNECT_DWELL_TIME_MS; -+ } -+} -+ -+static s32 -+wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action) -+{ -+ u32 n_channels; -+ u32 n_ssids; -+ s32 params_size = -+ (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); -+ struct wl_iscan_params *params = NULL; -+ s32 err = 0; -+ -+ if (request != NULL) { -+ n_channels = request->n_channels; -+ n_ssids = request->n_ssids; -+ /* Allocate space for populating ssids in wl_iscan_params struct */ -+ if (n_channels % 2) -+ /* If n_channels is odd, add a padd of u16 */ -+ params_size += sizeof(u16) * (n_channels + 1); -+ else -+ params_size += sizeof(u16) * n_channels; -+ -+ /* Allocate space for populating ssids in wl_iscan_params struct */ -+ params_size += sizeof(struct wlc_ssid) * n_ssids; -+ } -+ params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto done; -+ } -+ wl_scan_prep(¶ms->params, request); -+ -+ params->version = htod32(ISCAN_REQ_VERSION); -+ params->action = htod16(action); -+ params->scan_duration = htod16(0); -+ -+ if (params_size + sizeof("iscan") >= WLC_IOCTL_MEDLEN) { -+ WL_ERR(("ioctl buffer length is not sufficient\n")); -+ err = -ENOMEM; -+ goto done; -+ } -+ err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size, -+ iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); -+ if (unlikely(err)) { -+ if (err == -EBUSY) { -+ WL_ERR(("system busy : iscan canceled\n")); -+ } else { -+ WL_ERR(("error (%d)\n", err)); -+ } -+ } -+ -+done: -+ if (params) -+ kfree(params); -+ return err; -+} -+ -+static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request) -+{ -+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ s32 passive_scan; -+ s32 err = 0; -+ -+ iscan->state = WL_ISCAN_STATE_SCANING; -+ -+ passive_scan = wl->active_scan ? 0 : 1; -+ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, -+ &passive_scan, sizeof(passive_scan), true); -+ if (unlikely(err)) { -+ WL_DBG(("error (%d)\n", err)); -+ return err; -+ } -+ wl->iscan_kickstart = true; -+ wl_run_iscan(iscan, request, WL_SCAN_ACTION_START); -+ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); -+ iscan->timer_on = 1; -+ -+ return err; -+} -+ -+static s32 -+wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) -+{ -+ wl_uint32_list_t *list; -+ s32 err = BCME_OK; -+ if (valid_chan_list == NULL || size <= 0) -+ return -ENOMEM; -+ -+ memset(valid_chan_list, 0, size); -+ list = (wl_uint32_list_t *)(void *) valid_chan_list; -+ list->count = htod32(WL_NUMCHANNELS); -+ err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); -+ if (err != 0) { -+ WL_ERR(("get channels failed with %d\n", err)); -+ } -+ -+ return err; -+} -+ -+static s32 -+wl_run_escan(struct wl_priv *wl, struct net_device *ndev, -+ struct cfg80211_scan_request *request, uint16 action) -+{ -+ s32 err = BCME_OK; -+ u32 n_channels; -+ u32 n_ssids; -+ s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); -+ wl_escan_params_t *params = NULL; -+ u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; -+ u32 num_chans = 0; -+ s32 channel; -+ s32 n_valid_chan; -+ s32 search_state = WL_P2P_DISC_ST_SCAN; -+ u32 i, j, n_nodfs = 0; -+ u16 *default_chan_list = NULL; -+ wl_uint32_list_t *list; -+ struct net_device *dev = NULL; -+ -+ WL_DBG(("Enter \n")); -+ -+ if (!wl) { -+ err = -EINVAL; -+ goto exit; -+ } -+ if (!wl->p2p_supported || !p2p_scan(wl)) { -+ /* LEGACY SCAN TRIGGER */ -+ WL_SCAN((" LEGACY E-SCAN START\n")); -+ -+ /* if scan request is not empty parse scan request paramters */ -+ if (request != NULL) { -+ n_channels = request->n_channels; -+ n_ssids = request->n_ssids; -+ /* Allocate space for populating ssids in wl_iscan_params struct */ -+ if (n_channels % 2) -+ /* If n_channels is odd, add a padd of u16 */ -+ params_size += sizeof(u16) * (n_channels + 1); -+ else -+ params_size += sizeof(u16) * n_channels; -+ -+ /* Allocate space for populating ssids in wl_iscan_params struct */ -+ params_size += sizeof(struct wlc_ssid) * n_ssids; -+ } -+ params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); -+ if (params == NULL) { -+ err = -ENOMEM; -+ goto exit; -+ } -+ -+ wl_scan_prep(¶ms->params, request); -+ -+ params->version = htod32(ESCAN_REQ_VERSION); -+ params->action = htod16(action); -+ params->sync_id = htod16(0x1234); -+ if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { -+ WL_ERR(("ioctl buffer length not sufficient\n")); -+ kfree(params); -+ err = -ENOMEM; -+ goto exit; -+ } -+ err = wldev_iovar_setbuf(ndev, "escan", params, params_size, -+ wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); -+ if (unlikely(err)) { -+ if (err == BCME_EPERM) -+ /* Scan Not permitted at this point of time */ -+ WL_DBG((" Escan not permitted at this time (%d)\n", err)); -+ else -+ WL_ERR((" Escan set error (%d)\n", err)); -+ } -+ kfree(params); -+ } -+ else if (p2p_is_on(wl) && p2p_scan(wl)) { -+ /* P2P SCAN TRIGGER */ -+ s32 _freq = 0; -+ n_nodfs = 0; -+ if (request && request->n_channels) { -+ num_chans = request->n_channels; -+ WL_SCAN((" chann number : %d\n", num_chans)); -+ default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), -+ GFP_KERNEL); -+ if (default_chan_list == NULL) { -+ WL_ERR(("channel list allocation failed \n")); -+ err = -ENOMEM; -+ goto exit; -+ } -+ if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { -+ list = (wl_uint32_list_t *) chan_buf; -+ n_valid_chan = dtoh32(list->count); -+ for (i = 0; i < num_chans; i++) -+ { -+#ifdef WL_HOST_BAND_MGMT -+ int channel_band = 0; -+#endif /* WL_HOST_BAND_MGMT */ -+ _freq = request->channels[i]->center_freq; -+ channel = ieee80211_frequency_to_channel(_freq); -+#ifdef WL_HOST_BAND_MGMT -+ channel_band = (channel > CH_MAX_2G_CHANNEL) ? -+ WLC_BAND_5G : WLC_BAND_2G; -+ if ((wl->curr_band != WLC_BAND_AUTO) && -+ (wl->curr_band != channel_band) && -+ !IS_P2P_SOCIAL_CHANNEL(channel)) -+ continue; -+#endif /* WL_HOST_BAND_MGMT */ -+ -+ /* ignore DFS channels */ -+ if (request->channels[i]->flags & -+ (IEEE80211_CHAN_RADAR -+ | IEEE80211_CHAN_PASSIVE_SCAN)) -+ continue; -+ -+ for (j = 0; j < n_valid_chan; j++) { -+ /* allows only supported channel on -+ * current reguatory -+ */ -+ if (channel == (dtoh32(list->element[j]))) -+ default_chan_list[n_nodfs++] = -+ channel; -+ } -+ -+ } -+ } -+ if (num_chans == 3 && ( -+ (default_chan_list[0] == SOCIAL_CHAN_1) && -+ (default_chan_list[1] == SOCIAL_CHAN_2) && -+ (default_chan_list[2] == SOCIAL_CHAN_3))) { -+ /* SOCIAL CHANNELS 1, 6, 11 */ -+ search_state = WL_P2P_DISC_ST_SEARCH; -+ WL_INFO(("P2P SEARCH PHASE START \n")); -+ } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) && -+ (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) { -+ /* If you are already a GO, then do SEARCH only */ -+ WL_INFO(("Already a GO. Do SEARCH Only")); -+ search_state = WL_P2P_DISC_ST_SEARCH; -+ num_chans = n_nodfs; -+ -+ } else { -+ WL_INFO(("P2P SCAN STATE START \n")); -+ num_chans = n_nodfs; -+ } -+ -+ } -+ err = wl_cfgp2p_escan(wl, ndev, wl->active_scan, num_chans, default_chan_list, -+ search_state, action, -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), NULL); -+ kfree(default_chan_list); -+ } -+exit: -+ if (unlikely(err)) { -+ /* Don't print Error incase of Scan suppress */ -+ if ((err == BCME_EPERM) && wl->scan_suppressed) -+ WL_DBG(("Escan failed: Scan Suppressed \n")); -+ else -+ WL_ERR(("error (%d)\n", err)); -+ } -+ return err; -+} -+ -+ -+static s32 -+wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, -+ struct cfg80211_scan_request *request) -+{ -+ s32 err = BCME_OK; -+ s32 passive_scan; -+ wl_scan_results_t *results; -+ WL_SCAN(("Enter \n")); -+ mutex_lock(&wl->usr_sync); -+ results = (wl_scan_results_t *) wl->escan_info.escan_buf; -+ results->version = 0; -+ results->count = 0; -+ results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; -+ -+ wl->escan_info.ndev = ndev; -+ wl->escan_info.wiphy = wiphy; -+ wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; -+ passive_scan = wl->active_scan ? 0 : 1; -+ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, -+ &passive_scan, sizeof(passive_scan), true); -+ if (unlikely(err)) { -+ WL_ERR(("error (%d)\n", err)); -+ goto exit; -+ } -+ -+ err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START); -+exit: -+ mutex_unlock(&wl->usr_sync); -+ return err; -+} -+ -+static s32 -+__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, -+ struct cfg80211_scan_request *request, -+ struct cfg80211_ssid *this_ssid) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct cfg80211_ssid *ssids; -+ struct wl_scan_req *sr = wl_to_sr(wl); -+ struct ether_addr primary_mac; -+ s32 passive_scan; -+ bool iscan_req; -+ bool escan_req = false; -+ bool p2p_ssid; -+ s32 err = 0; -+ s32 bssidx = -1; -+ s32 i; -+ -+ unsigned long flags; -+ static s32 busy_count = 0; -+ -+ /* If scan req comes for p2p0, send it over primary I/F -+ * Scan results will be delivered corresponding to cfg80211_scan_request -+ */ -+ if (ndev == wl->p2p_net) { -+ ndev = wl_to_prmry_ndev(wl); -+ } -+ -+ if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(wl)) { -+ WL_ERR(("Sending Action Frames. Try it again.\n")); -+ return -EAGAIN; -+ } -+ -+ WL_DBG(("Enter wiphy (%p)\n", wiphy)); -+ if (wl_get_drv_status_all(wl, SCANNING)) { -+ if (wl->scan_request == NULL) { -+ wl_clr_drv_status_all(wl, SCANNING); -+ WL_DBG(("<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n")); -+ } else { -+ WL_ERR(("Scanning already\n")); -+ return -EAGAIN; -+ } -+ } -+ if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) { -+ WL_ERR(("Scanning being aborted\n")); -+ return -EAGAIN; -+ } -+ if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { -+ WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); -+ return -EOPNOTSUPP; -+ } -+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { -+ WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n")); -+ wl_notify_escan_complete(wl, ndev, true, true); -+ } -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ -+ /* Arm scan timeout timer */ -+ mod_timer(&wl->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); -+ iscan_req = false; -+ if (request) { /* scan bss */ -+ ssids = request->ssids; -+ if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) { -+ iscan_req = true; -+ } else if (wl->escan_on) { -+ escan_req = true; -+ p2p_ssid = false; -+ for (i = 0; i < request->n_ssids; i++) { -+ if (ssids[i].ssid_len && -+ IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) { -+ p2p_ssid = true; -+ break; -+ } -+ } -+ if (p2p_ssid) { -+ if (wl->p2p_supported) { -+ /* p2p scan trigger */ -+ if (p2p_on(wl) == false) { -+ /* p2p on at the first time */ -+ p2p_on(wl) = true; -+ wl_cfgp2p_set_firm_p2p(wl); -+ get_primary_mac(wl, &primary_mac); -+ wl_cfgp2p_generate_bss_mac(&primary_mac, -+ &wl->p2p->dev_addr, &wl->p2p->int_addr); -+ } -+ wl_clr_p2p_status(wl, GO_NEG_PHASE); -+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); -+ p2p_scan(wl) = true; -+ } -+ } else { -+ /* legacy scan trigger -+ * So, we have to disable p2p discovery if p2p discovery is on -+ */ -+ if (wl->p2p_supported) { -+ p2p_scan(wl) = false; -+ /* If Netdevice is not equals to primary and p2p is on -+ * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. -+ */ -+ -+ if (p2p_scan(wl) == false) { -+ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { -+ err = wl_cfgp2p_discover_enable_search(wl, -+ false); -+ if (unlikely(err)) { -+ goto scan_out; -+ } -+ -+ } -+ } -+ } -+ if (!wl->p2p_supported || !p2p_scan(wl)) { -+ bssidx = wl_cfgp2p_find_idx(wl, ndev); -+ err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, -+ VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, -+ request->ie_len); -+ -+ if (unlikely(err)) { -+ goto scan_out; -+ } -+ -+ } -+ } -+ } -+ } else { /* scan in ibss */ -+ /* we don't do iscan in ibss */ -+ ssids = this_ssid; -+ } -+ wl->scan_request = request; -+ wl_set_drv_status(wl, SCANNING, ndev); -+ if (iscan_req) { -+ err = wl_do_iscan(wl, request); -+ if (likely(!err)) -+ goto scan_success; -+ else -+ goto scan_out; -+ } else if (escan_req) { -+ if (wl->p2p_supported) { -+ if (p2p_on(wl) && p2p_scan(wl)) { -+ -+ /* find my listen channel */ -+ wl->afx_hdl->my_listen_chan = -+ wl_find_listen_channel(wl, (u8 *)request->ie, -+ request->ie_len); -+ err = wl_cfgp2p_enable_discovery(wl, ndev, -+ request->ie, request->ie_len); -+ -+ if (unlikely(err)) { -+ goto scan_out; -+ } -+ } -+ } -+ err = wl_do_escan(wl, wiphy, ndev, request); -+ if (likely(!err)) -+ goto scan_success; -+ else -+ goto scan_out; -+ -+ -+ } else { -+ memset(&sr->ssid, 0, sizeof(sr->ssid)); -+ sr->ssid.SSID_len = -+ min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len); -+ if (sr->ssid.SSID_len) { -+ memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); -+ sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); -+ WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n", -+ sr->ssid.SSID, sr->ssid.SSID_len)); -+ } else { -+ WL_SCAN(("Broadcast scan\n")); -+ } -+ WL_SCAN(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); -+ passive_scan = wl->active_scan ? 0 : 1; -+ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, -+ &passive_scan, sizeof(passive_scan), true); -+ if (unlikely(err)) { -+ WL_SCAN(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); -+ goto scan_out; -+ } -+ err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid, -+ sizeof(sr->ssid), false); -+ if (err) { -+ if (err == -EBUSY) { -+ WL_ERR(("system busy : scan for \"%s\" " -+ "canceled\n", sr->ssid.SSID)); -+ } else { -+ WL_ERR(("WLC_SCAN error (%d)\n", err)); -+ } -+ goto scan_out; -+ } -+ } -+ -+scan_success: -+ -+ busy_count = 0; -+ -+ return 0; -+ -+scan_out: -+ -+ if (err == BCME_BUSY || err == BCME_NOTREADY) { -+ WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY)); -+ err = -EBUSY; -+ } -+ -+#define SCAN_EBUSY_RETRY_LIMIT 10 -+ if (err == -EBUSY) { -+ if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) { -+ struct ether_addr bssid; -+ s32 ret = 0; -+ busy_count = 0; -+ WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n", -+ wl_get_drv_status(wl, SCANNING, ndev), -+ wl_get_drv_status(wl, SCAN_ABORTING, ndev), -+ wl_get_drv_status(wl, CONNECTING, ndev), -+ wl_get_drv_status(wl, CONNECTED, ndev), -+ wl_get_drv_status(wl, DISCONNECTING, ndev), -+ wl_get_drv_status(wl, AP_CREATING, ndev), -+ wl_get_drv_status(wl, AP_CREATED, ndev), -+ wl_get_drv_status(wl, SENDING_ACT_FRM, ndev), -+ wl_get_drv_status(wl, SENDING_ACT_FRM, ndev))); -+ -+ bzero(&bssid, sizeof(bssid)); -+ if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID, -+ &bssid, ETHER_ADDR_LEN, false)) == 0) -+ WL_ERR(("FW is connected with " MACDBG "/n", -+ MAC2STRDBG(bssid.octet))); -+ else -+ WL_ERR(("GET BSSID failed with %d\n", ret)); -+ -+ wl_cfg80211_disconnect(wiphy, ndev, DOT11_RC_DISASSOC_LEAVING); -+ } -+ } else { -+ busy_count = 0; -+ } -+ wl_clr_drv_status(wl, SCANNING, ndev); -+ if (timer_pending(&wl->scan_timeout)) -+ del_timer_sync(&wl->scan_timeout); -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ wl->scan_request = NULL; -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ return err; -+} -+ -+static s32 -+wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, -+ struct cfg80211_scan_request *request) -+{ -+ s32 err = 0; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ -+ WL_DBG(("Enter \n")); -+ CHECK_SYS_UP(wl); -+ -+ err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); -+ if (unlikely(err)) { -+ if ((err == BCME_EPERM) && wl->scan_suppressed) -+ WL_DBG(("scan not permitted at this time (%d)\n", err)); -+ else -+ WL_ERR(("scan error (%d)\n", err)); -+ return err; -+ } -+ -+ return err; -+} -+ -+static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) -+{ -+ s32 err = 0; -+ -+ err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); -+ if (unlikely(err)) { -+ WL_ERR(("Error (%d)\n", err)); -+ return err; -+ } -+ return err; -+} -+ -+static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) -+{ -+ s32 err = 0; -+ -+ err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); -+ if (unlikely(err)) { -+ WL_ERR(("Error (%d)\n", err)); -+ return err; -+ } -+ return err; -+} -+ -+static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) -+{ -+ s32 err = 0; -+ u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); -+ -+ retry = htod32(retry); -+ err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true); -+ if (unlikely(err)) { -+ WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); -+ return err; -+ } -+ return err; -+} -+ -+static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) -+{ -+ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ s32 err = 0; -+ -+ CHECK_SYS_UP(wl); -+ WL_DBG(("Enter\n")); -+ if (changed & WIPHY_PARAM_RTS_THRESHOLD && -+ (wl->conf->rts_threshold != wiphy->rts_threshold)) { -+ wl->conf->rts_threshold = wiphy->rts_threshold; -+ err = wl_set_rts(ndev, wl->conf->rts_threshold); -+ if (!err) -+ return err; -+ } -+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD && -+ (wl->conf->frag_threshold != wiphy->frag_threshold)) { -+ wl->conf->frag_threshold = wiphy->frag_threshold; -+ err = wl_set_frag(ndev, wl->conf->frag_threshold); -+ if (!err) -+ return err; -+ } -+ if (changed & WIPHY_PARAM_RETRY_LONG && -+ (wl->conf->retry_long != wiphy->retry_long)) { -+ wl->conf->retry_long = wiphy->retry_long; -+ err = wl_set_retry(ndev, wl->conf->retry_long, true); -+ if (!err) -+ return err; -+ } -+ if (changed & WIPHY_PARAM_RETRY_SHORT && -+ (wl->conf->retry_short != wiphy->retry_short)) { -+ wl->conf->retry_short = wiphy->retry_short; -+ err = wl_set_retry(ndev, wl->conf->retry_short, false); -+ if (!err) { -+ return err; -+ } -+ } -+ -+ return err; -+} -+ -+static s32 -+wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_ibss_params *params) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct cfg80211_bss *bss; -+ struct ieee80211_channel *chan; -+ struct wl_join_params join_params; -+ struct cfg80211_ssid ssid; -+ s32 scan_retry = 0; -+ s32 err = 0; -+ bool rollback_lock = false; -+ -+ WL_TRACE(("In\n")); -+ CHECK_SYS_UP(wl); -+ if (params->bssid) { -+ WL_ERR(("Invalid bssid\n")); -+ return -EOPNOTSUPP; -+ } -+ bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len); -+ if (!bss) { -+ memcpy(ssid.ssid, params->ssid, params->ssid_len); -+ ssid.ssid_len = params->ssid_len; -+ do { -+ if (unlikely -+ (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == -+ -EBUSY)) { -+ wl_delay(150); -+ } else { -+ break; -+ } -+ } while (++scan_retry < WL_SCAN_RETRY_MAX); -+ /* to allow scan_inform to propagate to cfg80211 plane */ -+ if (rtnl_is_locked()) { -+ rtnl_unlock(); -+ rollback_lock = true; -+ } -+ -+ /* wait 4 secons till scan done.... */ -+ schedule_timeout_interruptible(msecs_to_jiffies(4000)); -+ if (rollback_lock) -+ rtnl_lock(); -+ bss = cfg80211_get_ibss(wiphy, NULL, -+ params->ssid, params->ssid_len); -+ } -+ if (bss) { -+ wl->ibss_starter = false; -+ WL_DBG(("Found IBSS\n")); -+ } else { -+ wl->ibss_starter = true; -+ } -+ chan = params->channel; -+ if (chan) -+ wl->channel = ieee80211_frequency_to_channel(chan->center_freq); -+ /* -+ * Join with specific BSSID and cached SSID -+ * If SSID is zero join based on BSSID only -+ */ -+ memset(&join_params, 0, sizeof(join_params)); -+ memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, -+ params->ssid_len); -+ join_params.ssid.SSID_len = htod32(params->ssid_len); -+ if (params->bssid) -+ memcpy(&join_params.params.bssid, params->bssid, -+ ETHER_ADDR_LEN); -+ else -+ memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); -+ -+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, -+ sizeof(join_params), true); -+ if (unlikely(err)) { -+ WL_ERR(("Error (%d)\n", err)); -+ return err; -+ } -+ return err; -+} -+ -+static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 err = 0; -+ -+ CHECK_SYS_UP(wl); -+ wl_link_down(wl); -+ -+ return err; -+} -+ -+static s32 -+wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct wl_security *sec; -+ s32 val = 0; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) -+ val = WPA_AUTH_PSK | -+ WPA_AUTH_UNSPECIFIED; -+ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) -+ val = WPA2_AUTH_PSK| -+ WPA2_AUTH_UNSPECIFIED; -+ else -+ val = WPA_AUTH_DISABLED; -+ -+ if (is_wps_conn(sme)) -+ val = WPA_AUTH_DISABLED; -+ -+ WL_DBG(("setting wpa_auth to 0x%0x\n", val)); -+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("set wpa_auth failed (%d)\n", err)); -+ return err; -+ } -+ sec = wl_read_prof(wl, dev, WL_PROF_SEC); -+ sec->wpa_versions = sme->crypto.wpa_versions; -+ return err; -+} -+ -+ -+static s32 -+wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct wl_security *sec; -+ s32 val = 0; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ switch (sme->auth_type) { -+ case NL80211_AUTHTYPE_OPEN_SYSTEM: -+ val = WL_AUTH_OPEN_SYSTEM; -+ WL_DBG(("open system\n")); -+ break; -+ case NL80211_AUTHTYPE_SHARED_KEY: -+ val = WL_AUTH_SHARED_KEY; -+ WL_DBG(("shared key\n")); -+ break; -+ case NL80211_AUTHTYPE_AUTOMATIC: -+ val = WL_AUTH_OPEN_SHARED; -+ WL_DBG(("automatic\n")); -+ break; -+ default: -+ val = WL_AUTH_OPEN_SHARED; -+ WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); -+ break; -+ } -+ -+ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("set auth failed (%d)\n", err)); -+ return err; -+ } -+ sec = wl_read_prof(wl, dev, WL_PROF_SEC); -+ sec->auth_type = sme->auth_type; -+ return err; -+} -+ -+static s32 -+wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct wl_security *sec; -+ s32 pval = 0; -+ s32 gval = 0; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ if (sme->crypto.n_ciphers_pairwise) { -+ switch (sme->crypto.ciphers_pairwise[0]) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ case WLAN_CIPHER_SUITE_WEP104: -+ pval = WEP_ENABLED; -+ break; -+ case WLAN_CIPHER_SUITE_TKIP: -+ pval = TKIP_ENABLED; -+ break; -+ case WLAN_CIPHER_SUITE_CCMP: -+ pval = AES_ENABLED; -+ break; -+ case WLAN_CIPHER_SUITE_AES_CMAC: -+ pval = AES_ENABLED; -+ break; -+ default: -+ WL_ERR(("invalid cipher pairwise (%d)\n", -+ sme->crypto.ciphers_pairwise[0])); -+ return -EINVAL; -+ } -+ } -+ if (sme->crypto.cipher_group) { -+ switch (sme->crypto.cipher_group) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ case WLAN_CIPHER_SUITE_WEP104: -+ gval = WEP_ENABLED; -+ break; -+ case WLAN_CIPHER_SUITE_TKIP: -+ gval = TKIP_ENABLED; -+ break; -+ case WLAN_CIPHER_SUITE_CCMP: -+ gval = AES_ENABLED; -+ break; -+ case WLAN_CIPHER_SUITE_AES_CMAC: -+ gval = AES_ENABLED; -+ break; -+ default: -+ WL_ERR(("invalid cipher group (%d)\n", -+ sme->crypto.cipher_group)); -+ return -EINVAL; -+ } -+ } -+ -+ WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); -+ -+ if (is_wps_conn(sme)) { -+ if (sme->privacy) -+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); -+ else -+ /* WPS-2.0 allows no security */ -+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); -+ } else { -+ WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); -+ err = wldev_iovar_setint_bsscfg(dev, "wsec", -+ pval | gval, bssidx); -+ } -+ if (unlikely(err)) { -+ WL_ERR(("error (%d)\n", err)); -+ return err; -+ } -+ -+ sec = wl_read_prof(wl, dev, WL_PROF_SEC); -+ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; -+ sec->cipher_group = sme->crypto.cipher_group; -+ -+ return err; -+} -+ -+static s32 -+wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct wl_security *sec; -+ s32 val = 0; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ if (sme->crypto.n_akm_suites) { -+ err = wldev_iovar_getint(dev, "wpa_auth", &val); -+ if (unlikely(err)) { -+ WL_ERR(("could not get wpa_auth (%d)\n", err)); -+ return err; -+ } -+ if (val & (WPA_AUTH_PSK | -+ WPA_AUTH_UNSPECIFIED)) { -+ switch (sme->crypto.akm_suites[0]) { -+ case WLAN_AKM_SUITE_8021X: -+ val = WPA_AUTH_UNSPECIFIED; -+ break; -+ case WLAN_AKM_SUITE_PSK: -+ val = WPA_AUTH_PSK; -+ break; -+ default: -+ WL_ERR(("invalid cipher group (%d)\n", -+ sme->crypto.cipher_group)); -+ return -EINVAL; -+ } -+ } else if (val & (WPA2_AUTH_PSK | -+ WPA2_AUTH_UNSPECIFIED)) { -+ switch (sme->crypto.akm_suites[0]) { -+ case WLAN_AKM_SUITE_8021X: -+ val = WPA2_AUTH_UNSPECIFIED; -+ break; -+ case WLAN_AKM_SUITE_PSK: -+ val = WPA2_AUTH_PSK; -+ break; -+ default: -+ WL_ERR(("invalid cipher group (%d)\n", -+ sme->crypto.cipher_group)); -+ return -EINVAL; -+ } -+ } -+ WL_DBG(("setting wpa_auth to %d\n", val)); -+ -+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("could not set wpa_auth (%d)\n", err)); -+ return err; -+ } -+ } -+ sec = wl_read_prof(wl, dev, WL_PROF_SEC); -+ sec->wpa_auth = sme->crypto.akm_suites[0]; -+ -+ return err; -+} -+ -+static s32 -+wl_set_set_sharedkey(struct net_device *dev, -+ struct cfg80211_connect_params *sme) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct wl_security *sec; -+ struct wl_wsec_key key; -+ s32 val; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ WL_DBG(("key len (%d)\n", sme->key_len)); -+ if (sme->key_len) { -+ sec = wl_read_prof(wl, dev, WL_PROF_SEC); -+ WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", -+ sec->wpa_versions, sec->cipher_pairwise)); -+ if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | -+ NL80211_WPA_VERSION_2)) && -+ (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | -+ WLAN_CIPHER_SUITE_WEP104))) -+ { -+ memset(&key, 0, sizeof(key)); -+ key.len = (u32) sme->key_len; -+ key.index = (u32) sme->key_idx; -+ if (unlikely(key.len > sizeof(key.data))) { -+ WL_ERR(("Too long key length (%u)\n", key.len)); -+ return -EINVAL; -+ } -+ memcpy(key.data, sme->key, key.len); -+ key.flags = WL_PRIMARY_KEY; -+ switch (sec->cipher_pairwise) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ key.algo = CRYPTO_ALGO_WEP1; -+ break; -+ case WLAN_CIPHER_SUITE_WEP104: -+ key.algo = CRYPTO_ALGO_WEP128; -+ break; -+ default: -+ WL_ERR(("Invalid algorithm (%d)\n", -+ sme->crypto.ciphers_pairwise[0])); -+ return -EINVAL; -+ } -+ /* Set the new key/index */ -+ WL_DBG(("key length (%d) key index (%d) algo (%d)\n", -+ key.len, key.index, key.algo)); -+ WL_DBG(("key \"%s\"\n", key.data)); -+ swap_key_from_BE(&key); -+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_SET_KEY error (%d)\n", err)); -+ return err; -+ } -+ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { -+ WL_DBG(("set auth_type to shared key\n")); -+ val = WL_AUTH_SHARED_KEY; /* shared key */ -+ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("set auth failed (%d)\n", err)); -+ return err; -+ } -+ } -+ } -+ } -+ return err; -+} -+ -+#ifdef ESCAN_RESULT_PATCH -+static u8 connect_req_bssid[6]; -+static u8 broad_bssid[6]; -+#endif -+ -+ -+static s32 -+wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_connect_params *sme) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct ieee80211_channel *chan = sme->channel; -+ wl_extjoin_params_t *ext_join_params; -+ struct wl_join_params join_params; -+ size_t join_params_size; -+ s32 err = 0; -+ wpa_ie_fixed_t *wpa_ie; -+ bcm_tlv_t *wpa2_ie; -+ u8* wpaie = 0; -+ u32 wpaie_len = 0; -+ u32 chan_cnt = 0; -+ struct ether_addr bssid; -+ int ret; -+ -+ WL_DBG(("In\n")); -+ -+ if (unlikely(!sme->ssid)) { -+ WL_ERR(("Invalid ssid\n")); -+ return -EOPNOTSUPP; -+ } -+ -+ CHECK_SYS_UP(wl); -+ -+ /* -+ * Cancel ongoing scan to sync up with sme state machine of cfg80211. -+ */ -+#if !defined(ESCAN_RESULT_PATCH) -+ if (wl->scan_request) { -+ wl_notify_escan_complete(wl, dev, true, true); -+ } -+#endif -+#ifdef ESCAN_RESULT_PATCH -+ if (sme->bssid) { -+ memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); -+ } -+ else { -+ bzero(connect_req_bssid, ETHER_ADDR_LEN); -+ } -+ bzero(broad_bssid, ETHER_ADDR_LEN); -+#endif -+ -+ bzero(&bssid, sizeof(bssid)); -+ if (!wl_get_drv_status(wl, CONNECTED, dev)&& -+ (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) { -+ if (!ETHER_ISNULLADDR(&bssid)) { -+ scb_val_t scbval; -+ wl_set_drv_status(wl, DISCONNECTING, dev); -+ scbval.val = DOT11_RC_DISASSOC_LEAVING; -+ memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN); -+ scbval.val = htod32(scbval.val); -+ -+ WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n", -+ MAC2STRDBG(bssid.octet))); -+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, -+ sizeof(scb_val_t), true); -+ if (unlikely(err)) { -+ wl_clr_drv_status(wl, DISCONNECTING, dev); -+ WL_ERR(("error (%d)\n", err)); -+ return err; -+ } -+ while (wl_get_drv_status(wl, DISCONNECTING, dev)) { -+ WL_ERR(("Waiting for disconnection terminated.\n")); -+ msleep(20); -+ } -+ } else -+ WL_DBG(("Currently not associated!\n")); -+ } -+ -+ /* Clean BSSID */ -+ bzero(&bssid, sizeof(bssid)); -+ if (!wl_get_drv_status(wl, DISCONNECTING, dev)) -+ wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); -+ -+ if (p2p_is_on(wl) && (dev != wl_to_prmry_ndev(wl))) { -+ /* we only allow to connect using virtual interface in case of P2P */ -+ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), -+ VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); -+ } else if (dev == wl_to_prmry_ndev(wl)) { -+ /* find the RSN_IE */ -+ if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, -+ DOT11_MNG_RSN_ID)) != NULL) { -+ WL_DBG((" WPA2 IE is found\n")); -+ } -+ /* find the WPA_IE */ -+ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, -+ sme->ie_len)) != NULL) { -+ WL_DBG((" WPA IE is found\n")); -+ } -+ if (wpa_ie != NULL || wpa2_ie != NULL) { -+ wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; -+ wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; -+ wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; -+ wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ } else { -+ wldev_iovar_setbuf(dev, "wpaie", NULL, 0, -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ } -+ -+ err = wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), -+ VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len); -+ if (unlikely(err)) { -+ return err; -+ } -+ } -+ -+ if (chan) { -+ wl->channel = ieee80211_frequency_to_channel(chan->center_freq); -+ chan_cnt = 1; -+ WL_DBG(("channel (%d), center_req (%d), %d channels\n", wl->channel, -+ chan->center_freq, chan_cnt)); -+ } else -+ wl->channel = 0; -+ WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); -+ WL_DBG(("3. set wapi version \n")); -+ err = wl_set_wpa_version(dev, sme); -+ if (unlikely(err)) { -+ WL_ERR(("Invalid wpa_version\n")); -+ return err; -+ } -+ err = wl_set_auth_type(dev, sme); -+ if (unlikely(err)) { -+ WL_ERR(("Invalid auth type\n")); -+ return err; -+ } -+ -+ err = wl_set_set_cipher(dev, sme); -+ if (unlikely(err)) { -+ WL_ERR(("Invalid ciper\n")); -+ return err; -+ } -+ -+ err = wl_set_key_mgmt(dev, sme); -+ if (unlikely(err)) { -+ WL_ERR(("Invalid key mgmt\n")); -+ return err; -+ } -+ -+ err = wl_set_set_sharedkey(dev, sme); -+ if (unlikely(err)) { -+ WL_ERR(("Invalid shared key\n")); -+ return err; -+ } -+ -+ /* -+ * Join with specific BSSID and cached SSID -+ * If SSID is zero join based on BSSID only -+ */ -+ join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE + -+ chan_cnt * sizeof(chanspec_t); -+ ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); -+ if (ext_join_params == NULL) { -+ err = -ENOMEM; -+ wl_clr_drv_status(wl, CONNECTING, dev); -+ goto exit; -+ } -+ ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); -+ memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len); -+ wl_update_prof(wl, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID); -+ ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len); -+ /* increate dwell time to receive probe response or detect Beacon -+ * from target AP at a noisy air only during connect command -+ */ -+ ext_join_params->scan.active_time = WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS; -+ ext_join_params->scan.passive_time = WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS; -+ /* Set up join scan parameters */ -+ ext_join_params->scan.scan_type = -1; -+ ext_join_params->scan.nprobes -+ = (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS); -+ ext_join_params->scan.home_time = -1; -+ -+ if (sme->bssid) -+ memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); -+ else -+ memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN); -+ ext_join_params->assoc.chanspec_num = chan_cnt; -+ if (chan_cnt) { -+ u16 channel, band, bw, ctl_sb; -+ chanspec_t chspec; -+ channel = wl->channel; -+ band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G -+ : WL_CHANSPEC_BAND_5G; -+ bw = WL_CHANSPEC_BW_20; -+ ctl_sb = WL_CHANSPEC_CTL_SB_NONE; -+ chspec = (channel | band | bw | ctl_sb); -+ ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; -+ ext_join_params->assoc.chanspec_list[0] |= chspec; -+ ext_join_params->assoc.chanspec_list[0] = -+ wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); -+ } -+ ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); -+ if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { -+ WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, -+ ext_join_params->ssid.SSID_len)); -+ } -+ wl_set_drv_status(wl, CONNECTING, dev); -+ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync); -+ kfree(ext_join_params); -+ if (err) { -+ wl_clr_drv_status(wl, CONNECTING, dev); -+ if (err == BCME_UNSUPPORTED) { -+ WL_DBG(("join iovar is not supported\n")); -+ goto set_ssid; -+ } else -+ WL_ERR(("error (%d)\n", err)); -+ } else -+ goto exit; -+ -+set_ssid: -+ memset(&join_params, 0, sizeof(join_params)); -+ join_params_size = sizeof(join_params.ssid); -+ -+ join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); -+ memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); -+ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); -+ wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID); -+ if (sme->bssid) -+ memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); -+ else -+ memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); -+ -+ wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); -+ WL_DBG(("join_param_size %d\n", join_params_size)); -+ -+ if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { -+ WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, -+ join_params.ssid.SSID_len)); -+ } -+ wl_set_drv_status(wl, CONNECTING, dev); -+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); -+ if (err) { -+ WL_ERR(("error (%d)\n", err)); -+ wl_clr_drv_status(wl, CONNECTING, dev); -+ } -+exit: -+ return err; -+} -+ -+static s32 -+wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, -+ u16 reason_code) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ scb_val_t scbval; -+ bool act = false; -+ s32 err = 0; -+ u8 *curbssid; -+ WL_ERR(("Reason %d\n", reason_code)); -+ CHECK_SYS_UP(wl); -+ act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT); -+ curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID); -+ if (act) { -+ /* -+ * Cancel ongoing scan to sync up with sme state machine of cfg80211. -+ */ -+#if !defined(ESCAN_RESULT_PATCH) -+ /* Let scan aborted by F/W */ -+ if (wl->scan_request) { -+ wl_notify_escan_complete(wl, dev, true, true); -+ } -+#endif /* ESCAN_RESULT_PATCH */ -+ wl_set_drv_status(wl, DISCONNECTING, dev); -+ scbval.val = reason_code; -+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); -+ scbval.val = htod32(scbval.val); -+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, -+ sizeof(scb_val_t), true); -+ if (unlikely(err)) { -+ wl_clr_drv_status(wl, DISCONNECTING, dev); -+ WL_ERR(("error (%d)\n", err)); -+ return err; -+ } -+ } -+ -+ return err; -+} -+ -+static s32 -+wl_cfg80211_set_tx_power(struct wiphy *wiphy, -+ enum nl80211_tx_power_setting type, s32 dbm) -+{ -+ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ u16 txpwrmw; -+ s32 err = 0; -+ s32 disable = 0; -+ -+ CHECK_SYS_UP(wl); -+ switch (type) { -+ case NL80211_TX_POWER_AUTOMATIC: -+ break; -+ case NL80211_TX_POWER_LIMITED: -+ if (dbm < 0) { -+ WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n")); -+ return -EINVAL; -+ } -+ break; -+ case NL80211_TX_POWER_FIXED: -+ if (dbm < 0) { -+ WL_ERR(("TX_POWER_FIXED - dbm is negative..\n")); -+ return -EINVAL; -+ } -+ break; -+ } -+ /* Make sure radio is off or on as far as software is concerned */ -+ disable = WL_RADIO_SW_DISABLE << 16; -+ disable = htod32(disable); -+ err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), true); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); -+ return err; -+ } -+ -+ if (dbm > 0xffff) -+ txpwrmw = 0xffff; -+ else -+ txpwrmw = (u16) dbm; -+ err = wldev_iovar_setint(ndev, "qtxpower", -+ (s32) (bcm_mw_to_qdbm(txpwrmw))); -+ if (unlikely(err)) { -+ WL_ERR(("qtxpower error (%d)\n", err)); -+ return err; -+ } -+ wl->conf->tx_power = dbm; -+ -+ return err; -+} -+ -+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ s32 txpwrdbm; -+ u8 result; -+ s32 err = 0; -+ -+ CHECK_SYS_UP(wl); -+ err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm); -+ if (unlikely(err)) { -+ WL_ERR(("error (%d)\n", err)); -+ return err; -+ } -+ result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); -+ *dbm = (s32) bcm_qdbm_to_mw(result); -+ -+ return err; -+} -+ -+static s32 -+wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, bool unicast, bool multicast) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ u32 index; -+ s32 wsec; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ WL_DBG(("key index (%d)\n", key_idx)); -+ CHECK_SYS_UP(wl); -+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); -+ return err; -+ } -+ if (wsec & WEP_ENABLED) { -+ /* Just select a new current key */ -+ index = (u32) key_idx; -+ index = htod32(index); -+ err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, -+ sizeof(index), true); -+ if (unlikely(err)) { -+ WL_ERR(("error (%d)\n", err)); -+ } -+ } -+ return err; -+} -+ -+static s32 -+wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, const u8 *mac_addr, struct key_params *params) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct wl_wsec_key key; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ s32 mode = wl_get_mode_by_netdev(wl, dev); -+ memset(&key, 0, sizeof(key)); -+ key.index = (u32) key_idx; -+ -+ if (!ETHER_ISMULTI(mac_addr)) -+ memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN); -+ key.len = (u32) params->key_len; -+ -+ /* check for key index change */ -+ if (key.len == 0) { -+ /* key delete */ -+ swap_key_from_BE(&key); -+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); -+ if (unlikely(err)) { -+ WL_ERR(("key delete error (%d)\n", err)); -+ return err; -+ } -+ } else { -+ if (key.len > sizeof(key.data)) { -+ WL_ERR(("Invalid key length (%d)\n", key.len)); -+ return -EINVAL; -+ } -+ WL_DBG(("Setting the key index %d\n", key.index)); -+ memcpy(key.data, params->key, key.len); -+ -+ if ((mode == WL_MODE_BSS) && -+ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { -+ u8 keybuf[8]; -+ memcpy(keybuf, &key.data[24], sizeof(keybuf)); -+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); -+ memcpy(&key.data[16], keybuf, sizeof(keybuf)); -+ } -+ -+ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ -+ if (params->seq && params->seq_len == 6) { -+ /* rx iv */ -+ u8 *ivptr; -+ ivptr = (u8 *) params->seq; -+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | -+ (ivptr[3] << 8) | ivptr[2]; -+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; -+ key.iv_initialized = true; -+ } -+ -+ switch (params->cipher) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ key.algo = CRYPTO_ALGO_WEP1; -+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); -+ break; -+ case WLAN_CIPHER_SUITE_WEP104: -+ key.algo = CRYPTO_ALGO_WEP128; -+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); -+ break; -+ case WLAN_CIPHER_SUITE_TKIP: -+ key.algo = CRYPTO_ALGO_TKIP; -+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); -+ break; -+ case WLAN_CIPHER_SUITE_AES_CMAC: -+ key.algo = CRYPTO_ALGO_AES_CCM; -+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); -+ break; -+ case WLAN_CIPHER_SUITE_CCMP: -+ key.algo = CRYPTO_ALGO_AES_CCM; -+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); -+ break; -+ default: -+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); -+ return -EINVAL; -+ } -+ swap_key_from_BE(&key); -+ /* need to guarantee EAPOL 4/4 send out before set key */ -+ dhd_wait_pend8021x(dev); -+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_SET_KEY error (%d)\n", err)); -+ return err; -+ } -+ } -+ return err; -+} -+ -+static s32 -+wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, bool pairwise, const u8 *mac_addr, -+ struct key_params *params) -+{ -+ struct wl_wsec_key key; -+ s32 val = 0; -+ s32 wsec = 0; -+ s32 err = 0; -+ u8 keybuf[8]; -+ s32 bssidx = 0; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 mode = wl_get_mode_by_netdev(wl, dev); -+ WL_DBG(("key index (%d)\n", key_idx)); -+ CHECK_SYS_UP(wl); -+ -+ bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ if (mac_addr && -+ ((params->cipher != WLAN_CIPHER_SUITE_WEP40) && -+ (params->cipher != WLAN_CIPHER_SUITE_WEP104))) { -+ wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); -+ goto exit; -+ } -+ memset(&key, 0, sizeof(key)); -+ -+ key.len = (u32) params->key_len; -+ key.index = (u32) key_idx; -+ -+ if (unlikely(key.len > sizeof(key.data))) { -+ WL_ERR(("Too long key length (%u)\n", key.len)); -+ return -EINVAL; -+ } -+ memcpy(key.data, params->key, key.len); -+ -+ key.flags = WL_PRIMARY_KEY; -+ switch (params->cipher) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ key.algo = CRYPTO_ALGO_WEP1; -+ val = WEP_ENABLED; -+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); -+ break; -+ case WLAN_CIPHER_SUITE_WEP104: -+ key.algo = CRYPTO_ALGO_WEP128; -+ val = WEP_ENABLED; -+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); -+ break; -+ case WLAN_CIPHER_SUITE_TKIP: -+ key.algo = CRYPTO_ALGO_TKIP; -+ val = TKIP_ENABLED; -+ /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ -+ if (mode == WL_MODE_BSS) { -+ bcopy(&key.data[24], keybuf, sizeof(keybuf)); -+ bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); -+ bcopy(keybuf, &key.data[16], sizeof(keybuf)); -+ } -+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); -+ break; -+ case WLAN_CIPHER_SUITE_AES_CMAC: -+ key.algo = CRYPTO_ALGO_AES_CCM; -+ val = AES_ENABLED; -+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); -+ break; -+ case WLAN_CIPHER_SUITE_CCMP: -+ key.algo = CRYPTO_ALGO_AES_CCM; -+ val = AES_ENABLED; -+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); -+ break; -+ default: -+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); -+ return -EINVAL; -+ } -+ -+ /* Set the new key/index */ -+ swap_key_from_BE(&key); -+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, -+ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_SET_KEY error (%d)\n", err)); -+ return err; -+ } -+ -+exit: -+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("get wsec error (%d)\n", err)); -+ return err; -+ } -+ -+ wsec |= val; -+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("set wsec error (%d)\n", err)); -+ return err; -+ } -+ -+ return err; -+} -+ -+static s32 -+wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, bool pairwise, const u8 *mac_addr) -+{ -+ struct wl_wsec_key key; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ WL_DBG(("Enter\n")); -+#ifndef IEEE80211W -+ if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2)) -+ return -EINVAL; -+#endif -+ CHECK_SYS_UP(wl); -+ memset(&key, 0, sizeof(key)); -+ -+ key.flags = WL_PRIMARY_KEY; -+ key.algo = CRYPTO_ALGO_OFF; -+ key.index = (u32) key_idx; -+ -+ WL_DBG(("key index (%d)\n", key_idx)); -+ /* Set the new key/index */ -+ swap_key_from_BE(&key); -+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, -+ WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); -+ if (unlikely(err)) { -+ if (err == -EINVAL) { -+ if (key.index >= DOT11_MAX_DEFAULT_KEYS) { -+ /* we ignore this key index in this case */ -+ WL_DBG(("invalid key index (%d)\n", key_idx)); -+ } -+ } else { -+ WL_ERR(("WLC_SET_KEY error (%d)\n", err)); -+ } -+ return err; -+ } -+ return err; -+} -+ -+static s32 -+wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, -+ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, -+ void (*callback) (void *cookie, struct key_params * params)) -+{ -+ struct key_params params; -+ struct wl_wsec_key key; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct wl_security *sec; -+ s32 wsec; -+ s32 err = 0; -+ s32 bssidx = wl_cfgp2p_find_idx(wl, dev); -+ -+ WL_DBG(("key index (%d)\n", key_idx)); -+ CHECK_SYS_UP(wl); -+ memset(&key, 0, sizeof(key)); -+ key.index = key_idx; -+ swap_key_to_BE(&key); -+ memset(¶ms, 0, sizeof(params)); -+ params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); -+ memcpy(params.key, key.data, params.key_len); -+ -+ wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); -+ return err; -+ } -+ switch (wsec & ~SES_OW_ENABLED) { -+ case WEP_ENABLED: -+ sec = wl_read_prof(wl, dev, WL_PROF_SEC); -+ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { -+ params.cipher = WLAN_CIPHER_SUITE_WEP40; -+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); -+ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { -+ params.cipher = WLAN_CIPHER_SUITE_WEP104; -+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); -+ } -+ break; -+ case TKIP_ENABLED: -+ params.cipher = WLAN_CIPHER_SUITE_TKIP; -+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); -+ break; -+ case AES_ENABLED: -+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; -+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); -+ break; -+ default: -+ WL_ERR(("Invalid algo (0x%x)\n", wsec)); -+ return -EINVAL; -+ } -+ -+ callback(cookie, ¶ms); -+ return err; -+} -+ -+static s32 -+wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, -+ struct net_device *dev, u8 key_idx) -+{ -+ WL_INFO(("Not supported\n")); -+ return -EOPNOTSUPP; -+} -+ -+static s32 -+wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, -+ u8 *mac, struct station_info *sinfo) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ scb_val_t scb_val; -+ s32 rssi; -+ s32 rate; -+ s32 err = 0; -+ sta_info_t *sta; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) -+ s8 eabuf[ETHER_ADDR_STR_LEN]; -+#endif -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+ CHECK_SYS_UP(wl); -+ if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { -+ err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, -+ ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); -+ if (err < 0) { -+ WL_ERR(("GET STA INFO failed, %d\n", err)); -+ return err; -+ } -+ sinfo->filled = STATION_INFO_INACTIVE_TIME; -+ sta = (sta_info_t *)wl->ioctl_buf; -+ sta->len = dtoh16(sta->len); -+ sta->cap = dtoh16(sta->cap); -+ sta->flags = dtoh32(sta->flags); -+ sta->idle = dtoh32(sta->idle); -+ sta->in = dtoh32(sta->in); -+ sinfo->inactive_time = sta->idle * 1000; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) -+ if (sta->flags & WL_STA_ASSOC) { -+ sinfo->filled |= STATION_INFO_CONNECTED_TIME; -+ sinfo->connected_time = sta->in; -+ } -+ WL_INFO(("STA %s : idle time : %d sec, connected time :%d ms\n", -+ bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, -+ sta->idle * 1000)); -+#endif -+ } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { -+ get_pktcnt_t pktcnt; -+ u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); -+ if (!wl_get_drv_status(wl, CONNECTED, dev) || -+ (dhd_is_associated(dhd, NULL, &err) == FALSE)) { -+ WL_ERR(("NOT assoc\n")); -+ if (err == -ERESTARTSYS) -+ return err; -+ err = -ENODEV; -+ return err; -+ } -+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { -+ WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n", -+ MAC2STRDBG(mac), MAC2STRDBG(curmacp))); -+ } -+ -+ /* Report the current tx rate */ -+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); -+ if (err) { -+ WL_ERR(("Could not get rate (%d)\n", err)); -+ } else { -+ rate = dtoh32(rate); -+ sinfo->filled |= STATION_INFO_TX_BITRATE; -+ sinfo->txrate.legacy = rate * 5; -+ WL_DBG(("Rate %d Mbps\n", (rate / 2))); -+ } -+ -+ memset(&scb_val, 0, sizeof(scb_val)); -+ scb_val.val = 0; -+ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, -+ sizeof(scb_val_t), false); -+ if (err) { -+ WL_ERR(("Could not get rssi (%d)\n", err)); -+ goto get_station_err; -+ } -+ rssi = dtoh32(scb_val.val) + RSSI_OFFSET; -+ sinfo->filled |= STATION_INFO_SIGNAL; -+ sinfo->signal = rssi; -+ WL_DBG(("RSSI %d dBm\n", rssi)); -+ err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt, -+ sizeof(pktcnt), false); -+ if (!err) { -+ sinfo->filled |= (STATION_INFO_RX_PACKETS | -+ STATION_INFO_RX_DROP_MISC | -+ STATION_INFO_TX_PACKETS | -+ STATION_INFO_TX_FAILED); -+ sinfo->rx_packets = pktcnt.rx_good_pkt; -+ sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt; -+ sinfo->tx_packets = pktcnt.tx_good_pkt; -+ sinfo->tx_failed = pktcnt.tx_bad_pkt; -+ } -+get_station_err: -+ if (err && (err != -ERESTARTSYS)) { -+ /* Disconnect due to zero BSSID or error to get RSSI */ -+ WL_ERR(("force cfg80211_disconnected\n")); -+ wl_clr_drv_status(wl, CONNECTED, dev); -+ cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); -+ wl_link_down(wl); -+ } -+ } -+ -+ return err; -+} -+ -+/* Function to update sta power save mode for Kernel wifi stack */ -+int wl_cfg80211_update_power_mode(struct net_device *dev) -+{ -+ int pm = -1; -+ int err; -+ -+ err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), false); -+ if (err || (pm == -1)) { -+ WL_ERR(("error (%d)\n", err)); -+ } else { -+ pm = (pm == PM_OFF) ? false : true; -+ WL_DBG(("%s: %d\n", __func__, pm)); -+ if (dev->ieee80211_ptr) -+ dev->ieee80211_ptr->ps = pm; -+ } -+ return err; -+} -+ -+static s32 -+wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, -+ bool enabled, s32 timeout) -+{ -+ s32 pm; -+ s32 err = 0; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_info *_net_info = wl_get_netinfo_by_netdev(wl, dev); -+#if !defined(SUPPORT_PM2_ONLY) -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+#endif -+ -+ CHECK_SYS_UP(wl); -+ -+ if (wl->p2p_net == dev || _net_info == NULL) { -+ return err; -+ } -+ WL_DBG(("%s: Enter power save enabled %d\n", dev->name, enabled)); -+ -+#if !defined(SUPPORT_PM2_ONLY) -+ /* android has special hooks to change pm when kernel suspended */ -+ pm = enabled ? ((dhd->in_suspend) ? PM_MAX : PM_FAST) : PM_OFF; -+#else -+ pm = enabled ? PM_FAST : PM_OFF; -+#endif /* SUPPORT_PM2_ONLY */ -+ -+ if (_net_info->pm_block || wl->vsdb_mode) { -+ /* Do not enable the power save if it is p2p interface or vsdb mode is set */ -+ WL_DBG(("%s:Do not enable the power save for pm_block %d or vsdb_mode %d\n", -+ dev->name, _net_info->pm_block, wl->vsdb_mode)); -+ pm = PM_OFF; -+ } -+ pm = htod32(pm); -+ WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled"))); -+ err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true); -+ if (unlikely(err)) { -+ if (err == -ENODEV) -+ WL_DBG(("net_device is not ready yet\n")); -+ else -+ WL_ERR(("error (%d)\n", err)); -+ return err; -+ } -+ return err; -+} -+ -+static __used u32 wl_find_msb(u16 bit16) -+{ -+ u32 ret = 0; -+ -+ if (bit16 & 0xff00) { -+ ret += 8; -+ bit16 >>= 8; -+ } -+ -+ if (bit16 & 0xf0) { -+ ret += 4; -+ bit16 >>= 4; -+ } -+ -+ if (bit16 & 0xc) { -+ ret += 2; -+ bit16 >>= 2; -+ } -+ -+ if (bit16 & 2) -+ ret += bit16 & 2; -+ else if (bit16) -+ ret += bit16; -+ -+ return ret; -+} -+ -+static s32 wl_cfg80211_resume(struct wiphy *wiphy) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ s32 err = 0; -+ -+ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { -+ WL_INFO(("device is not ready\n")); -+ return 0; -+ } -+ -+ wl_invoke_iscan(wl); -+ -+ return err; -+} -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) -+static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) -+#else -+static s32 wl_cfg80211_suspend(struct wiphy *wiphy) -+#endif -+{ -+#ifdef DHD_CLEAR_ON_SUSPEND -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_info *iter, *next; -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ unsigned long flags; -+ if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { -+ WL_INFO(("device is not ready : status (%d)\n", -+ (int)wl->status)); -+ return 0; -+ } -+ for_each_ndev(wl, iter, next) -+ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); -+ wl_term_iscan(wl); -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ if (wl->scan_request) { -+ cfg80211_scan_done(wl->scan_request, true); -+ wl->scan_request = NULL; -+ } -+ for_each_ndev(wl, iter, next) { -+ wl_clr_drv_status(wl, SCANNING, iter->ndev); -+ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); -+ } -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ for_each_ndev(wl, iter, next) { -+ if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) { -+ wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false); -+ } -+ } -+#endif /* DHD_CLEAR_ON_SUSPEND */ -+ return 0; -+} -+ -+static s32 -+wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, -+ s32 err) -+{ -+ int i, j; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct net_device *primary_dev = wl_to_prmry_ndev(wl); -+ -+ if (!pmk_list) { -+ printk("pmk_list is NULL\n"); -+ return -EINVAL; -+ } -+ /* pmk list is supported only for STA interface i.e. primary interface -+ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init -+ */ -+ if (primary_dev != dev) { -+ WL_INFO(("Not supporting Flushing pmklist on virtual" -+ " interfaces than primary interface\n")); -+ return err; -+ } -+ -+ WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); -+ for (i = 0; i < pmk_list->pmkids.npmkid; i++) { -+ WL_DBG(("PMKID[%d]: %pM =\n", i, -+ &pmk_list->pmkids.pmkid[i].BSSID)); -+ for (j = 0; j < WPA2_PMKID_LEN; j++) { -+ WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j])); -+ } -+ } -+ if (likely(!err)) { -+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, -+ sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); -+ } -+ -+ return err; -+} -+ -+static s32 -+wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_pmksa *pmksa) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 err = 0; -+ int i; -+ -+ CHECK_SYS_UP(wl); -+ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) -+ if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, -+ ETHER_ADDR_LEN)) -+ break; -+ if (i < WL_NUM_PMKIDS_MAX) { -+ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, -+ ETHER_ADDR_LEN); -+ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, -+ WPA2_PMKID_LEN); -+ if (i == wl->pmk_list->pmkids.npmkid) -+ wl->pmk_list->pmkids.npmkid++; -+ } else { -+ err = -EINVAL; -+ } -+ WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", -+ &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].BSSID)); -+ for (i = 0; i < WPA2_PMKID_LEN; i++) { -+ WL_DBG(("%02x\n", -+ wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1]. -+ PMKID[i])); -+ } -+ -+ err = wl_update_pmklist(dev, wl->pmk_list, err); -+ -+ return err; -+} -+ -+static s32 -+wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, -+ struct cfg80211_pmksa *pmksa) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct _pmkid_list pmkid; -+ s32 err = 0; -+ int i; -+ -+ CHECK_SYS_UP(wl); -+ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); -+ memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); -+ -+ WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", -+ &pmkid.pmkid[0].BSSID)); -+ for (i = 0; i < WPA2_PMKID_LEN; i++) { -+ WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i])); -+ } -+ -+ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) -+ if (!memcmp -+ (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, -+ ETHER_ADDR_LEN)) -+ break; -+ -+ if ((wl->pmk_list->pmkids.npmkid > 0) && -+ (i < wl->pmk_list->pmkids.npmkid)) { -+ memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t)); -+ for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) { -+ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, -+ &wl->pmk_list->pmkids.pmkid[i + 1].BSSID, -+ ETHER_ADDR_LEN); -+ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, -+ &wl->pmk_list->pmkids.pmkid[i + 1].PMKID, -+ WPA2_PMKID_LEN); -+ } -+ wl->pmk_list->pmkids.npmkid--; -+ } else { -+ err = -EINVAL; -+ } -+ -+ err = wl_update_pmklist(dev, wl->pmk_list, err); -+ -+ return err; -+ -+} -+ -+static s32 -+wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 err = 0; -+ CHECK_SYS_UP(wl); -+ memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); -+ err = wl_update_pmklist(dev, wl->pmk_list, err); -+ return err; -+ -+} -+ -+static wl_scan_params_t * -+wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) -+{ -+ wl_scan_params_t *params; -+ int params_size; -+ int num_chans; -+ -+ *out_params_size = 0; -+ -+ /* Our scan params only need space for 1 channel and 0 ssids */ -+ params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16); -+ params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL); -+ if (params == NULL) { -+ WL_ERR(("%s: mem alloc failed (%d bytes)\n", __func__, params_size)); -+ return params; -+ } -+ memset(params, 0, params_size); -+ params->nprobes = nprobes; -+ -+ num_chans = (channel == 0) ? 0 : 1; -+ -+ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); -+ params->bss_type = DOT11_BSSTYPE_ANY; -+ params->scan_type = DOT11_SCANTYPE_ACTIVE; -+ params->nprobes = htod32(1); -+ params->active_time = htod32(-1); -+ params->passive_time = htod32(-1); -+ params->home_time = htod32(10); -+ if (channel == -1) -+ params->channel_list[0] = htodchanspec(channel); -+ else -+ params->channel_list[0] = wl_ch_host_to_driver(channel); -+ -+ /* Our scan params have 1 channel and 0 ssids */ -+ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | -+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); -+ -+ *out_params_size = params_size; /* rtn size to the caller */ -+ return params; -+} -+ -+static s32 -+wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, -+ struct ieee80211_channel * channel, -+ enum nl80211_channel_type channel_type, -+ unsigned int duration, u64 *cookie) -+{ -+ s32 target_channel; -+ u32 id; -+ struct ether_addr primary_mac; -+ struct net_device *ndev = NULL; -+ -+ s32 err = BCME_OK; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ -+ WL_DBG(("Enter, ifindex: %d, channel: %d, duration ms (%d) SCANNING ?? %s \n", -+ dev->ifindex, ieee80211_frequency_to_channel(channel->center_freq), -+ duration, (wl_get_drv_status(wl, SCANNING, ndev)) ? "YES":"NO")); -+ -+ if (wl->p2p_net == dev) { -+ ndev = wl_to_prmry_ndev(wl); -+ } else { -+ ndev = dev; -+ } -+ -+ if (!wl->p2p) { -+ WL_ERR(("wl->p2p is not initialized\n")); -+ err = BCME_ERROR; -+ goto exit; -+ } -+ -+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ if (wl_get_drv_status(wl, SCANNING, ndev)) { -+ wl_notify_escan_complete(wl, ndev, true, true); -+ } -+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ -+ target_channel = ieee80211_frequency_to_channel(channel->center_freq); -+ memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); -+ wl->remain_on_chan_type = channel_type; -+ id = ++wl->last_roc_id; -+ if (id == 0) -+ id = ++wl->last_roc_id; -+ *cookie = id; -+ -+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ if (wl_get_drv_status(wl, SCANNING, ndev)) { -+ struct timer_list *_timer; -+ WL_DBG(("scan is running. go to fake listen state\n")); -+ -+ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); -+ -+ if (timer_pending(&wl->p2p->listen_timer)) { -+ WL_DBG(("cancel current listen timer \n")); -+ del_timer_sync(&wl->p2p->listen_timer); -+ } -+ -+ _timer = &wl->p2p->listen_timer; -+ wl_clr_p2p_status(wl, LISTEN_EXPIRED); -+ -+ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0); -+ -+ err = BCME_OK; -+ goto exit; -+ } -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ -+#ifdef WL_CFG80211_SYNC_GON -+ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { -+ /* do not enter listen mode again if we are in listen mode already for next af. -+ * remain on channel completion will be returned by waiting next af completion. -+ */ -+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); -+#else -+ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ goto exit; -+ } -+#endif /* WL_CFG80211_SYNC_GON */ -+ if (wl->p2p && !wl->p2p->on) { -+ /* In case of p2p_listen command, supplicant send remain_on_channel -+ * without turning on P2P -+ */ -+ get_primary_mac(wl, &primary_mac); -+ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); -+ p2p_on(wl) = true; -+ } -+ -+ if (p2p_is_on(wl)) { -+ err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0); -+ if (unlikely(err)) { -+ goto exit; -+ } -+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); -+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ err = wl_cfgp2p_discover_listen(wl, target_channel, duration); -+ -+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ if (err == BCME_OK) { -+ wl_set_drv_status(wl, REMAINING_ON_CHANNEL, ndev); -+ } else { -+ /* if failed, firmware may be internal scanning state. -+ * so other scan request shall not abort it -+ */ -+ wl_set_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, ndev); -+ } -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant -+ * and expire timer will send a completion to the upper layer -+ */ -+ err = BCME_OK; -+ } -+ -+exit: -+ if (err == BCME_OK) { -+ WL_INFO(("Success\n")); -+ cfg80211_ready_on_channel(dev, *cookie, channel, -+ channel_type, duration, GFP_KERNEL); -+ } else { -+ WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie)); -+ } -+ return err; -+} -+ -+static s32 -+wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, -+ u64 cookie) -+{ -+ s32 err = 0; -+ WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex)); -+ return err; -+} -+ -+static void -+wl_cfg80211_afx_handler(struct work_struct *work) -+{ -+ struct afx_hdl *afx_instance; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ s32 ret = BCME_OK; -+ -+ afx_instance = container_of(work, struct afx_hdl, work); -+ if (afx_instance != NULL && wl->afx_hdl->is_active) { -+ if (wl->afx_hdl->is_listen && wl->afx_hdl->my_listen_chan) { -+ ret = wl_cfgp2p_discover_listen(wl, wl->afx_hdl->my_listen_chan, -+ (100 * (1 + (random32() % 3)))); /* 100ms ~ 300ms */ -+ } else { -+ ret = wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, -+ wl->afx_hdl->bssidx, wl->afx_hdl->peer_listen_chan, -+ &wl->afx_hdl->tx_dst_addr); -+ } -+ if (unlikely(ret != BCME_OK)) { -+ WL_ERR(("ERROR occurred! returned value is (%d)\n", ret)); -+ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) -+ complete(&wl->act_frm_scan); -+ } -+ } -+} -+ -+static s32 -+wl_cfg80211_af_searching_channel(struct wl_priv *wl, struct net_device *dev) -+{ -+ u32 max_retry = WL_CHANNEL_SYNC_RETRY; -+ -+ if (dev == NULL) -+ return -1; -+ -+ WL_DBG((" enter ) \n")); -+ -+ wl_set_drv_status(wl, FINDING_COMMON_CHANNEL, dev); -+ wl->afx_hdl->is_active = TRUE; -+ -+ /* Loop to wait until we find a peer's channel or the -+ * pending action frame tx is cancelled. -+ */ -+ while ((wl->afx_hdl->retry < max_retry) && -+ (wl->afx_hdl->peer_chan == WL_INVALID)) { -+ wl->afx_hdl->is_listen = FALSE; -+ wl_set_drv_status(wl, SCANNING, dev); -+ WL_DBG(("Scheduling the action frame for sending.. retry %d\n", -+ wl->afx_hdl->retry)); -+ /* search peer on peer's listen channel */ -+ schedule_work(&wl->afx_hdl->work); -+ wait_for_completion_timeout(&wl->act_frm_scan, -+ msecs_to_jiffies(MAX_WAIT_TIME)); -+ -+ if ((wl->afx_hdl->peer_chan != WL_INVALID) || -+ !(wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev))) -+ break; -+ -+ if (wl->afx_hdl->my_listen_chan) { -+ WL_DBG(("Scheduling Listen peer in my listen channel = %d\n", -+ wl->afx_hdl->my_listen_chan)); -+ /* listen on my listen channel */ -+ wl->afx_hdl->is_listen = TRUE; -+ schedule_work(&wl->afx_hdl->work); -+ wait_for_completion_timeout(&wl->act_frm_scan, -+ msecs_to_jiffies(MAX_WAIT_TIME)); -+ } -+ if ((wl->afx_hdl->peer_chan != WL_INVALID) || -+ !(wl_get_drv_status(wl, FINDING_COMMON_CHANNEL, dev))) -+ break; -+ -+ wl->afx_hdl->retry++; -+ -+ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); -+ } -+ -+ wl->afx_hdl->is_active = FALSE; -+ -+ wl_clr_drv_status(wl, SCANNING, dev); -+ wl_clr_drv_status(wl, FINDING_COMMON_CHANNEL, dev); -+ -+ return (wl->afx_hdl->peer_chan); -+} -+ -+struct p2p_config_af_params { -+ s32 max_tx_retry; /* max tx retry count if tx no ack */ -+ /* To make sure to send successfully action frame, we have to turn off mpc -+ * 0: off, 1: on, (-1): do nothing -+ */ -+ s32 mpc_onoff; -+#ifdef WL_CFG80211_SYNC_GON -+ bool extra_listen; -+#endif -+ bool search_channel; /* 1: search peer's channel to send af */ -+}; -+ -+static s32 -+wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, -+ wl_action_frame_t *action_frame, wl_af_params_t *af_params, -+ struct p2p_config_af_params *config_af_params) -+{ -+ s32 err = BCME_OK; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ wifi_p2p_pub_act_frame_t *act_frm = -+ (wifi_p2p_pub_act_frame_t *) (action_frame->data); -+ -+ /* initialize default value */ -+#ifdef WL_CFG80211_SYNC_GON -+ config_af_params->extra_listen = true; -+#endif -+ config_af_params->search_channel = false; -+ config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY; -+ config_af_params->mpc_onoff = -1; -+ -+ switch (act_frm->subtype) { -+ case P2P_PAF_GON_REQ: { -+ WL_DBG(("P2P: GO_NEG_PHASE status set \n")); -+ wl_set_p2p_status(wl, GO_NEG_PHASE); -+ -+ config_af_params->mpc_onoff = 0; -+ config_af_params->search_channel = true; -+ wl->next_af_subtype = act_frm->subtype + 1; -+ -+ /* increase dwell time to wait for RESP frame */ -+ af_params->dwell_time = WL_MED_DWELL_TIME; -+ -+ break; -+ } -+ case P2P_PAF_GON_RSP: { -+ wl->next_af_subtype = act_frm->subtype + 1; -+ /* increase dwell time to wait for CONF frame */ -+ af_params->dwell_time = WL_MED_DWELL_TIME; -+ break; -+ } -+ case P2P_PAF_GON_CONF: { -+ /* If we reached till GO Neg confirmation reset the filter */ -+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); -+ wl_clr_p2p_status(wl, GO_NEG_PHASE); -+ -+ /* turn on mpc again if go nego is done */ -+ config_af_params->mpc_onoff = 1; -+ -+ /* minimize dwell time */ -+ af_params->dwell_time = WL_MIN_DWELL_TIME; -+ -+#ifdef WL_CFG80211_SYNC_GON -+ config_af_params->extra_listen = false; -+#endif /* WL_CFG80211_SYNC_GON */ -+ break; -+ } -+ case P2P_PAF_INVITE_REQ: { -+ config_af_params->search_channel = true; -+ wl->next_af_subtype = act_frm->subtype + 1; -+ -+ /* increase dwell time */ -+ af_params->dwell_time = WL_MED_DWELL_TIME; -+ break; -+ } -+ case P2P_PAF_INVITE_RSP: -+ /* minimize dwell time */ -+ af_params->dwell_time = WL_MIN_DWELL_TIME; -+#ifdef WL_CFG80211_SYNC_GON -+ config_af_params->extra_listen = false; -+#endif /* WL_CFG80211_SYNC_GON */ -+ break; -+ case P2P_PAF_DEVDIS_REQ: { -+ config_af_params->search_channel = true; -+ -+ wl->next_af_subtype = act_frm->subtype + 1; -+ /* maximize dwell time to wait for RESP frame */ -+ af_params->dwell_time = WL_LONG_DWELL_TIME; -+ break; -+ } -+ case P2P_PAF_DEVDIS_RSP: -+ /* minimize dwell time */ -+ af_params->dwell_time = WL_MIN_DWELL_TIME; -+#ifdef WL_CFG80211_SYNC_GON -+ config_af_params->extra_listen = false; -+#endif /* WL_CFG80211_SYNC_GON */ -+ break; -+ case P2P_PAF_PROVDIS_REQ: { -+ if (IS_PROV_DISC_WITHOUT_GROUP_ID(&act_frm->elts[0], -+ action_frame->len)) { -+ config_af_params->search_channel = true; -+ } -+ -+ config_af_params->mpc_onoff = 0; -+ wl->next_af_subtype = act_frm->subtype + 1; -+ /* increase dwell time to wait for RESP frame */ -+ af_params->dwell_time = WL_MED_DWELL_TIME; -+ break; -+ } -+ case P2P_PAF_PROVDIS_RSP: { -+ wl->next_af_subtype = P2P_PAF_GON_REQ; -+ /* increase dwell time to MED level */ -+ af_params->dwell_time = WL_MED_DWELL_TIME; -+#ifdef WL_CFG80211_SYNC_GON -+ config_af_params->extra_listen = false; -+#endif /* WL_CFG80211_SYNC_GON */ -+ break; -+ } -+ default: -+ WL_DBG(("Unknown p2p pub act frame subtype: %d\n", -+ act_frm->subtype)); -+ err = BCME_BADARG; -+ } -+ return err; -+} -+ -+ -+static bool -+wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, -+ struct net_device *ndev, wl_af_params_t *af_params, -+ wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ bool ack = false; -+ u8 category, action; -+ s32 tx_retry; -+ struct p2p_config_af_params config_af_params; -+#ifdef VSDB -+ ulong off_chan_started_jiffies = 0; -+#endif -+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -+ -+ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len); -+ -+ category = action_frame->data[DOT11_ACTION_CAT_OFF]; -+ action = action_frame->data[DOT11_ACTION_ACT_OFF]; -+ -+ /* initialize variables */ -+ tx_retry = 0; -+ wl->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; -+ config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY; -+ config_af_params.mpc_onoff = -1; -+ config_af_params.search_channel = false; -+#ifdef WL_CFG80211_SYNC_GON -+ config_af_params.extra_listen = false; -+#endif -+ -+ /* config parameters */ -+ /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */ -+ if (category == DOT11_ACTION_CAT_PUBLIC) { -+ if ((action == P2P_PUB_AF_ACTION) && -+ (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) { -+ /* p2p public action frame process */ -+ if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy, -+ action_frame, af_params, &config_af_params)) { -+ WL_DBG(("Unknown subtype.\n")); -+ } -+ -+ } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) { -+ /* service discovery process */ -+ if (action == P2PSD_ACTION_ID_GAS_IREQ || -+ action == P2PSD_ACTION_ID_GAS_CREQ) { -+ /* configure service discovery query frame */ -+ -+ config_af_params.search_channel = true; -+ -+ /* save next af suptype to cancel remained dwell time */ -+ wl->next_af_subtype = action + 1; -+ -+ af_params->dwell_time = WL_MED_DWELL_TIME; -+ } else if (action == P2PSD_ACTION_ID_GAS_IRESP || -+ action == P2PSD_ACTION_ID_GAS_CRESP) { -+ /* configure service discovery response frame */ -+ af_params->dwell_time = WL_MIN_DWELL_TIME; -+ } else { -+ WL_DBG(("Unknown action type: %d\n", action)); -+ } -+ } else { -+ WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n", -+ category, action, action_frame_len)); -+ } -+ } else if (category == P2P_AF_CATEGORY) { -+ /* do not configure anything. it will be sent with a default configuration */ -+ } else { -+ WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n", -+ category, action)); -+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { -+ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); -+ return false; -+ } -+ } -+ -+ /* To make sure to send successfully action frame, we have to turn off mpc */ -+ if (config_af_params.mpc_onoff == 0) { -+ wldev_iovar_setint(dev, "mpc", 0); -+ } -+ -+ /* validate channel and p2p ies */ -+ if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) && -+ wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { -+ config_af_params.search_channel = true; -+ } else { -+ config_af_params.search_channel = false; -+ } -+ -+#ifdef VSDB -+ /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ -+ if (wl_get_drv_status(wl, CONNECTING, wl_to_prmry_ndev(wl))) { -+ msleep(50); -+ } -+#endif -+ -+ /* if scan is ongoing, abort current scan. */ -+ if (wl_get_drv_status_all(wl, SCANNING)) { -+ wl_notify_escan_complete(wl, ndev, true, true); -+ } -+ -+ /* set status and destination address before sending af */ -+ if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { -+ /* set this status to cancel the remained dwell time in rx process */ -+ wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); -+ } -+ wl_set_drv_status(wl, SENDING_ACT_FRM, dev); -+ memcpy(wl->afx_hdl->tx_dst_addr.octet, -+ af_params->action_frame.da.octet, -+ sizeof(wl->afx_hdl->tx_dst_addr.octet)); -+ -+ /* save af_params for rx process */ -+ wl->afx_hdl->pending_tx_act_frm = af_params; -+ -+ /* search peer's channel */ -+ if (config_af_params.search_channel) { -+ /* initialize afx_hdl */ -+ wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev); -+ wl->afx_hdl->dev = dev; -+ wl->afx_hdl->retry = 0; -+ wl->afx_hdl->peer_chan = WL_INVALID; -+ -+ if (wl_cfg80211_af_searching_channel(wl, dev) == WL_INVALID) { -+ WL_ERR(("couldn't find peer's channel.\n")); -+ goto exit; -+ } -+ -+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); -+ /* -+ * Abort scan even for VSDB scenarios. Scan gets aborted in firmware -+ * but after the check of piggyback algorithm. -+ * To take care of current piggback algo, lets abort the scan here itself. -+ */ -+ wl_notify_escan_complete(wl, dev, true, true); -+ /* Suspend P2P discovery's search-listen to prevent it from -+ * starting a scan or changing the channel. -+ */ -+ wl_cfgp2p_discover_enable_search(wl, false); -+ -+ /* update channel */ -+ af_params->channel = wl->afx_hdl->peer_chan; -+ } -+ -+#ifdef VSDB -+ off_chan_started_jiffies = jiffies; -+#endif /* VSDB */ -+ -+ /* Now send a tx action frame */ -+ ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? false : true; -+ -+ /* if failed, retry it. tx_retry_max value is configure by .... */ -+ while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) { -+#ifdef VSDB -+ if (af_params->channel) { -+ if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) > -+ OFF_CHAN_TIME_THRESHOLD_MS) { -+ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(wl); -+ off_chan_started_jiffies = jiffies; -+ } -+ } -+#endif /* VSDB */ -+ ack = wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx) ? -+ false : true; -+ } -+ if (ack == false) { -+ WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry)); -+ } -+exit: -+ /* Clear SENDING_ACT_FRM after all sending af is done */ -+ wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); -+ -+#ifdef WL_CFG80211_SYNC_GON -+ /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. -+ * if we coundn't get the next action response frame and dongle does not keep -+ * the dwell time, go to listen state again to get next action response frame. -+ */ -+ if (ack && config_af_params.extra_listen && -+ wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM) && -+ wl->af_sent_channel == wl->afx_hdl->my_listen_chan) { -+ s32 extar_listen_time; -+ -+ extar_listen_time = af_params->dwell_time - -+ jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies); -+ -+ if (extar_listen_time > 50) { -+ wl_set_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); -+ WL_DBG(("Wait more time! actual af time:%d," -+ "calculated extar listen:%d\n", -+ af_params->dwell_time, extar_listen_time)); -+ if (wl_cfgp2p_discover_listen(wl, wl->af_sent_channel, -+ extar_listen_time + 100) == BCME_OK) { -+ wait_for_completion_timeout(&wl->wait_next_af, -+ msecs_to_jiffies(extar_listen_time + 100 + 300)); -+ } -+ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, dev); -+ } -+ } -+#endif /* WL_CFG80211_SYNC_GON */ -+ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, dev); -+ -+ if (wl->afx_hdl->pending_tx_act_frm) -+ wl->afx_hdl->pending_tx_act_frm = NULL; -+ -+ WL_INFO(("-- sending Action Frame is %s, listen chan: %d\n", -+ (ack) ? "Succeeded!!":"Failed!!", wl->afx_hdl->my_listen_chan)); -+ -+ -+ /* if all done, turn mpc on again */ -+ if (config_af_params.mpc_onoff == 1) { -+ wldev_iovar_setint(dev, "mpc", 1); -+ } -+ -+ return ack; -+} -+ -+#define MAX_NUM_OF_ASSOCIATED_DEV 64 -+static s32 -+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, -+ struct ieee80211_channel *channel, bool offchan, -+ enum nl80211_channel_type channel_type, -+ bool channel_type_valid, unsigned int wait, -+ const u8* buf, size_t len, -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) -+ bool no_cck, -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) -+ bool dont_wait_for_ack, -+#endif -+ u64 *cookie) -+{ -+ wl_action_frame_t *action_frame; -+ wl_af_params_t *af_params; -+ scb_val_t scb_val; -+ const struct ieee80211_mgmt *mgmt; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct net_device *dev = NULL; -+ s32 err = BCME_OK; -+ s32 bssidx = 0; -+ u32 id; -+ bool ack = false; -+ s8 eabuf[ETHER_ADDR_STR_LEN]; -+ -+ WL_DBG(("Enter \n")); -+ -+ if (ndev == wl->p2p_net) { -+ dev = wl_to_prmry_ndev(wl); -+ } else { -+ /* If TX req is for any valid ifidx. Use as is */ -+ dev = ndev; -+ } -+ -+ /* find bssidx based on ndev */ -+ bssidx = wl_cfgp2p_find_idx(wl, dev); -+ if (bssidx == -1) { -+ -+ WL_ERR(("Can not find the bssidx for dev( %p )\n", dev)); -+ return -ENODEV; -+ } -+ if (p2p_is_on(wl)) { -+ /* Suspend P2P discovery search-listen to prevent it from changing the -+ * channel. -+ */ -+ if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) { -+ WL_ERR(("Can not disable discovery mode\n")); -+ return -EFAULT; -+ } -+ } -+ *cookie = 0; -+ id = wl->send_action_id++; -+ if (id == 0) -+ id = wl->send_action_id++; -+ *cookie = id; -+ mgmt = (const struct ieee80211_mgmt *)buf; -+ if (ieee80211_is_mgmt(mgmt->frame_control)) { -+ if (ieee80211_is_probe_resp(mgmt->frame_control)) { -+ s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; -+ s32 ie_len = len - ie_offset; -+ if (dev == wl_to_prmry_ndev(wl)) -+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); -+ wl_cfgp2p_set_management_ie(wl, dev, bssidx, -+ VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len); -+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); -+ goto exit; -+ } else if (ieee80211_is_disassoc(mgmt->frame_control) || -+ ieee80211_is_deauth(mgmt->frame_control)) { -+ char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * -+ sizeof(struct ether_addr) + sizeof(uint)] = {0}; -+ int num_associated = 0; -+ struct maclist *assoc_maclist = (struct maclist *)mac_buf; -+ if (!bcmp((const uint8 *)BSSID_BROADCAST, -+ (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) { -+ assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; -+ err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST, -+ assoc_maclist, sizeof(mac_buf), false); -+ if (err < 0) -+ WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); -+ else -+ num_associated = assoc_maclist->count; -+ } -+ memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); -+ scb_val.val = mgmt->u.disassoc.reason_code; -+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, -+ sizeof(scb_val_t), true); -+ if (err < 0) -+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err)); -+ WL_DBG(("Disconnect STA : %s scb_val.val %d\n", -+ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), -+ scb_val.val)); -+ if (num_associated) { -+ wl_delay(400); -+ } -+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); -+ goto exit; -+ -+ } else if (ieee80211_is_action(mgmt->frame_control)) { -+ /* Abort the dwell time of any previous off-channel -+ * action frame that may be still in effect. Sending -+ * off-channel action frames relies on the driver's -+ * scan engine. If a previous off-channel action frame -+ * tx is still in progress (including the dwell time), -+ * then this new action frame will not be sent out. -+ */ -+/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary. -+ * And previous off-channel action frame must be ended before new af tx. -+ */ -+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ wl_notify_escan_complete(wl, dev, true, true); -+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ } -+ -+ } else { -+ WL_ERR(("Driver only allows MGMT packet type\n")); -+ goto exit; -+ } -+ -+ af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); -+ -+ if (af_params == NULL) -+ { -+ WL_ERR(("unable to allocate frame\n")); -+ return -ENOMEM; -+ } -+ -+ action_frame = &af_params->action_frame; -+ -+ /* Add the packet Id */ -+ action_frame->packetId = *cookie; -+ WL_DBG(("action frame %d\n", action_frame->packetId)); -+ /* Add BSSID */ -+ memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); -+ memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN); -+ -+ /* Add the length exepted for 802.11 header */ -+ action_frame->len = len - DOT11_MGMT_HDR_LEN; -+ WL_DBG(("action_frame->len: %d\n", action_frame->len)); -+ -+ /* Add the channel */ -+ af_params->channel = -+ ieee80211_frequency_to_channel(channel->center_freq); -+ -+ /* Save listen_chan for searching common channel */ -+ wl->afx_hdl->peer_listen_chan = af_params->channel; -+ WL_DBG(("channel from upper layer %d\n", wl->afx_hdl->peer_listen_chan)); -+ -+ /* Add the default dwell time -+ * Dwell time to stay off-channel to wait for a response action frame -+ * after transmitting an GO Negotiation action frame -+ */ -+ af_params->dwell_time = WL_DWELL_TIME; -+ -+ memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); -+ -+ ack = wl_cfg80211_send_action_frame(wiphy, dev, ndev, af_params, -+ action_frame, action_frame->len, bssidx); -+ -+ cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); -+ -+ kfree(af_params); -+exit: -+ return err; -+} -+ -+ -+static void -+wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev, -+ u16 frame_type, bool reg) -+{ -+ -+ WL_DBG(("%s: frame_type: %x, reg: %d\n", __func__, frame_type, reg)); -+ -+ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) -+ return; -+ -+ return; -+} -+ -+ -+static s32 -+wl_cfg80211_change_bss(struct wiphy *wiphy, -+ struct net_device *dev, -+ struct bss_parameters *params) -+{ -+ if (params->use_cts_prot >= 0) { -+ } -+ -+ if (params->use_short_preamble >= 0) { -+ } -+ -+ if (params->use_short_slot_time >= 0) { -+ } -+ -+ if (params->basic_rates) { -+ } -+ -+ if (params->ap_isolate >= 0) { -+ } -+ -+ if (params->ht_opmode >= 0) { -+ } -+ -+ return 0; -+} -+ -+static s32 -+wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, -+ struct ieee80211_channel *chan, -+ enum nl80211_channel_type channel_type) -+{ -+ s32 _chan; -+ chanspec_t chspec = 0; -+ chanspec_t fw_chspec = 0; -+ u32 bw = WL_CHANSPEC_BW_20; -+ -+ s32 err = BCME_OK; -+ s32 bw_cap = 0; -+ struct { -+ u32 band; -+ u32 bw_cap; -+ } param = {0, 0}; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ -+ if (wl->p2p_net == dev) { -+ dev = wl_to_prmry_ndev(wl); -+ } -+ _chan = ieee80211_frequency_to_channel(chan->center_freq); -+ WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", -+ dev->ifindex, channel_type, _chan)); -+ -+ -+ if (chan->band == IEEE80211_BAND_5GHZ) { -+ param.band = WLC_BAND_5G; -+ err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param), -+ wl->ioctl_buf, WLC_IOCTL_SMLEN, &wl->ioctl_buf_sync); -+ if (err) { -+ if (err != BCME_UNSUPPORTED) { -+ WL_ERR(("bw_cap failed, %d\n", err)); -+ return err; -+ } else { -+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); -+ if (err) { -+ WL_ERR(("error get mimo_bw_cap (%d)\n", err)); -+ } -+ if (bw_cap != WLC_N_BW_20ALL) -+ bw = WL_CHANSPEC_BW_40; -+ } -+ } else { -+ if (WL_BW_CAP_80MHZ(wl->ioctl_buf[0])) -+ bw = WL_CHANSPEC_BW_80; -+ else if (WL_BW_CAP_40MHZ(wl->ioctl_buf[0])) -+ bw = WL_CHANSPEC_BW_40; -+ else -+ bw = WL_CHANSPEC_BW_20; -+ -+ } -+ -+ } else if (chan->band == IEEE80211_BAND_2GHZ) -+ bw = WL_CHANSPEC_BW_20; -+set_channel: -+ chspec = wf_channel2chspec(_chan, bw); -+ if (wf_chspec_valid(chspec)) { -+ fw_chspec = wl_chspec_host_to_driver(chspec); -+ if (fw_chspec != INVCHANSPEC) { -+ if ((err = wldev_iovar_setint(dev, "chanspec", -+ fw_chspec)) == BCME_BADCHAN) { -+ if (bw == WL_CHANSPEC_BW_80) -+ goto change_bw; -+ err = wldev_ioctl(dev, WLC_SET_CHANNEL, -+ &_chan, sizeof(_chan), true); -+ if (err < 0) { -+ WL_ERR(("WLC_SET_CHANNEL error %d" -+ "chip may not be supporting this channel\n", err)); -+ } -+ } else if (err) { -+ WL_ERR(("failed to set chanspec error %d\n", err)); -+ } -+ } else { -+ WL_ERR(("failed to convert host chanspec to fw chanspec\n")); -+ err = BCME_ERROR; -+ } -+ } else { -+change_bw: -+ if (bw == WL_CHANSPEC_BW_80) -+ bw = WL_CHANSPEC_BW_40; -+ else if (bw == WL_CHANSPEC_BW_40) -+ bw = WL_CHANSPEC_BW_20; -+ else -+ bw = 0; -+ if (bw) -+ goto set_channel; -+ WL_ERR(("Invalid chanspec 0x%x\n", chspec)); -+ err = BCME_ERROR; -+ } -+ return err; -+} -+ -+static s32 -+wl_validate_opensecurity(struct net_device *dev, s32 bssidx) -+{ -+ s32 err = BCME_OK; -+ -+ /* set auth */ -+ err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx); -+ if (err < 0) { -+ WL_ERR(("auth error %d\n", err)); -+ return BCME_ERROR; -+ } -+ /* set wsec */ -+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx); -+ if (err < 0) { -+ WL_ERR(("wsec error %d\n", err)); -+ return BCME_ERROR; -+ } -+ /* set upper-layer auth */ -+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx); -+ if (err < 0) { -+ WL_ERR(("wpa_auth error %d\n", err)); -+ return BCME_ERROR; -+ } -+ -+ return 0; -+} -+ -+static s32 -+wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) -+{ -+ s32 len = 0; -+ s32 err = BCME_OK; -+ u16 auth = 0; /* d11 open authentication */ -+ u32 wsec; -+ u32 pval = 0; -+ u32 gval = 0; -+ u32 wpa_auth = 0; -+ wpa_suite_mcast_t *mcast; -+ wpa_suite_ucast_t *ucast; -+ wpa_suite_auth_key_mgmt_t *mgmt; -+ -+ u16 suite_count; -+ u8 rsn_cap[2]; -+ u32 wme_bss_disable; -+ -+ if (wpa2ie == NULL) -+ goto exit; -+ -+ WL_DBG(("Enter \n")); -+ len = wpa2ie->len; -+ /* check the mcast cipher */ -+ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; -+ switch (mcast->type) { -+ case WPA_CIPHER_NONE: -+ gval = 0; -+ break; -+ case WPA_CIPHER_WEP_40: -+ case WPA_CIPHER_WEP_104: -+ gval = WEP_ENABLED; -+ break; -+ case WPA_CIPHER_TKIP: -+ gval = TKIP_ENABLED; -+ break; -+ case WPA_CIPHER_AES_CCM: -+ gval = AES_ENABLED; -+ break; -+ default: -+ WL_ERR(("No Security Info\n")); -+ break; -+ } -+ if ((len -= WPA_SUITE_LEN) <= 0) -+ return BCME_BADLEN; -+ -+ /* check the unicast cipher */ -+ ucast = (wpa_suite_ucast_t *)&mcast[1]; -+ suite_count = ltoh16_ua(&ucast->count); -+ switch (ucast->list[0].type) { -+ case WPA_CIPHER_NONE: -+ pval = 0; -+ break; -+ case WPA_CIPHER_WEP_40: -+ case WPA_CIPHER_WEP_104: -+ pval = WEP_ENABLED; -+ break; -+ case WPA_CIPHER_TKIP: -+ pval = TKIP_ENABLED; -+ break; -+ case WPA_CIPHER_AES_CCM: -+ pval = AES_ENABLED; -+ break; -+ default: -+ WL_ERR(("No Security Info\n")); -+ } -+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) -+ return BCME_BADLEN; -+ -+ /* FOR WPS , set SEC_OW_ENABLED */ -+ wsec = (pval | gval | SES_OW_ENABLED); -+ /* check the AKM */ -+ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count]; -+ suite_count = ltoh16_ua(&mgmt->count); -+ switch (mgmt->list[0].type) { -+ case RSN_AKM_NONE: -+ wpa_auth = WPA_AUTH_NONE; -+ break; -+ case RSN_AKM_UNSPECIFIED: -+ wpa_auth = WPA2_AUTH_UNSPECIFIED; -+ break; -+ case RSN_AKM_PSK: -+ wpa_auth = WPA2_AUTH_PSK; -+ break; -+ default: -+ WL_ERR(("No Key Mgmt Info\n")); -+ } -+ -+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) { -+ rsn_cap[0] = *(u8 *)&mgmt->list[suite_count]; -+ rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1); -+ -+ if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) { -+ wme_bss_disable = 0; -+ } else { -+ wme_bss_disable = 1; -+ } -+ -+ /* set wme_bss_disable to sync RSN Capabilities */ -+ err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx); -+ if (err < 0) { -+ WL_ERR(("wme_bss_disable error %d\n", err)); -+ return BCME_ERROR; -+ } -+ } else { -+ WL_DBG(("There is no RSN Capabilities. remained len %d\n", len)); -+ } -+ -+ /* set auth */ -+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); -+ if (err < 0) { -+ WL_ERR(("auth error %d\n", err)); -+ return BCME_ERROR; -+ } -+ /* set wsec */ -+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); -+ if (err < 0) { -+ WL_ERR(("wsec error %d\n", err)); -+ return BCME_ERROR; -+ } -+ /* set upper-layer auth */ -+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); -+ if (err < 0) { -+ WL_ERR(("wpa_auth error %d\n", err)); -+ return BCME_ERROR; -+ } -+exit: -+ return 0; -+} -+ -+static s32 -+wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) -+{ -+ wpa_suite_mcast_t *mcast; -+ wpa_suite_ucast_t *ucast; -+ wpa_suite_auth_key_mgmt_t *mgmt; -+ u16 auth = 0; /* d11 open authentication */ -+ u16 count; -+ s32 err = BCME_OK; -+ s32 len = 0; -+ u32 i; -+ u32 wsec; -+ u32 pval = 0; -+ u32 gval = 0; -+ u32 wpa_auth = 0; -+ u32 tmp = 0; -+ -+ if (wpaie == NULL) -+ goto exit; -+ WL_DBG(("Enter \n")); -+ len = wpaie->length; /* value length */ -+ len -= WPA_IE_TAG_FIXED_LEN; -+ /* check for multicast cipher suite */ -+ if (len < WPA_SUITE_LEN) { -+ WL_INFO(("no multicast cipher suite\n")); -+ goto exit; -+ } -+ -+ /* pick up multicast cipher */ -+ mcast = (wpa_suite_mcast_t *)&wpaie[1]; -+ len -= WPA_SUITE_LEN; -+ if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { -+ if (IS_WPA_CIPHER(mcast->type)) { -+ tmp = 0; -+ switch (mcast->type) { -+ case WPA_CIPHER_NONE: -+ tmp = 0; -+ break; -+ case WPA_CIPHER_WEP_40: -+ case WPA_CIPHER_WEP_104: -+ tmp = WEP_ENABLED; -+ break; -+ case WPA_CIPHER_TKIP: -+ tmp = TKIP_ENABLED; -+ break; -+ case WPA_CIPHER_AES_CCM: -+ tmp = AES_ENABLED; -+ break; -+ default: -+ WL_ERR(("No Security Info\n")); -+ } -+ gval |= tmp; -+ } -+ } -+ /* Check for unicast suite(s) */ -+ if (len < WPA_IE_SUITE_COUNT_LEN) { -+ WL_INFO(("no unicast suite\n")); -+ goto exit; -+ } -+ /* walk thru unicast cipher list and pick up what we recognize */ -+ ucast = (wpa_suite_ucast_t *)&mcast[1]; -+ count = ltoh16_ua(&ucast->count); -+ len -= WPA_IE_SUITE_COUNT_LEN; -+ for (i = 0; i < count && len >= WPA_SUITE_LEN; -+ i++, len -= WPA_SUITE_LEN) { -+ if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { -+ if (IS_WPA_CIPHER(ucast->list[i].type)) { -+ tmp = 0; -+ switch (ucast->list[i].type) { -+ case WPA_CIPHER_NONE: -+ tmp = 0; -+ break; -+ case WPA_CIPHER_WEP_40: -+ case WPA_CIPHER_WEP_104: -+ tmp = WEP_ENABLED; -+ break; -+ case WPA_CIPHER_TKIP: -+ tmp = TKIP_ENABLED; -+ break; -+ case WPA_CIPHER_AES_CCM: -+ tmp = AES_ENABLED; -+ break; -+ default: -+ WL_ERR(("No Security Info\n")); -+ } -+ pval |= tmp; -+ } -+ } -+ } -+ len -= (count - i) * WPA_SUITE_LEN; -+ /* Check for auth key management suite(s) */ -+ if (len < WPA_IE_SUITE_COUNT_LEN) { -+ WL_INFO((" no auth key mgmt suite\n")); -+ goto exit; -+ } -+ /* walk thru auth management suite list and pick up what we recognize */ -+ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; -+ count = ltoh16_ua(&mgmt->count); -+ len -= WPA_IE_SUITE_COUNT_LEN; -+ for (i = 0; i < count && len >= WPA_SUITE_LEN; -+ i++, len -= WPA_SUITE_LEN) { -+ if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { -+ if (IS_WPA_AKM(mgmt->list[i].type)) { -+ tmp = 0; -+ switch (mgmt->list[i].type) { -+ case RSN_AKM_NONE: -+ tmp = WPA_AUTH_NONE; -+ break; -+ case RSN_AKM_UNSPECIFIED: -+ tmp = WPA_AUTH_UNSPECIFIED; -+ break; -+ case RSN_AKM_PSK: -+ tmp = WPA_AUTH_PSK; -+ break; -+ default: -+ WL_ERR(("No Key Mgmt Info\n")); -+ } -+ wpa_auth |= tmp; -+ } -+ } -+ -+ } -+ /* FOR WPS , set SEC_OW_ENABLED */ -+ wsec = (pval | gval | SES_OW_ENABLED); -+ /* set auth */ -+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); -+ if (err < 0) { -+ WL_ERR(("auth error %d\n", err)); -+ return BCME_ERROR; -+ } -+ /* set wsec */ -+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); -+ if (err < 0) { -+ WL_ERR(("wsec error %d\n", err)); -+ return BCME_ERROR; -+ } -+ /* set upper-layer auth */ -+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); -+ if (err < 0) { -+ WL_ERR(("wpa_auth error %d\n", err)); -+ return BCME_ERROR; -+ } -+exit: -+ return 0; -+} -+ -+static s32 -+wl_cfg80211_bcn_validate_sec( -+ struct net_device *dev, -+ struct parsed_ies *ies, -+ u32 dev_role, -+ s32 bssidx) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+ if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) { -+ /* For P2P GO, the sec type is WPA2-PSK */ -+ WL_DBG(("P2P GO: validating wpa2_ie")); -+ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) -+ return BCME_ERROR; -+ -+ } else if (dev_role == NL80211_IFTYPE_AP) { -+ -+ WL_DBG(("SoftAP: validating security")); -+ /* If wpa2_ie or wpa_ie is present validate it */ -+ if ((ies->wpa2_ie || ies->wpa_ie) && -+ ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || -+ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) { -+ wl->ap_info->security_mode = false; -+ return BCME_ERROR; -+ } -+ -+ wl->ap_info->security_mode = true; -+ if (wl->ap_info->rsn_ie) { -+ kfree(wl->ap_info->rsn_ie); -+ wl->ap_info->rsn_ie = NULL; -+ } -+ if (wl->ap_info->wpa_ie) { -+ kfree(wl->ap_info->wpa_ie); -+ wl->ap_info->wpa_ie = NULL; -+ } -+ if (wl->ap_info->wps_ie) { -+ kfree(wl->ap_info->wps_ie); -+ wl->ap_info->wps_ie = NULL; -+ } -+ if (ies->wpa_ie != NULL) { -+ /* WPAIE */ -+ wl->ap_info->rsn_ie = NULL; -+ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, -+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, -+ GFP_KERNEL); -+ } else if (ies->wpa2_ie != NULL) { -+ /* RSNIE */ -+ wl->ap_info->wpa_ie = NULL; -+ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, -+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, -+ GFP_KERNEL); -+ } -+ -+ if (!ies->wpa2_ie && !ies->wpa_ie) { -+ wl_validate_opensecurity(dev, bssidx); -+ wl->ap_info->security_mode = false; -+ } -+ -+ if (ies->wps_ie) { -+ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); -+ } -+ } -+ -+ return 0; -+ -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+static s32 wl_cfg80211_bcn_set_params( -+ struct cfg80211_ap_settings *info, -+ struct net_device *dev, -+ u32 dev_role, s32 bssidx) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ s32 err = BCME_OK; -+ -+ WL_DBG(("interval (%d) \ndtim_period (%d) \n", -+ info->beacon_interval, info->dtim_period)); -+ -+ if (info->beacon_interval) { -+ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, -+ &info->beacon_interval, sizeof(s32), true)) < 0) { -+ WL_ERR(("Beacon Interval Set Error, %d\n", err)); -+ return err; -+ } -+ } -+ -+ if (info->dtim_period) { -+ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, -+ &info->dtim_period, sizeof(s32), true)) < 0) { -+ WL_ERR(("DTIM Interval Set Error, %d\n", err)); -+ return err; -+ } -+ } -+ -+ if ((info->ssid) && (info->ssid_len > 0) && -+ (info->ssid_len <= 32)) { -+ WL_DBG(("SSID (%s) len:%d \n", info->ssid, info->ssid_len)); -+ if (dev_role == NL80211_IFTYPE_AP) { -+ /* Store the hostapd SSID */ -+ memset(wl->hostapd_ssid.SSID, 0x00, 32); -+ memcpy(wl->hostapd_ssid.SSID, info->ssid, info->ssid_len); -+ wl->hostapd_ssid.SSID_len = info->ssid_len; -+ } else { -+ /* P2P GO */ -+ memset(wl->p2p->ssid.SSID, 0x00, 32); -+ memcpy(wl->p2p->ssid.SSID, info->ssid, info->ssid_len); -+ wl->p2p->ssid.SSID_len = info->ssid_len; -+ } -+ } -+ -+ if (info->hidden_ssid) { -+ if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) -+ WL_ERR(("failed to set hidden : %d\n", err)); -+ WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid)); -+ } -+ -+ return err; -+} -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ -+ -+static s32 -+wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies) -+{ -+ s32 err = BCME_OK; -+ -+ memset(ies, 0, sizeof(struct parsed_ies)); -+ -+ /* find the WPSIE */ -+ if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) { -+ WL_DBG(("WPSIE in beacon \n")); -+ ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; -+ } else { -+ WL_ERR(("No WPSIE in beacon \n")); -+ } -+ -+ /* find the RSN_IE */ -+ if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, -+ DOT11_MNG_RSN_ID)) != NULL) { -+ WL_DBG((" WPA2 IE found\n")); -+ ies->wpa2_ie_len = ies->wpa2_ie->len; -+ } -+ -+ /* find the WPA_IE */ -+ if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) { -+ WL_DBG((" WPA found\n")); -+ ies->wpa_ie_len = ies->wpa_ie->length; -+ } -+ -+ return err; -+ -+} -+ -+static s32 -+wl_cfg80211_bcn_bringup_ap( -+ struct net_device *dev, -+ struct parsed_ies *ies, -+ u32 dev_role, s32 bssidx) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct wl_join_params join_params; -+ bool is_bssup = false; -+ s32 infra = 1; -+ s32 join_params_size = 0; -+ s32 ap = 1; -+ s32 err = BCME_OK; -+ -+ WL_DBG(("Enter dev_role: %d\n", dev_role)); -+ -+ /* Common code for SoftAP and P2P GO */ -+ wldev_iovar_setint(dev, "mpc", 0); -+ -+ if (dev_role == NL80211_IFTYPE_P2P_GO) { -+ is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); -+ if (!is_bssup && (ies->wpa2_ie != NULL)) { -+ -+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); -+ if (err < 0) { -+ WL_ERR(("SET INFRA error %d\n", err)); -+ goto exit; -+ } -+ -+ err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid, -+ sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN, -+ bssidx, &wl->ioctl_buf_sync); -+ if (err < 0) { -+ WL_ERR(("GO SSID setting error %d\n", err)); -+ goto exit; -+ } -+ -+ if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) { -+ WL_ERR(("GO Bring up error %d\n", err)); -+ goto exit; -+ } -+ } else -+ WL_DBG(("Bss is already up\n")); -+ } else if ((dev_role == NL80211_IFTYPE_AP) && -+ (wl_get_drv_status(wl, AP_CREATING, dev))) { -+ /* Device role SoftAP */ -+ err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true); -+ if (err < 0) { -+ WL_ERR(("WLC_DOWN error %d\n", err)); -+ goto exit; -+ } -+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); -+ if (err < 0) { -+ WL_ERR(("SET INFRA error %d\n", err)); -+ goto exit; -+ } -+ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { -+ WL_ERR(("setting AP mode failed %d \n", err)); -+ goto exit; -+ } -+ -+ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_UP error (%d)\n", err)); -+ goto exit; -+ } -+ -+ memset(&join_params, 0, sizeof(join_params)); -+ /* join parameters starts with ssid */ -+ join_params_size = sizeof(join_params.ssid); -+ memcpy(join_params.ssid.SSID, wl->hostapd_ssid.SSID, -+ wl->hostapd_ssid.SSID_len); -+ join_params.ssid.SSID_len = htod32(wl->hostapd_ssid.SSID_len); -+ -+ /* create softap */ -+ if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, -+ join_params_size, true)) == 0) { -+ WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID)); -+ wl_clr_drv_status(wl, AP_CREATING, dev); -+ wl_set_drv_status(wl, AP_CREATED, dev); -+ } -+ } -+ -+ -+exit: -+ return err; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+s32 -+wl_cfg80211_parse_ap_ies( -+ struct net_device *dev, -+ struct cfg80211_beacon_data *info, -+ struct parsed_ies *ies) -+{ -+ struct parsed_ies prb_ies; -+ s32 err = BCME_OK; -+ -+ /* Parse Beacon IEs */ -+ if (wl_cfg80211_parse_ies((u8 *)info->tail, -+ info->tail_len, ies) < 0) { -+ WL_ERR(("Beacon get IEs failed \n")); -+ err = -EINVAL; -+ goto fail; -+ } -+ -+ /* Parse Probe Response IEs */ -+ if (wl_cfg80211_parse_ies((u8 *)info->proberesp_ies, -+ info->proberesp_ies_len, &prb_ies) < 0) { -+ WL_ERR(("PROBE RESP get IEs failed \n")); -+ err = -EINVAL; -+ } -+ -+fail: -+ -+ return err; -+} -+ -+s32 -+wl_cfg80211_set_ies( -+ struct net_device *dev, -+ struct cfg80211_beacon_data *info, -+ s32 bssidx) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ s32 err = BCME_OK; -+ -+ /* Set Beacon IEs to FW */ -+ if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, -+ VNDR_IE_BEACON_FLAG, (u8 *)info->tail, -+ info->tail_len)) < 0) { -+ WL_ERR(("Set Beacon IE Failed \n")); -+ } else { -+ WL_DBG(("Applied Vndr IEs for Beacon \n")); -+ } -+ -+ /* Set Probe Response IEs to FW */ -+ if ((err = wl_cfgp2p_set_management_ie(wl, dev, bssidx, -+ VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies, -+ info->proberesp_ies_len)) < 0) { -+ WL_ERR(("Set Probe Resp IE Failed \n")); -+ } else { -+ WL_DBG(("Applied Vndr IEs for Probe Resp \n")); -+ } -+ -+ return err; -+} -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ -+ -+static s32 wl_cfg80211_hostapd_sec( -+ struct net_device *dev, -+ struct parsed_ies *ies, -+ s32 bssidx) -+{ -+ bool update_bss = 0; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+ -+ if (ies->wps_ie) { -+ if (wl->ap_info->wps_ie && -+ memcmp(wl->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) { -+ WL_DBG((" WPS IE is changed\n")); -+ kfree(wl->ap_info->wps_ie); -+ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); -+ } else if (wl->ap_info->wps_ie == NULL) { -+ WL_DBG((" WPS IE is added\n")); -+ wl->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL); -+ } -+ if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) { -+ if (!wl->ap_info->security_mode) { -+ /* change from open mode to security mode */ -+ update_bss = true; -+ if (ies->wpa_ie != NULL) { -+ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, -+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, -+ GFP_KERNEL); -+ } else { -+ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, -+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, -+ GFP_KERNEL); -+ } -+ } else if (wl->ap_info->wpa_ie) { -+ /* change from WPA2 mode to WPA mode */ -+ if (ies->wpa_ie != NULL) { -+ update_bss = true; -+ kfree(wl->ap_info->rsn_ie); -+ wl->ap_info->rsn_ie = NULL; -+ wl->ap_info->wpa_ie = kmemdup(ies->wpa_ie, -+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, -+ GFP_KERNEL); -+ } else if (memcmp(wl->ap_info->rsn_ie, -+ ies->wpa2_ie, ies->wpa2_ie->len -+ + WPA_RSN_IE_TAG_FIXED_LEN)) { -+ update_bss = true; -+ kfree(wl->ap_info->rsn_ie); -+ wl->ap_info->rsn_ie = kmemdup(ies->wpa2_ie, -+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, -+ GFP_KERNEL); -+ wl->ap_info->wpa_ie = NULL; -+ } -+ } -+ if (update_bss) { -+ wl->ap_info->security_mode = true; -+ wl_cfgp2p_bss(wl, dev, bssidx, 0); -+ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 || -+ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) { -+ return BCME_ERROR; -+ } -+ wl_cfgp2p_bss(wl, dev, bssidx, 1); -+ } -+ } -+ } else { -+ WL_ERR(("No WPSIE in beacon \n")); -+ } -+ return 0; -+} -+ -+static s32 -+wl_cfg80211_del_station( -+ struct wiphy *wiphy, -+ struct net_device *ndev, -+ u8* mac_addr) -+{ -+ struct net_device *dev; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ scb_val_t scb_val; -+ s8 eabuf[ETHER_ADDR_STR_LEN]; -+ char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * -+ sizeof(struct ether_addr) + sizeof(uint)] = {0}; -+ struct maclist *assoc_maclist = (struct maclist *)mac_buf; -+ int num_associated = 0, err; -+ -+ WL_DBG(("Entry\n")); -+ if (mac_addr == NULL) { -+ WL_DBG(("mac_addr is NULL ignore it\n")); -+ return 0; -+ } -+ -+ if (ndev == wl->p2p_net) { -+ dev = wl_to_prmry_ndev(wl); -+ } else { -+ dev = ndev; -+ } -+ -+ if (p2p_is_on(wl)) { -+ /* Suspend P2P discovery search-listen to prevent it from changing the -+ * channel. -+ */ -+ if ((wl_cfgp2p_discover_enable_search(wl, false)) < 0) { -+ WL_ERR(("Can not disable discovery mode\n")); -+ return -EFAULT; -+ } -+ } -+ -+ assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV; -+ err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST, -+ assoc_maclist, sizeof(mac_buf), false); -+ if (err < 0) -+ WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err)); -+ else -+ num_associated = assoc_maclist->count; -+ -+ memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN); -+ scb_val.val = DOT11_RC_DEAUTH_LEAVING; -+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, -+ sizeof(scb_val_t), true); -+ if (err < 0) -+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err)); -+ WL_DBG(("Disconnect STA : %s scb_val.val %d\n", -+ bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf), -+ scb_val.val)); -+ if (num_associated) -+ wl_delay(400); -+ return 0; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+static s32 -+wl_cfg80211_start_ap( -+ struct wiphy *wiphy, -+ struct net_device *dev, -+ struct cfg80211_ap_settings *info) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 err = BCME_OK; -+ struct parsed_ies ies; -+ s32 bssidx = 0; -+ u32 dev_role = 0; -+ -+ WL_DBG(("Enter \n")); -+ if (dev == wl_to_prmry_ndev(wl)) { -+ WL_DBG(("Start AP req on primary iface: Softap\n")); -+ dev_role = NL80211_IFTYPE_AP; -+ } else if (dev == wl->p2p_net) { -+ /* Group Add request on p2p0 */ -+ WL_DBG(("Start AP req on P2P iface: GO\n")); -+ dev = wl_to_prmry_ndev(wl); -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ } -+ -+ bssidx = wl_cfgp2p_find_idx(wl, dev); -+ if (p2p_is_on(wl) && -+ (bssidx == wl_to_p2p_bss_bssidx(wl, -+ P2PAPI_BSSCFG_CONNECTION))) { -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ WL_DBG(("Start AP req on P2P connection iface\n")); -+ } -+ -+ if ((err = wl_cfg80211_bcn_set_params(info, dev, -+ dev_role, bssidx)) < 0) { -+ WL_ERR(("Beacon params set failed \n")); -+ goto fail; -+ } -+ -+ /* Parse IEs */ -+ if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies) < 0)) { -+ WL_ERR(("Set IEs failed \n")); -+ goto fail; -+ } -+ -+ if ((wl_cfg80211_bcn_validate_sec(dev, &ies, -+ dev_role, bssidx)) < 0) -+ { -+ WL_ERR(("Beacon set security failed \n")); -+ goto fail; -+ } -+ -+ if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, -+ dev_role, bssidx)) < 0) { -+ WL_ERR(("Beacon bring up AP/GO failed \n")); -+ goto fail; -+ } -+ -+ WL_DBG(("** AP/GO Created **\n")); -+ -+ /* Set IEs to FW */ -+ if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx) < 0)) -+ WL_ERR(("Set IEs failed \n")); -+ -+fail: -+ if (err) { -+ WL_ERR(("ADD/SET beacon failed\n")); -+ wldev_iovar_setint(dev, "mpc", 1); -+ } -+ -+ return err; -+} -+ -+static s32 -+wl_cfg80211_stop_ap( -+ struct wiphy *wiphy, -+ struct net_device *dev) -+{ -+ int err = 0; -+ u32 dev_role = 0; -+ int infra = 0; -+ int ap = 0; -+ s32 bssidx = 0; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ -+ WL_DBG(("Enter \n")); -+ if (dev == wl_to_prmry_ndev(wl)) { -+ dev_role = NL80211_IFTYPE_AP; -+ } else if (dev == wl->p2p_net) { -+ /* Group Add request on p2p0 */ -+ dev = wl_to_prmry_ndev(wl); -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ } -+ bssidx = wl_cfgp2p_find_idx(wl, dev); -+ if (p2p_is_on(wl) && -+ (bssidx == wl_to_p2p_bss_bssidx(wl, -+ P2PAPI_BSSCFG_CONNECTION))) { -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ } -+ -+ if (dev_role == NL80211_IFTYPE_AP) { -+ /* SoftAp on primary Interface. -+ * Shut down AP and turn on MPC -+ */ -+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true); -+ if (err < 0) { -+ WL_ERR(("SET INFRA error %d\n", err)); -+ err = -ENOTSUPP; -+ goto exit; -+ } -+ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) { -+ WL_ERR(("setting AP mode failed %d \n", err)); -+ err = -ENOTSUPP; -+ goto exit; -+ } -+ -+ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_UP error (%d)\n", err)); -+ err = -EINVAL; -+ goto exit; -+ } -+ -+ wl_clr_drv_status(wl, AP_CREATED, dev); -+ /* Turn on the MPC */ -+ wldev_iovar_setint(dev, "mpc", 1); -+ } else { -+ WL_DBG(("Stopping P2P GO \n")); -+ } -+ -+exit: -+ return err; -+} -+ -+static s32 -+wl_cfg80211_change_beacon( -+ struct wiphy *wiphy, -+ struct net_device *dev, -+ struct cfg80211_beacon_data *info) -+{ -+ s32 err = BCME_OK; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct parsed_ies ies; -+ u32 dev_role = 0; -+ s32 bssidx = 0; -+ -+ WL_DBG(("Enter \n")); -+ -+ if (dev == wl_to_prmry_ndev(wl)) { -+ dev_role = NL80211_IFTYPE_AP; -+ } else if (dev == wl->p2p_net) { -+ /* Group Add request on p2p0 */ -+ dev = wl_to_prmry_ndev(wl); -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ } -+ -+ bssidx = wl_cfgp2p_find_idx(wl, dev); -+ if (p2p_is_on(wl) && -+ (bssidx == wl_to_p2p_bss_bssidx(wl, -+ P2PAPI_BSSCFG_CONNECTION))) { -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ } -+ -+ /* Parse IEs */ -+ if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies) < 0)) { -+ WL_ERR(("Parse IEs failed \n")); -+ goto fail; -+ } -+ -+ /* Set IEs to FW */ -+ if ((err = wl_cfg80211_set_ies(dev, info, bssidx) < 0)) { -+ WL_ERR(("Set IEs failed \n")); -+ goto fail; -+ } -+ -+ if (dev_role == NL80211_IFTYPE_AP) { -+ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { -+ WL_ERR(("Hostapd update sec failed \n")); -+ err = -EINVAL; -+ goto fail; -+ } -+ } -+ -+fail: -+ return err; -+} -+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ -+static s32 -+wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, -+ struct beacon_parameters *info) -+{ -+ s32 err = BCME_OK; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ s32 ie_offset = 0; -+ s32 bssidx = 0; -+ u32 dev_role = NL80211_IFTYPE_AP; -+ struct parsed_ies ies; -+ bcm_tlv_t *ssid_ie; -+ bool pbc = 0; -+ -+ WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", -+ info->interval, info->dtim_period, info->head_len, info->tail_len)); -+ -+ if (dev == wl_to_prmry_ndev(wl)) { -+ dev_role = NL80211_IFTYPE_AP; -+ } else if (dev == wl->p2p_net) { -+ /* Group Add request on p2p0 */ -+ dev = wl_to_prmry_ndev(wl); -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ } -+ -+ bssidx = wl_cfgp2p_find_idx(wl, dev); -+ if (p2p_is_on(wl) && -+ (bssidx == wl_to_p2p_bss_bssidx(wl, -+ P2PAPI_BSSCFG_CONNECTION))) { -+ dev_role = NL80211_IFTYPE_P2P_GO; -+ } -+ -+ ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; -+ /* find the SSID */ -+ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], -+ info->head_len - ie_offset, -+ DOT11_MNG_SSID_ID)) != NULL) { -+ if (dev_role == NL80211_IFTYPE_AP) { -+ /* Store the hostapd SSID */ -+ memset(&wl->hostapd_ssid.SSID[0], 0x00, 32); -+ memcpy(&wl->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len); -+ wl->hostapd_ssid.SSID_len = ssid_ie->len; -+ } else { -+ /* P2P GO */ -+ memset(&wl->p2p->ssid.SSID[0], 0x00, 32); -+ memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len); -+ wl->p2p->ssid.SSID_len = ssid_ie->len; -+ } -+ } -+ -+ if (wl_cfg80211_parse_ies((u8 *)info->tail, -+ info->tail_len, &ies) < 0) { -+ WL_ERR(("Beacon get IEs failed \n")); -+ err = -EINVAL; -+ goto fail; -+ } -+ -+ if (wl_cfgp2p_set_management_ie(wl, dev, bssidx, -+ VNDR_IE_BEACON_FLAG, (u8 *)info->tail, -+ info->tail_len) < 0) { -+ WL_ERR(("Beacon set IEs failed \n")); -+ goto fail; -+ } else { -+ WL_DBG(("Applied Vndr IEs for Beacon \n")); -+ } -+ if (!wl_cfgp2p_bss_isup(dev, bssidx) && -+ (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0)) -+ { -+ WL_ERR(("Beacon set security failed \n")); -+ goto fail; -+ } -+ -+ /* Set BI and DTIM period */ -+ if (info->interval) { -+ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD, -+ &info->interval, sizeof(s32), true)) < 0) { -+ WL_ERR(("Beacon Interval Set Error, %d\n", err)); -+ return err; -+ } -+ } -+ if (info->dtim_period) { -+ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD, -+ &info->dtim_period, sizeof(s32), true)) < 0) { -+ WL_ERR(("DTIM Interval Set Error, %d\n", err)); -+ return err; -+ } -+ } -+ -+ if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) { -+ WL_ERR(("Beacon bring up AP/GO failed \n")); -+ goto fail; -+ } -+ -+ if (wl_get_drv_status(wl, AP_CREATED, dev)) { -+ /* Soft AP already running. Update changed params */ -+ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) { -+ WL_ERR(("Hostapd update sec failed \n")); -+ err = -EINVAL; -+ goto fail; -+ } -+ } -+ -+ /* Enable Probe Req filter */ -+ if (((dev_role == NL80211_IFTYPE_P2P_GO) || -+ (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) { -+ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc); -+ if (pbc) -+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); -+ } -+ -+ WL_DBG(("** ADD/SET beacon done **\n")); -+ -+fail: -+ if (err) { -+ WL_ERR(("ADD/SET beacon failed\n")); -+ wldev_iovar_setint(dev, "mpc", 1); -+ } -+ return err; -+ -+} -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ -+ -+#ifdef WL_SCHED_SCAN -+#define PNO_TIME 30 -+#define PNO_REPEAT 4 -+#define PNO_FREQ_EXPO_MAX 2 -+int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, -+ struct net_device *dev, -+ struct cfg80211_sched_scan_request *request) -+{ -+ ushort pno_time = PNO_TIME; -+ int pno_repeat = PNO_REPEAT; -+ int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; -+ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ struct cfg80211_ssid *ssid = NULL; -+ int ssid_count = 0; -+ int i; -+ int ret = 0; -+ -+ WL_DBG(("Enter \n")); -+ WL_PNO((">>> SCHED SCAN START\n")); -+ WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n", -+ request->n_match_sets, request->n_ssids)); -+ WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", -+ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max)); -+ -+ -+ if (!request || !request->n_ssids || !request->n_match_sets) { -+ WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); -+ return -EINVAL; -+ } -+ -+ memset(&ssids_local, 0, sizeof(ssids_local)); -+ -+ if (request->n_match_sets > 0) { -+ for (i = 0; i < request->n_match_sets; i++) { -+ ssid = &request->match_sets[i].ssid; -+ memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len); -+ ssids_local[i].SSID_len = ssid->ssid_len; -+ WL_PNO((">>> PNO filter set for ssid (%s) \n", ssid->ssid)); -+ ssid_count++; -+ } -+ } -+ -+ if (request->n_ssids > 0) { -+ for (i = 0; i < request->n_ssids; i++) { -+ /* Active scan req for ssids */ -+ WL_PNO((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid)); -+ -+ /* match_set ssids is a supert set of n_ssid list, so we need -+ * not add these set seperately -+ */ -+ } -+ } -+ -+ if (ssid_count) { -+ if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets, -+ pno_time, pno_repeat, pno_freq_expo_max)) < 0) { -+ WL_ERR(("PNO setup failed!! ret=%d \n", ret)); -+ return -EINVAL; -+ } -+ -+ /* Enable the PNO */ -+ if (dhd_dev_pno_enable(dev, 1) < 0) { -+ WL_ERR(("PNO enable failed!! ret=%d \n", ret)); -+ return -EINVAL; -+ } -+ wl->sched_scan_req = request; -+ } else { -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) -+{ -+ struct wl_priv *wl = wiphy_priv(wiphy); -+ -+ WL_DBG(("Enter \n")); -+ WL_PNO((">>> SCHED SCAN STOP\n")); -+ -+ if (dhd_dev_pno_enable(dev, 0) < 0) -+ WL_ERR(("PNO disable failed")); -+ -+ if (dhd_dev_pno_reset(dev) < 0) -+ WL_ERR(("PNO reset failed")); -+ -+ if (wl->scan_request && wl->sched_scan_running) { -+ WL_PNO((">>> Sched scan running. Aborting it..\n")); -+ wl_notify_escan_complete(wl, dev, true, true); -+ } -+ -+ wl->sched_scan_req = NULL; -+ wl->sched_scan_running = FALSE; -+ -+ return 0; -+} -+#endif /* WL_SCHED_SCAN */ -+ -+static struct cfg80211_ops wl_cfg80211_ops = { -+ .add_virtual_intf = wl_cfg80211_add_virtual_iface, -+ .del_virtual_intf = wl_cfg80211_del_virtual_iface, -+ .change_virtual_intf = wl_cfg80211_change_virtual_iface, -+ .scan = wl_cfg80211_scan, -+ .set_wiphy_params = wl_cfg80211_set_wiphy_params, -+ .join_ibss = wl_cfg80211_join_ibss, -+ .leave_ibss = wl_cfg80211_leave_ibss, -+ .get_station = wl_cfg80211_get_station, -+ .set_tx_power = wl_cfg80211_set_tx_power, -+ .get_tx_power = wl_cfg80211_get_tx_power, -+ .add_key = wl_cfg80211_add_key, -+ .del_key = wl_cfg80211_del_key, -+ .get_key = wl_cfg80211_get_key, -+ .set_default_key = wl_cfg80211_config_default_key, -+ .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key, -+ .set_power_mgmt = wl_cfg80211_set_power_mgmt, -+ .connect = wl_cfg80211_connect, -+ .disconnect = wl_cfg80211_disconnect, -+ .suspend = wl_cfg80211_suspend, -+ .resume = wl_cfg80211_resume, -+ .set_pmksa = wl_cfg80211_set_pmksa, -+ .del_pmksa = wl_cfg80211_del_pmksa, -+ .flush_pmksa = wl_cfg80211_flush_pmksa, -+ .remain_on_channel = wl_cfg80211_remain_on_channel, -+ .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel, -+ .mgmt_tx = wl_cfg80211_mgmt_tx, -+ .mgmt_frame_register = wl_cfg80211_mgmt_frame_register, -+ .change_bss = wl_cfg80211_change_bss, -+ .set_channel = wl_cfg80211_set_channel, -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) -+ .set_beacon = wl_cfg80211_add_set_beacon, -+ .add_beacon = wl_cfg80211_add_set_beacon, -+#else -+ .change_beacon = wl_cfg80211_change_beacon, -+ .start_ap = wl_cfg80211_start_ap, -+ .stop_ap = wl_cfg80211_stop_ap, -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) */ -+#ifdef WL_SCHED_SCAN -+ .sched_scan_start = wl_cfg80211_sched_scan_start, -+ .sched_scan_stop = wl_cfg80211_sched_scan_stop, -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ -+ .del_station = wl_cfg80211_del_station, -+ .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait, -+}; -+ -+s32 wl_mode_to_nl80211_iftype(s32 mode) -+{ -+ s32 err = 0; -+ -+ switch (mode) { -+ case WL_MODE_BSS: -+ return NL80211_IFTYPE_STATION; -+ case WL_MODE_IBSS: -+ return NL80211_IFTYPE_ADHOC; -+ case WL_MODE_AP: -+ return NL80211_IFTYPE_AP; -+ default: -+ return NL80211_IFTYPE_UNSPECIFIED; -+ } -+ -+ return err; -+} -+ -+/* Kernel Network Support->Wireless->Regulatory rules database -+ options should be enabled and regulatory CRDA regdb table populated in Kernel -+ for proper country reg notification -+*/ -+#ifdef CONFIG_CFG80211_INTERNAL_REGDB -+static int -+wl_cfg80211_reg_notifier( -+ struct wiphy *wiphy, -+ struct regulatory_request *request) -+{ -+ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy); -+ int ret = 0; -+ -+ if (!request || !wl) { -+ WL_ERR(("Invalid arg\n")); -+ return -EINVAL; -+ } -+ -+ WL_DBG(("ccode: %c%c Initiator: %d\n", -+ request->alpha2[0], request->alpha2[1], request->initiator)); -+ -+ /* We support only REGDOM_SET_BY_USER and by -+ NL80211_REGDOM_SET_BY_COUNTRY_IE (11d) right now -+ */ -+ if ((request->initiator != NL80211_REGDOM_SET_BY_USER) && -+ (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) { -+ WL_ERR(("reg_notifier for intiator:%d not supported : set default\n", -+ request->initiator)); -+ /* in case of no supported country by regdb -+ lets driver setup platform default Locale -+ */ -+ } -+ -+ WL_ERR(("Set country code %c%c from %s\n", -+ request->alpha2[0], request->alpha2[1], -+ ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User"))); -+ -+ if ((ret = wldev_set_country(wl_to_prmry_ndev(wl), request->alpha2, -+ false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false))) < 0) { -+ WL_ERR(("set country Failed :%d\n", ret)); -+ } -+ -+ return ret; -+} -+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ -+ -+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev) -+{ -+ s32 err = 0; -+ wdev->wiphy = -+ wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv)); -+ if (unlikely(!wdev->wiphy)) { -+ WL_ERR(("Couldn not allocate wiphy device\n")); -+ err = -ENOMEM; -+ return err; -+ } -+ set_wiphy_dev(wdev->wiphy, sdiofunc_dev); -+ wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; -+ /* Report how many SSIDs Driver can support per Scan request */ -+ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; -+ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; -+#ifdef WL_SCHED_SCAN -+ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; -+ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; -+ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; -+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; -+#endif /* WL_SCHED_SCAN */ -+ wdev->wiphy->interface_modes = -+ BIT(NL80211_IFTYPE_STATION) -+#if !(defined(WLP2P) && defined(WL_ENABLE_P2P_IF)) -+ | BIT(NL80211_IFTYPE_MONITOR) -+#endif -+ | BIT(NL80211_IFTYPE_AP); -+ -+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; -+ -+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; -+ wdev->wiphy->cipher_suites = __wl_cipher_suites; -+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); -+ wdev->wiphy->max_remain_on_channel_duration = 5000; -+ wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; -+#ifndef WL_POWERSAVE_DISABLED -+ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; -+#else -+ wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; -+#endif /* !WL_POWERSAVE_DISABLED */ -+ wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | -+ WIPHY_FLAG_4ADDR_AP | -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39) -+ WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | -+#endif -+ WIPHY_FLAG_4ADDR_STATION; -+ /* If driver advertises FW_ROAM, the supplicant wouldn't -+ * send the BSSID & Freq in the connect command allowing the -+ * the driver to choose the AP to connect to. But unless we -+ * support ROAM_CACHE in firware this will delay the ASSOC as -+ * as the FW need to do a full scan before attempting to connect -+ * So that feature will just increase assoc. The better approach -+ * to let Supplicant to provide channel info and FW letter may roam -+ * if needed so DON'T advertise that featur eto Supplicant. -+ */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) -+ /* wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; */ -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) -+ wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | -+ WIPHY_FLAG_OFFCHAN_TX; -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+ /* From 3.4 kernel ownards AP_SME flag can be advertised -+ * to remove the patch from supplicant -+ */ -+ wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; -+#endif -+ -+#ifdef CONFIG_CFG80211_INTERNAL_REGDB -+ wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier; -+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ -+ -+ WL_DBG(("Registering custom regulatory)\n")); -+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; -+ wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); -+ /* Now we can register wiphy with cfg80211 module */ -+ err = wiphy_register(wdev->wiphy); -+ if (unlikely(err < 0)) { -+ WL_ERR(("Couldn not register wiphy device (%d)\n", err)); -+ wiphy_free(wdev->wiphy); -+ } -+ return err; -+} -+ -+static void wl_free_wdev(struct wl_priv *wl) -+{ -+ struct wireless_dev *wdev = wl->wdev; -+ struct wiphy *wiphy; -+ if (!wdev) { -+ WL_ERR(("wdev is invalid\n")); -+ return; -+ } -+ wiphy = wdev->wiphy; -+ wiphy_unregister(wdev->wiphy); -+ wdev->wiphy->dev.parent = NULL; -+ -+ wl_delete_all_netinfo(wl); -+ wiphy_free(wiphy); -+ /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl", -+ * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! -+ */ -+} -+ -+static s32 wl_inform_bss(struct wl_priv *wl) -+{ -+ struct wl_scan_results *bss_list; -+ struct wl_bss_info *bi = NULL; /* must be initialized */ -+ s32 err = 0; -+ s32 i; -+ -+ bss_list = wl->bss_list; -+ WL_DBG(("scanned AP count (%d)\n", bss_list->count)); -+ bi = next_bss(bss_list, bi); -+ for_each_bss(bss_list, bi, i) { -+ err = wl_inform_single_bss(wl, bi, 0); -+ if (unlikely(err)) -+ break; -+ } -+ return err; -+} -+ -+static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi, u8 is_roam_done) -+{ -+ struct wiphy *wiphy = wl_to_wiphy(wl); -+ struct ieee80211_mgmt *mgmt; -+ struct ieee80211_channel *channel; -+ struct ieee80211_supported_band *band; -+ struct wl_cfg80211_bss_info *notif_bss_info; -+ struct wl_scan_req *sr = wl_to_sr(wl); -+ struct beacon_proberesp *beacon_proberesp; -+ struct cfg80211_bss *cbss = NULL; -+ s32 mgmt_type; -+ s32 signal; -+ u32 freq; -+ s32 err = 0; -+ gfp_t aflags; -+ u8 *ie_offset = NULL; -+ -+ if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) { -+ WL_DBG(("Beacon is larger than buffer. Discarding\n")); -+ return err; -+ } -+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; -+ notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) -+ - sizeof(u8) + WL_BSS_INFO_MAX, aflags); -+ if (unlikely(!notif_bss_info)) { -+ WL_ERR(("notif_bss_info alloc failed\n")); -+ return -ENOMEM; -+ } -+ mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf; -+ notif_bss_info->channel = -+ bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); -+ -+ if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) -+ band = wiphy->bands[IEEE80211_BAND_2GHZ]; -+ else -+ band = wiphy->bands[IEEE80211_BAND_5GHZ]; -+ if (!band) { -+ WL_ERR(("No valid band")); -+ kfree(notif_bss_info); -+ return -EINVAL; -+ } -+ notif_bss_info->rssi = dtoh16(bi->RSSI) + RSSI_OFFSET; -+ memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN); -+ mgmt_type = wl->active_scan ? -+ IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON; -+ if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) { -+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type); -+ } -+ beacon_proberesp = wl->active_scan ? -+ (struct beacon_proberesp *)&mgmt->u.probe_resp : -+ (struct beacon_proberesp *)&mgmt->u.beacon; -+ beacon_proberesp->timestamp = 0; -+ beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); -+ beacon_proberesp->capab_info = cpu_to_le16(bi->capability); -+ wl_rst_ie(wl); -+ -+ ie_offset = ((u8 *) bi) + bi->ie_offset; -+ -+ if (is_roam_done && ((int)(*(ie_offset)) == WLAN_EID_SSID && -+ ((int)(*(ie_offset+1)) == 0 || (int)(*(ie_offset+2)) == 0))) { -+ u8 *ie_new_offset = NULL; -+ uint8 ie_new_length; -+ -+ WL_ERR(("WAR trace: Changing the SSID Info, from beacon %d\n", -+ bi->flags & WL_BSS_FLAGS_FROM_BEACON)); -+ -+ ie_new_offset = (u8 *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); -+ if (ie_new_offset) { -+ *(ie_new_offset) = WLAN_EID_SSID; -+ *(ie_new_offset+1) = bi->SSID_len; -+ memcpy(ie_new_offset+2, bi->SSID, bi->SSID_len); -+ ie_new_length = bi->ie_length - *(ie_offset+1) + bi->SSID_len; -+ -+ /* Copy the remaining IE apart from SSID IE from bi */ -+ memcpy(ie_new_offset+2 + bi->SSID_len, -+ ie_offset+2 + *(ie_offset+1), -+ bi->ie_length - 2 - *(ie_offset+1)); -+ wl_mrg_ie(wl, ie_new_offset, ie_new_length); -+ kfree(ie_new_offset); -+ } else { -+ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); -+ } -+ } else { -+ wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); -+ } -+ -+ wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - -+ offsetof(struct wl_cfg80211_bss_info, frame_buf)); -+ notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, -+ u.beacon.variable) + wl_get_ielen(wl); -+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) -+ freq = ieee80211_channel_to_frequency(notif_bss_info->channel); -+ (void)band->band; -+#else -+ freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); -+#endif -+ if (freq == 0) { -+ WL_ERR(("Invalid channel, fail to chcnage channel to freq\n")); -+ kfree(notif_bss_info); -+ return -EINVAL; -+ } -+ channel = ieee80211_get_channel(wiphy, freq); -+ if (unlikely(!channel)) { -+ WL_ERR(("ieee80211_get_channel error\n")); -+ kfree(notif_bss_info); -+ return -EINVAL; -+ } -+ WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM" -+ "mgmt_type %d frame_len %d\n", bi->SSID, -+ notif_bss_info->rssi, notif_bss_info->channel, -+ mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type, -+ notif_bss_info->frame_len)); -+ -+ signal = notif_bss_info->rssi * 100; -+ if (!mgmt->u.probe_resp.timestamp) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) -+ struct timespec ts; -+ get_monotonic_boottime(&ts); -+ mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000) -+ + ts.tv_nsec / 1000; -+#else -+ struct timeval tv; -+ do_gettimeofday(&tv); -+ mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000) -+ + tv.tv_usec; -+#endif -+ } -+ -+ cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, -+ le16_to_cpu(notif_bss_info->frame_len), signal, aflags); -+ if (unlikely(!cbss)) { -+ WL_ERR(("cfg80211_inform_bss_frame error\n")); -+ kfree(notif_bss_info); -+ return -EINVAL; -+ } -+ -+ cfg80211_put_bss(cbss); -+ kfree(notif_bss_info); -+ return err; -+} -+ -+static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev) -+{ -+ u32 event = ntoh32(e->event_type); -+ u32 status = ntoh32(e->status); -+ u16 flags = ntoh16(e->flags); -+ -+ WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); -+ if (event == WLC_E_SET_SSID) { -+ if (status == WLC_E_STATUS_SUCCESS) { -+ if (!wl_is_ibssmode(wl, ndev)) -+ return true; -+ } -+ } else if (event == WLC_E_LINK) { -+ if (flags & WLC_EVENT_MSG_LINK) -+ return true; -+ } -+ -+ WL_DBG(("wl_is_linkup false\n")); -+ return false; -+} -+ -+static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e) -+{ -+ u32 event = ntoh32(e->event_type); -+ u16 flags = ntoh16(e->flags); -+ -+ if (event == WLC_E_DEAUTH_IND || -+ event == WLC_E_DISASSOC_IND || -+ event == WLC_E_DISASSOC || -+ event == WLC_E_DEAUTH) { -+#if (WL_DBG_LEVEL > 0) -+ WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); -+#endif /* (WL_DBG_LEVEL > 0) */ -+ return true; -+ } else if (event == WLC_E_LINK) { -+ if (!(flags & WLC_EVENT_MSG_LINK)) { -+#if (WL_DBG_LEVEL > 0) -+ WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event])); -+#endif /* (WL_DBG_LEVEL > 0) */ -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) -+{ -+ u32 event = ntoh32(e->event_type); -+ u32 status = ntoh32(e->status); -+ -+ if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) -+ return true; -+ if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) -+ return true; -+ -+ return false; -+} -+ -+/* The mainline kernel >= 3.2.0 has support for indicating new/del station -+ * to AP/P2P GO via events. If this change is backported to kernel for which -+ * this driver is being built, then define WL_CFG80211_STA_EVENT. You -+ * should use this new/del sta event mechanism for BRCM supplicant >= 22. -+ */ -+static s32 -+wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ s32 err = 0; -+ u32 event = ntoh32(e->event_type); -+ u32 reason = ntoh32(e->reason); -+ u32 len = ntoh32(e->datalen); -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) -+ bool isfree = false; -+ u8 *mgmt_frame; -+ u8 bsscfgidx = e->bsscfgidx; -+ s32 freq; -+ s32 channel; -+ u8 *body = NULL; -+ u16 fc = 0; -+ -+ struct ieee80211_supported_band *band; -+ struct ether_addr da; -+ struct ether_addr bssid; -+ struct wiphy *wiphy = wl_to_wiphy(wl); -+ channel_info_t ci; -+#else -+ struct station_info sinfo; -+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !WL_CFG80211_STA_EVENT */ -+ -+ WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason)); -+ /* if link down, bsscfg is disabled. */ -+ if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS && -+ wl_get_p2p_status(wl, IF_DELETING) && (ndev != wl_to_prmry_ndev(wl))) { -+ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false); -+ WL_INFO(("AP mode link down !! \n")); -+ complete(&wl->iface_disable); -+ return 0; -+ } -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) -+ WL_DBG(("Enter \n")); -+ if (!len && (event == WLC_E_DEAUTH)) { -+ len = 2; /* reason code field */ -+ data = &reason; -+ } -+ if (len) { -+ body = kzalloc(len, GFP_KERNEL); -+ -+ if (body == NULL) { -+ WL_ERR(("wl_notify_connect_status: Failed to allocate body\n")); -+ return WL_INVALID; -+ } -+ } -+ memset(&bssid, 0, ETHER_ADDR_LEN); -+ WL_DBG(("Enter event %d ndev %p\n", event, ndev)); -+ if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) { -+ kfree(body); -+ return WL_INVALID; -+ } -+ if (len) -+ memcpy(body, data, len); -+ -+ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", -+ NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); -+ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); -+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); -+ switch (event) { -+ case WLC_E_ASSOC_IND: -+ fc = FC_ASSOC_REQ; -+ break; -+ case WLC_E_REASSOC_IND: -+ fc = FC_REASSOC_REQ; -+ break; -+ case WLC_E_DISASSOC_IND: -+ fc = FC_DISASSOC; -+ break; -+ case WLC_E_DEAUTH_IND: -+ fc = FC_DISASSOC; -+ break; -+ case WLC_E_DEAUTH: -+ fc = FC_DISASSOC; -+ break; -+ default: -+ fc = 0; -+ goto exit; -+ } -+ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) { -+ kfree(body); -+ return err; -+ } -+ -+ channel = dtoh32(ci.hw_channel); -+ if (channel <= CH_MAX_2G_CHANNEL) -+ band = wiphy->bands[IEEE80211_BAND_2GHZ]; -+ else -+ band = wiphy->bands[IEEE80211_BAND_5GHZ]; -+ if (!band) { -+ WL_ERR(("No valid band")); -+ if (body) -+ kfree(body); -+ return -EINVAL; -+ } -+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) -+ freq = ieee80211_channel_to_frequency(channel); -+ (void)band->band; -+#else -+ freq = ieee80211_channel_to_frequency(channel, band->band); -+#endif -+ -+ err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, -+ &mgmt_frame, &len, body); -+ if (err < 0) -+ goto exit; -+ isfree = true; -+ -+ if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -+#else -+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ -+ } else if (event == WLC_E_DISASSOC_IND) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -+#else -+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ -+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC); -+#else -+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ -+ } -+ -+exit: -+ if (isfree) -+ kfree(mgmt_frame); -+ if (body) -+ kfree(body); -+ return err; -+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ -+ sinfo.filled = 0; -+ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && -+ reason == DOT11_SC_SUCCESS) { -+ sinfo.filled = STATION_INFO_ASSOC_REQ_IES; -+ if (!data) { -+ WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); -+ return -EINVAL; -+ } -+ sinfo.assoc_req_ies = data; -+ sinfo.assoc_req_ies_len = len; -+ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); -+ } else if (event == WLC_E_DISASSOC_IND) { -+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); -+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { -+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); -+ } -+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !WL_CFG80211_STA_EVENT */ -+ return err; -+} -+ -+static s32 -+wl_get_auth_assoc_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e) -+{ -+ u32 reason = ntoh32(e->reason); -+ u32 event = ntoh32(e->event_type); -+ struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); -+ WL_DBG(("event type : %d, reason : %d\n", event, reason)); -+ if (sec) { -+ switch (event) { -+ case WLC_E_ASSOC: -+ case WLC_E_AUTH: -+ sec->auth_assoc_res_status = reason; -+ default: -+ break; -+ } -+ } else -+ WL_ERR(("sec is NULL\n")); -+ return 0; -+} -+ -+static s32 -+wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ bool act; -+ s32 err = 0; -+ u32 event = ntoh32(e->event_type); -+ -+ if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { -+ wl_notify_connect_status_ap(wl, ndev, e, data); -+ } else { -+ WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", -+ ntoh32(e->event_type), ntoh32(e->status), ndev)); -+ if (event == WLC_E_ASSOC || event == WLC_E_AUTH) { -+ wl_get_auth_assoc_status(wl, ndev, e); -+ return err; -+ } -+ if (wl_is_linkup(wl, e, ndev)) { -+ wl_link_up(wl); -+ act = true; -+ if (wl_is_ibssmode(wl, ndev)) { -+ printk("cfg80211_ibss_joined\n"); -+ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, -+ GFP_KERNEL); -+ WL_DBG(("joined in IBSS network\n")); -+ } else { -+ if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) { -+ printk("wl_bss_connect_done succeeded with " MACDBG "\n", -+ MAC2STRDBG((u8*)(&e->addr))); -+ wl_bss_connect_done(wl, ndev, e, data, true); -+ WL_DBG(("joined in BSS network \"%s\"\n", -+ ((struct wlc_ssid *) -+ wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID)); -+ } -+ } -+ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); -+ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); -+ -+ } else if (wl_is_linkdown(wl, e)) { -+ if (wl->scan_request) { -+ if (wl->escan_on) { -+ wl_notify_escan_complete(wl, ndev, true, true); -+ } else { -+ del_timer_sync(&wl->scan_timeout); -+ wl_iscan_aborted(wl); -+ } -+ } -+ if (wl_get_drv_status(wl, CONNECTED, ndev)) { -+ scb_val_t scbval; -+ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); -+ s32 reason = 0; -+ if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) -+ reason = ntoh32(e->reason); -+ /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */ -+ reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason; -+ -+ printk("link down if %s may call cfg80211_disconnected. " -+ "event : %d, reason=%d from " MACDBG "\n", -+ ndev->name, event, ntoh32(e->reason), -+ MAC2STRDBG((u8*)(&e->addr))); -+ if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) { -+ WL_ERR(("BSSID of event is not the connected BSSID" -+ "(ignore it) cur: " MACDBG " event: " MACDBG"\n", -+ MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr)))); -+ return 0; -+ } -+ wl_clr_drv_status(wl, CONNECTED, ndev); -+ if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { -+ /* To make sure disconnect, explictly send dissassoc -+ * for BSSID 00:00:00:00:00:00 issue -+ */ -+ scbval.val = WLAN_REASON_DEAUTH_LEAVING; -+ -+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); -+ scbval.val = htod32(scbval.val); -+ err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval, -+ sizeof(scb_val_t), true); -+ if (err < 0) { -+ WL_ERR(("WLC_DISASSOC error %d\n", err)); -+ err = 0; -+ } -+ cfg80211_disconnected(ndev, reason, NULL, 0, GFP_KERNEL); -+ wl_link_down(wl); -+ wl_init_prof(wl, ndev); -+ } -+ } -+ else if (wl_get_drv_status(wl, CONNECTING, ndev)) { -+ printk("link down, during connecting\n"); -+#ifdef ESCAN_RESULT_PATCH -+ if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) || -+ (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) || -+ (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0)) -+ /* In case this event comes while associating another AP */ -+#endif /* ESCAN_RESULT_PATCH */ -+ wl_bss_connect_done(wl, ndev, e, data, false); -+ } -+ wl_clr_drv_status(wl, DISCONNECTING, ndev); -+ -+ /* if link down, bsscfg is diabled */ -+ if (ndev != wl_to_prmry_ndev(wl)) -+ complete(&wl->iface_disable); -+ -+ } else if (wl_is_nonetwork(wl, e)) { -+ printk("connect failed event=%d e->status %d e->reason %d \n", -+ event, (int)ntoh32(e->status), (int)ntoh32(e->reason)); -+ /* Clean up any pending scan request */ -+ if (wl->scan_request) { -+ if (wl->escan_on) { -+ wl_notify_escan_complete(wl, ndev, true, true); -+ } else { -+ del_timer_sync(&wl->scan_timeout); -+ wl_iscan_aborted(wl); -+ } -+ } -+ if (wl_get_drv_status(wl, CONNECTING, ndev)) -+ wl_bss_connect_done(wl, ndev, e, data, false); -+ } else { -+ printk("%s nothing\n", __FUNCTION__); -+ } -+ } -+ return err; -+} -+ -+static s32 -+wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ bool act; -+ s32 err = 0; -+ u32 event = be32_to_cpu(e->event_type); -+ u32 status = be32_to_cpu(e->status); -+ WL_DBG(("Enter \n")); -+ if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) { -+ if (wl_get_drv_status(wl, CONNECTED, ndev)) -+ wl_bss_roaming_done(wl, ndev, e, data); -+ else -+ wl_bss_connect_done(wl, ndev, e, data, true); -+ act = true; -+ wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); -+ wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); -+ } -+ return err; -+} -+ -+static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) -+{ -+ wl_assoc_info_t assoc_info; -+ struct wl_connect_info *conn_info = wl_to_conn(wl); -+ s32 err = 0; -+ -+ WL_DBG(("Enter \n")); -+ err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf, -+ WL_ASSOC_INFO_MAX, NULL); -+ if (unlikely(err)) { -+ WL_ERR(("could not get assoc info (%d)\n", err)); -+ return err; -+ } -+ memcpy(&assoc_info, wl->extra_buf, sizeof(wl_assoc_info_t)); -+ assoc_info.req_len = htod32(assoc_info.req_len); -+ assoc_info.resp_len = htod32(assoc_info.resp_len); -+ assoc_info.flags = htod32(assoc_info.flags); -+ if (conn_info->req_ie_len) { -+ conn_info->req_ie_len = 0; -+ bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); -+ } -+ if (conn_info->resp_ie_len) { -+ conn_info->resp_ie_len = 0; -+ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); -+ } -+ if (assoc_info.req_len) { -+ err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf, -+ WL_ASSOC_INFO_MAX, NULL); -+ if (unlikely(err)) { -+ WL_ERR(("could not get assoc req (%d)\n", err)); -+ return err; -+ } -+ conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); -+ if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { -+ conn_info->req_ie_len -= ETHER_ADDR_LEN; -+ } -+ if (conn_info->req_ie_len <= MAX_REQ_LINE) -+ memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len); -+ else { -+ WL_ERR(("%s IE size %d above max %d size \n", -+ __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE)); -+ return err; -+ } -+ } else { -+ conn_info->req_ie_len = 0; -+ } -+ if (assoc_info.resp_len) { -+ err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf, -+ WL_ASSOC_INFO_MAX, NULL); -+ if (unlikely(err)) { -+ WL_ERR(("could not get assoc resp (%d)\n", err)); -+ return err; -+ } -+ conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); -+ if (conn_info->resp_ie_len <= MAX_REQ_LINE) -+ memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len); -+ else { -+ WL_ERR(("%s IE size %d above max %d size \n", -+ __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE)); -+ return err; -+ } -+ } else { -+ conn_info->resp_ie_len = 0; -+ } -+ WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, -+ conn_info->resp_ie_len)); -+ -+ return err; -+} -+ -+static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, -+ size_t *join_params_size) -+{ -+ chanspec_t chanspec = 0; -+ if (ch != 0) { -+ join_params->params.chanspec_num = 1; -+ join_params->params.chanspec_list[0] = ch; -+ -+ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) -+ chanspec |= WL_CHANSPEC_BAND_2G; -+ else -+ chanspec |= WL_CHANSPEC_BAND_5G; -+ -+ chanspec |= WL_CHANSPEC_BW_20; -+ chanspec |= WL_CHANSPEC_CTL_SB_NONE; -+ -+ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE + -+ join_params->params.chanspec_num * sizeof(chanspec_t); -+ -+ join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; -+ join_params->params.chanspec_list[0] |= chanspec; -+ join_params->params.chanspec_list[0] = -+ wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); -+ -+ join_params->params.chanspec_num = -+ htod32(join_params->params.chanspec_num); -+ WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n", -+ join_params->params.chanspec_list[0], -+ join_params->params.chanspec_num)); -+ } -+} -+ -+static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev, u8 is_roam_done) -+{ -+ struct cfg80211_bss *bss; -+ struct wl_bss_info *bi; -+ struct wlc_ssid *ssid; -+ struct bcm_tlv *tim; -+ s32 beacon_interval; -+ s32 dtim_period; -+ size_t ie_len; -+ u8 *ie; -+ u8 *ssidie; -+ u8 *curbssid; -+ s32 err = 0; -+ struct wiphy *wiphy; -+ -+ wiphy = wl_to_wiphy(wl); -+ -+ if (wl_is_ibssmode(wl, ndev)) -+ return err; -+ -+ ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID); -+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); -+ bss = cfg80211_get_bss(wiphy, NULL, curbssid, -+ ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, -+ WLAN_CAPABILITY_ESS); -+ -+ mutex_lock(&wl->usr_sync); -+ if (!bss) { -+ WL_DBG(("Could not find the AP\n")); -+ *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); -+ err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, -+ wl->extra_buf, WL_EXTRA_BUF_MAX, false); -+ if (unlikely(err)) { -+ WL_ERR(("Could not get bss info %d\n", err)); -+ goto update_bss_info_out; -+ } -+ bi = (struct wl_bss_info *)(wl->extra_buf + 4); -+ if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) { -+ err = -EIO; -+ goto update_bss_info_out; -+ } -+ -+ ie = ((u8 *)bi) + bi->ie_offset; -+ ie_len = bi->ie_length; -+ ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie, ie_len); -+ if (ssidie && ssidie[1] == bi->SSID_len && !ssidie[2] && bi->SSID[0]) -+ memcpy(ssidie + 2, bi->SSID, bi->SSID_len); -+ -+ err = wl_inform_single_bss(wl, bi, is_roam_done); -+ if (unlikely(err)) -+ goto update_bss_info_out; -+ -+ ie = ((u8 *)bi) + bi->ie_offset; -+ ie_len = bi->ie_length; -+ beacon_interval = cpu_to_le16(bi->beacon_period); -+ } else { -+ WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid)); -+ ie = bss->information_elements; -+ ie_len = bss->len_information_elements; -+ beacon_interval = bss->beacon_interval; -+ cfg80211_put_bss(bss); -+ } -+ -+ tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM); -+ if (tim) { -+ dtim_period = tim->data[1]; -+ } else { -+ /* -+ * active scan was done so we could not get dtim -+ * information out of probe response. -+ * so we speficially query dtim information. -+ */ -+ err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, -+ &dtim_period, sizeof(dtim_period), false); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); -+ goto update_bss_info_out; -+ } -+ } -+ -+ wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); -+ wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); -+ -+update_bss_info_out: -+ mutex_unlock(&wl->usr_sync); -+ return err; -+} -+ -+static s32 -+wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ struct wl_connect_info *conn_info = wl_to_conn(wl); -+ s32 err = 0; -+ u8 *curbssid; -+ -+ wl_get_assoc_ies(wl, ndev); -+ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); -+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); -+ wl_update_bss_info(wl, ndev, 1); -+ wl_update_pmklist(ndev, wl->pmk_list, err); -+ printk("wl_bss_roaming_done succeeded to " MACDBG "\n", -+ MAC2STRDBG((u8*)(&e->addr))); -+ -+ cfg80211_roamed(ndev, -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) -+ NULL, /* struct cfg80211_bss *bss */ -+#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) -+ NULL, -+#endif -+ curbssid, -+ conn_info->req_ie, conn_info->req_ie_len, -+ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); -+ WL_DBG(("Report roaming result\n")); -+ -+ wl_set_drv_status(wl, CONNECTED, ndev); -+ -+ return err; -+} -+ -+static s32 -+wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data, bool completed) -+{ -+ struct wl_connect_info *conn_info = wl_to_conn(wl); -+ struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); -+ s32 err = 0; -+ u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); -+ if (!sec) { -+ WL_ERR(("sec is NULL\n")); -+ return -ENODEV; -+ } -+ WL_DBG((" enter\n")); -+#ifdef ESCAN_RESULT_PATCH -+ if (wl_get_drv_status(wl, CONNECTED, ndev)) { -+ if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) { -+ WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n", -+ ntoh32(e->event_type), ntoh32(e->status))); -+ return err; -+ } -+ } -+ if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 && -+ memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) { -+ WL_DBG(("copy bssid\n")); -+ memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN); -+ } -+ -+#else -+ if (wl->scan_request) { -+ wl_notify_escan_complete(wl, ndev, true, true); -+ } -+#endif /* ESCAN_RESULT_PATCH */ -+ if (wl_get_drv_status(wl, CONNECTING, ndev)) { -+ wl_clr_drv_status(wl, CONNECTING, ndev); -+ if (completed) { -+ wl_get_assoc_ies(wl, ndev); -+ wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); -+ curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); -+ wl_update_bss_info(wl, ndev, 0); -+ wl_update_pmklist(ndev, wl->pmk_list, err); -+ wl_set_drv_status(wl, CONNECTED, ndev); -+ } -+ cfg80211_connect_result(ndev, -+ curbssid, -+ conn_info->req_ie, -+ conn_info->req_ie_len, -+ conn_info->resp_ie, -+ conn_info->resp_ie_len, -+ completed ? WLAN_STATUS_SUCCESS : -+ (sec->auth_assoc_res_status) ? -+ sec->auth_assoc_res_status : -+ WLAN_STATUS_UNSPECIFIED_FAILURE, -+ GFP_KERNEL); -+ if (completed) -+ WL_INFO(("Report connect result - connection succeeded\n")); -+ else -+ WL_ERR(("Report connect result - connection failed\n")); -+ } -+ return err; -+} -+ -+static s32 -+wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ u16 flags = ntoh16(e->flags); -+ enum nl80211_key_type key_type; -+ -+ mutex_lock(&wl->usr_sync); -+ if (flags & WLC_EVENT_MSG_GROUP) -+ key_type = NL80211_KEYTYPE_GROUP; -+ else -+ key_type = NL80211_KEYTYPE_PAIRWISE; -+ -+ cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, -+ NULL, GFP_KERNEL); -+ mutex_unlock(&wl->usr_sync); -+ -+ return 0; -+} -+ -+#ifdef PNO_SUPPORT -+static s32 -+wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ WL_ERR((">>> PNO Event\n")); -+ -+#ifndef WL_SCHED_SCAN -+ mutex_lock(&wl->usr_sync); -+ /* TODO: Use cfg80211_sched_scan_results(wiphy); */ -+ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); -+ mutex_unlock(&wl->usr_sync); -+#else -+ /* If cfg80211 scheduled scan is supported, report the pno results via sched -+ * scan results -+ */ -+ wl_notify_sched_scan_results(wl, ndev, e, data); -+#endif /* WL_SCHED_SCAN */ -+ return 0; -+} -+#endif /* PNO_SUPPORT */ -+ -+static s32 -+wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ struct channel_info channel_inform; -+ struct wl_scan_results *bss_list; -+ u32 len = WL_SCAN_BUF_MAX; -+ s32 err = 0; -+ unsigned long flags; -+ -+ WL_DBG(("Enter \n")); -+ if (!wl_get_drv_status(wl, SCANNING, ndev)) { -+ WL_ERR(("scan is not ready \n")); -+ return err; -+ } -+ if (wl->iscan_on && wl->iscan_kickstart) -+ return wl_wakeup_iscan(wl_to_iscan(wl)); -+ -+ mutex_lock(&wl->usr_sync); -+ wl_clr_drv_status(wl, SCANNING, ndev); -+ err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, -+ sizeof(channel_inform), false); -+ if (unlikely(err)) { -+ WL_ERR(("scan busy (%d)\n", err)); -+ goto scan_done_out; -+ } -+ channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); -+ if (unlikely(channel_inform.scan_channel)) { -+ -+ WL_DBG(("channel_inform.scan_channel (%d)\n", -+ channel_inform.scan_channel)); -+ } -+ wl->bss_list = wl->scan_results; -+ bss_list = wl->bss_list; -+ memset(bss_list, 0, len); -+ bss_list->buflen = htod32(len); -+ err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false); -+ if (unlikely(err) && unlikely(!wl->scan_suppressed)) { -+ WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); -+ err = -EINVAL; -+ goto scan_done_out; -+ } -+ bss_list->buflen = dtoh32(bss_list->buflen); -+ bss_list->version = dtoh32(bss_list->version); -+ bss_list->count = dtoh32(bss_list->count); -+ -+ err = wl_inform_bss(wl); -+ -+scan_done_out: -+ del_timer_sync(&wl->scan_timeout); -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ if (wl->scan_request) { -+ cfg80211_scan_done(wl->scan_request, false); -+ wl->scan_request = NULL; -+ } -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ WL_DBG(("cfg80211_scan_done\n")); -+ mutex_unlock(&wl->usr_sync); -+ return err; -+} -+static s32 -+wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, -+ const struct ether_addr *sa, const struct ether_addr *bssid, -+ u8 **pheader, u32 *body_len, u8 *pbody) -+{ -+ struct dot11_management_header *hdr; -+ u32 totlen = 0; -+ s32 err = 0; -+ u8 *offset; -+ u32 prebody_len = *body_len; -+ switch (fc) { -+ case FC_ASSOC_REQ: -+ /* capability , listen interval */ -+ totlen = DOT11_ASSOC_REQ_FIXED_LEN; -+ *body_len += DOT11_ASSOC_REQ_FIXED_LEN; -+ break; -+ -+ case FC_REASSOC_REQ: -+ /* capability, listen inteval, ap address */ -+ totlen = DOT11_REASSOC_REQ_FIXED_LEN; -+ *body_len += DOT11_REASSOC_REQ_FIXED_LEN; -+ break; -+ } -+ totlen += DOT11_MGMT_HDR_LEN + prebody_len; -+ *pheader = kzalloc(totlen, GFP_KERNEL); -+ if (*pheader == NULL) { -+ WL_ERR(("memory alloc failed \n")); -+ return -ENOMEM; -+ } -+ hdr = (struct dot11_management_header *) (*pheader); -+ hdr->fc = htol16(fc); -+ hdr->durid = 0; -+ hdr->seq = 0; -+ offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); -+ bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); -+ bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); -+ bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); -+ if ((pbody != NULL) && prebody_len) -+ bcopy((const char*)pbody, offset, prebody_len); -+ *body_len = totlen; -+ return err; -+} -+ -+ -+void -+wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev) -+{ -+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM) && -+ (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || -+ wl_get_p2p_status(wl, ACTION_TX_NOACK))) { -+ WL_DBG(("*** Wake UP ** abort actframe iovar\n")); -+ /* if channel is not zero, "actfame" uses off channel scan. -+ * So abort scan for off channel completion. -+ */ -+ if (wl->af_sent_channel) -+ /* wl_cfg80211_scan_abort(wl, ndev); */ -+ wl_notify_escan_complete(wl, -+ (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); -+ } -+#ifdef WL_CFG80211_SYNC_GON -+ else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { -+ WL_DBG(("*** Wake UP ** abort listen for next af frame\n")); -+ /* So abort scan to cancel listen */ -+ wl_notify_escan_complete(wl, -+ (ndev == wl->p2p_net) ? wl_to_prmry_ndev(wl) : ndev, true, true); -+ } -+#endif /* WL_CFG80211_SYNC_GON */ -+} -+ -+static s32 -+wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ struct ieee80211_supported_band *band; -+ struct wiphy *wiphy = wl_to_wiphy(wl); -+ struct ether_addr da; -+ struct ether_addr bssid; -+ bool isfree = false; -+ s32 err = 0; -+ s32 freq; -+ struct net_device *dev = NULL; -+ wifi_p2p_pub_act_frame_t *act_frm = NULL; -+ wifi_p2p_action_frame_t *p2p_act_frm = NULL; -+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; -+ wl_event_rx_frame_data_t *rxframe = -+ (wl_event_rx_frame_data_t*)data; -+ u32 event = ntoh32(e->event_type); -+ u8 *mgmt_frame; -+ u8 bsscfgidx = e->bsscfgidx; -+ u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); -+ u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); -+ -+ memset(&bssid, 0, ETHER_ADDR_LEN); -+ -+ if (wl->p2p_net == ndev) { -+ dev = wl_to_prmry_ndev(wl); -+ } else { -+ dev = ndev; -+ } -+ -+ if (channel <= CH_MAX_2G_CHANNEL) -+ band = wiphy->bands[IEEE80211_BAND_2GHZ]; -+ else -+ band = wiphy->bands[IEEE80211_BAND_5GHZ]; -+ if (!band) { -+ WL_ERR(("No valid band")); -+ return -EINVAL; -+ } -+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) -+ freq = ieee80211_channel_to_frequency(channel); -+ (void)band->band; -+#else -+ freq = ieee80211_channel_to_frequency(channel, band->band); -+#endif -+ if (event == WLC_E_ACTION_FRAME_RX) { -+ wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", -+ NULL, 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &wl->ioctl_buf_sync); -+ -+ err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); -+ if (err < 0) -+ WL_ERR(("WLC_GET_BSSID error %d\n", err)); -+ memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); -+ err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, -+ &mgmt_frame, &mgmt_frame_len, -+ (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); -+ if (err < 0) { -+ WL_ERR(("%s: Error in receiving action frame len %d channel %d freq %d\n", -+ __func__, mgmt_frame_len, channel, freq)); -+ goto exit; -+ } -+ isfree = true; -+ if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], -+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { -+ act_frm = (wifi_p2p_pub_act_frame_t *) -+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); -+ } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], -+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { -+ p2p_act_frm = (wifi_p2p_action_frame_t *) -+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); -+ (void) p2p_act_frm; -+ } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], -+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { -+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) -+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]); -+ if (sd_act_frm && wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { -+ if (wl->next_af_subtype == sd_act_frm->action) { -+ WL_DBG(("We got a right next frame of SD!(%d)\n", -+ sd_act_frm->action)); -+ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, -+ (ndev == wl->p2p_net) ? -+ wl_to_prmry_ndev(wl) : ndev); -+ -+ /* Stop waiting for next AF. */ -+ wl_stop_wait_next_action_frame(wl, ndev); -+ } -+ } -+ (void) sd_act_frm; -+ } else { -+ /* -+ * if we got normal action frame and ndev is p2p0, -+ * we have to change ndev from p2p0 to wlan0 -+ */ -+ if (wl->p2p_net == ndev) -+ ndev = wl_to_prmry_ndev(wl); -+ } -+ -+ if (act_frm) { -+ -+ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) { -+ if (wl->next_af_subtype == act_frm->subtype) { -+ WL_DBG(("We got a right next frame!(%d)\n", -+ act_frm->subtype)); -+ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, -+ (ndev == wl->p2p_net) ? -+ wl_to_prmry_ndev(wl) : ndev); -+ -+ /* Stop waiting for next AF. */ -+ wl_stop_wait_next_action_frame(wl, ndev); -+ } -+ } -+ } -+ -+ wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], -+ mgmt_frame_len - DOT11_MGMT_HDR_LEN); -+ /* -+ * After complete GO Negotiation, roll back to mpc mode -+ */ -+ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || -+ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { -+ wldev_iovar_setint(dev, "mpc", 1); -+ } -+ if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) { -+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n")); -+ wl_clr_p2p_status(wl, GO_NEG_PHASE); -+ } -+ } else { -+ mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); -+ -+ /* wpa supplicant use probe request event for restarting another GON Req. -+ * but it makes GON Req repetition. -+ * so if src addr of prb req is same as my target device, -+ * do not send probe request event during sending action frame. -+ */ -+ if (event == WLC_E_P2P_PROBREQ_MSG) { -+ WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ? -+ "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG")); -+ -+ -+ /* Filter any P2P probe reqs arriving during the -+ * GO-NEG Phase -+ */ -+ if (wl->p2p && -+ wl_get_p2p_status(wl, GO_NEG_PHASE)) { -+ WL_DBG(("Filtering P2P probe_req while " -+ "being in GO-Neg state\n")); -+ return 0; -+ } -+ } -+ } -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); -+#else -+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */ -+ -+ WL_DBG(("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__, -+ mgmt_frame_len, ntoh32(e->datalen), channel, freq)); -+exit: -+ if (isfree) -+ kfree(mgmt_frame); -+ return 0; -+} -+ -+#ifdef WL_SCHED_SCAN -+/* If target scan is not reliable, set the below define to "1" to do a -+ * full escan -+ */ -+#define FULL_ESCAN_ON_PFN_NET_FOUND 0 -+static s32 -+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ wl_pfn_net_info_t *netinfo, *pnetinfo; -+ struct cfg80211_scan_request request; -+ struct wiphy *wiphy = wl_to_wiphy(wl); -+ int err = 0; -+ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; -+ struct ieee80211_channel *channel = NULL; -+ int channel_req = 0; -+ int band = 0; -+ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; -+ -+ WL_DBG(("Enter\n")); -+ -+ if (e->event_type == WLC_E_PFN_NET_LOST) { -+ WL_PNO(("PFN NET LOST event. Do Nothing \n")); -+ return 0; -+ } -+ WL_PNO((">>> PFN NET FOUND event. count:%d \n", pfn_result->count)); -+ if (pfn_result->count > 0) { -+ int i; -+ -+ memset(&request, 0x00, sizeof(struct cfg80211_scan_request)); -+ memset(&ssid, 0x00, sizeof(ssid)); -+ request.wiphy = wiphy; -+ -+ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) -+ - sizeof(wl_pfn_net_info_t)); -+ channel = (struct ieee80211_channel *)kzalloc( -+ (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT), -+ GFP_KERNEL); -+ if (!channel) { -+ WL_ERR(("No memory")); -+ err = -ENOMEM; -+ goto out_err; -+ } -+ -+ for (i = 0; i < pfn_result->count; i++) { -+ netinfo = &pnetinfo[i]; -+ if (!netinfo) { -+ WL_ERR(("Invalid netinfo ptr. index:%d", i)); -+ err = -EINVAL; -+ goto out_err; -+ } -+ WL_PNO((">>> SSID:%s Channel:%d \n", -+ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); -+ /* PFN result doesn't have all the info which are required by the supplicant -+ * (For e.g IEs) Do a target Escan so that sched scan results are reported -+ * via wl_inform_single_bss in the required format. Escan does require the -+ * scan request in the form of cfg80211_scan_request. For timebeing, create -+ * cfg80211_scan_request one out of the received PNO event. -+ */ -+ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, -+ netinfo->pfnsubnet.SSID_len); -+ ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len; -+ request.n_ssids++; -+ -+ channel_req = netinfo->pfnsubnet.channel; -+ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ -+ : NL80211_BAND_5GHZ; -+ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); -+ channel[i].band = band; -+ channel[i].flags |= IEEE80211_CHAN_NO_HT40; -+ request.channels[i] = &channel[i]; -+ request.n_channels++; -+ } -+ -+ /* assign parsed ssid array */ -+ if (request.n_ssids) -+ request.ssids = &ssid[0]; -+ -+ if (wl_get_drv_status_all(wl, SCANNING)) { -+ /* Abort any on-going scan */ -+ wl_notify_escan_complete(wl, ndev, true, true); -+ } -+ -+ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { -+ WL_PNO((">>> P2P discovery was ON. Disabling it\n")); -+ err = wl_cfgp2p_discover_enable_search(wl, false); -+ if (unlikely(err)) { -+ wl_clr_drv_status(wl, SCANNING, ndev); -+ goto out_err; -+ } -+ } -+ -+ wl_set_drv_status(wl, SCANNING, ndev); -+#if FULL_ESCAN_ON_PFN_NET_FOUND -+ WL_PNO((">>> Doing Full ESCAN on PNO event\n")); -+ err = wl_do_escan(wl, wiphy, ndev, NULL); -+#else -+ WL_PNO((">>> Doing targeted ESCAN on PNO event\n")); -+ err = wl_do_escan(wl, wiphy, ndev, &request); -+#endif -+ if (err) { -+ wl_clr_drv_status(wl, SCANNING, ndev); -+ goto out_err; -+ } -+ wl->sched_scan_running = TRUE; -+ } -+ else { -+ WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); -+ } -+out_err: -+ if (channel) -+ kfree(channel); -+ return err; -+} -+#endif /* WL_SCHED_SCAN */ -+ -+static void wl_init_conf(struct wl_conf *conf) -+{ -+ WL_DBG(("Enter \n")); -+ conf->frag_threshold = (u32)-1; -+ conf->rts_threshold = (u32)-1; -+ conf->retry_short = (u32)-1; -+ conf->retry_long = (u32)-1; -+ conf->tx_power = -1; -+} -+ -+static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev) -+{ -+ unsigned long flags; -+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); -+ -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ memset(profile, 0, sizeof(struct wl_profile)); -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+} -+ -+static void wl_init_event_handler(struct wl_priv *wl) -+{ -+ memset(wl->evt_handler, 0, sizeof(wl->evt_handler)); -+ -+ wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; -+ wl->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; -+ wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; -+ wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; -+ wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; -+ wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; -+ wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; -+ wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; -+ wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; -+ wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; -+#ifdef PNO_SUPPORT -+ wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; -+#endif /* PNO_SUPPORT */ -+} -+ -+static s32 wl_init_priv_mem(struct wl_priv *wl) -+{ -+ WL_DBG(("Enter \n")); -+ wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); -+ if (unlikely(!wl->scan_results)) { -+ WL_ERR(("Scan results alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL); -+ if (unlikely(!wl->conf)) { -+ WL_ERR(("wl_conf alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->scan_req_int = -+ (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); -+ if (unlikely(!wl->scan_req_int)) { -+ WL_ERR(("Scan req alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); -+ if (unlikely(!wl->ioctl_buf)) { -+ WL_ERR(("Ioctl buf alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); -+ if (unlikely(!wl->escan_ioctl_buf)) { -+ WL_ERR(("Ioctl buf alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); -+ if (unlikely(!wl->extra_buf)) { -+ WL_ERR(("Extra buf alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL); -+ if (unlikely(!wl->iscan)) { -+ WL_ERR(("Iscan buf alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); -+ if (unlikely(!wl->pmk_list)) { -+ WL_ERR(("pmk list alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL); -+ if (unlikely(!wl->sta_info)) { -+ WL_ERR(("sta info alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ -+#if defined(STATIC_WL_PRIV_STRUCT) -+ wl->conn_info = (void *)kzalloc(sizeof(*wl->conn_info), GFP_KERNEL); -+ if (unlikely(!wl->conn_info)) { -+ WL_ERR(("wl->conn_info alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->ie = (void *)kzalloc(sizeof(*wl->ie), GFP_KERNEL); -+ if (unlikely(!wl->ie)) { -+ WL_ERR(("wl->ie alloc failed\n")); -+ goto init_priv_mem_out; -+ } -+ wl->escan_info.escan_buf = dhd_os_prealloc(NULL, DHD_PREALLOC_WIPHY_ESCAN0, 0); -+ bzero(wl->escan_info.escan_buf, ESCAN_BUF_SIZE); -+#endif /* STATIC_WL_PRIV_STRUCT */ -+ wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL); -+ if (unlikely(!wl->afx_hdl)) { -+ WL_ERR(("afx hdl alloc failed\n")); -+ goto init_priv_mem_out; -+ } else { -+ init_completion(&wl->act_frm_scan); -+ init_completion(&wl->wait_next_af); -+ -+ INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler); -+ } -+ return 0; -+ -+init_priv_mem_out: -+ wl_deinit_priv_mem(wl); -+ -+ return -ENOMEM; -+} -+ -+static void wl_deinit_priv_mem(struct wl_priv *wl) -+{ -+ kfree(wl->scan_results); -+ wl->scan_results = NULL; -+ kfree(wl->conf); -+ wl->conf = NULL; -+ kfree(wl->scan_req_int); -+ wl->scan_req_int = NULL; -+ kfree(wl->ioctl_buf); -+ wl->ioctl_buf = NULL; -+ kfree(wl->escan_ioctl_buf); -+ wl->escan_ioctl_buf = NULL; -+ kfree(wl->extra_buf); -+ wl->extra_buf = NULL; -+ kfree(wl->iscan); -+ wl->iscan = NULL; -+ kfree(wl->pmk_list); -+ wl->pmk_list = NULL; -+ kfree(wl->sta_info); -+ wl->sta_info = NULL; -+#if defined(STATIC_WL_PRIV_STRUCT) -+ kfree(wl->conn_info); -+ wl->conn_info = NULL; -+ kfree(wl->ie); -+ wl->ie = NULL; -+ wl->escan_info.escan_buf = NULL; -+#endif /* STATIC_WL_PRIV_STRUCT */ -+ if (wl->afx_hdl) { -+ cancel_work_sync(&wl->afx_hdl->work); -+ kfree(wl->afx_hdl); -+ wl->afx_hdl = NULL; -+ } -+ -+ if (wl->ap_info) { -+ kfree(wl->ap_info->wpa_ie); -+ kfree(wl->ap_info->rsn_ie); -+ kfree(wl->ap_info->wps_ie); -+ kfree(wl->ap_info); -+ wl->ap_info = NULL; -+ } -+} -+ -+static s32 wl_create_event_handler(struct wl_priv *wl) -+{ -+ int ret = 0; -+ WL_DBG(("Enter \n")); -+ -+ /* Do not use DHD in cfg driver */ -+ wl->event_tsk.thr_pid = -1; -+ PROC_START(wl_event_handler, wl, &wl->event_tsk, 0); -+ if (wl->event_tsk.thr_pid < 0) -+ ret = -ENOMEM; -+ return ret; -+} -+ -+static void wl_destroy_event_handler(struct wl_priv *wl) -+{ -+ if (wl->event_tsk.thr_pid >= 0) -+ PROC_STOP(&wl->event_tsk); -+} -+ -+static void wl_term_iscan(struct wl_priv *wl) -+{ -+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); -+ WL_TRACE(("In\n")); -+ if (wl->iscan_on && iscan->tsk) { -+ iscan->state = WL_ISCAN_STATE_IDLE; -+ WL_INFO(("SIGTERM\n")); -+ send_sig(SIGTERM, iscan->tsk, 1); -+ WL_DBG(("kthread_stop\n")); -+ kthread_stop(iscan->tsk); -+ iscan->tsk = NULL; -+ } -+} -+ -+static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) -+{ -+ struct wl_priv *wl = iscan_to_wl(iscan); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ unsigned long flags; -+ -+ WL_DBG(("Enter \n")); -+ if (!wl_get_drv_status(wl, SCANNING, ndev)) { -+ wl_clr_drv_status(wl, SCANNING, ndev); -+ WL_ERR(("Scan complete while device not scanning\n")); -+ return; -+ } -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ wl_clr_drv_status(wl, SCANNING, ndev); -+ if (likely(wl->scan_request)) { -+ cfg80211_scan_done(wl->scan_request, aborted); -+ wl->scan_request = NULL; -+ } -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ wl->iscan_kickstart = false; -+} -+ -+static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan) -+{ -+ if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { -+ WL_DBG(("wake up iscan\n")); -+ up(&iscan->sync); -+ return 0; -+ } -+ -+ return -EIO; -+} -+ -+static s32 -+wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, -+ struct wl_scan_results **bss_list) -+{ -+ struct wl_iscan_results list; -+ struct wl_scan_results *results; -+ struct wl_iscan_results *list_buf; -+ s32 err = 0; -+ -+ WL_DBG(("Enter \n")); -+ memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); -+ list_buf = (struct wl_iscan_results *)iscan->scan_buf; -+ results = &list_buf->results; -+ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; -+ results->version = 0; -+ results->count = 0; -+ -+ memset(&list, 0, sizeof(list)); -+ list.results.buflen = htod32(WL_ISCAN_BUF_MAX); -+ err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list, -+ WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, -+ WL_ISCAN_BUF_MAX, NULL); -+ if (unlikely(err)) { -+ WL_ERR(("error (%d)\n", err)); -+ return err; -+ } -+ results->buflen = dtoh32(results->buflen); -+ results->version = dtoh32(results->version); -+ results->count = dtoh32(results->count); -+ WL_DBG(("results->count = %d\n", results->count)); -+ WL_DBG(("results->buflen = %d\n", results->buflen)); -+ *status = dtoh32(list_buf->status); -+ *bss_list = results; -+ -+ return err; -+} -+ -+static s32 wl_iscan_done(struct wl_priv *wl) -+{ -+ struct wl_iscan_ctrl *iscan = wl->iscan; -+ s32 err = 0; -+ -+ iscan->state = WL_ISCAN_STATE_IDLE; -+ mutex_lock(&wl->usr_sync); -+ wl_inform_bss(wl); -+ wl_notify_iscan_complete(iscan, false); -+ mutex_unlock(&wl->usr_sync); -+ -+ return err; -+} -+ -+static s32 wl_iscan_pending(struct wl_priv *wl) -+{ -+ struct wl_iscan_ctrl *iscan = wl->iscan; -+ s32 err = 0; -+ -+ /* Reschedule the timer */ -+ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); -+ iscan->timer_on = 1; -+ -+ return err; -+} -+ -+static s32 wl_iscan_inprogress(struct wl_priv *wl) -+{ -+ struct wl_iscan_ctrl *iscan = wl->iscan; -+ s32 err = 0; -+ -+ mutex_lock(&wl->usr_sync); -+ wl_inform_bss(wl); -+ wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); -+ mutex_unlock(&wl->usr_sync); -+ /* Reschedule the timer */ -+ mod_timer(&iscan->timer, jiffies + msecs_to_jiffies(iscan->timer_ms)); -+ iscan->timer_on = 1; -+ -+ return err; -+} -+ -+static s32 wl_iscan_aborted(struct wl_priv *wl) -+{ -+ struct wl_iscan_ctrl *iscan = wl->iscan; -+ s32 err = 0; -+ -+ iscan->state = WL_ISCAN_STATE_IDLE; -+ mutex_lock(&wl->usr_sync); -+ wl_notify_iscan_complete(iscan, true); -+ mutex_unlock(&wl->usr_sync); -+ -+ return err; -+} -+ -+static s32 wl_iscan_thread(void *data) -+{ -+ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; -+ struct wl_priv *wl = iscan_to_wl(iscan); -+ u32 status; -+ int err = 0; -+ -+ allow_signal(SIGTERM); -+ status = WL_SCAN_RESULTS_PARTIAL; -+ while (likely(!down_interruptible(&iscan->sync))) { -+ if (kthread_should_stop()) -+ break; -+ if (iscan->timer_on) { -+ del_timer_sync(&iscan->timer); -+ iscan->timer_on = 0; -+ } -+ mutex_lock(&wl->usr_sync); -+ err = wl_get_iscan_results(iscan, &status, &wl->bss_list); -+ if (unlikely(err)) { -+ status = WL_SCAN_RESULTS_ABORTED; -+ WL_ERR(("Abort iscan\n")); -+ } -+ mutex_unlock(&wl->usr_sync); -+ iscan->iscan_handler[status] (wl); -+ } -+ if (iscan->timer_on) { -+ del_timer_sync(&iscan->timer); -+ iscan->timer_on = 0; -+ } -+ WL_DBG(("%s was terminated\n", __func__)); -+ -+ return 0; -+} -+ -+static void wl_scan_timeout(unsigned long data) -+{ -+ struct wl_priv *wl = (struct wl_priv *)data; -+ -+ if (wl->scan_request) { -+ WL_ERR(("timer expired\n")); -+ if (wl->escan_on) -+ wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); -+ else -+ wl_notify_iscan_complete(wl_to_iscan(wl), true); -+ } -+} -+static void wl_iscan_timer(unsigned long data) -+{ -+ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; -+ -+ if (iscan) { -+ iscan->timer_on = 0; -+ WL_DBG(("timer expired\n")); -+ wl_wakeup_iscan(iscan); -+ } -+} -+ -+static s32 wl_invoke_iscan(struct wl_priv *wl) -+{ -+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); -+ int err = 0; -+ -+ if (wl->iscan_on && !iscan->tsk) { -+ iscan->state = WL_ISCAN_STATE_IDLE; -+ sema_init(&iscan->sync, 0); -+ iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); -+ if (IS_ERR(iscan->tsk)) { -+ WL_ERR(("Could not create iscan thread\n")); -+ iscan->tsk = NULL; -+ return -ENOMEM; -+ } -+ } -+ -+ return err; -+} -+ -+static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan) -+{ -+ memset(iscan->iscan_handler, 0, sizeof(iscan->iscan_handler)); -+ iscan->iscan_handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done; -+ iscan->iscan_handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress; -+ iscan->iscan_handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending; -+ iscan->iscan_handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted; -+ iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted; -+} -+ -+static s32 -+wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, -+ unsigned long state, -+ void *ndev) -+{ -+ struct net_device *dev = ndev; -+ struct wireless_dev *wdev = dev->ieee80211_ptr; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ int refcnt = 0; -+ -+ WL_DBG(("Enter \n")); -+ if (!wdev || !wl || dev == wl_to_prmry_ndev(wl)) -+ return NOTIFY_DONE; -+ switch (state) { -+ case NETDEV_DOWN: -+ while (work_pending(&wdev->cleanup_work) && refcnt < 100) { -+ if (refcnt%5 == 0) -+ WL_ERR(("%s : [NETDEV_DOWN] work_pending (%d th)\n", -+ __FUNCTION__, refcnt)); -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(100); -+ set_current_state(TASK_RUNNING); -+ refcnt++; -+ } -+ break; -+ -+ case NETDEV_UNREGISTER: -+ /* after calling list_del_rcu(&wdev->list) */ -+ wl_dealloc_netinfo(wl, ndev); -+ break; -+ case NETDEV_GOING_DOWN: -+ /* At NETDEV_DOWN state, wdev_cleanup_work work will be called. -+ * In front of door, the function checks -+ * whether current scan is working or not. -+ * If the scanning is still working, wdev_cleanup_work call WARN_ON and -+ * make the scan done forcibly. -+ */ -+ if (wl_get_drv_status(wl, SCANNING, dev)) { -+ if (wl->escan_on) { -+ wl_notify_escan_complete(wl, dev, true, true); -+ } -+ } -+ break; -+ } -+ return NOTIFY_DONE; -+} -+static struct notifier_block wl_cfg80211_netdev_notifier = { -+ .notifier_call = wl_cfg80211_netdev_notifier_call, -+}; -+ -+static s32 wl_notify_escan_complete(struct wl_priv *wl, -+ struct net_device *ndev, -+ bool aborted, bool fw_abort) -+{ -+ wl_scan_params_t *params = NULL; -+ s32 params_size = 0; -+ s32 err = BCME_OK; -+ unsigned long flags; -+ struct net_device *dev; -+ -+ WL_DBG(("Enter \n")); -+ -+ if (wl->escan_info.ndev != ndev) -+ { -+ WL_ERR(("ndev is different %p %p\n", wl->escan_info.ndev, ndev)); -+ return err; -+ } -+ -+ if (wl->scan_request) { -+ if (wl->scan_request->dev == wl->p2p_net) -+ dev = wl_to_prmry_ndev(wl); -+ else -+ dev = wl->scan_request->dev; -+ } -+ else { -+ WL_DBG(("wl->scan_request is NULL may be internal scan." -+ "doing scan_abort for ndev %p primary %p p2p_net %p", -+ ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); -+ dev = ndev; -+ } -+ if (fw_abort && !in_atomic()) { -+ /* Our scan params only need space for 1 channel and 0 ssids */ -+ params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); -+ if (params == NULL) { -+ WL_ERR(("scan params allocation failed \n")); -+ err = -ENOMEM; -+ } else { -+ /* Do a scan abort to stop the driver's scan engine */ -+ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); -+ if (err < 0) { -+ WL_ERR(("scan abort failed \n")); -+ } -+ } -+ } -+ if (timer_pending(&wl->scan_timeout)) -+ del_timer_sync(&wl->scan_timeout); -+#if defined(ESCAN_RESULT_PATCH) -+ if (likely(wl->scan_request)) { -+ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; -+ wl_inform_bss(wl); -+ } -+#endif /* ESCAN_RESULT_PATCH */ -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+#ifdef WL_SCHED_SCAN -+ if (wl->sched_scan_req && !wl->scan_request) { -+ WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n")); -+ if (aborted) -+ cfg80211_sched_scan_stopped(wl->sched_scan_req->wiphy); -+ else -+ cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); -+ wl->sched_scan_running = FALSE; -+ wl->sched_scan_req = NULL; -+ } -+#endif /* WL_SCHED_SCAN */ -+ if (likely(wl->scan_request)) { -+ cfg80211_scan_done(wl->scan_request, aborted); -+ wl->scan_request = NULL; -+ } -+ if (p2p_is_on(wl)) -+ wl_clr_p2p_status(wl, SCANNING); -+ wl_clr_drv_status(wl, SCANNING, dev); -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ if (params) -+ kfree(params); -+ -+ return err; -+} -+ -+static s32 wl_escan_handler(struct wl_priv *wl, -+ struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ s32 err = BCME_OK; -+ s32 status = ntoh32(e->status); -+ wl_bss_info_t *bi; -+ wl_escan_result_t *escan_result; -+ wl_bss_info_t *bss = NULL; -+ wl_scan_results_t *list; -+ wifi_p2p_ie_t * p2p_ie; -+ u32 bi_length; -+ u32 i; -+ u8 *p2p_dev_addr = NULL; -+ -+ WL_DBG((" enter event type : %d, status : %d \n", -+ ntoh32(e->event_type), ntoh32(e->status))); -+ -+ mutex_lock(&wl->usr_sync); -+ /* P2P SCAN is coming from primary interface */ -+ if (wl_get_p2p_status(wl, SCANNING)) { -+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) -+ ndev = wl->afx_hdl->dev; -+ else -+ ndev = wl->escan_info.ndev; -+ -+ } -+ if (!ndev || !wl->escan_on || -+ (!wl_get_drv_status(wl, SCANNING, ndev) && -+ !wl->sched_scan_running)) { -+ WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n", -+ ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev))); -+ goto exit; -+ } -+ if (status == WLC_E_STATUS_PARTIAL) { -+ WL_INFO(("WLC_E_STATUS_PARTIAL \n")); -+ escan_result = (wl_escan_result_t *) data; -+ if (!escan_result) { -+ WL_ERR(("Invalid escan result (NULL pointer)\n")); -+ goto exit; -+ } -+ if (dtoh16(escan_result->bss_count) != 1) { -+ WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count)); -+ goto exit; -+ } -+ bi = escan_result->bss_info; -+ if (!bi) { -+ WL_ERR(("Invalid escan bss info (NULL pointer)\n")); -+ goto exit; -+ } -+ bi_length = dtoh32(bi->length); -+ if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) { -+ WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); -+ goto exit; -+ } -+ -+ if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { -+ if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { -+ WL_DBG(("Ignoring IBSS result\n")); -+ goto exit; -+ } -+ } -+ -+ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { -+ p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); -+ if (p2p_dev_addr && !memcmp(p2p_dev_addr, -+ wl->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) { -+ s32 channel = wf_chspec_ctlchan( -+ wl_chspec_driver_to_host(bi->chanspec)); -+ WL_DBG(("ACTION FRAME SCAN : Peer " MACDBG " found, channel : %d\n", -+ MAC2STRDBG(wl->afx_hdl->tx_dst_addr.octet), channel)); -+ wl_clr_p2p_status(wl, SCANNING); -+ wl->afx_hdl->peer_chan = channel; -+ complete(&wl->act_frm_scan); -+ goto exit; -+ } -+ -+ } else { -+ int cur_len = 0; -+ list = (wl_scan_results_t *)wl->escan_info.escan_buf; -+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) -+ if (wl->p2p_net && wl->scan_request && -+ wl->scan_request->dev == wl->p2p_net) { -+#else -+ if (p2p_is_on(wl) && p2p_scan(wl)) { -+#endif -+#ifdef WL_HOST_BAND_MGMT -+ s32 channel = 0; -+ s32 channel_band = 0; -+#endif /* WL_HOST_BAND_MGMT */ -+ /* p2p scan && allow only probe response */ -+ if (bi->flags & WL_BSS_FLAGS_FROM_BEACON) -+ goto exit; -+ if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, -+ bi->ie_length)) == NULL) { -+ WL_ERR(("Couldn't find P2PIE in probe" -+ " response/beacon\n")); -+ goto exit; -+ } -+#ifdef WL_HOST_BAND_MGMT -+ channel = CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec)); -+ channel_band = (channel > CH_MAX_2G_CHANNEL) ? -+ WLC_BAND_5G : WLC_BAND_2G; -+ -+ -+ if ((wl->curr_band == WLC_BAND_5G) && -+ (channel_band == WLC_BAND_2G)) { -+ /* Avoid sending the GO results in band conflict */ -+ if (wl_cfgp2p_retreive_p2pattrib(p2p_ie, -+ P2P_SEID_GROUP_ID) != NULL) -+ goto exit; -+ } -+#endif /* WL_HOST_BAND_MGMT */ -+ } -+ for (i = 0; i < list->count; i++) { -+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) -+ : list->bss_info; -+ -+ if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && -+ (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec)) -+ == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) && -+ bi->SSID_len == bss->SSID_len && -+ !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { -+ -+ /* do not allow beacon data to update -+ *the data recd from a probe response -+ */ -+ if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) && -+ (bi->flags & WL_BSS_FLAGS_FROM_BEACON)) -+ goto exit; -+ -+ WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d" -+ " flags 0x%x, new: RSSI %d flags 0x%x\n", -+ bss->SSID, MAC2STRDBG(bi->BSSID.octet), i, -+ bss->RSSI, bss->flags, bi->RSSI, bi->flags)); -+ -+ if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == -+ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) { -+ /* preserve max RSSI if the measurements are -+ * both on-channel or both off-channel -+ */ -+ WL_SCAN(("%s("MACDBG"), same onchan" -+ ", RSSI: prev %d new %d\n", -+ bss->SSID, MAC2STRDBG(bi->BSSID.octet), -+ bss->RSSI, bi->RSSI)); -+ bi->RSSI = MAX(bss->RSSI, bi->RSSI); -+ } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) && -+ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) { -+ /* preserve the on-channel rssi measurement -+ * if the new measurement is off channel -+ */ -+ WL_SCAN(("%s("MACDBG"), prev onchan" -+ ", RSSI: prev %d new %d\n", -+ bss->SSID, MAC2STRDBG(bi->BSSID.octet), -+ bss->RSSI, bi->RSSI)); -+ bi->RSSI = bss->RSSI; -+ bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL; -+ } -+ if (dtoh32(bss->length) != bi_length) { -+ u32 prev_len = dtoh32(bss->length); -+ -+ WL_SCAN(("bss info replacement" -+ " is occured(bcast:%d->probresp%d)\n", -+ bss->ie_length, bi->ie_length)); -+ WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n", -+ bss->SSID, MAC2STRDBG(bi->BSSID.octet), -+ prev_len, bi_length)); -+ -+ if (list->buflen - prev_len + bi_length -+ > ESCAN_BUF_SIZE) { -+ WL_ERR(("Buffer is too small: keep the" -+ " previous result of this AP\n")); -+ /* Only update RSSI */ -+ bss->RSSI = bi->RSSI; -+ bss->flags |= (bi->flags -+ & WL_BSS_FLAGS_RSSI_ONCHANNEL); -+ goto exit; -+ } -+ -+ if (i < list->count - 1) { -+ /* memory copy required by this case only */ -+ memmove((u8 *)bss + bi_length, -+ (u8 *)bss + prev_len, -+ list->buflen - cur_len - prev_len); -+ } -+ list->buflen -= prev_len; -+ list->buflen += bi_length; -+ } -+ list->version = dtoh32(bi->version); -+ memcpy((u8 *)bss, (u8 *)bi, bi_length); -+ goto exit; -+ } -+ cur_len += dtoh32(bss->length); -+ } -+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) { -+ WL_ERR(("Buffer is too small: ignoring\n")); -+ goto exit; -+ } -+ memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); -+ list->version = dtoh32(bi->version); -+ list->buflen += bi_length; -+ list->count++; -+ } -+ -+ } -+ else if (status == WLC_E_STATUS_SUCCESS) { -+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; -+ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { -+ WL_INFO(("ACTION FRAME SCAN DONE\n")); -+ wl_clr_p2p_status(wl, SCANNING); -+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); -+ if (wl->afx_hdl->peer_chan == WL_INVALID) -+ complete(&wl->act_frm_scan); -+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { -+ WL_INFO(("ESCAN COMPLETED\n")); -+ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; -+ wl_inform_bss(wl); -+ wl_notify_escan_complete(wl, ndev, false, false); -+ } -+ } -+ else if (status == WLC_E_STATUS_ABORT) { -+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; -+ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { -+ WL_INFO(("ACTION FRAME SCAN DONE\n")); -+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); -+ wl_clr_p2p_status(wl, SCANNING); -+ if (wl->afx_hdl->peer_chan == WL_INVALID) -+ complete(&wl->act_frm_scan); -+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { -+ WL_INFO(("ESCAN ABORTED\n")); -+ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; -+ wl_inform_bss(wl); -+ wl_notify_escan_complete(wl, ndev, true, false); -+ } -+ } -+ else if (status == WLC_E_STATUS_NEWSCAN) -+ { -+ escan_result = (wl_escan_result_t *) data; -+ WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", wl->scan_request)); -+ WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id, -+ escan_result->bss_count)); -+ } else { -+ WL_ERR(("unexpected Escan Event %d : abort\n", status)); -+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; -+ if (wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { -+ WL_INFO(("ACTION FRAME SCAN DONE\n")); -+ wl_clr_p2p_status(wl, SCANNING); -+ wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); -+ if (wl->afx_hdl->peer_chan == WL_INVALID) -+ complete(&wl->act_frm_scan); -+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { -+ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; -+ wl_inform_bss(wl); -+ wl_notify_escan_complete(wl, ndev, true, false); -+ } -+ } -+exit: -+ mutex_unlock(&wl->usr_sync); -+ return err; -+} -+static void wl_cfg80211_concurrent_roam(struct wl_priv *wl, int enable) -+{ -+ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); -+ struct net_info *iter, *next; -+ int err; -+ -+ if (!wl->roamoff_on_concurrent) -+ return; -+ if (enable && connected_cnt > 1) { -+ for_each_ndev(wl, iter, next) { -+ /* Save the current roam setting */ -+ if ((err = wldev_iovar_getint(iter->ndev, "roam_off", -+ (s32 *)&iter->roam_off)) != BCME_OK) { -+ WL_ERR(("%s:Failed to get current roam setting err %d\n", -+ iter->ndev->name, err)); -+ continue; -+ } -+ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) { -+ WL_ERR((" %s:failed to set roam_off : %d\n", -+ iter->ndev->name, err)); -+ } -+ } -+ } -+ else if (!enable) { -+ for_each_ndev(wl, iter, next) { -+ if (iter->roam_off != WL_INVALID) { -+ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", -+ iter->roam_off)) == BCME_OK) -+ iter->roam_off = WL_INVALID; -+ else { -+ WL_ERR((" %s:failed to set roam_off : %d\n", -+ iter->ndev->name, err)); -+ } -+ } -+ } -+ } -+ return; -+} -+ -+static void wl_cfg80211_determine_vsdb_mode(struct wl_priv *wl) -+{ -+ struct net_info *iter, *next; -+ u32 chan = 0; -+ u32 chanspec = 0; -+ u32 prev_chan = 0; -+ u32 connected_cnt = wl_get_drv_status_all(wl, CONNECTED); -+ wl->vsdb_mode = false; -+ -+ if (connected_cnt <= 1) { -+ return; -+ } -+ for_each_ndev(wl, iter, next) { -+ chanspec = 0; -+ chan = 0; -+ if (wl_get_drv_status(wl, CONNECTED, iter->ndev)) { -+ if (wldev_iovar_getint(iter->ndev, "chanspec", -+ (s32 *)&chanspec) == BCME_OK) { -+ chan = CHSPEC_CHANNEL(chanspec); -+ if (CHSPEC_IS40(chanspec)) { -+ if (CHSPEC_SB_UPPER(chanspec)) -+ chan += CH_10MHZ_APART; -+ else -+ chan -= CH_10MHZ_APART; -+ } -+ wl_update_prof(wl, iter->ndev, NULL, -+ &chan, WL_PROF_CHAN); -+ } -+ if (!prev_chan && chan) -+ prev_chan = chan; -+ else if (prev_chan && (prev_chan != chan)) -+ wl->vsdb_mode = true; -+ } -+ } -+ return; -+} -+static s32 wl_notifier_change_state(struct wl_priv *wl, struct net_info *_net_info, -+ enum wl_status state, bool set) -+{ -+ s32 pm = PM_FAST; -+ s32 err = BCME_OK; -+ u32 chan = 0; -+ struct net_info *iter, *next; -+ struct net_device *primary_dev = wl_to_prmry_ndev(wl); -+ WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n", -+ state, set, _net_info->pm_restore, _net_info->ndev->name)); -+ -+ if (state != WL_STATUS_CONNECTED) -+ return 0; -+ -+ if (set) { -+ wl_cfg80211_concurrent_roam(wl, 1); -+ -+ if (wl_get_mode_by_netdev(wl, _net_info->ndev) == WL_MODE_AP) { -+ pm = PM_OFF; -+ WL_DBG(("%s:AP power save %s\n", _net_info->ndev->name, -+ pm ? "enabled" : "disabled")); -+ if ((err = wldev_ioctl(_net_info->ndev, WLC_SET_PM, -+ &pm, sizeof(pm), true)) != 0) { -+ if (err == -ENODEV) -+ WL_DBG(("%s:net_device is not ready\n", -+ _net_info->ndev->name)); -+ else -+ WL_ERR(("%s:error (%d)\n", _net_info->ndev->name, err)); -+ } -+ if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false)) -+ WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); -+ return 0; -+ } -+ wl_cfg80211_determine_vsdb_mode(wl); -+ pm = PM_OFF; -+ for_each_ndev(wl, iter, next) { -+ if ((!wl->vsdb_mode) && (iter->ndev != _net_info->ndev)) { -+ /* Do not touch the other interfaces power save -+ * if we are not in vsdb mode -+ */ -+ continue; -+ } -+ /* Save the current power mode */ -+ iter->pm_restore = true; -+ err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm, -+ sizeof(iter->pm), false); -+ WL_DBG(("%s:power save %s\n", iter->ndev->name, -+ iter->pm ? "enabled" : "disabled")); -+ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm, -+ sizeof(pm), true)) != 0) { -+ if (err == -ENODEV) -+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); -+ else -+ WL_ERR(("%s:error (%d)\n", iter->ndev->name, err)); -+ iter->ndev->ieee80211_ptr->ps = pm ? true: false; -+ } -+ } -+ } -+ else { /* clear */ -+ chan = 0; -+ /* clear chan information when the net device is disconnected */ -+ wl_update_prof(wl, _net_info->ndev, NULL, &chan, WL_PROF_CHAN); -+ wl_cfg80211_determine_vsdb_mode(wl); -+ for_each_ndev(wl, iter, next) { -+ if (iter->pm_restore) { -+ WL_DBG(("%s:restoring power save %s\n", -+ iter->ndev->name, (iter->pm ? "enabled" : "disabled"))); -+ err = wldev_ioctl(iter->ndev, -+ WLC_SET_PM, &iter->pm, sizeof(iter->pm), true); -+ if (unlikely(err)) { -+ if (err == -ENODEV) -+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name)); -+ else -+ WL_ERR(("%s:error(%d)\n", iter->ndev->name, err)); -+ break; -+ } -+ iter->pm_restore = 0; -+ } -+ } -+ wl_cfg80211_concurrent_roam(wl, 0); -+ } -+ return err; -+} -+ -+static s32 wl_init_scan(struct wl_priv *wl) -+{ -+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); -+ int err = 0; -+ -+ if (wl->iscan_on) { -+ iscan->dev = wl_to_prmry_ndev(wl); -+ iscan->state = WL_ISCAN_STATE_IDLE; -+ wl_init_iscan_handler(iscan); -+ iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; -+ init_timer(&iscan->timer); -+ iscan->timer.data = (unsigned long) iscan; -+ iscan->timer.function = wl_iscan_timer; -+ sema_init(&iscan->sync, 0); -+ iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan"); -+ if (IS_ERR(iscan->tsk)) { -+ WL_ERR(("Could not create iscan thread\n")); -+ iscan->tsk = NULL; -+ return -ENOMEM; -+ } -+ iscan->data = wl; -+ } else if (wl->escan_on) { -+ wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler; -+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; -+ } -+ /* Init scan_timeout timer */ -+ init_timer(&wl->scan_timeout); -+ wl->scan_timeout.data = (unsigned long) wl; -+ wl->scan_timeout.function = wl_scan_timeout; -+ -+ return err; -+} -+ -+static s32 wl_init_priv(struct wl_priv *wl) -+{ -+ struct wiphy *wiphy = wl_to_wiphy(wl); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ s32 err = 0; -+ -+ wl->scan_request = NULL; -+ wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); -+ wl->iscan_on = false; -+ wl->escan_on = true; -+ wl->roam_on = false; -+ wl->iscan_kickstart = false; -+ wl->active_scan = true; -+ wl->rf_blocked = false; -+ wl->vsdb_mode = false; -+ wl->wlfc_on = false; -+ wl->roamoff_on_concurrent = true; -+ /* register interested state */ -+ set_bit(WL_STATUS_CONNECTED, &wl->interrested_state); -+ spin_lock_init(&wl->cfgdrv_lock); -+ mutex_init(&wl->ioctl_buf_sync); -+ init_waitqueue_head(&wl->netif_change_event); -+ init_completion(&wl->send_af_done); -+ init_completion(&wl->iface_disable); -+ wl_init_eq(wl); -+ err = wl_init_priv_mem(wl); -+ if (err) -+ return err; -+ if (wl_create_event_handler(wl)) -+ return -ENOMEM; -+ wl_init_event_handler(wl); -+ mutex_init(&wl->usr_sync); -+ mutex_init(&wl->event_sync); -+ err = wl_init_scan(wl); -+ if (err) -+ return err; -+ wl_init_conf(wl->conf); -+ wl_init_prof(wl, ndev); -+ wl_link_down(wl); -+ DNGL_FUNC(dhd_cfg80211_init, (wl)); -+ -+ return err; -+} -+ -+static void wl_deinit_priv(struct wl_priv *wl) -+{ -+ DNGL_FUNC(dhd_cfg80211_deinit, (wl)); -+ wl_destroy_event_handler(wl); -+ wl_flush_eq(wl); -+ wl_link_down(wl); -+ del_timer_sync(&wl->scan_timeout); -+ wl_term_iscan(wl); -+ wl_deinit_priv_mem(wl); -+ unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); -+} -+ -+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) -+static s32 wl_cfg80211_attach_p2p(void) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+ WL_TRACE(("Enter \n")); -+ -+ if (wl_cfgp2p_register_ndev(wl) < 0) { -+ WL_ERR(("%s: P2P attach failed. \n", __func__)); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static s32 wl_cfg80211_detach_p2p(void) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct wireless_dev *wdev = wl->p2p_wdev; -+ -+ WL_DBG(("Enter \n")); -+ if (!wdev || !wl) { -+ WL_ERR(("Invalid Ptr\n")); -+ return -EINVAL; -+ } -+ -+ wl_cfgp2p_unregister_ndev(wl); -+ -+ wl->p2p_wdev = NULL; -+ wl->p2p_net = NULL; -+ WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev)); -+ kfree(wdev); -+ -+ return 0; -+} -+#endif /* defined(WLP2P) && defined(WL_ENABLE_P2P_IF) */ -+ -+s32 wl_cfg80211_attach_post(struct net_device *ndev) -+{ -+ struct wl_priv * wl = NULL; -+ s32 err = 0; -+ WL_TRACE(("In\n")); -+ if (unlikely(!ndev)) { -+ WL_ERR(("ndev is invaild\n")); -+ return -ENODEV; -+ } -+ wl = wlcfg_drv_priv; -+ if (unlikely(!wl)) { -+ WL_ERR(("wl is invaild\n")); -+ return -EINVAL; -+ } -+ if (!wl_get_drv_status(wl, READY, ndev)) { -+ if (wl->wdev && -+ wl_cfgp2p_supported(wl, ndev)) { -+#if !defined(WL_ENABLE_P2P_IF) -+ wl->wdev->wiphy->interface_modes |= -+ (BIT(NL80211_IFTYPE_P2P_CLIENT)| -+ BIT(NL80211_IFTYPE_P2P_GO)); -+#endif -+ if ((err = wl_cfgp2p_init_priv(wl)) != 0) -+ goto fail; -+ -+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) -+ if (wl->p2p_net) { -+ /* Update MAC addr for p2p0 interface here. */ -+ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); -+ wl->p2p_net->dev_addr[0] |= 0x02; -+ WL_ERR(("%s: p2p_dev_addr="MACDBG "\n", -+ wl->p2p_net->name, -+ MAC2STRDBG(wl->p2p_net->dev_addr))); -+ } else { -+ WL_ERR(("p2p_net not yet populated." -+ " Couldn't update the MAC Address for p2p0 \n")); -+ return -ENODEV; -+ } -+#endif /* defined(WLP2P) && (WL_ENABLE_P2P_IF) */ -+ -+ wl->p2p_supported = true; -+ } -+ } -+ wl_set_drv_status(wl, READY, ndev); -+fail: -+ return err; -+} -+ -+s32 wl_cfg80211_attach(struct net_device *ndev, void *data) -+{ -+ struct wireless_dev *wdev; -+ struct wl_priv *wl; -+ s32 err = 0; -+ struct device *dev; -+ -+ WL_TRACE(("In\n")); -+ if (!ndev) { -+ WL_ERR(("ndev is invaild\n")); -+ return -ENODEV; -+ } -+ WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); -+ dev = wl_cfg80211_get_parent_dev(); -+ -+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); -+ if (unlikely(!wdev)) { -+ WL_ERR(("Could not allocate wireless device\n")); -+ return -ENOMEM; -+ } -+ err = wl_setup_wiphy(wdev, dev); -+ if (unlikely(err)) { -+ kfree(wdev); -+ return -ENOMEM; -+ } -+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); -+ wl = (struct wl_priv *)wiphy_priv(wdev->wiphy); -+ wl->wdev = wdev; -+ wl->pub = data; -+ INIT_LIST_HEAD(&wl->net_list); -+ ndev->ieee80211_ptr = wdev; -+ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); -+ wdev->netdev = ndev; -+ wl->state_notifier = wl_notifier_change_state; -+ err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS, PM_ENABLE); -+ if (err) { -+ WL_ERR(("Failed to alloc net_info (%d)\n", err)); -+ goto cfg80211_attach_out; -+ } -+ err = wl_init_priv(wl); -+ if (err) { -+ WL_ERR(("Failed to init iwm_priv (%d)\n", err)); -+ goto cfg80211_attach_out; -+ } -+ -+ err = wl_setup_rfkill(wl, TRUE); -+ if (err) { -+ WL_ERR(("Failed to setup rfkill %d\n", err)); -+ goto cfg80211_attach_out; -+ } -+ err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); -+ if (err) { -+ WL_ERR(("Failed to register notifierl %d\n", err)); -+ goto cfg80211_attach_out; -+ } -+#if defined(COEX_DHCP) -+ err = wl_cfg80211_btcoex_init(wl); -+ if (err) -+ goto cfg80211_attach_out; -+#endif -+ -+ wlcfg_drv_priv = wl; -+ -+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) -+ err = wl_cfg80211_attach_p2p(); -+ if (err) -+ goto cfg80211_attach_out; -+#endif -+ -+ return err; -+ -+cfg80211_attach_out: -+ wl_setup_rfkill(wl, FALSE); -+ wl_free_wdev(wl); -+ return err; -+} -+ -+void wl_cfg80211_detach(void *para) -+{ -+ struct wl_priv *wl; -+ -+ (void)para; -+ wl = wlcfg_drv_priv; -+ -+ WL_TRACE(("In\n")); -+ -+#if defined(COEX_DHCP) -+ wl_cfg80211_btcoex_deinit(wl); -+#endif -+ -+ wl_setup_rfkill(wl, FALSE); -+ if (wl->p2p_supported) { -+ if (timer_pending(&wl->p2p->listen_timer)) -+ del_timer_sync(&wl->p2p->listen_timer); -+ wl_cfgp2p_deinit_priv(wl); -+ } -+ -+#if defined(WLP2P) && defined(WL_ENABLE_P2P_IF) -+ wl_cfg80211_detach_p2p(); -+#endif -+ wl_deinit_priv(wl); -+ wlcfg_drv_priv = NULL; -+ wl_cfg80211_clear_parent_dev(); -+ wl_free_wdev(wl); -+ /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl", -+ * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!! -+ */ -+} -+ -+static void wl_wakeup_event(struct wl_priv *wl) -+{ -+ if (wl->event_tsk.thr_pid >= 0) { -+ DHD_OS_WAKE_LOCK(wl->pub); -+ up(&wl->event_tsk.sema); -+ } -+} -+ -+static int wl_is_p2p_event(struct wl_event_q *e) -+{ -+ switch (e->etype) { -+ /* We have to seperate out the P2P events received -+ * on primary interface so that it can be send up -+ * via p2p0 interface. -+ */ -+ case WLC_E_P2P_PROBREQ_MSG: -+ case WLC_E_P2P_DISC_LISTEN_COMPLETE: -+ case WLC_E_ACTION_FRAME_RX: -+ case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE: -+ case WLC_E_ACTION_FRAME_COMPLETE: -+ -+ if (e->emsg.ifidx != 0) { -+ WL_TRACE(("P2P Event on Virtual I/F (ifidx:%d) \n", -+ e->emsg.ifidx)); -+ /* We are only bothered about the P2P events received -+ * on primary interface. For rest of them return false -+ * so that it is sent over the interface corresponding -+ * to the ifidx. -+ */ -+ return FALSE; -+ } else { -+ WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)." -+ " Sent it to p2p0 \n", e->emsg.ifidx)); -+ return TRUE; -+ } -+ break; -+ -+ default: -+ WL_TRACE(("NON-P2P Event %d on ifidx (ifidx:%d) \n", -+ e->etype, e->emsg.ifidx)); -+ return FALSE; -+ } -+} -+ -+static s32 wl_event_handler(void *data) -+{ -+ struct net_device *netdev; -+ struct wl_priv *wl = NULL; -+ struct wl_event_q *e; -+ tsk_ctl_t *tsk = (tsk_ctl_t *)data; -+ -+ wl = (struct wl_priv *)tsk->parent; -+ DAEMONIZE("dhd_cfg80211_event"); -+ complete(&tsk->completed); -+ -+ while (down_interruptible (&tsk->sema) == 0) { -+ SMP_RD_BARRIER_DEPENDS(); -+ if (tsk->terminated) -+ break; -+ while ((e = wl_deq_event(wl))) { -+ WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); -+ /* All P2P device address related events comes on primary interface since -+ * there is no corresponding bsscfg for P2P interface. Map it to p2p0 -+ * interface. -+ */ -+ if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) { -+ netdev = wl->p2p_net; -+ } else { -+ netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); -+ } -+ if (!netdev) -+ netdev = wl_to_prmry_ndev(wl); -+ if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { -+ wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); -+ } else { -+ WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); -+ } -+ wl_put_event(e); -+ } -+ DHD_OS_WAKE_UNLOCK(wl->pub); -+ } -+ WL_ERR(("%s was terminated\n", __func__)); -+ complete_and_exit(&tsk->completed, 0); -+ return 0; -+} -+ -+void -+wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) -+{ -+ u32 event_type = ntoh32(e->event_type); -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+#if (WL_DBG_LEVEL > 0) -+ s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? -+ wl_dbg_estr[event_type] : (s8 *) "Unknown"; -+ WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); -+#endif /* (WL_DBG_LEVEL > 0) */ -+ -+ if (event_type == WLC_E_PFN_NET_FOUND) { -+ WL_DBG((" PNOEVENT: PNO_NET_FOUND\n")); -+ } -+ else if (event_type == WLC_E_PFN_NET_LOST) { -+ WL_DBG((" PNOEVENT: PNO_NET_LOST\n")); -+ } -+ -+ if (likely(!wl_enq_event(wl, ndev, event_type, e, data))) -+ wl_wakeup_event(wl); -+} -+ -+static void wl_init_eq(struct wl_priv *wl) -+{ -+ wl_init_eq_lock(wl); -+ INIT_LIST_HEAD(&wl->eq_list); -+} -+ -+static void wl_flush_eq(struct wl_priv *wl) -+{ -+ struct wl_event_q *e; -+ unsigned long flags; -+ -+ flags = wl_lock_eq(wl); -+ while (!list_empty(&wl->eq_list)) { -+ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); -+ list_del(&e->eq_list); -+ kfree(e); -+ } -+ wl_unlock_eq(wl, flags); -+} -+ -+/* -+* retrieve first queued event from head -+*/ -+ -+static struct wl_event_q *wl_deq_event(struct wl_priv *wl) -+{ -+ struct wl_event_q *e = NULL; -+ unsigned long flags; -+ -+ flags = wl_lock_eq(wl); -+ if (likely(!list_empty(&wl->eq_list))) { -+ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list); -+ list_del(&e->eq_list); -+ } -+ wl_unlock_eq(wl, flags); -+ -+ return e; -+} -+ -+/* -+ * push event to tail of the queue -+ */ -+ -+static s32 -+wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_event_msg_t *msg, -+ void *data) -+{ -+ struct wl_event_q *e; -+ s32 err = 0; -+ uint32 evtq_size; -+ uint32 data_len; -+ unsigned long flags; -+ gfp_t aflags; -+ -+ data_len = 0; -+ if (data) -+ data_len = ntoh32(msg->datalen); -+ evtq_size = sizeof(struct wl_event_q) + data_len; -+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; -+ e = kzalloc(evtq_size, aflags); -+ if (unlikely(!e)) { -+ WL_ERR(("event alloc failed\n")); -+ return -ENOMEM; -+ } -+ e->etype = event; -+ memcpy(&e->emsg, msg, sizeof(wl_event_msg_t)); -+ if (data) -+ memcpy(e->edata, data, data_len); -+ flags = wl_lock_eq(wl); -+ list_add_tail(&e->eq_list, &wl->eq_list); -+ wl_unlock_eq(wl, flags); -+ -+ return err; -+} -+ -+static void wl_put_event(struct wl_event_q *e) -+{ -+ kfree(e); -+} -+ -+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype) -+{ -+ s32 infra = 0; -+ s32 err = 0; -+ s32 mode = 0; -+ switch (iftype) { -+ case NL80211_IFTYPE_MONITOR: -+ case NL80211_IFTYPE_WDS: -+ WL_ERR(("type (%d) : currently we do not support this mode\n", -+ iftype)); -+ err = -EINVAL; -+ return err; -+ case NL80211_IFTYPE_ADHOC: -+ mode = WL_MODE_IBSS; -+ break; -+ case NL80211_IFTYPE_STATION: -+ case NL80211_IFTYPE_P2P_CLIENT: -+ mode = WL_MODE_BSS; -+ infra = 1; -+ break; -+ case NL80211_IFTYPE_AP: -+ case NL80211_IFTYPE_P2P_GO: -+ mode = WL_MODE_AP; -+ infra = 1; -+ break; -+ default: -+ err = -EINVAL; -+ WL_ERR(("invalid type (%d)\n", iftype)); -+ return err; -+ } -+ infra = htod32(infra); -+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true); -+ if (unlikely(err)) { -+ WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); -+ return err; -+ } -+ -+ wl_set_mode_by_netdev(wl, ndev, mode); -+ -+ return 0; -+} -+ -+void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set) -+{ -+ if (!ev || (event > WLC_E_LAST)) -+ return; -+ -+ if (ev->num < MAX_EVENT_BUF_NUM) { -+ ev->event[ev->num].type = event; -+ ev->event[ev->num].set = set; -+ ev->num++; -+ } else { -+ WL_ERR(("evenbuffer doesn't support > %u events. Update" -+ " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM)); -+ ASSERT(0); -+ } -+} -+ -+s32 wl_cfg80211_apply_eventbuffer( -+ struct net_device *ndev, -+ struct wl_priv *wl, -+ wl_eventmsg_buf_t *ev) -+{ -+ char eventmask[WL_EVENTING_MASK_LEN]; -+ int i, ret = 0; -+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; -+ -+ if (!ev || (!ev->num)) -+ return -EINVAL; -+ -+ mutex_lock(&wl->event_sync); -+ -+ /* Read event_msgs mask */ -+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf, -+ sizeof(iovbuf)); -+ ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); -+ if (unlikely(ret)) { -+ WL_ERR(("Get event_msgs error (%d)\n", ret)); -+ goto exit; -+ } -+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); -+ -+ /* apply the set bits */ -+ for (i = 0; i < ev->num; i++) { -+ if (ev->event[i].set) -+ setbit(eventmask, ev->event[i].type); -+ else -+ clrbit(eventmask, ev->event[i].type); -+ } -+ -+ /* Write updated Event mask */ -+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, -+ sizeof(iovbuf)); -+ ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); -+ if (unlikely(ret)) { -+ WL_ERR(("Set event_msgs error (%d)\n", ret)); -+ } -+ -+exit: -+ mutex_unlock(&wl->event_sync); -+ return ret; -+} -+ -+s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) -+{ -+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; -+ s8 eventmask[WL_EVENTING_MASK_LEN]; -+ s32 err = 0; -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+ if (!ndev || !wl) -+ return -ENODEV; -+ -+ mutex_lock(&wl->event_sync); -+ -+ /* Setup event_msgs */ -+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf, -+ sizeof(iovbuf)); -+ err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); -+ if (unlikely(err)) { -+ WL_ERR(("Get event_msgs error (%d)\n", err)); -+ goto eventmsg_out; -+ } -+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); -+ if (add) { -+ setbit(eventmask, event); -+ } else { -+ clrbit(eventmask, event); -+ } -+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, -+ sizeof(iovbuf)); -+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); -+ if (unlikely(err)) { -+ WL_ERR(("Set event_msgs error (%d)\n", err)); -+ goto eventmsg_out; -+ } -+ -+eventmsg_out: -+ mutex_unlock(&wl->event_sync); -+ return err; -+} -+ -+static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap) -+{ -+ struct net_device *dev = wl_to_prmry_ndev(wl); -+ struct ieee80211_channel *band_chan_arr = NULL; -+ wl_uint32_list_t *list; -+ u32 i, j, index, n_2g, n_5g, band, channel, array_size; -+ u32 *n_cnt = NULL; -+ chanspec_t c = 0; -+ s32 err = BCME_OK; -+ bool update; -+ bool ht40_allowed; -+ u8 *pbuf = NULL; -+ -+#define LOCAL_BUF_LEN 1024 -+ pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL); -+ -+ if (pbuf == NULL) { -+ WL_ERR(("failed to allocate local buf\n")); -+ return -ENOMEM; -+ } -+ list = (wl_uint32_list_t *)(void *) pbuf; -+ list->count = htod32(WL_NUMCHANSPECS); -+ -+ -+ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, -+ 0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync); -+ if (err != 0) { -+ WL_ERR(("get chanspecs failed with %d\n", err)); -+ kfree(pbuf); -+ return err; -+ } -+#undef LOCAL_BUF_LEN -+ -+ list = (wl_uint32_list_t *)(void *)pbuf; -+ band = array_size = n_2g = n_5g = 0; -+ for (i = 0; i < dtoh32(list->count); i++) { -+ index = 0; -+ update = false; -+ ht40_allowed = false; -+ c = (chanspec_t)dtoh32(list->element[i]); -+ c = wl_chspec_driver_to_host(c); -+ channel = CHSPEC_CHANNEL(c); -+ if (CHSPEC_IS40(c)) { -+ if (CHSPEC_SB_UPPER(c)) -+ channel += CH_10MHZ_APART; -+ else -+ channel -= CH_10MHZ_APART; -+ } else if (CHSPEC_IS80(c)) { -+ WL_DBG(("HT80 center channel : %d\n", channel)); -+ continue; -+ } -+ if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && -+ (channel <= CH_MAX_2G_CHANNEL)) { -+ band_chan_arr = __wl_2ghz_channels; -+ array_size = ARRAYSIZE(__wl_2ghz_channels); -+ n_cnt = &n_2g; -+ band = IEEE80211_BAND_2GHZ; -+ ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false; -+ } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { -+ band_chan_arr = __wl_5ghz_a_channels; -+ array_size = ARRAYSIZE(__wl_5ghz_a_channels); -+ n_cnt = &n_5g; -+ band = IEEE80211_BAND_5GHZ; -+ ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true; -+ } else { -+ WL_ERR(("Invalid channel Sepc. 0x%x.\n", c)); -+ continue; -+ } -+ if (!ht40_allowed && CHSPEC_IS40(c)) -+ continue; -+ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { -+ if (band_chan_arr[j].hw_value == channel) { -+ update = true; -+ break; -+ } -+ } -+ if (update) -+ index = j; -+ else -+ index = *n_cnt; -+ if (index < array_size) { -+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) -+ band_chan_arr[index].center_freq = -+ ieee80211_channel_to_frequency(channel); -+#else -+ band_chan_arr[index].center_freq = -+ ieee80211_channel_to_frequency(channel, band); -+#endif -+ band_chan_arr[index].hw_value = channel; -+ -+ if (CHSPEC_IS40(c) && ht40_allowed) { -+ /* assuming the order is HT20, HT40 Upper, -+ HT40 lower from chanspecs -+ */ -+ u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40; -+ if (CHSPEC_SB_UPPER(c)) { -+ if (ht40_flag == IEEE80211_CHAN_NO_HT40) -+ band_chan_arr[index].flags &= -+ ~IEEE80211_CHAN_NO_HT40; -+ band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS; -+ } else { -+ /* It should be one of -+ IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS -+ */ -+ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40; -+ if (ht40_flag == IEEE80211_CHAN_NO_HT40) -+ band_chan_arr[index].flags |= -+ IEEE80211_CHAN_NO_HT40MINUS; -+ } -+ } else { -+ band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40; -+ if (band == IEEE80211_BAND_2GHZ) -+ channel |= WL_CHANSPEC_BAND_2G; -+ else -+ channel |= WL_CHANSPEC_BAND_5G; -+ channel |= WL_CHANSPEC_BW_20; -+ channel = wl_chspec_host_to_driver(channel); -+ err = wldev_iovar_getint(dev, "per_chan_info", &channel); -+ if (!err) { -+ if (channel & WL_CHAN_RADAR) -+ band_chan_arr[index].flags |= -+ (IEEE80211_CHAN_RADAR | -+ IEEE80211_CHAN_NO_IBSS); -+ if (channel & WL_CHAN_PASSIVE) -+ band_chan_arr[index].flags |= -+ IEEE80211_CHAN_PASSIVE_SCAN; -+ } -+ } -+ if (!update) -+ (*n_cnt)++; -+ } -+ -+ } -+ __wl_band_2ghz.n_channels = n_2g; -+ __wl_band_5ghz_a.n_channels = n_5g; -+ kfree(pbuf); -+ return err; -+} -+ -+s32 wl_update_wiphybands(struct wl_priv *wl, bool notify) -+{ -+ struct wiphy *wiphy; -+ struct net_device *dev; -+ u32 bandlist[3]; -+ u32 nband = 0; -+ u32 i = 0; -+ s32 err = 0; -+ s32 index = 0; -+ s32 nmode = 0; -+ bool rollback_lock = false; -+ s32 bw_cap = 0; -+ s32 cur_band = -1; -+ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, }; -+ -+ if (wl == NULL) { -+ wl = wlcfg_drv_priv; -+ mutex_lock(&wl->usr_sync); -+ rollback_lock = true; -+ } -+ dev = wl_to_prmry_ndev(wl); -+ -+ memset(bandlist, 0, sizeof(bandlist)); -+ err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist, -+ sizeof(bandlist), false); -+ if (unlikely(err)) { -+ WL_ERR(("error read bandlist (%d)\n", err)); -+ goto end_bands; -+ } -+ -+ wiphy = wl_to_wiphy(wl); -+ wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; -+ wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; -+ -+ err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band, -+ sizeof(s32), false); -+ if (unlikely(err)) { -+ WL_ERR(("error (%d)\n", err)); -+ goto end_bands; -+ } -+ -+ err = wldev_iovar_getint(dev, "nmode", &nmode); -+ if (unlikely(err)) { -+ WL_ERR(("error reading nmode (%d)\n", err)); -+ } else { -+ /* For nmodeonly check bw cap */ -+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap); -+ if (unlikely(err)) { -+ WL_ERR(("error get mimo_bw_cap (%d)\n", err)); -+ } -+ } -+ -+ err = wl_construct_reginfo(wl, bw_cap); -+ if (err) { -+ WL_ERR(("wl_construct_reginfo() fails err=%d\n", err)); -+ if (err != BCME_UNSUPPORTED) -+ goto end_bands; -+ /* Ignore error if "chanspecs" command is not supported */ -+ err = 0; -+ } -+ -+ nband = bandlist[0]; -+ -+ for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) { -+ index = -1; -+ if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) { -+ bands[IEEE80211_BAND_5GHZ] = -+ &__wl_band_5ghz_a; -+ index = IEEE80211_BAND_5GHZ; -+ if (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G) -+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; -+ } -+ else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) { -+ bands[IEEE80211_BAND_2GHZ] = -+ &__wl_band_2ghz; -+ index = IEEE80211_BAND_2GHZ; -+ if (bw_cap == WLC_N_BW_40ALL) -+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; -+ } -+ -+ if ((index >= 0) && nmode) { -+ bands[index]->ht_cap.cap |= -+ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40); -+ bands[index]->ht_cap.ht_supported = TRUE; -+ bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; -+ bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; -+ /* An HT shall support all EQM rates for one spatial stream */ -+ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; -+ } -+ -+ } -+ -+ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; -+ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; -+ -+ if (notify) -+ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); -+ -+end_bands: -+ if (rollback_lock) -+ mutex_unlock(&wl->usr_sync); -+ return err; -+} -+ -+static s32 __wl_cfg80211_up(struct wl_priv *wl) -+{ -+ s32 err = 0; -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ struct wireless_dev *wdev = ndev->ieee80211_ptr; -+ -+ WL_DBG(("In\n")); -+ -+ err = dhd_config_dongle(wl, false); -+ if (unlikely(err)) -+ return err; -+ -+ err = wl_config_ifmode(wl, ndev, wdev->iftype); -+ if (unlikely(err && err != -EINPROGRESS)) { -+ WL_ERR(("wl_config_ifmode failed\n")); -+ } -+ err = wl_update_wiphybands(wl, true); -+ if (unlikely(err)) { -+ WL_ERR(("wl_update_wiphybands failed\n")); -+ } -+ -+ err = dhd_monitor_init(wl->pub); -+ err = wl_invoke_iscan(wl); -+ -+#ifdef WL_HOST_BAND_MGMT -+ /* By default the curr_band is initialized to BAND_AUTO */ -+ if (wl_cfg80211_set_band(ndev, WLC_BAND_AUTO) < 0) { -+ WL_ERR(("roam_band set failed\n")); -+ err = -1; -+ } -+#endif /* WL_HOST_BAND_MGMT */ -+ -+#if defined(DHCP_SCAN_SUPPRESS) -+ /* wlan scan_supp timer and work thread info */ -+ init_timer(&wl->scan_supp_timer); -+ wl->scan_supp_timer.data = (ulong)wl; -+ wl->scan_supp_timer.function = wl_cfg80211_scan_supp_timerfunc; -+ INIT_WORK(&wl->wlan_work, wl_cfg80211_work_handler); -+#endif /* DHCP_SCAN_SUPPRESS */ -+ -+ wl_set_drv_status(wl, READY, ndev); -+ return err; -+} -+ -+static s32 __wl_cfg80211_down(struct wl_priv *wl) -+{ -+ s32 err = 0; -+ unsigned long flags; -+ struct net_info *iter, *next; -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ struct net_device *p2p_net = wl->p2p_net; -+ u32 bssidx = wl_cfgp2p_find_idx(wl, ndev); -+ WL_DBG(("In\n")); -+ -+#if defined(DHCP_SCAN_SUPPRESS) -+ /* Force clear of scan_suppress */ -+ if (wl->scan_suppressed) -+ wl_cfg80211_scan_suppress(ndev, 0); -+ if (timer_pending(&wl->scan_supp_timer)) -+ del_timer_sync(&wl->scan_supp_timer); -+ cancel_work_sync(&wl->wlan_work); -+#endif /* DHCP_SCAN_SUPPRESS */ -+ -+ /* If BSS is operational (e.g SoftAp), bring it down */ -+ if (wl_cfgp2p_bss_isup(ndev, bssidx)) { -+ if (wl_cfgp2p_bss(wl, ndev, bssidx, 0) < 0) -+ WL_ERR(("BSS down failed \n")); -+ } -+ -+ /* Check if cfg80211 interface is already down */ -+ if (!wl_get_drv_status(wl, READY, ndev)) -+ return err; /* it is even not ready */ -+ -+ for_each_ndev(wl, iter, next) -+ wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); -+ -+ wl_term_iscan(wl); -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ if (wl->scan_request) { -+ cfg80211_scan_done(wl->scan_request, true); -+ wl->scan_request = NULL; -+ } -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ -+ for_each_ndev(wl, iter, next) { -+ wl_clr_drv_status(wl, READY, iter->ndev); -+ wl_clr_drv_status(wl, SCANNING, iter->ndev); -+ wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); -+ wl_clr_drv_status(wl, CONNECTING, iter->ndev); -+ wl_clr_drv_status(wl, CONNECTED, iter->ndev); -+ wl_clr_drv_status(wl, DISCONNECTING, iter->ndev); -+ wl_clr_drv_status(wl, AP_CREATED, iter->ndev); -+ wl_clr_drv_status(wl, AP_CREATING, iter->ndev); -+ } -+ wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = -+ NL80211_IFTYPE_STATION; -+ if (p2p_net) -+ dev_close(p2p_net); -+ DNGL_FUNC(dhd_cfg80211_down, (wl)); -+ wl_flush_eq(wl); -+ wl_link_down(wl); -+ if (wl->p2p_supported) -+ wl_cfgp2p_down(wl); -+ dhd_monitor_uninit(); -+ -+ return err; -+} -+ -+s32 wl_cfg80211_up(void *para) -+{ -+ struct wl_priv *wl; -+ s32 err = 0; -+ int val = 1; -+ dhd_pub_t *dhd; -+ -+ (void)para; -+ WL_DBG(("In\n")); -+ wl = wlcfg_drv_priv; -+ -+ if ((err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_VERSION, &val, -+ sizeof(int), false) < 0)) { -+ WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); -+ return err; -+ } -+ val = dtoh32(val); -+ if (val != WLC_IOCTL_VERSION && val != 1) { -+ WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", -+ val, WLC_IOCTL_VERSION)); -+ return BCME_VERSION; -+ } -+ ioctl_version = val; -+ WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version)); -+ -+ mutex_lock(&wl->usr_sync); -+ dhd = (dhd_pub_t *)(wl->pub); -+ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) { -+ err = wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); -+ if (unlikely(err)) -+ return err; -+ } -+ err = __wl_cfg80211_up(wl); -+ if (unlikely(err)) -+ WL_ERR(("__wl_cfg80211_up failed\n")); -+ mutex_unlock(&wl->usr_sync); -+ return err; -+} -+ -+/* Private Event to Supplicant with indication that chip hangs */ -+int wl_cfg80211_hang(struct net_device *dev, u16 reason) -+{ -+ struct wl_priv *wl; -+ wl = wlcfg_drv_priv; -+ -+ WL_ERR(("In : chip crash eventing\n")); -+ cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); -+ if (wl != NULL) { -+ wl_link_down(wl); -+ } -+ return 0; -+} -+ -+s32 wl_cfg80211_down(void *para) -+{ -+ struct wl_priv *wl; -+ s32 err = 0; -+ -+ (void)para; -+ WL_DBG(("In\n")); -+ wl = wlcfg_drv_priv; -+ mutex_lock(&wl->usr_sync); -+ err = __wl_cfg80211_down(wl); -+ mutex_unlock(&wl->usr_sync); -+ -+ return err; -+} -+ -+static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item) -+{ -+ unsigned long flags; -+ void *rptr = NULL; -+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); -+ -+ if (!profile) -+ return NULL; -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ switch (item) { -+ case WL_PROF_SEC: -+ rptr = &profile->sec; -+ break; -+ case WL_PROF_ACT: -+ rptr = &profile->active; -+ break; -+ case WL_PROF_BSSID: -+ rptr = profile->bssid; -+ break; -+ case WL_PROF_SSID: -+ rptr = &profile->ssid; -+ break; -+ case WL_PROF_CHAN: -+ rptr = &profile->channel; -+ break; -+ } -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ if (!rptr) -+ WL_ERR(("invalid item (%d)\n", item)); -+ return rptr; -+} -+ -+static s32 -+wl_update_prof(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data, s32 item) -+{ -+ s32 err = 0; -+ struct wlc_ssid *ssid; -+ unsigned long flags; -+ struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); -+ -+ if (!profile) -+ return WL_INVALID; -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ switch (item) { -+ case WL_PROF_SSID: -+ ssid = (wlc_ssid_t *) data; -+ memset(profile->ssid.SSID, 0, -+ sizeof(profile->ssid.SSID)); -+ memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len); -+ profile->ssid.SSID_len = ssid->SSID_len; -+ break; -+ case WL_PROF_BSSID: -+ if (data) -+ memcpy(profile->bssid, data, ETHER_ADDR_LEN); -+ else -+ memset(profile->bssid, 0, ETHER_ADDR_LEN); -+ break; -+ case WL_PROF_SEC: -+ memcpy(&profile->sec, data, sizeof(profile->sec)); -+ break; -+ case WL_PROF_ACT: -+ profile->active = *(bool *)data; -+ break; -+ case WL_PROF_BEACONINT: -+ profile->beacon_interval = *(u16 *)data; -+ break; -+ case WL_PROF_DTIMPERIOD: -+ profile->dtim_period = *(u8 *)data; -+ break; -+ case WL_PROF_CHAN: -+ profile->channel = *(u32*)data; -+ break; -+ default: -+ err = -EOPNOTSUPP; -+ break; -+ } -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ -+ if (err == EOPNOTSUPP) -+ WL_ERR(("unsupported item (%d)\n", item)); -+ -+ return err; -+} -+ -+void wl_cfg80211_dbg_level(u32 level) -+{ -+ /* -+ * prohibit to change debug level -+ * by insmod parameter. -+ * eventually debug level will be configured -+ * in compile time by using CONFIG_XXX -+ */ -+ /* wl_dbg_level = level; */ -+} -+ -+static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev) -+{ -+ return wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS; -+} -+ -+static __used bool wl_is_ibssstarter(struct wl_priv *wl) -+{ -+ return wl->ibss_starter; -+} -+ -+static void wl_rst_ie(struct wl_priv *wl) -+{ -+ struct wl_ie *ie = wl_to_ie(wl); -+ -+ ie->offset = 0; -+} -+ -+static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v) -+{ -+ struct wl_ie *ie = wl_to_ie(wl); -+ s32 err = 0; -+ -+ if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) { -+ WL_ERR(("ei crosses buffer boundary\n")); -+ return -ENOSPC; -+ } -+ ie->buf[ie->offset] = t; -+ ie->buf[ie->offset + 1] = l; -+ memcpy(&ie->buf[ie->offset + 2], v, l); -+ ie->offset += l + 2; -+ -+ return err; -+} -+ -+static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size) -+{ -+ struct wl_ie *ie = wl_to_ie(wl); -+ s32 err = 0; -+ -+ if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) { -+ WL_ERR(("ei_stream crosses buffer boundary\n")); -+ return -ENOSPC; -+ } -+ memcpy(&ie->buf[ie->offset], ie_stream, ie_size); -+ ie->offset += ie_size; -+ -+ return err; -+} -+ -+static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size) -+{ -+ struct wl_ie *ie = wl_to_ie(wl); -+ s32 err = 0; -+ -+ if (unlikely(ie->offset > dst_size)) { -+ WL_ERR(("dst_size is not enough\n")); -+ return -ENOSPC; -+ } -+ memcpy(dst, &ie->buf[0], ie->offset); -+ -+ return err; -+} -+ -+static u32 wl_get_ielen(struct wl_priv *wl) -+{ -+ struct wl_ie *ie = wl_to_ie(wl); -+ -+ return ie->offset; -+} -+ -+static void wl_link_up(struct wl_priv *wl) -+{ -+ wl->link_up = true; -+} -+ -+static void wl_link_down(struct wl_priv *wl) -+{ -+ struct wl_connect_info *conn_info = wl_to_conn(wl); -+ -+ WL_DBG(("In\n")); -+ wl->link_up = false; -+ conn_info->req_ie_len = 0; -+ conn_info->resp_ie_len = 0; -+} -+ -+static unsigned long wl_lock_eq(struct wl_priv *wl) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&wl->eq_lock, flags); -+ return flags; -+} -+ -+static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags) -+{ -+ spin_unlock_irqrestore(&wl->eq_lock, flags); -+} -+ -+static void wl_init_eq_lock(struct wl_priv *wl) -+{ -+ spin_lock_init(&wl->eq_lock); -+} -+ -+static void wl_delay(u32 ms) -+{ -+ if (in_atomic() || (ms < jiffies_to_msecs(1))) { -+ mdelay(ms); -+ } else { -+ msleep(ms); -+ } -+} -+ -+s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ struct ether_addr p2pif_addr; -+ struct ether_addr primary_mac; -+ if (!wl->p2p) -+ return -1; -+ if (!p2p_is_on(wl)) { -+ get_primary_mac(wl, &primary_mac); -+ wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); -+ } else { -+ memcpy(p2pdev_addr->octet, -+ wl->p2p->dev_addr.octet, ETHER_ADDR_LEN); -+ } -+ -+ -+ return 0; -+} -+s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) -+{ -+ struct wl_priv *wl; -+ -+ wl = wlcfg_drv_priv; -+ -+ return wl_cfgp2p_set_p2p_noa(wl, net, buf, len); -+} -+ -+s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) -+{ -+ struct wl_priv *wl; -+ wl = wlcfg_drv_priv; -+ -+ return wl_cfgp2p_get_p2p_noa(wl, net, buf, len); -+} -+ -+s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) -+{ -+ struct wl_priv *wl; -+ wl = wlcfg_drv_priv; -+ -+ return wl_cfgp2p_set_p2p_ps(wl, net, buf, len); -+} -+ -+s32 wl_cfg80211_channel_to_freq(u32 channel) -+{ -+ int freq = 0; -+ -+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) -+ freq = ieee80211_channel_to_frequency(channel); -+#else -+ { -+ u16 band = 0; -+ if (channel <= CH_MAX_2G_CHANNEL) -+ band = IEEE80211_BAND_2GHZ; -+ else -+ band = IEEE80211_BAND_5GHZ; -+ freq = ieee80211_channel_to_frequency(channel, band); -+ } -+#endif -+ return freq; -+} -+ -+s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, -+ enum wl_management_type type) -+{ -+ struct wl_priv *wl; -+ struct net_device *ndev = NULL; -+ struct ether_addr primary_mac; -+ s32 ret = 0; -+ s32 bssidx = 0; -+ s32 pktflag = 0; -+ wl = wlcfg_drv_priv; -+ -+ if (wl_get_drv_status(wl, AP_CREATING, net) || -+ wl_get_drv_status(wl, AP_CREATED, net)) { -+ ndev = net; -+ bssidx = 0; -+ } else if (wl->p2p) { -+ if (net == wl->p2p_net) { -+ net = wl_to_prmry_ndev(wl); -+ } -+ if (!wl->p2p->on) { -+ get_primary_mac(wl, &primary_mac); -+ wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, -+ &wl->p2p->int_addr); -+ /* In case of p2p_listen command, supplicant send remain_on_channel -+ * without turning on P2P -+ */ -+ -+ p2p_on(wl) = true; -+ ret = wl_cfgp2p_enable_discovery(wl, net, NULL, 0); -+ -+ if (unlikely(ret)) { -+ goto exit; -+ } -+ } -+ if (net != wl_to_prmry_ndev(wl)) { -+ if (wl_get_mode_by_netdev(wl, net) == WL_MODE_AP) { -+ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); -+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION); -+ } -+ } else { -+ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); -+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); -+ } -+ } -+ if (ndev != NULL) { -+ switch (type) { -+ case WL_BEACON: -+ pktflag = VNDR_IE_BEACON_FLAG; -+ break; -+ case WL_PROBE_RESP: -+ pktflag = VNDR_IE_PRBRSP_FLAG; -+ break; -+ case WL_ASSOC_RESP: -+ pktflag = VNDR_IE_ASSOCRSP_FLAG; -+ break; -+ } -+ if (pktflag) -+ ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len); -+ } -+exit: -+ return ret; -+} -+ -+static const struct rfkill_ops wl_rfkill_ops = { -+ .set_block = wl_rfkill_set -+}; -+ -+static int wl_rfkill_set(void *data, bool blocked) -+{ -+ struct wl_priv *wl = (struct wl_priv *)data; -+ -+ WL_DBG(("Enter \n")); -+ WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); -+ -+ if (!wl) -+ return -EINVAL; -+ -+ wl->rf_blocked = blocked; -+ -+ return 0; -+} -+ -+static int wl_setup_rfkill(struct wl_priv *wl, bool setup) -+{ -+ s32 err = 0; -+ -+ WL_DBG(("Enter \n")); -+ if (!wl) -+ return -EINVAL; -+ if (setup) { -+ wl->rfkill = rfkill_alloc("brcmfmac-wifi", -+ wl_cfg80211_get_parent_dev(), -+ RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl); -+ -+ if (!wl->rfkill) { -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ err = rfkill_register(wl->rfkill); -+ -+ if (err) -+ rfkill_destroy(wl->rfkill); -+ } else { -+ if (!wl->rfkill) { -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ rfkill_unregister(wl->rfkill); -+ rfkill_destroy(wl->rfkill); -+ } -+ -+err_out: -+ return err; -+} -+ -+struct device *wl_cfg80211_get_parent_dev(void) -+{ -+ return cfg80211_parent_dev; -+} -+ -+void wl_cfg80211_set_parent_dev(void *dev) -+{ -+ cfg80211_parent_dev = dev; -+} -+ -+static void wl_cfg80211_clear_parent_dev(void) -+{ -+ cfg80211_parent_dev = NULL; -+} -+ -+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) -+{ -+ wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL, -+ 0, wl->ioctl_buf, WLC_IOCTL_SMLEN, 0, &wl->ioctl_buf_sync); -+ memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN); -+} -+ -+int wl_cfg80211_do_driver_init(struct net_device *net) -+{ -+ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); -+ -+ if (!wl || !wl->wdev) -+ return -EINVAL; -+ -+ if (dhd_do_driver_init(wl->wdev->netdev) < 0) -+ return -1; -+ -+ return 0; -+} -+ -+void wl_cfg80211_enable_trace(bool set, u32 level) -+{ -+ if (set) -+ wl_dbg_level = level & WL_DBG_LEVEL; -+ else -+ wl_dbg_level |= (WL_DBG_LEVEL & level); -+} -+ -+static s32 -+wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, -+ struct net_device *dev, u64 cookie) -+{ -+ /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION -+ * is passed with CMD_FRAME. This callback is supposed to cancel -+ * the OFFCHANNEL Wait. Since we are already taking care of that -+ * with the tx_mgmt logic, do nothing here. -+ */ -+ -+ return 0; -+} -+ -+#ifdef WL_HOST_BAND_MGMT -+s32 -+wl_cfg80211_set_band(struct net_device *ndev, int band) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ int ret = 0; -+ char ioctl_buf[50]; -+ -+ if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) { -+ WL_ERR(("Invalid band\n")); -+ return -EINVAL; -+ } -+ -+ if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band, -+ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) { -+ WL_ERR(("seting roam_band failed code=%d\n", ret)); -+ return ret; -+ } -+ -+ WL_DBG(("Setting band to %d\n", band)); -+ wl->curr_band = band; -+ -+ return 0; -+} -+#endif /* WL_HOST_BAND_MGMT */ -+ -+#if defined(DHCP_SCAN_SUPPRESS) -+static void wl_cfg80211_scan_supp_timerfunc(ulong data) -+{ -+ struct wl_priv *wl = (struct wl_priv *)data; -+ -+ WL_DBG(("Enter \n")); -+ schedule_work(&wl->wlan_work); -+} -+ -+static void wl_cfg80211_work_handler(struct work_struct *work) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ -+ wl = container_of(work, struct wl_priv, wlan_work); -+ -+ if (!wl) { -+ WL_ERR(("wl_priv ptr NULL\n")); -+ return; -+ } -+ -+ if (wl->scan_suppressed) { -+ /* There is pending scan_suppress. Clean it */ -+ WL_ERR(("Clean up from timer after %d msec\n", WL_SCAN_SUPPRESS_TIMEOUT)); -+ wl_cfg80211_scan_suppress(wl_to_prmry_ndev(wl), 0); -+ } -+} -+ -+int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress) -+{ -+ struct wl_priv *wl = wlcfg_drv_priv; -+ int ret = 0; -+ -+ if (!dev || !wl || ((suppress != 0) && (suppress != 1))) -+ return -EINVAL; -+ -+ if (suppress == wl->scan_suppressed) { -+ WL_DBG(("No change in scan_suppress state. Ignoring cmd..\n")); -+ return 0; -+ } -+ -+ if (timer_pending(&wl->scan_supp_timer)) -+ del_timer_sync(&wl->scan_supp_timer); -+ -+ if ((ret = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS, -+ &suppress, sizeof(int), true)) < 0) { -+ WL_ERR(("Scan suppress setting failed ret:%d \n", ret)); -+ } else { -+ WL_DBG(("Scan suppress %s \n", suppress ? "Enabled" : "Disabled")); -+ wl->scan_suppressed = suppress; -+ } -+ -+ /* If scan_suppress is set, Start a timer to monitor it (just incase) */ -+ if (wl->scan_suppressed) { -+ if (ret) { -+ WL_ERR(("Retry scan_suppress reset at a later time \n")); -+ mod_timer(&wl->scan_supp_timer, -+ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_RETRY)); -+ } else { -+ WL_DBG(("Start wlan_timer to clear of scan_suppress \n")); -+ mod_timer(&wl->scan_supp_timer, -+ jiffies + msecs_to_jiffies(WL_SCAN_SUPPRESS_TIMEOUT)); -+ } -+ } -+ -+ return ret; -+} -+#endif /* DHCP_SCAN_SUPPRESS */ -diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h -new file mode 100644 -index 00000000..fc300899 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h -@@ -0,0 +1,850 @@ -+/* -+ * Linux cfg80211 driver -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_cfg80211.h 378667 2013-01-14 10:11:50Z $ -+ */ -+ -+#ifndef _wl_cfg80211_h_ -+#define _wl_cfg80211_h_ -+ -+#include <linux/wireless.h> -+#include <typedefs.h> -+#include <proto/ethernet.h> -+#include <wlioctl.h> -+#include <linux/wireless.h> -+#include <net/cfg80211.h> -+#include <linux/rfkill.h> -+ -+#include <wl_cfgp2p.h> -+ -+struct wl_conf; -+struct wl_iface; -+struct wl_priv; -+struct wl_security; -+struct wl_ibss; -+ -+ -+#define htod32(i) i -+#define htod16(i) i -+#define dtoh32(i) i -+#define dtoh16(i) i -+#define htodchanspec(i) i -+#define dtohchanspec(i) i -+ -+#define WL_DBG_NONE 0 -+#define WL_DBG_P2P_ACTION (1 << 5) -+#define WL_DBG_TRACE (1 << 4) -+#define WL_DBG_SCAN (1 << 3) -+#define WL_DBG_DBG (1 << 2) -+#define WL_DBG_INFO (1 << 1) -+#define WL_DBG_ERR (1 << 0) -+ -+/* 0 invalidates all debug messages. default is 1 */ -+#define WL_DBG_LEVEL 0xFF -+ -+#define CFG80211_ERROR_TEXT "CFG80211-ERROR) " -+ -+#if defined(DHD_DEBUG) -+#define WL_ERR(args) \ -+do { \ -+ if (wl_dbg_level & WL_DBG_ERR) { \ -+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ -+ printk args; \ -+ } \ -+} while (0) -+#else /* defined(DHD_DEBUG) */ -+#define WL_ERR(args) \ -+do { \ -+ if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \ -+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \ -+ printk args; \ -+ } \ -+} while (0) -+#endif /* defined(DHD_DEBUG) */ -+ -+#ifdef WL_INFO -+#undef WL_INFO -+#endif -+#define WL_INFO(args) \ -+do { \ -+ if (wl_dbg_level & WL_DBG_INFO) { \ -+ printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \ -+ printk args; \ -+ } \ -+} while (0) -+#ifdef WL_SCAN -+#undef WL_SCAN -+#endif -+#define WL_SCAN(args) \ -+do { \ -+ if (wl_dbg_level & WL_DBG_SCAN) { \ -+ printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \ -+ printk args; \ -+ } \ -+} while (0) -+#ifdef WL_TRACE -+#undef WL_TRACE -+#endif -+#define WL_TRACE(args) \ -+do { \ -+ if (wl_dbg_level & WL_DBG_TRACE) { \ -+ printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \ -+ printk args; \ -+ } \ -+} while (0) -+#ifdef WL_TRACE_HW4 -+#undef WL_TRACE_HW4 -+#endif -+#define WL_TRACE_HW4 WL_TRACE -+#if (WL_DBG_LEVEL > 0) -+#define WL_DBG(args) \ -+do { \ -+ if (wl_dbg_level & WL_DBG_DBG) { \ -+ printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \ -+ printk args; \ -+ } \ -+} while (0) -+#else /* !(WL_DBG_LEVEL > 0) */ -+#define WL_DBG(args) -+#endif /* (WL_DBG_LEVEL > 0) */ -+#define WL_PNO(x) -+#define WL_SD(x) -+ -+ -+#define WL_SCAN_RETRY_MAX 3 -+#define WL_NUM_PMKIDS_MAX MAXPMKID -+#define WL_SCAN_BUF_MAX (1024 * 8) -+#define WL_TLV_INFO_MAX 1500 -+#define WL_SCAN_IE_LEN_MAX 2048 -+#define WL_BSS_INFO_MAX 2048 -+#define WL_ASSOC_INFO_MAX 512 -+#define WL_IOCTL_LEN_MAX 1024 -+#define WL_EXTRA_BUF_MAX 2048 -+#define WL_ISCAN_BUF_MAX 2048 -+#define WL_ISCAN_TIMER_INTERVAL_MS 3000 -+#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) -+#define WL_AP_MAX 256 -+#define WL_FILE_NAME_MAX 256 -+#define WL_DWELL_TIME 200 -+#define WL_MED_DWELL_TIME 400 -+#define WL_MIN_DWELL_TIME 100 -+#define WL_LONG_DWELL_TIME 1000 -+#define IFACE_MAX_CNT 2 -+#define WL_SCAN_CONNECT_DWELL_TIME_MS 200 -+#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 -+#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 -+#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 -+#define WL_AF_TX_MAX_RETRY 5 -+ -+#define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ -+#define WL_CHANNEL_SYNC_RETRY 5 -+#define WL_INVALID -1 -+ -+/* Bring down SCB Timeout to 20secs from 60secs default */ -+#ifndef WL_SCB_TIMEOUT -+#define WL_SCB_TIMEOUT 20 -+#endif -+ -+/* SCAN_SUPPRESS timer values in ms */ -+#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */ -+#define WL_SCAN_SUPPRESS_RETRY 3000 -+ -+/* driver status */ -+enum wl_status { -+ WL_STATUS_READY = 0, -+ WL_STATUS_SCANNING, -+ WL_STATUS_SCAN_ABORTING, -+ WL_STATUS_CONNECTING, -+ WL_STATUS_CONNECTED, -+ WL_STATUS_DISCONNECTING, -+ WL_STATUS_AP_CREATING, -+ WL_STATUS_AP_CREATED, -+ /* whole sending action frame procedure: -+ * includes a) 'finding common channel' for public action request frame -+ * and b) 'sending af via 'actframe' iovar' -+ */ -+ WL_STATUS_SENDING_ACT_FRM, -+ /* find a peer to go to a common channel before sending public action req frame */ -+ WL_STATUS_FINDING_COMMON_CHANNEL, -+ /* waiting for next af to sync time of supplicant. -+ * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN -+ */ -+ WL_STATUS_WAITING_NEXT_ACT_FRM, -+#ifdef WL_CFG80211_SYNC_GON -+ /* go to listen state to wait for next af after SENDING_ACT_FRM */ -+ WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN, -+#endif /* WL_CFG80211_SYNC_GON */ -+ /* it will be set when upper layer requests listen and succeed in setting listen mode. -+ * if set, other scan request can abort current listen state -+ */ -+ WL_STATUS_REMAINING_ON_CHANNEL, -+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ /* it's fake listen state to keep current scan state. -+ * it will be set when upper layer requests listen but scan is running. then just run -+ * a expire timer without actual listen state. -+ * if set, other scan request does not need to abort scan. -+ */ -+ WL_STATUS_FAKE_REMAINING_ON_CHANNEL -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+}; -+ -+/* wi-fi mode */ -+enum wl_mode { -+ WL_MODE_BSS, -+ WL_MODE_IBSS, -+ WL_MODE_AP -+}; -+ -+/* driver profile list */ -+enum wl_prof_list { -+ WL_PROF_MODE, -+ WL_PROF_SSID, -+ WL_PROF_SEC, -+ WL_PROF_IBSS, -+ WL_PROF_BAND, -+ WL_PROF_CHAN, -+ WL_PROF_BSSID, -+ WL_PROF_ACT, -+ WL_PROF_BEACONINT, -+ WL_PROF_DTIMPERIOD -+}; -+ -+/* driver iscan state */ -+enum wl_iscan_state { -+ WL_ISCAN_STATE_IDLE, -+ WL_ISCAN_STATE_SCANING -+}; -+ -+/* donlge escan state */ -+enum wl_escan_state { -+ WL_ESCAN_STATE_IDLE, -+ WL_ESCAN_STATE_SCANING -+}; -+/* fw downloading status */ -+enum wl_fw_status { -+ WL_FW_LOADING_DONE, -+ WL_NVRAM_LOADING_DONE -+}; -+ -+enum wl_management_type { -+ WL_BEACON = 0x1, -+ WL_PROBE_RESP = 0x2, -+ WL_ASSOC_RESP = 0x4 -+}; -+/* beacon / probe_response */ -+struct beacon_proberesp { -+ __le64 timestamp; -+ __le16 beacon_int; -+ __le16 capab_info; -+ u8 variable[0]; -+} __attribute__ ((packed)); -+ -+/* driver configuration */ -+struct wl_conf { -+ u32 frag_threshold; -+ u32 rts_threshold; -+ u32 retry_short; -+ u32 retry_long; -+ s32 tx_power; -+ struct ieee80211_channel channel; -+}; -+ -+typedef s32(*EVENT_HANDLER) (struct wl_priv *wl, -+ struct net_device *ndev, const wl_event_msg_t *e, void *data); -+ -+/* bss inform structure for cfg80211 interface */ -+struct wl_cfg80211_bss_info { -+ u16 band; -+ u16 channel; -+ s16 rssi; -+ u16 frame_len; -+ u8 frame_buf[1]; -+}; -+ -+/* basic structure of scan request */ -+struct wl_scan_req { -+ struct wlc_ssid ssid; -+}; -+ -+/* basic structure of information element */ -+struct wl_ie { -+ u16 offset; -+ u8 buf[WL_TLV_INFO_MAX]; -+}; -+ -+/* event queue for cfg80211 main event */ -+struct wl_event_q { -+ struct list_head eq_list; -+ u32 etype; -+ wl_event_msg_t emsg; -+ s8 edata[1]; -+}; -+ -+/* security information with currently associated ap */ -+struct wl_security { -+ u32 wpa_versions; -+ u32 auth_type; -+ u32 cipher_pairwise; -+ u32 cipher_group; -+ u32 wpa_auth; -+ u32 auth_assoc_res_status; -+}; -+ -+/* ibss information for currently joined ibss network */ -+struct wl_ibss { -+ u8 beacon_interval; /* in millisecond */ -+ u8 atim; /* in millisecond */ -+ s8 join_only; -+ u8 band; -+ u8 channel; -+}; -+ -+/* wl driver profile */ -+struct wl_profile { -+ u32 mode; -+ s32 band; -+ u32 channel; -+ struct wlc_ssid ssid; -+ struct wl_security sec; -+ struct wl_ibss ibss; -+ u8 bssid[ETHER_ADDR_LEN]; -+ u16 beacon_interval; -+ u8 dtim_period; -+ bool active; -+}; -+ -+struct net_info { -+ struct net_device *ndev; -+ struct wireless_dev *wdev; -+ struct wl_profile profile; -+ s32 mode; -+ s32 roam_off; -+ unsigned long sme_state; -+ bool pm_restore; -+ bool pm_block; -+ s32 pm; -+ struct list_head list; /* list of all net_info structure */ -+}; -+typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); -+ -+/* iscan controller */ -+struct wl_iscan_ctrl { -+ struct net_device *dev; -+ struct timer_list timer; -+ u32 timer_ms; -+ u32 timer_on; -+ s32 state; -+ struct task_struct *tsk; -+ struct semaphore sync; -+ ISCAN_HANDLER iscan_handler[WL_SCAN_ERSULTS_LAST]; -+ void *data; -+ s8 ioctl_buf[WLC_IOCTL_SMLEN]; -+ s8 scan_buf[WL_ISCAN_BUF_MAX]; -+}; -+ -+/* association inform */ -+#define MAX_REQ_LINE 1024 -+struct wl_connect_info { -+ u8 req_ie[MAX_REQ_LINE]; -+ s32 req_ie_len; -+ u8 resp_ie[MAX_REQ_LINE]; -+ s32 resp_ie_len; -+}; -+ -+/* firmware /nvram downloading controller */ -+struct wl_fw_ctrl { -+ const struct firmware *fw_entry; -+ unsigned long status; -+ u32 ptr; -+ s8 fw_name[WL_FILE_NAME_MAX]; -+ s8 nvram_name[WL_FILE_NAME_MAX]; -+}; -+ -+/* assoc ie length */ -+struct wl_assoc_ielen { -+ u32 req_len; -+ u32 resp_len; -+}; -+ -+/* wpa2 pmk list */ -+struct wl_pmk_list { -+ pmkid_list_t pmkids; -+ pmkid_t foo[MAXPMKID - 1]; -+}; -+ -+ -+#define ESCAN_BUF_SIZE (64 * 1024) -+ -+struct escan_info { -+ u32 escan_state; -+#if defined(STATIC_WL_PRIV_STRUCT) -+#ifndef CONFIG_DHD_USE_STATIC_BUF -+#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF -+#endif -+ u8 *escan_buf; -+#else -+ u8 escan_buf[ESCAN_BUF_SIZE]; -+#endif /* STATIC_WL_PRIV_STRUCT */ -+ struct wiphy *wiphy; -+ struct net_device *ndev; -+}; -+ -+struct ap_info { -+/* Structure to hold WPS, WPA IEs for a AP */ -+ u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN]; -+ u8 beacon_ie[VNDR_IES_MAX_BUF_LEN]; -+ u32 probe_res_ie_len; -+ u32 beacon_ie_len; -+ u8 *wpa_ie; -+ u8 *rsn_ie; -+ u8 *wps_ie; -+ bool security_mode; -+}; -+struct btcoex_info { -+ struct timer_list timer; -+ u32 timer_ms; -+ u32 timer_on; -+ u32 ts_dhcp_start; /* ms ts ecord time stats */ -+ u32 ts_dhcp_ok; /* ms ts ecord time stats */ -+ bool dhcp_done; /* flag, indicates that host done with -+ * dhcp before t1/t2 expiration -+ */ -+ s32 bt_state; -+ struct work_struct work; -+ struct net_device *dev; -+}; -+ -+struct sta_info { -+ /* Structure to hold WPS IE for a STA */ -+ u8 probe_req_ie[VNDR_IES_BUF_LEN]; -+ u8 assoc_req_ie[VNDR_IES_BUF_LEN]; -+ u32 probe_req_ie_len; -+ u32 assoc_req_ie_len; -+}; -+ -+struct afx_hdl { -+ wl_af_params_t *pending_tx_act_frm; -+ struct ether_addr tx_dst_addr; -+ struct net_device *dev; -+ struct work_struct work; -+ u32 bssidx; -+ u32 retry; -+ s32 peer_chan; -+ s32 peer_listen_chan; /* search channel: configured by upper layer */ -+ s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */ -+ bool is_listen; -+ bool ack_recv; -+ bool is_active; -+}; -+ -+struct parsed_ies { -+ wpa_ie_fixed_t *wps_ie; -+ u32 wps_ie_len; -+ wpa_ie_fixed_t *wpa_ie; -+ u32 wpa_ie_len; -+ bcm_tlv_t *wpa2_ie; -+ u32 wpa2_ie_len; -+}; -+ -+ -+#define MAX_EVENT_BUF_NUM 16 -+typedef struct wl_eventmsg_buf { -+ u16 num; -+ struct { -+ u16 type; -+ bool set; -+ } event [MAX_EVENT_BUF_NUM]; -+} wl_eventmsg_buf_t; -+ -+/* private data of cfg80211 interface */ -+struct wl_priv { -+ struct wireless_dev *wdev; /* representing wl cfg80211 device */ -+ -+ struct wireless_dev *p2p_wdev; /* representing wl cfg80211 device for P2P */ -+ struct net_device *p2p_net; /* reference to p2p0 interface */ -+ -+ struct wl_conf *conf; -+ struct cfg80211_scan_request *scan_request; /* scan request object */ -+ EVENT_HANDLER evt_handler[WLC_E_LAST]; -+ struct list_head eq_list; /* used for event queue */ -+ struct list_head net_list; /* used for struct net_info */ -+ spinlock_t eq_lock; /* for event queue synchronization */ -+ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ -+ struct completion act_frm_scan; -+ struct completion iface_disable; -+ struct completion wait_next_af; -+ struct mutex usr_sync; /* maily for up/down synchronization */ -+ struct wl_scan_results *bss_list; -+ struct wl_scan_results *scan_results; -+ -+ /* scan request object for internal purpose */ -+ struct wl_scan_req *scan_req_int; -+ /* information element object for internal purpose */ -+#if defined(STATIC_WL_PRIV_STRUCT) -+ struct wl_ie *ie; -+#else -+ struct wl_ie ie; -+#endif -+ struct wl_iscan_ctrl *iscan; /* iscan controller */ -+ -+ /* association information container */ -+#if defined(STATIC_WL_PRIV_STRUCT) -+ struct wl_connect_info *conn_info; -+#else -+ struct wl_connect_info conn_info; -+#endif -+ -+ struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ -+ tsk_ctl_t event_tsk; /* task of main event handler thread */ -+ void *pub; -+ u32 iface_cnt; -+ u32 channel; /* current channel */ -+ u32 af_sent_channel; /* channel action frame is sent */ -+ /* next af subtype to cancel the remained dwell time in rx process */ -+ u8 next_af_subtype; -+#ifdef WL_CFG80211_SYNC_GON -+ ulong af_tx_sent_jiffies; -+#endif /* WL_CFG80211_SYNC_GON */ -+ bool iscan_on; /* iscan on/off switch */ -+ bool iscan_kickstart; /* indicate iscan already started */ -+ bool escan_on; /* escan on/off switch */ -+ struct escan_info escan_info; /* escan information */ -+ bool active_scan; /* current scan mode */ -+ bool ibss_starter; /* indicates this sta is ibss starter */ -+ bool link_up; /* link/connection up flag */ -+ -+ /* indicate whether chip to support power save mode */ -+ bool pwr_save; -+ bool roam_on; /* on/off switch for self-roaming */ -+ bool scan_tried; /* indicates if first scan attempted */ -+ bool wlfc_on; -+ bool vsdb_mode; -+ bool roamoff_on_concurrent; -+ u8 *ioctl_buf; /* ioctl buffer */ -+ struct mutex ioctl_buf_sync; -+ u8 *escan_ioctl_buf; -+ u8 *extra_buf; /* maily to grab assoc information */ -+ struct dentry *debugfsdir; -+ struct rfkill *rfkill; -+ bool rf_blocked; -+ struct ieee80211_channel remain_on_chan; -+ enum nl80211_channel_type remain_on_chan_type; -+ u64 send_action_id; -+ u64 last_roc_id; -+ wait_queue_head_t netif_change_event; -+ struct completion send_af_done; -+ struct afx_hdl *afx_hdl; -+ struct ap_info *ap_info; -+ struct sta_info *sta_info; -+ struct p2p_info *p2p; -+ bool p2p_supported; -+ struct btcoex_info *btcoex_info; -+ struct timer_list scan_timeout; /* Timer for catch scan event timeout */ -+ s32(*state_notifier) (struct wl_priv *wl, -+ struct net_info *_net_info, enum wl_status state, bool set); -+ unsigned long interrested_state; -+ wlc_ssid_t hostapd_ssid; -+ bool sched_scan_running; /* scheduled scan req status */ -+#ifdef WL_SCHED_SCAN -+ struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ -+#endif /* WL_SCHED_SCAN */ -+#ifdef WL_HOST_BAND_MGMT -+ u8 curr_band; -+#endif /* WL_HOST_BAND_MGMT */ -+ bool scan_suppressed; -+ struct timer_list scan_supp_timer; -+ struct work_struct wlan_work; -+ struct mutex event_sync; /* maily for up/down synchronization */ -+}; -+ -+ -+static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) -+{ -+ return bss = bss ? -+ (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; -+} -+static inline s32 -+wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, -+ struct wireless_dev * wdev, s32 mode, bool pm_block) -+{ -+ struct net_info *_net_info; -+ s32 err = 0; -+ if (wl->iface_cnt == IFACE_MAX_CNT) -+ return -ENOMEM; -+ _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); -+ if (!_net_info) -+ err = -ENOMEM; -+ else { -+ _net_info->mode = mode; -+ _net_info->ndev = ndev; -+ _net_info->wdev = wdev; -+ _net_info->pm_restore = 0; -+ _net_info->pm = 0; -+ _net_info->pm_block = pm_block; -+ _net_info->roam_off = WL_INVALID; -+ wl->iface_cnt++; -+ list_add(&_net_info->list, &wl->net_list); -+ } -+ return err; -+} -+static inline void -+wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev) -+{ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (ndev && (_net_info->ndev == ndev)) { -+ list_del(&_net_info->list); -+ wl->iface_cnt--; -+ if (_net_info->wdev) { -+ kfree(_net_info->wdev); -+ ndev->ieee80211_ptr = NULL; -+ } -+ kfree(_net_info); -+ } -+ } -+ -+} -+static inline void -+wl_delete_all_netinfo(struct wl_priv *wl) -+{ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ list_del(&_net_info->list); -+ if (_net_info->wdev) -+ kfree(_net_info->wdev); -+ kfree(_net_info); -+ } -+ wl->iface_cnt = 0; -+} -+static inline u32 -+wl_get_status_all(struct wl_priv *wl, s32 status) -+ -+{ -+ struct net_info *_net_info, *next; -+ u32 cnt = 0; -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (_net_info->ndev && -+ test_bit(status, &_net_info->sme_state)) -+ cnt++; -+ } -+ return cnt; -+} -+static inline void -+wl_set_status_all(struct wl_priv *wl, s32 status, u32 op) -+{ -+ struct net_info *_net_info, *next; -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ switch (op) { -+ case 1: -+ return; /* set all status is not allowed */ -+ case 2: -+ clear_bit(status, &_net_info->sme_state); -+ if (wl->state_notifier && -+ test_bit(status, &(wl->interrested_state))) -+ wl->state_notifier(wl, _net_info, status, false); -+ break; -+ case 4: -+ return; /* change all status is not allowed */ -+ default: -+ return; /* unknown operation */ -+ } -+ } -+} -+static inline void -+wl_set_status_by_netdev(struct wl_priv *wl, s32 status, -+ struct net_device *ndev, u32 op) -+{ -+ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (ndev && (_net_info->ndev == ndev)) { -+ switch (op) { -+ case 1: -+ set_bit(status, &_net_info->sme_state); -+ if (wl->state_notifier && -+ test_bit(status, &(wl->interrested_state))) -+ wl->state_notifier(wl, _net_info, status, true); -+ break; -+ case 2: -+ clear_bit(status, &_net_info->sme_state); -+ if (wl->state_notifier && -+ test_bit(status, &(wl->interrested_state))) -+ wl->state_notifier(wl, _net_info, status, false); -+ break; -+ case 4: -+ change_bit(status, &_net_info->sme_state); -+ break; -+ } -+ } -+ -+ } -+ -+} -+ -+static inline u32 -+wl_get_status_by_netdev(struct wl_priv *wl, s32 status, -+ struct net_device *ndev) -+{ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (ndev && (_net_info->ndev == ndev)) -+ return test_bit(status, &_net_info->sme_state); -+ } -+ return 0; -+} -+ -+static inline s32 -+wl_get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev) -+{ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (ndev && (_net_info->ndev == ndev)) -+ return _net_info->mode; -+ } -+ return -1; -+} -+ -+ -+static inline void -+wl_set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, -+ s32 mode) -+{ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (ndev && (_net_info->ndev == ndev)) -+ _net_info->mode = mode; -+ } -+} -+static inline struct wl_profile * -+wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) -+{ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (ndev && (_net_info->ndev == ndev)) -+ return &_net_info->profile; -+ } -+ return NULL; -+} -+static inline struct net_info * -+wl_get_netinfo_by_netdev(struct wl_priv *wl, struct net_device *ndev) -+{ -+ struct net_info *_net_info, *next; -+ -+ list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { -+ if (ndev && (_net_info->ndev == ndev)) -+ return _net_info; -+ } -+ return NULL; -+} -+#define wl_to_wiphy(w) (w->wdev->wiphy) -+#define wl_to_prmry_ndev(w) (w->wdev->netdev) -+#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) -+#define wl_to_sr(w) (w->scan_req_int) -+#if defined(STATIC_WL_PRIV_STRUCT) -+#define wl_to_ie(w) (w->ie) -+#define wl_to_conn(w) (w->conn_info) -+#else -+#define wl_to_ie(w) (&w->ie) -+#define wl_to_conn(w) (&w->conn_info) -+#endif -+#define iscan_to_wl(i) ((struct wl_priv *)(i->data)) -+#define wl_to_iscan(w) (w->iscan) -+#define wiphy_from_scan(w) (w->escan_info.wiphy) -+#define wl_get_drv_status_all(wl, stat) \ -+ (wl_get_status_all(wl, WL_STATUS_ ## stat)) -+#define wl_get_drv_status(wl, stat, ndev) \ -+ (wl_get_status_by_netdev(wl, WL_STATUS_ ## stat, ndev)) -+#define wl_set_drv_status(wl, stat, ndev) \ -+ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1)) -+#define wl_clr_drv_status(wl, stat, ndev) \ -+ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2)) -+#define wl_clr_drv_status_all(wl, stat) \ -+ (wl_set_status_all(wl, WL_STATUS_ ## stat, 2)) -+#define wl_chg_drv_status(wl, stat, ndev) \ -+ (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4)) -+ -+#define for_each_bss(list, bss, __i) \ -+ for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) -+ -+#define for_each_ndev(wl, iter, next) \ -+ list_for_each_entry_safe(iter, next, &wl->net_list, list) -+ -+ -+/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. -+ * In addtion to that, wpa_version is WPA_VERSION_1 -+ */ -+#define is_wps_conn(_sme) \ -+ ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ -+ (!_sme->crypto.n_ciphers_pairwise) && \ -+ (!_sme->crypto.cipher_group)) -+extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data); -+extern s32 wl_cfg80211_attach_post(struct net_device *ndev); -+extern void wl_cfg80211_detach(void *para); -+ -+extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, -+ void *data); -+void wl_cfg80211_set_parent_dev(void *dev); -+struct device *wl_cfg80211_get_parent_dev(void); -+ -+extern s32 wl_cfg80211_up(void *para); -+extern s32 wl_cfg80211_down(void *para); -+extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, -+ void* _net_attach); -+extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); -+extern s32 wl_cfg80211_notify_ifdel(void); -+extern s32 wl_cfg80211_is_progress_ifadd(void); -+extern s32 wl_cfg80211_is_progress_ifchange(void); -+extern s32 wl_cfg80211_is_progress_ifadd(void); -+extern s32 wl_cfg80211_notify_ifchange(void); -+extern void wl_cfg80211_dbg_level(u32 level); -+extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); -+extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); -+extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); -+extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, -+ enum wl_management_type type); -+extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); -+extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); -+extern s32 wl_mode_to_nl80211_iftype(s32 mode); -+int wl_cfg80211_do_driver_init(struct net_device *net); -+void wl_cfg80211_enable_trace(bool set, u32 level); -+extern s32 wl_update_wiphybands(struct wl_priv *wl, bool notify); -+extern s32 wl_cfg80211_if_is_group_owner(void); -+extern chanspec_t wl_ch_host_to_driver(u16 channel); -+extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); -+extern void wl_stop_wait_next_action_frame(struct wl_priv *wl, struct net_device *ndev); -+extern s32 wl_cfg80211_set_band(struct net_device *ndev, int band); -+extern int wl_cfg80211_update_power_mode(struct net_device *dev); -+#if defined(DHCP_SCAN_SUPPRESS) -+extern int wl_cfg80211_scan_suppress(struct net_device *dev, int suppress); -+#endif -+extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set); -+extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, -+ struct wl_priv *wl, wl_eventmsg_buf_t *ev); -+#endif /* _wl_cfg80211_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c -new file mode 100644 -index 00000000..c3144ca2 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c -@@ -0,0 +1,2339 @@ -+/* -+ * Linux cfgp2p driver -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_cfgp2p.c 376685 2013-01-02 06:28:45Z $ -+ * -+ */ -+#include <typedefs.h> -+#include <linuxver.h> -+#include <osl.h> -+#include <linux/kernel.h> -+#include <linux/kthread.h> -+#include <linux/netdevice.h> -+#include <linux/etherdevice.h> -+#include <linux/types.h> -+#include <linux/string.h> -+#include <linux/timer.h> -+#include <linux/if_arp.h> -+#include <asm/uaccess.h> -+ -+#include <bcmutils.h> -+#include <bcmendian.h> -+#include <proto/ethernet.h> -+#include <proto/802.11.h> -+ -+#include <wl_cfg80211.h> -+#include <wl_cfgp2p.h> -+#include <wldev_common.h> -+#include <wl_android.h> -+ -+static s8 scanparambuf[WLC_IOCTL_SMLEN]; -+static s8 g_mgmt_ie_buf[2048]; -+static bool -+wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); -+ -+static u32 -+wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, -+ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd); -+ -+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); -+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); -+static int wl_cfgp2p_if_open(struct net_device *net); -+static int wl_cfgp2p_if_stop(struct net_device *net); -+static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, -+ bool notify); -+ -+static const struct net_device_ops wl_cfgp2p_if_ops = { -+ .ndo_open = wl_cfgp2p_if_open, -+ .ndo_stop = wl_cfgp2p_if_stop, -+ .ndo_do_ioctl = wl_cfgp2p_do_ioctl, -+ .ndo_start_xmit = wl_cfgp2p_start_xmit, -+}; -+ -+bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) -+{ -+ wifi_p2p_pub_act_frame_t *pact_frm; -+ -+ if (frame == NULL) -+ return false; -+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame; -+ if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) -+ return false; -+ -+ if (pact_frm->category == P2P_PUB_AF_CATEGORY && -+ pact_frm->action == P2P_PUB_AF_ACTION && -+ pact_frm->oui_type == P2P_VER && -+ memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { -+ return true; -+ } -+ -+ return false; -+} -+ -+bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) -+{ -+ wifi_p2p_action_frame_t *act_frm; -+ -+ if (frame == NULL) -+ return false; -+ act_frm = (wifi_p2p_action_frame_t *)frame; -+ if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) -+ return false; -+ -+ if (act_frm->category == P2P_AF_CATEGORY && -+ act_frm->type == P2P_VER && -+ memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { -+ return true; -+ } -+ -+ return false; -+} -+bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) -+{ -+ -+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; -+ -+ if (frame == NULL) -+ return false; -+ -+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; -+ if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1) -+ return false; -+ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) -+ return false; -+ -+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || -+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || -+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || -+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) -+ return true; -+ else -+ return false; -+ -+} -+void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) -+{ -+ wifi_p2p_pub_act_frame_t *pact_frm; -+ wifi_p2p_action_frame_t *act_frm; -+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; -+ if (!frame || frame_len <= 2) -+ return; -+ -+ if (wl_cfgp2p_is_pub_action(frame, frame_len)) { -+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame; -+ switch (pact_frm->subtype) { -+ case P2P_PAF_GON_REQ: -+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_GON_RSP: -+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_GON_CONF: -+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_INVITE_REQ: -+ CFGP2P_ACTION(("%s P2P Invitation Request Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_INVITE_RSP: -+ CFGP2P_ACTION(("%s P2P Invitation Response Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_DEVDIS_REQ: -+ CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_DEVDIS_RSP: -+ CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_PROVDIS_REQ: -+ CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_PAF_PROVDIS_RSP: -+ CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ default: -+ CFGP2P_ACTION(("%s Unknown P2P Public Action Frame\n", -+ (tx)? "TX": "RX")); -+ -+ } -+ -+ } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { -+ act_frm = (wifi_p2p_action_frame_t *)frame; -+ switch (act_frm->subtype) { -+ case P2P_AF_NOTICE_OF_ABSENCE: -+ CFGP2P_ACTION(("%s P2P Notice of Absence Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_AF_PRESENCE_REQ: -+ CFGP2P_ACTION(("%s P2P Presence Request Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_AF_PRESENCE_RSP: -+ CFGP2P_ACTION(("%s P2P Presence Response Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ case P2P_AF_GO_DISC_REQ: -+ CFGP2P_ACTION(("%s P2P Discoverability Request Frame\n", -+ (tx)? "TX": "RX")); -+ break; -+ default: -+ CFGP2P_ACTION(("%s Unknown P2P Action Frame\n", -+ (tx)? "TX": "RX")); -+ } -+ -+ } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { -+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; -+ switch (sd_act_frm->action) { -+ case P2PSD_ACTION_ID_GAS_IREQ: -+ CFGP2P_ACTION(("%s P2P GAS Initial Request\n", -+ (tx)? "TX" : "RX")); -+ break; -+ case P2PSD_ACTION_ID_GAS_IRESP: -+ CFGP2P_ACTION(("%s P2P GAS Initial Response\n", -+ (tx)? "TX" : "RX")); -+ break; -+ case P2PSD_ACTION_ID_GAS_CREQ: -+ CFGP2P_ACTION(("%s P2P GAS Comback Request\n", -+ (tx)? "TX" : "RX")); -+ break; -+ case P2PSD_ACTION_ID_GAS_CRESP: -+ CFGP2P_ACTION(("%s P2P GAS Comback Response\n", -+ (tx)? "TX" : "RX")); -+ break; -+ default: -+ CFGP2P_ACTION(("%s Unknown P2P GAS Frame\n", -+ (tx)? "TX" : "RX")); -+ } -+ -+ -+ } -+} -+ -+/* -+ * Initialize variables related to P2P -+ * -+ */ -+s32 -+wl_cfgp2p_init_priv(struct wl_priv *wl) -+{ -+ if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { -+ CFGP2P_ERR(("struct p2p_info allocation failed\n")); -+ return -ENOMEM; -+ } -+#define INIT_IE(IE_TYPE, BSS_TYPE) \ -+ do { \ -+ memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ -+ sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ -+ wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ -+ } while (0); -+ -+ INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY); -+ INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY); -+ INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY); -+ INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY); -+ INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY); -+ INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE); -+ INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE); -+ INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE); -+ INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE); -+ INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE); -+ INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION); -+ INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION); -+ INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION); -+ INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION); -+ INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION); -+#undef INIT_IE -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY) = wl_to_prmry_ndev(wl); -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY) = 0; -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL; -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0; -+ return BCME_OK; -+ -+} -+/* -+ * Deinitialize variables related to P2P -+ * -+ */ -+void -+wl_cfgp2p_deinit_priv(struct wl_priv *wl) -+{ -+ CFGP2P_DBG(("In\n")); -+ if (wl->p2p) { -+ kfree(wl->p2p); -+ wl->p2p = NULL; -+ } -+ wl->p2p_supported = 0; -+} -+/* -+ * Set P2P functions into firmware -+ */ -+s32 -+wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) -+{ -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } }; -+ s32 ret = BCME_OK; -+ s32 val = 0; -+ /* Do we have to check whether APSTA is enabled or not ? */ -+ wldev_iovar_getint(ndev, "apsta", &val); -+ if (val == 0) { -+ val = 1; -+ ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true); -+ if (ret < 0) { -+ CFGP2P_ERR(("WLC_DOWN error %d\n", ret)); -+ return ret; -+ } -+ wldev_iovar_setint(ndev, "apsta", val); -+ ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true); -+ if (ret < 0) { -+ CFGP2P_ERR(("WLC_UP error %d\n", ret)); -+ return ret; -+ } -+ } -+ -+ /* In case of COB type, firmware has default mac address -+ * After Initializing firmware, we have to set current mac address to -+ * firmware for P2P device address -+ */ -+ ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, -+ sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); -+ if (ret && ret != BCME_UNSUPPORTED) { -+ CFGP2P_ERR(("failed to update device address ret %d\n", ret)); -+ } -+ return ret; -+} -+ -+/* Create a new P2P BSS. -+ * Parameters: -+ * @mac : MAC address of the BSS to create -+ * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT -+ * @chspec : chspec to use if creating a GO BSS. -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, -+ chanspec_t chspec) -+{ -+ wl_p2p_if_t ifreq; -+ s32 err; -+ u32 scb_timeout = WL_SCB_TIMEOUT; -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ -+ ifreq.type = if_type; -+ ifreq.chspec = chspec; -+ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); -+ -+ CFGP2P_DBG(("---wl p2p_ifadd "MACDBG" %s %u\n", -+ MAC2STRDBG(ifreq.addr.octet), -+ (if_type == WL_P2P_IF_GO) ? "go" : "client", -+ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); -+ -+ err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ -+ if (unlikely(err < 0)) -+ printk("'wl p2p_ifadd' error %d\n", err); -+ else if (if_type == WL_P2P_IF_GO) { -+ err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); -+ if (unlikely(err < 0)) -+ printk("'wl scb_timeout' error %d\n", err); -+ } -+ return err; -+} -+ -+/* Disable a P2P BSS. -+ * Parameters: -+ * @mac : MAC address of the BSS to create -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac) -+{ -+ s32 ret; -+ struct net_device *netdev = wl_to_prmry_ndev(wl); -+ -+ CFGP2P_INFO(("------primary idx %d : wl p2p_ifdis "MACDBG"\n", -+ netdev->ifindex, MAC2STRDBG(mac->octet))); -+ ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ if (unlikely(ret < 0)) { -+ printk("'wl p2p_ifdis' error %d\n", ret); -+ } -+ return ret; -+} -+ -+/* Delete a P2P BSS. -+ * Parameters: -+ * @mac : MAC address of the BSS to create -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) -+{ -+ s32 ret; -+ struct net_device *netdev = wl_to_prmry_ndev(wl); -+ -+ CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel "MACDBG"\n", -+ netdev->ifindex, MAC2STRDBG(mac->octet))); -+ ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ if (unlikely(ret < 0)) { -+ printk("'wl p2p_ifdel' error %d\n", ret); -+ } -+ return ret; -+} -+ -+/* Change a P2P Role. -+ * Parameters: -+ * @mac : MAC address of the BSS to change a role -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, -+ chanspec_t chspec) -+{ -+ wl_p2p_if_t ifreq; -+ s32 err; -+ u32 scb_timeout = WL_SCB_TIMEOUT; -+ -+ struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); -+ -+ ifreq.type = if_type; -+ ifreq.chspec = chspec; -+ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); -+ -+ CFGP2P_INFO(("---wl p2p_ifchange "MACDBG" %s %u" -+ " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet), -+ (if_type == WL_P2P_IF_GO) ? "go" : "client", -+ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT, -+ ifreq.chspec)); -+ -+ err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ -+ if (unlikely(err < 0)) { -+ printk("'wl p2p_ifupd' error %d\n", err); -+ } else if (if_type == WL_P2P_IF_GO) { -+ err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true); -+ if (unlikely(err < 0)) -+ printk("'wl scb_timeout' error %d\n", err); -+ } -+ return err; -+} -+ -+ -+/* Get the index of a created P2P BSS. -+ * Parameters: -+ * @mac : MAC address of the created BSS -+ * @index : output: index of created BSS -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) -+{ -+ s32 ret; -+ u8 getbuf[64]; -+ struct net_device *dev = wl_to_prmry_ndev(wl); -+ -+ CFGP2P_INFO(("---wl p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet))); -+ -+ ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, -+ sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL); -+ -+ if (ret == 0) { -+ memcpy(index, getbuf, sizeof(s32)); -+ CFGP2P_INFO(("---wl p2p_if ==> %d\n", *index)); -+ } -+ -+ return ret; -+} -+ -+static s32 -+wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on) -+{ -+ s32 ret = BCME_OK; -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ CFGP2P_DBG(("enter\n")); -+ -+ ret = wldev_iovar_setint(ndev, "p2p_disc", on); -+ -+ if (unlikely(ret < 0)) { -+ CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); -+ } -+ -+ return ret; -+} -+ -+/* Set the WL driver's P2P mode. -+ * Parameters : -+ * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}. -+ * @channel : the channel to listen -+ * @listen_ms : the time (milli seconds) to wait -+ * @bssidx : bss index for BSSCFG -+ * Returns 0 if success -+ */ -+ -+s32 -+wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx) -+{ -+ wl_p2p_disc_st_t discovery_mode; -+ s32 ret; -+ struct net_device *dev; -+ CFGP2P_DBG(("enter\n")); -+ -+ if (unlikely(bssidx == WL_INVALID || bssidx >= P2PAPI_BSSCFG_MAX)) { -+ CFGP2P_ERR((" %d index out of range\n", bssidx)); -+ return -1; -+ } -+ -+ dev = wl_to_p2p_bss_ndev(wl, bssidx); -+ if (unlikely(dev == NULL)) { -+ CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx)); -+ return BCME_NOTFOUND; -+ } -+ -+ /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */ -+ discovery_mode.state = mode; -+ discovery_mode.chspec = wl_ch_host_to_driver(channel); -+ discovery_mode.dwell = listen_ms; -+ ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, -+ sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN, -+ bssidx, &wl->ioctl_buf_sync); -+ -+ return ret; -+} -+ -+/* Get the index of the P2P Discovery BSS */ -+static s32 -+wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index) -+{ -+ s32 ret; -+ struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); -+ -+ ret = wldev_iovar_getint(dev, "p2p_dev", index); -+ CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret)); -+ -+ if (unlikely(ret < 0)) { -+ CFGP2P_ERR(("'p2p_dev' error %d\n", ret)); -+ return ret; -+ } -+ return ret; -+} -+ -+s32 -+wl_cfgp2p_init_discovery(struct wl_priv *wl) -+{ -+ -+ s32 index = 0; -+ s32 ret = BCME_OK; -+ -+ CFGP2P_DBG(("enter\n")); -+ -+ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) { -+ CFGP2P_ERR(("do nothing, already initialized\n")); -+ return ret; -+ } -+ -+ ret = wl_cfgp2p_set_discovery(wl, 1); -+ if (ret < 0) { -+ CFGP2P_ERR(("set discover error\n")); -+ return ret; -+ } -+ /* Enable P2P Discovery in the WL Driver */ -+ ret = wl_cfgp2p_get_disc_idx(wl, &index); -+ -+ if (ret < 0) { -+ return ret; -+ } -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index; -+ -+ /* Set the initial discovery state to SCAN */ -+ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); -+ -+ if (unlikely(ret != 0)) { -+ CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); -+ wl_cfgp2p_set_discovery(wl, 0); -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0; -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; -+ return 0; -+ } -+ return ret; -+} -+ -+/* Deinitialize P2P Discovery -+ * Parameters : -+ * @wl : wl_private data -+ * Returns 0 if succes -+ */ -+static s32 -+wl_cfgp2p_deinit_discovery(struct wl_priv *wl) -+{ -+ s32 ret = BCME_OK; -+ CFGP2P_DBG(("enter\n")); -+ -+ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { -+ CFGP2P_ERR(("do nothing, not initialized\n")); -+ return -1; -+ } -+ /* Set the discovery state to SCAN */ -+ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); -+ /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */ -+ ret = wl_cfgp2p_set_discovery(wl, 0); -+ -+ /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver -+ * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery -+ * BSS. -+ */ -+ -+ /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we -+ * have no discovery BSS. -+ */ -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = WL_INVALID; -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL; -+ -+ return ret; -+ -+} -+/* Enable P2P Discovery -+ * Parameters: -+ * @wl : wl_private data -+ * @ie : probe request ie (WPS IE + P2P IE) -+ * @ie_len : probe request ie length -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, -+ const u8 *ie, u32 ie_len) -+{ -+ s32 ret = BCME_OK; -+ s32 bssidx = (wl_to_prmry_ndev(wl) == dev) ? -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) : wl_cfgp2p_find_idx(wl, dev); -+ if (wl_get_p2p_status(wl, DISCOVERY_ON)) { -+ CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n")); -+ goto set_ie; -+ } -+ -+ wl_set_p2p_status(wl, DISCOVERY_ON); -+ -+ CFGP2P_DBG(("enter\n")); -+ -+ ret = wl_cfgp2p_init_discovery(wl); -+ if (unlikely(ret < 0)) { -+ CFGP2P_ERR((" init discovery error %d\n", ret)); -+ goto exit; -+ } -+ /* Set wsec to any non-zero value in the discovery bsscfg to ensure our -+ * P2P probe responses have the privacy bit set in the 802.11 WPA IE. -+ * Some peer devices may not initiate WPS with us if this bit is not set. -+ */ -+ ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), -+ "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); -+ if (unlikely(ret < 0)) { -+ CFGP2P_ERR((" wsec error %d\n", ret)); -+ } -+set_ie: -+ if (ie_len) { -+ ret = wl_cfgp2p_set_management_ie(wl, dev, -+ bssidx, -+ VNDR_IE_PRBREQ_FLAG, ie, ie_len); -+ -+ if (unlikely(ret < 0)) { -+ CFGP2P_ERR(("set probreq ie occurs error %d\n", ret)); -+ goto exit; -+ } -+ } -+exit: -+ return ret; -+} -+ -+/* Disable P2P Discovery -+ * Parameters: -+ * @wl : wl_private_data -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_disable_discovery(struct wl_priv *wl) -+{ -+ s32 ret = BCME_OK; -+ CFGP2P_DBG((" enter\n")); -+ wl_clr_p2p_status(wl, DISCOVERY_ON); -+ -+ if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) { -+ CFGP2P_ERR((" do nothing, not initialized\n")); -+ goto exit; -+ } -+ -+ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); -+ -+ if (unlikely(ret < 0)) { -+ -+ CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n")); -+ } -+ /* Do a scan abort to stop the driver's scan engine in case it is still -+ * waiting out an action frame tx dwell time. -+ */ -+ wl_clr_p2p_status(wl, DISCOVERY_ON); -+ ret = wl_cfgp2p_deinit_discovery(wl); -+ -+exit: -+ return ret; -+} -+ -+s32 -+wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, -+ u32 num_chans, u16 *channels, -+ s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr) -+{ -+ s32 ret = BCME_OK; -+ s32 memsize; -+ s32 eparams_size; -+ u32 i; -+ s8 *memblk; -+ wl_p2p_scan_t *p2p_params; -+ wl_escan_params_t *eparams; -+ wlc_ssid_t ssid; -+ /* Scan parameters */ -+#define P2PAPI_SCAN_NPROBES 1 -+#define P2PAPI_SCAN_DWELL_TIME_MS 80 -+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 -+#define P2PAPI_SCAN_HOME_TIME_MS 60 -+#define P2PAPI_SCAN_NPROBS_TIME_MS 30 -+#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 -+ -+ struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); -+ /* Allocate scan params which need space for 3 channels and 0 ssids */ -+ eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE + -+ OFFSETOF(wl_escan_params_t, params)) + -+ num_chans * sizeof(eparams->params.channel_list[0]); -+ -+ memsize = sizeof(wl_p2p_scan_t) + eparams_size; -+ memblk = scanparambuf; -+ if (memsize > sizeof(scanparambuf)) { -+ CFGP2P_ERR((" scanpar buf too small (%u > %u)\n", -+ memsize, sizeof(scanparambuf))); -+ return -1; -+ } -+ memset(memblk, 0, memsize); -+ memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN); -+ if (search_state == WL_P2P_DISC_ST_SEARCH) { -+ /* -+ * If we in SEARCH STATE, we don't need to set SSID explictly -+ * because dongle use P2P WILDCARD internally by default -+ */ -+ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx); -+ ssid.SSID_len = htod32(0); -+ -+ } else if (search_state == WL_P2P_DISC_ST_SCAN) { -+ /* SCAN STATE 802.11 SCAN -+ * WFD Supplicant has p2p_find command with (type=progressive, type= full) -+ * So if P2P_find command with type=progressive, -+ * we have to set ssid to P2P WILDCARD because -+ * we just do broadcast scan unless setting SSID -+ */ -+ strncpy(ssid.SSID, WL_P2P_WILDCARD_SSID, sizeof(ssid.SSID) - 1); -+ ssid.SSID[sizeof(ssid.SSID) - 1] = 0; -+ ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN); -+ wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx); -+ } -+ else { -+ CFGP2P_ERR((" invalid search state %d\n", search_state)); -+ return -1; -+ } -+ -+ -+ /* Fill in the P2P scan structure at the start of the iovar param block */ -+ p2p_params = (wl_p2p_scan_t*) memblk; -+ p2p_params->type = 'E'; -+ /* Fill in the Scan structure that follows the P2P scan structure */ -+ eparams = (wl_escan_params_t*) (p2p_params + 1); -+ eparams->params.bss_type = DOT11_BSSTYPE_ANY; -+ if (active) -+ eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE; -+ else -+ eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE; -+ -+ if (tx_dst_addr == NULL) -+ memcpy(&eparams->params.bssid, ðer_bcast, ETHER_ADDR_LEN); -+ else -+ memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN); -+ -+ if (ssid.SSID_len) -+ memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t)); -+ -+ eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); -+ -+ /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by -+ * the supplicant -+ */ -+ if ((num_chans == SOCIAL_CHAN_CNT) || (num_chans == SOCIAL_CHAN_CNT + 1)) -+ eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); -+ else if (num_chans == AF_PEER_SEARCH_CNT) -+ eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS); -+ else if (wl_get_drv_status_all(wl, CONNECTED)) -+ eparams->params.active_time = -1; -+ else -+ eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS); -+ eparams->params.nprobes = htod32((eparams->params.active_time / -+ P2PAPI_SCAN_NPROBS_TIME_MS)); -+ -+ /* Override scan params to find a peer for a connection */ -+ if (num_chans == 1) { -+ eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS); -+ eparams->params.nprobes = htod32(eparams->params.active_time / -+ WL_SCAN_JOIN_PROBE_INTERVAL_MS); -+ } -+ -+ if (eparams->params.nprobes <= 0) -+ eparams->params.nprobes = 1; -+ CFGP2P_DBG(("nprobes # %d, active_time %d\n", -+ eparams->params.nprobes, eparams->params.active_time)); -+ eparams->params.passive_time = htod32(-1); -+ eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | -+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK)); -+ -+ for (i = 0; i < num_chans; i++) { -+ eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]); -+ } -+ eparams->version = htod32(ESCAN_REQ_VERSION); -+ eparams->action = htod16(action); -+ eparams->sync_id = htod16(0x1234); -+ CFGP2P_INFO(("SCAN CHANNELS : ")); -+ -+ for (i = 0; i < num_chans; i++) { -+ if (i == 0) CFGP2P_INFO(("%d", channels[i])); -+ else CFGP2P_INFO((",%d", channels[i])); -+ } -+ -+ CFGP2P_INFO(("\n")); -+ -+ ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", -+ memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); -+ if (ret == BCME_OK) -+ wl_set_p2p_status(wl, SCANNING); -+ return ret; -+} -+ -+/* search function to reach at common channel to send action frame -+ * Parameters: -+ * @wl : wl_private data -+ * @ndev : net device for bssidx -+ * @bssidx : bssidx for BSS -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, -+ s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr) -+{ -+ s32 ret = 0; -+ u32 chan_cnt = 0; -+ u16 *default_chan_list = NULL; -+ if (!p2p_is_on(wl) || ndev == NULL || bssidx == WL_INVALID) -+ return -BCME_ERROR; -+ CFGP2P_ERR((" Enter\n")); -+ if (bssidx == P2PAPI_BSSCFG_PRIMARY) -+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); -+ if (channel) -+ chan_cnt = AF_PEER_SEARCH_CNT; -+ else -+ chan_cnt = SOCIAL_CHAN_CNT; -+ default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); -+ if (default_chan_list == NULL) { -+ CFGP2P_ERR(("channel list allocation failed \n")); -+ ret = -ENOMEM; -+ goto exit; -+ } -+ if (channel) { -+ u32 i; -+ /* insert same channel to the chan_list */ -+ for (i = 0; i < chan_cnt; i++) { -+ default_chan_list[i] = channel; -+ } -+ } else { -+ default_chan_list[0] = SOCIAL_CHAN_1; -+ default_chan_list[1] = SOCIAL_CHAN_2; -+ default_chan_list[2] = SOCIAL_CHAN_3; -+ } -+ ret = wl_cfgp2p_escan(wl, ndev, true, chan_cnt, -+ default_chan_list, WL_P2P_DISC_ST_SEARCH, -+ WL_SCAN_ACTION_START, bssidx, tx_dst_addr); -+ kfree(default_chan_list); -+exit: -+ return ret; -+} -+ -+/* Check whether pointed-to IE looks like WPA. */ -+#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ -+ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) -+/* Check whether pointed-to IE looks like WPS. */ -+#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ -+ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) -+/* Check whether the given IE looks like WFA P2P IE. */ -+#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ -+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) -+/* Check whether the given IE looks like WFA WFDisplay IE. */ -+#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */ -+#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ -+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD) -+ -+static s32 -+wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len, -+ struct parsed_vndr_ies *vndr_ies) -+{ -+ s32 err = BCME_OK; -+ vndr_ie_t *vndrie; -+ bcm_tlv_t *ie; -+ struct parsed_vndr_ie_info *parsed_info; -+ u32 count = 0; -+ s32 remained_len; -+ -+ remained_len = (s32)len; -+ memset(vndr_ies, 0, sizeof(*vndr_ies)); -+ -+ WL_INFO(("---> len %d\n", len)); -+ ie = (bcm_tlv_t *) parse; -+ if (!bcm_valid_tlv(ie, remained_len)) -+ ie = NULL; -+ while (ie) { -+ if (count >= MAX_VNDR_IE_NUMBER) -+ break; -+ if (ie->id == DOT11_MNG_VS_ID) { -+ vndrie = (vndr_ie_t *) ie; -+ /* len should be bigger than OUI length + one data length at least */ -+ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) { -+ CFGP2P_ERR(("%s: invalid vndr ie. length is too small %d\n", -+ __FUNCTION__, vndrie->len)); -+ goto end; -+ } -+ /* if wpa or wme ie, do not add ie */ -+ if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) && -+ ((vndrie->data[0] == WPA_OUI_TYPE) || -+ (vndrie->data[0] == WME_OUI_TYPE))) { -+ CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n")); -+ goto end; -+ } -+ -+ parsed_info = &vndr_ies->ie_info[count++]; -+ -+ /* save vndr ie information */ -+ parsed_info->ie_ptr = (char *)vndrie; -+ parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN); -+ memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t)); -+ -+ vndr_ies->count = count; -+ -+ CFGP2P_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n", -+ parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1], -+ parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0])); -+ } -+end: -+ ie = bcm_next_tlv(ie, &remained_len); -+ } -+ return err; -+} -+ -+ -+/* Delete and Set a management vndr ie to firmware -+ * Parameters: -+ * @wl : wl_private data -+ * @ndev : net device for bssidx -+ * @bssidx : bssidx for BSS -+ * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, -+ * VNDR_IE_ASSOCREQ_FLAG) -+ * @ie : VNDR IE (such as P2P IE , WPS IE) -+ * @ie_len : VNDR IE Length -+ * Returns 0 if success. -+ */ -+ -+s32 -+wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, -+ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) -+{ -+ s32 ret = BCME_OK; -+ u8 *curr_ie_buf = NULL; -+ u8 *mgmt_ie_buf = NULL; -+ u32 mgmt_ie_buf_len = 0; -+ u32 *mgmt_ie_len = 0; -+ u32 del_add_ie_buf_len = 0; -+ u32 total_ie_buf_len = 0; -+ u32 parsed_ie_buf_len = 0; -+ struct parsed_vndr_ies old_vndr_ies; -+ struct parsed_vndr_ies new_vndr_ies; -+ s32 i; -+ u8 *ptr; -+ s32 remained_buf_len; -+ -+#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) -+#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) -+ memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf)); -+ curr_ie_buf = g_mgmt_ie_buf; -+ CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag)); -+ if (wl->p2p != NULL) { -+ switch (pktflag) { -+ case VNDR_IE_PRBREQ_FLAG : -+ mgmt_ie_buf = IE_TYPE(probe_req, bssidx); -+ mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx); -+ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx)); -+ break; -+ case VNDR_IE_PRBRSP_FLAG : -+ mgmt_ie_buf = IE_TYPE(probe_res, bssidx); -+ mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx); -+ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx)); -+ break; -+ case VNDR_IE_ASSOCREQ_FLAG : -+ mgmt_ie_buf = IE_TYPE(assoc_req, bssidx); -+ mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx); -+ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx)); -+ break; -+ case VNDR_IE_ASSOCRSP_FLAG : -+ mgmt_ie_buf = IE_TYPE(assoc_res, bssidx); -+ mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx); -+ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx)); -+ break; -+ case VNDR_IE_BEACON_FLAG : -+ mgmt_ie_buf = IE_TYPE(beacon, bssidx); -+ mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx); -+ mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx)); -+ break; -+ default: -+ mgmt_ie_buf = NULL; -+ mgmt_ie_len = NULL; -+ CFGP2P_ERR(("not suitable type\n")); -+ return -1; -+ } -+ } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { -+ switch (pktflag) { -+ case VNDR_IE_PRBRSP_FLAG : -+ mgmt_ie_buf = wl->ap_info->probe_res_ie; -+ mgmt_ie_len = &wl->ap_info->probe_res_ie_len; -+ mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie); -+ break; -+ case VNDR_IE_BEACON_FLAG : -+ mgmt_ie_buf = wl->ap_info->beacon_ie; -+ mgmt_ie_len = &wl->ap_info->beacon_ie_len; -+ mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie); -+ break; -+ default: -+ mgmt_ie_buf = NULL; -+ mgmt_ie_len = NULL; -+ CFGP2P_ERR(("not suitable type\n")); -+ return -1; -+ } -+ bssidx = 0; -+ } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { -+ switch (pktflag) { -+ case VNDR_IE_PRBREQ_FLAG : -+ mgmt_ie_buf = wl->sta_info->probe_req_ie; -+ mgmt_ie_len = &wl->sta_info->probe_req_ie_len; -+ mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie); -+ break; -+ case VNDR_IE_ASSOCREQ_FLAG : -+ mgmt_ie_buf = wl->sta_info->assoc_req_ie; -+ mgmt_ie_len = &wl->sta_info->assoc_req_ie_len; -+ mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie); -+ break; -+ default: -+ mgmt_ie_buf = NULL; -+ mgmt_ie_len = NULL; -+ CFGP2P_ERR(("not suitable type\n")); -+ return -1; -+ } -+ bssidx = 0; -+ } else { -+ CFGP2P_ERR(("not suitable type\n")); -+ return -1; -+ } -+ -+ if (vndr_ie_len > mgmt_ie_buf_len) { -+ CFGP2P_ERR(("extra IE size too big\n")); -+ ret = -ENOMEM; -+ } else { -+ /* parse and save new vndr_ie in curr_ie_buff before comparing it */ -+ if (vndr_ie && vndr_ie_len && curr_ie_buf) { -+ ptr = curr_ie_buf; -+ -+ wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie, -+ vndr_ie_len, &new_vndr_ies); -+ -+ for (i = 0; i < new_vndr_ies.count; i++) { -+ struct parsed_vndr_ie_info *vndrie_info = -+ &new_vndr_ies.ie_info[i]; -+ -+ memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr, -+ vndrie_info->ie_len); -+ parsed_ie_buf_len += vndrie_info->ie_len; -+ } -+ } -+ -+ if (mgmt_ie_buf != NULL) { -+ if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) && -+ (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) { -+ CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); -+ goto exit; -+ } -+ -+ /* parse old vndr_ie */ -+ wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, -+ &old_vndr_ies); -+ -+ /* make a command to delete old ie */ -+ for (i = 0; i < old_vndr_ies.count; i++) { -+ struct parsed_vndr_ie_info *vndrie_info = -+ &old_vndr_ies.ie_info[i]; -+ -+ CFGP2P_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n", -+ vndrie_info->vndrie.id, vndrie_info->vndrie.len, -+ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], -+ vndrie_info->vndrie.oui[2])); -+ -+ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, -+ bssidx, pktflag, vndrie_info->vndrie.oui, -+ vndrie_info->vndrie.id, -+ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, -+ vndrie_info->ie_len - VNDR_IE_FIXED_LEN, -+ "del"); -+ -+ curr_ie_buf += del_add_ie_buf_len; -+ total_ie_buf_len += del_add_ie_buf_len; -+ } -+ } -+ -+ *mgmt_ie_len = 0; -+ /* Add if there is any extra IE */ -+ if (mgmt_ie_buf && parsed_ie_buf_len) { -+ ptr = mgmt_ie_buf; -+ -+ remained_buf_len = mgmt_ie_buf_len; -+ -+ /* make a command to add new ie */ -+ for (i = 0; i < new_vndr_ies.count; i++) { -+ struct parsed_vndr_ie_info *vndrie_info = -+ &new_vndr_ies.ie_info[i]; -+ -+ CFGP2P_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n", -+ vndrie_info->vndrie.id, vndrie_info->vndrie.len, -+ vndrie_info->ie_len - 2, -+ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1], -+ vndrie_info->vndrie.oui[2])); -+ -+ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(wl, curr_ie_buf, -+ bssidx, pktflag, vndrie_info->vndrie.oui, -+ vndrie_info->vndrie.id, -+ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN, -+ vndrie_info->ie_len - VNDR_IE_FIXED_LEN, -+ "add"); -+ -+ /* verify remained buf size before copy data */ -+ if (remained_buf_len >= vndrie_info->ie_len) { -+ remained_buf_len -= vndrie_info->ie_len; -+ } else { -+ CFGP2P_ERR(("no space in mgmt_ie_buf: pktflag = %d, " -+ "found vndr ies # = %d(cur %d), remained len %d, " -+ "cur mgmt_ie_len %d, new ie len = %d\n", -+ pktflag, new_vndr_ies.count, i, remained_buf_len, -+ *mgmt_ie_len, vndrie_info->ie_len)); -+ break; -+ } -+ -+ /* save the parsed IE in wl struct */ -+ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr, -+ vndrie_info->ie_len); -+ *mgmt_ie_len += vndrie_info->ie_len; -+ -+ curr_ie_buf += del_add_ie_buf_len; -+ total_ie_buf_len += del_add_ie_buf_len; -+ } -+ } -+ if (total_ie_buf_len) { -+ ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf, -+ total_ie_buf_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, -+ bssidx, &wl->ioctl_buf_sync); -+ if (ret) -+ CFGP2P_ERR(("vndr ie set error : %d\n", ret)); -+ } -+ } -+#undef IE_TYPE -+#undef IE_TYPE_LEN -+exit: -+ return ret; -+} -+ -+/* Clear the manament IE buffer of BSSCFG -+ * Parameters: -+ * @wl : wl_private data -+ * @bssidx : bssidx for BSS -+ * -+ * Returns 0 if success. -+ */ -+s32 -+wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) -+{ -+ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, -+ VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG}; -+ s32 index = -1; -+ struct net_device *ndev = wl_cfgp2p_find_ndev(wl, bssidx); -+#define INIT_IE(IE_TYPE, BSS_TYPE) \ -+ do { \ -+ memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ -+ sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \ -+ wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \ -+ } while (0); -+ -+ if (bssidx < 0 || ndev == NULL) { -+ CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev")); -+ return BCME_BADARG; -+ } -+ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) { -+ /* clean up vndr ies in dongle */ -+ wl_cfgp2p_set_management_ie(wl, ndev, bssidx, vndrie_flag[index], NULL, 0); -+ } -+ INIT_IE(probe_req, bssidx); -+ INIT_IE(probe_res, bssidx); -+ INIT_IE(assoc_req, bssidx); -+ INIT_IE(assoc_res, bssidx); -+ INIT_IE(beacon, bssidx); -+ return BCME_OK; -+} -+ -+ -+/* Is any of the tlvs the expected entry? If -+ * not update the tlvs buffer pointer/length. -+ */ -+static bool -+wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type) -+{ -+ /* If the contents match the OUI and the type */ -+ if (ie[TLV_LEN_OFF] >= oui_len + 1 && -+ !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) && -+ type == ie[TLV_BODY_OFF + oui_len]) { -+ return TRUE; -+ } -+ -+ if (tlvs == NULL) -+ return FALSE; -+ /* point to the next ie */ -+ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; -+ /* calculate the length of the rest of the buffer */ -+ *tlvs_len -= (int)(ie - *tlvs); -+ /* update the pointer to the start of the buffer */ -+ *tlvs = ie; -+ -+ return FALSE; -+} -+ -+wpa_ie_fixed_t * -+wl_cfgp2p_find_wpaie(u8 *parse, u32 len) -+{ -+ bcm_tlv_t *ie; -+ -+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { -+ if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) { -+ return (wpa_ie_fixed_t *)ie; -+ } -+ } -+ return NULL; -+} -+ -+wpa_ie_fixed_t * -+wl_cfgp2p_find_wpsie(u8 *parse, u32 len) -+{ -+ bcm_tlv_t *ie; -+ -+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) { -+ if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) { -+ return (wpa_ie_fixed_t *)ie; -+ } -+ } -+ return NULL; -+} -+ -+wifi_p2p_ie_t * -+wl_cfgp2p_find_p2pie(u8 *parse, u32 len) -+{ -+ bcm_tlv_t *ie; -+ -+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { -+ if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) { -+ return (wifi_p2p_ie_t *)ie; -+ } -+ } -+ return NULL; -+} -+ -+wifi_wfd_ie_t * -+wl_cfgp2p_find_wfdie(u8 *parse, u32 len) -+{ -+ bcm_tlv_t *ie; -+ -+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) { -+ if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) { -+ return (wifi_wfd_ie_t *)ie; -+ } -+ } -+ return NULL; -+} -+static u32 -+wl_cfgp2p_vndr_ie(struct wl_priv *wl, u8 *iebuf, s32 bssidx, s32 pktflag, -+ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd) -+{ -+ vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */ -+ s32 iecount; -+ u32 data_offset; -+ -+ /* Validate the pktflag parameter */ -+ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | -+ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | -+ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) { -+ CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag)); -+ return -1; -+ } -+ -+ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ -+ strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1); -+ hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; -+ -+ /* Set the IE count - the buffer contains only 1 IE */ -+ iecount = htod32(1); -+ memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32)); -+ -+ /* Copy packet flags that indicate which packets will contain this IE */ -+ pktflag = htod32(pktflag); -+ memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, -+ sizeof(u32)); -+ -+ /* Add the IE ID to the buffer */ -+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id; -+ -+ /* Add the IE length to the buffer */ -+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = -+ (uint8) VNDR_IE_MIN_LEN + datalen; -+ -+ /* Add the IE OUI to the buffer */ -+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0]; -+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1]; -+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2]; -+ -+ /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */ -+ memcpy(iebuf, &hdr, sizeof(hdr) - 1); -+ -+ /* Copy the IE data to the IE buffer */ -+ data_offset = -+ (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] - -+ (u8*)&hdr; -+ memcpy(iebuf + data_offset, data, datalen); -+ return data_offset + datalen; -+ -+} -+ -+/* -+ * Search the bssidx based on dev argument -+ * Parameters: -+ * @wl : wl_private data -+ * @ndev : net device to search bssidx -+ * Returns bssidx for ndev -+ */ -+s32 -+wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev) -+{ -+ u32 i; -+ s32 index = -1; -+ -+ if (ndev == NULL) { -+ CFGP2P_ERR((" ndev is NULL\n")); -+ goto exit; -+ } -+ if (!wl->p2p_supported) { -+ return P2PAPI_BSSCFG_PRIMARY; -+ } -+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { -+ if (ndev == wl_to_p2p_bss_ndev(wl, i)) { -+ index = wl_to_p2p_bss_bssidx(wl, i); -+ break; -+ } -+ } -+ if (index == -1) -+ return P2PAPI_BSSCFG_PRIMARY; -+exit: -+ return index; -+} -+ -+struct net_device * -+wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx) -+{ -+ u32 i; -+ struct net_device *ndev = NULL; -+ if (bssidx < 0) { -+ CFGP2P_ERR((" bsscfg idx is invalid\n")); -+ goto exit; -+ } -+ -+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { -+ if (bssidx == wl_to_p2p_bss_bssidx(wl, i)) { -+ ndev = wl_to_p2p_bss_ndev(wl, i); -+ break; -+ } -+ } -+ -+exit: -+ return ndev; -+} -+ -+/* -+ * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE -+ */ -+s32 -+wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ s32 ret = BCME_OK; -+ struct net_device *netdev; -+ if (!wl || !wl->p2p) -+ return BCME_ERROR; -+ if (wl->p2p_net == ndev) { -+ netdev = wl_to_prmry_ndev(wl); -+ } else { -+ netdev = ndev; -+ } -+ CFGP2P_DBG((" Enter\n")); -+ if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) { -+ wl_set_p2p_status(wl, LISTEN_EXPIRED); -+ if (timer_pending(&wl->p2p->listen_timer)) { -+ del_timer_sync(&wl->p2p->listen_timer); -+ } -+ -+ if (wl->afx_hdl->is_listen == TRUE && -+ wl_get_drv_status_all(wl, FINDING_COMMON_CHANNEL)) { -+ WL_DBG(("Listen DONE for action frame\n")); -+ complete(&wl->act_frm_scan); -+ } -+#ifdef WL_CFG80211_SYNC_GON -+ else if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM_LISTEN)) { -+ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM_LISTEN, netdev); -+ WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n", -+ jiffies_to_msecs(jiffies - wl->af_tx_sent_jiffies))); -+ -+ if (wl_get_drv_status_all(wl, WAITING_NEXT_ACT_FRM)) -+ wl_clr_drv_status(wl, WAITING_NEXT_ACT_FRM, netdev); -+ -+ complete(&wl->wait_next_af); -+ } -+#endif /* WL_CFG80211_SYNC_GON */ -+ -+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL)) { -+#else -+ if (wl_get_drv_status_all(wl, REMAINING_ON_CHANNEL) || -+ wl_get_drv_status_all(wl, FAKE_REMAINING_ON_CHANNEL)) { -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ WL_DBG(("Listen DONE for ramain on channel expired\n")); -+ wl_clr_drv_status(wl, REMAINING_ON_CHANNEL, netdev); -+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ wl_clr_drv_status(wl, FAKE_REMAINING_ON_CHANNEL, netdev); -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ if (ndev && (ndev->ieee80211_ptr != NULL)) { -+ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, -+ &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); -+ } -+ } -+ if (wl_add_remove_eventmsg(wl_to_prmry_ndev(wl), -+ WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) { -+ CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n")); -+ } -+ } else -+ wl_clr_p2p_status(wl, LISTEN_EXPIRED); -+ -+ return ret; -+ -+} -+ -+/* -+ * Timer expire callback function for LISTEN -+ * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, -+ * so lets do it from thread context. -+ */ -+void -+wl_cfgp2p_listen_expired(unsigned long data) -+{ -+ wl_event_msg_t msg; -+ struct wl_priv *wl = (struct wl_priv *) data; -+ CFGP2P_DBG((" Enter\n")); -+ bzero(&msg, sizeof(wl_event_msg_t)); -+ msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); -+ wl_cfg80211_event(wl->p2p_net ? wl->p2p_net : -+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL); -+} -+/* -+ * Routine for cancelling the P2P LISTEN -+ */ -+static s32 -+wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev, -+ bool notify) -+{ -+ WL_DBG(("Enter \n")); -+ /* Irrespective of whether timer is running or not, reset -+ * the LISTEN state. -+ */ -+ if (timer_pending(&wl->p2p->listen_timer)) { -+ del_timer_sync(&wl->p2p->listen_timer); -+ if (notify) -+ if (ndev && ndev->ieee80211_ptr) { -+ cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, -+ &wl->remain_on_chan, wl->remain_on_chan_type, -+ GFP_KERNEL); -+ } -+ } -+ return 0; -+} -+/* -+ * Do a P2P Listen on the given channel for the given duration. -+ * A listen consists of sitting idle and responding to P2P probe requests -+ * with a P2P probe response. -+ * -+ * This fn assumes dongle p2p device discovery is already enabled. -+ * Parameters : -+ * @wl : wl_private data -+ * @channel : channel to listen -+ * @duration_ms : the time (milli seconds) to wait -+ */ -+s32 -+wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) -+{ -+#define EXTRA_DELAY_TIME 100 -+ s32 ret = BCME_OK; -+ struct timer_list *_timer; -+ s32 extra_delay; -+ struct net_device *netdev = wl_to_prmry_ndev(wl); -+ -+ CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms)); -+ if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) { -+ -+ CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); -+ -+ ret = BCME_NOTREADY; -+ goto exit; -+ } -+ if (timer_pending(&wl->p2p->listen_timer)) { -+ CFGP2P_DBG(("previous LISTEN is not completed yet\n")); -+ goto exit; -+ -+ } -+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ else -+ wl_clr_p2p_status(wl, LISTEN_EXPIRED); -+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) { -+ CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n")); -+ } -+ -+ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); -+ _timer = &wl->p2p->listen_timer; -+ -+ /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , -+ * otherwise we will wait up to duration_ms + 100ms + duration / 10 -+ */ -+ if (ret == BCME_OK) { -+ extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10); -+ } else { -+ /* if failed to set listen, it doesn't need to wait whole duration. */ -+ duration_ms = 100 + duration_ms / 20; -+ extra_delay = 0; -+ } -+ -+ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay); -+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST -+ wl_clr_p2p_status(wl, LISTEN_EXPIRED); -+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ -+ -+#undef EXTRA_DELAY_TIME -+exit: -+ return ret; -+} -+ -+ -+s32 -+wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable) -+{ -+ s32 ret = BCME_OK; -+ CFGP2P_DBG((" Enter\n")); -+ if (!wl_get_p2p_status(wl, DISCOVERY_ON)) { -+ -+ CFGP2P_DBG((" do nothing, discovery is off\n")); -+ return ret; -+ } -+ if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) { -+ CFGP2P_DBG(("already : %d\n", enable)); -+ return ret; -+ } -+ -+ wl_chg_p2p_status(wl, SEARCH_ENABLED); -+ /* When disabling Search, reset the WL driver's p2p discovery state to -+ * WL_P2P_DISC_ST_SCAN. -+ */ -+ if (!enable) { -+ wl_clr_p2p_status(wl, SCANNING); -+ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, -+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); -+ } -+ -+ return ret; -+} -+ -+/* -+ * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE -+ */ -+s32 -+wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data) -+{ -+ s32 ret = BCME_OK; -+ u32 event_type = ntoh32(e->event_type); -+ u32 status = ntoh32(e->status); -+ CFGP2P_DBG((" Enter\n")); -+ if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { -+ -+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); -+ if (status == WLC_E_STATUS_SUCCESS) { -+ wl_set_p2p_status(wl, ACTION_TX_COMPLETED); -+ CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n")); -+ } -+ else { -+ wl_set_p2p_status(wl, ACTION_TX_NOACK); -+ CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); -+ wl_stop_wait_next_action_frame(wl, ndev); -+ } -+ } else { -+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," -+ "status : %d\n", status)); -+ -+ if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) -+ complete(&wl->send_af_done); -+ } -+ return ret; -+} -+/* Send an action frame immediately without doing channel synchronization. -+ * -+ * This function does not wait for a completion event before returning. -+ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action -+ * frame is transmitted. -+ * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an -+ * 802.11 ack has been received for the sent action frame. -+ */ -+s32 -+wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, -+ wl_af_params_t *af_params, s32 bssidx) -+{ -+ s32 ret = BCME_OK; -+ s32 timeout = 0; -+ wl_eventmsg_buf_t buf; -+ -+ -+ CFGP2P_INFO(("\n")); -+ CFGP2P_INFO(("channel : %u , dwell time : %u\n", -+ af_params->channel, af_params->dwell_time)); -+ -+ wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); -+ wl_clr_p2p_status(wl, ACTION_TX_NOACK); -+ -+ bzero(&buf, sizeof(wl_eventmsg_buf_t)); -+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true); -+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true); -+ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) -+ return ret; -+ -+#define MAX_WAIT_TIME 2000 -+ if (bssidx == P2PAPI_BSSCFG_PRIMARY) -+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); -+ -+ wl->af_sent_channel = af_params->channel; -+#ifdef WL_CFG80211_SYNC_GON -+ wl->af_tx_sent_jiffies = jiffies; -+#endif /* WL_CFG80211_SYNC_GON */ -+ -+ ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); -+ -+ if (ret < 0) { -+ CFGP2P_ERR((" sending action frame is failed\n")); -+ goto exit; -+ } -+ -+ timeout = wait_for_completion_timeout(&wl->send_af_done, msecs_to_jiffies(MAX_WAIT_TIME)); -+ -+ if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { -+ CFGP2P_INFO(("tx action frame operation is completed\n")); -+ ret = BCME_OK; -+ } else { -+ ret = BCME_ERROR; -+ CFGP2P_INFO(("tx action frame operation is failed\n")); -+ } -+ /* clear status bit for action tx */ -+ wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); -+ wl_clr_p2p_status(wl, ACTION_TX_NOACK); -+ -+exit: -+ CFGP2P_INFO((" via act frame iovar : status = %d\n", ret)); -+ -+ bzero(&buf, sizeof(wl_eventmsg_buf_t)); -+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false); -+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false); -+ if ((ret = wl_cfg80211_apply_eventbuffer(wl_to_prmry_ndev(wl), wl, &buf)) < 0) -+ WL_ERR(("TX frame events revert back failed \n")); -+ -+#undef MAX_WAIT_TIME -+ return ret; -+} -+ -+/* Generate our P2P Device Address and P2P Interface Address from our primary -+ * MAC address. -+ */ -+void -+wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, -+ struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr) -+{ -+ memset(out_dev_addr, 0, sizeof(*out_dev_addr)); -+ memset(out_int_addr, 0, sizeof(*out_int_addr)); -+ -+ /* Generate the P2P Device Address. This consists of the device's -+ * primary MAC address with the locally administered bit set. -+ */ -+ memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr)); -+ out_dev_addr->octet[0] |= 0x02; -+ -+ /* Generate the P2P Interface Address. If the discovery and connection -+ * BSSCFGs need to simultaneously co-exist, then this address must be -+ * different from the P2P Device Address. -+ */ -+ memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr)); -+ out_int_addr->octet[4] ^= 0x80; -+ -+} -+ -+/* P2P IF Address change to Virtual Interface MAC Address */ -+void -+wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id) -+{ -+ wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf; -+ u16 len = ie->len; -+ u8 *subel; -+ u8 subelt_id; -+ u16 subelt_len; -+ CFGP2P_DBG((" Enter\n")); -+ -+ /* Point subel to the P2P IE's subelt field. -+ * Subtract the preceding fields (id, len, OUI, oui_type) from the length. -+ */ -+ subel = ie->subelts; -+ len -= 4; /* exclude OUI + OUI_TYPE */ -+ -+ while (len >= 3) { -+ /* attribute id */ -+ subelt_id = *subel; -+ subel += 1; -+ len -= 1; -+ -+ /* 2-byte little endian */ -+ subelt_len = *subel++; -+ subelt_len |= *subel++ << 8; -+ -+ len -= 2; -+ len -= subelt_len; /* for the remaining subelt fields */ -+ -+ if (subelt_id == element_id) { -+ if (subelt_id == P2P_SEID_INTINTADDR) { -+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); -+ CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n")); -+ } else if (subelt_id == P2P_SEID_DEV_ID) { -+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); -+ CFGP2P_INFO(("Device ID ATTR FOUND\n")); -+ } else if (subelt_id == P2P_SEID_DEV_INFO) { -+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); -+ CFGP2P_INFO(("Device INFO ATTR FOUND\n")); -+ } else if (subelt_id == P2P_SEID_GROUP_ID) { -+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); -+ CFGP2P_INFO(("GROUP ID ATTR FOUND\n")); -+ } return; -+ } else { -+ CFGP2P_DBG(("OTHER id : %d\n", subelt_id)); -+ } -+ subel += subelt_len; -+ } -+} -+/* -+ * Check if a BSS is up. -+ * This is a common implementation called by most OSL implementations of -+ * p2posl_bss_isup(). DO NOT call this function directly from the -+ * common code -- call p2posl_bss_isup() instead to allow the OSL to -+ * override the common implementation if necessary. -+ */ -+bool -+wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) -+{ -+ s32 result, val; -+ bool isup = false; -+ s8 getbuf[64]; -+ -+ /* Check if the BSS is up */ -+ *(int*)getbuf = -1; -+ result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, -+ sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); -+ if (result != 0) { -+ CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result)); -+ CFGP2P_ERR(("NOTE: this ioctl error is normal " -+ "when the BSS has not been created yet.\n")); -+ } else { -+ val = *(int*)getbuf; -+ val = dtoh32(val); -+ CFGP2P_INFO(("---wl bss -C %d ==> %d\n", bsscfg_idx, val)); -+ isup = (val ? TRUE : FALSE); -+ } -+ return isup; -+} -+ -+ -+/* Bring up or down a BSS */ -+s32 -+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up) -+{ -+ s32 ret = BCME_OK; -+ s32 val = up ? 1 : 0; -+ -+ struct { -+ s32 cfg; -+ s32 val; -+ } bss_setbuf; -+ -+ bss_setbuf.cfg = htod32(bsscfg_idx); -+ bss_setbuf.val = htod32(val); -+ CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); -+ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ -+ if (ret != 0) { -+ CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); -+ } -+ -+ return ret; -+} -+ -+/* Check if 'p2p' is supported in the driver */ -+s32 -+wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) -+{ -+ s32 ret = BCME_OK; -+ s32 p2p_supported = 0; -+ ret = wldev_iovar_getint(ndev, "p2p", -+ &p2p_supported); -+ if (ret < 0) { -+ CFGP2P_ERR(("wl p2p error %d\n", ret)); -+ return 0; -+ } -+ if (p2p_supported == 1) { -+ CFGP2P_INFO(("p2p is supported\n")); -+ } else { -+ CFGP2P_INFO(("p2p is unsupported\n")); -+ p2p_supported = 0; -+ } -+ return p2p_supported; -+} -+ -+/* Cleanup P2P resources */ -+s32 -+wl_cfgp2p_down(struct wl_priv *wl) -+{ -+ s32 i = 0, index = -1; -+ wl_cfgp2p_cancel_listen(wl, -+ wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE); -+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { -+ index = wl_to_p2p_bss_bssidx(wl, i); -+ if (index != WL_INVALID) -+ wl_cfgp2p_clear_management_ie(wl, index); -+ } -+ wl_cfgp2p_deinit_priv(wl); -+ return 0; -+} -+ -+s32 -+wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) -+{ -+ s32 ret = -1; -+ int count, start, duration; -+ wl_p2p_sched_t dongle_noa; -+ -+ CFGP2P_DBG((" Enter\n")); -+ -+ memset(&dongle_noa, 0, sizeof(dongle_noa)); -+ -+ if (wl->p2p && wl->p2p->vif_created) { -+ -+ wl->p2p->noa.desc[0].start = 0; -+ -+ sscanf(buf, "%10d %10d %10d", &count, &start, &duration); -+ CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", -+ count, start, duration)); -+ if (count != -1) -+ wl->p2p->noa.desc[0].count = count; -+ -+ /* supplicant gives interval as start */ -+ if (start != -1) -+ wl->p2p->noa.desc[0].interval = start; -+ -+ if (duration != -1) -+ wl->p2p->noa.desc[0].duration = duration; -+ -+ if (wl->p2p->noa.desc[0].count != 255) { -+ wl->p2p->noa.desc[0].start = 200; -+ dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; -+ dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; -+ dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; -+ } -+ else { -+ /* Continuous NoA interval. */ -+ dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; -+ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; -+ if ((wl->p2p->noa.desc[0].interval == 102) || -+ (wl->p2p->noa.desc[0].interval == 100)) { -+ wl->p2p->noa.desc[0].start = 100 - -+ wl->p2p->noa.desc[0].duration; -+ dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; -+ } -+ else { -+ dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; -+ } -+ } -+ /* Put the noa descriptor in dongle format for dongle */ -+ dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count); -+ if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) { -+ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start); -+ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration); -+ } -+ else { -+ dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start*1000); -+ dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration*1000); -+ } -+ dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000); -+ -+ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), -+ "p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN, -+ &wl->ioctl_buf_sync); -+ -+ if (ret < 0) { -+ CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret)); -+ } -+ } -+ else { -+ CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); -+ } -+ return ret; -+} -+s32 -+wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len) -+{ -+ -+ wifi_p2p_noa_desc_t *noa_desc; -+ int len = 0, i; -+ char _buf[200]; -+ -+ CFGP2P_DBG((" Enter\n")); -+ buf[0] = '\0'; -+ if (wl->p2p && wl->p2p->vif_created) { -+ if (wl->p2p->noa.desc[0].count || wl->p2p->ops.ops) { -+ _buf[0] = 1; /* noa index */ -+ _buf[1] = (wl->p2p->ops.ops ? 0x80: 0) | -+ (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */ -+ len += 2; -+ if (wl->p2p->noa.desc[0].count) { -+ noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len]; -+ noa_desc->cnt_type = wl->p2p->noa.desc[0].count; -+ noa_desc->duration = wl->p2p->noa.desc[0].duration; -+ noa_desc->interval = wl->p2p->noa.desc[0].interval; -+ noa_desc->start = wl->p2p->noa.desc[0].start; -+ len += sizeof(wifi_p2p_noa_desc_t); -+ } -+ if (buf_len <= len * 2) { -+ CFGP2P_ERR(("ERROR: buf_len %d in not enough for" -+ "returning noa in string format\n", buf_len)); -+ return -1; -+ } -+ /* We have to convert the buffer data into ASCII strings */ -+ for (i = 0; i < len; i++) { -+ snprintf(buf, 3, "%02x", _buf[i]); -+ buf += 2; -+ } -+ buf[i*2] = '\0'; -+ } -+ } -+ else { -+ CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n")); -+ return -1; -+ } -+ return len * 2; -+} -+s32 -+wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) -+{ -+ int ps, ctw; -+ int ret = -1; -+ s32 legacy_ps; -+ -+ CFGP2P_DBG((" Enter\n")); -+ if (wl->p2p && wl->p2p->vif_created) { -+ sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw); -+ CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw)); -+ if (ctw != -1) { -+ wl->p2p->ops.ctw = ctw; -+ ret = 0; -+ } -+ if (ps != -1) { -+ wl->p2p->ops.ops = ps; -+ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), -+ "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops), -+ wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); -+ if (ret < 0) { -+ CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret)); -+ } -+ } -+ -+ if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) { -+#if defined(SUPPORT_PM2_ONLY) -+ if (legacy_ps == PM_MAX) -+ legacy_ps = PM_FAST; -+#endif /* SUPPORT_PM2_ONLY */ -+ -+ ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), -+ WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true); -+ if (unlikely(ret)) { -+ CFGP2P_ERR(("error (%d)\n", ret)); -+ } else { -+ wl_cfg80211_update_power_mode(ndev); -+ } -+ } -+ else -+ CFGP2P_ERR(("ilegal setting\n")); -+ } -+ else { -+ CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n")); -+ ret = -1; -+ } -+ return ret; -+} -+ -+u8 * -+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) -+{ -+ wifi_p2p_ie_t *ie = NULL; -+ u16 len = 0; -+ u8 *subel; -+ u8 subelt_id; -+ u16 subelt_len; -+ -+ if (!buf) { -+ WL_ERR(("P2P IE not present")); -+ return 0; -+ } -+ -+ ie = (wifi_p2p_ie_t*) buf; -+ len = ie->len; -+ -+ /* Point subel to the P2P IE's subelt field. -+ * Subtract the preceding fields (id, len, OUI, oui_type) from the length. -+ */ -+ subel = ie->subelts; -+ len -= 4; /* exclude OUI + OUI_TYPE */ -+ -+ while (len >= 3) { -+ /* attribute id */ -+ subelt_id = *subel; -+ subel += 1; -+ len -= 1; -+ -+ /* 2-byte little endian */ -+ subelt_len = *subel++; -+ subelt_len |= *subel++ << 8; -+ -+ len -= 2; -+ len -= subelt_len; /* for the remaining subelt fields */ -+ -+ if (subelt_id == element_id) { -+ /* This will point to start of subelement attrib after -+ * attribute id & len -+ */ -+ return subel; -+ } -+ -+ /* Go to next subelement */ -+ subel += subelt_len; -+ } -+ -+ /* Not Found */ -+ return NULL; -+} -+ -+#define P2P_GROUP_CAPAB_GO_BIT 0x01 -+u8 * -+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) -+{ -+ wifi_p2p_ie_t * p2p_ie = NULL; -+ u8 *capability = NULL; -+ bool p2p_go = 0; -+ u8 *ptr = NULL; -+ -+ if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) { -+ WL_ERR(("P2P IE not found")); -+ return NULL; -+ } -+ -+ if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) { -+ WL_ERR(("P2P Capability attribute not found")); -+ return NULL; -+ } -+ -+ /* Check Group capability for Group Owner bit */ -+ p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; -+ if (!p2p_go) { -+ return bi->BSSID.octet; -+ } -+ -+ /* In probe responses, DEVICE INFO attribute will be present */ -+ if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) { -+ /* If DEVICE_INFO is not found, this might be a beacon frame. -+ * check for DEVICE_ID in the beacon frame. -+ */ -+ ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID); -+ } -+ -+ if (!ptr) -+ WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE ")); -+ -+ return ptr; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -+static void -+wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -+{ -+ snprintf(info->driver, sizeof(info->driver), "p2p"); -+ snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0)); -+} -+ -+struct ethtool_ops cfgp2p_ethtool_ops = { -+ .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo -+}; -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ -+ -+s32 -+wl_cfgp2p_register_ndev(struct wl_priv *wl) -+{ -+ int ret = 0; -+ struct net_device* net = NULL; -+ struct wireless_dev *wdev = NULL; -+ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; -+ -+ if (wl->p2p_net) { -+ CFGP2P_ERR(("p2p_net defined already.\n")); -+ return -EINVAL; -+ } -+ -+ /* Allocate etherdev, including space for private structure */ -+ if (!(net = alloc_etherdev(sizeof(struct wl_priv *)))) { -+ CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); -+ return -ENODEV; -+ } -+ -+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); -+ if (unlikely(!wdev)) { -+ WL_ERR(("Could not allocate wireless device\n")); -+ free_netdev(net); -+ return -ENOMEM; -+ } -+ -+ strncpy(net->name, "p2p%d", sizeof(net->name) - 1); -+ net->name[IFNAMSIZ - 1] = '\0'; -+ -+ /* Copy the reference to wl_priv */ -+ memcpy((void *)netdev_priv(net), &wl, sizeof(struct wl_priv *)); -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) -+ ASSERT(!net->open); -+ net->do_ioctl = wl_cfgp2p_do_ioctl; -+ net->hard_start_xmit = wl_cfgp2p_start_xmit; -+ net->open = wl_cfgp2p_if_open; -+ net->stop = wl_cfgp2p_if_stop; -+#else -+ ASSERT(!net->netdev_ops); -+ net->netdev_ops = &wl_cfgp2p_if_ops; -+#endif -+ -+ /* Register with a dummy MAC addr */ -+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); -+ -+ wdev->wiphy = wl->wdev->wiphy; -+ -+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); -+ -+ net->ieee80211_ptr = wdev; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -+ net->ethtool_ops = &cfgp2p_ethtool_ops; -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ -+ -+ SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); -+ -+ /* Associate p2p0 network interface with new wdev */ -+ wdev->netdev = net; -+ -+ ret = register_netdev(net); -+ if (ret) { -+ CFGP2P_ERR((" register_netdevice failed (%d)\n", ret)); -+ free_netdev(net); -+ kfree(wdev); -+ return -ENODEV; -+ } -+ -+ /* store p2p net ptr for further reference. Note that iflist won't have this -+ * entry as there corresponding firmware interface is a "Hidden" interface. -+ */ -+ wl->p2p_wdev = wdev; -+ wl->p2p_net = net; -+ -+ printk("%s: P2P Interface Registered\n", net->name); -+ -+ return ret; -+} -+ -+s32 -+wl_cfgp2p_unregister_ndev(struct wl_priv *wl) -+{ -+ -+ if (!wl || !wl->p2p_net) { -+ CFGP2P_ERR(("Invalid Ptr\n")); -+ return -EINVAL; -+ } -+ -+ unregister_netdev(wl->p2p_net); -+ free_netdev(wl->p2p_net); -+ -+ return 0; -+} -+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) -+{ -+ if (skb) -+ { -+ CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n", -+ ndev->name)); -+ dev_kfree_skb_any(skb); -+ } -+ -+ return 0; -+} -+ -+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) -+{ -+ int ret = 0; -+ struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); -+ struct net_device *ndev = wl_to_prmry_ndev(wl); -+ -+ /* There is no ifidx corresponding to p2p0 in our firmware. So we should -+ * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. -+ * For Android PRIV CMD handling map it to primary I/F -+ */ -+ if (cmd == SIOCDEVPRIVATE+1) { -+ ret = wl_android_priv_cmd(ndev, ifr, cmd); -+ -+ } else { -+ CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", -+ __FUNCTION__, cmd)); -+ return -1; -+ } -+ -+ return ret; -+} -+ -+static int wl_cfgp2p_if_open(struct net_device *net) -+{ -+ extern struct wl_priv *wlcfg_drv_priv; -+ struct wireless_dev *wdev = net->ieee80211_ptr; -+ struct wl_priv *wl = NULL; -+ wl = wlcfg_drv_priv; -+ if (!wdev || !wl || !wl->p2p) -+ return -EINVAL; -+ WL_TRACE(("Enter\n")); -+ /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, -+ * do it here. This will make sure that in concurrent mode, supplicant -+ * is not dependent on a particular order of interface initialization. -+ * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N -+ * -iwlan0. -+ */ -+ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) -+ | BIT(NL80211_IFTYPE_P2P_GO)); -+ wl_cfg80211_do_driver_init(net); -+ -+ return 0; -+} -+ -+static int wl_cfgp2p_if_stop(struct net_device *net) -+{ -+ extern struct wl_priv *wlcfg_drv_priv; -+ struct wl_priv *wl = NULL; -+ unsigned long flags; -+ struct wireless_dev *wdev = net->ieee80211_ptr; -+ int clear_flag = 0; -+ if (!wdev) -+ return -EINVAL; -+ -+ WL_TRACE(("Enter\n")); -+ wl = wlcfg_drv_priv; -+ if (!wl) -+ return -EINVAL; -+ spin_lock_irqsave(&wl->cfgdrv_lock, flags); -+ if (wl->scan_request && wl->scan_request->dev == net) { -+ cfg80211_scan_done(wl->scan_request, true); -+ wl->scan_request = NULL; -+ clear_flag = 1; -+ } -+ spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); -+ if (clear_flag) -+ wl_clr_drv_status(wl, SCANNING, net); -+ wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) -+ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| -+ BIT(NL80211_IFTYPE_P2P_GO))); -+ return 0; -+} -+ -+bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops) -+{ -+ return (if_ops == &wl_cfgp2p_if_ops); -+} -diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h -new file mode 100644 -index 00000000..4c64db61 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h -@@ -0,0 +1,342 @@ -+/* -+ * Linux cfgp2p driver -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_cfgp2p.h 376685 2013-01-02 06:28:45Z $ -+ */ -+#ifndef _wl_cfgp2p_h_ -+#define _wl_cfgp2p_h_ -+#include <proto/802.11.h> -+#include <proto/p2p.h> -+ -+struct wl_priv; -+extern u32 wl_dbg_level; -+ -+typedef struct wifi_p2p_ie wifi_wfd_ie_t; -+/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not -+ * confuse this with a bsscfg index. This value is an index into the -+ * saved_ie[] array of structures which in turn contains a bsscfg index field. -+ */ -+typedef enum { -+ P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ -+ P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ -+ P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ -+ P2PAPI_BSSCFG_MAX -+} p2p_bsscfg_type_t; -+ -+/* vendor ies max buffer length for probe response or beacon */ -+#define VNDR_IES_MAX_BUF_LEN 1400 -+/* normal vendor ies buffer length */ -+#define VNDR_IES_BUF_LEN 512 -+ -+/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */ -+struct p2p_saved_ie { -+ u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN]; -+ u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN]; -+ u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN]; -+ u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN]; -+ u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN]; -+ u32 p2p_probe_req_ie_len; -+ u32 p2p_probe_res_ie_len; -+ u32 p2p_assoc_req_ie_len; -+ u32 p2p_assoc_res_ie_len; -+ u32 p2p_beacon_ie_len; -+}; -+ -+struct p2p_bss { -+ u32 bssidx; -+ struct net_device *dev; -+ struct p2p_saved_ie saved_ie; -+ void *private_data; -+}; -+ -+struct p2p_info { -+ bool on; /* p2p on/off switch */ -+ bool scan; -+ bool vif_created; -+ s8 vir_ifname[IFNAMSIZ]; -+ unsigned long status; -+ struct ether_addr dev_addr; -+ struct ether_addr int_addr; -+ struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; -+ struct timer_list listen_timer; -+ wl_p2p_sched_t noa; -+ wl_p2p_ops_t ops; -+ wlc_ssid_t ssid; -+}; -+ -+#define MAX_VNDR_IE_NUMBER 5 -+ -+struct parsed_vndr_ie_info { -+ char *ie_ptr; -+ u32 ie_len; /* total length including id & length field */ -+ vndr_ie_t vndrie; -+}; -+ -+struct parsed_vndr_ies { -+ u32 count; -+ struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; -+}; -+ -+/* dongle status */ -+enum wl_cfgp2p_status { -+ WLP2P_STATUS_DISCOVERY_ON = 0, -+ WLP2P_STATUS_SEARCH_ENABLED, -+ WLP2P_STATUS_IF_ADD, -+ WLP2P_STATUS_IF_DEL, -+ WLP2P_STATUS_IF_DELETING, -+ WLP2P_STATUS_IF_CHANGING, -+ WLP2P_STATUS_IF_CHANGED, -+ WLP2P_STATUS_LISTEN_EXPIRED, -+ WLP2P_STATUS_ACTION_TX_COMPLETED, -+ WLP2P_STATUS_ACTION_TX_NOACK, -+ WLP2P_STATUS_SCANNING, -+ WLP2P_STATUS_GO_NEG_PHASE, -+ WLP2P_STATUS_DISC_IN_PROGRESS -+}; -+ -+ -+#define wl_to_p2p_bss_ndev(wl, type) ((wl)->p2p->bss_idx[type].dev) -+#define wl_to_p2p_bss_bssidx(wl, type) ((wl)->p2p->bss_idx[type].bssidx) -+#define wl_to_p2p_bss_saved_ie(wl, type) ((wl)->p2p->bss_idx[type].saved_ie) -+#define wl_to_p2p_bss_private(wl, type) ((wl)->p2p->bss_idx[type].private_data) -+#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) -+#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ -+ &(wl)->p2p->status)) -+#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \ -+ &(wl)->p2p->status)) -+#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \ -+ &(wl)->p2p->status)) -+#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:change_bit(WLP2P_STATUS_ ## stat, \ -+ &(wl)->p2p->status)) -+#define p2p_on(wl) ((wl)->p2p->on) -+#define p2p_scan(wl) ((wl)->p2p->scan) -+#define p2p_is_on(wl) ((wl)->p2p && (wl)->p2p->on) -+ -+/* dword align allocation */ -+#define WLC_IOCTL_MAXLEN 8192 -+ -+#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) " -+ -+#define CFGP2P_ERR(args) \ -+ do { \ -+ if (wl_dbg_level & WL_DBG_ERR) { \ -+ printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \ -+ printk args; \ -+ } \ -+ } while (0) -+#define CFGP2P_INFO(args) \ -+ do { \ -+ if (wl_dbg_level & WL_DBG_INFO) { \ -+ printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \ -+ printk args; \ -+ } \ -+ } while (0) -+#define CFGP2P_DBG(args) \ -+ do { \ -+ if (wl_dbg_level & WL_DBG_DBG) { \ -+ printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \ -+ printk args; \ -+ } \ -+ } while (0) -+ -+#define CFGP2P_ACTION(args) \ -+ do { \ -+ if (wl_dbg_level & WL_DBG_P2P_ACTION) { \ -+ printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \ -+ printk args; \ -+ } \ -+ } while (0) -+#define INIT_TIMER(timer, func, duration, extra_delay) \ -+ do { \ -+ init_timer(timer); \ -+ timer->function = func; \ -+ timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \ -+ timer->data = (unsigned long) wl; \ -+ add_timer(timer); \ -+ } while (0); -+extern void -+wl_cfgp2p_listen_expired(unsigned long data); -+extern bool -+wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); -+extern bool -+wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); -+extern bool -+wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); -+extern void -+wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len); -+extern s32 -+wl_cfgp2p_init_priv(struct wl_priv *wl); -+extern void -+wl_cfgp2p_deinit_priv(struct wl_priv *wl); -+extern s32 -+wl_cfgp2p_set_firm_p2p(struct wl_priv *wl); -+extern s32 -+wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, -+ u32 channel, u16 listen_ms, int bssidx); -+extern s32 -+wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, -+ chanspec_t chspec); -+extern s32 -+wl_cfgp2p_ifdisable(struct wl_priv *wl, struct ether_addr *mac); -+extern s32 -+wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac); -+extern s32 -+wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec); -+ -+extern s32 -+wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index); -+ -+extern s32 -+wl_cfgp2p_init_discovery(struct wl_priv *wl); -+extern s32 -+wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len); -+extern s32 -+wl_cfgp2p_disable_discovery(struct wl_priv *wl); -+extern s32 -+wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_chans, -+ u16 *channels, -+ s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr); -+ -+extern s32 -+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, -+ s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr); -+ -+extern wpa_ie_fixed_t * -+wl_cfgp2p_find_wpaie(u8 *parse, u32 len); -+ -+extern wpa_ie_fixed_t * -+wl_cfgp2p_find_wpsie(u8 *parse, u32 len); -+ -+extern wifi_p2p_ie_t * -+wl_cfgp2p_find_p2pie(u8 *parse, u32 len); -+ -+extern wifi_wfd_ie_t * -+wl_cfgp2p_find_wfdie(u8 *parse, u32 len); -+extern s32 -+wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, -+ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); -+extern s32 -+wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx); -+ -+extern s32 -+wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev); -+extern struct net_device * -+wl_cfgp2p_find_ndev(struct wl_priv *wl, s32 bssidx); -+ -+ -+extern s32 -+wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+extern s32 -+wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms); -+ -+extern s32 -+wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable); -+ -+extern s32 -+wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, -+ const wl_event_msg_t *e, void *data); -+extern s32 -+wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, -+ wl_af_params_t *af_params, s32 bssidx); -+ -+extern void -+wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, -+ struct ether_addr *out_int_addr); -+ -+extern void -+wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); -+extern bool -+wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); -+ -+extern s32 -+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up); -+ -+ -+extern s32 -+wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev); -+ -+extern s32 -+wl_cfgp2p_down(struct wl_priv *wl); -+ -+extern s32 -+wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); -+ -+extern s32 -+wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); -+ -+extern s32 -+wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); -+ -+extern u8 * -+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); -+ -+extern u8 * -+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); -+ -+extern s32 -+wl_cfgp2p_register_ndev(struct wl_priv *wl); -+ -+extern s32 -+wl_cfgp2p_unregister_ndev(struct wl_priv *wl); -+ -+extern bool -+wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops); -+ -+/* WiFi Direct */ -+#define SOCIAL_CHAN_1 1 -+#define SOCIAL_CHAN_2 6 -+#define SOCIAL_CHAN_3 11 -+#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ -+ (channel == SOCIAL_CHAN_2) || \ -+ (channel == SOCIAL_CHAN_3)) -+#define SOCIAL_CHAN_CNT 3 -+#define AF_PEER_SEARCH_CNT 2 -+#define WL_P2P_WILDCARD_SSID "DIRECT-" -+#define WL_P2P_WILDCARD_SSID_LEN 7 -+#define WL_P2P_INTERFACE_PREFIX "p2p" -+#define WL_P2P_TEMP_CHAN 11 -+ -+/* If the provision discovery is for JOIN operations, -+ * then we need not do an internal scan to find GO. -+ */ -+#define IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len) \ -+ (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL) -+ -+#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ -+ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ -+ (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) -+#define IS_P2P_PUB_ACT_REQ(frame, p2p_ie, len) \ -+ (wl_cfgp2p_is_pub_action(frame, len) && \ -+ ((frame->subtype == P2P_PAF_GON_REQ) || \ -+ (frame->subtype == P2P_PAF_INVITE_REQ) || \ -+ ((frame->subtype == P2P_PAF_PROVDIS_REQ) && \ -+ IS_PROV_DISC_WITHOUT_GROUP_ID(p2p_ie, len)))) -+#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \ -+ ((subtype == P2P_PAF_GON_CONF) || \ -+ (subtype == P2P_PAF_INVITE_RSP) || \ -+ (subtype == P2P_PAF_PROVDIS_RSP))) -+#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) -+#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \ -+ (len == WL_P2P_WILDCARD_SSID_LEN)) -+#endif /* _wl_cfgp2p_h_ */ -diff --git a/drivers/net/wireless/bcmdhd/wl_dbg.h b/drivers/net/wireless/bcmdhd/wl_dbg.h -new file mode 100644 -index 00000000..b5e70807 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_dbg.h -@@ -0,0 +1,63 @@ -+/* -+ * Minimal debug/trace/assert driver definitions for -+ * Broadcom 802.11 Networking Adapter. -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_dbg.h 326635 2012-04-10 03:15:29Z $ -+ */ -+ -+ -+#ifndef _wl_dbg_h_ -+#define _wl_dbg_h_ -+ -+ -+extern uint32 wl_msg_level; -+extern uint32 wl_msg_level2; -+ -+#define WL_TIMESTAMP() -+ -+#if 0 && (VERSION_MAJOR > 9) -+#include <IOKit/apple80211/IO8Log.h> -+#define WL_PRINT(args) do { printf args; IO8Log args; } while (0) -+#else -+#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0) -+#endif -+ -+ -+ -+#define WL_NONE(args) -+ -+#define WL_ERROR(args) -+#define WL_TRACE(args) -+#define WL_APSTA_UPDN(args) -+#define WL_APSTA_RX(args) -+#ifdef WLMSG_WSEC -+#define WL_WSEC(args) WL_PRINT(args) -+#define WL_WSEC_DUMP(args) WL_PRINT(args) -+#else -+#define WL_WSEC(args) -+#define WL_WSEC_DUMP(args) -+#endif -+ -+extern uint32 wl_msg_level; -+extern uint32 wl_msg_level2; -+#endif -diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c -new file mode 100644 -index 00000000..c9b24ebc ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_iw.c -@@ -0,0 +1,3589 @@ -+/* -+ * Linux Wireless Extensions support -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_iw.c 347632 2012-07-27 11:00:35Z $ -+ */ -+ -+#if defined(USE_IW) -+#define LINUX_PORT -+ -+#include <typedefs.h> -+#include <linuxver.h> -+#include <osl.h> -+ -+#include <bcmutils.h> -+#include <bcmendian.h> -+#include <proto/ethernet.h> -+ -+#include <linux/if_arp.h> -+#include <asm/uaccess.h> -+ -+ -+typedef const struct si_pub si_t; -+#include <wlioctl.h> -+ -+ -+#include <wl_dbg.h> -+#include <wl_iw.h> -+ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+#include <linux/rtnetlink.h> -+#endif -+#if defined(SOFTAP) -+struct net_device *ap_net_dev = NULL; -+tsk_ctl_t ap_eth_ctl; -+#endif -+ -+extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, -+ uint32 reason, char* stringBuf, uint buflen); -+ -+uint wl_msg_level = WL_ERROR_VAL; -+ -+#define MAX_WLIW_IOCTL_LEN 1024 -+ -+ -+#define htod32(i) i -+#define htod16(i) i -+#define dtoh32(i) i -+#define dtoh16(i) i -+#define htodchanspec(i) i -+#define dtohchanspec(i) i -+ -+extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -+extern int dhd_wait_pend8021x(struct net_device *dev); -+ -+#if WIRELESS_EXT < 19 -+#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) -+#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) -+#endif -+ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -+#define DAEMONIZE(a) daemonize(a); \ -+ allow_signal(SIGKILL); \ -+ allow_signal(SIGTERM); -+#else -+#define RAISE_RX_SOFTIRQ() \ -+ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -+#define DAEMONIZE(a) daemonize(); \ -+ do { if (a) \ -+ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ -+ } while (0); -+#endif -+ -+#define ISCAN_STATE_IDLE 0 -+#define ISCAN_STATE_SCANING 1 -+ -+ -+#define WLC_IW_ISCAN_MAXLEN 2048 -+typedef struct iscan_buf { -+ struct iscan_buf * next; -+ char iscan_buf[WLC_IW_ISCAN_MAXLEN]; -+} iscan_buf_t; -+ -+typedef struct iscan_info { -+ struct net_device *dev; -+ struct timer_list timer; -+ uint32 timer_ms; -+ uint32 timer_on; -+ int iscan_state; -+ iscan_buf_t * list_hdr; -+ iscan_buf_t * list_cur; -+ -+ -+ long sysioc_pid; -+ struct semaphore sysioc_sem; -+ struct completion sysioc_exited; -+ -+ -+ char ioctlbuf[WLC_IOCTL_SMLEN]; -+} iscan_info_t; -+iscan_info_t *g_iscan = NULL; -+static void wl_iw_timerfunc(ulong data); -+static void wl_iw_set_event_mask(struct net_device *dev); -+static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); -+ -+ -+typedef struct priv_link { -+ wl_iw_t *wliw; -+} priv_link_t; -+ -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) -+#define WL_DEV_LINK(dev) (priv_link_t*)(dev->priv) -+#else -+#define WL_DEV_LINK(dev) (priv_link_t*)netdev_priv(dev) -+#endif -+ -+ -+#define IW_DEV_IF(dev) ((wl_iw_t*)(WL_DEV_LINK(dev))->wliw) -+ -+static void swap_key_from_BE( -+ wl_wsec_key_t *key -+) -+{ -+ key->index = htod32(key->index); -+ key->len = htod32(key->len); -+ key->algo = htod32(key->algo); -+ key->flags = htod32(key->flags); -+ key->rxiv.hi = htod32(key->rxiv.hi); -+ key->rxiv.lo = htod16(key->rxiv.lo); -+ key->iv_initialized = htod32(key->iv_initialized); -+} -+ -+static void swap_key_to_BE( -+ wl_wsec_key_t *key -+) -+{ -+ key->index = dtoh32(key->index); -+ key->len = dtoh32(key->len); -+ key->algo = dtoh32(key->algo); -+ key->flags = dtoh32(key->flags); -+ key->rxiv.hi = dtoh32(key->rxiv.hi); -+ key->rxiv.lo = dtoh16(key->rxiv.lo); -+ key->iv_initialized = dtoh32(key->iv_initialized); -+} -+ -+static int -+dev_wlc_ioctl( -+ struct net_device *dev, -+ int cmd, -+ void *arg, -+ int len -+) -+{ -+ struct ifreq ifr; -+ wl_ioctl_t ioc; -+ mm_segment_t fs; -+ int ret; -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ ioc.cmd = cmd; -+ ioc.buf = arg; -+ ioc.len = len; -+ -+ strcpy(ifr.ifr_name, dev->name); -+ ifr.ifr_data = (caddr_t) &ioc; -+ -+#ifndef LINUX_HYBRID -+ -+ dev_open(dev); -+#endif -+ -+ fs = get_fs(); -+ set_fs(get_ds()); -+#if defined(WL_USE_NETDEV_OPS) -+ ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); -+#else -+ ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); -+#endif -+ set_fs(fs); -+ -+ return ret; -+} -+ -+ -+ -+static int -+dev_wlc_intvar_set( -+ struct net_device *dev, -+ char *name, -+ int val) -+{ -+ char buf[WLC_IOCTL_SMLEN]; -+ uint len; -+ -+ val = htod32(val); -+ len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); -+ ASSERT(len); -+ -+ return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len)); -+} -+ -+static int -+dev_iw_iovar_setbuf( -+ struct net_device *dev, -+ char *iovar, -+ void *param, -+ int paramlen, -+ void *bufptr, -+ int buflen) -+{ -+ int iolen; -+ -+ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); -+ ASSERT(iolen); -+ BCM_REFERENCE(iolen); -+ -+ return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen)); -+} -+ -+static int -+dev_iw_iovar_getbuf( -+ struct net_device *dev, -+ char *iovar, -+ void *param, -+ int paramlen, -+ void *bufptr, -+ int buflen) -+{ -+ int iolen; -+ -+ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); -+ ASSERT(iolen); -+ BCM_REFERENCE(iolen); -+ -+ return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen)); -+} -+ -+#if WIRELESS_EXT > 17 -+static int -+dev_wlc_bufvar_set( -+ struct net_device *dev, -+ char *name, -+ char *buf, int len) -+{ -+ char *ioctlbuf; -+ uint buflen; -+ int error; -+ -+ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); -+ if (!ioctlbuf) -+ return -ENOMEM; -+ -+ buflen = bcm_mkiovar(name, buf, len, ioctlbuf, MAX_WLIW_IOCTL_LEN); -+ ASSERT(buflen); -+ error = dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen); -+ -+ kfree(ioctlbuf); -+ return error; -+} -+#endif -+ -+ -+ -+static int -+dev_wlc_bufvar_get( -+ struct net_device *dev, -+ char *name, -+ char *buf, int buflen) -+{ -+ char *ioctlbuf; -+ int error; -+ -+ uint len; -+ -+ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL); -+ if (!ioctlbuf) -+ return -ENOMEM; -+ len = bcm_mkiovar(name, NULL, 0, ioctlbuf, MAX_WLIW_IOCTL_LEN); -+ ASSERT(len); -+ BCM_REFERENCE(len); -+ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN); -+ if (!error) -+ bcopy(ioctlbuf, buf, buflen); -+ -+ kfree(ioctlbuf); -+ return (error); -+} -+ -+ -+ -+static int -+dev_wlc_intvar_get( -+ struct net_device *dev, -+ char *name, -+ int *retval) -+{ -+ union { -+ char buf[WLC_IOCTL_SMLEN]; -+ int val; -+ } var; -+ int error; -+ -+ uint len; -+ uint data_null; -+ -+ len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); -+ ASSERT(len); -+ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len); -+ -+ *retval = dtoh32(var.val); -+ -+ return (error); -+} -+ -+ -+#if WIRELESS_EXT < 13 -+struct iw_request_info -+{ -+ __u16 cmd; -+ __u16 flags; -+}; -+ -+typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, -+ void *wrqu, char *extra); -+#endif -+ -+#if WIRELESS_EXT > 12 -+static int -+wl_iw_set_leddc( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, -+ char *extra -+) -+{ -+ int dc = *(int *)extra; -+ int error; -+ -+ error = dev_wlc_intvar_set(dev, "leddc", dc); -+ return error; -+} -+ -+static int -+wl_iw_set_vlanmode( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, -+ char *extra -+) -+{ -+ int mode = *(int *)extra; -+ int error; -+ -+ mode = htod32(mode); -+ error = dev_wlc_intvar_set(dev, "vlan_mode", mode); -+ return error; -+} -+ -+static int -+wl_iw_set_pm( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, -+ char *extra -+) -+{ -+ int pm = *(int *)extra; -+ int error; -+ -+ pm = htod32(pm); -+ error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); -+ return error; -+} -+#endif -+ -+int -+wl_iw_send_priv_event( -+ struct net_device *dev, -+ char *flag -+) -+{ -+ union iwreq_data wrqu; -+ char extra[IW_CUSTOM_MAX + 1]; -+ int cmd; -+ -+ cmd = IWEVCUSTOM; -+ memset(&wrqu, 0, sizeof(wrqu)); -+ if (strlen(flag) > sizeof(extra)) -+ return -1; -+ -+ strcpy(extra, flag); -+ wrqu.data.length = strlen(extra); -+ wireless_send_event(dev, cmd, &wrqu, extra); -+ WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra)); -+ -+ return 0; -+} -+ -+static int -+wl_iw_config_commit( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ void *zwrq, -+ char *extra -+) -+{ -+ wlc_ssid_t ssid; -+ int error; -+ struct sockaddr bssid; -+ -+ WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name)); -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) -+ return error; -+ -+ ssid.SSID_len = dtoh32(ssid.SSID_len); -+ -+ if (!ssid.SSID_len) -+ return 0; -+ -+ bzero(&bssid, sizeof(struct sockaddr)); -+ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) { -+ WL_ERROR(("%s: WLC_REASSOC failed (%d)\n", __FUNCTION__, error)); -+ return error; -+ } -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_name( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *cwrq, -+ char *extra -+) -+{ -+ int phytype, err; -+ uint band[3]; -+ char cap[5]; -+ -+ WL_TRACE(("%s: SIOCGIWNAME\n", dev->name)); -+ -+ cap[0] = 0; -+ if ((err = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))) < 0) -+ goto done; -+ if ((err = dev_wlc_ioctl(dev, WLC_GET_BANDLIST, band, sizeof(band))) < 0) -+ goto done; -+ -+ band[0] = dtoh32(band[0]); -+ switch (phytype) { -+ case WLC_PHY_TYPE_A: -+ strcpy(cap, "a"); -+ break; -+ case WLC_PHY_TYPE_B: -+ strcpy(cap, "b"); -+ break; -+ case WLC_PHY_TYPE_LP: -+ case WLC_PHY_TYPE_G: -+ if (band[0] >= 2) -+ strcpy(cap, "abg"); -+ else -+ strcpy(cap, "bg"); -+ break; -+ case WLC_PHY_TYPE_N: -+ if (band[0] >= 2) -+ strcpy(cap, "abgn"); -+ else -+ strcpy(cap, "bgn"); -+ break; -+ } -+done: -+ snprintf(cwrq->name, IFNAMSIZ, "IEEE 802.11%s", cap); -+ return 0; -+} -+ -+static int -+wl_iw_set_freq( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_freq *fwrq, -+ char *extra -+) -+{ -+ int error, chan; -+ uint sf = 0; -+ -+ WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name)); -+ -+ -+ if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { -+ chan = fwrq->m; -+ } -+ -+ -+ else { -+ -+ if (fwrq->e >= 6) { -+ fwrq->e -= 6; -+ while (fwrq->e--) -+ fwrq->m *= 10; -+ } else if (fwrq->e < 6) { -+ while (fwrq->e++ < 6) -+ fwrq->m /= 10; -+ } -+ -+ if (fwrq->m > 4000 && fwrq->m < 5000) -+ sf = WF_CHAN_FACTOR_4_G; -+ -+ chan = wf_mhz2channel(fwrq->m, sf); -+ } -+ chan = htod32(chan); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) -+ return error; -+ -+ -+ return -EINPROGRESS; -+} -+ -+static int -+wl_iw_get_freq( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_freq *fwrq, -+ char *extra -+) -+{ -+ channel_info_t ci; -+ int error; -+ -+ WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) -+ return error; -+ -+ -+ fwrq->m = dtoh32(ci.hw_channel); -+ fwrq->e = dtoh32(0); -+ return 0; -+} -+ -+static int -+wl_iw_set_mode( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ __u32 *uwrq, -+ char *extra -+) -+{ -+ int infra = 0, ap = 0, error = 0; -+ -+ WL_TRACE(("%s: SIOCSIWMODE\n", dev->name)); -+ -+ switch (*uwrq) { -+ case IW_MODE_MASTER: -+ infra = ap = 1; -+ break; -+ case IW_MODE_ADHOC: -+ case IW_MODE_AUTO: -+ break; -+ case IW_MODE_INFRA: -+ infra = 1; -+ break; -+ default: -+ return -EINVAL; -+ } -+ infra = htod32(infra); -+ ap = htod32(ap); -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) || -+ (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap)))) -+ return error; -+ -+ -+ return -EINPROGRESS; -+} -+ -+static int -+wl_iw_get_mode( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ __u32 *uwrq, -+ char *extra -+) -+{ -+ int error, infra = 0, ap = 0; -+ -+ WL_TRACE(("%s: SIOCGIWMODE\n", dev->name)); -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) || -+ (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap)))) -+ return error; -+ -+ infra = dtoh32(infra); -+ ap = dtoh32(ap); -+ *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_range( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ struct iw_range *range = (struct iw_range *) extra; -+ static int channels[MAXCHANNEL+1]; -+ wl_uint32_list_t *list = (wl_uint32_list_t *) channels; -+ wl_rateset_t rateset; -+ int error, i, k; -+ uint sf, ch; -+ -+ int phytype; -+ int bw_cap = 0, sgi_tx = 0, nmode = 0; -+ channel_info_t ci; -+ uint8 nrate_list2copy = 0; -+ uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130}, -+ {14, 29, 43, 58, 87, 116, 130, 144}, -+ {27, 54, 81, 108, 162, 216, 243, 270}, -+ {30, 60, 90, 120, 180, 240, 270, 300}}; -+ -+ WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ dwrq->length = sizeof(struct iw_range); -+ memset(range, 0, sizeof(*range)); -+ -+ -+ range->min_nwid = range->max_nwid = 0; -+ -+ -+ list->count = htod32(MAXCHANNEL); -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels)))) -+ return error; -+ for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) { -+ range->freq[i].i = dtoh32(list->element[i]); -+ -+ ch = dtoh32(list->element[i]); -+ if (ch <= CH_MAX_2G_CHANNEL) -+ sf = WF_CHAN_FACTOR_2_4_G; -+ else -+ sf = WF_CHAN_FACTOR_5_G; -+ -+ range->freq[i].m = wf_channel2mhz(ch, sf); -+ range->freq[i].e = 6; -+ } -+ range->num_frequency = range->num_channels = i; -+ -+ -+ range->max_qual.qual = 5; -+ -+ range->max_qual.level = 0x100 - 200; -+ -+ range->max_qual.noise = 0x100 - 200; -+ -+ range->sensitivity = 65535; -+ -+#if WIRELESS_EXT > 11 -+ -+ range->avg_qual.qual = 3; -+ -+ range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD; -+ -+ range->avg_qual.noise = 0x100 - 75; -+#endif -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) -+ return error; -+ rateset.count = dtoh32(rateset.count); -+ range->num_bitrates = rateset.count; -+ for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) -+ range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; -+ dev_wlc_intvar_get(dev, "nmode", &nmode); -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)))) -+ return error; -+ -+ if (nmode == 1 && ((phytype == WLC_PHY_TYPE_SSN) || (phytype == WLC_PHY_TYPE_LCN) || -+ (phytype == WLC_PHY_TYPE_LCN40))) { -+ dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap); -+ dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx); -+ dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t)); -+ ci.hw_channel = dtoh32(ci.hw_channel); -+ -+ if (bw_cap == 0 || -+ (bw_cap == 2 && ci.hw_channel <= 14)) { -+ if (sgi_tx == 0) -+ nrate_list2copy = 0; -+ else -+ nrate_list2copy = 1; -+ } -+ if (bw_cap == 1 || -+ (bw_cap == 2 && ci.hw_channel >= 36)) { -+ if (sgi_tx == 0) -+ nrate_list2copy = 2; -+ else -+ nrate_list2copy = 3; -+ } -+ range->num_bitrates += 8; -+ for (k = 0; i < range->num_bitrates; k++, i++) { -+ -+ range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000; -+ } -+ } -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) -+ return error; -+ i = dtoh32(i); -+ if (i == WLC_PHY_TYPE_A) -+ range->throughput = 24000000; -+ else -+ range->throughput = 1500000; -+ -+ -+ range->min_rts = 0; -+ range->max_rts = 2347; -+ range->min_frag = 256; -+ range->max_frag = 2346; -+ -+ range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS; -+ range->num_encoding_sizes = 4; -+ range->encoding_size[0] = WEP1_KEY_SIZE; -+ range->encoding_size[1] = WEP128_KEY_SIZE; -+#if WIRELESS_EXT > 17 -+ range->encoding_size[2] = TKIP_KEY_SIZE; -+#else -+ range->encoding_size[2] = 0; -+#endif -+ range->encoding_size[3] = AES_KEY_SIZE; -+ -+ -+ range->min_pmp = 0; -+ range->max_pmp = 0; -+ range->min_pmt = 0; -+ range->max_pmt = 0; -+ range->pmp_flags = 0; -+ range->pm_capa = 0; -+ -+ -+ range->num_txpower = 2; -+ range->txpower[0] = 1; -+ range->txpower[1] = 255; -+ range->txpower_capa = IW_TXPOW_MWATT; -+ -+#if WIRELESS_EXT > 10 -+ range->we_version_compiled = WIRELESS_EXT; -+ range->we_version_source = 19; -+ -+ -+ range->retry_capa = IW_RETRY_LIMIT; -+ range->retry_flags = IW_RETRY_LIMIT; -+ range->r_time_flags = 0; -+ -+ range->min_retry = 1; -+ range->max_retry = 255; -+ -+ range->min_r_time = 0; -+ range->max_r_time = 0; -+#endif -+ -+#if WIRELESS_EXT > 17 -+ range->enc_capa = IW_ENC_CAPA_WPA; -+ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; -+ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; -+ range->enc_capa |= IW_ENC_CAPA_WPA2; -+#if (defined(BCMSUP_PSK) && defined(WLFBT)) -+ -+ range->enc_capa |= IW_ENC_CAPA_4WAY_HANDSHAKE; -+#endif -+ -+ -+ IW_EVENT_CAPA_SET_KERNEL(range->event_capa); -+ -+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); -+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); -+ IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); -+ IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); -+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE); -+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE); -+ IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); -+ -+#if WIRELESS_EXT >= 22 && defined(IW_SCAN_CAPA_ESSID) -+ -+ range->scan_capa = IW_SCAN_CAPA_ESSID; -+#endif -+#endif -+ -+ return 0; -+} -+ -+static int -+rssi_to_qual(int rssi) -+{ -+ if (rssi <= WL_IW_RSSI_NO_SIGNAL) -+ return 0; -+ else if (rssi <= WL_IW_RSSI_VERY_LOW) -+ return 1; -+ else if (rssi <= WL_IW_RSSI_LOW) -+ return 2; -+ else if (rssi <= WL_IW_RSSI_GOOD) -+ return 3; -+ else if (rssi <= WL_IW_RSSI_VERY_GOOD) -+ return 4; -+ else -+ return 5; -+} -+ -+static int -+wl_iw_set_spy( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_iw_t *iw = IW_DEV_IF(dev); -+ struct sockaddr *addr = (struct sockaddr *) extra; -+ int i; -+ -+ WL_TRACE(("%s: SIOCSIWSPY\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length); -+ for (i = 0; i < iw->spy_num; i++) -+ memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN); -+ memset(iw->spy_qual, 0, sizeof(iw->spy_qual)); -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_spy( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_iw_t *iw = IW_DEV_IF(dev); -+ struct sockaddr *addr = (struct sockaddr *) extra; -+ struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; -+ int i; -+ -+ WL_TRACE(("%s: SIOCGIWSPY\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ dwrq->length = iw->spy_num; -+ for (i = 0; i < iw->spy_num; i++) { -+ memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN); -+ addr[i].sa_family = AF_UNIX; -+ memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality)); -+ iw->spy_qual[i].updated = 0; -+ } -+ -+ return 0; -+} -+ -+static int -+wl_iw_set_wap( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct sockaddr *awrq, -+ char *extra -+) -+{ -+ int error = -EINVAL; -+ -+ WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); -+ -+ if (awrq->sa_family != ARPHRD_ETHER) { -+ WL_ERROR(("%s: Invalid Header...sa_family\n", __FUNCTION__)); -+ return -EINVAL; -+ } -+ -+ -+ if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { -+ scb_val_t scbval; -+ bzero(&scbval, sizeof(scb_val_t)); -+ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) { -+ WL_ERROR(("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error)); -+ } -+ return 0; -+ } -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { -+ WL_ERROR(("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error)); -+ return error; -+ } -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_wap( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct sockaddr *awrq, -+ char *extra -+) -+{ -+ WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); -+ -+ awrq->sa_family = ARPHRD_ETHER; -+ memset(awrq->sa_data, 0, ETHER_ADDR_LEN); -+ -+ -+ (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); -+ -+ return 0; -+} -+ -+#if WIRELESS_EXT > 17 -+static int -+wl_iw_mlme( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct sockaddr *awrq, -+ char *extra -+) -+{ -+ struct iw_mlme *mlme; -+ scb_val_t scbval; -+ int error = -EINVAL; -+ -+ WL_TRACE(("%s: SIOCSIWMLME\n", dev->name)); -+ -+ mlme = (struct iw_mlme *)extra; -+ if (mlme == NULL) { -+ WL_ERROR(("Invalid ioctl data.\n")); -+ return error; -+ } -+ -+ scbval.val = mlme->reason_code; -+ bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN); -+ -+ if (mlme->cmd == IW_MLME_DISASSOC) { -+ scbval.val = htod32(scbval.val); -+ error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); -+ } -+ else if (mlme->cmd == IW_MLME_DEAUTH) { -+ scbval.val = htod32(scbval.val); -+ error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, -+ sizeof(scb_val_t)); -+ } -+ else { -+ WL_ERROR(("%s: Invalid ioctl data.\n", __FUNCTION__)); -+ return error; -+ } -+ -+ return error; -+} -+#endif -+ -+static int -+wl_iw_get_aplist( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_scan_results_t *list; -+ struct sockaddr *addr = (struct sockaddr *) extra; -+ struct iw_quality qual[IW_MAX_AP]; -+ wl_bss_info_t *bi = NULL; -+ int error, i; -+ uint buflen = dwrq->length; -+ -+ WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ -+ list = kmalloc(buflen, GFP_KERNEL); -+ if (!list) -+ return -ENOMEM; -+ memset(list, 0, buflen); -+ list->buflen = htod32(buflen); -+ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { -+ WL_ERROR(("%d: Scan results error %d\n", __LINE__, error)); -+ kfree(list); -+ return error; -+ } -+ list->buflen = dtoh32(list->buflen); -+ list->version = dtoh32(list->version); -+ list->count = dtoh32(list->count); -+ ASSERT(list->version == WL_BSS_INFO_VERSION); -+ -+ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { -+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; -+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + -+ buflen)); -+ -+ -+ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) -+ continue; -+ -+ -+ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); -+ addr[dwrq->length].sa_family = ARPHRD_ETHER; -+ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); -+ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); -+ qual[dwrq->length].noise = 0x100 + bi->phy_noise; -+ -+ -+#if WIRELESS_EXT > 18 -+ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; -+#else -+ qual[dwrq->length].updated = 7; -+#endif -+ -+ dwrq->length++; -+ } -+ -+ kfree(list); -+ -+ if (dwrq->length) { -+ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); -+ -+ dwrq->flags = 1; -+ } -+ -+ return 0; -+} -+ -+static int -+wl_iw_iscan_get_aplist( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_scan_results_t *list; -+ iscan_buf_t * buf; -+ iscan_info_t *iscan = g_iscan; -+ -+ struct sockaddr *addr = (struct sockaddr *) extra; -+ struct iw_quality qual[IW_MAX_AP]; -+ wl_bss_info_t *bi = NULL; -+ int i; -+ -+ WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ if ((!iscan) || (iscan->sysioc_pid < 0)) { -+ return wl_iw_get_aplist(dev, info, dwrq, extra); -+ } -+ -+ buf = iscan->list_hdr; -+ -+ while (buf) { -+ list = &((wl_iscan_results_t*)buf->iscan_buf)->results; -+ ASSERT(list->version == WL_BSS_INFO_VERSION); -+ -+ bi = NULL; -+ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { -+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; -+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + -+ WLC_IW_ISCAN_MAXLEN)); -+ -+ -+ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS)) -+ continue; -+ -+ -+ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); -+ addr[dwrq->length].sa_family = ARPHRD_ETHER; -+ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI)); -+ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI); -+ qual[dwrq->length].noise = 0x100 + bi->phy_noise; -+ -+ -+#if WIRELESS_EXT > 18 -+ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; -+#else -+ qual[dwrq->length].updated = 7; -+#endif -+ -+ dwrq->length++; -+ } -+ buf = buf->next; -+ } -+ if (dwrq->length) { -+ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); -+ -+ dwrq->flags = 1; -+ } -+ -+ return 0; -+} -+ -+#if WIRELESS_EXT > 13 -+static int -+wl_iw_set_scan( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, -+ char *extra -+) -+{ -+ wlc_ssid_t ssid; -+ -+ WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); -+ -+ -+ memset(&ssid, 0, sizeof(ssid)); -+ -+#if WIRELESS_EXT > 17 -+ -+ if (wrqu->data.length == sizeof(struct iw_scan_req)) { -+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { -+ struct iw_scan_req *req = (struct iw_scan_req *)extra; -+ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); -+ memcpy(ssid.SSID, req->essid, ssid.SSID_len); -+ ssid.SSID_len = htod32(ssid.SSID_len); -+ } -+ } -+#endif -+ -+ (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid)); -+ -+ return 0; -+} -+ -+static int -+wl_iw_iscan_set_scan( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, -+ char *extra -+) -+{ -+ wlc_ssid_t ssid; -+ iscan_info_t *iscan = g_iscan; -+ -+ WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); -+ -+ -+ if ((!iscan) || (iscan->sysioc_pid < 0)) { -+ return wl_iw_set_scan(dev, info, wrqu, extra); -+ } -+ if (iscan->iscan_state == ISCAN_STATE_SCANING) { -+ return 0; -+ } -+ -+ -+ memset(&ssid, 0, sizeof(ssid)); -+ -+#if WIRELESS_EXT > 17 -+ -+ if (wrqu->data.length == sizeof(struct iw_scan_req)) { -+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { -+ struct iw_scan_req *req = (struct iw_scan_req *)extra; -+ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len); -+ memcpy(ssid.SSID, req->essid, ssid.SSID_len); -+ ssid.SSID_len = htod32(ssid.SSID_len); -+ } -+ } -+#endif -+ -+ iscan->list_cur = iscan->list_hdr; -+ iscan->iscan_state = ISCAN_STATE_SCANING; -+ -+ -+ wl_iw_set_event_mask(dev); -+ wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START); -+ -+ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); -+ add_timer(&iscan->timer); -+ iscan->timer_on = 1; -+ -+ return 0; -+} -+ -+#if WIRELESS_EXT > 17 -+static bool -+ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len) -+{ -+ -+ -+ uint8 *ie = *wpaie; -+ -+ -+ if ((ie[1] >= 6) && -+ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { -+ return TRUE; -+ } -+ -+ -+ ie += ie[1] + 2; -+ -+ *tlvs_len -= (int)(ie - *tlvs); -+ -+ *tlvs = ie; -+ return FALSE; -+} -+ -+static bool -+ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len) -+{ -+ -+ -+ uint8 *ie = *wpsie; -+ -+ -+ if ((ie[1] >= 4) && -+ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) { -+ return TRUE; -+ } -+ -+ -+ ie += ie[1] + 2; -+ -+ *tlvs_len -= (int)(ie - *tlvs); -+ -+ *tlvs = ie; -+ return FALSE; -+} -+#endif -+ -+ -+static int -+wl_iw_handle_scanresults_ies(char **event_p, char *end, -+ struct iw_request_info *info, wl_bss_info_t *bi) -+{ -+#if WIRELESS_EXT > 17 -+ struct iw_event iwe; -+ char *event; -+ -+ event = *event_p; -+ if (bi->ie_length) { -+ -+ bcm_tlv_t *ie; -+ uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); -+ int ptr_len = bi->ie_length; -+ -+ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) { -+ iwe.cmd = IWEVGENIE; -+ iwe.u.data.length = ie->len + 2; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); -+ } -+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); -+ -+#if defined(WLFBT) -+ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_MDIE_ID))) { -+ iwe.cmd = IWEVGENIE; -+ iwe.u.data.length = ie->len + 2; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); -+ } -+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); -+#endif -+ -+ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { -+ -+ if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) { -+ iwe.cmd = IWEVGENIE; -+ iwe.u.data.length = ie->len + 2; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); -+ break; -+ } -+ } -+ -+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t); -+ ptr_len = bi->ie_length; -+ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { -+ if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) { -+ iwe.cmd = IWEVGENIE; -+ iwe.u.data.length = ie->len + 2; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie); -+ break; -+ } -+ } -+ -+ *event_p = event; -+ } -+ -+#endif -+ return 0; -+} -+static int -+wl_iw_get_scan( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ channel_info_t ci; -+ wl_scan_results_t *list; -+ struct iw_event iwe; -+ wl_bss_info_t *bi = NULL; -+ int error, i, j; -+ char *event = extra, *end = extra + dwrq->length, *value; -+ uint buflen = dwrq->length; -+ -+ WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) -+ return error; -+ ci.scan_channel = dtoh32(ci.scan_channel); -+ if (ci.scan_channel) -+ return -EAGAIN; -+ -+ -+ list = kmalloc(buflen, GFP_KERNEL); -+ if (!list) -+ return -ENOMEM; -+ memset(list, 0, buflen); -+ list->buflen = htod32(buflen); -+ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) { -+ kfree(list); -+ return error; -+ } -+ list->buflen = dtoh32(list->buflen); -+ list->version = dtoh32(list->version); -+ list->count = dtoh32(list->count); -+ -+ ASSERT(list->version == WL_BSS_INFO_VERSION); -+ -+ for (i = 0; i < list->count && i < IW_MAX_AP; i++) { -+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; -+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + -+ buflen)); -+ -+ -+ iwe.cmd = SIOCGIWAP; -+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; -+ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); -+ -+ -+ iwe.u.data.length = dtoh32(bi->SSID_len); -+ iwe.cmd = SIOCGIWESSID; -+ iwe.u.data.flags = 1; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); -+ -+ -+ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { -+ iwe.cmd = SIOCGIWMODE; -+ if (dtoh16(bi->capability) & DOT11_CAP_ESS) -+ iwe.u.mode = IW_MODE_INFRA; -+ else -+ iwe.u.mode = IW_MODE_ADHOC; -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); -+ } -+ -+ -+ iwe.cmd = SIOCGIWFREQ; -+ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), -+ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? -+ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); -+ iwe.u.freq.e = 6; -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); -+ -+ -+ iwe.cmd = IWEVQUAL; -+ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); -+ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); -+ iwe.u.qual.noise = 0x100 + bi->phy_noise; -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); -+ -+ -+ wl_iw_handle_scanresults_ies(&event, end, info, bi); -+ -+ -+ iwe.cmd = SIOCGIWENCODE; -+ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) -+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; -+ else -+ iwe.u.data.flags = IW_ENCODE_DISABLED; -+ iwe.u.data.length = 0; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); -+ -+ -+ if (bi->rateset.count) { -+ value = event + IW_EV_LCP_LEN; -+ iwe.cmd = SIOCGIWRATE; -+ -+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; -+ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { -+ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; -+ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, -+ IW_EV_PARAM_LEN); -+ } -+ event = value; -+ } -+ } -+ -+ kfree(list); -+ -+ dwrq->length = event - extra; -+ dwrq->flags = 0; -+ -+ return 0; -+} -+ -+static int -+wl_iw_iscan_get_scan( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_scan_results_t *list; -+ struct iw_event iwe; -+ wl_bss_info_t *bi = NULL; -+ int ii, j; -+ int apcnt; -+ char *event = extra, *end = extra + dwrq->length, *value; -+ iscan_info_t *iscan = g_iscan; -+ iscan_buf_t * p_buf; -+ -+ WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ -+ if ((!iscan) || (iscan->sysioc_pid < 0)) { -+ return wl_iw_get_scan(dev, info, dwrq, extra); -+ } -+ -+ -+ if (iscan->iscan_state == ISCAN_STATE_SCANING) -+ return -EAGAIN; -+ -+ apcnt = 0; -+ p_buf = iscan->list_hdr; -+ -+ while (p_buf != iscan->list_cur) { -+ list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results; -+ -+ if (list->version != WL_BSS_INFO_VERSION) { -+ WL_ERROR(("list->version %d != WL_BSS_INFO_VERSION\n", list->version)); -+ } -+ -+ bi = NULL; -+ for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) { -+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info; -+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list + -+ WLC_IW_ISCAN_MAXLEN)); -+ -+ -+ if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + -+ IW_EV_QUAL_LEN >= end) -+ return -E2BIG; -+ -+ iwe.cmd = SIOCGIWAP; -+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; -+ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN); -+ -+ -+ iwe.u.data.length = dtoh32(bi->SSID_len); -+ iwe.cmd = SIOCGIWESSID; -+ iwe.u.data.flags = 1; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID); -+ -+ -+ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { -+ iwe.cmd = SIOCGIWMODE; -+ if (dtoh16(bi->capability) & DOT11_CAP_ESS) -+ iwe.u.mode = IW_MODE_INFRA; -+ else -+ iwe.u.mode = IW_MODE_ADHOC; -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN); -+ } -+ -+ -+ iwe.cmd = SIOCGIWFREQ; -+ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec), -+ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ? -+ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G); -+ iwe.u.freq.e = 6; -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN); -+ -+ -+ iwe.cmd = IWEVQUAL; -+ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI)); -+ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI); -+ iwe.u.qual.noise = 0x100 + bi->phy_noise; -+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN); -+ -+ -+ wl_iw_handle_scanresults_ies(&event, end, info, bi); -+ -+ -+ iwe.cmd = SIOCGIWENCODE; -+ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY) -+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; -+ else -+ iwe.u.data.flags = IW_ENCODE_DISABLED; -+ iwe.u.data.length = 0; -+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event); -+ -+ -+ if (bi->rateset.count <= sizeof(bi->rateset.rates)) { -+ if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) -+ return -E2BIG; -+ -+ value = event + IW_EV_LCP_LEN; -+ iwe.cmd = SIOCGIWRATE; -+ -+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; -+ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { -+ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; -+ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe, -+ IW_EV_PARAM_LEN); -+ } -+ event = value; -+ } -+ } -+ p_buf = p_buf->next; -+ } -+ -+ dwrq->length = event - extra; -+ dwrq->flags = 0; -+ -+ return 0; -+} -+ -+#endif -+ -+ -+static int -+wl_iw_set_essid( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wlc_ssid_t ssid; -+ int error; -+ -+ WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); -+ -+ -+ memset(&ssid, 0, sizeof(ssid)); -+ if (dwrq->length && extra) { -+#if WIRELESS_EXT > 20 -+ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length); -+#else -+ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length-1); -+#endif -+ memcpy(ssid.SSID, extra, ssid.SSID_len); -+ ssid.SSID_len = htod32(ssid.SSID_len); -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid)))) -+ return error; -+ } -+ -+ else { -+ scb_val_t scbval; -+ bzero(&scbval, sizeof(scb_val_t)); -+ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) -+ return error; -+ } -+ return 0; -+} -+ -+static int -+wl_iw_get_essid( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wlc_ssid_t ssid; -+ int error; -+ -+ WL_TRACE(("%s: SIOCGIWESSID\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) { -+ WL_ERROR(("Error getting the SSID\n")); -+ return error; -+ } -+ -+ ssid.SSID_len = dtoh32(ssid.SSID_len); -+ -+ -+ memcpy(extra, ssid.SSID, ssid.SSID_len); -+ -+ dwrq->length = ssid.SSID_len; -+ -+ dwrq->flags = 1; -+ -+ return 0; -+} -+ -+static int -+wl_iw_set_nick( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_iw_t *iw = IW_DEV_IF(dev); -+ WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ -+ if (dwrq->length > sizeof(iw->nickname)) -+ return -E2BIG; -+ -+ memcpy(iw->nickname, extra, dwrq->length); -+ iw->nickname[dwrq->length - 1] = '\0'; -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_nick( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_iw_t *iw = IW_DEV_IF(dev); -+ WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); -+ -+ if (!extra) -+ return -EINVAL; -+ -+ strcpy(extra, iw->nickname); -+ dwrq->length = strlen(extra) + 1; -+ -+ return 0; -+} -+ -+static int wl_iw_set_rate( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ wl_rateset_t rateset; -+ int error, rate, i, error_bg, error_a; -+ -+ WL_TRACE(("%s: SIOCSIWRATE\n", dev->name)); -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) -+ return error; -+ -+ rateset.count = dtoh32(rateset.count); -+ -+ if (vwrq->value < 0) { -+ -+ rate = rateset.rates[rateset.count - 1] & 0x7f; -+ } else if (vwrq->value < rateset.count) { -+ -+ rate = rateset.rates[vwrq->value] & 0x7f; -+ } else { -+ -+ rate = vwrq->value / 500000; -+ } -+ -+ if (vwrq->fixed) { -+ -+ error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate); -+ error_a = dev_wlc_intvar_set(dev, "a_rate", rate); -+ -+ if (error_bg && error_a) -+ return (error_bg | error_a); -+ } else { -+ -+ -+ error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0); -+ -+ error_a = dev_wlc_intvar_set(dev, "a_rate", 0); -+ -+ if (error_bg && error_a) -+ return (error_bg | error_a); -+ -+ -+ for (i = 0; i < rateset.count; i++) -+ if ((rateset.rates[i] & 0x7f) > rate) -+ break; -+ rateset.count = htod32(i); -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset)))) -+ return error; -+ } -+ -+ return 0; -+} -+ -+static int wl_iw_get_rate( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, rate; -+ -+ WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) -+ return error; -+ rate = dtoh32(rate); -+ vwrq->value = rate * 500000; -+ -+ return 0; -+} -+ -+static int -+wl_iw_set_rts( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, rts; -+ -+ WL_TRACE(("%s: SIOCSIWRTS\n", dev->name)); -+ -+ if (vwrq->disabled) -+ rts = DOT11_DEFAULT_RTS_LEN; -+ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN) -+ return -EINVAL; -+ else -+ rts = vwrq->value; -+ -+ if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts))) -+ return error; -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_rts( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, rts; -+ -+ WL_TRACE(("%s: SIOCGIWRTS\n", dev->name)); -+ -+ if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts))) -+ return error; -+ -+ vwrq->value = rts; -+ vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN); -+ vwrq->fixed = 1; -+ -+ return 0; -+} -+ -+static int -+wl_iw_set_frag( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, frag; -+ -+ WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name)); -+ -+ if (vwrq->disabled) -+ frag = DOT11_DEFAULT_FRAG_LEN; -+ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN) -+ return -EINVAL; -+ else -+ frag = vwrq->value; -+ -+ if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag))) -+ return error; -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_frag( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, fragthreshold; -+ -+ WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name)); -+ -+ if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold))) -+ return error; -+ -+ vwrq->value = fragthreshold; -+ vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN); -+ vwrq->fixed = 1; -+ -+ return 0; -+} -+ -+static int -+wl_iw_set_txpow( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, disable; -+ uint16 txpwrmw; -+ WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name)); -+ -+ -+ disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0; -+ disable += WL_RADIO_SW_DISABLE << 16; -+ -+ disable = htod32(disable); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable)))) -+ return error; -+ -+ -+ if (disable & WL_RADIO_SW_DISABLE) -+ return 0; -+ -+ -+ if (!(vwrq->flags & IW_TXPOW_MWATT)) -+ return -EINVAL; -+ -+ -+ if (vwrq->value < 0) -+ return 0; -+ -+ if (vwrq->value > 0xffff) txpwrmw = 0xffff; -+ else txpwrmw = (uint16)vwrq->value; -+ -+ -+ error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw))); -+ return error; -+} -+ -+static int -+wl_iw_get_txpow( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, disable, txpwrdbm; -+ uint8 result; -+ -+ WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name)); -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) || -+ (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm))) -+ return error; -+ -+ disable = dtoh32(disable); -+ result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE); -+ vwrq->value = (int32)bcm_qdbm_to_mw(result); -+ vwrq->fixed = 0; -+ vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0; -+ vwrq->flags = IW_TXPOW_MWATT; -+ -+ return 0; -+} -+ -+#if WIRELESS_EXT > 10 -+static int -+wl_iw_set_retry( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, lrl, srl; -+ -+ WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name)); -+ -+ -+ if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME)) -+ return -EINVAL; -+ -+ -+ if (vwrq->flags & IW_RETRY_LIMIT) { -+ -+#if WIRELESS_EXT > 20 -+ if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) || -+ !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) { -+#else -+ if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) { -+#endif -+ -+ lrl = htod32(vwrq->value); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl)))) -+ return error; -+ } -+ -+#if WIRELESS_EXT > 20 -+ if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) || -+ !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) { -+#else -+ if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) { -+#endif -+ -+ srl = htod32(vwrq->value); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl)))) -+ return error; -+ } -+ } -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_retry( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, lrl, srl; -+ -+ WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name)); -+ -+ vwrq->disabled = 0; -+ -+ -+ if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) -+ return -EINVAL; -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) || -+ (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl)))) -+ return error; -+ -+ lrl = dtoh32(lrl); -+ srl = dtoh32(srl); -+ -+ -+ if (vwrq->flags & IW_RETRY_MAX) { -+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; -+ vwrq->value = lrl; -+ } else { -+ vwrq->flags = IW_RETRY_LIMIT; -+ vwrq->value = srl; -+ if (srl != lrl) -+ vwrq->flags |= IW_RETRY_MIN; -+ } -+ -+ return 0; -+} -+#endif -+ -+static int -+wl_iw_set_encode( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_wsec_key_t key; -+ int error, val, wsec; -+ -+ WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name)); -+ -+ memset(&key, 0, sizeof(key)); -+ -+ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { -+ -+ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { -+ val = htod32(key.index); -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) -+ return error; -+ val = dtoh32(val); -+ if (val) -+ break; -+ } -+ -+ if (key.index == DOT11_MAX_DEFAULT_KEYS) -+ key.index = 0; -+ } else { -+ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; -+ if (key.index >= DOT11_MAX_DEFAULT_KEYS) -+ return -EINVAL; -+ } -+ -+ -+ wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED; -+ -+ if ((error = dev_wlc_intvar_set(dev, "wsec", wsec))) -+ return error; -+ -+ -+ if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) { -+ -+ val = htod32(key.index); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val)))) -+ return error; -+ } else { -+ key.len = dwrq->length; -+ -+ if (dwrq->length > sizeof(key.data)) -+ return -EINVAL; -+ -+ memcpy(key.data, extra, dwrq->length); -+ -+ key.flags = WL_PRIMARY_KEY; -+ switch (key.len) { -+ case WEP1_KEY_SIZE: -+ key.algo = CRYPTO_ALGO_WEP1; -+ break; -+ case WEP128_KEY_SIZE: -+ key.algo = CRYPTO_ALGO_WEP128; -+ break; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) -+ case TKIP_KEY_SIZE: -+ key.algo = CRYPTO_ALGO_TKIP; -+ break; -+#endif -+ case AES_KEY_SIZE: -+ key.algo = CRYPTO_ALGO_AES_CCM; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ -+ swap_key_from_BE(&key); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)))) -+ return error; -+ } -+ -+ -+ val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0; -+ val = htod32(val); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)))) -+ return error; -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_encode( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_wsec_key_t key; -+ int error, val, wsec, auth; -+ -+ WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name)); -+ -+ -+ bzero(&key, sizeof(wl_wsec_key_t)); -+ -+ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) { -+ -+ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) { -+ val = key.index; -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val)))) -+ return error; -+ val = dtoh32(val); -+ if (val) -+ break; -+ } -+ } else -+ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; -+ -+ if (key.index >= DOT11_MAX_DEFAULT_KEYS) -+ key.index = 0; -+ -+ -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) || -+ (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth)))) -+ return error; -+ -+ swap_key_to_BE(&key); -+ -+ wsec = dtoh32(wsec); -+ auth = dtoh32(auth); -+ -+ dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len); -+ -+ -+ dwrq->flags = key.index + 1; -+ if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) { -+ -+ dwrq->flags |= IW_ENCODE_DISABLED; -+ } -+ if (auth) { -+ -+ dwrq->flags |= IW_ENCODE_RESTRICTED; -+ } -+ -+ -+ if (dwrq->length && extra) -+ memcpy(extra, key.data, dwrq->length); -+ -+ return 0; -+} -+ -+static int -+wl_iw_set_power( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, pm; -+ -+ WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name)); -+ -+ pm = vwrq->disabled ? PM_OFF : PM_MAX; -+ -+ pm = htod32(pm); -+ if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)))) -+ return error; -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_power( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error, pm; -+ -+ WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name)); -+ -+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm)))) -+ return error; -+ -+ pm = dtoh32(pm); -+ vwrq->disabled = pm ? 0 : 1; -+ vwrq->flags = IW_POWER_ALL_R; -+ -+ return 0; -+} -+ -+#if WIRELESS_EXT > 17 -+static int -+wl_iw_set_wpaie( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *iwp, -+ char *extra -+) -+{ -+ dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length); -+ -+ return 0; -+} -+ -+static int -+wl_iw_get_wpaie( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *iwp, -+ char *extra -+) -+{ -+ WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name)); -+ iwp->length = 64; -+ dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length); -+ return 0; -+} -+ -+static int -+wl_iw_set_encodeext( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_point *dwrq, -+ char *extra -+) -+{ -+ wl_wsec_key_t key; -+ int error; -+ struct iw_encode_ext *iwe; -+ -+ WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name)); -+ -+ memset(&key, 0, sizeof(key)); -+ iwe = (struct iw_encode_ext *)extra; -+ -+ -+ if (dwrq->flags & IW_ENCODE_DISABLED) { -+ -+ } -+ -+ -+ key.index = 0; -+ if (dwrq->flags & IW_ENCODE_INDEX) -+ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1; -+ -+ key.len = iwe->key_len; -+ -+ -+ if (!ETHER_ISMULTI(iwe->addr.sa_data)) -+ bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN); -+ -+ -+ if (key.len == 0) { -+ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { -+ WL_WSEC(("Changing the the primary Key to %d\n", key.index)); -+ -+ key.index = htod32(key.index); -+ error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, -+ &key.index, sizeof(key.index)); -+ if (error) -+ return error; -+ } -+ -+ else { -+ swap_key_from_BE(&key); -+ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); -+ if (error) -+ return error; -+ } -+ } -+#if (defined(BCMSUP_PSK) && defined(WLFBT)) -+ -+ else if (iwe->alg == IW_ENCODE_ALG_PMK) { -+ int j; -+ wsec_pmk_t pmk; -+ char keystring[WSEC_MAX_PSK_LEN + 1]; -+ char* charptr = keystring; -+ uint len; -+ -+ -+ for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) { -+ sprintf(charptr, "%02x", iwe->key[j]); -+ charptr += 2; -+ } -+ len = strlen(keystring); -+ pmk.key_len = htod16(len); -+ bcopy(keystring, pmk.key, len); -+ pmk.flags = htod16(WSEC_PASSPHRASE); -+ -+ error = dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk)); -+ if (error) -+ return error; -+ } -+#endif -+ -+ else { -+ if (iwe->key_len > sizeof(key.data)) -+ return -EINVAL; -+ -+ WL_WSEC(("Setting the key index %d\n", key.index)); -+ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { -+ WL_WSEC(("key is a Primary Key\n")); -+ key.flags = WL_PRIMARY_KEY; -+ } -+ -+ bcopy((void *)iwe->key, key.data, iwe->key_len); -+ -+ if (iwe->alg == IW_ENCODE_ALG_TKIP) { -+ uint8 keybuf[8]; -+ bcopy(&key.data[24], keybuf, sizeof(keybuf)); -+ bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); -+ bcopy(keybuf, &key.data[16], sizeof(keybuf)); -+ } -+ -+ -+ if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { -+ uchar *ivptr; -+ ivptr = (uchar *)iwe->rx_seq; -+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | -+ (ivptr[3] << 8) | ivptr[2]; -+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; -+ key.iv_initialized = TRUE; -+ } -+ -+ switch (iwe->alg) { -+ case IW_ENCODE_ALG_NONE: -+ key.algo = CRYPTO_ALGO_OFF; -+ break; -+ case IW_ENCODE_ALG_WEP: -+ if (iwe->key_len == WEP1_KEY_SIZE) -+ key.algo = CRYPTO_ALGO_WEP1; -+ else -+ key.algo = CRYPTO_ALGO_WEP128; -+ break; -+ case IW_ENCODE_ALG_TKIP: -+ key.algo = CRYPTO_ALGO_TKIP; -+ break; -+ case IW_ENCODE_ALG_CCMP: -+ key.algo = CRYPTO_ALGO_AES_CCM; -+ break; -+ default: -+ break; -+ } -+ swap_key_from_BE(&key); -+ -+ dhd_wait_pend8021x(dev); -+ -+ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key)); -+ if (error) -+ return error; -+ } -+ return 0; -+} -+ -+ -+#if WIRELESS_EXT > 17 -+struct { -+ pmkid_list_t pmkids; -+ pmkid_t foo[MAXPMKID-1]; -+} pmkid_list; -+static int -+wl_iw_set_pmksa( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ struct iw_pmksa *iwpmksa; -+ uint i; -+ char eabuf[ETHER_ADDR_STR_LEN]; -+ pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid; -+ -+ WL_TRACE(("%s: SIOCSIWPMKSA\n", dev->name)); -+ iwpmksa = (struct iw_pmksa *)extra; -+ bzero((char *)eabuf, ETHER_ADDR_STR_LEN); -+ if (iwpmksa->cmd == IW_PMKSA_FLUSH) { -+ WL_TRACE(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n")); -+ bzero((char *)&pmkid_list, sizeof(pmkid_list)); -+ } -+ if (iwpmksa->cmd == IW_PMKSA_REMOVE) { -+ pmkid_list_t pmkid, *pmkidptr; -+ pmkidptr = &pmkid; -+ bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN); -+ bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN); -+ { -+ uint j; -+ WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ", -+ bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID, -+ eabuf))); -+ for (j = 0; j < WPA2_PMKID_LEN; j++) -+ WL_TRACE(("%02x ", pmkidptr->pmkid[0].PMKID[j])); -+ WL_TRACE(("\n")); -+ } -+ for (i = 0; i < pmkid_list.pmkids.npmkid; i++) -+ if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID, -+ ETHER_ADDR_LEN)) -+ break; -+ for (; i < pmkid_list.pmkids.npmkid; i++) { -+ bcopy(&pmkid_array[i+1].BSSID, -+ &pmkid_array[i].BSSID, -+ ETHER_ADDR_LEN); -+ bcopy(&pmkid_array[i+1].PMKID, -+ &pmkid_array[i].PMKID, -+ WPA2_PMKID_LEN); -+ } -+ pmkid_list.pmkids.npmkid--; -+ } -+ if (iwpmksa->cmd == IW_PMKSA_ADD) { -+ bcopy(&iwpmksa->bssid.sa_data[0], -+ &pmkid_array[pmkid_list.pmkids.npmkid].BSSID, -+ ETHER_ADDR_LEN); -+ bcopy(&iwpmksa->pmkid[0], &pmkid_array[pmkid_list.pmkids.npmkid].PMKID, -+ WPA2_PMKID_LEN); -+ { -+ uint j; -+ uint k; -+ k = pmkid_list.pmkids.npmkid; -+ BCM_REFERENCE(k); -+ WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ", -+ bcm_ether_ntoa(&pmkid_array[k].BSSID, -+ eabuf))); -+ for (j = 0; j < WPA2_PMKID_LEN; j++) -+ WL_TRACE(("%02x ", pmkid_array[k].PMKID[j])); -+ WL_TRACE(("\n")); -+ } -+ pmkid_list.pmkids.npmkid++; -+ } -+ WL_TRACE(("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid)); -+ for (i = 0; i < pmkid_list.pmkids.npmkid; i++) { -+ uint j; -+ WL_TRACE(("PMKID[%d]: %s = ", i, -+ bcm_ether_ntoa(&pmkid_array[i].BSSID, -+ eabuf))); -+ for (j = 0; j < WPA2_PMKID_LEN; j++) -+ WL_TRACE(("%02x ", pmkid_array[i].PMKID[j])); -+ printf("\n"); -+ } -+ WL_TRACE(("\n")); -+ dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list)); -+ return 0; -+} -+#endif -+ -+static int -+wl_iw_get_encodeext( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name)); -+ return 0; -+} -+ -+static int -+wl_iw_set_wpaauth( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error = 0; -+ int paramid; -+ int paramval; -+ uint32 cipher_combined; -+ int val = 0; -+ wl_iw_t *iw = IW_DEV_IF(dev); -+ -+ WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name)); -+ -+ paramid = vwrq->flags & IW_AUTH_INDEX; -+ paramval = vwrq->value; -+ -+ WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n", -+ dev->name, paramid, paramval)); -+ -+ switch (paramid) { -+ -+ case IW_AUTH_WPA_VERSION: -+ -+ if (paramval & IW_AUTH_WPA_VERSION_DISABLED) -+ val = WPA_AUTH_DISABLED; -+ else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) -+ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; -+ else if (paramval & IW_AUTH_WPA_VERSION_WPA2) -+ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; -+ WL_TRACE(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val)); -+ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) -+ return error; -+ break; -+ -+ case IW_AUTH_CIPHER_PAIRWISE: -+ case IW_AUTH_CIPHER_GROUP: -+ -+ if (paramid == IW_AUTH_CIPHER_PAIRWISE) { -+ iw->pwsec = paramval; -+ } -+ else { -+ iw->gwsec = paramval; -+ } -+ -+ if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) -+ return error; -+ -+ cipher_combined = iw->gwsec | iw->pwsec; -+ val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED); -+ if (cipher_combined & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) -+ val |= WEP_ENABLED; -+ if (cipher_combined & IW_AUTH_CIPHER_TKIP) -+ val |= TKIP_ENABLED; -+ if (cipher_combined & IW_AUTH_CIPHER_CCMP) -+ val |= AES_ENABLED; -+ -+ if (iw->privacy_invoked && !val) { -+ WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming " -+ "we're a WPS enrollee\n", dev->name, __FUNCTION__)); -+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { -+ WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); -+ return error; -+ } -+ } else if (val) { -+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { -+ WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); -+ return error; -+ } -+ } -+ -+ if ((error = dev_wlc_intvar_set(dev, "wsec", val))) -+ return error; -+#ifdef WLFBT -+ if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val | AES_ENABLED)) { -+ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1))) -+ return error; -+ } -+ else if (val == 0) { -+ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0))) -+ return error; -+ } -+#endif -+ break; -+ -+ case IW_AUTH_KEY_MGMT: -+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) -+ return error; -+ -+ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { -+ if (paramval & IW_AUTH_KEY_MGMT_PSK) -+ val = WPA_AUTH_PSK; -+ else -+ val = WPA_AUTH_UNSPECIFIED; -+ } -+ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { -+ if (paramval & IW_AUTH_KEY_MGMT_PSK) -+ val = WPA2_AUTH_PSK; -+ else -+ val = WPA2_AUTH_UNSPECIFIED; -+ } -+ WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); -+ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) -+ return error; -+ break; -+ -+ case IW_AUTH_TKIP_COUNTERMEASURES: -+ dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)¶mval, 1); -+ break; -+ -+ case IW_AUTH_80211_AUTH_ALG: -+ -+ WL_ERROR(("Setting the D11auth %d\n", paramval)); -+ if (paramval & IW_AUTH_ALG_OPEN_SYSTEM) -+ val = 0; -+ else if (paramval & IW_AUTH_ALG_SHARED_KEY) -+ val = 1; -+ else -+ error = 1; -+ if (!error && (error = dev_wlc_intvar_set(dev, "auth", val))) -+ return error; -+ break; -+ -+ case IW_AUTH_WPA_ENABLED: -+ if (paramval == 0) { -+ val = 0; -+ WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val)); -+ error = dev_wlc_intvar_set(dev, "wpa_auth", val); -+ return error; -+ } -+ else { -+ -+ } -+ break; -+ -+ case IW_AUTH_DROP_UNENCRYPTED: -+ dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)¶mval, 1); -+ break; -+ -+ case IW_AUTH_RX_UNENCRYPTED_EAPOL: -+ dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); -+ break; -+ -+#if WIRELESS_EXT > 17 -+ -+ case IW_AUTH_ROAMING_CONTROL: -+ WL_TRACE(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); -+ -+ break; -+ -+ case IW_AUTH_PRIVACY_INVOKED: { -+ int wsec; -+ -+ if (paramval == 0) { -+ iw->privacy_invoked = FALSE; -+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { -+ WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); -+ return error; -+ } -+ } else { -+ iw->privacy_invoked = TRUE; -+ if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec))) -+ return error; -+ -+ if (!WSEC_ENABLED(wsec)) { -+ -+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) { -+ WL_WSEC(("Failed to set iovar is_WPS_enrollee\n")); -+ return error; -+ } -+ } else { -+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) { -+ WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n")); -+ return error; -+ } -+ } -+ } -+ break; -+ } -+ -+ -+#endif -+ -+ -+ default: -+ break; -+ } -+ return 0; -+} -+#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK)) -+ -+static int -+wl_iw_get_wpaauth( -+ struct net_device *dev, -+ struct iw_request_info *info, -+ struct iw_param *vwrq, -+ char *extra -+) -+{ -+ int error; -+ int paramid; -+ int paramval = 0; -+ int val; -+ wl_iw_t *iw = IW_DEV_IF(dev); -+ -+ WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name)); -+ -+ paramid = vwrq->flags & IW_AUTH_INDEX; -+ -+ switch (paramid) { -+ case IW_AUTH_WPA_VERSION: -+ -+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) -+ return error; -+ if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED)) -+ paramval = IW_AUTH_WPA_VERSION_DISABLED; -+ else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) -+ paramval = IW_AUTH_WPA_VERSION_WPA; -+ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) -+ paramval = IW_AUTH_WPA_VERSION_WPA2; -+ break; -+ -+ case IW_AUTH_CIPHER_PAIRWISE: -+ paramval = iw->pwsec; -+ break; -+ -+ case IW_AUTH_CIPHER_GROUP: -+ paramval = iw->gwsec; -+ break; -+ -+ case IW_AUTH_KEY_MGMT: -+ -+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) -+ return error; -+ if (VAL_PSK(val)) -+ paramval = IW_AUTH_KEY_MGMT_PSK; -+ else -+ paramval = IW_AUTH_KEY_MGMT_802_1X; -+ -+ break; -+ case IW_AUTH_TKIP_COUNTERMEASURES: -+ dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)¶mval, 1); -+ break; -+ -+ case IW_AUTH_DROP_UNENCRYPTED: -+ dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)¶mval, 1); -+ break; -+ -+ case IW_AUTH_RX_UNENCRYPTED_EAPOL: -+ dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)¶mval, 1); -+ break; -+ -+ case IW_AUTH_80211_AUTH_ALG: -+ -+ if ((error = dev_wlc_intvar_get(dev, "auth", &val))) -+ return error; -+ if (!val) -+ paramval = IW_AUTH_ALG_OPEN_SYSTEM; -+ else -+ paramval = IW_AUTH_ALG_SHARED_KEY; -+ break; -+ case IW_AUTH_WPA_ENABLED: -+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) -+ return error; -+ if (val) -+ paramval = TRUE; -+ else -+ paramval = FALSE; -+ break; -+ -+#if WIRELESS_EXT > 17 -+ -+ case IW_AUTH_ROAMING_CONTROL: -+ WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__)); -+ -+ break; -+ -+ case IW_AUTH_PRIVACY_INVOKED: -+ paramval = iw->privacy_invoked; -+ break; -+ -+#endif -+ } -+ vwrq->value = paramval; -+ return 0; -+} -+#endif -+ -+static const iw_handler wl_iw_handler[] = -+{ -+ (iw_handler) wl_iw_config_commit, -+ (iw_handler) wl_iw_get_name, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) wl_iw_set_freq, -+ (iw_handler) wl_iw_get_freq, -+ (iw_handler) wl_iw_set_mode, -+ (iw_handler) wl_iw_get_mode, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) wl_iw_get_range, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) wl_iw_set_spy, -+ (iw_handler) wl_iw_get_spy, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) wl_iw_set_wap, -+ (iw_handler) wl_iw_get_wap, -+#if WIRELESS_EXT > 17 -+ (iw_handler) wl_iw_mlme, -+#else -+ (iw_handler) NULL, -+#endif -+ (iw_handler) wl_iw_iscan_get_aplist, -+#if WIRELESS_EXT > 13 -+ (iw_handler) wl_iw_iscan_set_scan, -+ (iw_handler) wl_iw_iscan_get_scan, -+#else -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+#endif -+ (iw_handler) wl_iw_set_essid, -+ (iw_handler) wl_iw_get_essid, -+ (iw_handler) wl_iw_set_nick, -+ (iw_handler) wl_iw_get_nick, -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) wl_iw_set_rate, -+ (iw_handler) wl_iw_get_rate, -+ (iw_handler) wl_iw_set_rts, -+ (iw_handler) wl_iw_get_rts, -+ (iw_handler) wl_iw_set_frag, -+ (iw_handler) wl_iw_get_frag, -+ (iw_handler) wl_iw_set_txpow, -+ (iw_handler) wl_iw_get_txpow, -+#if WIRELESS_EXT > 10 -+ (iw_handler) wl_iw_set_retry, -+ (iw_handler) wl_iw_get_retry, -+#endif -+ (iw_handler) wl_iw_set_encode, -+ (iw_handler) wl_iw_get_encode, -+ (iw_handler) wl_iw_set_power, -+ (iw_handler) wl_iw_get_power, -+#if WIRELESS_EXT > 17 -+ (iw_handler) NULL, -+ (iw_handler) NULL, -+ (iw_handler) wl_iw_set_wpaie, -+ (iw_handler) wl_iw_get_wpaie, -+ (iw_handler) wl_iw_set_wpaauth, -+ (iw_handler) wl_iw_get_wpaauth, -+ (iw_handler) wl_iw_set_encodeext, -+ (iw_handler) wl_iw_get_encodeext, -+ (iw_handler) wl_iw_set_pmksa, -+#endif -+}; -+ -+#if WIRELESS_EXT > 12 -+enum { -+ WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV, -+ WL_IW_SET_VLANMODE, -+ WL_IW_SET_PM -+}; -+ -+static iw_handler wl_iw_priv_handler[] = { -+ wl_iw_set_leddc, -+ wl_iw_set_vlanmode, -+ wl_iw_set_pm -+}; -+ -+static struct iw_priv_args wl_iw_priv_args[] = { -+ { -+ WL_IW_SET_LEDDC, -+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, -+ 0, -+ "set_leddc" -+ }, -+ { -+ WL_IW_SET_VLANMODE, -+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, -+ 0, -+ "set_vlanmode" -+ }, -+ { -+ WL_IW_SET_PM, -+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, -+ 0, -+ "set_pm" -+ } -+}; -+ -+const struct iw_handler_def wl_iw_handler_def = -+{ -+ .num_standard = ARRAYSIZE(wl_iw_handler), -+ .num_private = ARRAY_SIZE(wl_iw_priv_handler), -+ .num_private_args = ARRAY_SIZE(wl_iw_priv_args), -+ .standard = (iw_handler *) wl_iw_handler, -+ .private = wl_iw_priv_handler, -+ .private_args = wl_iw_priv_args, -+#if WIRELESS_EXT >= 19 -+ get_wireless_stats: dhd_get_wireless_stats, -+#endif -+ }; -+#endif -+ -+int -+wl_iw_ioctl( -+ struct net_device *dev, -+ struct ifreq *rq, -+ int cmd -+) -+{ -+ struct iwreq *wrq = (struct iwreq *) rq; -+ struct iw_request_info info; -+ iw_handler handler; -+ char *extra = NULL; -+ size_t token_size = 1; -+ int max_tokens = 0, ret = 0; -+ -+ if (cmd < SIOCIWFIRST || -+ IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) || -+ !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) -+ return -EOPNOTSUPP; -+ -+ switch (cmd) { -+ -+ case SIOCSIWESSID: -+ case SIOCGIWESSID: -+ case SIOCSIWNICKN: -+ case SIOCGIWNICKN: -+ max_tokens = IW_ESSID_MAX_SIZE + 1; -+ break; -+ -+ case SIOCSIWENCODE: -+ case SIOCGIWENCODE: -+#if WIRELESS_EXT > 17 -+ case SIOCSIWENCODEEXT: -+ case SIOCGIWENCODEEXT: -+#endif -+ max_tokens = IW_ENCODING_TOKEN_MAX; -+ break; -+ -+ case SIOCGIWRANGE: -+ max_tokens = sizeof(struct iw_range); -+ break; -+ -+ case SIOCGIWAPLIST: -+ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); -+ max_tokens = IW_MAX_AP; -+ break; -+ -+#if WIRELESS_EXT > 13 -+ case SIOCGIWSCAN: -+ if (g_iscan) -+ max_tokens = wrq->u.data.length; -+ else -+ max_tokens = IW_SCAN_MAX_DATA; -+ break; -+#endif -+ -+ case SIOCSIWSPY: -+ token_size = sizeof(struct sockaddr); -+ max_tokens = IW_MAX_SPY; -+ break; -+ -+ case SIOCGIWSPY: -+ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality); -+ max_tokens = IW_MAX_SPY; -+ break; -+ default: -+ break; -+ } -+ -+ if (max_tokens && wrq->u.data.pointer) { -+ if (wrq->u.data.length > max_tokens) -+ return -E2BIG; -+ -+ if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) -+ return -ENOMEM; -+ -+ if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) { -+ kfree(extra); -+ return -EFAULT; -+ } -+ } -+ -+ info.cmd = cmd; -+ info.flags = 0; -+ -+ ret = handler(dev, &info, &wrq->u, extra); -+ -+ if (extra) { -+ if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) { -+ kfree(extra); -+ return -EFAULT; -+ } -+ -+ kfree(extra); -+ } -+ -+ return ret; -+} -+ -+ -+bool -+wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason, -+ char* stringBuf, uint buflen) -+{ -+ typedef struct conn_fail_event_map_t { -+ uint32 inEvent; -+ uint32 inStatus; -+ uint32 inReason; -+ const char* outName; -+ const char* outCause; -+ } conn_fail_event_map_t; -+ -+ -+# define WL_IW_DONT_CARE 9999 -+ const conn_fail_event_map_t event_map [] = { -+ -+ -+ {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE, -+ "Conn", "Success"}, -+ {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE, -+ "Conn", "NoNetworks"}, -+ {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, -+ "Conn", "ConfigMismatch"}, -+ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH, -+ "Conn", "EncrypMismatch"}, -+ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH, -+ "Conn", "RsnMismatch"}, -+ {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, -+ "Conn", "AuthTimeout"}, -+ {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, -+ "Conn", "AuthFail"}, -+ {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE, -+ "Conn", "AuthNoAck"}, -+ {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE, -+ "Conn", "ReassocFail"}, -+ {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE, -+ "Conn", "ReassocTimeout"}, -+ {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE, -+ "Conn", "ReassocAbort"}, -+ {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE, -+ "Sup", "ConnSuccess"}, -+ {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE, -+ "Sup", "WpaHandshakeFail"}, -+ {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, -+ "Conn", "Deauth"}, -+ {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE, -+ "Conn", "DisassocInd"}, -+ {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE, -+ "Conn", "Disassoc"} -+ }; -+ -+ const char* name = ""; -+ const char* cause = NULL; -+ int i; -+ -+ -+ for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) { -+ const conn_fail_event_map_t* row = &event_map[i]; -+ if (row->inEvent == event_type && -+ (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) && -+ (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) { -+ name = row->outName; -+ cause = row->outCause; -+ break; -+ } -+ } -+ -+ -+ if (cause) { -+ memset(stringBuf, 0, buflen); -+ snprintf(stringBuf, buflen, "%s %s %02d %02d", -+ name, cause, status, reason); -+ WL_TRACE(("Connection status: %s\n", stringBuf)); -+ return TRUE; -+ } else { -+ return FALSE; -+ } -+} -+ -+#if (WIRELESS_EXT > 14) -+ -+static bool -+wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen) -+{ -+ uint32 event = ntoh32(e->event_type); -+ uint32 status = ntoh32(e->status); -+ uint32 reason = ntoh32(e->reason); -+ -+ if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) { -+ return TRUE; -+ } else -+ { -+ return FALSE; -+ } -+} -+#endif -+ -+#ifndef IW_CUSTOM_MAX -+#define IW_CUSTOM_MAX 256 -+#endif -+ -+void -+wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) -+{ -+#if WIRELESS_EXT > 13 -+ union iwreq_data wrqu; -+ char extra[IW_CUSTOM_MAX + 1]; -+ int cmd = 0; -+ uint32 event_type = ntoh32(e->event_type); -+ uint16 flags = ntoh16(e->flags); -+ uint32 datalen = ntoh32(e->datalen); -+ uint32 status = ntoh32(e->status); -+ -+ memset(&wrqu, 0, sizeof(wrqu)); -+ memset(extra, 0, sizeof(extra)); -+ -+ memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN); -+ wrqu.addr.sa_family = ARPHRD_ETHER; -+ -+ switch (event_type) { -+ case WLC_E_TXFAIL: -+ cmd = IWEVTXDROP; -+ break; -+#if WIRELESS_EXT > 14 -+ case WLC_E_JOIN: -+ case WLC_E_ASSOC_IND: -+ case WLC_E_REASSOC_IND: -+ cmd = IWEVREGISTERED; -+ break; -+ case WLC_E_DEAUTH_IND: -+ case WLC_E_DISASSOC_IND: -+ cmd = SIOCGIWAP; -+ wrqu.data.length = strlen(extra); -+ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); -+ bzero(&extra, ETHER_ADDR_LEN); -+ break; -+ -+ case WLC_E_LINK: -+ case WLC_E_NDIS_LINK: -+ cmd = SIOCGIWAP; -+ wrqu.data.length = strlen(extra); -+ if (!(flags & WLC_EVENT_MSG_LINK)) { -+ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); -+ bzero(&extra, ETHER_ADDR_LEN); -+ } -+ break; -+ case WLC_E_ACTION_FRAME: -+ cmd = IWEVCUSTOM; -+ if (datalen + 1 <= sizeof(extra)) { -+ wrqu.data.length = datalen + 1; -+ extra[0] = WLC_E_ACTION_FRAME; -+ memcpy(&extra[1], data, datalen); -+ WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length)); -+ } -+ break; -+ -+ case WLC_E_ACTION_FRAME_COMPLETE: -+ cmd = IWEVCUSTOM; -+ if (sizeof(status) + 1 <= sizeof(extra)) { -+ wrqu.data.length = sizeof(status) + 1; -+ extra[0] = WLC_E_ACTION_FRAME_COMPLETE; -+ memcpy(&extra[1], &status, sizeof(status)); -+ WL_TRACE(("wl_iw_event status %d \n", status)); -+ } -+ break; -+#endif -+#if WIRELESS_EXT > 17 -+ case WLC_E_MIC_ERROR: { -+ struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra; -+ cmd = IWEVMICHAELMICFAILURE; -+ wrqu.data.length = sizeof(struct iw_michaelmicfailure); -+ if (flags & WLC_EVENT_MSG_GROUP) -+ micerrevt->flags |= IW_MICFAILURE_GROUP; -+ else -+ micerrevt->flags |= IW_MICFAILURE_PAIRWISE; -+ memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN); -+ micerrevt->src_addr.sa_family = ARPHRD_ETHER; -+ -+ break; -+ } -+ -+ case WLC_E_ASSOC_REQ_IE: -+ cmd = IWEVASSOCREQIE; -+ wrqu.data.length = datalen; -+ if (datalen < sizeof(extra)) -+ memcpy(extra, data, datalen); -+ break; -+ -+ case WLC_E_ASSOC_RESP_IE: -+ cmd = IWEVASSOCRESPIE; -+ wrqu.data.length = datalen; -+ if (datalen < sizeof(extra)) -+ memcpy(extra, data, datalen); -+ break; -+ -+ case WLC_E_PMKID_CACHE: { -+ struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra; -+ pmkid_cand_list_t *pmkcandlist; -+ pmkid_cand_t *pmkidcand; -+ int count; -+ -+ if (data == NULL) -+ break; -+ -+ cmd = IWEVPMKIDCAND; -+ pmkcandlist = data; -+ count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand); -+ wrqu.data.length = sizeof(struct iw_pmkid_cand); -+ pmkidcand = pmkcandlist->pmkid_cand; -+ while (count) { -+ bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand)); -+ if (pmkidcand->preauth) -+ iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH; -+ bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data, -+ ETHER_ADDR_LEN); -+ wireless_send_event(dev, cmd, &wrqu, extra); -+ pmkidcand++; -+ count--; -+ } -+ break; -+ } -+#endif -+ -+ case WLC_E_SCAN_COMPLETE: -+#if WIRELESS_EXT > 14 -+ cmd = SIOCGIWSCAN; -+#endif -+ WL_TRACE(("event WLC_E_SCAN_COMPLETE\n")); -+ if ((g_iscan) && (g_iscan->sysioc_pid >= 0) && -+ (g_iscan->iscan_state != ISCAN_STATE_IDLE)) -+ up(&g_iscan->sysioc_sem); -+ break; -+ -+ default: -+ -+ break; -+ } -+ -+ if (cmd) { -+ if (cmd == SIOCGIWSCAN) -+ wireless_send_event(dev, cmd, &wrqu, NULL); -+ else -+ wireless_send_event(dev, cmd, &wrqu, extra); -+ } -+ -+#if WIRELESS_EXT > 14 -+ -+ memset(extra, 0, sizeof(extra)); -+ if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) { -+ cmd = IWEVCUSTOM; -+ wrqu.data.length = strlen(extra); -+ wireless_send_event(dev, cmd, &wrqu, extra); -+ } -+#endif -+ -+#endif -+} -+ -+int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats) -+{ -+ int res = 0; -+ wl_cnt_t cnt; -+ int phy_noise; -+ int rssi; -+ scb_val_t scb_val; -+ -+ phy_noise = 0; -+ if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise)))) -+ goto done; -+ -+ phy_noise = dtoh32(phy_noise); -+ WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise)); -+ -+ scb_val.val = 0; -+ if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) -+ goto done; -+ -+ rssi = dtoh32(scb_val.val); -+ WL_TRACE(("wl_iw_get_wireless_stats rssi=%d ****** \n", rssi)); -+ if (rssi <= WL_IW_RSSI_NO_SIGNAL) -+ wstats->qual.qual = 0; -+ else if (rssi <= WL_IW_RSSI_VERY_LOW) -+ wstats->qual.qual = 1; -+ else if (rssi <= WL_IW_RSSI_LOW) -+ wstats->qual.qual = 2; -+ else if (rssi <= WL_IW_RSSI_GOOD) -+ wstats->qual.qual = 3; -+ else if (rssi <= WL_IW_RSSI_VERY_GOOD) -+ wstats->qual.qual = 4; -+ else -+ wstats->qual.qual = 5; -+ -+ -+ wstats->qual.level = 0x100 + rssi; -+ wstats->qual.noise = 0x100 + phy_noise; -+#if WIRELESS_EXT > 18 -+ wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); -+#else -+ wstats->qual.updated |= 7; -+#endif -+ -+#if WIRELESS_EXT > 11 -+ WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t))); -+ -+ memset(&cnt, 0, sizeof(wl_cnt_t)); -+ res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t)); -+ if (res) -+ { -+ WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d ****** \n", res)); -+ goto done; -+ } -+ -+ cnt.version = dtoh16(cnt.version); -+ if (cnt.version != WL_CNT_T_VERSION) { -+ WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n", -+ WL_CNT_T_VERSION, cnt.version)); -+ goto done; -+ } -+ -+ wstats->discard.nwid = 0; -+ wstats->discard.code = dtoh32(cnt.rxundec); -+ wstats->discard.fragment = dtoh32(cnt.rxfragerr); -+ wstats->discard.retries = dtoh32(cnt.txfail); -+ wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant); -+ wstats->miss.beacon = 0; -+ -+ WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n", -+ dtoh32(cnt.txframe), dtoh32(cnt.txbyte))); -+ WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong))); -+ WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp))); -+ WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec))); -+ WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr))); -+ WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail))); -+ WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt))); -+ WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant))); -+ -+#endif -+ -+done: -+ return res; -+} -+ -+static void -+wl_iw_timerfunc(ulong data) -+{ -+ iscan_info_t *iscan = (iscan_info_t *)data; -+ iscan->timer_on = 0; -+ if (iscan->iscan_state != ISCAN_STATE_IDLE) { -+ WL_TRACE(("timer trigger\n")); -+ up(&iscan->sysioc_sem); -+ } -+} -+ -+static void -+wl_iw_set_event_mask(struct net_device *dev) -+{ -+ char eventmask[WL_EVENTING_MASK_LEN]; -+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; -+ -+ dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf)); -+ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); -+ setbit(eventmask, WLC_E_SCAN_COMPLETE); -+ dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, -+ iovbuf, sizeof(iovbuf)); -+ -+} -+ -+static int -+wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) -+{ -+ int err = 0; -+ -+ memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); -+ params->bss_type = DOT11_BSSTYPE_ANY; -+ params->scan_type = 0; -+ params->nprobes = -1; -+ params->active_time = -1; -+ params->passive_time = -1; -+ params->home_time = -1; -+ params->channel_num = 0; -+ -+ params->nprobes = htod32(params->nprobes); -+ params->active_time = htod32(params->active_time); -+ params->passive_time = htod32(params->passive_time); -+ params->home_time = htod32(params->home_time); -+ if (ssid && ssid->SSID_len) -+ memcpy(¶ms->ssid, ssid, sizeof(wlc_ssid_t)); -+ -+ return err; -+} -+ -+static int -+wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) -+{ -+ int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)); -+ wl_iscan_params_t *params; -+ int err = 0; -+ -+ if (ssid && ssid->SSID_len) { -+ params_size += sizeof(wlc_ssid_t); -+ } -+ params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); -+ if (params == NULL) { -+ return -ENOMEM; -+ } -+ memset(params, 0, params_size); -+ ASSERT(params_size < WLC_IOCTL_SMLEN); -+ -+ err = wl_iw_iscan_prep(¶ms->params, ssid); -+ -+ if (!err) { -+ params->version = htod32(ISCAN_REQ_VERSION); -+ params->action = htod16(action); -+ params->scan_duration = htod16(0); -+ -+ -+ (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, -+ iscan->ioctlbuf, WLC_IOCTL_SMLEN); -+ } -+ -+ kfree(params); -+ return err; -+} -+ -+static uint32 -+wl_iw_iscan_get(iscan_info_t *iscan) -+{ -+ iscan_buf_t * buf; -+ iscan_buf_t * ptr; -+ wl_iscan_results_t * list_buf; -+ wl_iscan_results_t list; -+ wl_scan_results_t *results; -+ uint32 status; -+ -+ -+ if (iscan->list_cur) { -+ buf = iscan->list_cur; -+ iscan->list_cur = buf->next; -+ } -+ else { -+ buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL); -+ if (!buf) -+ return WL_SCAN_RESULTS_ABORTED; -+ buf->next = NULL; -+ if (!iscan->list_hdr) -+ iscan->list_hdr = buf; -+ else { -+ ptr = iscan->list_hdr; -+ while (ptr->next) { -+ ptr = ptr->next; -+ } -+ ptr->next = buf; -+ } -+ } -+ memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); -+ list_buf = (wl_iscan_results_t*)buf->iscan_buf; -+ results = &list_buf->results; -+ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; -+ results->version = 0; -+ results->count = 0; -+ -+ memset(&list, 0, sizeof(list)); -+ list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); -+ (void) dev_iw_iovar_getbuf( -+ iscan->dev, -+ "iscanresults", -+ &list, -+ WL_ISCAN_RESULTS_FIXED_SIZE, -+ buf->iscan_buf, -+ WLC_IW_ISCAN_MAXLEN); -+ results->buflen = dtoh32(results->buflen); -+ results->version = dtoh32(results->version); -+ results->count = dtoh32(results->count); -+ WL_TRACE(("results->count = %d\n", results->count)); -+ -+ WL_TRACE(("results->buflen = %d\n", results->buflen)); -+ status = dtoh32(list_buf->status); -+ return status; -+} -+ -+static void wl_iw_send_scan_complete(iscan_info_t *iscan) -+{ -+ union iwreq_data wrqu; -+ -+ memset(&wrqu, 0, sizeof(wrqu)); -+ -+ -+ wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); -+} -+ -+static int -+_iscan_sysioc_thread(void *data) -+{ -+ uint32 status; -+ iscan_info_t *iscan = (iscan_info_t *)data; -+ -+ DAEMONIZE("iscan_sysioc"); -+ -+ status = WL_SCAN_RESULTS_PARTIAL; -+ while (down_interruptible(&iscan->sysioc_sem) == 0) { -+ if (iscan->timer_on) { -+ del_timer(&iscan->timer); -+ iscan->timer_on = 0; -+ } -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ rtnl_lock(); -+#endif -+ status = wl_iw_iscan_get(iscan); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ rtnl_unlock(); -+#endif -+ -+ switch (status) { -+ case WL_SCAN_RESULTS_PARTIAL: -+ WL_TRACE(("iscanresults incomplete\n")); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ rtnl_lock(); -+#endif -+ -+ wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -+ rtnl_unlock(); -+#endif -+ -+ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); -+ add_timer(&iscan->timer); -+ iscan->timer_on = 1; -+ break; -+ case WL_SCAN_RESULTS_SUCCESS: -+ WL_TRACE(("iscanresults complete\n")); -+ iscan->iscan_state = ISCAN_STATE_IDLE; -+ wl_iw_send_scan_complete(iscan); -+ break; -+ case WL_SCAN_RESULTS_PENDING: -+ WL_TRACE(("iscanresults pending\n")); -+ -+ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms); -+ add_timer(&iscan->timer); -+ iscan->timer_on = 1; -+ break; -+ case WL_SCAN_RESULTS_ABORTED: -+ WL_TRACE(("iscanresults aborted\n")); -+ iscan->iscan_state = ISCAN_STATE_IDLE; -+ wl_iw_send_scan_complete(iscan); -+ break; -+ default: -+ WL_TRACE(("iscanresults returned unknown status %d\n", status)); -+ break; -+ } -+ } -+ complete_and_exit(&iscan->sysioc_exited, 0); -+} -+ -+int -+wl_iw_attach(struct net_device *dev, void * dhdp) -+{ -+ iscan_info_t *iscan = NULL; -+ -+ if (!dev) -+ return 0; -+ -+ iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL); -+ if (!iscan) -+ return -ENOMEM; -+ memset(iscan, 0, sizeof(iscan_info_t)); -+ iscan->sysioc_pid = -1; -+ -+ g_iscan = iscan; -+ iscan->dev = dev; -+ iscan->iscan_state = ISCAN_STATE_IDLE; -+ -+ -+ -+ iscan->timer_ms = 2000; -+ init_timer(&iscan->timer); -+ iscan->timer.data = (ulong)iscan; -+ iscan->timer.function = wl_iw_timerfunc; -+ -+ sema_init(&iscan->sysioc_sem, 0); -+ init_completion(&iscan->sysioc_exited); -+ iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0); -+ if (iscan->sysioc_pid < 0) -+ return -ENOMEM; -+ return 0; -+} -+ -+void wl_iw_detach(void) -+{ -+ iscan_buf_t *buf; -+ iscan_info_t *iscan = g_iscan; -+ if (!iscan) -+ return; -+ if (iscan->sysioc_pid >= 0) { -+ KILL_PROC(iscan->sysioc_pid, SIGTERM); -+ wait_for_completion(&iscan->sysioc_exited); -+ } -+ -+ while (iscan->list_hdr) { -+ buf = iscan->list_hdr->next; -+ kfree(iscan->list_hdr); -+ iscan->list_hdr = buf; -+ } -+ kfree(iscan); -+ g_iscan = NULL; -+} -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h -new file mode 100644 -index 00000000..2afb5a68 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_iw.h -@@ -0,0 +1,161 @@ -+/* -+ * Linux Wireless Extensions support -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wl_iw.h 291086 2011-10-21 01:17:24Z $ -+ */ -+ -+#ifndef _wl_iw_h_ -+#define _wl_iw_h_ -+ -+#include <linux/wireless.h> -+ -+#include <typedefs.h> -+#include <proto/ethernet.h> -+#include <wlioctl.h> -+ -+#define WL_SCAN_PARAMS_SSID_MAX 10 -+#define GET_SSID "SSID=" -+#define GET_CHANNEL "CH=" -+#define GET_NPROBE "NPROBE=" -+#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" -+#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" -+#define GET_HOME_DWELL "HOME=" -+#define GET_SCAN_TYPE "TYPE=" -+ -+#define BAND_GET_CMD "GETBAND" -+#define BAND_SET_CMD "SETBAND" -+#define DTIM_SKIP_GET_CMD "DTIMSKIPGET" -+#define DTIM_SKIP_SET_CMD "DTIMSKIPSET" -+#define SETSUSPEND_CMD "SETSUSPENDOPT" -+#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" -+ -+#define PNOSETUP_SET_CMD "PNOSETUP " -+#define PNOENABLE_SET_CMD "PNOFORCE" -+#define PNODEBUG_SET_CMD "PNODEBUG" -+#define TXPOWER_SET_CMD "TXPOWER" -+ -+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -+ -+ -+typedef struct wl_iw_extra_params { -+ int target_channel; -+} wl_iw_extra_params_t; -+ -+struct cntry_locales_custom { -+ char iso_abbrev[WLC_CNTRY_BUF_SZ]; -+ char custom_locale[WLC_CNTRY_BUF_SZ]; -+ int32 custom_locale_rev; -+}; -+ -+ -+#define WL_IW_RSSI_MINVAL -200 -+#define WL_IW_RSSI_NO_SIGNAL -91 -+#define WL_IW_RSSI_VERY_LOW -80 -+#define WL_IW_RSSI_LOW -70 -+#define WL_IW_RSSI_GOOD -68 -+#define WL_IW_RSSI_VERY_GOOD -58 -+#define WL_IW_RSSI_EXCELLENT -57 -+#define WL_IW_RSSI_INVALID 0 -+#define MAX_WX_STRING 80 -+#define SSID_FMT_BUF_LEN ((4 * 32) + 1) -+#define isprint(c) bcm_isprint(c) -+#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1) -+#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3) -+#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5) -+#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7) -+#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9) -+#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11) -+#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13) -+ -+#define G_SCAN_RESULTS 8*1024 -+#define WE_ADD_EVENT_FIX 0x80 -+#define G_WLAN_SET_ON 0 -+#define G_WLAN_SET_OFF 1 -+ -+ -+typedef struct wl_iw { -+ char nickname[IW_ESSID_MAX_SIZE]; -+ -+ struct iw_statistics wstats; -+ -+ int spy_num; -+ uint32 pwsec; -+ uint32 gwsec; -+ bool privacy_invoked; -+ struct ether_addr spy_addr[IW_MAX_SPY]; -+ struct iw_quality spy_qual[IW_MAX_SPY]; -+ void *wlinfo; -+} wl_iw_t; -+ -+struct wl_ctrl { -+ struct timer_list *timer; -+ struct net_device *dev; -+ long sysioc_pid; -+ struct semaphore sysioc_sem; -+ struct completion sysioc_exited; -+}; -+ -+ -+#if WIRELESS_EXT > 12 -+#include <net/iw_handler.h> -+extern const struct iw_handler_def wl_iw_handler_def; -+#endif -+ -+extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -+extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data); -+extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats); -+int wl_iw_attach(struct net_device *dev, void * dhdp); -+int wl_iw_send_priv_event(struct net_device *dev, char *flag); -+ -+void wl_iw_detach(void); -+ -+#define CSCAN_COMMAND "CSCAN " -+#define CSCAN_TLV_PREFIX 'S' -+#define CSCAN_TLV_VERSION 1 -+#define CSCAN_TLV_SUBVERSION 0 -+#define CSCAN_TLV_TYPE_SSID_IE 'S' -+#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' -+#define CSCAN_TLV_TYPE_NPROBE_IE 'N' -+#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' -+#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' -+#define CSCAN_TLV_TYPE_HOME_IE 'H' -+#define CSCAN_TLV_TYPE_STYPE_IE 'T' -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) -+#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ -+ iwe_stream_add_event(info, stream, ends, iwe, extra) -+#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ -+ iwe_stream_add_value(info, event, value, ends, iwe, event_len) -+#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ -+ iwe_stream_add_point(info, stream, ends, iwe, extra) -+#else -+#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \ -+ iwe_stream_add_event(stream, ends, iwe, extra) -+#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \ -+ iwe_stream_add_value(event, value, ends, iwe, event_len) -+#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \ -+ iwe_stream_add_point(stream, ends, iwe, extra) -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c -new file mode 100644 -index 00000000..af258632 ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wl_linux_mon.c -@@ -0,0 +1,422 @@ -+/* -+ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: dhd_linux_mon.c 280623 2011-08-30 14:49:39Z $ -+ */ -+ -+#include <osl.h> -+#include <linux/string.h> -+#include <linux/module.h> -+#include <linux/netdevice.h> -+#include <linux/etherdevice.h> -+#include <linux/if_arp.h> -+#include <linux/ieee80211.h> -+#include <linux/rtnetlink.h> -+#include <net/ieee80211_radiotap.h> -+ -+#include <wlioctl.h> -+#include <bcmutils.h> -+#include <dhd_dbg.h> -+#include <dngl_stats.h> -+#include <dhd.h> -+ -+typedef enum monitor_states -+{ -+ MONITOR_STATE_DEINIT = 0x0, -+ MONITOR_STATE_INIT = 0x1, -+ MONITOR_STATE_INTERFACE_ADDED = 0x2, -+ MONITOR_STATE_INTERFACE_DELETED = 0x4 -+} monitor_states_t; -+int dhd_add_monitor(char *name, struct net_device **new_ndev); -+extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); -+int dhd_del_monitor(struct net_device *ndev); -+int dhd_monitor_init(void *dhd_pub); -+int dhd_monitor_uninit(void); -+ -+/** -+ * Local declarations and defintions (not exposed) -+ */ -+#ifndef DHD_MAX_IFS -+#define DHD_MAX_IFS 16 -+#endif -+#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) -+#define MON_TRACE MON_PRINT -+ -+typedef struct monitor_interface { -+ int radiotap_enabled; -+ struct net_device* real_ndev; /* The real interface that the monitor is on */ -+ struct net_device* mon_ndev; -+} monitor_interface; -+ -+typedef struct dhd_linux_monitor { -+ void *dhd_pub; -+ monitor_states_t monitor_state; -+ monitor_interface mon_if[DHD_MAX_IFS]; -+ struct mutex lock; /* lock to protect mon_if */ -+} dhd_linux_monitor_t; -+ -+static dhd_linux_monitor_t g_monitor; -+ -+static struct net_device* lookup_real_netdev(char *name); -+static monitor_interface* ndev_to_monif(struct net_device *ndev); -+static int dhd_mon_if_open(struct net_device *ndev); -+static int dhd_mon_if_stop(struct net_device *ndev); -+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); -+static void dhd_mon_if_set_multicast_list(struct net_device *ndev); -+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); -+ -+static const struct net_device_ops dhd_mon_if_ops = { -+ .ndo_open = dhd_mon_if_open, -+ .ndo_stop = dhd_mon_if_stop, -+ .ndo_start_xmit = dhd_mon_if_subif_start_xmit, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) -+ .ndo_set_rx_mode = dhd_mon_if_set_multicast_list, -+#else -+ .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, -+#endif -+ .ndo_set_mac_address = dhd_mon_if_change_mac, -+}; -+ -+/** -+ * Local static function defintions -+ */ -+ -+/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" -+ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") -+ */ -+static struct net_device* lookup_real_netdev(char *name) -+{ -+ struct net_device *ndev_found = NULL; -+ -+ int i; -+ int len = 0; -+ int last_name_len = 0; -+ struct net_device *ndev; -+ -+ /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", -+ * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon -+ * iface would be mon-p2p0-0. -+ */ -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ ndev = dhd_idx2net(g_monitor.dhd_pub, i); -+ -+ /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it -+ * it matches, then this netdev is the corresponding real_netdev. -+ */ -+ if (ndev && strstr(ndev->name, "p2p-p2p0")) { -+ len = strlen("p2p"); -+ } else { -+ /* if p2p- is not present, then the IFNAMSIZ have reached and name -+ * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x -+ */ -+ len = 0; -+ } -+ if (ndev && strstr(name, (ndev->name + len))) { -+ if (strlen(ndev->name) > last_name_len) { -+ ndev_found = ndev; -+ last_name_len = strlen(ndev->name); -+ } -+ } -+ } -+ -+ return ndev_found; -+} -+ -+static monitor_interface* ndev_to_monif(struct net_device *ndev) -+{ -+ int i; -+ -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ if (g_monitor.mon_if[i].mon_ndev == ndev) -+ return &g_monitor.mon_if[i]; -+ } -+ -+ return NULL; -+} -+ -+static int dhd_mon_if_open(struct net_device *ndev) -+{ -+ int ret = 0; -+ -+ MON_PRINT("enter\n"); -+ return ret; -+} -+ -+static int dhd_mon_if_stop(struct net_device *ndev) -+{ -+ int ret = 0; -+ -+ MON_PRINT("enter\n"); -+ return ret; -+} -+ -+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) -+{ -+ int ret = 0; -+ int rtap_len; -+ int qos_len = 0; -+ int dot11_hdr_len = 24; -+ int snap_len = 6; -+ unsigned char *pdata; -+ unsigned short frame_ctl; -+ unsigned char src_mac_addr[6]; -+ unsigned char dst_mac_addr[6]; -+ struct ieee80211_hdr *dot11_hdr; -+ struct ieee80211_radiotap_header *rtap_hdr; -+ monitor_interface* mon_if; -+ -+ MON_PRINT("enter\n"); -+ -+ mon_if = ndev_to_monif(ndev); -+ if (mon_if == NULL || mon_if->real_ndev == NULL) { -+ MON_PRINT(" cannot find matched net dev, skip the packet\n"); -+ goto fail; -+ } -+ -+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) -+ goto fail; -+ -+ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; -+ if (unlikely(rtap_hdr->it_version)) -+ goto fail; -+ -+ rtap_len = ieee80211_get_radiotap_len(skb->data); -+ if (unlikely(skb->len < rtap_len)) -+ goto fail; -+ -+ MON_PRINT("radiotap len (should be 14): %d\n", rtap_len); -+ -+ /* Skip the ratio tap header */ -+ skb_pull(skb, rtap_len); -+ -+ dot11_hdr = (struct ieee80211_hdr *)skb->data; -+ frame_ctl = le16_to_cpu(dot11_hdr->frame_control); -+ /* Check if the QoS bit is set */ -+ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { -+ /* Check if this ia a Wireless Distribution System (WDS) frame -+ * which has 4 MAC addresses -+ */ -+ if (dot11_hdr->frame_control & 0x0080) -+ qos_len = 2; -+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300) -+ dot11_hdr_len += 6; -+ -+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); -+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); -+ -+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for -+ * for two MAC addresses -+ */ -+ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); -+ pdata = (unsigned char*)skb->data; -+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); -+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); -+ PKTSETPRIO(skb, 0); -+ -+ MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); -+ -+ /* Use the real net device to transmit the packet */ -+ ret = dhd_start_xmit(skb, mon_if->real_ndev); -+ -+ return ret; -+ } -+fail: -+ dev_kfree_skb(skb); -+ return 0; -+} -+ -+static void dhd_mon_if_set_multicast_list(struct net_device *ndev) -+{ -+ monitor_interface* mon_if; -+ -+ mon_if = ndev_to_monif(ndev); -+ if (mon_if == NULL || mon_if->real_ndev == NULL) { -+ MON_PRINT(" cannot find matched net dev, skip the packet\n"); -+ } else { -+ MON_PRINT("enter, if name: %s, matched if name %s\n", -+ ndev->name, mon_if->real_ndev->name); -+ } -+} -+ -+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) -+{ -+ int ret = 0; -+ monitor_interface* mon_if; -+ -+ mon_if = ndev_to_monif(ndev); -+ if (mon_if == NULL || mon_if->real_ndev == NULL) { -+ MON_PRINT(" cannot find matched net dev, skip the packet\n"); -+ } else { -+ MON_PRINT("enter, if name: %s, matched if name %s\n", -+ ndev->name, mon_if->real_ndev->name); -+ } -+ return ret; -+} -+ -+/** -+ * Global function definitions (declared in dhd_linux_mon.h) -+ */ -+ -+int dhd_add_monitor(char *name, struct net_device **new_ndev) -+{ -+ int i; -+ int idx = -1; -+ int ret = 0; -+ struct net_device* ndev = NULL; -+ dhd_linux_monitor_t **dhd_mon; -+ -+ mutex_lock(&g_monitor.lock); -+ -+ MON_TRACE("enter, if name: %s\n", name); -+ if (!name || !new_ndev) { -+ MON_PRINT("invalid parameters\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* -+ * Find a vacancy -+ */ -+ for (i = 0; i < DHD_MAX_IFS; i++) -+ if (g_monitor.mon_if[i].mon_ndev == NULL) { -+ idx = i; -+ break; -+ } -+ if (idx == -1) { -+ MON_PRINT("exceeds maximum interfaces\n"); -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); -+ if (!ndev) { -+ MON_PRINT("failed to allocate memory\n"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ndev->type = ARPHRD_IEEE80211_RADIOTAP; -+ strncpy(ndev->name, name, IFNAMSIZ); -+ ndev->name[IFNAMSIZ - 1] = 0; -+ ndev->netdev_ops = &dhd_mon_if_ops; -+ -+ ret = register_netdevice(ndev); -+ if (ret) { -+ MON_PRINT(" register_netdevice failed (%d)\n", ret); -+ goto out; -+ } -+ -+ *new_ndev = ndev; -+ g_monitor.mon_if[idx].radiotap_enabled = TRUE; -+ g_monitor.mon_if[idx].mon_ndev = ndev; -+ g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); -+ dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); -+ *dhd_mon = &g_monitor; -+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED; -+ MON_PRINT("net device returned: 0x%p\n", ndev); -+ MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); -+ -+out: -+ if (ret && ndev) -+ free_netdev(ndev); -+ -+ mutex_unlock(&g_monitor.lock); -+ return ret; -+ -+} -+ -+int dhd_del_monitor(struct net_device *ndev) -+{ -+ int i; -+ bool rollback_lock = false; -+ if (!ndev) -+ return -EINVAL; -+ mutex_lock(&g_monitor.lock); -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ if (g_monitor.mon_if[i].mon_ndev == ndev || -+ g_monitor.mon_if[i].real_ndev == ndev) { -+ g_monitor.mon_if[i].real_ndev = NULL; -+ if (rtnl_is_locked()) { -+ rtnl_unlock(); -+ rollback_lock = true; -+ } -+ unregister_netdev(g_monitor.mon_if[i].mon_ndev); -+ free_netdev(g_monitor.mon_if[i].mon_ndev); -+ g_monitor.mon_if[i].mon_ndev = NULL; -+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED; -+ break; -+ } -+ } -+ if (rollback_lock) { -+ rtnl_lock(); -+ rollback_lock = false; -+ } -+ -+ if (g_monitor.monitor_state != -+ MONITOR_STATE_INTERFACE_DELETED) -+ MON_PRINT("interface not found in monitor IF array, is this a monitor IF? 0x%p\n", -+ ndev); -+ mutex_unlock(&g_monitor.lock); -+ -+ return 0; -+} -+ -+int dhd_monitor_init(void *dhd_pub) -+{ -+ if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) { -+ g_monitor.dhd_pub = dhd_pub; -+ mutex_init(&g_monitor.lock); -+ g_monitor.monitor_state = MONITOR_STATE_INIT; -+ } -+ return 0; -+} -+ -+int dhd_monitor_uninit(void) -+{ -+ int i; -+ struct net_device *ndev; -+ bool rollback_lock = false; -+ mutex_lock(&g_monitor.lock); -+ if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) { -+ for (i = 0; i < DHD_MAX_IFS; i++) { -+ ndev = g_monitor.mon_if[i].mon_ndev; -+ if (ndev) { -+ if (rtnl_is_locked()) { -+ rtnl_unlock(); -+ rollback_lock = true; -+ } -+ unregister_netdev(ndev); -+ free_netdev(ndev); -+ g_monitor.mon_if[i].real_ndev = NULL; -+ g_monitor.mon_if[i].mon_ndev = NULL; -+ if (rollback_lock) { -+ rtnl_lock(); -+ rollback_lock = false; -+ } -+ } -+ } -+ g_monitor.monitor_state = MONITOR_STATE_DEINIT; -+ } -+ mutex_unlock(&g_monitor.lock); -+ return 0; -+} -diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c -new file mode 100644 -index 00000000..18008e0b ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wldev_common.c -@@ -0,0 +1,384 @@ -+/* -+ * Common function shared by Linux WEXT, cfg80211 and p2p drivers -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ -+ */ -+ -+#include <osl.h> -+#include <linux/kernel.h> -+#include <linux/kthread.h> -+#include <linux/netdevice.h> -+ -+#include <wldev_common.h> -+#include <bcmutils.h> -+ -+#define htod32(i) i -+#define htod16(i) i -+#define dtoh32(i) i -+#define dtoh16(i) i -+#define htodchanspec(i) i -+#define dtohchanspec(i) i -+ -+#define WLDEV_ERROR(args) \ -+ do { \ -+ printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \ -+ printk args; \ -+ } while (0) -+ -+extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); -+ -+s32 wldev_ioctl( -+ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) -+{ -+ s32 ret = 0; -+ struct wl_ioctl ioc; -+ -+ -+ memset(&ioc, 0, sizeof(ioc)); -+ ioc.cmd = cmd; -+ ioc.buf = arg; -+ ioc.len = len; -+ ioc.set = set; -+ -+ ret = dhd_ioctl_entry_local(dev, &ioc, cmd); -+ -+ return ret; -+} -+ -+/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be -+ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to -+ * wl_iw, wl_cfg80211 and wl_cfgp2p -+ */ -+static s32 wldev_mkiovar( -+ s8 *iovar_name, s8 *param, s32 paramlen, -+ s8 *iovar_buf, u32 buflen) -+{ -+ s32 iolen = 0; -+ -+ iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); -+ return iolen; -+} -+ -+s32 wldev_iovar_getbuf( -+ struct net_device *dev, s8 *iovar_name, -+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -+{ -+ s32 ret = 0; -+ if (buf_sync) { -+ mutex_lock(buf_sync); -+ } -+ wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); -+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); -+ if (buf_sync) -+ mutex_unlock(buf_sync); -+ return ret; -+} -+ -+ -+s32 wldev_iovar_setbuf( -+ struct net_device *dev, s8 *iovar_name, -+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) -+{ -+ s32 ret = 0; -+ s32 iovar_len; -+ if (buf_sync) { -+ mutex_lock(buf_sync); -+ } -+ iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); -+ if (iovar_len > 0) -+ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); -+ else -+ ret = BCME_BUFTOOSHORT; -+ if (buf_sync) -+ mutex_unlock(buf_sync); -+ return ret; -+} -+ -+s32 wldev_iovar_setint( -+ struct net_device *dev, s8 *iovar, s32 val) -+{ -+ s8 iovar_buf[WLC_IOCTL_SMLEN]; -+ -+ val = htod32(val); -+ memset(iovar_buf, 0, sizeof(iovar_buf)); -+ return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, -+ sizeof(iovar_buf), NULL); -+} -+ -+ -+s32 wldev_iovar_getint( -+ struct net_device *dev, s8 *iovar, s32 *pval) -+{ -+ s8 iovar_buf[WLC_IOCTL_SMLEN]; -+ s32 err; -+ -+ memset(iovar_buf, 0, sizeof(iovar_buf)); -+ err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, -+ sizeof(iovar_buf), NULL); -+ if (err == 0) -+ { -+ memcpy(pval, iovar_buf, sizeof(*pval)); -+ *pval = dtoh32(*pval); -+ } -+ return err; -+} -+ -+/** Format a bsscfg indexed iovar buffer. The bsscfg index will be -+ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to -+ * wl_iw, wl_cfg80211 and wl_cfgp2p -+ */ -+s32 wldev_mkiovar_bsscfg( -+ const s8 *iovar_name, s8 *param, s32 paramlen, -+ s8 *iovar_buf, s32 buflen, s32 bssidx) -+{ -+ const s8 *prefix = "bsscfg:"; -+ s8 *p; -+ u32 prefixlen; -+ u32 namelen; -+ u32 iolen; -+ -+ if (bssidx == 0) { -+ return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, -+ (s8 *) iovar_buf, buflen); -+ } -+ -+ prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ -+ namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ -+ iolen = prefixlen + namelen + sizeof(u32) + paramlen; -+ -+ if (buflen < 0 || iolen > (u32)buflen) -+ { -+ WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__)); -+ return BCME_BUFTOOSHORT; -+ } -+ -+ p = (s8 *)iovar_buf; -+ -+ /* copy prefix, no null */ -+ memcpy(p, prefix, prefixlen); -+ p += prefixlen; -+ -+ /* copy iovar name including null */ -+ memcpy(p, iovar_name, namelen); -+ p += namelen; -+ -+ /* bss config index as first param */ -+ bssidx = htod32(bssidx); -+ memcpy(p, &bssidx, sizeof(u32)); -+ p += sizeof(u32); -+ -+ /* parameter buffer follows */ -+ if (paramlen) -+ memcpy(p, param, paramlen); -+ -+ return iolen; -+ -+} -+ -+s32 wldev_iovar_getbuf_bsscfg( -+ struct net_device *dev, s8 *iovar_name, -+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -+{ -+ s32 ret = 0; -+ if (buf_sync) { -+ mutex_lock(buf_sync); -+ } -+ -+ wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); -+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); -+ if (buf_sync) { -+ mutex_unlock(buf_sync); -+ } -+ return ret; -+ -+} -+ -+s32 wldev_iovar_setbuf_bsscfg( -+ struct net_device *dev, s8 *iovar_name, -+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) -+{ -+ s32 ret = 0; -+ s32 iovar_len; -+ if (buf_sync) { -+ mutex_lock(buf_sync); -+ } -+ iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); -+ if (iovar_len > 0) -+ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); -+ else { -+ ret = BCME_BUFTOOSHORT; -+ } -+ -+ if (buf_sync) { -+ mutex_unlock(buf_sync); -+ } -+ return ret; -+} -+ -+s32 wldev_iovar_setint_bsscfg( -+ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) -+{ -+ s8 iovar_buf[WLC_IOCTL_SMLEN]; -+ -+ val = htod32(val); -+ memset(iovar_buf, 0, sizeof(iovar_buf)); -+ return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, -+ sizeof(iovar_buf), bssidx, NULL); -+} -+ -+ -+s32 wldev_iovar_getint_bsscfg( -+ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) -+{ -+ s8 iovar_buf[WLC_IOCTL_SMLEN]; -+ s32 err; -+ -+ memset(iovar_buf, 0, sizeof(iovar_buf)); -+ err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, -+ sizeof(iovar_buf), bssidx, NULL); -+ if (err == 0) -+ { -+ memcpy(pval, iovar_buf, sizeof(*pval)); -+ *pval = dtoh32(*pval); -+ } -+ return err; -+} -+ -+int wldev_get_link_speed( -+ struct net_device *dev, int *plink_speed) -+{ -+ int error; -+ -+ if (!plink_speed) -+ return -ENOMEM; -+ error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0); -+ if (unlikely(error)) -+ return error; -+ -+ /* Convert internal 500Kbps to Kbps */ -+ *plink_speed *= 500; -+ return error; -+} -+ -+int wldev_get_rssi( -+ struct net_device *dev, int *prssi) -+{ -+ scb_val_t scb_val; -+ int error; -+ -+ if (!prssi) -+ return -ENOMEM; -+ bzero(&scb_val, sizeof(scb_val_t)); -+ -+ error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0); -+ if (unlikely(error)) -+ return error; -+ -+ *prssi = dtoh32(scb_val.val); -+ return error; -+} -+ -+int wldev_get_ssid( -+ struct net_device *dev, wlc_ssid_t *pssid) -+{ -+ int error; -+ -+ if (!pssid) -+ return -ENOMEM; -+ error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0); -+ if (unlikely(error)) -+ return error; -+ pssid->SSID_len = dtoh32(pssid->SSID_len); -+ return error; -+} -+ -+int wldev_get_band( -+ struct net_device *dev, uint *pband) -+{ -+ int error; -+ -+ error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0); -+ return error; -+} -+ -+int wldev_set_band( -+ struct net_device *dev, uint band) -+{ -+ int error = -1; -+ -+ if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) { -+ error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true); -+ if (!error) -+ dhd_bus_band_set(dev, band); -+ } -+ return error; -+} -+ -+int wldev_set_country( -+ struct net_device *dev, char *country_code, bool notify, bool user_enforced) -+{ -+ int error = -1; -+ wl_country_t cspec = {{0}, 0, {0}}; -+ scb_val_t scbval; -+ char smbuf[WLC_IOCTL_SMLEN]; -+ -+ if (!country_code) -+ return error; -+ -+ bzero(&scbval, sizeof(scb_val_t)); -+ error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL); -+ if (error < 0) { -+ WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); -+ return error; -+ } -+ -+ if ((error < 0) || -+ (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) { -+ -+ if (user_enforced) { -+ bzero(&scbval, sizeof(scb_val_t)); -+ error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); -+ if (error < 0) { -+ WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", -+ __FUNCTION__, error)); -+ return error; -+ } -+ } -+ -+ cspec.rev = -1; -+ memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ); -+ memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); -+ get_customized_country_code((char *)&cspec.country_abbrev, &cspec); -+ error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), -+ smbuf, sizeof(smbuf), NULL); -+ if (error < 0) { -+ WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", -+ __FUNCTION__, country_code, cspec.ccode, cspec.rev)); -+ return error; -+ } -+ dhd_bus_country_set(dev, &cspec, notify); -+ WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", -+ __FUNCTION__, country_code, cspec.ccode, cspec.rev)); -+ } -+ return 0; -+} -diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h -new file mode 100644 -index 00000000..e63620fe ---- /dev/null -+++ b/drivers/net/wireless/bcmdhd/wldev_common.h -@@ -0,0 +1,112 @@ -+/* -+ * Common function shared by Linux WEXT, cfg80211 and p2p drivers -+ * -+ * Copyright (C) 1999-2012, Broadcom Corporation -+ * -+ * Unless you and Broadcom execute a separate written software license -+ * agreement governing use of this software, this software is licensed to you -+ * under the terms of the GNU General Public License version 2 (the "GPL"), -+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the -+ * following added to such license: -+ * -+ * As a special exception, the copyright holders of this software give you -+ * permission to link this software with independent modules, and to copy and -+ * distribute the resulting executable under terms of your choice, provided that -+ * you also meet, for each linked independent module, the terms and conditions of -+ * the license of that module. An independent module is a module which is not -+ * derived from this software. The special exception does not apply to any -+ * modifications of the software. -+ * -+ * Notwithstanding the above, under no circumstances may you combine this -+ * software in any way with any other Broadcom software provided under a license -+ * other than the GPL, without Broadcom's express prior written consent. -+ * -+ * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ -+ */ -+#ifndef __WLDEV_COMMON_H__ -+#define __WLDEV_COMMON_H__ -+ -+#include <wlioctl.h> -+ -+/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or -+ * netdev_ops->ndo_do_ioctl in new kernels) -+ * @dev: the net_device handle -+ */ -+s32 wldev_ioctl( -+ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); -+ -+/** Retrieve named IOVARs, this function calls wl_dev_ioctl with -+ * WLC_GET_VAR IOCTL code -+ */ -+s32 wldev_iovar_getbuf( -+ struct net_device *dev, s8 *iovar_name, -+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); -+ -+/** Set named IOVARs, this function calls wl_dev_ioctl with -+ * WLC_SET_VAR IOCTL code -+ */ -+s32 wldev_iovar_setbuf( -+ struct net_device *dev, s8 *iovar_name, -+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); -+ -+s32 wldev_iovar_setint( -+ struct net_device *dev, s8 *iovar, s32 val); -+ -+s32 wldev_iovar_getint( -+ struct net_device *dev, s8 *iovar, s32 *pval); -+ -+/** The following function can be implemented if there is a need for bsscfg -+ * indexed IOVARs -+ */ -+ -+s32 wldev_mkiovar_bsscfg( -+ const s8 *iovar_name, s8 *param, s32 paramlen, -+ s8 *iovar_buf, s32 buflen, s32 bssidx); -+ -+/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with -+ * WLC_GET_VAR IOCTL code -+ */ -+s32 wldev_iovar_getbuf_bsscfg( -+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, -+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); -+ -+/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with -+ * WLC_SET_VAR IOCTL code -+ */ -+s32 wldev_iovar_setbuf_bsscfg( -+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, -+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); -+ -+s32 wldev_iovar_getint_bsscfg( -+ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); -+ -+s32 wldev_iovar_setint_bsscfg( -+ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); -+ -+extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); -+extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify); -+extern void dhd_bus_band_set(struct net_device *dev, uint band); -+extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify, -+ bool user_enforced); -+extern int net_os_wake_lock(struct net_device *dev); -+extern int net_os_wake_unlock(struct net_device *dev); -+extern int net_os_wake_lock_timeout(struct net_device *dev); -+extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); -+extern int net_os_set_dtim_skip(struct net_device *dev, int val); -+extern int net_os_set_suspend_disable(struct net_device *dev, int val); -+extern int net_os_set_suspend(struct net_device *dev, int val, int force); -+extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, -+ int max, int *bytes_left); -+ -+/* Get the link speed from dongle, speed is in kpbs */ -+int wldev_get_link_speed(struct net_device *dev, int *plink_speed); -+ -+int wldev_get_rssi(struct net_device *dev, int *prssi); -+ -+int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid); -+ -+int wldev_get_band(struct net_device *dev, uint *pband); -+ -+int wldev_set_band(struct net_device *dev, uint band); -+ -+#endif /* __WLDEV_COMMON_H__ */ -diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig -index 99dc29f2..a86498ba 100644 ---- a/drivers/power/Kconfig -+++ b/drivers/power/Kconfig -@@ -190,6 +190,16 @@ config BATTERY_MAX17042 - multi-function devices that include fuel gauages that are compatible - with MAX17042. - -+config BATTERY_ANDROID -+ tristate "Battery driver for Android" -+ help -+ Say Y to enable generic support for battery charging according -+ to common Android policies. -+ This driver adds periodic battery level and health monitoring, -+ kernel log reporting and other debugging features, common board -+ battery file glue logic for battery/case temperature sensors, -+ etc. -+ - config BATTERY_Z2 - tristate "Z2 battery driver" - depends on I2C && MACH_ZIPIT2 -@@ -307,4 +317,12 @@ config AB8500_BATTERY_THERM_ON_BATCTRL - help - Say Y to enable battery temperature measurements using - thermistor connected on BATCTRL ADC. -+ -+config BATTERY_AK -+ tristate "Anyka Battery driver support" -+ depends on ARCH_AK39 -+ help -+ Say Y to enable support for the anyka battery from SOCLE. -+ -+ - endif # POWER_SUPPLY -diff --git a/drivers/power/Makefile b/drivers/power/Makefile -index b6b24341..07e3946a 100644 ---- a/drivers/power/Makefile -+++ b/drivers/power/Makefile -@@ -44,3 +44,5 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o - obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o - obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o - obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o -+obj-$(CONFIG_BATTERY_ANDROID) += android_battery.o -+obj-$(CONFIG_BATTERY_AK) += plat-anyka/ -diff --git a/drivers/power/android_battery.c b/drivers/power/android_battery.c -new file mode 100644 -index 00000000..ee437d08 ---- /dev/null -+++ b/drivers/power/android_battery.c -@@ -0,0 +1,692 @@ -+/* -+ * android_battery.c -+ * Android Battery Driver -+ * -+ * Copyright (C) 2012 Google, Inc. -+ * Copyright (C) 2012 Samsung Electronics -+ * -+ * Based on work by himihee.seo@samsung.com, ms925.kim@samsung.com, and -+ * joshua.chang@samsung.com. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#include <linux/types.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/jiffies.h> -+#include <linux/platform_device.h> -+#include <linux/power_supply.h> -+#include <linux/slab.h> -+#include <linux/wakelock.h> -+#include <linux/workqueue.h> -+#include <linux/alarmtimer.h> -+#include <linux/timer.h> -+#include <linux/mutex.h> -+#include <linux/debugfs.h> -+#include <linux/platform_data/android_battery.h> -+ -+#define FAST_POLL (1 * 60) -+#define SLOW_POLL (10 * 60) -+ -+struct android_bat_data { -+ struct android_bat_platform_data *pdata; -+ struct android_bat_callbacks callbacks; -+ -+ struct device *dev; -+ -+ struct power_supply psy_bat; -+ -+ struct wake_lock monitor_wake_lock; -+ struct wake_lock charger_wake_lock; -+ -+ int charge_source; -+ -+ int batt_temp; -+ int batt_current; -+ unsigned int batt_health; -+ unsigned int batt_vcell; -+ unsigned int batt_soc; -+ unsigned int charging_status; -+ bool recharging; -+ unsigned long charging_start_time; -+ -+ struct workqueue_struct *monitor_wqueue; -+ struct work_struct monitor_work; -+ struct work_struct charger_work; -+ -+ struct alarm monitor_alarm; -+ ktime_t last_poll; -+ -+ struct dentry *debugfs_entry; -+}; -+ -+static enum power_supply_property android_battery_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_ONLINE, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_TECHNOLOGY, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+}; -+ -+static DEFINE_MUTEX(android_bat_state_lock); -+ -+static void android_bat_update_data(struct android_bat_data *battery); -+static int android_bat_enable_charging(struct android_bat_data *battery, -+ bool enable); -+ -+static char *charge_source_str(int charge_source) -+{ -+ switch (charge_source) { -+ case CHARGE_SOURCE_NONE: -+ return "none"; -+ case CHARGE_SOURCE_AC: -+ return "ac"; -+ case CHARGE_SOURCE_USB: -+ return "usb"; -+ default: -+ break; -+ } -+ -+ return "?"; -+} -+ -+static int android_bat_get_property(struct power_supply *ps, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct android_bat_data *battery = -+ container_of(ps, struct android_bat_data, psy_bat); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ val->intval = battery->charging_status; -+ break; -+ case POWER_SUPPLY_PROP_HEALTH: -+ val->intval = battery->batt_health; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+ val->intval = 1; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ val->intval = battery->batt_temp; -+ break; -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = 1; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ android_bat_update_data(battery); -+ val->intval = battery->batt_vcell; -+ if (val->intval == -1) -+ return -EINVAL; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ val->intval = battery->batt_soc; -+ if (val->intval == -1) -+ return -EINVAL; -+ break; -+ case POWER_SUPPLY_PROP_TECHNOLOGY: -+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ android_bat_update_data(battery); -+ val->intval = battery->batt_current; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static void android_bat_get_temp(struct android_bat_data *battery) -+{ -+ int batt_temp = 42; /* 4.2C */ -+ int health = battery->batt_health; -+ -+ if (battery->pdata->get_temperature) -+ battery->pdata->get_temperature(&batt_temp); -+ -+ if (battery->charge_source != CHARGE_SOURCE_NONE) { -+ if (batt_temp >= battery->pdata->temp_high_threshold) { -+ if (health != POWER_SUPPLY_HEALTH_OVERHEAT && -+ health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) { -+ pr_info("battery overheat (%d>=%d), " \ -+ "charging unavailable\n", -+ batt_temp, -+ battery->pdata->temp_high_threshold); -+ battery->batt_health = -+ POWER_SUPPLY_HEALTH_OVERHEAT; -+ } -+ } else if (batt_temp <= battery->pdata->temp_high_recovery && -+ batt_temp >= battery->pdata->temp_low_recovery) { -+ if (health == POWER_SUPPLY_HEALTH_OVERHEAT || -+ health == POWER_SUPPLY_HEALTH_COLD) { -+ pr_info("battery recovery (%d,%d~%d)," \ -+ "charging available\n", -+ batt_temp, -+ battery->pdata->temp_low_recovery, -+ battery->pdata->temp_high_recovery); -+ battery->batt_health = -+ POWER_SUPPLY_HEALTH_GOOD; -+ } -+ } else if (batt_temp <= battery->pdata->temp_low_threshold) { -+ if (health != POWER_SUPPLY_HEALTH_COLD && -+ health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) { -+ pr_info("battery cold (%d <= %d)," \ -+ "charging unavailable\n", -+ batt_temp, -+ battery->pdata->temp_low_threshold); -+ battery->batt_health = -+ POWER_SUPPLY_HEALTH_COLD; -+ } -+ } -+ } -+ -+ battery->batt_temp = batt_temp; -+} -+ -+/* -+ * android_bat_state_lock not held, may call back into -+ * android_bat_charge_source_changed. Gathering data here can be -+ * non-atomic; updating our state based on the data may need to be -+ * atomic. -+ */ -+ -+static void android_bat_update_data(struct android_bat_data *battery) -+{ -+ int ret; -+ int v; -+ -+ if (battery->pdata->poll_charge_source) -+ battery->charge_source = battery->pdata->poll_charge_source(); -+ -+ if (battery->pdata->get_voltage_now) { -+ ret = battery->pdata->get_voltage_now(); -+ battery->batt_vcell = ret >= 0 ? ret : 4242000; -+ } -+ -+ if (battery->pdata->get_capacity) { -+ ret = battery->pdata->get_capacity(); -+ battery->batt_soc = ret >= 0 ? ret : 42; -+ } -+ -+ if (battery->pdata->get_current_now) { -+ ret = battery->pdata->get_current_now(&v); -+ -+ if (!ret) -+ battery->batt_current = v; -+ } -+ -+ android_bat_get_temp(battery); -+} -+ -+static void android_bat_set_charge_time(struct android_bat_data *battery, -+ bool enable) -+{ -+ if (enable && !battery->charging_start_time) { -+ struct timespec cur_time; -+ -+ get_monotonic_boottime(&cur_time); -+ /* record start time for charge timeout timer */ -+ battery->charging_start_time = cur_time.tv_sec; -+ } else if (!enable) { -+ /* clear charge timeout timer */ -+ battery->charging_start_time = 0; -+ } -+} -+ -+static int android_bat_enable_charging(struct android_bat_data *battery, -+ bool enable) -+{ -+ if (enable && (battery->batt_health != POWER_SUPPLY_HEALTH_GOOD)) { -+ battery->charging_status = -+ POWER_SUPPLY_STATUS_NOT_CHARGING; -+ return -EPERM; -+ } -+ -+ if (enable) { -+ if (battery->pdata && battery->pdata->set_charging_current) -+ battery->pdata->set_charging_current -+ (battery->charge_source); -+ } -+ -+ if (battery->pdata && battery->pdata->set_charging_enable) -+ battery->pdata->set_charging_enable(enable); -+ -+ android_bat_set_charge_time(battery, enable); -+ pr_info("battery: enable=%d charger: %s\n", enable, -+ charge_source_str(battery->charge_source)); -+ return 0; -+} -+ -+static bool android_bat_charge_timeout(struct android_bat_data *battery, -+ unsigned long timeout) -+{ -+ struct timespec cur_time; -+ -+ if (!battery->charging_start_time) -+ return 0; -+ -+ get_monotonic_boottime(&cur_time); -+ pr_debug("%s: Start time: %ld, End time: %ld, current time: %ld\n", -+ __func__, battery->charging_start_time, -+ battery->charging_start_time + timeout, -+ cur_time.tv_sec); -+ return cur_time.tv_sec >= battery->charging_start_time + timeout; -+} -+ -+static void android_bat_charging_timer(struct android_bat_data *battery) -+{ -+ if (!battery->charging_start_time && -+ battery->charging_status == POWER_SUPPLY_STATUS_CHARGING) { -+ android_bat_enable_charging(battery, true); -+ battery->recharging = true; -+ pr_debug("%s: charge status charging but timer is expired\n", -+ __func__); -+ } else if (battery->charging_start_time == 0) { -+ pr_debug("%s: charging_start_time never initialized\n", -+ __func__); -+ return; -+ } -+ -+ if (android_bat_charge_timeout( -+ battery, -+ battery->recharging ? battery->pdata->recharging_time : -+ battery->pdata->full_charging_time)) { -+ android_bat_enable_charging(battery, false); -+ if (battery->batt_vcell > -+ battery->pdata->recharging_voltage && -+ battery->batt_soc == 100) -+ battery->charging_status = -+ POWER_SUPPLY_STATUS_FULL; -+ battery->recharging = false; -+ battery->charging_start_time = 0; -+ pr_info("battery: charging timer expired\n"); -+ } -+ -+ return; -+} -+ -+static void android_bat_charge_source_changed(struct android_bat_callbacks *ptr, -+ int charge_source) -+{ -+ struct android_bat_data *battery = -+ container_of(ptr, struct android_bat_data, callbacks); -+ -+ wake_lock(&battery->charger_wake_lock); -+ mutex_lock(&android_bat_state_lock); -+ battery->charge_source = charge_source; -+ -+ pr_info("battery: charge source type was changed: %s\n", -+ charge_source_str(battery->charge_source)); -+ -+ mutex_unlock(&android_bat_state_lock); -+ queue_work(battery->monitor_wqueue, &battery->charger_work); -+} -+ -+static void android_bat_set_full_status(struct android_bat_callbacks *ptr) -+{ -+ struct android_bat_data *battery = -+ container_of(ptr, struct android_bat_data, callbacks); -+ -+ mutex_lock(&android_bat_state_lock); -+ pr_info("battery: battery full\n"); -+ battery->charging_status = POWER_SUPPLY_STATUS_FULL; -+ android_bat_enable_charging(battery, false); -+ battery->recharging = false; -+ mutex_unlock(&android_bat_state_lock); -+ power_supply_changed(&battery->psy_bat); -+} -+ -+static void android_bat_charger_work(struct work_struct *work) -+{ -+ struct android_bat_data *battery = -+ container_of(work, struct android_bat_data, charger_work); -+ -+ mutex_lock(&android_bat_state_lock); -+ -+ switch (battery->charge_source) { -+ case CHARGE_SOURCE_NONE: -+ battery->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; -+ android_bat_enable_charging(battery, false); -+ battery->batt_health = POWER_SUPPLY_HEALTH_GOOD; -+ battery->recharging = false; -+ battery->charging_start_time = 0; -+ break; -+ case CHARGE_SOURCE_USB: -+ case CHARGE_SOURCE_AC: -+ /* -+ * If charging status indicates a charger was already -+ * connected prior to this and the status is something -+ * other than charging ("full" or "not-charging"), leave -+ * the status alone. -+ */ -+ if (battery->charging_status == -+ POWER_SUPPLY_STATUS_DISCHARGING || -+ battery->charging_status == POWER_SUPPLY_STATUS_UNKNOWN) -+ battery->charging_status = POWER_SUPPLY_STATUS_CHARGING; -+ -+ /* -+ * Don't re-enable charging if the battery is full and we -+ * are not actively re-charging it, or if "not-charging" -+ * status is set. -+ */ -+ if (!((battery->charging_status == POWER_SUPPLY_STATUS_FULL -+ && !battery->recharging) || battery->charging_status == -+ POWER_SUPPLY_STATUS_NOT_CHARGING)) -+ android_bat_enable_charging(battery, true); -+ -+ break; -+ default: -+ pr_err("%s: Invalid charger type\n", __func__); -+ break; -+ } -+ -+ mutex_unlock(&android_bat_state_lock); -+ wake_lock_timeout(&battery->charger_wake_lock, HZ * 2); -+ power_supply_changed(&battery->psy_bat); -+} -+ -+ -+static void android_bat_monitor_set_alarm(struct android_bat_data *battery, -+ int seconds) -+{ -+ alarm_start(&battery->monitor_alarm, -+ ktime_add(battery->last_poll, ktime_set(seconds, 0))); -+} -+ -+static void android_bat_monitor_work(struct work_struct *work) -+{ -+ struct android_bat_data *battery = -+ container_of(work, struct android_bat_data, monitor_work); -+ struct timespec cur_time; -+ -+ wake_lock(&battery->monitor_wake_lock); -+ android_bat_update_data(battery); -+ mutex_lock(&android_bat_state_lock); -+ -+ switch (battery->charging_status) { -+ case POWER_SUPPLY_STATUS_FULL: -+ if (battery->batt_vcell < battery->pdata->recharging_voltage && -+ !battery->recharging) { -+ battery->recharging = true; -+ android_bat_enable_charging(battery, true); -+ pr_info("battery: start recharging, v=%d\n", -+ battery->batt_vcell/1000); -+ } -+ break; -+ case POWER_SUPPLY_STATUS_DISCHARGING: -+ break; -+ case POWER_SUPPLY_STATUS_CHARGING: -+ switch (battery->batt_health) { -+ case POWER_SUPPLY_HEALTH_OVERHEAT: -+ case POWER_SUPPLY_HEALTH_COLD: -+ case POWER_SUPPLY_HEALTH_OVERVOLTAGE: -+ case POWER_SUPPLY_HEALTH_DEAD: -+ case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: -+ battery->charging_status = -+ POWER_SUPPLY_STATUS_NOT_CHARGING; -+ android_bat_enable_charging(battery, false); -+ -+ pr_info("battery: Not charging, health=%d\n", -+ battery->batt_health); -+ break; -+ default: -+ break; -+ } -+ break; -+ case POWER_SUPPLY_STATUS_NOT_CHARGING: -+ if (battery->batt_health == POWER_SUPPLY_HEALTH_GOOD) { -+ pr_info("battery: battery health recovered\n"); -+ if (battery->charge_source != CHARGE_SOURCE_NONE) { -+ android_bat_enable_charging(battery, true); -+ battery->charging_status -+ = POWER_SUPPLY_STATUS_CHARGING; -+ } else { -+ battery->charging_status -+ = POWER_SUPPLY_STATUS_DISCHARGING; -+ } -+ } -+ break; -+ default: -+ pr_err("%s: Undefined battery status: %d\n", __func__, -+ battery->charging_status); -+ break; -+ } -+ -+ android_bat_charging_timer(battery); -+ get_monotonic_boottime(&cur_time); -+ pr_info("battery: l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d%s ct=%lu type=%s\n", -+ battery->batt_soc, battery->batt_vcell/1000, -+ battery->batt_current, battery->batt_temp < 0 ? "-" : "", -+ abs(battery->batt_temp / 10), abs(battery->batt_temp % 10), -+ battery->batt_health, battery->charging_status, -+ battery->recharging ? "r" : "", -+ battery->charging_start_time ? -+ cur_time.tv_sec - battery->charging_start_time : 0, -+ charge_source_str(battery->charge_source)); -+ mutex_unlock(&android_bat_state_lock); -+ power_supply_changed(&battery->psy_bat); -+ battery->last_poll = ktime_get_boottime(); -+ android_bat_monitor_set_alarm(battery, FAST_POLL); -+ wake_unlock(&battery->monitor_wake_lock); -+ return; -+} -+ -+static enum alarmtimer_restart android_bat_monitor_alarm( -+ struct alarm *alarm, ktime_t now) -+{ -+ struct android_bat_data *battery = -+ container_of(alarm, struct android_bat_data, monitor_alarm); -+ -+ wake_lock(&battery->monitor_wake_lock); -+ queue_work(battery->monitor_wqueue, &battery->monitor_work); -+ return ALARMTIMER_NORESTART; -+} -+ -+static int android_power_debug_dump(struct seq_file *s, void *unused) -+{ -+ struct android_bat_data *battery = s->private; -+ struct timespec cur_time; -+ -+ android_bat_update_data(battery); -+ get_monotonic_boottime(&cur_time); -+ mutex_lock(&android_bat_state_lock); -+ seq_printf(s, "l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d%s ct=%lu type=%s\n", -+ battery->batt_soc, battery->batt_vcell/1000, -+ battery->batt_current, battery->batt_temp < 0 ? "-" : "", -+ abs(battery->batt_temp / 10), abs(battery->batt_temp % 10), -+ battery->batt_health, battery->charging_status, -+ battery->recharging ? "r" : "", -+ battery->charging_start_time ? -+ cur_time.tv_sec - battery->charging_start_time : 0, -+ charge_source_str(battery->charge_source)); -+ mutex_unlock(&android_bat_state_lock); -+ return 0; -+} -+ -+static int android_power_debug_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, android_power_debug_dump, inode->i_private); -+} -+ -+static const struct file_operations android_power_debug_fops = { -+ .open = android_power_debug_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static __devinit int android_bat_probe(struct platform_device *pdev) -+{ -+ struct android_bat_platform_data *pdata = dev_get_platdata(&pdev->dev); -+ struct android_bat_data *battery; -+ int ret = 0; -+ -+ dev_info(&pdev->dev, "Android Battery Driver\n"); -+ battery = kzalloc(sizeof(*battery), GFP_KERNEL); -+ if (!battery) -+ return -ENOMEM; -+ -+ battery->pdata = pdata; -+ if (!battery->pdata) { -+ pr_err("%s : No platform data\n", __func__); -+ ret = -EINVAL; -+ goto err_pdata; -+ } -+ -+ battery->dev = &pdev->dev; -+ platform_set_drvdata(pdev, battery); -+ battery->batt_health = POWER_SUPPLY_HEALTH_GOOD; -+ -+ battery->psy_bat.name = "android-battery", -+ battery->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, -+ battery->psy_bat.properties = android_battery_props, -+ battery->psy_bat.num_properties = ARRAY_SIZE(android_battery_props), -+ battery->psy_bat.get_property = android_bat_get_property, -+ -+ battery->batt_vcell = -1; -+ battery->batt_soc = -1; -+ -+ wake_lock_init(&battery->monitor_wake_lock, WAKE_LOCK_SUSPEND, -+ "android-battery-monitor"); -+ wake_lock_init(&battery->charger_wake_lock, WAKE_LOCK_SUSPEND, -+ "android-chargerdetect"); -+ -+ ret = power_supply_register(&pdev->dev, &battery->psy_bat); -+ if (ret) { -+ dev_err(battery->dev, "%s: failed to register psy_bat\n", -+ __func__); -+ goto err_psy_bat_reg; -+ } -+ -+ battery->monitor_wqueue = -+ alloc_workqueue(dev_name(&pdev->dev), WQ_FREEZABLE, 1); -+ if (!battery->monitor_wqueue) { -+ dev_err(battery->dev, "%s: fail to create workqueue\n", -+ __func__); -+ goto err_wq; -+ } -+ -+ INIT_WORK(&battery->monitor_work, android_bat_monitor_work); -+ INIT_WORK(&battery->charger_work, android_bat_charger_work); -+ -+ battery->callbacks.charge_source_changed = -+ android_bat_charge_source_changed; -+ battery->callbacks.battery_set_full = -+ android_bat_set_full_status; -+ if (battery->pdata && battery->pdata->register_callbacks) -+ battery->pdata->register_callbacks(&battery->callbacks); -+ -+ /* get initial charger status */ -+ if (battery->pdata->poll_charge_source) -+ battery->charge_source = battery->pdata->poll_charge_source(); -+ -+ wake_lock(&battery->charger_wake_lock); -+ queue_work(battery->monitor_wqueue, &battery->charger_work); -+ -+ wake_lock(&battery->monitor_wake_lock); -+ battery->last_poll = ktime_get_boottime(); -+ alarm_init(&battery->monitor_alarm, ALARM_BOOTTIME, -+ android_bat_monitor_alarm); -+ queue_work(battery->monitor_wqueue, &battery->monitor_work); -+ -+ battery->debugfs_entry = -+ debugfs_create_file("android-power", S_IRUGO, NULL, -+ battery, &android_power_debug_fops); -+ if (!battery->debugfs_entry) -+ pr_err("failed to create android-power debugfs entry\n"); -+ -+ return 0; -+ -+err_wq: -+ power_supply_unregister(&battery->psy_bat); -+err_psy_bat_reg: -+ wake_lock_destroy(&battery->monitor_wake_lock); -+ wake_lock_destroy(&battery->charger_wake_lock); -+err_pdata: -+ kfree(battery); -+ -+ return ret; -+} -+ -+static int __devexit android_bat_remove(struct platform_device *pdev) -+{ -+ struct android_bat_data *battery = platform_get_drvdata(pdev); -+ -+ alarm_cancel(&battery->monitor_alarm); -+ flush_workqueue(battery->monitor_wqueue); -+ destroy_workqueue(battery->monitor_wqueue); -+ power_supply_unregister(&battery->psy_bat); -+ wake_lock_destroy(&battery->monitor_wake_lock); -+ wake_lock_destroy(&battery->charger_wake_lock); -+ debugfs_remove(battery->debugfs_entry); -+ kfree(battery); -+ return 0; -+} -+ -+static int android_bat_suspend(struct device *dev) -+{ -+ struct android_bat_data *battery = dev_get_drvdata(dev); -+ -+ cancel_work_sync(&battery->monitor_work); -+ android_bat_monitor_set_alarm( -+ battery, -+ battery->charge_source == CHARGE_SOURCE_NONE ? -+ SLOW_POLL : FAST_POLL); -+ return 0; -+} -+ -+static void android_bat_resume(struct device *dev) -+{ -+ struct android_bat_data *battery = dev_get_drvdata(dev); -+ -+ android_bat_monitor_set_alarm(battery, FAST_POLL); -+ return; -+} -+ -+static const struct dev_pm_ops android_bat_pm_ops = { -+ .prepare = android_bat_suspend, -+ .complete = android_bat_resume, -+}; -+ -+static struct platform_driver android_bat_driver = { -+ .driver = { -+ .name = "android-battery", -+ .owner = THIS_MODULE, -+ .pm = &android_bat_pm_ops, -+ }, -+ .probe = android_bat_probe, -+ .remove = __devexit_p(android_bat_remove), -+}; -+ -+static int __init android_bat_init(void) -+{ -+ return platform_driver_register(&android_bat_driver); -+} -+ -+static void __exit android_bat_exit(void) -+{ -+ platform_driver_unregister(&android_bat_driver); -+} -+ -+late_initcall(android_bat_init); -+module_exit(android_bat_exit); -+ -+MODULE_DESCRIPTION("Android battery driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/power/plat-anyka/Makefile b/drivers/power/plat-anyka/Makefile -new file mode 100644 -index 00000000..b8f84617 ---- /dev/null -+++ b/drivers/power/plat-anyka/Makefile -@@ -0,0 +1,5 @@ -+# -+# Makefile for RTC class/drivers. -+# -+ -+obj-$(CONFIG_BATTERY_AK) += battery.o -diff --git a/drivers/power/plat-anyka/battery.c b/drivers/power/plat-anyka/battery.c -new file mode 100755 -index 00000000..60a13269 ---- /dev/null -+++ b/drivers/power/plat-anyka/battery.c -@@ -0,0 +1,1436 @@ -+/* -+ * @file battery.c -+ * @battery driver for ak chip -+ * @Copyright (C) 2010 Anyka (Guangzhou) Microelectronics Technology Co -+ * @author gao_wangsheng -+ * @date 2011-04 -+ * @version 2.0 -+*/ -+ -+/* -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ */ -+ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/power_supply.h> -+#include <linux/delay.h> -+#include <linux/spinlock.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/gpio.h> -+#include <linux/notifier.h> -+#include <linux/reboot.h> -+#include <plat-anyka/bat.h> -+#include <plat-anyka/adkey.h> -+#include <mach/adc.h> -+ -+//#define BATTERY_GET_VOLTAGE -+ -+/* BATTERY DEFINE*/ -+#define UPDATE_DISCHARGE_DELAY (HZ * 6) /* delay 6s */ -+#define UPDATE_CHARGE_DELAY (HZ * 60) /* delay 60s */ -+#define UPDATE_VOLTAGE_DELAY (HZ * 1) /* delay 1s */ -+#define CHECK_PDOWN_DELAY 50 /* delay 50ms */ -+#define CHECK_READ_CNT 10 -+#define CHECK_PDOWN_CNT 5 -+#define CHARGE_FULL 1 -+#define CHARGE_NOT_FULL 0 -+ -+#define PK(fmt...) //printk(fmt) // debug and read ad4 voltage -+#define PK_SAMPLE(fmt...) //printk(fmt) //debug read voltage sample -+#define PK_CHARGE(fmt...) //printk(fmt) //debug charge ac and usb in -+#define PK_DISCHARGE(fmt...) //printk(fmt) //debug discharge -+#define PK_PDOWN(fmt...) //printk(fmt) //debug check power down -+#define get_bat_platform_data(x) ((x)->bat_ps.dev->parent->platform_data) -+ -+struct ak_bat{ -+ struct power_supply bat_ps; -+ struct power_supply ac_ps; -+ struct power_supply usb_ps; -+ struct read_voltage_sample rd_voltage; -+ struct mutex bat_lock; -+ struct timer_list timer; -+ int status; -+ int ac_online; -+ int usb_online; -+ int voltage; -+ int capacity; -+ int pdown_count; -+ int read_count; -+ atomic_t full_flag; -+}; -+ -+static struct delayed_work charge_work; -+static struct delayed_work discharge_work; -+static struct delayed_work voltage_work; -+static struct delayed_work usbirq_work; -+static struct delayed_work acirq_work; -+static struct delayed_work pdown_work; -+static struct delayed_work resume_work; -+static struct ak_bat bat_device; -+ -+static struct notifier_block ac_detect_nb; -+ -+ -+static void ak_bat_update(struct ak_bat *battery); -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief set battery full flag -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void bat_charge_full_timer(unsigned long bat_dev) -+{ -+ struct ak_bat *battery = (void *)bat_dev; -+ -+ if (POWER_SUPPLY_STATUS_CHARGING == battery->status) -+ { -+ atomic_set(&battery->full_flag, CHARGE_FULL); -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief check capacity -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void bat_check_charge_capacity(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ unsigned int delay = info->bat_mach_info.full_delay * 60 * 1000; //minute to ms -+ -+ if (POWER_SUPPLY_STATUS_CHARGING != battery->status) -+ { -+ return; -+ } -+ -+ if (atomic_read(&battery->full_flag) == CHARGE_FULL -+ && battery->capacity != info->bat_mach_info.full_capacity) -+ { -+ battery->capacity = info->bat_mach_info.full_capacity; -+ } -+ -+ if (atomic_read(&battery->full_flag) == CHARGE_NOT_FULL -+ && battery->capacity == info->bat_mach_info.full_capacity) -+ { -+ battery->capacity = info->bat_mach_info.full_capacity - 1; -+ -+ if (!timer_pending(&battery->timer)) -+ { -+ mod_timer(&battery->timer,jiffies + msecs_to_jiffies(delay)); -+ } -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief read battery voltage -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *info -+* @return voltage -+*/ -+int ak_bat_read_voltage(struct ak_bat_mach_info *info) -+{ -+ int voltage; -+ -+ PK("\n###############%s; \n",__func__); -+ -+ // read voltage sample -+ PK("############adc1_read_bat:\n"); -+ voltage = (int)adc1_read_bat(); -+ PK("ad4_voltage = %d:\n",voltage); -+ -+ voltage = voltage -+ * (info->bat_adc.up_resistance + info->bat_adc.dw_resistance) -+ / info->bat_adc.dw_resistance; -+ PK("bat_voltage = %d:\n",voltage); -+ -+ voltage += info->bat_adc.voltage_correct; // correct battery voltage -+ PK("correct_voltage = %d:\n",voltage); -+ -+ return voltage; -+ -+} -+EXPORT_SYMBOL(ak_bat_read_voltage); -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief read and set gpio interrupt -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] gpio pin -+* @return void -+*/ -+static void bat_set_int_inverse(unsigned int pin) -+{ -+ if (ak_gpio_getpin(pin) == AK_GPIO_OUT_HIGH) -+ { -+ ak_gpio_intpol(pin, AK_GPIO_INT_LOWLEVEL); -+ } -+ else -+ { -+ ak_gpio_intpol(pin, AK_GPIO_INT_HIGHLEVEL); -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief notify ac and usb state who interest in -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void bat_notify_ac_usb_plug(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ PK_CHARGE("##################%s:\n", __func__); -+ -+ if (info->usb_gpio.pindata.pin >= 0) -+ { -+ // usb and ac pin all exist -+ if (battery->usb_online) -+ { -+ power_notifier_call_chain(POWER_EVENT_AC_PLUGIN, NULL); -+ } -+ else -+ { -+ power_notifier_call_chain(POWER_EVENT_AC_PLUGOUT, NULL); -+ } -+ } -+ -+ else -+ { -+ // only ac exist -+ if (battery->ac_online) -+ { -+ power_notifier_call_chain(POWER_EVENT_AC_PLUGIN, NULL); -+ } -+ else -+ { -+ power_notifier_call_chain(POWER_EVENT_AC_PLUGOUT, NULL); -+ } -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief poweroff system when voltage down to setting level -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void bat_check_voltage_poweroff(struct ak_bat *battery ) -+{ -+ int voltage; -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ voltage = ak_bat_read_voltage(info); -+ if (voltage <= info->bat_mach_info.min_voltage) -+ { -+ PK_PDOWN("voltage=%d <= pdown_voltage=%d\n",voltage, -+ info->bat_mach_info.min_voltage); -+ schedule_delayed_work(&pdown_work,0); -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief switch work depend on status -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void switch_charge_discharge_work(struct ak_bat *battery) -+{ -+ if (POWER_SUPPLY_STATUS_CHARGING == battery->status) -+ { -+ cancel_delayed_work_sync(&discharge_work); -+ schedule_delayed_work(&charge_work,UPDATE_CHARGE_DELAY); -+ } -+ else -+ { -+ cancel_delayed_work_sync(&charge_work); -+ del_timer_sync(&battery->timer); -+ schedule_delayed_work(&discharge_work,UPDATE_DISCHARGE_DELAY); -+ } -+} -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief return battery property to user space -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *psy... -+* @return int -+*/ -+static int bat_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct ak_bat *battery = container_of(psy, struct ak_bat, bat_ps); -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ val->intval = battery->status; -+ break; -+ case POWER_SUPPLY_PROP_TECHNOLOGY: -+ val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ val->intval = battery->voltage; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ val->intval = info->bat_mach_info.max_voltage; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: -+ val->intval = info->bat_mach_info.min_voltage; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ val->intval = 25; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+ val->intval = 1; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ val->intval = battery->capacity; // real capacity -+ break; -+#if 0 -+ case POWER_SUPPLY_PROP_POWEROFF_CAP: -+ val->intval = info->bat_mach_info.poweroff_cap; //power off capacity value -+ break; -+ case POWER_SUPPLY_PROP_LOW_CAP: -+ val->intval = info->bat_mach_info.low_cap; //low warring capacity -+ break; -+ case POWER_SUPPLY_PROP_RECOVER_CAP: -+ val->intval = info->bat_mach_info.recover_cap; //recover capacity limit -+ break; -+ case POWER_SUPPLY_PROP_POWER_ON_VOLTAGE: -+ val->intval = info->bat_mach_info.power_on_voltage; //power on voltage -+ break; -+ case POWER_SUPPLY_PROP_CPOWER_ON_VOLTAGE: -+ val->intval = info->bat_mach_info.cpower_on_voltage; //low warring capacity -+ break; -+#endif -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief return usb property -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *psy... -+* @return void -+*/ -+static int usb_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ int ret = 0; -+ struct ak_bat *battery = container_of(psy, struct ak_bat, usb_ps); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = battery->usb_online; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief return ac property -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *psy... -+* @return void -+*/ -+static int ac_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ int ret = 0; -+ struct ak_bat *battery = container_of(psy, struct ak_bat, ac_ps); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = battery->ac_online; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+ -+static void ak_battery_external_power_changed(struct power_supply *bat_ps) -+{ -+ // NULL -+} -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief power manage function -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *dev -+* @return int -+*/ -+#ifdef CONFIG_PM -+static int ak_battery_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ flush_scheduled_work(); -+ del_timer_sync(&bat_device.timer); -+ atomic_set(&bat_device.full_flag, CHARGE_NOT_FULL); -+ cancel_delayed_work_sync(&charge_work); -+ cancel_delayed_work_sync(&discharge_work); -+ cancel_delayed_work_sync(&voltage_work); -+ cancel_delayed_work_sync(&usbirq_work); -+ cancel_delayed_work_sync(&acirq_work); -+ cancel_delayed_work_sync(&pdown_work); -+ cancel_delayed_work_sync(&resume_work); -+ -+ return 0; -+} -+ -+static int ak_battery_resume(struct platform_device *dev) -+{ -+ -+ schedule_delayed_work(&resume_work,msecs_to_jiffies(1000)); -+ return 0; -+} -+#else -+#define ak_battery_suspend NULL -+#define ak_battery_resume NULL -+#endif -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief caculate capacity from discharge voltage -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery... -+* @return void -+*/ -+static void get_capacity_from_voltage(struct ak_bat *battery, -+ struct ak_bat_mach_info *info,int voltage) -+{ -+ int vtg = voltage; -+ int min_voltage; -+ int max_voltage; -+ -+ min_voltage = (POWER_SUPPLY_STATUS_CHARGING == battery->status) -+ ? info->bat_mach_info.charge_min_voltage -+ : info->bat_mach_info.min_voltage; -+ max_voltage = (POWER_SUPPLY_STATUS_DISCHARGING == battery->status -+ && atomic_read(&battery->full_flag) == CHARGE_FULL) -+ ? info->bat_mach_info.full_voltage -+ : info->bat_mach_info.max_voltage; -+ -+ if (vtg < min_voltage) -+ { -+ vtg = min_voltage; -+ } -+ -+ if (vtg > max_voltage) -+ { -+ vtg = max_voltage; -+ } -+ -+ -+ battery->capacity = (vtg - min_voltage) * info->bat_mach_info.full_capacity -+ / (max_voltage - min_voltage); -+ -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief init sample value -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void ak_init_sample_value(struct ak_bat *battery) -+{ -+ struct read_voltage_sample *rd_voltage = &(battery->rd_voltage); -+ -+ rd_voltage->index = 0; -+ rd_voltage->sum = 0; -+ rd_voltage->max = 0; -+ rd_voltage->min = rd_voltage->design_max * 2; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief caculate voltage -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery,*info -+* @return void -+*/ -+static void ak_update_voltage(struct ak_bat *battery, -+ struct ak_bat_mach_info *info) -+{ -+ int temp; -+ struct read_voltage_sample *rd_voltage = &(battery->rd_voltage); -+ -+ PK_SAMPLE("\n###############%s; \n",__func__); -+ -+ // if voltage_index in correct range -+ if ((rd_voltage->index >= rd_voltage->sample) -+ || (rd_voltage->index < 0)) -+ { -+ PK_SAMPLE("%s:error voltage sample index\n",__func__); -+ ak_init_sample_value(battery); -+ } -+ -+ // read voltage sample -+ temp = ak_bat_read_voltage(info); -+ -+ // save voltage max and min -+ if (temp > rd_voltage->max) -+ { -+ rd_voltage->max = temp; -+ } -+ -+ if (temp < rd_voltage->min) -+ { -+ rd_voltage->min = temp; -+ } -+ -+ PK_SAMPLE("read_voltage=%d\n",temp); -+ PK_SAMPLE("voltage_max=%d; voltage_min=%d;\n",rd_voltage->max,rd_voltage->min); -+ PK_SAMPLE("voltage_index=%d; voltage_sum=%d;\n",rd_voltage->index,rd_voltage->sum); -+ -+ rd_voltage->sum += temp; -+ -+ if (++rd_voltage->index == rd_voltage->sample) -+ { -+ rd_voltage->sum -= rd_voltage->min + rd_voltage->max; -+ rd_voltage->index -= 2; -+ battery->voltage =rd_voltage->sum / rd_voltage->index; -+ -+ PK_SAMPLE("=========bat_data.voltage = %d;=======\n",battery->voltage); -+ ak_init_sample_value(battery); -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief wrap for caculating voltage -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void bat_update_voltage(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ mutex_lock(&battery->bat_lock); -+ ak_update_voltage(battery,info); -+ mutex_unlock(&battery->bat_lock); -+} -+ -+static void update_voltage_immediately(struct ak_bat *battery, -+ struct ak_bat_mach_info *info) -+{ -+ int read_cnt; -+ -+ ak_init_sample_value(battery); -+ -+ for (read_cnt = 0; read_cnt < battery->rd_voltage.sample; read_cnt++) -+ { -+ ak_update_voltage(battery,info); -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief debug message -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void bat_print_battery_info(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ printk("battery:cap=%d; vol=%d; status=%s; full=%d; poweroff_cap=%d; low_cap=%d.\n", -+ battery->capacity, -+ battery->voltage, -+ (battery->status == POWER_SUPPLY_STATUS_CHARGING) ? "charge" : "discharge", -+ ak_gpio_getpin(info->full_gpio.pindata.pin), -+ info->bat_mach_info.poweroff_cap, -+ info->bat_mach_info.low_cap); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief check capacity flag -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void check_cap_full_flag(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ if (atomic_read(&battery->full_flag) == CHARGE_FULL) -+ { -+ if (battery->voltage < info->bat_mach_info.full_voltage) -+ { -+ atomic_set(&battery->full_flag, CHARGE_NOT_FULL); -+ } -+ } -+ else -+ { -+ if (battery->capacity == info->bat_mach_info.full_capacity) -+ { -+ atomic_set(&battery->full_flag, CHARGE_FULL); -+ } -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief caculate discharge capacity from discharge voltage -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void update_discharge_capacity(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ int old_capacity = battery->capacity; -+ -+ PK_DISCHARGE("###########%s:\n",__func__); -+ get_capacity_from_voltage(battery,info,battery->voltage); -+ check_cap_full_flag(battery); -+ -+ if (old_capacity != battery->capacity) -+ { -+ power_supply_changed(&battery->bat_ps); -+ } -+ -+ PK_DISCHARGE("voltage = %d;capacity = %d;\n", battery->voltage, battery->capacity); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief caculate capacity from charge voltage -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void update_charge_capacity(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ int old_capacity = battery->capacity; -+ -+ get_capacity_from_voltage(battery,info,battery->voltage); -+ bat_check_charge_capacity(battery); -+ -+ if (battery->capacity != old_capacity) -+ { -+ power_supply_changed(&battery->bat_ps); -+ } -+ -+ PK_CHARGE("voltage = %d; capacity = %d;\n", -+ battery->voltage,battery->capacity); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief caculate ac and usb status -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery, *info -+* @return void -+*/ -+static void ak_get_bat_status(struct ak_bat *battery -+ ,struct ak_bat_mach_info *info) -+{ -+ if (info->ac_gpio.is_detect_mode == BAT_CHARGE_GPIO_DETECT) { -+ if (info->ac_gpio.pindata.pin >= 0) -+ { -+ battery->ac_online = -+ (ak_gpio_getpin(info->ac_gpio.pindata.pin) == info->ac_gpio.active)? 1 : 0; -+ } -+ else -+ { -+ battery->ac_online = 0; -+ } -+ } -+ -+ if (info->usb_gpio.pindata.pin >= 0) -+ { -+ battery->usb_online = -+ (ak_gpio_getpin(info->usb_gpio.pindata.pin)== info->usb_gpio.active)? 1 : 0; -+ } -+ else -+ { -+ battery->usb_online = 0; -+ } -+ -+ // if (battery->ac_online || battery->usb_online) -+ if (battery->ac_online) -+ { -+ battery->status = POWER_SUPPLY_STATUS_CHARGING; -+ } -+ else -+ { -+ battery->status = POWER_SUPPLY_STATUS_DISCHARGING; -+ } -+ -+} -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief quickly power off system -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void check_machine_power_off(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ if ((poweroff_enable == info->bat_mach_info.power_off) -+ && (POWER_SUPPLY_STATUS_DISCHARGING == battery->status) -+ && (battery->voltage <= info->bat_mach_info.min_voltage)) -+ { -+ printk("battery:voltage=%d,machine power off immediately!\n",battery->voltage); -+ machine_power_off(); -+ } -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief ac irq work -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *work -+* @return void -+*/ -+static void bat_acirq_work(struct work_struct *work) -+{ -+ struct ak_bat *battery = &bat_device; -+ -+ PK_CHARGE("##################%s:\n", __func__); -+ ak_bat_update(battery); -+ check_machine_power_off(battery); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief ac irq handler -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] irq, *battery -+* @return irqreturn_t -+*/ -+static irqreturn_t akbat_ac_irqhandler(int irq, void *handle) -+{ -+ struct ak_bat *battery = (struct ak_bat *)handle; -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ PK_CHARGE("##################%s:\n", __func__); -+ disable_irq_nosync(irq); -+ bat_set_int_inverse(ak_irq_to_gpio(irq)); -+ schedule_delayed_work(&acirq_work,msecs_to_jiffies(info->ac_gpio.delay)); -+ enable_irq(irq); -+ return IRQ_HANDLED; -+} -+ -+static int ac_detect_plugin(struct notifier_block *nb, -+ unsigned long val, void *data) -+{ -+ struct ak_bat *battery = &bat_device; -+ -+ if (val == ADDETECT_AC_PLUGIN) { -+ battery->ac_online = 1; -+ } -+ else if (val == ADDETECT_AC_PLUGOUT) { -+ battery->ac_online = 0; -+ } -+ -+ ak_bat_update(battery); -+ return 0; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief usb irq handler -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery, irq -+* @return irqreturn_t -+*/ -+static irqreturn_t akbat_usb_irqhandler(int irq, void *handle) -+{ -+ struct ak_bat *battery = (struct ak_bat *)handle; -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ PK_CHARGE("##################%s:\n", __func__); -+ disable_irq_nosync(irq); -+ bat_set_int_inverse(ak_irq_to_gpio(irq)); -+ schedule_delayed_work(&usbirq_work,msecs_to_jiffies(info->usb_gpio.delay)); -+ enable_irq(irq); -+ return IRQ_HANDLED; -+} -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief update battery info -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void ak_bat_update(struct ak_bat *battery) -+{ -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ PK_CHARGE("##################%s:\n", __func__); -+ mutex_lock(&battery->bat_lock); -+ -+ ak_get_bat_status(battery,info); -+ update_voltage_immediately(battery,info); -+ get_capacity_from_voltage(battery,info,battery->voltage); -+ bat_check_charge_capacity(battery); -+ power_supply_changed(&battery->bat_ps); -+ power_supply_changed(&battery->ac_ps); -+ power_supply_changed(&battery->usb_ps); -+ -+ switch_charge_discharge_work(battery); -+ bat_notify_ac_usb_plug(battery); -+ -+ mutex_unlock(&battery->bat_lock); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief update charge info -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void ak_bat_update_charge(struct ak_bat *battery) -+{ -+ PK_CHARGE("##################%s:\n", __func__); -+ mutex_lock(&battery->bat_lock); -+ update_charge_capacity(battery); -+ mutex_unlock(&battery->bat_lock); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief update discharge info -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void ak_bat_update_discharge(struct ak_bat *battery) -+{ -+ PK_DISCHARGE("##################%s:\n", __func__); -+ mutex_lock(&battery->bat_lock); -+ update_discharge_capacity(battery); -+ mutex_unlock(&battery->bat_lock); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief charge work -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *work -+* @return void -+*/ -+static void bat_charge_work(struct work_struct *work) -+{ -+ ak_bat_update_charge(&bat_device); -+ schedule_delayed_work(&charge_work,UPDATE_CHARGE_DELAY); -+// schedule_delayed_work(&charge_work,HZ*6); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief discharge work -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *battery -+* @return void -+*/ -+static void bat_discharge_work(struct work_struct *work) -+{ -+ ak_bat_update_discharge(&bat_device); -+ schedule_delayed_work(&discharge_work,UPDATE_DISCHARGE_DELAY); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief voltage work -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *work -+* @return void -+*/ -+static void bat_voltage_work(struct work_struct *work) -+{ -+#ifdef BATTERY_GET_VOLTAGE -+ // 5 seconds to print battery info -+ static int print_time = 10; -+ if (--print_time < 0) { -+ print_time = 5; -+ bat_print_battery_info(&bat_device); -+ } -+#endif -+ bat_check_voltage_poweroff(&bat_device); -+ bat_update_voltage(&bat_device); -+ schedule_delayed_work(&voltage_work,UPDATE_VOLTAGE_DELAY); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief usb irq work -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *work -+* @return void -+*/ -+static void bat_usbirq_work(struct work_struct *work) -+{ -+ struct ak_bat *battery = &bat_device; -+ -+ PK_CHARGE("##################%s:\n", __func__); -+ ak_bat_update (battery); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief power down work -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *work -+* @return void -+*/ -+static void bat_pdown_work(struct work_struct *work) -+{ -+ int voltage; -+ struct ak_bat *battery = &bat_device; -+ struct ak_bat_mach_info *info = get_bat_platform_data(battery); -+ -+ PK_PDOWN("#############%s:\n",__func__); -+ if (battery->status != POWER_SUPPLY_STATUS_DISCHARGING) -+ { -+ return; -+ } -+ -+ if (battery->read_count++ < CHECK_READ_CNT) -+ { -+ PK_PDOWN("read_count=%d\n",battery->read_count); -+ voltage = ak_bat_read_voltage(info); -+ PK_PDOWN("voltage=%d\n",voltage); -+ -+ if (voltage <= info->bat_mach_info.min_voltage) -+ { -+ battery->pdown_count++; -+ } -+ -+ schedule_delayed_work(&pdown_work,msecs_to_jiffies(CHECK_PDOWN_DELAY)); -+ } -+ else -+ { -+ PK_PDOWN("pdown_count=%d\n",battery->pdown_count); -+ -+ if (battery->pdown_count >= CHECK_PDOWN_CNT) -+ { -+ mutex_lock(&battery->bat_lock); -+ printk(KERN_WARNING "Ak_battery:capacity=%d => 0!\n",battery->capacity); -+ battery->capacity = 0; -+ power_supply_changed(&battery->bat_ps); -+ cancel_delayed_work_sync(&voltage_work); -+ cancel_delayed_work_sync(&charge_work); -+ cancel_delayed_work_sync(&discharge_work); -+ mutex_unlock(&battery->bat_lock); -+ } -+ -+ battery->read_count = 0; -+ battery->pdown_count = 0; -+ } -+ -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief resume work -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *work -+* @return void -+*/ -+static void bat_resume_work(struct work_struct *work) -+{ -+ ak_bat_update(&bat_device); -+ schedule_delayed_work(&voltage_work,UPDATE_VOLTAGE_DELAY); -+} -+ -+static int battery_reboot_notify(struct notifier_block *nb, unsigned long code, -+ void *unused) -+{ -+ switch (code) { -+ case SYS_DOWN: -+ case SYS_HALT: -+ case SYS_POWER_OFF: -+ printk("%s:code=%ld, cap=%d, vol=%d, status=%s.\n", -+ __func__, -+ code, -+ bat_device.capacity, -+ bat_device.voltage, -+ bat_device.status==POWER_SUPPLY_STATUS_CHARGING ? "charging":"discharging"); -+ break; -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief power supply property -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] void -+* @return void -+*/ -+static enum power_supply_property bat_power_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_TECHNOLOGY, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_CAPACITY, -+#if 0 -+ POWER_SUPPLY_PROP_POWEROFF_CAP, -+ POWER_SUPPLY_PROP_LOW_CAP, -+ POWER_SUPPLY_PROP_RECOVER_CAP, -+ POWER_SUPPLY_PROP_POWER_ON_VOLTAGE, -+ POWER_SUPPLY_PROP_CPOWER_ON_VOLTAGE, -+#endif -+}; -+ -+static enum power_supply_property usb_power_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static enum power_supply_property ac_power_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief battery device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] void -+* @return void -+*/ -+static struct ak_bat bat_device = { -+ .bat_ps= { -+ .name = "battery", -+ .type = POWER_SUPPLY_TYPE_BATTERY, -+ .properties = bat_power_props, -+ .num_properties = ARRAY_SIZE(bat_power_props), -+ .get_property = bat_get_property, -+ .external_power_changed = ak_battery_external_power_changed, -+ .use_for_apm = 1, -+ }, -+ -+ .ac_ps = { -+ .name = "ac", -+ .type = POWER_SUPPLY_TYPE_MAINS, -+ .properties = ac_power_props, -+ .num_properties = ARRAY_SIZE(ac_power_props), -+ .get_property = ac_get_property, -+ }, -+ -+ .usb_ps = { -+ .name = "usb", -+ .type = POWER_SUPPLY_TYPE_USB, -+ .properties = usb_power_props, -+ .num_properties = ARRAY_SIZE(usb_power_props), -+ .get_property = usb_get_property, -+ }, -+ -+ .status = POWER_SUPPLY_STATUS_CHARGING, -+ .ac_online = 0, -+ .usb_online = 0, -+ .read_count = 0, -+ .pdown_count = 0, -+ .full_flag = ATOMIC_INIT(CHARGE_NOT_FULL), -+}; -+ -+ -+static struct notifier_block battery_reboot_nb = { -+ .notifier_call = battery_reboot_notify, -+ .next = NULL, -+ .priority = INT_MIN -+}; -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief probe battery -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *dev -+* @return fail or not -+*/ -+static int __devinit ak_battery_probe(struct platform_device *dev) -+{ -+ int ret = 0; -+ struct ak_bat_mach_info *info; -+ -+ info = (struct ak_bat_mach_info *)dev->dev.platform_data; -+ if (!info) -+ { -+ printk(KERN_ERR "%s:no platform data for battery\n",__func__); -+ ret = -EINVAL; -+ goto nodata_out; -+ } -+ -+ /* initialize hardware */ -+ mutex_init(&bat_device.bat_lock); -+ bat_device.rd_voltage.sample = info->bat_mach_info.voltage_sample; -+ bat_device.rd_voltage.design_max = info->bat_mach_info.max_voltage; -+ init_timer(&bat_device.timer); -+ bat_device.timer.function = bat_charge_full_timer; -+ bat_device.timer.data = (unsigned long) &bat_device; -+ -+ INIT_DELAYED_WORK(&charge_work,bat_charge_work); -+ INIT_DELAYED_WORK(&discharge_work,bat_discharge_work); -+ INIT_DELAYED_WORK(&voltage_work,bat_voltage_work); -+ INIT_DELAYED_WORK(&usbirq_work,bat_usbirq_work); -+ INIT_DELAYED_WORK(&pdown_work,bat_pdown_work); -+ INIT_DELAYED_WORK(&resume_work,bat_resume_work); -+ -+ ret = power_supply_register(&dev->dev, &bat_device.bat_ps); -+ if (ret != 0) -+ { -+ goto cancel_out; -+ } -+ -+ ret = power_supply_register(&dev->dev,&bat_device.usb_ps); -+ if (ret != 0) -+ { -+ goto free_bat_ps_out; -+ } -+ -+ ret = power_supply_register(&dev->dev,&bat_device.ac_ps); -+ if (ret != 0) -+ { -+ goto free_usb_ps_out; -+ } -+ -+ // use for charge full state -+ if (info->full_gpio.pindata.pin >= 0) -+ { -+ info->gpio_init(&info->full_gpio.pindata); -+ } -+ -+ if (info->ac_gpio.is_detect_mode == BAT_CHARGE_GPIO_DETECT) { -+ INIT_DELAYED_WORK(&acirq_work,bat_acirq_work); -+ // use for ac charge in irq -+ if (info->ac_gpio.irq >= 0) -+ { -+ info->gpio_init(&info->ac_gpio.pindata); -+ bat_set_int_inverse(info->ac_gpio.pindata.pin); -+ if (request_irq(info->ac_gpio.irq,akbat_ac_irqhandler,0,"ac_charge",&bat_device)) -+ { -+ printk(KERN_ERR "%s:Could not allocate IRQ %d\n", __func__,info->ac_gpio.irq); -+ ret = -EIO; -+ goto free_ac_ps_out; -+ } -+ } -+ } else if (info->ac_gpio.is_detect_mode == BAT_CHARGE_ADC_DETECT) { -+ memset(&ac_detect_nb, 0, sizeof(ac_detect_nb)); -+ ac_detect_nb.notifier_call = ac_detect_plugin; -+ addetect_register_client(&ac_detect_nb); -+ } -+ -+ // use for usb charge in irq -+ if (info->usb_gpio.irq >= 0) -+ { -+ info->gpio_init(&info->usb_gpio.pindata); -+ mdelay(100); -+ bat_set_int_inverse(info->usb_gpio.pindata.pin); -+ if (request_irq(info->usb_gpio.irq,akbat_usb_irqhandler,0,"usb_charge",&bat_device)) -+ { -+ printk(KERN_ERR "%s:Could not allocate IRQ %d\n", __func__,info->usb_gpio.irq); -+ ret = -EIO; -+ goto free_acirq_out; -+ } -+ } -+ -+ ak_bat_update(&bat_device); -+ schedule_delayed_work(&voltage_work,UPDATE_VOLTAGE_DELAY); -+ register_reboot_notifier(&battery_reboot_nb); -+ -+ bat_print_battery_info(&bat_device); -+ printk("AK Battery initialized\n"); -+ return ret; -+ -+free_acirq_out: -+ if (info->ac_gpio.irq > 0) -+ { -+ disable_irq(info->ac_gpio.irq); -+ free_irq(info->ac_gpio.irq, dev); -+ } -+free_ac_ps_out: -+ power_supply_unregister(&bat_device.ac_ps); -+free_usb_ps_out: -+ power_supply_unregister(&bat_device.usb_ps); -+free_bat_ps_out: -+ power_supply_unregister(&bat_device.bat_ps); -+cancel_out: -+ del_timer_sync(&bat_device.timer); -+ cancel_delayed_work_sync(&charge_work); -+ cancel_delayed_work_sync(&discharge_work); -+ cancel_delayed_work_sync(&voltage_work); -+ cancel_delayed_work_sync(&usbirq_work); -+ cancel_delayed_work_sync(&acirq_work); -+ cancel_delayed_work_sync(&pdown_work); -+ cancel_delayed_work_sync(&resume_work); -+ -+nodata_out: -+ printk(KERN_ERR "###########%s:ERR out##########\n",__func__); -+ return ret; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief remove battery -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] *dev -+* @return fail or not -+*/ -+static int __devexit ak_battery_remove(struct platform_device *dev) -+{ -+ struct ak_bat_mach_info *info; -+ -+ info = (struct ak_bat_mach_info *)dev->dev.platform_data; -+ if (!info) { -+ printk(KERN_ERR "no platform data for battery\n"); -+ return -EINVAL; -+ } -+ -+#ifdef CONFIG_AC_GPIO_DETECT -+ if (info->ac_gpio.irq > 0) -+ { -+ disable_irq(info->ac_gpio.irq); -+ free_irq(info->ac_gpio.irq, &bat_device); -+ } -+#elif defined(CONFIG_AC_AD_DETECT) -+ addetect_unregister_client(&ac_detect_nb); -+#endif -+ -+ if (info->usb_gpio.irq > 0) -+ { -+ disable_irq(info->usb_gpio.irq); -+ free_irq(info->usb_gpio.irq, &bat_device); -+ } -+ -+ del_timer_sync(&bat_device.timer); -+ cancel_delayed_work_sync(&charge_work); -+ cancel_delayed_work_sync(&discharge_work); -+ cancel_delayed_work_sync(&voltage_work); -+ cancel_delayed_work_sync(&usbirq_work); -+ cancel_delayed_work_sync(&acirq_work); -+ cancel_delayed_work_sync(&pdown_work); -+ cancel_delayed_work_sync(&resume_work); -+ -+ power_supply_unregister(&bat_device.bat_ps); -+ power_supply_unregister(&bat_device.ac_ps); -+ power_supply_unregister(&bat_device.usb_ps); -+ -+ unregister_reboot_notifier(&battery_reboot_nb); -+ return 0; -+} -+ -+static struct platform_driver ak_battery_driver = { -+ .driver = { -+ .name = "battery", -+ }, -+ .probe = ak_battery_probe, -+ .remove = __devexit_p(ak_battery_remove), -+ .suspend = ak_battery_suspend, -+ .resume = ak_battery_resume, -+}; -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief init battery -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] void -+* @return fail or not -+*/ -+static int __init ak_battery_init(void) -+{ -+ return platform_driver_register(&ak_battery_driver); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief exit battery -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-11-2 -+* @param[out] void -+* @param[in] void -+* @return void -+*/ -+static void __exit ak_battery_exit(void) -+{ -+ platform_driver_unregister(&ak_battery_driver); -+} -+ -+module_init(ak_battery_init); -+module_exit(ak_battery_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("gao_wangsheng <gao_wangsheng@anyka.oa>"); -+MODULE_DESCRIPTION("ak battery driver"); -diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c -index 6ad61272..773fca15 100644 ---- a/drivers/power/power_supply_core.c -+++ b/drivers/power/power_supply_core.c -@@ -41,23 +41,40 @@ static int __power_supply_changed_work(struct device *dev, void *data) - - static void power_supply_changed_work(struct work_struct *work) - { -+ unsigned long flags; - struct power_supply *psy = container_of(work, struct power_supply, - changed_work); - - dev_dbg(psy->dev, "%s\n", __func__); - -- class_for_each_device(power_supply_class, NULL, psy, -- __power_supply_changed_work); -+ spin_lock_irqsave(&psy->changed_lock, flags); -+ if (psy->changed) { -+ psy->changed = false; -+ spin_unlock_irqrestore(&psy->changed_lock, flags); - -- power_supply_update_leds(psy); -+ class_for_each_device(power_supply_class, NULL, psy, -+ __power_supply_changed_work); - -- kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); -+ power_supply_update_leds(psy); -+ -+ kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); -+ spin_lock_irqsave(&psy->changed_lock, flags); -+ } -+ if (!psy->changed) -+ pm_relax(psy->dev); -+ spin_unlock_irqrestore(&psy->changed_lock, flags); - } - - void power_supply_changed(struct power_supply *psy) - { -+ unsigned long flags; -+ - dev_dbg(psy->dev, "%s\n", __func__); - -+ spin_lock_irqsave(&psy->changed_lock, flags); -+ psy->changed = true; -+ pm_stay_awake(psy->dev); -+ spin_unlock_irqrestore(&psy->changed_lock, flags); - schedule_work(&psy->changed_work); - } - EXPORT_SYMBOL_GPL(power_supply_changed); -@@ -197,6 +214,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy) - if (rc) - goto device_add_failed; - -+ spin_lock_init(&psy->changed_lock); -+ rc = device_init_wakeup(dev, true); -+ if (rc) -+ goto wakeup_init_failed; -+ - rc = power_supply_create_triggers(psy); - if (rc) - goto create_triggers_failed; -@@ -206,6 +228,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy) - goto success; - - create_triggers_failed: -+wakeup_init_failed: - device_del(dev); - kobject_set_name_failed: - device_add_failed: -diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c -index 4368e7d6..b20acfa9 100644 ---- a/drivers/power/power_supply_sysfs.c -+++ b/drivers/power/power_supply_sysfs.c -@@ -174,6 +174,10 @@ static struct device_attribute power_supply_attrs[] = { - POWER_SUPPLY_ATTR(time_to_full_avg), - POWER_SUPPLY_ATTR(type), - POWER_SUPPLY_ATTR(scope), -+ /* Local extensions */ -+ POWER_SUPPLY_ATTR(usb_hc), -+ POWER_SUPPLY_ATTR(usb_otg), -+ POWER_SUPPLY_ATTR(charge_enabled), - /* Properties of type `const char *' */ - POWER_SUPPLY_ATTR(model_name), - POWER_SUPPLY_ATTR(manufacturer), -diff --git a/drivers/power/smb347-charger.c b/drivers/power/smb347-charger.c -index ce1694d1..fb56ec75 100644 ---- a/drivers/power/smb347-charger.c -+++ b/drivers/power/smb347-charger.c -@@ -22,6 +22,7 @@ - #include <linux/power_supply.h> - #include <linux/power/smb347-charger.h> - #include <linux/seq_file.h> -+#include <linux/delay.h> - - /* - * Configuration registers. These are mirrored to volatile RAM and can be -@@ -38,14 +39,20 @@ - #define CFG_CURRENT_LIMIT_DC_MASK 0xf0 - #define CFG_CURRENT_LIMIT_DC_SHIFT 4 - #define CFG_CURRENT_LIMIT_USB_MASK 0x0f -+#define CFG_VARIOUS_FUNCTION 0x02 -+#define CFG_INPUT_SOURCE_PRIORITY BIT(2) - #define CFG_FLOAT_VOLTAGE 0x03 - #define CFG_FLOAT_VOLTAGE_THRESHOLD_MASK 0xc0 -+#define CFG_FLOAT_VOLTAGE_MASK 0x3F - #define CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT 6 -+#define CFG_CHARGE_CONTROL 0x04 -+#define CFG_AUTOMATIC_RECHARGE_DISABLE BIT(7) - #define CFG_STAT 0x05 - #define CFG_STAT_DISABLED BIT(5) - #define CFG_STAT_ACTIVE_HIGH BIT(7) - #define CFG_PIN 0x06 - #define CFG_PIN_EN_CTRL_MASK 0x60 -+#define CFG_PIN_USB_MODE_CTRL BIT(4) - #define CFG_PIN_EN_CTRL_ACTIVE_HIGH 0x40 - #define CFG_PIN_EN_CTRL_ACTIVE_LOW 0x60 - #define CFG_PIN_EN_APSD_IRQ BIT(1) -@@ -85,8 +92,12 @@ - #define CMD_A 0x30 - #define CMD_A_CHG_ENABLED BIT(1) - #define CMD_A_SUSPEND_ENABLED BIT(2) -+#define CMD_A_OTG_ENABLE BIT(4) - #define CMD_A_ALLOW_WRITE BIT(7) - #define CMD_B 0x31 -+#define CMD_B_POR BIT(7) -+#define CMD_B_USB59_MODE BIT(1) -+#define CMD_B_HC_MODE BIT(0) - #define CMD_C 0x33 - - /* Interrupt Status registers */ -@@ -108,6 +119,7 @@ - #define STAT_B 0x3c - #define STAT_C 0x3d - #define STAT_C_CHG_ENABLED BIT(0) -+#define STAT_C_CHG_STATUS BIT(5) - #define STAT_C_CHG_MASK 0x06 - #define STAT_C_CHG_SHIFT 1 - #define STAT_C_CHARGER_ERROR BIT(6) -@@ -135,6 +147,11 @@ struct smb347_charger { - bool mains_online; - bool usb_online; - bool charging_enabled; -+ unsigned int mains_current_limit; -+ bool usb_hc_mode; -+ bool usb_otg_enabled; -+ bool is_fully_charged; -+ int en_gpio; - struct dentry *dentry; - const struct smb347_charger_platform_data *pdata; - }; -@@ -315,9 +332,17 @@ static int smb347_charging_set(struct smb347_charger *smb, bool enable) - { - int ret = 0; - -+ if (enable && !smb->charging_enabled) -+ smb->is_fully_charged = false; -+ - if (smb->pdata->enable_control != SMB347_CHG_ENABLE_SW) { -- dev_dbg(&smb->client->dev, -- "charging enable/disable in SW disabled\n"); -+ smb->charging_enabled = enable; -+ -+ if (smb->en_gpio) -+ gpio_set_value( -+ smb->en_gpio, -+ (smb->pdata->enable_control == -+ SMB347_CHG_ENABLE_PIN_ACTIVE_LOW) ^ enable); - return 0; - } - -@@ -424,9 +449,9 @@ static int smb347_set_current_limits(struct smb347_charger *smb) - if (ret < 0) - return ret; - -- if (smb->pdata->mains_current_limit) { -+ if (smb->mains_current_limit) { - val = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), -- smb->pdata->mains_current_limit); -+ smb->mains_current_limit); - if (val < 0) - return val; - -@@ -473,6 +498,7 @@ static int smb347_set_voltage_limits(struct smb347_charger *smb) - val = clamp_val(val, 3500000, 4500000) - 3500000; - val /= 20000; - -+ ret &= ~CFG_FLOAT_VOLTAGE_MASK; - ret |= val; - } - -@@ -662,6 +688,168 @@ static int smb347_set_writable(struct smb347_charger *smb, bool writable) - return smb347_write(smb, CMD_A, ret); - } - -+static int smb347_irq_set(struct smb347_charger *smb, bool enable) -+{ -+ int ret; -+ -+ ret = smb347_set_writable(smb, true); -+ if (ret < 0) -+ return ret; -+ -+ /* -+ * Enable/disable interrupts for: -+ * - under voltage -+ * - termination current reached -+ * - charger error -+ */ -+ if (enable) { -+ ret = smb347_write(smb, CFG_FAULT_IRQ, CFG_FAULT_IRQ_DCIN_UV); -+ if (ret < 0) -+ goto fail; -+ -+ ret = smb347_write(smb, CFG_STATUS_IRQ, -+ CFG_STATUS_IRQ_TERMINATION_OR_TAPER); -+ if (ret < 0) -+ goto fail; -+ -+ ret = smb347_read(smb, CFG_PIN); -+ if (ret < 0) -+ goto fail; -+ -+ ret |= CFG_PIN_EN_CHARGER_ERROR; -+ -+ ret = smb347_write(smb, CFG_PIN, ret); -+ } else { -+ ret = smb347_write(smb, CFG_FAULT_IRQ, 0); -+ if (ret < 0) -+ goto fail; -+ -+ ret = smb347_write(smb, CFG_STATUS_IRQ, 0); -+ if (ret < 0) -+ goto fail; -+ -+ ret = smb347_read(smb, CFG_PIN); -+ if (ret < 0) -+ goto fail; -+ -+ ret &= ~CFG_PIN_EN_CHARGER_ERROR; -+ -+ ret = smb347_write(smb, CFG_PIN, ret); -+ } -+ -+fail: -+ smb347_set_writable(smb, false); -+ return ret; -+} -+ -+static inline int smb347_irq_enable(struct smb347_charger *smb) -+{ -+ return smb347_irq_set(smb, true); -+} -+ -+static inline int smb347_irq_disable(struct smb347_charger *smb) -+{ -+ return smb347_irq_set(smb, false); -+} -+ -+static irqreturn_t smb347_interrupt(int irq, void *data) -+{ -+ struct smb347_charger *smb = data; -+ int stat_c, t; -+ u8 irqstat[6]; -+ irqreturn_t ret = IRQ_NONE; -+ -+ t = i2c_smbus_read_i2c_block_data(smb->client, IRQSTAT_A, 6, irqstat); -+ if (t < 0) { -+ dev_warn(&smb->client->dev, -+ "reading IRQSTAT registers failed\n"); -+ return IRQ_NONE; -+ } -+ -+ stat_c = smb347_read(smb, STAT_C); -+ if (stat_c < 0) { -+ dev_warn(&smb->client->dev, "reading STAT_C failed\n"); -+ return IRQ_NONE; -+ } -+ -+ pr_debug("%s: stat c=%x irq a=%x b=%x c=%x d=%x e=%x f=%x\n", -+ __func__, stat_c, irqstat[0], irqstat[1], irqstat[2], -+ irqstat[3], irqstat[4], irqstat[5]); -+ -+ /* -+ * If we get charger error we report the error back to user and -+ * disable charging. -+ */ -+ if (stat_c & STAT_C_CHARGER_ERROR) { -+ dev_err(&smb->client->dev, -+ "error in charger, disabling charging\n"); -+ -+ smb347_charging_disable(smb); -+ power_supply_changed(&smb->battery); -+ -+ ret = IRQ_HANDLED; -+ } else if (((stat_c & STAT_C_CHG_STATUS) || -+ (irqstat[2] & (IRQSTAT_C_TERMINATION_IRQ | -+ IRQSTAT_C_TERMINATION_STAT))) && -+ !smb->is_fully_charged) { -+ dev_info(&smb->client->dev, "charge terminated\n"); -+ smb->is_fully_charged = true; -+ smb347_charging_disable(smb); -+ power_supply_changed(&smb->battery); -+ ret = IRQ_HANDLED; -+ } -+ -+ if (irqstat[2] & IRQSTAT_C_TAPER_IRQ) -+ ret = IRQ_HANDLED; -+ -+ /* -+ * If we got an under voltage interrupt it means that AC/USB input -+ * was disconnected. -+ */ -+ if (irqstat[4] & (IRQSTAT_E_USBIN_UV_IRQ | IRQSTAT_E_DCIN_UV_IRQ)) -+ ret = IRQ_HANDLED; -+ -+ if (smb347_update_status(smb) > 0) { -+ smb347_update_online(smb); -+ power_supply_changed(&smb->mains); -+ power_supply_changed(&smb->usb); -+ ret = IRQ_HANDLED; -+ } -+ -+ return ret; -+} -+ -+static int smb347_irq_init(struct smb347_charger *smb) -+{ -+ const struct smb347_charger_platform_data *pdata = smb->pdata; -+ int ret, irq = gpio_to_irq(pdata->irq_gpio); -+ -+ ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, smb->client->name); -+ if (ret < 0) -+ goto fail; -+ -+ ret = request_threaded_irq(irq, NULL, smb347_interrupt, -+ pdata->disable_stat_interrupts ? -+ IRQF_TRIGGER_RISING | IRQF_ONESHOT : -+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT, -+ smb->client->name, smb); -+ if (ret < 0) -+ goto fail_gpio; -+ -+ ret = enable_irq_wake(irq); -+ if (ret) -+ pr_err("%s: failed to enable wake on irq %d\n", __func__, irq); -+ -+ smb->client->irq = irq; -+ return 0; -+ -+fail_gpio: -+ gpio_free(pdata->irq_gpio); -+fail: -+ smb->client->irq = 0; -+ return ret; -+} -+ - static int smb347_hw_init(struct smb347_charger *smb) - { - int ret; -@@ -686,9 +874,12 @@ static int smb347_hw_init(struct smb347_charger *smb) - if (ret < 0) - goto fail; - -+// HACK for Manta pre-alpha 0.2, TH_BATTERY not connected properly -+#if 0 // HACK - ret = smb347_set_temp_limits(smb); - if (ret < 0) - goto fail; -+#endif // HACK - - /* If USB charging is disabled we put the USB in suspend mode */ - if (!smb->pdata->use_usb) { -@@ -719,6 +910,19 @@ static int smb347_hw_init(struct smb347_charger *smb) - if (ret < 0) - goto fail; - -+ /* If configured by platform data, disable AUTOMATIC RECHARGE */ -+ if (smb->pdata->disable_automatic_recharge) { -+ ret = smb347_read(smb, CFG_CHARGE_CONTROL); -+ if (ret < 0) -+ goto fail; -+ -+ ret |= CFG_AUTOMATIC_RECHARGE_DISABLE; -+ -+ ret = smb347_write(smb, CFG_CHARGE_CONTROL, ret); -+ if (ret < 0) -+ goto fail; -+ } -+ - ret = smb347_read(smb, CFG_PIN); - if (ret < 0) - goto fail; -@@ -728,7 +932,7 @@ static int smb347_hw_init(struct smb347_charger *smb) - * command register unless pin control is specified in the platform - * data. - */ -- ret &= ~CFG_PIN_EN_CTRL_MASK; -+ ret &= ~(CFG_PIN_EN_CTRL_MASK | CFG_PIN_USB_MODE_CTRL); - - switch (smb->pdata->enable_control) { - case SMB347_CHG_ENABLE_SW: -@@ -742,6 +946,9 @@ static int smb347_hw_init(struct smb347_charger *smb) - break; - } - -+ if (smb->pdata->usb_mode_pin_ctrl) -+ ret |= CFG_PIN_USB_MODE_CTRL; -+ - /* Disable Automatic Power Source Detection (APSD) interrupt. */ - ret &= ~CFG_PIN_EN_APSD_IRQ; - -@@ -755,123 +962,27 @@ static int smb347_hw_init(struct smb347_charger *smb) - - ret = smb347_update_online(smb); - --fail: -- smb347_set_writable(smb, false); -- return ret; --} -- --static irqreturn_t smb347_interrupt(int irq, void *data) --{ -- struct smb347_charger *smb = data; -- int stat_c, irqstat_e, irqstat_c; -- irqreturn_t ret = IRQ_NONE; -- -- stat_c = smb347_read(smb, STAT_C); -- if (stat_c < 0) { -- dev_warn(&smb->client->dev, "reading STAT_C failed\n"); -- return IRQ_NONE; -- } -- -- irqstat_c = smb347_read(smb, IRQSTAT_C); -- if (irqstat_c < 0) { -- dev_warn(&smb->client->dev, "reading IRQSTAT_C failed\n"); -- return IRQ_NONE; -- } -- -- irqstat_e = smb347_read(smb, IRQSTAT_E); -- if (irqstat_e < 0) { -- dev_warn(&smb->client->dev, "reading IRQSTAT_E failed\n"); -- return IRQ_NONE; -- } -- -- /* -- * If we get charger error we report the error back to user and -- * disable charging. -- */ -- if (stat_c & STAT_C_CHARGER_ERROR) { -- dev_err(&smb->client->dev, -- "error in charger, disabling charging\n"); -- -- smb347_charging_disable(smb); -- power_supply_changed(&smb->battery); -- -- ret = IRQ_HANDLED; -- } -- -- /* -- * If we reached the termination current the battery is charged and -- * we can update the status now. Charging is automatically -- * disabled by the hardware. -- */ -- if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) { -- if (irqstat_c & IRQSTAT_C_TERMINATION_STAT) -- power_supply_changed(&smb->battery); -- ret = IRQ_HANDLED; -- } -- -- /* -- * If we got an under voltage interrupt it means that AC/USB input -- * was connected or disconnected. -- */ -- if (irqstat_e & (IRQSTAT_E_USBIN_UV_IRQ | IRQSTAT_E_DCIN_UV_IRQ)) { -- if (smb347_update_status(smb) > 0) { -- smb347_update_online(smb); -- power_supply_changed(&smb->mains); -- power_supply_changed(&smb->usb); -- } -- ret = IRQ_HANDLED; -- } -- -- return ret; --} -- --static int smb347_irq_set(struct smb347_charger *smb, bool enable) --{ -- int ret; -- -- ret = smb347_set_writable(smb, true); -- if (ret < 0) -- return ret; -- -- /* -- * Enable/disable interrupts for: -- * - under voltage -- * - termination current reached -- * - charger error -- */ -- if (enable) { -- ret = smb347_write(smb, CFG_FAULT_IRQ, CFG_FAULT_IRQ_DCIN_UV); -- if (ret < 0) -- goto fail; -- -- ret = smb347_write(smb, CFG_STATUS_IRQ, -- CFG_STATUS_IRQ_TERMINATION_OR_TAPER); -- if (ret < 0) -- goto fail; -- -- ret = smb347_read(smb, CFG_PIN); -+ if ((smb->pdata->irq_gpio >= 0) && -+ !smb->pdata->disable_stat_interrupts) { -+ /* -+ * Configure the STAT output to be suitable for interrupts: -+ * disable all other output (except interrupts) and make it -+ * active low. -+ */ -+ ret = smb347_read(smb, CFG_STAT); - if (ret < 0) - goto fail; - -- ret |= CFG_PIN_EN_CHARGER_ERROR; -+ ret &= ~CFG_STAT_ACTIVE_HIGH; -+ ret |= CFG_STAT_DISABLED; - -- ret = smb347_write(smb, CFG_PIN, ret); -- } else { -- ret = smb347_write(smb, CFG_FAULT_IRQ, 0); -+ ret = smb347_write(smb, CFG_STAT, ret); - if (ret < 0) - goto fail; - -- ret = smb347_write(smb, CFG_STATUS_IRQ, 0); -- if (ret < 0) -- goto fail; -- -- ret = smb347_read(smb, CFG_PIN); -+ ret = smb347_irq_enable(smb); - if (ret < 0) - goto fail; -- -- ret &= ~CFG_PIN_EN_CHARGER_ERROR; -- -- ret = smb347_write(smb, CFG_PIN, ret); - } - - fail: -@@ -879,85 +990,90 @@ fail: - return ret; - } - --static inline int smb347_irq_enable(struct smb347_charger *smb) -+static int smb347_mains_get_property(struct power_supply *psy, -+ enum power_supply_property prop, -+ union power_supply_propval *val) - { -- return smb347_irq_set(smb, true); --} -+ struct smb347_charger *smb = -+ container_of(psy, struct smb347_charger, mains); - --static inline int smb347_irq_disable(struct smb347_charger *smb) --{ -- return smb347_irq_set(smb, false); -+ switch (prop) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = smb->mains_online; -+ return 0; -+ -+ case POWER_SUPPLY_PROP_CURRENT_MAX: -+ val->intval = smb->mains_current_limit; -+ return 0; -+ -+ default: -+ return -EINVAL; -+ } -+ return -EINVAL; - } - --static int smb347_irq_init(struct smb347_charger *smb) -+static int smb347_mains_set_property(struct power_supply *psy, -+ enum power_supply_property prop, -+ const union power_supply_propval *val) - { -- const struct smb347_charger_platform_data *pdata = smb->pdata; -- int ret, irq = gpio_to_irq(pdata->irq_gpio); -+ struct smb347_charger *smb = -+ container_of(psy, struct smb347_charger, mains); -+ int ret; -+ bool oldval; - -- ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, smb->client->name); -- if (ret < 0) -- goto fail; -+ switch (prop) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ oldval = smb->mains_online; - -- ret = request_threaded_irq(irq, NULL, smb347_interrupt, -- IRQF_TRIGGER_FALLING, smb->client->name, -- smb); -- if (ret < 0) -- goto fail_gpio; -+ smb->mains_online = val->intval; - -- ret = smb347_set_writable(smb, true); -- if (ret < 0) -- goto fail_irq; -+ smb347_set_writable(smb, true); - -- /* -- * Configure the STAT output to be suitable for interrupts: disable -- * all other output (except interrupts) and make it active low. -- */ -- ret = smb347_read(smb, CFG_STAT); -- if (ret < 0) -- goto fail_readonly; -+ ret = smb347_read(smb, CMD_A); -+ if (ret < 0) -+ return -EINVAL; - -- ret &= ~CFG_STAT_ACTIVE_HIGH; -- ret |= CFG_STAT_DISABLED; -+ ret &= ~CMD_A_SUSPEND_ENABLED; -+ if (val->intval) -+ ret |= CMD_A_SUSPEND_ENABLED; - -- ret = smb347_write(smb, CFG_STAT, ret); -- if (ret < 0) -- goto fail_readonly; -+ ret = smb347_write(smb, CMD_A, ret); - -- ret = smb347_irq_enable(smb); -- if (ret < 0) -- goto fail_readonly; -+ smb347_hw_init(smb); - -- smb347_set_writable(smb, false); -- smb->client->irq = irq; -- return 0; -+ smb347_set_writable(smb, false); - --fail_readonly: -- smb347_set_writable(smb, false); --fail_irq: -- free_irq(irq, smb); --fail_gpio: -- gpio_free(pdata->irq_gpio); --fail: -- smb->client->irq = 0; -- return ret; -+ if (smb->mains_online != oldval) -+ power_supply_changed(psy); -+ return 0; -+ case POWER_SUPPLY_PROP_CURRENT_MAX: -+ smb->mains_current_limit = val->intval; -+ smb347_hw_init(smb); -+ return 0; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return -EINVAL; - } - --static int smb347_mains_get_property(struct power_supply *psy, -- enum power_supply_property prop, -- union power_supply_propval *val) -+static int smb347_mains_property_is_writeable(struct power_supply *psy, -+ enum power_supply_property prop) - { -- struct smb347_charger *smb = -- container_of(psy, struct smb347_charger, mains); -- -- if (prop == POWER_SUPPLY_PROP_ONLINE) { -- val->intval = smb->mains_online; -- return 0; -+ switch (prop) { -+ case POWER_SUPPLY_PROP_CURRENT_MAX: -+ return 1; -+ default: -+ break; - } -- return -EINVAL; -+ -+ return 0; - } - - static enum power_supply_property smb347_mains_properties[] = { - POWER_SUPPLY_PROP_ONLINE, -+ POWER_SUPPLY_PROP_CURRENT_MAX, - }; - - static int smb347_usb_get_property(struct power_supply *psy, -@@ -967,15 +1083,94 @@ static int smb347_usb_get_property(struct power_supply *psy, - struct smb347_charger *smb = - container_of(psy, struct smb347_charger, usb); - -- if (prop == POWER_SUPPLY_PROP_ONLINE) { -+ switch (prop) { -+ case POWER_SUPPLY_PROP_ONLINE: - val->intval = smb->usb_online; - return 0; -+ -+ case POWER_SUPPLY_PROP_USB_HC: -+ val->intval = smb->usb_hc_mode; -+ return 0; -+ -+ case POWER_SUPPLY_PROP_USB_OTG: -+ val->intval = smb->usb_otg_enabled; -+ return 0; -+ -+ default: -+ break; - } - return -EINVAL; - } - -+static int smb347_usb_set_property(struct power_supply *psy, -+ enum power_supply_property prop, -+ const union power_supply_propval *val) -+{ -+ int ret = -EINVAL; -+ struct smb347_charger *smb = -+ container_of(psy, struct smb347_charger, usb); -+ bool oldval; -+ -+ switch (prop) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ oldval = smb->usb_online; -+ smb->usb_online = val->intval; -+ -+ if (smb->usb_online != oldval) -+ power_supply_changed(psy); -+ ret = 0; -+ break; -+ case POWER_SUPPLY_PROP_USB_HC: -+ smb347_set_writable(smb, true); -+ ret = smb347_write(smb, CMD_B, val->intval ? -+ CMD_B_HC_MODE : CMD_B_USB59_MODE); -+ smb347_set_writable(smb, false); -+ smb->usb_hc_mode = val->intval; -+ break; -+ -+ case POWER_SUPPLY_PROP_USB_OTG: -+ ret = smb347_read(smb, CMD_A); -+ -+ if (ret < 0) -+ return ret; -+ -+ if (val->intval) -+ ret |= CMD_A_OTG_ENABLE; -+ else -+ ret &= ~CMD_A_OTG_ENABLE; -+ -+ ret = smb347_write(smb, CMD_A, ret); -+ -+ if (ret >= 0) -+ smb->usb_otg_enabled = val->intval; -+ -+ break; -+ -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+static int smb347_usb_property_is_writeable(struct power_supply *psy, -+ enum power_supply_property prop) -+{ -+ switch (prop) { -+ case POWER_SUPPLY_PROP_USB_HC: -+ case POWER_SUPPLY_PROP_USB_OTG: -+ return 1; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ - static enum power_supply_property smb347_usb_properties[] = { - POWER_SUPPLY_PROP_ONLINE, -+ POWER_SUPPLY_PROP_USB_HC, -+ POWER_SUPPLY_PROP_USB_OTG, - }; - - static int smb347_battery_get_property(struct power_supply *psy, -@@ -991,16 +1186,25 @@ static int smb347_battery_get_property(struct power_supply *psy, - if (ret < 0) - return ret; - -+ if (ret > 0) { -+ smb347_update_online(smb); -+ power_supply_changed(&smb->mains); -+ power_supply_changed(&smb->usb); -+ } -+ - switch (prop) { - case POWER_SUPPLY_PROP_STATUS: - if (!smb347_is_online(smb)) { -+ smb->is_fully_charged = false; - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - break; - } - if (smb347_charging_status(smb)) - val->intval = POWER_SUPPLY_STATUS_CHARGING; - else -- val->intval = POWER_SUPPLY_STATUS_FULL; -+ val->intval = smb->is_fully_charged ? -+ POWER_SUPPLY_STATUS_FULL : -+ POWER_SUPPLY_STATUS_NOT_CHARGING; - break; - - case POWER_SUPPLY_PROP_CHARGE_TYPE: -@@ -1078,6 +1282,10 @@ static int smb347_battery_get_property(struct power_supply *psy, - val->intval = pdata->battery_info.charge_full_design; - break; - -+ case POWER_SUPPLY_PROP_CHARGE_ENABLED: -+ val->intval = smb->charging_enabled; -+ break; -+ - case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = pdata->battery_info.name; - break; -@@ -1089,6 +1297,39 @@ static int smb347_battery_get_property(struct power_supply *psy, - return 0; - } - -+static int smb347_battery_set_property(struct power_supply *psy, -+ enum power_supply_property prop, -+ const union power_supply_propval *val) -+{ -+ int ret = -EINVAL; -+ struct smb347_charger *smb = -+ container_of(psy, struct smb347_charger, battery); -+ -+ switch (prop) { -+ case POWER_SUPPLY_PROP_CHARGE_ENABLED: -+ ret = smb347_charging_set(smb, val->intval); -+ break; -+ -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+static int smb347_battery_property_is_writeable(struct power_supply *psy, -+ enum power_supply_property prop) -+{ -+ switch (prop) { -+ case POWER_SUPPLY_PROP_CHARGE_ENABLED: -+ return 1; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ - static enum power_supply_property smb347_battery_properties[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_CHARGE_TYPE, -@@ -1098,6 +1339,7 @@ static enum power_supply_property smb347_battery_properties[] = { - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_ENABLED, - POWER_SUPPLY_PROP_MODEL_NAME, - }; - -@@ -1181,6 +1423,33 @@ static int smb347_probe(struct i2c_client *client, - smb->client = client; - smb->pdata = pdata; - -+ smb->mains_current_limit = smb->pdata->mains_current_limit; -+ -+ if (pdata->en_gpio) { -+ ret = gpio_request_one( -+ pdata->en_gpio, -+ smb->pdata->enable_control == -+ SMB347_CHG_ENABLE_PIN_ACTIVE_LOW ? -+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, -+ smb->client->name); -+ if (ret < 0) -+ dev_warn(dev, "failed to claim EN GPIO: %d\n", ret); -+ else -+ smb->en_gpio = pdata->en_gpio; -+ } -+ -+ ret = smb347_write(smb, CMD_B, CMD_B_POR); -+ if (ret < 0) -+ return ret; -+ -+ msleep(20); -+ -+ ret = smb347_read(smb, CMD_B); -+ if (ret < 0) { -+ dev_err(dev, "failed read after reset\n"); -+ return ret; -+ } -+ - ret = smb347_hw_init(smb); - if (ret < 0) - return ret; -@@ -1188,6 +1457,8 @@ static int smb347_probe(struct i2c_client *client, - smb->mains.name = "smb347-mains"; - smb->mains.type = POWER_SUPPLY_TYPE_MAINS; - smb->mains.get_property = smb347_mains_get_property; -+ smb->mains.set_property = smb347_mains_set_property; -+ smb->mains.property_is_writeable = smb347_mains_property_is_writeable; - smb->mains.properties = smb347_mains_properties; - smb->mains.num_properties = ARRAY_SIZE(smb347_mains_properties); - smb->mains.supplied_to = battery; -@@ -1196,6 +1467,8 @@ static int smb347_probe(struct i2c_client *client, - smb->usb.name = "smb347-usb"; - smb->usb.type = POWER_SUPPLY_TYPE_USB; - smb->usb.get_property = smb347_usb_get_property; -+ smb->usb.set_property = smb347_usb_set_property; -+ smb->usb.property_is_writeable = smb347_usb_property_is_writeable; - smb->usb.properties = smb347_usb_properties; - smb->usb.num_properties = ARRAY_SIZE(smb347_usb_properties); - smb->usb.supplied_to = battery; -@@ -1204,9 +1477,17 @@ static int smb347_probe(struct i2c_client *client, - smb->battery.name = "smb347-battery"; - smb->battery.type = POWER_SUPPLY_TYPE_BATTERY; - smb->battery.get_property = smb347_battery_get_property; -+ smb->battery.set_property = smb347_battery_set_property; -+ smb->battery.property_is_writeable = smb347_battery_property_is_writeable; - smb->battery.properties = smb347_battery_properties; - smb->battery.num_properties = ARRAY_SIZE(smb347_battery_properties); - -+ if (smb->pdata->supplied_to) { -+ smb->battery.supplied_to = smb->pdata->supplied_to; -+ smb->battery.num_supplicants = smb->pdata->num_supplicants; -+ smb->battery.external_power_changed = power_supply_changed; -+ } -+ - ret = power_supply_register(dev, &smb->mains); - if (ret < 0) - return ret; -@@ -1250,6 +1531,7 @@ static int smb347_remove(struct i2c_client *client) - - if (client->irq) { - smb347_irq_disable(smb); -+ disable_irq_wake(client->irq); - free_irq(client->irq, smb); - gpio_free(smb->pdata->irq_gpio); - } -@@ -1260,6 +1542,29 @@ static int smb347_remove(struct i2c_client *client) - return 0; - } - -+static int smb347_suspend(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ -+ if (client->irq) -+ disable_irq(client->irq); -+ return 0; -+} -+ -+static int smb347_resume(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ -+ if (client->irq) -+ enable_irq(client->irq); -+ return 0; -+} -+ -+static const struct dev_pm_ops smb347_pm_ops = { -+ .suspend = smb347_suspend, -+ .resume = smb347_resume, -+}; -+ - static const struct i2c_device_id smb347_id[] = { - { "smb347", 0 }, - { } -@@ -1269,6 +1574,7 @@ MODULE_DEVICE_TABLE(i2c, smb347_id); - static struct i2c_driver smb347_driver = { - .driver = { - .name = "smb347", -+ .pm = &smb347_pm_ops, - }, - .probe = smb347_probe, - .remove = __devexit_p(smb347_remove), -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 8c8377d5..cef7eeba 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -1087,4 +1087,10 @@ config RTC_DRV_LOONGSON1 - This driver can also be built as a module. If so, the module - will be called rtc-ls1x. - -+config RTC_DRV_AK -+ tristate "AK RTC" -+ depends on ARCH_AK39 -+ help -+ If you say Y here you will get support for the onboard AK RTC. -+ - endif # RTC_CLASS -diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 727ae778..aaa613a2 100644 ---- a/drivers/rtc/Makefile -+++ b/drivers/rtc/Makefile -@@ -111,3 +111,4 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o - obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o - obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o - obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o -+obj-$(CONFIG_RTC_DRV_AK) += plat-anyka/ -diff --git a/drivers/rtc/plat-anyka/Makefile b/drivers/rtc/plat-anyka/Makefile -new file mode 100644 -index 00000000..b18e7080 ---- /dev/null -+++ b/drivers/rtc/plat-anyka/Makefile -@@ -0,0 +1,5 @@ -+# -+# Makefile for RTC class/drivers. -+# -+ -+obj-$(CONFIG_RTC_DRV_AK) += rtc.o -diff --git a/drivers/rtc/plat-anyka/rtc.c b/drivers/rtc/plat-anyka/rtc.c -new file mode 100755 -index 00000000..976f791f ---- /dev/null -+++ b/drivers/rtc/plat-anyka/rtc.c -@@ -0,0 +1,655 @@ -+/** -+* @file drivers/rtc/rtc-ak.c -+* @brief -+* Copyright C 2011 Anyka CO.,LTD -+ -+* This program is free software; you can redistribute it and/or modify -+* it under the terms of the GNU General Public License version 2 as -+* published by the Free Software Foundation. -+* @author zhou wenyong -+* @date 2011-08-29 -+* @note -+* -+*/ -+/* -+ * drivers/rtc/rtc-ak.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * 2011-3-22 for AK zwy -+ */ -+ -+#include <linux/module.h> -+#include <linux/fs.h> -+#include <linux/string.h> -+#include <linux/init.h> -+#include <linux/platform_device.h> -+#include <linux/interrupt.h> -+#include <linux/rtc.h> -+#include <linux/bcd.h> -+#include <linux/clk.h> -+#include <linux/log2.h> -+#include <linux/delay.h> -+ -+#include <asm/uaccess.h> -+#include <asm/io.h> -+ -+#include <asm/mach/time.h> -+ -+#include <mach/hardware.h> -+#include <plat/rtc.h> -+ -+ -+ -+//#define RTC_DEBUG -+#define REG32(_reg_) (*(volatile unsigned long *)(_reg_)) -+ -+ -+#undef PDEBUG /* undef it, just in case */ -+#ifdef RTC_DEBUG -+#ifdef __KERNEL__ -+/* This one if debugging is on, and kernel space */ -+#define PDEBUG(fmt, args...) printk( KERN_INFO fmt,## args) -+#else -+/* This one for user space */ -+#define PDEBUG(fmt, args...) fprintf(stderr, "%s %d: "fmt,__FILE__, __LINE__, ## args) -+#endif -+#else -+#define PDEBUG(fmt, args...) /* not debugging: nothing */ -+#endif -+ -+ -+static int ak_rtc_wakeup_enable(int en); -+static void ak_rtc_alarm_enable(void ); -+static void ak_rtc_alarm_disable(void ); -+ -+ -+/** -+* @brief ak_rtc_int_clear -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] void -+* @return void -+*/ -+static inline void ak_rtc_int_clear(void) -+{ -+ unsigned int regval; -+ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ regval = ak_rtc_read(AK_RTC_SETTING); -+ regval |= (1<<0); -+ -+ ak_rtc_write(AK_RTC_SETTING, regval); -+ -+} -+ -+ -+/** -+* @brief ak_rtc_wakeup_enable -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] en -+* @return int -+*/ -+static int ak_rtc_wakeup_enable(int en) -+{ -+ unsigned int val; -+ -+ PDEBUG("%s(): Entering...\n", __func__); -+ PDEBUG("%s: %s\n", __FUNCTION__, en ? "enable" : "disable"); -+ -+ /* read rtc wakeup setting and clear status */ -+ val = REG32(OTHER_WAKEUP_CTRL); -+ val &= ~RTC_WAKEUP_EN; -+ REG32(OTHER_WAKEUP_CTRL) = val; -+ -+ -+ if (en) -+ { -+ /* enable wakeup signal */ -+ val |= RTC_WAKEUP_EN ;//| RTC_WAKEUP_SIGNAL_LOWACTIVE); -+ REG32(OTHER_WAKEUP_CTRL) = val; -+ } -+ else -+ { -+ /* disable wakeup signal */ -+ /* val |= RTC_WAKEUP_SIGNAL_CLEAR; */ -+ /* ak_rtc_write(AK_WDT_TIMER1, val); */ -+ } -+ return 0; -+ -+} -+ -+ -+/** -+* @brief ak_rtc_gettime -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @param[out] *tm -+* @return int -+*/ -+static int ak_rtc_gettime(struct device *dev, struct rtc_time *tm) -+{ -+ unsigned long rtcset; -+ unsigned long rtc_time1; -+ unsigned long rtc_time2; -+ unsigned long rtc_time3; -+ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ rtcset = ak_rtc_read(AK_RTC_SETTING); -+ rtcset |= RTC_SETTING_REAL_TIME_RE; -+ ak_rtc_write(AK_RTC_SETTING, rtcset); -+ -+ rtc_time1 = ak_rtc_read(AK_RTC_REAL_TIME1); -+ rtc_time2 = ak_rtc_read(AK_RTC_REAL_TIME2); -+ rtc_time3 = ak_rtc_read(AK_RTC_REAL_TIME3); -+ -+ tm->tm_year = ((rtc_time3 >> 4) & 0x7F) - EPOCH_START_YEAR + RTC_START_YEAR; -+ tm->tm_mon = (rtc_time3 & 0xF) - 1; -+ tm->tm_mday = (rtc_time2 >> 5) & 0x1F; -+ tm->tm_hour = rtc_time2 & 0x1F; -+ tm->tm_min = (rtc_time1 >> 6) & 0x3F; -+ tm->tm_sec = rtc_time1 & 0x3F; -+ tm->tm_wday = (rtc_time2 >> 10) & 0x7; -+ tm->tm_isdst = -1; -+ if ((tm->tm_year < (RTC_START_YEAR - EPOCH_START_YEAR)) -+ || (tm->tm_year > (RTC_START_YEAR - EPOCH_START_YEAR + RTC_YEAR_COUNT))) { -+ printk("%s(): -----RTC Year must between (%d ~ %d), now tm->tm_year:%d--------------\n", -+ __func__, RTC_START_YEAR, (RTC_START_YEAR + RTC_YEAR_COUNT), tm->tm_year); -+ -+ tm->tm_year = 2011 - EPOCH_START_YEAR ; -+ tm->tm_mon = 0; -+ tm->tm_mday = 1; -+ tm->tm_hour = 0; -+ tm->tm_min = 0; -+ tm->tm_sec = 0; -+ tm->tm_wday = 6; -+ -+ } -+#if 0 -+ printk("Current RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", -+ tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday, -+ tm->tm_hour, tm->tm_min, tm->tm_sec); -+#endif -+ return 0; -+} -+ -+ -+/** -+* @brief ak_rtc_settime -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @param[out] *tm -+* @return int -+*/ -+static int ak_rtc_settime(struct device *dev, struct rtc_time *tm) -+{ -+ unsigned long regval; -+ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ printk("%s: %d-%d-%d %d:%d:%d\n", __func__, tm->tm_year, tm->tm_mon + 1, -+ tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); -+ if ((tm->tm_year < (RTC_START_YEAR - EPOCH_START_YEAR)) -+ || (tm->tm_year > (RTC_START_YEAR - EPOCH_START_YEAR + RTC_YEAR_COUNT))) { -+ printk("%s(): RTC Year must between (%d ~ %d)\n", -+ __func__, RTC_START_YEAR, (RTC_START_YEAR + RTC_YEAR_COUNT)); -+ return -1; -+ } -+ -+ ak_rtc_write(AK_RTC_REAL_TIME1, (tm->tm_min << 6) | tm->tm_sec); -+ ak_rtc_write(AK_RTC_REAL_TIME2, (tm->tm_wday << 10) | (tm->tm_mday << 5) | tm->tm_hour); -+ ak_rtc_write(AK_RTC_REAL_TIME3, ((tm->tm_year + EPOCH_START_YEAR - RTC_START_YEAR) << 4) | (tm->tm_mon + 1)); -+ -+ regval = ak_rtc_read(AK_RTC_SETTING); -+ regval |= RTC_SETTING_REAL_TIME_WR; -+ ak_rtc_write(AK_RTC_SETTING, regval); -+ -+ while (ak_rtc_read(AK_RTC_SETTING) & RTC_SETTING_REAL_TIME_WR) -+ ; -+ -+ udelay(40); -+ -+ return 0; -+} -+ -+/** -+* @brief ak_rtc_getalarm -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @param[out] *wkalrm -+* @return int -+*/ -+static int ak_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm) -+{ -+ unsigned long rtc_alarm1; -+ unsigned long rtc_alarm2; -+ unsigned long rtc_alarm3; -+ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ -+ rtc_alarm1 = ak_rtc_read(AK_RTC_ALARM_TIME1); -+ rtc_alarm2 = ak_rtc_read(AK_RTC_ALARM_TIME2); -+ rtc_alarm3 = ak_rtc_read(AK_RTC_ALARM_TIME3); -+ -+ PDEBUG("%x %x %x\n", rtc_alarm1, rtc_alarm2, rtc_alarm3); -+ -+ wkalrm->time.tm_sec = rtc_alarm1 & 0x3F; -+ wkalrm->time.tm_min = (rtc_alarm1 >> 6) & 0x3F; -+ wkalrm->time.tm_hour = rtc_alarm2 & 0x1F; -+ wkalrm->time.tm_mday = (rtc_alarm2 >> 5) & 0x1F; -+ wkalrm->time.tm_mon = (rtc_alarm3 & 0xF) - 1; -+ wkalrm->time.tm_year = ((rtc_alarm3 >> 4) & 0x7F) - EPOCH_START_YEAR + RTC_START_YEAR; -+ wkalrm->time.tm_isdst = -1; -+ -+ PDEBUG("%d-%d-%d %d:%d:%d",wkalrm->time.tm_year,wkalrm->time.tm_mon + 1,wkalrm->time.tm_mday, -+ wkalrm->time.tm_hour,wkalrm->time.tm_min ,wkalrm->time.tm_sec); -+ return 0; -+} -+ -+ -+/** -+* @brief ak_rtc_setalarm -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @param[out] *wkalrm -+* @return int -+*/ -+static int ak_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) -+{ -+ unsigned long rtc_alarm1; -+ unsigned long rtc_alarm2; -+ unsigned long rtc_alarm3; -+ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ rtc_alarm1 = ak_rtc_read(AK_RTC_ALARM_TIME1); -+ rtc_alarm2 = ak_rtc_read(AK_RTC_ALARM_TIME2); -+ rtc_alarm3 = ak_rtc_read(AK_RTC_ALARM_TIME3); -+ -+ PDEBUG("%u %u %u\n", rtc_alarm1, rtc_alarm2, rtc_alarm3); -+ PDEBUG("%d-%d-%d %d:%d:%d",wkalrm->time.tm_year,wkalrm->time.tm_mon + 1,wkalrm->time.tm_mday, -+ wkalrm->time.tm_hour,wkalrm->time.tm_min ,wkalrm->time.tm_sec); -+ -+ rtc_alarm1 &= ~(0xFFF); -+ rtc_alarm2 &= ~(0x3FF); -+ rtc_alarm3 &= ~(0x7FF); -+ -+ -+ rtc_alarm1 |= ((wkalrm->time.tm_min << 6) + wkalrm->time.tm_sec); -+ rtc_alarm2 |= ((wkalrm->time.tm_mday << 5) + wkalrm->time.tm_hour); -+ rtc_alarm3 |= (((wkalrm->time.tm_year + EPOCH_START_YEAR - RTC_START_YEAR) << 4) + (wkalrm->time.tm_mon + 1)); -+ -+ ak_rtc_write(AK_RTC_ALARM_TIME1, rtc_alarm1); -+ ak_rtc_write(AK_RTC_ALARM_TIME2, rtc_alarm2); -+ ak_rtc_write(AK_RTC_ALARM_TIME3, rtc_alarm3); -+ -+ PDEBUG("%u %u %u\n", rtc_alarm1, rtc_alarm2, rtc_alarm3); -+ -+ if (wkalrm->enabled == 1) -+ { -+ ak_rtc_wakeup_enable(1); -+ ak_rtc_alarm_enable(); -+ } -+ else -+ { -+ ak_rtc_alarm_disable(); -+ ak_rtc_wakeup_enable(0); -+ } -+ -+ return 0; -+} -+/** -+* @brief ak_rtc_alarm_enable -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] void -+* @return void -+*/ -+static void ak_rtc_alarm_enable(void ) -+{ -+ unsigned long rtc_alarm1; -+ unsigned long rtc_alarm2; -+ unsigned long rtc_alarm3; -+ -+ rtc_alarm1 = ak_rtc_read(AK_RTC_ALARM_TIME1); -+ rtc_alarm2 = ak_rtc_read(AK_RTC_ALARM_TIME2); -+ rtc_alarm3 = ak_rtc_read(AK_RTC_ALARM_TIME3); -+ -+ rtc_alarm1 |= (1<<13); -+ rtc_alarm2 |= (1<<13); -+ rtc_alarm3 |= (1<<13); -+ -+ ak_rtc_write(AK_RTC_ALARM_TIME1, rtc_alarm1); -+ ak_rtc_write(AK_RTC_ALARM_TIME2, rtc_alarm2); -+ ak_rtc_write(AK_RTC_ALARM_TIME3, rtc_alarm3); -+} -+ -+/** -+* @brief ak_rtc_alarm_disable -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] void -+* @return void -+*/ -+static void ak_rtc_alarm_disable(void ) -+{ -+ unsigned long rtc_alarm1; -+ unsigned long rtc_alarm2; -+ unsigned long rtc_alarm3; -+ -+ rtc_alarm1 = ak_rtc_read(AK_RTC_ALARM_TIME1); -+ rtc_alarm2 = ak_rtc_read(AK_RTC_ALARM_TIME2); -+ rtc_alarm3 = ak_rtc_read(AK_RTC_ALARM_TIME3); -+ -+ rtc_alarm1 &= ~(1<<13); -+ rtc_alarm2 &= ~(1<<13); -+ rtc_alarm3 &= ~(1<<13); -+ -+ ak_rtc_write(AK_RTC_ALARM_TIME1, rtc_alarm1); -+ ak_rtc_write(AK_RTC_ALARM_TIME2, rtc_alarm2); -+ ak_rtc_write(AK_RTC_ALARM_TIME3, rtc_alarm3); -+} -+ -+ -+/** -+* @brief ak_rtc_ioctl -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @param[in] cmd -+* @param[in] arg -+* @return int -+*/ -+static int ak_rtc_ioctl(struct device *dev, -+ unsigned int cmd, unsigned long arg) -+{ -+ //PDEBUG("Entering %s: cmd %d\n", __FUNCTION__, cmd); -+ unsigned int ret = -ENOIOCTLCMD; -+ -+ switch (cmd) { -+ case RTC_AIE_OFF: -+ PDEBUG("RTC_AIE_OFF\n"); -+ ak_rtc_alarm_disable(); -+ ak_rtc_wakeup_enable(0); -+ -+ ret = 0; -+ break; -+ case RTC_AIE_ON: -+ PDEBUG("RTC_AIE_ON\n"); -+ ak_rtc_wakeup_enable(1); -+ ak_rtc_alarm_enable(); -+ ret = 0; -+ break; -+ -+ case RTC_UIE_ON: -+ case RTC_UIE_OFF: -+ ret = -ENOTTY; -+ break; -+ case RTC_RD_TIME: -+ PDEBUG("Read Time\n"); -+ break; -+ case RTC_SET_TIME: -+ PDEBUG("Set Time\n"); -+ break; -+ case RTC_ALM_SET: -+ PDEBUG("Set alarm\n"); -+ break; -+ case RTC_ALM_READ: -+ PDEBUG("Read alarm\n"); -+ break; -+ case RTC_WKALM_SET: -+ PDEBUG("Set alarm\n"); -+ break; -+ case RTC_WKALM_RD: -+ PDEBUG("Read alarm\n"); -+ break; -+ default: -+ return -ENOTTY; -+ -+ } -+ -+ return ret; -+} -+ -+/** -+* @brief ak_rtc_proc -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @param[out] *seq -+* @return int -+*/ -+static int ak_rtc_proc(struct device *dev, struct seq_file *seq) -+{ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ return 0; -+} -+ -+/** -+* @brief ak_rtc_alarmirq -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] irq -+* @param[out] *id -+* @return irqreturn_t -+*/ -+static irqreturn_t ak_rtc_alarmirq(int irq, void *id) -+{ -+ struct rtc_device *rdev = id; -+ PDEBUG("%s(): Entering...\n", __func__); -+ ak_rtc_int_clear(); -+ rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+* @brief ak_rtc_open -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @return int -+*/ -+static int ak_rtc_open(struct device *dev) -+{ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ return 0; -+} -+ -+/** -+* @brief ak_rtc_release -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @return void -+*/ -+static void ak_rtc_release(struct device *dev) -+{ -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ -+} -+ -+static const struct rtc_class_ops ak_rtc_ops = { -+ .open = ak_rtc_open, -+ .release = ak_rtc_release, -+ .ioctl = ak_rtc_ioctl, -+ .read_time = ak_rtc_gettime, -+ .set_time = ak_rtc_settime, -+ .read_alarm = ak_rtc_getalarm, -+ .set_alarm = ak_rtc_setalarm, -+ .proc = ak_rtc_proc, -+}; -+ -+/** -+* @brief ak_rtc_remove -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *dev -+* @return int -+*/ -+static int ak_rtc_remove(struct platform_device *dev) -+{ -+ struct rtc_device *rtc = platform_get_drvdata(dev); -+ PDEBUG("Entering %s\n", __FUNCTION__); -+ free_irq(IRQ_RTC_ALARM, rtc); -+ -+ platform_set_drvdata(dev, NULL); -+ rtc_device_unregister(rtc); -+ -+ return 0; -+} -+ -+/** -+* @brief ak_rtc_probe -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *pdev -+* @return int -+*/ -+static int ak_rtc_probe(struct platform_device *pdev) -+{ -+ struct rtc_device *rtc; -+ /* struct resource *res; */ -+ int ret; -+ -+ rtc = rtc_device_register("ak-rtc", &pdev->dev, &ak_rtc_ops, -+ THIS_MODULE); -+ -+ if (IS_ERR(rtc)) { -+ dev_err(&pdev->dev, "cannot attach rtc\n"); -+ ret = PTR_ERR(rtc); -+ -+ return -1; -+ } -+ -+ rtc->max_user_freq = 128; -+ -+ platform_set_drvdata(pdev, rtc); -+ -+ ak_rtc_wakeup_enable(0); -+ -+ ret = request_irq(IRQ_RTC_ALARM, ak_rtc_alarmirq, -+ IRQF_DISABLED, "ak-rtc alarm", rtc); -+ if (ret) { -+ printk("IRQ %d error %d\n", IRQ_RTC_ALARM, ret); -+ return ret; -+ } -+ -+ return 0; -+ -+} -+ -+#ifdef CONFIG_PM -+ -+ -+//static struct timespec ak_rtc_delta; -+/* RTC Power management control */ -+/** -+* @brief ak_rtc_suspend -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *pdev -+* @param[in] state -+* @return int -+*/ -+static int ak_rtc_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ struct rtc_time tm; -+ struct timespec time; -+ -+ time.tv_nsec = 0; -+ -+ /* calculate time delta for suspend */ -+ -+ ak_rtc_gettime(&pdev->dev, &tm); -+ rtc_tm_to_time(&tm, &time.tv_sec); -+// save_time_delta(&ak_rtc_delta, &time); -+ -+ return 0; -+} -+ -+/** -+* @brief ak_rtc_resume -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[out] *pdev -+* @return int -+*/ -+static int ak_rtc_resume(struct platform_device *pdev) -+{ -+ struct rtc_time tm; -+ struct timespec time; -+ -+ time.tv_nsec = 0; -+ ak_rtc_gettime(&pdev->dev, &tm); -+ rtc_tm_to_time(&tm, &time.tv_sec); -+// restore_time_delta(&ak_rtc_delta, &time); -+ -+ return 0; -+} -+#else -+#define ak_rtc_suspend NULL -+#define ak_rtc_resume NULL -+#endif -+ -+static struct platform_driver ak_rtcdrv = { -+ .probe = ak_rtc_probe, -+ .remove = ak_rtc_remove, -+ .suspend = ak_rtc_suspend, -+ .resume = ak_rtc_resume, -+ .driver = { -+ .name = "ak-rtc", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+/** -+* @brief ak_rtc_init -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] void -+* @return int __init -+*/ -+static int __init ak_rtc_init(void) -+{ -+ PDEBUG("RTC Init...\n"); -+ -+ ak_rtc_power(RTC_ON); -+ -+ if (test_rtc_inter_reg(AK_RTC_REAL_TIME1)<0) { -+ printk("Board has not RTC support. exit %s\n", __func__); -+ ak_rtc_power(RTC_OFF); -+ return -ENODEV; -+ } -+ -+ //printk("AK RTC, (c) 2010 ANYKA \n"); -+ return platform_driver_register(&ak_rtcdrv); -+} -+ -+/** -+* @brief ak_rtc_exit -+* @author zhou wenyong -+* @date 2011-08-29 -+* @param[in] void -+* @return void __exit -+*/ -+static void __exit ak_rtc_exit(void) -+{ -+ /* -+ When RTC is powered off, this bit(AK_RTC_CONF [24] ) should be set to 0 -+ */ -+ ak_rtc_power(RTC_OFF); -+ platform_driver_unregister(&ak_rtcdrv); -+} -+ -+module_init(ak_rtc_init); -+module_exit(ak_rtc_exit); -+ -+MODULE_DESCRIPTION("ANYKA AK RTC Driver"); -+MODULE_AUTHOR("anyka"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ak-rtc"); -diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig -index 29684c81..362baecf 100644 ---- a/drivers/scsi/Kconfig -+++ b/drivers/scsi/Kconfig -@@ -265,7 +265,7 @@ config SCSI_SCAN_ASYNC - - config SCSI_WAIT_SCAN - tristate # No prompt here, this is an invisible symbol. -- default m -+ default n - depends on SCSI - depends on MODULES - # scsi_wait_scan is a loadable module which waits until all the async scans are -diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -index 00c02403..0706d7a0 100644 ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -403,6 +403,14 @@ config SPI_NUC900 - help - SPI driver for Nuvoton NUC900 series ARM SoCs - -+config SPI_ANYKA -+ tristate "ANYKA SPI controller" -+ depends on SPI_MASTER && (ARCH_AK98 || ARCH_AK39) -+ select SPI_BITBANG -+ help -+ SPI driver for anyka ARM SoCs -+ -+ - # - # Add new SPI master controllers in alphabetical order above this line - # -@@ -454,6 +462,13 @@ config SPI_TLE62X0 - - endif # SPI_MASTER - -+# (slave support would go here) -+config SPI_ANYKA_SLAVE -+ tristate "ANYKA SPI slave controller " -+ depends on (ARCH_AK98 || ARCH_AK39) && !SPI_ANYKA -+ help -+ This is the SPI slave controller driver for anyka platform -+ - # (slave support would go here) - - endif # SPI -diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile -index 9d75d219..f88966f0 100644 ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -62,4 +62,6 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o - obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o - obj-$(CONFIG_SPI_TXX9) += spi-txx9.o - obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o -+obj-$(CONFIG_SPI_ANYKA) += spi-anyka.o -+obj-$(CONFIG_SPI_ANYKA_SLAVE) += spi-anyka-slave.o - -diff --git a/drivers/spi/spi-anyka-slave.c b/drivers/spi/spi-anyka-slave.c -new file mode 100644 -index 00000000..ec17db3c ---- /dev/null -+++ b/drivers/spi/spi-anyka-slave.c -@@ -0,0 +1,1050 @@ -+/* -+ * spi_anyka_slave.c - Anyka SPI slave controller driver -+ * based on spi_anyka.c -+ * -+ * Copyright (C) Anyka 2012 -+ * Wangsheng Gao <gao_wangsheng@anyka.oa> -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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 -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ */ -+ -+/* -+ * Note: -+ * -+ * Supports interrupt programmed transfers. -+ * -+ */ -+ -+ /* -+ * Usage: -+ * 1. set one device as master: -+ * 1. register spidev board info in platform file; -+ * 2. select spidev and anyka spi controler in menuconfig. -+ * 2. set one device as slave: select anyka spi slave controler in menuconfig -+ * 3. run make command in Documentation/spi/ directory -+ * 4. copy Documentation/spi/spi_master_test and Documentation/spi/spi_slave_test to Your_rootfs_dir -+ * 5. firstly run spi_slave_test in slave and then run spi_master_test in master -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/device.h> -+#include <linux/ioport.h> -+#include <linux/errno.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+#include <linux/cdev.h> -+#include <linux/workqueue.h> -+#include <linux/delay.h> -+#include <linux/clk.h> -+#include <linux/gpio.h> -+#include <linux/fs.h> -+#include <linux/types.h> -+#include <linux/fcntl.h> -+#include <linux/poll.h> -+#include <asm/io.h> -+#include <asm/irq.h> -+#include <mach/gpio.h> -+#include <mach/regs-comm.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+ -+#include <plat-anyka/spi-anyka-slave.h> -+#include <plat/spi.h> -+#include <linux/spi/spidev.h> -+#include <asm/uaccess.h> -+#include <mach/clock.h> -+ -+/** -+* @brief slave data: devices, lock, wait_queue, io resource... -+* @author gao wangsheng -+* @date 2012-10-16 -+* @param[out] void -+* @param[in] void -+* @param[in] void -+* @return void -+*/ -+struct spi_anyka_slave { -+ /* Driver model hookup */ -+ struct platform_device *pdev; -+ struct ak_spi_info *pdata; -+ struct cdev cdev; -+ struct fasync_struct *async_queue; /* asynchronous readers */ -+ -+ struct clk *clk; -+ -+ /* Lock */ -+ struct mutex slave_lock; -+ spinlock_t regs_lock; -+ -+ /* wait queue */ -+ wait_queue_head_t readq; -+ wait_queue_head_t writeq; -+ -+ /* read and write buffer */ -+ char *rdbuf, *rdend; -+ char *recvp, *readp; -+ int rdsize; -+ char *wrbuf, *wrend; -+ char *sentp, *writep; -+ int wrsize; -+ -+ /* Spi controler register addresses */ -+ void *ioarea; -+ void *regs; -+ int irq; -+ -+ /* flag */ -+ u8 mode; -+ u8 bits_per_word; -+ u32 max_speed_hz; -+ int openers; -+}; -+ -+static struct class *slave_class; -+static int slave_major; -+static int slave_minor = 0; -+#define SLAVE_MAX_MINOR (8) -+#define DFT_DIV (255) -+#define DFT_CON AK_SPICON_EN -+#define BUF_LEN (512) -+#define DCNT (0xffff) -+#define SET_CLK (1 << 0) -+#define SET_MODE (1 << 1) -+#define SPI_MODE_MASK (SPI_CPOL | SPI_CPHA ) -+#define SLAVE_MASK (AK_SPISTA_RXHFULL|AK_SPIINT_TIMEOUT |AK_SPIINT_RXFULL) -+ -+#define sdbug(fmt...) //printk(fmt) -+ -+static int akspi_slave_fasync(int fd, struct file *filp, int mode); -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief How much space is free? -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *slave -+* @return free space in buffer -+*/ -+static int akspi_slave_space_free(struct spi_anyka_slave *slave) -+{ -+ if (slave->readp == slave->recvp){ -+ return slave->rdsize - 1; -+ } -+ return ((slave->readp + slave->rdsize - slave->recvp) % slave->rdsize) - 1; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief store data into buffer -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] slave->recvp -+* @param[in] *slave -+* @param[in] *buf -+* @param[in] count -+* @return How much data has been stored -+*/ -+static int akspi_slave_reveive_data(struct spi_anyka_slave *slave, -+ char *buf, size_t count) -+{ -+// sdbug("%s\n", __func__); -+ -+ /* ok, space is there, accept something */ -+ count = min(count, (size_t)akspi_slave_space_free(slave)); -+ if (slave->recvp >= slave->readp){ -+ /* to end-of-buf */ -+ count = min(count, (size_t)(slave->rdend - slave->recvp)); -+ } -+ else { -+ /* the write pointer has wrapped, fill up to rp-1 */ -+ count = min(count, (size_t)(slave->readp - slave->recvp - 1)); -+ } -+ -+ memcpy(slave->recvp, buf, count); -+ slave->recvp += count; -+ if (slave->recvp == slave->rdend){ -+ slave->recvp = slave->rdbuf; /* wrapped */ -+ } -+ -+ return count; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief Enable or disable irq -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *slave -+* @param[in] is enable? -+* @return void -+*/ -+static void akspi_slave_set_irq(struct spi_anyka_slave *slave, int enable) -+{ -+ u32 spiint = SLAVE_MASK; -+ if (enable) -+ iowrite32(spiint, slave->regs + AK_SPIINT); -+ else -+ iowrite32(0, slave->regs + AK_SPIINT); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief receive data int interupt -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *slave -+* @param[in] irq -+* @return irqreturn_t -+*/ -+static irqreturn_t akspi_slave_int(int irq, void *dev_id) -+{ -+ struct spi_anyka_slave *slave = (struct spi_anyka_slave *)dev_id; -+ u32 status, val; -+ u16 count; -+ int i; -+ -+ spin_lock(&slave->regs_lock); -+ status = ioread32(slave->regs + AK_SPISTA); -+ sdbug("%s: status=0x%08x\n", __func__, status); -+ -+ if (((status & AK_SPISTA_TIMEOUT) == AK_SPISTA_TIMEOUT) -+ && ((status & AK_SPISTA_RXEMP) != AK_SPISTA_RXEMP)) -+ { -+ char temp; -+ u16 cnt =0; -+ -+ count = ioread32(slave->regs + AK_SPICNT); -+ cnt = (DCNT - count)%4; -+ val = ioread32(slave->regs + AK_SPIIN); -+ sdbug("%s: AK_SPISTA_TIMEOUT, val=0x%08x, cnt=%u\n", __func__, val, cnt); -+ -+ for (i=0; i<cnt; i++) -+ { -+ temp = (val >> i*8) & 0xff; -+ akspi_slave_reveive_data(slave, &temp, 1); -+ } -+ -+ iowrite32(DCNT, slave->regs + AK_SPICNT); -+ } -+ else if ((status & AK_SPISTA_RXFULL) == AK_SPISTA_RXFULL) -+ { -+ val = ioread32(slave->regs + AK_SPIIN); -+ sdbug("%s: AK_SPISTA_RXFULL, val=0x%08x\n", __func__, val); -+ akspi_slave_reveive_data(slave, (char *)&val, 4); -+ val = ioread32(slave->regs + AK_SPIIN); -+ sdbug("%s: AK_SPISTA_RXFULL, val=0x%08x\n", __func__, val); -+ akspi_slave_reveive_data(slave, (char *)&val, 4); -+ } -+ -+ else if ((status & AK_SPISTA_RXHFULL) == AK_SPISTA_RXHFULL) -+ { -+ val = ioread32(slave->regs + AK_SPIIN); -+ sdbug("%s: AK_SPISTA_RXHFULL, val=0x%08x\n", __func__, val); -+ akspi_slave_reveive_data(slave, (char *)&val, 4); -+ } -+ -+ wake_up_interruptible(&slave->readq); -+ if (slave->async_queue){ -+ kill_fasync(&slave->async_queue, SIGIO, POLL_IN); -+ } -+ spin_unlock(&slave->regs_lock); -+ return IRQ_HANDLED; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief prepare receive data from master -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *slave -+* @return void -+*/ -+static void akspi_slave_prepare_read(struct spi_anyka_slave *slave) -+{ -+ u32 val; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&slave->regs_lock, flags); -+ -+ val = ioread32(slave->regs + AK_SPICON); -+ val &= ~(AK_SPICON_ARRM); -+ val |= AK_SPICON_TGDM; -+ iowrite32(val, slave->regs + AK_SPICON); -+ iowrite32(DCNT, slave->regs + AK_SPICNT); -+ akspi_slave_set_irq(slave, 1); -+ -+ spin_unlock_irqrestore(&slave->regs_lock, flags); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief open slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *node -+* @param[in] *filp -+* @return fail or not -+*/ -+static int akspi_slave_open(struct inode *node, struct file *filp) -+{ -+ struct spi_anyka_slave *slave = container_of(node->i_cdev, struct spi_anyka_slave, cdev); -+ -+ if (mutex_lock_interruptible(&slave->slave_lock)){ -+ return -ERESTARTSYS; -+ } -+ -+ nonseekable_open(node, filp); -+ -+ if (!slave->rdbuf){ -+ /* Alloc memory for receive data */ -+ slave->rdbuf = kzalloc(BUF_LEN, GFP_KERNEL); -+ if (!slave->rdbuf){ -+ mutex_unlock(&slave->slave_lock); -+ printk("%s: %d\n", __func__, __LINE__); -+ return -ENOMEM; -+ } -+ akspi_slave_prepare_read(slave); -+ } -+ -+ slave->rdsize = BUF_LEN; -+ slave->rdend = slave->rdbuf + slave->rdsize; -+ slave->readp = slave->recvp = slave->rdbuf; /* rd and wr from the beginning */ -+ slave->openers++; -+ filp->private_data = slave; -+ mutex_unlock(&slave->slave_lock); -+ sdbug("%s: openers=%d\n", __func__, slave->openers); -+ return 0; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief relese slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *node -+* @param[in] *filp -+* @return fail or not -+*/ -+static int akspi_slave_release(struct inode *node, struct file *filp) -+{ -+ struct spi_anyka_slave *slave = container_of(node->i_cdev, struct spi_anyka_slave, cdev); -+ -+ akspi_slave_fasync(-1, filp, 0); -+ mutex_lock(&slave->slave_lock); -+ -+ slave->openers--; -+ if (!slave->openers){ -+ /* close spi controler */ -+ akspi_slave_set_irq(slave, 0); -+ kfree(slave->rdbuf); -+ slave->rdbuf = NULL; -+ } -+ -+ filp->private_data = NULL; -+ mutex_unlock(&slave->slave_lock); -+ sdbug("%s: openers=%d\n", __func__, slave->openers); -+ return 0; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief setup slave controler -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *slave -+* @param[in] *void -+* @return fail or not -+*/ -+static int akspi_slave_setmode(struct spi_anyka_slave *slave) -+{ -+ u16 spicon; -+ -+ sdbug("%s: set mode-------------.\n", __func__); -+ spin_lock(&slave->regs_lock); -+ spicon = ioread32(slave->regs + AK_SPICON); -+ -+ if (slave->mode & SPI_CPHA) -+ spicon |= AK_SPICON_CPHA; -+ else -+ spicon &= ~AK_SPICON_CPHA; -+ if (slave->mode & SPI_CPOL) -+ spicon |= AK_SPICON_CPOL; -+ else -+ spicon &= ~AK_SPICON_CPOL; -+ -+ iowrite32(spicon, slave->regs + AK_SPICON); -+ spin_unlock(&slave->regs_lock); -+ return 0; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief setup slave controler -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *slave -+* @param[in] *void -+* @return fail or not -+*/ -+static int akspi_slave_setclk(struct spi_anyka_slave *slave) -+{ -+ unsigned int div; -+ unsigned int hz = slave->max_speed_hz; -+ unsigned long clk = ak_get_asic_clk(); -+ u16 spicon; -+ -+ sdbug("%s: set clk-------------.\n", __func__); -+ spin_lock(&slave->regs_lock); -+ spicon = ioread32(slave->regs + AK_SPICON); -+ -+ div = clk / (hz*2) - 1; -+ if (div > 255){ -+ div = 255; -+ } -+ else if (div < 3){ -+ div = 3; -+ } -+ -+ spicon &=~(0xff << 8); -+ spicon |= div << 8; -+ iowrite32(spicon, slave->regs + AK_SPICON); -+ spin_unlock(&slave->regs_lock); -+ return 0; -+} -+ -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief ioctl slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *node -+* @param[in] *filp, cmd, arg -+* @return fail or not -+*/ -+static long akspi_slave_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ int retval = 0; -+ int err = 0; -+ u32 tmp; -+ struct spi_anyka_slave *slave; -+ -+ sdbug("%s: cmd=%u\n", __func__, cmd); -+ -+ /* Check type and command number */ -+ if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC) -+ return -ENOTTY; -+ -+ /* Check access direction once here; don't repeat below. -+ * IOC_DIR is from the user perspective, while access_ok is -+ * from the kernel perspective; so they look reversed. -+ */ -+ if (_IOC_DIR(cmd) & _IOC_READ){ -+ err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); -+ } -+ -+ if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE){ -+ err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); -+ } -+ -+ if (err){ -+ return -EFAULT; -+ } -+ -+ slave = filp->private_data; -+ if (!slave){ -+ return -ESHUTDOWN; -+ } -+ -+ mutex_lock(&slave->slave_lock); -+ -+ switch (cmd){ -+ /* read requests */ -+ case SPI_IOC_RD_MODE: -+ retval = __put_user(slave->mode & SPI_MODE_MASK, (__u8 __user *)arg); -+ break; -+ case SPI_IOC_RD_LSB_FIRST: -+ retval = __put_user((slave->mode & SPI_LSB_FIRST) ? 1 : 0, (__u8 __user *)arg); -+ break; -+ case SPI_IOC_RD_BITS_PER_WORD: -+ retval = __put_user(slave->bits_per_word, (__u8 __user *)arg); -+ break; -+ case SPI_IOC_RD_MAX_SPEED_HZ: -+ retval = __put_user(slave->max_speed_hz, (__u32 __user *)arg); -+ break; -+ -+ /* write requests */ -+ case SPI_IOC_WR_MODE: -+ retval = __get_user(tmp, (u8 __user *)arg); -+ if (retval == 0) { -+ u8 save = slave->mode; -+ -+ if (tmp & ~SPI_MODE_MASK) { -+ retval = -EINVAL; -+ break; -+ } -+ -+ tmp |= slave->mode & ~SPI_MODE_MASK; -+ slave->mode = (u8)tmp; -+ retval = akspi_slave_setmode(slave); -+ if (retval < 0) -+ slave->mode = save; -+ else -+ dev_dbg(&slave->pdev->dev, "spi mode %02x\n", tmp); -+ } -+ break; -+ case SPI_IOC_WR_LSB_FIRST: -+ retval = -EINVAL; -+ break; -+ case SPI_IOC_WR_BITS_PER_WORD: -+ retval = -EINVAL; -+ break; -+ case SPI_IOC_WR_MAX_SPEED_HZ: -+ retval = __get_user(tmp, (__u32 __user *)arg); -+ if (retval == 0) { -+ u32 save = slave->max_speed_hz; -+ -+ slave->max_speed_hz = tmp; -+ retval = akspi_slave_setclk(slave); -+ if (retval < 0) -+ slave->max_speed_hz = save; -+ else -+ dev_dbg(&slave->pdev->dev, "%d Hz (max)\n", tmp); -+ } -+ break; -+ -+ default: -+ retval = -EINVAL; -+ break; -+ } -+ -+ mutex_unlock(&slave->slave_lock); -+ return retval; -+ } -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief read slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *buf -+* @param[in] *filp -+* @return read data count -+*/ -+static ssize_t akspi_slave_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) -+{ -+ struct spi_anyka_slave *slave = filp->private_data; -+ -+ if (mutex_lock_interruptible(&slave->slave_lock)){ -+ return -ERESTARTSYS; -+ } -+ -+ sdbug("%s: %d\n", __func__, __LINE__); -+ while (slave->recvp == slave->readp){ -+ mutex_unlock(&slave->slave_lock); -+ if (filp->f_flags & O_NONBLOCK){ -+ return -EAGAIN; -+ } -+ if (wait_event_interruptible(slave->readq, (slave->recvp != slave->readp))){ -+ return -ERESTARTSYS; -+ } -+ if (mutex_lock_interruptible(&slave->slave_lock)){ -+ return -ERESTARTSYS; -+ } -+ sdbug("%s: %d\n", __func__, __LINE__); -+ } -+ sdbug("%s: %d\n", __func__, __LINE__); -+ -+ if (slave->recvp > slave->readp) { -+ /* return the data */ -+ count = min(count, (size_t)(slave->recvp - slave->readp)); -+ } -+ else { -+ /* the write pointer has wrapped, return data up to end */ -+ count = min (count, (size_t)(slave->rdend - slave->readp)); -+ } -+ -+ if (copy_to_user(buf, slave->readp, count)) { -+ mutex_unlock(&slave->slave_lock); -+ return -EFAULT; -+ } -+ -+ slave->readp += count; -+ if (slave->readp == slave->rdend){ -+ slave->readp = slave->rdbuf; -+ } -+ -+ mutex_unlock(&slave->slave_lock); -+ sdbug("%s: %d\n", __func__, __LINE__); -+ return count; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief write slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *buf -+* @param[in] *filp, count, pos -+* @return write data count -+*/ -+static ssize_t akspi_slave_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) -+{ -+ struct spi_anyka_slave *slave = filp->private_data; -+ -+ sdbug("%s: %d\n", __func__, __LINE__); -+ -+ return count; -+ -+ if (mutex_lock_interruptible(&slave->slave_lock)){ -+ return -ERESTARTSYS; -+ } -+ -+ while (slave->sentp != slave->writep){ -+ mutex_unlock(&slave->slave_lock); -+ if (filp->f_flags & O_NONBLOCK){ -+ return -EAGAIN; -+ } -+ if (wait_event_interruptible(slave->writeq, slave->sentp != slave->writep)){ -+ return -ERESTARTSYS; -+ } -+ if (mutex_lock_interruptible(&slave->slave_lock)){ -+ return -ERESTARTSYS; -+ } -+ } -+ -+ /* spi slave has something to write */ -+ -+ mutex_unlock(&slave->slave_lock); -+ sdbug("%s: %d\n", __func__, __LINE__); -+ return count; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief poll slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *table -+* @param[in] *filp -+* @return fail or not -+*/ -+unsigned int akspi_slave_poll (struct file *filp, struct poll_table_struct *table) -+{ -+ struct spi_anyka_slave *slave = filp->private_data; -+ int mask = 0; -+ -+ sdbug("%s: %d\n", __func__, __LINE__); -+ mutex_lock(&slave->slave_lock); -+ poll_wait(filp, &slave->readq, table); -+ poll_wait(filp, &slave->writeq, table); -+ -+ if (slave->recvp != slave->readp){ -+ mask |= POLLIN | POLLRDNORM; /* readable */ -+ } -+ -+ if (slave->sentp != slave->writep){ -+ mask |= POLLOUT | POLLWRNORM; /* writable */ -+ } -+ mutex_unlock(&slave->slave_lock); -+ sdbug("%s: %d\n", __func__, __LINE__); -+ return mask; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief fasync slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *node -+* @param[in] *filp, fd, mode -+* @return fail or not -+*/ -+static int akspi_slave_fasync(int fd, struct file *filp, int mode) -+{ -+ struct spi_anyka_slave *slave = filp->private_data; -+ -+ return fasync_helper(fd, filp, mode, &slave->async_queue); -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief initialize slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *slave -+* @param[in] void -+* @return void -+*/ -+static void akspi_slave_initial_setup(struct spi_anyka_slave *slave) -+{ -+ u32 value = 0; -+ -+ sdbug("%s: %d\n", __func__, __LINE__); -+ clk_enable(slave->clk); -+ -+ spin_lock(&slave->regs_lock); -+ value = DFT_CON ; -+ iowrite32(value, slave->regs + AK_SPICON); -+ spin_unlock(&slave->regs_lock); -+ akspi_slave_setclk(slave); -+ akspi_slave_setmode(slave); -+ sdbug("value=%08x, reg=%08x\n",value, ioread32(slave->regs + AK_SPICON)); -+ akspi_slave_set_irq(slave, 0); -+ -+ if (slave->pdata) { -+ if (slave->pdata->gpio_setup){ -+ slave->pdata->gpio_setup(slave->pdata, 1); -+ } -+ } -+} -+ -+static const struct file_operations slave_ops = { -+ .owner = THIS_MODULE, -+ .open = akspi_slave_open, -+ .release = akspi_slave_release, -+ .unlocked_ioctl = akspi_slave_ioctl, -+ .read = akspi_slave_read, -+ .write = akspi_slave_write, -+ .poll = akspi_slave_poll, -+ .fasync = akspi_slave_fasync, -+}; -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief probe slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] slave -+* @param[in] *pdev -+* @param[in] *pdata -+* @return fail or not -+*/ -+static int ak_spi_slave_probe(struct platform_device *pdev) -+{ -+ struct ak_spi_info *pdata; -+ struct spi_anyka_slave *slave = NULL; -+ struct resource *res; -+ int err = 0; -+ -+ pdata = pdev->dev.platform_data; -+ if (pdata == NULL) -+ { -+ dev_err(&pdev->dev, "No platform data supplied\n"); -+ err = -ENOENT; -+ goto err_no_pdata; -+ } -+ -+ /* Allocate Slave with space for drv_data and null dma buffer */ -+ slave = kzalloc(sizeof(struct spi_anyka_slave), GFP_KERNEL); -+ if (!slave) { -+ dev_err(&pdev->dev, "cannot alloc mem\n"); -+ err = -ENOMEM; -+ goto err_nomem; -+ } -+ -+ slave->pdata = pdata; -+ slave->pdev = pdev; -+ cdev_init(&slave->cdev, &slave_ops); -+ slave->cdev.owner = THIS_MODULE; -+ -+ spin_lock_init(&slave->regs_lock); -+ mutex_init(&slave->slave_lock); -+ init_waitqueue_head(&slave->readq); -+ init_waitqueue_head(&slave->writeq); -+ slave->mode = SPI_MODE_0; -+ slave->bits_per_word = 8; -+ slave->max_speed_hz = 2147483647; -+ -+ /* get basic io resource and map it */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res == NULL) { -+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); -+ err = -ENOENT; -+ goto err_no_iores; -+ } -+ -+ slave->ioarea = request_mem_region(res->start, resource_size(res), pdev->name); -+ if (slave->ioarea == NULL) { -+ dev_err(&pdev->dev, "Cannot reserve region\n"); -+ err = -ENXIO; -+ goto err_no_iores; -+ } -+ -+ slave->regs = ioremap(res->start, resource_size(res)); -+ if (!slave->regs) { -+ err = -ENOMEM; -+ goto err_no_iomap; -+ } -+ printk(KERN_INFO "SPI-Slave:map regs = %08x\n", (int)slave->regs); -+ -+ /* Attach to IRQ */ -+ slave->irq = platform_get_irq(pdev, 0); -+ if (slave->irq < 0) { -+ dev_err(&pdev->dev, "No IRQ specified\n"); -+ err = -ENOENT; -+ goto err_no_irq; -+ } -+ printk(KERN_INFO "SPI-Slave:get irq = %04x\n", (int)slave->irq); -+ -+ err = request_irq(slave->irq, akspi_slave_int, IRQF_DISABLED, pdev->name, slave); -+ if (err < 0) { -+ dev_err(&pdev->dev, "can not get IRQ\n"); -+ goto err_no_irq; -+ } -+ printk(KERN_INFO "SPI-Slave: request IRQ: %04x\n", slave->irq); -+ -+ err = cdev_add(&slave->cdev, MKDEV(slave_major, slave_minor), 1); -+ if (err){ -+ dev_err(&pdev->dev, "cannot add cdev\n"); -+ err = -ENOMEM; -+ goto err_register; -+ } -+ printk(KERN_INFO "SPI-Slave: register with char device framework\n"); -+ -+ if (IS_ERR(device_create(slave_class, &pdev->dev, -+ MKDEV(slave_major, slave_minor), -+ slave, "spi_slave.%u", slave_minor))){ -+ dev_err(&pdev->dev, "cannot device_create\n"); -+ } -+ -+ slave->clk = clk_get(&pdev->dev, pdata->clk_name); -+ sdbug("%s: %lu \n", slave->clk->name, clk_get_rate(slave->clk)); -+ if (IS_ERR(slave->clk)) { -+ dev_err(&pdev->dev, "No clock for device\n"); -+ err = PTR_ERR(slave->clk); -+ goto err_no_clk; -+ } -+ -+ akspi_slave_initial_setup(slave); -+ -+ platform_set_drvdata(pdev, slave); -+ printk("Ak spi slave initialized!\n"); -+ return 0; -+ -+ err_no_clk: -+ device_destroy(slave_class, MKDEV(slave_major, slave_minor)); -+ cdev_del(&slave->cdev); -+ err_register: -+ free_irq(slave->irq, slave); -+ err_no_irq: -+ iounmap(slave->regs); -+ err_no_iomap: -+ release_resource(slave->ioarea); -+ kfree(slave->ioarea); -+ err_no_iores: -+ err_no_pdata: -+ err_nomem: -+ return err; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief remove slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *pdev -+* @param[in] *slave -+* @return void -+*/ -+static void __devexit ak_spi_slave_remove(struct platform_device *pdev) -+{ -+ struct spi_anyka_slave *slave = platform_get_drvdata(pdev); -+ int minor = MINOR(slave->cdev.dev); -+ -+ if (!slave) -+ return; -+ -+ platform_set_drvdata(pdev, NULL); -+ device_destroy(slave_class, MKDEV(slave_major, minor)); -+ cdev_del(&slave->cdev); -+ -+ /* Release IRQ */ -+ free_irq(slave->irq, slave); -+ iounmap(slave->regs); -+ release_resource(slave->ioarea); -+ kfree(slave->ioarea); -+ kfree(slave); -+ -+ return; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief suspend and resume slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] *dev -+* @param[in] state -+* @return fail or not -+*/ -+#ifdef CONFIG_PM -+static int ak_spi_slave_suspend(struct device *dev, pm_message_t state) -+{ -+ struct spi_anyka_slave *slave = dev_get_drvdata(dev); -+ -+ printk(KERN_ERR "%s: suspend\n", slave->pdev->name); -+ return 0; -+} -+ -+static int ak_spi_slave_resume(struct device *dev) -+{ -+ struct spi_anyka_slave *slave = dev_get_drvdata(dev); -+ -+ printk(KERN_ERR "%s: resume\n", slave->pdev->name); -+ return 0; -+} -+#else -+#define ak_spi_slave_suspend NULL -+#define ak_spi_slave_resume NULL -+#endif /* CONFIG_PM */ -+ -+static struct platform_driver akspi_slave_driver = { -+ .driver = { -+ .name = "akspi-spi", -+ .owner = THIS_MODULE, -+ .suspend = ak_spi_slave_suspend, -+ .resume = ak_spi_slave_resume, -+ }, -+ .remove = __exit_p(ak_spi_slave_remove), -+ .probe = ak_spi_slave_probe, -+}; -+ -+static ssize_t slave_show_version(struct class *cls, struct class_attribute *attr, char *buf) -+{ -+ return sprintf(buf, "spi-1.0.01\n"); -+} -+static CLASS_ATTR(version, 0444, slave_show_version, NULL); -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief init slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] void -+* @param[in] void -+* @return fail or not -+*/ -+static int __init ak_spi_slave_init(void) -+{ -+ int ret; -+ dev_t dev; -+ -+ slave_class = class_create(THIS_MODULE, "spi_slave"); -+ if (IS_ERR(slave_class)){ -+ ret = PTR_ERR(slave_class); -+ printk("%s:class create fail!\n", __func__); -+ goto err; -+ } -+ -+ ret = class_create_file(slave_class, &class_attr_version); -+ if (ret){ -+ printk("%s:class create file fail!\n", __func__); -+ goto err_class; -+ } -+ -+ ret = alloc_chrdev_region(&dev, 0, SLAVE_MAX_MINOR, "spi_slave"); -+ if (ret){ -+ printk("%s:alloc chrdev fail!\n", __func__); -+ goto err_chrdev; -+ } -+ slave_major = MAJOR(dev); -+ -+ ret = platform_driver_register(&akspi_slave_driver); -+ if (ret){ -+ printk("%s:platform_driver_register fail!\n", __func__); -+ goto err_plat; -+ } -+ -+ return 0; -+ -+err_plat: -+ unregister_chrdev_region(dev, SLAVE_MAX_MINOR); -+err_chrdev: -+ class_remove_file(slave_class, &class_attr_version); -+err_class: -+ class_destroy(slave_class); -+err: -+ return ret; -+} -+ -+/** -+* @Copyright (C) Anyka 2012 -+* @brief exit slave device -+* @author Gao wangsheng -+* @email gao_wangsheng@anyka.oa -+* @date 2012-10-23 -+* @param[out] void -+* @param[in] void -+* @param[in] void -+* @return void -+*/ -+static void __exit ak_spi_slave_exit(void) -+{ -+ platform_driver_unregister(&akspi_slave_driver); -+ unregister_chrdev_region(MKDEV(slave_major, 0), SLAVE_MAX_MINOR); -+ class_remove_file(slave_class, &class_attr_version); -+ class_destroy(slave_class); -+} -+ -+MODULE_AUTHOR("Wangsheng Gao"); -+MODULE_DESCRIPTION("Anyka SPI Slave Contoller"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:AK-spi-slave"); -+module_init(ak_spi_slave_init); -+module_exit(ak_spi_slave_exit); -diff --git a/drivers/spi/spi-anyka.c b/drivers/spi/spi-anyka.c -new file mode 100644 -index 00000000..2e8c9f22 ---- /dev/null -+++ b/drivers/spi/spi-anyka.c -@@ -0,0 +1,1778 @@ -+/** -+* @file /driver/spi/spi_anyka.c -+* @brief AK On-chip SPI driver -+* Copyright C 2011 Anyka CO.,LTD -+* modify based on spi_s3c24xx.c -+* -+* Copyright (c) 2006 Ben Dooks -+* Copyright (c) 2006 Simtec Electronics -+* Ben Dooks <ben@simtec.co.uk> -+* -+* This program is free software; you can redistribute it and/or modify -+* it under the terms of the GNU General Public License version 2 as -+* published by the Free Software Foundation. -+* @author zhou wenyong -+* @date 2011-08-19 -+* @note 2011-5-16 created -+* @note 2011-08-19 add more comments -+*/ -+ -+#include <linux/init.h> -+#include <linux/spinlock.h> -+#include <linux/workqueue.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <linux/errno.h> -+#include <linux/err.h> -+#include <linux/clk.h> -+#include <linux/platform_device.h> -+#include <linux/module.h> -+#include <linux/io.h> -+#include <mach/gpio.h> -+ -+#include <linux/spi/spi.h> -+#include <linux/spi/spi_bitbang.h> -+ -+#include <mach/spi.h> -+#include <mach/clock.h> -+#include <plat-anyka/anyka_types.h> -+#include <plat/l2.h> -+#include <linux/dma-mapping.h> -+#include <plat-anyka/drv_module_lock.h> -+#include <mach/reset.h> -+ -+//#define SPI_DEBUG -+ -+#define TMPDBG(fmt, args...) //printk( KERN_INFO fmt,## args) -+ -+#define TMPDEBUG(fmt, args...) //printk( KERN_INFO fmt,## args) -+ -+/* #define DEBUG */ -+#undef PDEBUG /* undef it, just in case */ -+#ifdef SPI_DEBUG -+# ifdef __KERNEL__ -+/* This one if debugging is on, and kernel space */ -+# define PDEBUG(fmt, args...) printk( KERN_INFO fmt,## args) -+# else -+/* This one for user space */ -+# define PDEBUG(fmt, args...) fprintf(stderr, "%s %d: "fmt,__FILE__, __LINE__, ## args) -+# endif -+#else -+# define PDEBUG(fmt, args...) /* not debugging: nothing */ -+#endif -+ -+ /*usually use for spi keyboard or spi mouse.*/ -+//#define SPI_CPU_MODE_USE_INTERRUPT -+ -+ -+/** -+ * ak_spi_devstate - per device data -+ * @hz: Last frequency calculated for @sppre field. -+ * @mode: Last mode setting for the @spcon field. -+ * @spcon: Value to write to the SPCON register. -+ * @sppre: Value to write to the SPIINT register. -+ */ -+struct ak_spi_devstate { -+ unsigned int hz; -+ u16 mode; -+ u32 spcon; -+ u8 spint; -+ u8 initialed; -+}; -+ -+struct ak_spi { -+ /* bitbang has to be first */ -+ struct spi_bitbang bitbang; -+ struct completion done; -+ struct spi_master *master; -+ struct spi_device *curdev; -+ struct device *dev; -+ struct ak_spi_info *pdata; -+ -+ void __iomem *regs; -+ struct clk *clk; -+ struct resource *ioarea; -+ int irq; -+ int len; /*need transfer len*/ -+ int count; /*have transferred len*/ -+ -+ u8 l2buf_tid; -+ u8 l2buf_rid; -+ -+ /* data buffers */ -+ unsigned char *tx; -+ unsigned char *rx; -+ int xfer_dir; -+ int xfer_mode; /*use for dma or cpu*/ -+}; -+ -+enum spi_xfer_dir { -+ SPI_DIR_TX, -+ SPI_DIR_RX, -+ SPI_DIR_TXRX, -+ SPI_DIR_XFER_NUM, -+}; -+ -+ -+#define TRANS_TIMEOUT (10000) -+#define MAX_XFER_LEN (8*1024) -+#define SPI_TRANS_TIMEOUT (5000) -+ -+#define DFT_CON (AK_SPICON_EN | AK_SPICON_MS) -+#define DFT_DIV (1) //5 /*127*/ -+#define DFT_BIT_PER_WORD (8) -+#define FORCE_CS (1 << 5) -+#define SPPIN_DEFAULT (0) -+ -+#if 1 -+/** -+* @brief print the value of registers related spi bus. -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *hw -+* @return void -+*/ -+static void dbg_dumpregs(struct ak_spi *hw) -+{ -+ PDEBUG("\n"); -+ PDEBUG("CON: \t0x%x\n", ioread32(hw->regs + AK_SPICON)); -+ PDEBUG("STA: \t0x%x\n", ioread32(hw->regs + AK_SPISTA)); -+ PDEBUG("INT: \t0x%x\n", ioread32(hw->regs + AK_SPIINT)); -+ PDEBUG("CNT: \t0x%x\n", ioread32(hw->regs + AK_SPICNT)); -+ PDEBUG("DOUT: \t0x%x\n", ioread32(hw->regs + AK_SPIOUT)); -+ PDEBUG("DIN: \t0x%x\n", ioread32(hw->regs + AK_SPIIN)); -+} -+ -+static inline void dbg_dumpdata(struct ak_spi *hw, -+ void *data, int size) -+{ -+ int ii; -+ int dsize = (size +3)/4; -+ u32 *dptr = data; -+ -+ printk("xfer data (size:%d):", size); -+ -+ for(ii = 0; ii < dsize; ii++) { -+ if((ii%10) == 0) -+ printk("\n"); -+ -+ printk("%08x ", *(dptr + ii)); -+ } -+ printk("\n"); -+} -+#endif -+ -+ -+#define AKSPI_DATA_WIRE(mode) \ -+ (((mode & XFER_4DATAWIRE) == XFER_4DATAWIRE) ? \ -+ AKSPI_4DATAWIRE:((mode & XFER_2DATAWIRE) == XFER_2DATAWIRE) ? \ -+ AKSPI_2DATAWIRE : AKSPI_1DATAWIRE) -+ -+ -+#define SPI_L2_TXADDR(m) \ -+ ((m->bus_num == AKSPI_BUS_NUM1) ? ADDR_SPI1_TX : ADDR_SPI2_TX) -+ -+#define SPI_L2_RXADDR(m) \ -+ ((m->bus_num == AKSPI_BUS_NUM1) ? ADDR_SPI1_RX : ADDR_SPI2_RX) -+ -+ -+#define SPI_SHAREPIN(m) \ -+ ((m->bus_num == AKSPI_BUS_NUM1) ? ePIN_AS_SPI1 : ePIN_AS_SPI2) -+ -+#define SPI_RESET_NUM(m) \ -+ ((m->bus_num == AKSPI_BUS_NUM1) ? AK39_SRESET_SPI1 : AK39_SRESET_SPI2) -+ -+ -+static inline struct ak_spi *to_hw(struct spi_device *sdev) -+{ -+ return spi_master_get_devdata(sdev->master); -+} -+ -+/** -+* @brief hw_txbyte -+* TODO: send one bytes -+* @author lixinhai -+* @date 2013-03-19 -+* @param[in] *hw -+* @param[in] count -+* @return unsigned int -+*/ -+static inline unsigned int hw_txbyte(struct ak_spi *hw, int len) -+{ -+ u32 val = 0; -+ int i = 0; -+ -+ while (i < len) -+ { -+ val |= (hw->tx[hw->count+i] << i*8); -+ i++; -+ } -+ return val; -+} -+ -+/** -+* @brief hw_txdword -+* TODO: send double words -+* @author lixinhai -+* @date 2013-03-19 -+* @param[in] *hw -+* @param[in] count -+* @return unsigned int -+*/ -+static unsigned int hw_txdword(struct ak_spi *hw) -+{ -+ u32 val = 0; -+ int l = 0; -+ -+ l = (hw->len - hw->count) > 4 ? 4 : (hw->len - hw->count); -+ -+ val = hw_txbyte(hw, l); -+ -+ hw->count += l; -+ PDEBUG("[%08x] ", val); -+ return val; -+} -+ -+/** -+* @brief hw_rxbyte -+* TODO: recv one bytes -+* @author lixinhai -+* @date 2013-03-19 -+* @param[in] count -+* @return unsigned int -+*/ -+static inline void hw_rxbyte(struct ak_spi *hw, unsigned int val, int len) -+{ -+ int i = 0; -+ -+ while (i < len) -+ { -+ hw->rx[hw->count + i] = (val >> i*8) & 0xff; -+ i++; -+ } -+} -+ -+/** -+* @brief hw_rxbyte -+* TODO: double words -+* @author lixinhai -+* @date 2013-03-19 -+* @param[in] count -+* @return unsigned int -+*/ -+static void hw_rxdword(struct ak_spi *hw, unsigned int val) -+{ -+ int l = 0; -+ -+ l = (hw->len - hw->count) > 4 ? 4 : (hw->len - hw->count); -+ -+ hw_rxbyte(hw, val, l); -+ hw->count += l; -+ PDEBUG("[%08x] ", val); -+} -+ -+static inline u32 hw_remain_datalen(struct ak_spi *hw) -+{ -+ return (hw->len - hw->count); -+} -+ -+static inline bool ak_spi_use_dma(struct ak_spi *hw) -+{ -+ return (hw->xfer_mode == AKSPI_XFER_MODE_DMA); -+} -+ -+static inline int wait_for_spi_cnt_to_zero(struct ak_spi *hw, u32 timeout) -+{ -+ do { -+ if (readl(hw->regs + AK_SPICNT) == 0) -+ break; -+ udelay(1); -+ }while(timeout--); -+ -+ return (timeout > 0) ? 0 : -EBUSY; -+} -+ -+ -+static void ak_spi_gpio_setup(struct ak_spi *hw, int enable) -+{ -+ struct ak_spi_info *plat = hw->pdata; -+ -+ if(!plat) -+ return; -+ -+ if (enable) -+ { -+ int ii; -+ ak_group_config(SPI_SHAREPIN(hw->master)); -+ -+ for(ii=0; ii<plat->num_cs; ii++) { -+ if(ii == AKSPI_ONCHIP_CS) -+ continue; -+ -+ ak_setpin_as_gpio(plat->pin_cs[ii]); -+ ak_gpio_dircfg(plat->pin_cs[ii], AK_GPIO_DIR_OUTPUT); -+ ak_gpio_setpin(plat->pin_cs[ii], 1); -+ } -+ } -+} -+ -+static void ak_spi_set_cs(struct ak_spi *hw, int cs, int pol) -+{ -+ struct ak_spi_info *plat = hw->pdata; -+ -+ if(!plat) -+ return; -+ -+ BUG_ON(cs >= plat->num_cs); -+ -+ ak_gpio_setpin(plat->pin_cs[cs], pol); -+} -+ -+ -+ -+/** -+* @brief ak_spi_chipsel -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[out] *spi -+* @param[in] value -+* @return void -+*/ -+static void ak_spi_chipsel(struct spi_device *spi, int value) -+{ -+ struct ak_spi_devstate *cs = spi->controller_state; -+ struct ak_spi *hw = to_hw(spi); -+ unsigned int cspol = (spi->mode & SPI_CS_HIGH) ? 1 : 0; -+ -+ /* change the chipselect state and the state of the spi engine clock */ -+ switch (value) { -+ case BITBANG_CS_INACTIVE: -+ PDEBUG("BITBANG_CS_INACTIVE\n"); -+ -+ if(spi->chip_select == AKSPI_ONCHIP_CS) { -+ cs->spcon = ioread32(hw->regs + AK_SPICON); -+ cs->spcon &= ~FORCE_CS; -+ iowrite32(cs->spcon, hw->regs + AK_SPICON); -+ } -+ else -+ ak_spi_set_cs(hw, spi->chip_select, cspol^1); -+ -+ break; -+ case BITBANG_CS_ACTIVE: -+ PDEBUG("BITBANG_CS_ACTIVE"); -+ -+ if(spi->chip_select == AKSPI_ONCHIP_CS) { -+ cs->spcon = ioread32(hw->regs + AK_SPICON); -+ cs->spcon |= FORCE_CS; //by Shaohua -+ iowrite32(cs->spcon, hw->regs + AK_SPICON); -+ } -+ else -+ ak_spi_set_cs(hw, spi->chip_select, cspol); -+ -+ break; -+ default: -+ break; -+ } -+} -+ -+/** -+* @brief update the device's state -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *spi -+* @param[in] *t -+* @return int -+*/ -+static int ak_spi_update_state(struct spi_device *spi, -+ struct spi_transfer *t) -+{ -+ struct ak_spi_devstate *cs = spi->controller_state; -+ unsigned int bpw; -+ unsigned int hz, typical_hz; -+ unsigned int div = 0; -+ unsigned long clk; -+ -+ bpw = t ? t->bits_per_word : spi->bits_per_word; -+ typical_hz = t ? t->speed_hz : spi->max_speed_hz; -+ -+ if (!bpw) -+ bpw = DFT_BIT_PER_WORD; -+ -+ if (bpw != DFT_BIT_PER_WORD) { -+ dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw); -+ return -EINVAL; -+ } -+ -+ /*spi mode change, config again*/ -+ if (spi->mode != cs->mode) { -+ cs->spcon &= ~(AK_SPICON_CPHA|AK_SPICON_CPOL); -+ -+ if ((spi->mode & SPI_CPHA) == SPI_CPHA) -+ cs->spcon |= AK_SPICON_CPHA; -+ -+ if ((spi->mode & SPI_CPOL) == SPI_CPOL) -+ cs->spcon |= AK_SPICON_CPOL; -+ -+ cs->mode = spi->mode; -+ } -+ -+ if (cs->hz != typical_hz) { -+ if (!typical_hz) -+ typical_hz = spi->max_speed_hz; -+ -+ clk = ak_get_asic_clk(); -+ div = clk / (typical_hz*2) - 1; -+ -+ if (div > 255) -+ div = 255; -+ -+ if (div < 0) -+ div = 0; -+ -+ hz = clk /((div+1)*2); -+ -+ /*when got clock greater than wanted clock, increase divider*/ -+ if((hz - typical_hz) > 0) -+ div++; -+ -+ printk("pre-scaler=%d (wanted %ldMhz, got %ldMhz)\n", -+ div, typical_hz/MHz, (clk / (2 * (div + 1)))/MHz); -+ -+ cs->hz = hz; -+ cs->spcon &= ~AK_SPICON_CLKDIV; -+ cs->spcon |= div << 8; -+ } -+ PDEBUG("spi new hz is %u, div is %u(%s).\n", cs->hz, div, div ?"change":"not change"); -+ return 0; -+} -+ -+/** -+* @brief setup one transfer -+* setup_transfer() changes clock and/or wordsize to match settings -+* for this transfer; zeroes restore defaults from spi_device. -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *spi -+* @param[in] *t -+* @return int -+*/ -+static int ak_spi_setupxfer(struct spi_device *spi, -+ struct spi_transfer *t) -+{ -+ struct ak_spi_devstate *cs = spi->controller_state; -+ struct ak_spi *hw = to_hw(spi); -+ int ret=0; -+ -+ /*spi device not change and has been initilize, return.*/ -+ if(likely((cs->initialed == 1) && (spi == hw->curdev))) -+ return ret; -+ -+ cs->spcon = readl(hw->regs + AK_SPICON); -+ -+ ret = ak_spi_update_state(spi, t); -+ if (!ret) -+ { -+ /*Add code to fix the issue that the SPICON register -+ was deranged. Shaohua @2012-3-23 -+ */ -+ writel(cs->spcon, hw->regs + AK_SPICON); -+ printk("ak_spi_setupxfer,con:%08x.\n", cs->spcon); -+ cs->initialed = 1; -+ hw->curdev = spi; -+ } -+ -+ return ret; -+} -+ -+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) -+ -+/** -+* @brief ak_spi_setup -+* updates the device mode and clocking records used by a -+* device's SPI controller; -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *spi -- Master side proxy -+* @return int -- return 0 on success -+*/ -+static int ak_spi_setup(struct spi_device *spi) -+{ -+ struct ak_spi_devstate *cs = spi->controller_state; -+ struct ak_spi *hw = to_hw(spi); -+ int ret; -+ -+ printk("ak_spi setup the master.\n"); -+ -+ /* allocate settings on the first call */ -+ if (!cs) { -+ cs = kzalloc(sizeof(struct ak_spi_devstate), GFP_KERNEL); -+ if (!cs) { -+ dev_err(&spi->dev, "no memory for controller state\n"); -+ return -ENOMEM; -+ } -+ -+ cs->spcon = DFT_CON; -+ cs->hz = -1; -+ spi->controller_state = cs; -+ cs->initialed = 0; -+ } -+ -+ if (spi->mode & ~(hw->pdata->mode_bits)) { -+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", -+ spi->mode & ~(hw->pdata->mode_bits)); -+ return -EINVAL; -+ } -+ /* initialise the state from the device */ -+ ret = ak_spi_update_state(spi, NULL); -+ if (ret) -+ return ret; -+ -+ spin_lock(&hw->bitbang.lock); -+ if (!hw->bitbang.busy) { -+ hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); -+ /* need to ndelay for 0.5 clocktick ? */ -+ } -+ spin_unlock(&hw->bitbang.lock); -+ -+ return 0; -+} -+ -+/** -+* @brief ak_spi_cleanup -+* called on to free memory provided by spi_master -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[out] *spi -+* @return void -+*/ -+static void ak_spi_cleanup(struct spi_device *spi) -+{ -+ kfree(spi->controller_state); -+} -+ -+ -+/** -+* @brief enable the irq mask. -+* @author lixinhai -+* @date 2013-03-10 -+* @param[in] *hw :akspi master dev. -+* @param[in] imask: interrupt bit mask. -+* @return new mask. -+*/ -+static inline u32 enable_imask(struct ak_spi *hw, u32 imask) -+{ -+ u32 newmask; -+ -+ newmask = readl(hw->regs + AK_SPIINT); -+ newmask |= imask; -+ -+ writel(newmask, hw->regs + AK_SPIINT); -+ -+ return newmask; -+} -+ -+ -+/** -+* @brief disable the irq mask. -+* @author lixinhai -+* @date 2013-03-10 -+* @param[in] *hw :akspi master dev. -+* @param[in] imask: interrupt bit mask. -+* @return new mask. -+*/ -+static inline u32 disable_imask(struct ak_spi *hw, u32 imask) -+{ -+ u32 newmask; -+ -+ newmask = readl(hw->regs + AK_SPIINT); -+ newmask &= ~imask; -+ -+ writel(newmask, hw->regs + AK_SPIINT); -+ -+ return newmask; -+} -+ -+ -+/** -+* @brief configure the master register when start transfer data. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] t: a read/write buffer pair. -+* @return void -+*/ -+static void ak_spi_start_txrx(struct ak_spi *hw, struct spi_transfer *t) -+{ -+ u32 reg_value; -+ enum spi_xfer_dir dir = hw->xfer_dir; -+ -+ PDEBUG("the spi transfer mode is %s.\n", (dir == SPI_DIR_TXRX) ? -+ "txrx" : (dir == SPI_DIR_RX)? "rx":"tx"); -+ -+ reg_value = readl(hw->regs + AK_SPICON); -+ -+ switch(dir) { -+ case SPI_DIR_TX: -+ reg_value &= ~AK_SPICON_TGDM; -+ reg_value |= AK_SPICON_ARRM; -+ break; -+ case SPI_DIR_RX: -+ reg_value |= AK_SPICON_TGDM; -+ reg_value &= ~AK_SPICON_ARRM; -+ break; -+ case SPI_DIR_TXRX: -+ reg_value &= ~AK_SPICON_TGDM; -+ reg_value &= ~AK_SPICON_ARRM; -+ break; -+ default: -+ break; -+ } -+ -+ /*configure the data wire*/ -+ reg_value &= ~AK_SPICON_WIRE; -+ reg_value |= AKSPI_DATA_WIRE(t->xfer_mode); -+ -+ writel(reg_value, hw->regs + AK_SPICON); -+} -+ -+ -+/** -+* @brief configure the master register when stop transfer data. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] t: a read/write buffer pair. -+* @return void -+*/ -+static void ak_spi_stop_txrx(struct ak_spi *hw, struct spi_transfer *t) -+{ -+ u32 reg_value; -+ -+ reg_value = readl(hw->regs + AK_SPICON); -+ reg_value &= ~AK_SPICON_WIRE; -+ writel(reg_value, hw->regs + AK_SPICON); -+} -+ -+ -+/** -+* @brief spi write data function by l2dma/l2cpu mode. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] buf: transfer data pointer. -+* @param[in] count: transfer data length. -+* @return transfer success result 0, otherwise result a negative value -+*/ -+static int spi_dma_write(struct ak_spi *hw, unsigned char *buf, int count) -+{ -+ int ret = 0; -+ bool flags = false; -+ u32 val; -+ dma_addr_t phyaddr = 0; -+ -+ init_completion(&hw->done); -+ enable_imask(hw, AK_SPIINT_TRANSF); -+ -+ val = AK_SPIEXTX_BUFEN|AK_SPIEXTX_DMAEN; -+ iowrite32(val, hw->regs + AK_SPIEXTX); -+ iowrite32(count, hw->regs + AK_SPICNT); -+ -+ /*use for dma mode: greater than 256 bytes, align 4bytes of buf addr, -+ align 64 bytes of data count*/ -+ if((count < 256) || ((unsigned long)buf & 0x3) || (count & (64 - 1))) { -+ l2_combuf_cpu((unsigned long)buf, hw->l2buf_tid, count, MEM2BUF); -+ -+ } else { -+ phyaddr = dma_map_single(hw->dev, buf, count, DMA_TO_DEVICE); -+ if (phyaddr == 0) { -+ printk("tx dma_map_single error!\n"); -+ ret = -EINVAL; -+ goto wr_exit; -+ } -+ -+ //start l2 dma transmit -+ l2_combuf_dma(phyaddr, hw->l2buf_tid, count, MEM2BUF, AK_FALSE); -+ flags = true; -+ } -+ -+ ret = wait_for_completion_timeout(&hw->done, msecs_to_jiffies(SPI_TRANS_TIMEOUT)); -+ if(ret <= 0) { -+ printk("wait for spi transfer interrupt timeout(%s).\n", __func__); -+ dbg_dumpregs(hw); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ if (flags && (l2_combuf_wait_dma_finish(hw->l2buf_tid) == AK_FALSE)) { -+ printk("%s: l2_combuf_wait_dma_finish failed!\n", __func__); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ ret = wait_for_spi_cnt_to_zero(hw, TRANS_TIMEOUT); -+ if(ret) { -+ printk("%s: wait_for_spi_cnt_to_zero failed!\n", __func__); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ ret = count; -+xfer_fail: -+ if(phyaddr) -+ dma_unmap_single(hw->dev, phyaddr, count, DMA_TO_DEVICE); -+ -+wr_exit: -+ //disable l2 dma -+ iowrite32(0, hw->regs + AK_SPIEXTX); -+ l2_clr_status(hw->l2buf_tid); -+ return ret; -+} -+ -+ -+/** -+* @brief spi read data function by l2dma/l2cpu mode. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] buf: transfer data pointer. -+* @param[in] count: transfer data length. -+* @return transfer success result 0, otherwise result a negative value -+*/ -+static int spi_dma_read(struct ak_spi *hw, unsigned char *buf, int count) -+{ -+ int ret = 0; -+ bool flags = false; -+ u32 val; -+ dma_addr_t phyaddr = 0; -+ -+ //prepare spi read -+ init_completion(&hw->done); -+ enable_imask(hw, AK_SPIINT_TRANSF); -+ -+ val = AK_SPIEXTX_BUFEN|AK_SPIEXTX_DMAEN; -+ iowrite32(val, hw->regs + AK_SPIEXRX); -+ iowrite32(count, hw->regs + AK_SPICNT); -+ -+ if(count < 256 || ((unsigned long)buf & 0x3) || (count & (64 - 1))) { -+ l2_combuf_cpu((unsigned long)buf, hw->l2buf_rid, count, BUF2MEM); -+ } -+ else { -+ phyaddr = dma_map_single(hw->dev, buf, count, DMA_FROM_DEVICE); -+ if (phyaddr == 0) { -+ printk("tx dma_map_single error!\n"); -+ ret = -EINVAL; -+ goto rd_exit; -+ } -+ -+ //start L2 dma -+ l2_combuf_dma(phyaddr, hw->l2buf_rid, count, BUF2MEM, AK_FALSE); -+ flags = true; -+ } -+ -+ ret = wait_for_completion_timeout(&hw->done, msecs_to_jiffies(SPI_TRANS_TIMEOUT)); -+ if(ret <= 0) { -+ printk("wait for spi transfer interrupt timeout(%s).\n", __func__); -+ dbg_dumpregs(hw); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ //wait L2 dma finish, if need frac dma,start frac dma -+ if (flags && l2_combuf_wait_dma_finish(hw->l2buf_rid) == AK_FALSE) { -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ /*wait for spi count register value to zero.*/ -+ ret = wait_for_spi_cnt_to_zero(hw, TRANS_TIMEOUT); -+ if(ret) { -+ printk("%s: wait for spi count to zero failed!\n", __func__); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ ret = count; -+xfer_fail: -+ if(phyaddr) -+ dma_unmap_single(hw->dev, phyaddr, count, DMA_FROM_DEVICE); -+ -+rd_exit: -+ //disable l2 dma -+ iowrite32(0, hw->regs + AK_SPIEXRX); -+ l2_clr_status(hw->l2buf_rid); -+ return ret; -+} -+ -+ -+/** -+* @brief spi transfer function by l2dma/l2cpu mode. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] tx: send data pointer. -+* @param[in] rx: receive data pointer. -+* @param[in] count: transfer data length. -+* @return transfer success result 0, otherwise result a negative value -+*/ -+static int spi_dma_duplex(struct ak_spi *hw, -+ unsigned char *tx, unsigned char *rx, int count) -+{ -+ int ret = 0; -+ bool flags = false; -+ dma_addr_t tx_phyaddr, rx_phyaddr; -+ u32 val; -+ -+ init_completion(&hw->done); -+ enable_imask(hw, AK_SPIINT_TRANSF); -+ -+ val = AK_SPIEXTX_BUFEN|AK_SPIEXTX_DMAEN; -+ iowrite32(val, hw->regs + AK_SPIEXTX); -+ -+ val = AK_SPIEXRX_BUFEN|AK_SPIEXRX_DMAEN; -+ iowrite32(val, hw->regs + AK_SPIEXRX); -+ -+ iowrite32(count, hw->regs + AK_SPICNT); -+ -+ if((count < 512) || ((unsigned long)tx & 0x3)) { -+ //printk("write: l2_combuf_cpu\n"); -+ l2_combuf_cpu((unsigned long)tx, hw->l2buf_tid, count, MEM2BUF); -+ l2_combuf_cpu((unsigned long)rx, hw->l2buf_rid, count, BUF2MEM); -+ } -+ else { -+ tx_phyaddr = dma_map_single(hw->dev, tx, count, DMA_TO_DEVICE); -+ if (tx_phyaddr == 0) { -+ printk("tx dma_map_single error!\n"); -+ ret = -EINVAL; -+ goto wr_fail; -+ } -+ -+ //start l2 dma transmit -+ l2_combuf_dma(tx_phyaddr, hw->l2buf_tid, count, MEM2BUF, AK_FALSE); -+ -+ rx_phyaddr = dma_map_single(hw->dev, rx, count, DMA_FROM_DEVICE); -+ if (rx_phyaddr == 0) { -+ printk("tx dma_map_single error!\n"); -+ ret = -EINVAL; -+ goto rd_fail; -+ } -+ -+ //start L2 dma -+ l2_combuf_dma(rx_phyaddr, hw->l2buf_rid, count, BUF2MEM, AK_FALSE); -+ } -+ ret = wait_for_completion_timeout(&hw->done, msecs_to_jiffies(SPI_TRANS_TIMEOUT)); -+ if(ret <= 0) { -+ printk("wait for spi transfer interrupt timeout(%s).\n", __func__); -+ dbg_dumpregs(hw); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ if (flags && ((AK_FALSE == l2_combuf_wait_dma_finish(hw->l2buf_tid)) || -+ (AK_FALSE == l2_combuf_wait_dma_finish(hw->l2buf_rid)))) -+ { -+ printk("%s: l2_combuf_wait_dma_finish failed!\n", __func__); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ ret = wait_for_spi_cnt_to_zero(hw, TRANS_TIMEOUT); -+ if(ret) { -+ printk("%s: wait for spi count to zero failed!\n", __func__); -+ ret = -EINVAL; -+ goto xfer_fail; -+ } -+ -+ ret = 0; -+ -+xfer_fail: -+ dma_unmap_single(hw->dev, rx_phyaddr, count, DMA_FROM_DEVICE); -+ -+rd_fail: -+ dma_unmap_single(hw->dev, tx_phyaddr, count, DMA_TO_DEVICE); -+ -+wr_fail: -+ //disable l2 dma -+ iowrite32(0, hw->regs + AK_SPIEXTX); -+ iowrite32(0, hw->regs + AK_SPIEXRX); -+ l2_clr_status(hw->l2buf_tid); -+ l2_clr_status(hw->l2buf_rid); -+ return ret; -+} -+ -+ -+/** -+* @brief spi transfer function by l2dma/l2cpu mode, actual worker -+* spi_dma_read()/spi_dma_write() to be call. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] dir: transfer direction. -+* @return transfer success result 0, otherwise result a negative value -+*/ -+static int ak_spi_dma_txrx(struct ak_spi *hw, struct spi_transfer *t) -+{ -+ int ret = 0; -+ u32 retlen; -+ u32 count = t->len; -+ -+ hw->tx = (unsigned char*)t->tx_buf; -+ hw->rx = t->rx_buf; -+ hw->l2buf_tid = hw->l2buf_rid = BUF_NULL; -+ PDEBUG("start the spi dma transfer.\n"); -+ -+ switch(hw->xfer_dir) { -+ case SPI_DIR_TXRX: -+ { -+ //alloc L2 buffer -+ hw->l2buf_tid = l2_alloc(SPI_L2_TXADDR(hw->master)); -+ hw->l2buf_rid = l2_alloc(SPI_L2_RXADDR(hw->master)); -+ -+ if ((BUF_NULL == hw->l2buf_tid) || (BUF_NULL == hw->l2buf_rid)) -+ { -+ printk("%s: l2_alloc failed!\n", __func__); -+ ret = -EBUSY; -+ goto txrx_ret; -+ } -+ -+ while(count > 0) { -+ hw->count = 0; -+ hw->len = (count > MAX_XFER_LEN) ? MAX_XFER_LEN : count; -+ -+ retlen = spi_dma_duplex(hw, hw->tx, hw->rx, hw->len); -+ if(unlikely(retlen < 0)) { -+ printk("spi master transfer data error!\n"); -+ ret = -EBUSY; -+ goto txrx_ret; -+ } -+ hw->tx += retlen; -+ hw->rx += retlen; -+ count -= retlen; -+ } -+ break; -+ } -+ case SPI_DIR_TX: -+ { -+ //alloc L2 buffer -+ hw->l2buf_tid = l2_alloc(SPI_L2_TXADDR(hw->master)); -+ if (unlikely(BUF_NULL == hw->l2buf_tid)) { -+ printk("%s: l2_alloc failed!\n", __func__); -+ return -EBUSY; -+ } -+ -+ while(count > 0) { -+ hw->count = 0; -+ hw->len = (count > MAX_XFER_LEN) ? MAX_XFER_LEN : count; -+ -+ retlen = spi_dma_write(hw, hw->tx + hw->count, hw->len); -+ if(unlikely(retlen < 0)) { -+ printk("spi master read data error!\n"); -+ ret = -EBUSY; -+ goto txrx_ret; -+ } -+ hw->tx += retlen; -+ count -= retlen; -+ } -+ break; -+ } -+ case SPI_DIR_RX: -+ { -+ //alloc L2 buffer -+ hw->l2buf_rid = l2_alloc(SPI_L2_RXADDR(hw->master)); -+ if (unlikely(BUF_NULL == hw->l2buf_rid)) -+ { -+ return -EBUSY; -+ } -+ -+ while(count > 0) { -+ hw->count = 0; -+ hw->len = (count > MAX_XFER_LEN) ? MAX_XFER_LEN : count; -+ -+ retlen = spi_dma_read(hw, hw->rx, hw->len); -+ if(unlikely(retlen < 0)) { -+ printk("spi master read data error!\n"); -+ ret = -EBUSY; -+ goto txrx_ret; -+ } -+ hw->rx += retlen; -+ count -= retlen; -+ } -+ break; -+ } -+ } -+ PDEBUG("finish the spi dma transfer.\n"); -+txrx_ret: -+ if(hw->l2buf_tid != BUF_NULL) -+ l2_free(SPI_L2_TXADDR(hw->master)); -+ if(hw->l2buf_rid != BUF_NULL) -+ l2_free(SPI_L2_RXADDR(hw->master)); -+ -+ return ret ? ret : t->len; -+} -+ -+ -+/** -+* @brief spi read/write data function by cpu mode, -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] t: a read/write buffer pair. -+* @return transfer success result 0, otherwise result a negative value -+*/ -+static int ak_cpu_duplex(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct ak_spi *hw = to_hw(spi); -+ u32 tran_4_nbr = hw->len/4; -+ u32 frac_nbr = hw->len%4; -+ u32 status, val; -+ u32 off_set_read = 0, off_set_write = 0; -+ const u8 *buff_tx; -+ u8 *buff_rx; -+ int i = 0, j; -+ u32 to_read = 0, to_write = 0; //, to = 0; -+ -+ hw->tx = (unsigned char*)t->tx_buf; -+ hw->rx = t->rx_buf; -+ -+ buff_tx = hw->tx; -+ buff_rx = hw->rx; -+ -+ PDEBUG("duplex transfer,tran_4_nbr:%u frac_nbr:%u\n", tran_4_nbr, frac_nbr); -+ -+ if (hw->len >= MAX_XFER_LEN) -+ { -+ printk("Too much to be read and send...\n"); -+ return -EINVAL; -+ } -+ -+ //set data count, and the the master will rise clk -+ writel(hw->len, hw->regs + AK_SPICNT); -+ -+ while(1) { -+ //write 4 bytes first, and then read 4 bytes -+ if (i<tran_4_nbr) { -+ while(1) { -+ status = ioread32(hw->regs + AK_SPISTA); -+ if ((status & AK_SPISTA_TXHEMP) == AK_SPISTA_TXHEMP) { -+ PDEBUG("TX HEMP...\n"); -+ break; -+ } else { -+ if(to_write++ < TRANS_TIMEOUT) -+ udelay(10); -+ else { -+ PDEBUG("master transfer timeout...\n"); -+ goto SPI_TRANS_FAIL; -+ } -+ } -+ } -+ iowrite32(*(volatile u32 *)(buff_tx + off_set_write), hw->regs + AK_SPIOUT); -+ off_set_write += 4; -+ i++; -+ } -+ //write not finished -+ else if (off_set_write < hw->len) { -+ PDEBUG("write frac...\n"); -+ to_write = 0; -+ val = 0; -+ if (frac_nbr != 0) { -+ while(1) { -+ status = ioread32(hw->regs + AK_SPISTA); -+ if ((status & AK_SPISTA_TXHEMP) == AK_SPISTA_TXHEMP) -+ break; -+ if (to_write++ < TRANS_TIMEOUT) -+ udelay(10); -+ else { -+ printk("SPI master write timeout...\n"); -+ goto SPI_TRANS_FAIL; -+ } -+ } -+ -+ for (j=0; j<frac_nbr; j++) -+ { -+ PDEBUG("[%d]:%x ", off_set_write+j, *(buff_tx+off_set_write+j)); -+ val |= (*(buff_tx + off_set_write + j) << (j*8)); -+ } -+ PDEBUG("\nval: %x", val); -+ PDEBUG("\n\n"); -+ -+ iowrite32(val, hw->regs + AK_SPIOUT); -+ off_set_write += frac_nbr; -+ } -+ } -+ -+ //read -+ status = ioread32(hw->regs + AK_SPISTA); -+ -+ if ((status & AK_SPISTA_TRANSF) == AK_SPISTA_TRANSF) { -+ if (status & AK_SPISTA_RXFULL) { -+ val = ioread32(hw->regs + AK_SPIIN); -+ *(volatile u32 *)(buff_rx + off_set_read) = val; -+ off_set_read += 4; -+ -+ val = ioread32(hw->regs + AK_SPIIN); -+ *(volatile u32 *)(buff_rx + off_set_read) = val; -+ off_set_read += 4; -+ -+ } else if (status & AK_SPISTA_RXHFULL) { -+ -+ val = ioread32(hw->regs + AK_SPIIN); -+ *(volatile u32 *)(buff_rx + off_set_read) = val; -+ off_set_read += 4; -+ } -+ if (frac_nbr != 0) { -+ PDEBUG("read frac...\n"); -+ val = ioread32(hw->regs + AK_SPIIN); -+ -+ for (j=0; j<frac_nbr; j++) -+ { -+ *(buff_rx+off_set_read+j) = (val >> j*8) & 0xff; -+ PDEBUG("%x ", *(buff_rx+off_set_read+j)); -+ } -+ } -+ break; -+ } else { -+ if ( (status & AK_SPISTA_RXHFULL) == AK_SPISTA_RXHFULL) { -+ val = ioread32(hw->regs + AK_SPIIN); -+ *(volatile u32 *)(buff_rx + off_set_read) = val; -+ PDEBUG("rx hfull .. %x\n", val); -+ PDEBUG("[0]%x [1]%x [2]%x [3]%x\n", buff_rx[0], buff_rx[1], buff_rx[2], buff_rx[3]); -+ off_set_read += 4; -+ } else { -+ if (to_read++ < TRANS_TIMEOUT) -+ udelay(10); -+ else { -+ PDEBUG("master read timeout...\n"); -+ goto SPI_READ_TIMEOUT; -+ } -+ } -+ } -+ } -+ -+ return hw->len; -+ -+SPI_TRANS_FAIL: -+SPI_READ_TIMEOUT: -+ return off_set_read > off_set_write ? off_set_read: off_set_write; -+ -+} -+ -+ -+#if defined(SPI_CPU_MODE_USE_INTERRUPT) -+static int pio_imasks[SPI_DIR_XFER_NUM] = { -+ AK_SPIINT_TRANSF | AK_SPIINT_TXHEMP, -+ AK_SPIINT_TRANSF | AK_SPIINT_RXHFULL, -+ AK_SPIINT_TXHEMP | AK_SPIINT_RXHFULL, -+}; -+ -+ -+/** -+* @brief spi transfer function by cpu mode. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] dir: transfer direction. -+* @return transfer success result 0, otherwise result a negative value -+*/ -+static int ak_spi_pio_txrx(struct ak_spi *hw, struct spi_transfer *t) -+{ -+ int ret; -+ -+ init_completion(&hw->done); -+ -+ writel(hw->len, hw->regs + AK_SPICNT); -+ enable_imask(hw, pio_imasks[hw->xfer_dir]); -+ -+ ret = wait_for_completion_timeout(&hw->done, msecs_to_jiffies(SPI_TRANS_TIMEOUT)); -+ if(ret <= 0) { -+ printk("wait for spi transfer interrupt timeout(%s).\n", __func__); -+ dbg_dumpregs(hw); -+ return -EINVAL; -+ } -+ -+ return hw->count; -+} -+#else -+ -+ -+/** -+* @brief ak37_spi_writeCPU -+* send message function with CPU mode and polling mode -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *spi -+* @param[in] *t -+* @return int -+*/ -+static int spi_pio_write(struct ak_spi *hw, unsigned char *buf, int count) -+{ -+ u32 status; -+ u32 to = 0; -+ -+ PDEBUG("ak spi write by cpu mode\n"); -+ if (count > 64*1024) -+ { -+ printk("too much to be send...\n"); -+ return -EINVAL; -+ } -+ //set data count, and the the master will rise clk -+ writel(count, hw->regs + AK_SPICNT); -+ -+ while(hw_remain_datalen(hw) > 0) { -+ status = readl(hw->regs + AK_SPISTA); -+ if ((status & AK_SPISTA_TXHEMP) == AK_SPISTA_TXHEMP) { -+ writel(hw_txdword(hw), hw->regs + AK_SPIOUT); -+ }else { -+ if (to++ > 10 * 1000000) { -+ printk("master write data timeout.\n"); -+ return hw->count; -+ } -+ } -+ } -+ -+ //wait transfer finish -+ while(1) { -+ status = readl(hw->regs + AK_SPISTA); -+ if ((status & AK_SPISTA_TRANSF) == AK_SPISTA_TRANSF) -+ break; -+ -+ if (to++ > 10 * 1000000) { -+ printk("wait for write data finish timeout..\n"); -+ return hw->count; -+ } -+ } -+ -+ if (hw_remain_datalen(hw) > 0) -+ printk("write wasn't finished.\n"); -+ -+ return hw->count; -+} -+ -+/** -+* @brief spi_pio_read -+* receiving message function with CPU mode and polling mode -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *spi -+* @param[in] *t -+* @return int -+*/ -+static int spi_pio_read(struct ak_spi *hw, unsigned char *buf, int count) -+{ -+ u32 status; -+ u32 to=0; -+ -+ PDEBUG("ak spi read by cpu mode\n"); -+ if (count >= 64*1024) -+ { -+ printk("too much to be read...\n"); -+ return -EINVAL; -+ } -+ -+ //set data count, and the the master will rise clk -+ writel(count, hw->regs + AK_SPICNT); -+ -+ while(1) { -+ status = readl(hw->regs + AK_SPISTA); -+ -+ if((status & AK_SPISTA_TRANSF) == AK_SPISTA_TRANSF) -+ { -+ if(status & AK_SPISTA_RXFULL) { -+ hw_rxdword(hw, readl(hw->regs + AK_SPIIN)); -+ hw_rxdword(hw, readl(hw->regs + AK_SPIIN)); -+ }else if (status & AK_SPISTA_RXHFULL) { -+ hw_rxdword(hw, readl(hw->regs + AK_SPIIN)); -+ } -+ -+ if (hw_remain_datalen(hw) > 0) { -+ hw_rxdword(hw, readl(hw->regs + AK_SPIIN)); -+ } -+ break; -+ } else { -+ if((status & AK_SPISTA_RXHFULL) == AK_SPISTA_RXHFULL) { -+ hw_rxdword(hw, readl(hw->regs + AK_SPIIN)); -+ } -+ else { -+ if (to++ > 10 * 1000000) { -+ PDEBUG("master read timeout.\n"); -+ return hw->count; -+ } -+ } -+ } -+ } -+ if (hw_remain_datalen(hw) > 0) -+ printk("read wasn't finished.\n"); -+ -+ return hw->count; -+} -+ -+ -+/** -+* @brief spi transfer function by cpu mode. -+* @author lixinhai -+* @date 2013-03-15 -+* @param[in] *hw :akspi master dev. -+* @param[in] dir: transfer direction. -+* @return transfer success result 0, otherwise result a negative value -+*/ -+static int ak_spi_pio_txrx(struct ak_spi *hw, struct spi_transfer *t) -+{ -+ int retlen; -+ u32 count = t->len; -+ -+ hw->tx = (unsigned char*)t->tx_buf; -+ hw->rx = t->rx_buf; -+ PDEBUG("start the spi dma transfer.\n"); -+ -+ switch(hw->xfer_dir) { -+ case SPI_DIR_TX: -+ { -+ while(count > 0) { -+ hw->count = 0; -+ hw->len = (count > MAX_XFER_LEN) ? MAX_XFER_LEN : count; -+ -+ retlen = spi_pio_write(hw, hw->tx, hw->len); -+ if(unlikely(retlen < 0)) { -+ printk("spi master transfer data error!\n"); -+ goto txrx_ret; -+ } -+ hw->tx += retlen; -+ count -= retlen; -+ -+ } -+ break; -+ } -+ case SPI_DIR_RX: -+ { -+ while(count > 0) { -+ hw->count = 0; -+ hw->len = (count > MAX_XFER_LEN) ? MAX_XFER_LEN : count; -+ -+ retlen = spi_pio_read(hw, hw->rx, hw->len); -+ if(unlikely(retlen < 0)) { -+ printk("spi master transfer data error!\n"); -+ goto txrx_ret; -+ } -+ hw->rx += retlen; -+ count -= retlen; -+ } -+ break; -+ } -+ } -+ PDEBUG("finish the spi dma transfer.\n"); -+ -+txrx_ret: -+ return (retlen<0) ? retlen : t->len; -+} -+ -+#endif -+ -+/** -+* @brief transfer a message -+* call proper function to complete the transefer -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *spi -+* @param[in] *t -+* @return int -+*/ -+static int ak_spi_txrx(struct spi_device *spi, struct spi_transfer *t) -+{ -+ int ret; -+ struct ak_spi *hw = to_hw(spi); -+ -+ TMPDEBUG("txrx: tx %p, rx %p, len %d\n", -+ t->tx_buf, t->rx_buf, t->len); -+ -+ dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", -+ t->tx_buf, t->rx_buf, t->len); -+ -+ hw->xfer_mode = t->len < 256 ? AKSPI_XFER_MODE_CPU : AKSPI_XFER_MODE_DMA; -+ -+ hw->xfer_dir = (t->tx_buf && t->rx_buf) ? SPI_DIR_TXRX : -+ t->tx_buf ? SPI_DIR_TX : SPI_DIR_RX; -+ -+ ak_spi_start_txrx(hw, t); -+ -+ ak_drv_module_protect(DRV_MODULE_SPI); -+ -+ if(hw->xfer_dir == SPI_DIR_TXRX) { -+ //printk(KERN_WARNING "this spi master driver no support duplex now!\n"); -+ ret = ak_cpu_duplex(spi, t); -+ ak_drv_module_unprotect(DRV_MODULE_SPI); -+ return ret; -+ } -+ -+ if(ak_spi_use_dma(hw)) { -+ ret = ak_spi_dma_txrx(hw, t); -+ } else { -+ ret = ak_spi_pio_txrx(hw, t); -+ } -+ -+ ak_drv_module_unprotect(DRV_MODULE_SPI); -+ ak_spi_stop_txrx(hw, t); -+ -+ return ret; -+} -+ -+/** -+* @brief ak_spi_irq -+* TODO: used by interrupt mode -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] irq -+* @param[out] *dev -+* @return irqreturn_t -+*/ -+static irqreturn_t ak_spi_irq(int irq, void *dev) -+{ -+ struct ak_spi *hw = dev; -+ unsigned int status; -+ -+ status = readl(hw->regs + AK_SPISTA); -+ -+ PDEBUG("spi interrupt: status register value is %08x\n", status); -+ -+ if(ak_spi_use_dma(hw)) { -+ if((status & AK_SPISTA_TRANSF) == AK_SPISTA_TRANSF ) { -+ PDEBUG("spi transfer data have been finish.\n"); -+ -+ //printk("--->status:%d, cnt:%d\n", status, readl(hw->regs + AK_SPICNT)); -+ disable_imask(hw, AK_SPIINT_TRANSF); -+ complete(&hw->done); -+ } -+ } else { -+ switch(hw->xfer_dir) { -+ case SPI_DIR_RX: -+ if(status & (AK_SPISTA_RXHFULL | AK_SPISTA_TRANSF)) { -+ PDEBUG("spi recv buffer half full or data transfer finish.\n"); -+ -+ if(status & (AK_SPISTA_RXFULL|AK_SPISTA_TRANSF)) -+ hw_rxdword(hw, readl(hw->regs + AK_SPIIN)); -+ hw_rxdword(hw, readl(hw->regs + AK_SPIIN)); -+ -+ if (hw->count >= hw->len) { -+ disable_imask(hw, AK_SPIINT_RXHFULL|AK_SPIINT_TRANSF); -+ complete(&hw->done); -+ } -+ } -+ break; -+ case SPI_DIR_TX: -+ if(status & (AK_SPISTA_TXHEMP | AK_SPISTA_TRANSF)) { -+ PDEBUG("spi send buffer half empty or data transfer finish.\n"); -+ -+ if (hw->count < hw->len) { -+ if((status & AK_SPISTA_TXEMP) && ((hw->count - hw->len)>4)) -+ writel(hw_txdword(hw), hw->regs + AK_SPIOUT); -+ -+ writel(hw_txdword(hw), hw->regs + AK_SPIOUT); -+ } else { -+ disable_imask(hw, AK_SPIINT_TXHEMP|AK_SPIINT_TRANSF); -+ complete(&hw->done); -+ } -+ } -+ break; -+ case SPI_DIR_TXRX : -+ default: -+ BUG(); -+ break; -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+ -+/** -+* @brief ak_spi_initialsetup -+* set up gpio and spi master -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[out] *hw -+* @return void -+*/ -+static void ak_spi_initialsetup(struct ak_spi *hw) -+{ -+ /* for the moment, permanently enable the clock */ -+ TMPDEBUG("Entering %s\n", __FUNCTION__); -+ -+ BUG_ON(hw->master && hw->master->bus_num >= AKSPI_MAX_BUS_NUM); -+ -+ ak_soft_reset(SPI_RESET_NUM(hw->master)); -+ clk_enable(hw->clk); -+ -+ /* program defaults into the registers */ -+ writel(DFT_DIV<<8 | DFT_CON | (1<<1),hw->regs + AK_SPICON); -+ -+ writel(0, hw->regs + AK_SPIINT); -+ -+ ak_spi_gpio_setup(hw, 1); -+ -+ printk("akpi regs: SPICON:%08x, SPISTA:%08x, SPIINT:%08x.\n", -+ ioread32(hw->regs + AK_SPICON), -+ ioread32(hw->regs + AK_SPISTA), -+ ioread32(hw->regs + AK_SPIINT)); -+ -+} -+ -+/** -+* @brief ak_spi_probe -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[out] *pdev -+* @return int __init -+*/ -+static int __init ak_spi_probe(struct platform_device *pdev) -+{ -+ struct ak_spi_info *pdata; -+ struct ak_spi *hw; -+ struct spi_master *master; -+ struct resource *res; -+ int err = 0; -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(struct ak_spi)); -+ if (master == NULL) -+ { -+ dev_err(&pdev->dev, "No memory for spi_master\n"); -+ err = -ENOMEM; -+ goto err_nomem; -+ } -+ -+ hw = spi_master_get_devdata(master); -+ memset(hw, 0, sizeof(struct ak_spi)); -+ -+ hw->master = spi_master_get(master); -+ hw->pdata = pdata = pdev->dev.platform_data; -+ hw->dev = &pdev->dev; -+ hw->xfer_mode = pdata->xfer_mode; -+ -+ if (pdata == NULL) -+ { -+ dev_err(&pdev->dev, "No platform data supplied\n"); -+ err = -ENOENT; -+ goto err_no_pdata; -+ } -+ -+ platform_set_drvdata(pdev, hw); -+ init_completion(&hw->done); -+ -+ /* setup the master state. */ -+ /* the spi->mode bits understood by this driver: */ -+ master->mode_bits = hw->pdata->mode_bits; -+ -+ master->num_chipselect = hw->pdata->num_cs; -+ master->bus_num = pdata->bus_num; -+ -+ /* setup the state for the bitbang driver */ -+ -+ hw->bitbang.master = hw->master; -+ hw->bitbang.setup_transfer = ak_spi_setupxfer; -+ hw->bitbang.chipselect = ak_spi_chipsel; -+ hw->bitbang.txrx_bufs = ak_spi_txrx; -+ -+ hw->master->setup = ak_spi_setup; -+ hw->master->cleanup = ak_spi_cleanup; -+ -+ dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); -+ -+ /* find and map our resources */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res == NULL) { -+ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); -+ err = -ENOENT; -+ goto err_no_iores; -+ } -+ -+ hw->ioarea = request_mem_region(res->start, resource_size(res), -+ pdev->name); -+ -+ if (hw->ioarea == NULL) { -+ dev_err(&pdev->dev, "Cannot reserve region\n"); -+ err = -ENXIO; -+ goto err_no_iores; -+ } -+ -+ hw->regs = ioremap(res->start, resource_size(res)); -+ if (hw->regs == NULL) { -+ dev_err(&pdev->dev, "Cannot map IO\n"); -+ err = -ENXIO; -+ goto err_no_iomap; -+ } -+ -+ hw->irq = platform_get_irq(pdev, 0); -+ if (hw->irq < 0) { -+ dev_err(&pdev->dev, "No IRQ specified\n"); -+ err = -ENOENT; -+ goto err_no_irq; -+ } -+ -+ err = request_irq(hw->irq, ak_spi_irq, 0, pdev->name, hw); -+ if (err) { -+ dev_err(&pdev->dev, "Cannot claim IRQ\n"); -+ goto err_no_irq; -+ } -+ -+ hw->clk = clk_get(&pdev->dev, pdata->clk_name); -+ if (IS_ERR(hw->clk)) { -+ dev_err(&pdev->dev, "No clock for device\n"); -+ err = PTR_ERR(hw->clk); -+ goto err_no_clk; -+ } -+ PDEBUG("%s: %luMhz \n", hw->clk->name, clk_get_rate(hw->clk)/MHz); -+ -+ /* setup any gpio we can */ -+ -+ ak_spi_initialsetup(hw); -+ -+ /* register our spi controller */ -+ -+ err = spi_bitbang_start(&hw->bitbang); -+ if (err) { -+ dev_err(&pdev->dev, "Failed to register SPI master\n"); -+ goto err_register; -+ } -+ -+ printk("akspi master initialize success, use for %s mode.\n", -+ ak_spi_use_dma(hw)?"DMA":"PIO"); -+ -+ return 0; -+ -+ err_register: -+ //if (hw->set_cs == ak_spi_gpiocs) -+ // gpio_free(pdata->pin_cs); -+ -+ clk_disable(hw->clk); -+ clk_put(hw->clk); -+ -+ err_no_clk: -+ free_irq(hw->irq, hw); -+ -+ err_no_irq: -+ iounmap(hw->regs); -+ -+ err_no_iomap: -+ release_resource(hw->ioarea); -+ -+ err_no_iores: -+ err_no_pdata: -+ spi_master_put(hw->master); -+ -+ err_nomem: -+ return err; -+} -+ -+/** -+* @brief ak_spi_remove -+* free allocated resources while remove -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[out] *dev -+* @return int __exit -+*/ -+static int __exit ak_spi_remove(struct platform_device *dev) -+{ -+ struct ak_spi *hw = platform_get_drvdata(dev); -+ -+ platform_set_drvdata(dev, NULL); -+ -+ spi_unregister_master(hw->master); -+ -+ clk_disable(hw->clk); -+ clk_put(hw->clk); -+ -+ free_irq(hw->irq, hw); -+ iounmap(hw->regs); -+ -+ release_resource(hw->ioarea); -+ -+ spi_master_put(hw->master); -+ return 0; -+} -+ -+ -+#ifdef CONFIG_PM -+ -+/** -+* @brief ak_spi_suspend -+* suspend, disable the clock to the SPI -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[in] *dev -+* @return int -+*/ -+static int ak_spi_suspend(struct device *dev) -+{ -+ struct ak_spi *hw = platform_get_drvdata(to_platform_device(dev)); -+ -+ ak_spi_gpio_setup(hw, 0); -+ -+ clk_disable(hw->clk); -+ return 0; -+} -+ -+/** -+* @brief ak_spi_resume -+* resume, initialize the spi master -+* @author zhou wenyong -+* @date 2011-08-19 -+* @param[out] *dev -+* @return int -+*/ -+static int ak_spi_resume(struct device *dev) -+{ -+ struct ak_spi *hw = platform_get_drvdata(to_platform_device(dev)); -+ -+ ak_spi_initialsetup(hw); -+ return 0; -+} -+ -+static struct dev_pm_ops ak_spi_pmops = { -+ .suspend = ak_spi_suspend, -+ .resume = ak_spi_resume, -+}; -+ -+#define AK_SPI_PMOPS &ak_spi_pmops -+#else -+#define AK_SPI_PMOPS NULL -+#endif /* CONFIG_PM */ -+ -+MODULE_ALIAS("platform:ak-spi"); -+static struct platform_driver ak_spi_driver = { -+ .remove = __exit_p(ak_spi_remove), -+ .driver = { -+ .name = "ak-spi", -+ .owner = THIS_MODULE, -+ .pm = AK_SPI_PMOPS, -+ }, -+}; -+ -+/** -+* @brief ak_spi_init -+* init, register this driver -+* @author zhou wenyong -+* @date 2011-08-19 -+* @return int __init -+*/ -+static int __init ak_spi_init(void) -+{ -+ printk("AK SPI Driver, (c) 2012 ANYKA\n"); -+ return platform_driver_probe(&ak_spi_driver, ak_spi_probe); -+} -+ -+/** -+* @brief ak_spi_exit -+* exit, unregister this driver -+* @author zhou wenyong -+* @date 2011-08-19 -+* @return void __exit -+*/ -+static void __exit ak_spi_exit(void) -+{ -+ platform_driver_unregister(&ak_spi_driver); -+} -+ -+module_init(ak_spi_init); -+module_exit(ak_spi_exit); -+ -+MODULE_DESCRIPTION("AK On-Chip SPI Driver"); -+MODULE_AUTHOR("ANYKA"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c -index aef59b1a..b6f31bc1 100644 ---- a/drivers/spi/spi-bitbang.c -+++ b/drivers/spi/spi-bitbang.c -@@ -348,8 +348,6 @@ static void bitbang_work(struct work_struct *work) - - if (!cs_change) - continue; -- if (t->transfer_list.next == &m->transfers) -- break; - - /* sometimes a short mid-message deselect of the chip - * may be needed to terminate a mode or command -@@ -357,6 +355,9 @@ static void bitbang_work(struct work_struct *work) - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); -+ -+ if (t->transfer_list.next == &m->transfers) -+ break; - } - - m->status = status; -diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig -index eb1dee26..43d17c27 100644 ---- a/drivers/staging/android/Kconfig -+++ b/drivers/staging/android/Kconfig -@@ -38,6 +38,20 @@ config ANDROID_RAM_CONSOLE - select ANDROID_PERSISTENT_RAM - default n - -+config PERSISTENT_TRACER -+ bool "Persistent function tracer" -+ depends on HAVE_FUNCTION_TRACER -+ select FUNCTION_TRACER -+ select ANDROID_PERSISTENT_RAM -+ help -+ persistent_trace traces function calls into a persistent ram -+ buffer that can be decoded and dumped after reboot through -+ /sys/kernel/debug/persistent_trace. It can be used to -+ determine what function was last called before a reset or -+ panic. -+ -+ If unsure, say N. -+ - config ANDROID_TIMED_OUTPUT - bool "Timed output class driver" - default y -@@ -53,33 +67,25 @@ config ANDROID_LOW_MEMORY_KILLER - ---help--- - Register processes to be killed when memory is low - -+config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES -+ bool "Android Low Memory Killer: detect oom_adj values" -+ depends on ANDROID_LOW_MEMORY_KILLER -+ default y -+ ---help--- -+ Detect oom_adj values written to -+ /sys/module/lowmemorykiller/parameters/adj and convert them -+ to oom_score_adj values. -+ - source "drivers/staging/android/switch/Kconfig" - --config ANDROID_INTF_ALARM -+config ANDROID_INTF_ALARM_DEV - bool "Android alarm driver" - depends on RTC_CLASS - default n - help - Provides non-wakeup and rtc backed wakeup alarms based on rtc or - elapsed realtime, and a non-wakeup alarm on the monotonic clock. -- Also provides an interface to set the wall time which must be used -- for elapsed realtime to work. -- --config ANDROID_INTF_ALARM_DEV -- bool "Android alarm device" -- depends on ANDROID_INTF_ALARM -- default y -- help -- Exports the alarm interface to user-space. -- --config ANDROID_ALARM_OLDDRV_COMPAT -- bool "Android Alarm compatability with old drivers" -- depends on ANDROID_INTF_ALARM -- default n -- help -- Provides preprocessor alias to aid compatability with -- older out-of-tree drivers that use the Android Alarm -- in-kernel API. This will be removed eventually. -+ Also exports the alarm interface to user-space. - - endif # if ANDROID - -diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile -index 9b6c9ed9..8769e325 100644 ---- a/drivers/staging/android/Makefile -+++ b/drivers/staging/android/Makefile -@@ -1,3 +1,5 @@ -+ccflags-y += -I$(src) # needed for trace events -+ - obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o - obj-$(CONFIG_ASHMEM) += ashmem.o - obj-$(CONFIG_ANDROID_LOGGER) += logger.o -@@ -7,5 +9,7 @@ obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o - obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o - obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o - obj-$(CONFIG_ANDROID_SWITCH) += switch/ --obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o - obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o -+obj-$(CONFIG_PERSISTENT_TRACER) += trace_persistent.o -+ -+CFLAGS_REMOVE_trace_persistent.o = -pg -diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO -deleted file mode 100644 -index b15fb0d6..00000000 ---- a/drivers/staging/android/TODO -+++ /dev/null -@@ -1,10 +0,0 @@ --TODO: -- - checkpatch.pl cleanups -- - sparse fixes -- - rename files to be not so "generic" -- - make sure things build as modules properly -- - add proper arch dependencies as needed -- - audit userspace interfaces to make sure they are sane -- --Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc: --Brian Swetland <swetland@google.com> -diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c -index 03efb34c..e001fe58 100644 ---- a/drivers/staging/android/alarm-dev.c -+++ b/drivers/staging/android/alarm-dev.c -@@ -22,24 +22,14 @@ - #include <linux/sched.h> - #include <linux/spinlock.h> - #include <linux/uaccess.h> -+#include <linux/alarmtimer.h> -+#include <linux/wakelock.h> - #include "android_alarm.h" - --/* XXX - Hack out wakelocks, while they are out of tree */ --struct wake_lock { -- int i; --}; --#define wake_lock(x) --#define wake_lock_timeout(x, y) --#define wake_unlock(x) --#define WAKE_LOCK_SUSPEND 0 --#define wake_lock_init(x, y, z) ((x)->i = 1) --#define wake_lock_destroy(x) -- - #define ANDROID_ALARM_PRINT_INFO (1U << 0) - #define ANDROID_ALARM_PRINT_IO (1U << 1) - #define ANDROID_ALARM_PRINT_INT (1U << 2) - -- - static int debug_mask = ANDROID_ALARM_PRINT_INFO; - module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); - -@@ -66,7 +56,53 @@ static uint32_t alarm_pending; - static uint32_t alarm_enabled; - static uint32_t wait_pending; - --static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT]; -+struct devalarm { -+ union { -+ struct hrtimer hrt; -+ struct alarm alrm; -+ } u; -+ enum android_alarm_type type; -+}; -+ -+static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT]; -+ -+ -+static int is_wakeup(enum android_alarm_type type) -+{ -+ if (type == ANDROID_ALARM_RTC_WAKEUP || -+ type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP) -+ return 1; -+ return 0; -+} -+ -+ -+static void devalarm_start(struct devalarm *alrm, ktime_t exp) -+{ -+ if (is_wakeup(alrm->type)) -+ alarm_start(&alrm->u.alrm, exp); -+ else -+ hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS); -+} -+ -+ -+static int devalarm_try_to_cancel(struct devalarm *alrm) -+{ -+ int ret; -+ if (is_wakeup(alrm->type)) -+ ret = alarm_try_to_cancel(&alrm->u.alrm); -+ else -+ ret = hrtimer_try_to_cancel(&alrm->u.hrt); -+ return ret; -+} -+ -+static void devalarm_cancel(struct devalarm *alrm) -+{ -+ if (is_wakeup(alrm->type)) -+ alarm_cancel(&alrm->u.alrm); -+ else -+ hrtimer_cancel(&alrm->u.hrt); -+} -+ - - static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - { -@@ -75,6 +111,8 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - struct timespec new_alarm_time; - struct timespec new_rtc_time; - struct timespec tmp_time; -+ struct rtc_time new_rtc_tm; -+ struct rtc_device *rtc_dev; - enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd); - uint32_t alarm_type_mask = 1U << alarm_type; - -@@ -101,7 +139,7 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - case ANDROID_ALARM_CLEAR(0): - spin_lock_irqsave(&alarm_slock, flags); - pr_alarm(IO, "alarm %d clear\n", alarm_type); -- android_alarm_try_to_cancel(&alarms[alarm_type]); -+ devalarm_try_to_cancel(&alarms[alarm_type]); - if (alarm_pending) { - alarm_pending &= ~alarm_type_mask; - if (!alarm_pending && !wait_pending) -@@ -132,8 +170,7 @@ from_old_alarm_set: - pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type, - new_alarm_time.tv_sec, new_alarm_time.tv_nsec); - alarm_enabled |= alarm_type_mask; -- android_alarm_start_range(&alarms[alarm_type], -- timespec_to_ktime(new_alarm_time), -+ devalarm_start(&alarms[alarm_type], - timespec_to_ktime(new_alarm_time)); - spin_unlock_irqrestore(&alarm_slock, flags); - if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0) -@@ -163,7 +200,13 @@ from_old_alarm_set: - rv = -EFAULT; - goto err1; - } -- rv = android_alarm_set_rtc(new_rtc_time); -+ rtc_time_to_tm(new_rtc_time.tv_sec, &new_rtc_tm); -+ rtc_dev = alarmtimer_get_rtcdev(); -+ rv = do_settimeofday(&new_rtc_time); -+ if (rv < 0) -+ goto err1; -+ if (rtc_dev) -+ rv = rtc_set_time(rtc_dev, &new_rtc_tm); - spin_lock_irqsave(&alarm_slock, flags); - alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK; - wake_up(&alarm_wait_queue); -@@ -179,8 +222,7 @@ from_old_alarm_set: - break; - case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP: - case ANDROID_ALARM_ELAPSED_REALTIME: -- tmp_time = -- ktime_to_timespec(alarm_get_elapsed_realtime()); -+ get_monotonic_boottime(&tmp_time); - break; - case ANDROID_ALARM_TYPE_COUNT: - case ANDROID_ALARM_SYSTEMTIME: -@@ -224,7 +266,7 @@ static int alarm_release(struct inode *inode, struct file *file) - alarm_enabled &= ~alarm_type_mask; - } - spin_unlock_irqrestore(&alarm_slock, flags); -- android_alarm_cancel(&alarms[i]); -+ devalarm_cancel(&alarms[i]); - spin_lock_irqsave(&alarm_slock, flags); - } - if (alarm_pending | wait_pending) { -@@ -241,12 +283,12 @@ static int alarm_release(struct inode *inode, struct file *file) - return 0; - } - --static void alarm_triggered(struct android_alarm *alarm) -+static void devalarm_triggered(struct devalarm *alarm) - { - unsigned long flags; - uint32_t alarm_type_mask = 1U << alarm->type; - -- pr_alarm(INT, "alarm_triggered type %d\n", alarm->type); -+ pr_alarm(INT, "devalarm_triggered type %d\n", alarm->type); - spin_lock_irqsave(&alarm_slock, flags); - if (alarm_enabled & alarm_type_mask) { - wake_lock_timeout(&alarm_wake_lock, 5 * HZ); -@@ -257,6 +299,25 @@ static void alarm_triggered(struct android_alarm *alarm) - spin_unlock_irqrestore(&alarm_slock, flags); - } - -+ -+static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt) -+{ -+ struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt); -+ -+ devalarm_triggered(devalrm); -+ return HRTIMER_NORESTART; -+} -+ -+static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm, -+ ktime_t now) -+{ -+ struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm); -+ -+ devalarm_triggered(devalrm); -+ return ALARMTIMER_NORESTART; -+} -+ -+ - static const struct file_operations alarm_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = alarm_ioctl, -@@ -279,8 +340,23 @@ static int __init alarm_dev_init(void) - if (err) - return err; - -- for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) -- android_alarm_init(&alarms[i], i, alarm_triggered); -+ alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm, -+ ALARM_REALTIME, devalarm_alarmhandler); -+ hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt, -+ CLOCK_REALTIME, HRTIMER_MODE_ABS); -+ alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm, -+ ALARM_BOOTTIME, devalarm_alarmhandler); -+ hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt, -+ CLOCK_BOOTTIME, HRTIMER_MODE_ABS); -+ hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt, -+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -+ -+ for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) { -+ alarms[i].type = i; -+ if (!is_wakeup(i)) -+ alarms[i].u.hrt.function = devalarm_hrthandler; -+ } -+ - wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm"); - - return 0; -diff --git a/drivers/staging/android/alarm.c b/drivers/staging/android/alarm.c -deleted file mode 100644 -index c68950b9..00000000 ---- a/drivers/staging/android/alarm.c -+++ /dev/null -@@ -1,601 +0,0 @@ --/* drivers/rtc/alarm.c -- * -- * Copyright (C) 2007-2009 Google, Inc. -- * -- * This software is licensed under the terms of the GNU General Public -- * License version 2, as published by the Free Software Foundation, and -- * may be copied, distributed, and modified under those terms. -- * -- * 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. -- * -- */ -- --#include <linux/time.h> --#include <linux/module.h> --#include <linux/device.h> --#include <linux/miscdevice.h> --#include <linux/platform_device.h> --#include <linux/rtc.h> --#include <linux/sched.h> --#include <linux/spinlock.h> --#include "android_alarm.h" -- --/* XXX - Hack out wakelocks, while they are out of tree */ --struct wake_lock { -- int i; --}; --#define wake_lock(x) --#define wake_lock_timeout(x, y) --#define wake_unlock(x) --#define WAKE_LOCK_SUSPEND 0 --#define wake_lock_init(x, y, z) ((x)->i = 1) --#define wake_lock_destroy(x) -- --#define ANDROID_ALARM_PRINT_ERROR (1U << 0) --#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1) --#define ANDROID_ALARM_PRINT_TSET (1U << 2) --#define ANDROID_ALARM_PRINT_CALL (1U << 3) --#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4) --#define ANDROID_ALARM_PRINT_INT (1U << 5) --#define ANDROID_ALARM_PRINT_FLOW (1U << 6) -- --static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \ -- ANDROID_ALARM_PRINT_INIT_STATUS; --module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); -- --#define pr_alarm(debug_level_mask, args...) \ -- do { \ -- if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \ -- pr_info(args); \ -- } \ -- } while (0) -- --#define ANDROID_ALARM_WAKEUP_MASK ( \ -- ANDROID_ALARM_RTC_WAKEUP_MASK | \ -- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) -- --/* support old usespace code */ --#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */ --#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t) -- --struct alarm_queue { -- struct rb_root alarms; -- struct rb_node *first; -- struct hrtimer timer; -- ktime_t delta; -- bool stopped; -- ktime_t stopped_time; --}; -- --static struct rtc_device *alarm_rtc_dev; --static DEFINE_SPINLOCK(alarm_slock); --static DEFINE_MUTEX(alarm_setrtc_mutex); --static struct wake_lock alarm_rtc_wake_lock; --static struct platform_device *alarm_platform_dev; --struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT]; --static bool suspended; -- --static void update_timer_locked(struct alarm_queue *base, bool head_removed) --{ -- struct android_alarm *alarm; -- bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] || -- base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; -- -- if (base->stopped) { -- pr_alarm(FLOW, "changed alarm while setting the wall time\n"); -- return; -- } -- -- if (is_wakeup && !suspended && head_removed) -- wake_unlock(&alarm_rtc_wake_lock); -- -- if (!base->first) -- return; -- -- alarm = container_of(base->first, struct android_alarm, node); -- -- pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n", -- alarm->type, alarm->function, ktime_to_ns(alarm->expires)); -- -- if (is_wakeup && suspended) { -- pr_alarm(FLOW, "changed alarm while suspened\n"); -- wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); -- return; -- } -- -- hrtimer_try_to_cancel(&base->timer); -- base->timer.node.expires = ktime_add(base->delta, alarm->expires); -- base->timer._softexpires = ktime_add(base->delta, alarm->softexpires); -- hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS); --} -- --static void alarm_enqueue_locked(struct android_alarm *alarm) --{ -- struct alarm_queue *base = &alarms[alarm->type]; -- struct rb_node **link = &base->alarms.rb_node; -- struct rb_node *parent = NULL; -- struct android_alarm *entry; -- int leftmost = 1; -- bool was_first = false; -- -- pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n", -- alarm->type, alarm->function, ktime_to_ns(alarm->expires)); -- -- if (base->first == &alarm->node) { -- base->first = rb_next(&alarm->node); -- was_first = true; -- } -- if (!RB_EMPTY_NODE(&alarm->node)) { -- rb_erase(&alarm->node, &base->alarms); -- RB_CLEAR_NODE(&alarm->node); -- } -- -- while (*link) { -- parent = *link; -- entry = rb_entry(parent, struct android_alarm, node); -- /* -- * We dont care about collisions. Nodes with -- * the same expiry time stay together. -- */ -- if (alarm->expires.tv64 < entry->expires.tv64) { -- link = &(*link)->rb_left; -- } else { -- link = &(*link)->rb_right; -- leftmost = 0; -- } -- } -- if (leftmost) -- base->first = &alarm->node; -- if (leftmost || was_first) -- update_timer_locked(base, was_first); -- -- rb_link_node(&alarm->node, parent, link); -- rb_insert_color(&alarm->node, &base->alarms); --} -- --/** -- * android_alarm_init - initialize an alarm -- * @alarm: the alarm to be initialized -- * @type: the alarm type to be used -- * @function: alarm callback function -- */ --void android_alarm_init(struct android_alarm *alarm, -- enum android_alarm_type type, void (*function)(struct android_alarm *)) --{ -- RB_CLEAR_NODE(&alarm->node); -- alarm->type = type; -- alarm->function = function; -- -- pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function); --} -- -- --/** -- * android_alarm_start_range - (re)start an alarm -- * @alarm: the alarm to be added -- * @start: earliest expiry time -- * @end: expiry time -- */ --void android_alarm_start_range(struct android_alarm *alarm, ktime_t start, -- ktime_t end) --{ -- unsigned long flags; -- -- spin_lock_irqsave(&alarm_slock, flags); -- alarm->softexpires = start; -- alarm->expires = end; -- alarm_enqueue_locked(alarm); -- spin_unlock_irqrestore(&alarm_slock, flags); --} -- --/** -- * android_alarm_try_to_cancel - try to deactivate an alarm -- * @alarm: alarm to stop -- * -- * Returns: -- * 0 when the alarm was not active -- * 1 when the alarm was active -- * -1 when the alarm may currently be excuting the callback function and -- * cannot be stopped (it may also be inactive) -- */ --int android_alarm_try_to_cancel(struct android_alarm *alarm) --{ -- struct alarm_queue *base = &alarms[alarm->type]; -- unsigned long flags; -- bool first = false; -- int ret = 0; -- -- spin_lock_irqsave(&alarm_slock, flags); -- if (!RB_EMPTY_NODE(&alarm->node)) { -- pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n", -- alarm->type, alarm->function, -- ktime_to_ns(alarm->expires)); -- ret = 1; -- if (base->first == &alarm->node) { -- base->first = rb_next(&alarm->node); -- first = true; -- } -- rb_erase(&alarm->node, &base->alarms); -- RB_CLEAR_NODE(&alarm->node); -- if (first) -- update_timer_locked(base, true); -- } else -- pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n", -- alarm->type, alarm->function); -- spin_unlock_irqrestore(&alarm_slock, flags); -- if (!ret && hrtimer_callback_running(&base->timer)) -- ret = -1; -- return ret; --} -- --/** -- * android_alarm_cancel - cancel an alarm and wait for the handler to finish. -- * @alarm: the alarm to be cancelled -- * -- * Returns: -- * 0 when the alarm was not active -- * 1 when the alarm was active -- */ --int android_alarm_cancel(struct android_alarm *alarm) --{ -- for (;;) { -- int ret = android_alarm_try_to_cancel(alarm); -- if (ret >= 0) -- return ret; -- cpu_relax(); -- } --} -- --/** -- * alarm_set_rtc - set the kernel and rtc walltime -- * @new_time: timespec value containing the new time -- */ --int android_alarm_set_rtc(struct timespec new_time) --{ -- int i; -- int ret; -- unsigned long flags; -- struct rtc_time rtc_new_rtc_time; -- struct timespec tmp_time; -- -- rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time); -- -- pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n", -- new_time.tv_sec, new_time.tv_nsec, -- rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min, -- rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1, -- rtc_new_rtc_time.tm_mday, -- rtc_new_rtc_time.tm_year + 1900); -- -- mutex_lock(&alarm_setrtc_mutex); -- spin_lock_irqsave(&alarm_slock, flags); -- wake_lock(&alarm_rtc_wake_lock); -- getnstimeofday(&tmp_time); -- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { -- hrtimer_try_to_cancel(&alarms[i].timer); -- alarms[i].stopped = true; -- alarms[i].stopped_time = timespec_to_ktime(tmp_time); -- } -- alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = -- alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = -- ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta, -- timespec_to_ktime(timespec_sub(tmp_time, new_time))); -- spin_unlock_irqrestore(&alarm_slock, flags); -- ret = do_settimeofday(&new_time); -- spin_lock_irqsave(&alarm_slock, flags); -- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { -- alarms[i].stopped = false; -- update_timer_locked(&alarms[i], false); -- } -- spin_unlock_irqrestore(&alarm_slock, flags); -- if (ret < 0) { -- pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n"); -- goto err; -- } -- if (!alarm_rtc_dev) { -- pr_alarm(ERROR, -- "alarm_set_rtc: no RTC, time will be lost on reboot\n"); -- goto err; -- } -- ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time); -- if (ret < 0) -- pr_alarm(ERROR, "alarm_set_rtc: " -- "Failed to set RTC, time will be lost on reboot\n"); --err: -- wake_unlock(&alarm_rtc_wake_lock); -- mutex_unlock(&alarm_setrtc_mutex); -- return ret; --} -- --/** -- * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format -- * -- * returns the time in ktime_t format -- */ --ktime_t alarm_get_elapsed_realtime(void) --{ -- ktime_t now; -- unsigned long flags; -- struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME]; -- -- spin_lock_irqsave(&alarm_slock, flags); -- now = base->stopped ? base->stopped_time : ktime_get_real(); -- now = ktime_sub(now, base->delta); -- spin_unlock_irqrestore(&alarm_slock, flags); -- return now; --} -- --static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer) --{ -- struct alarm_queue *base; -- struct android_alarm *alarm; -- unsigned long flags; -- ktime_t now; -- -- spin_lock_irqsave(&alarm_slock, flags); -- -- base = container_of(timer, struct alarm_queue, timer); -- now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer); -- now = ktime_sub(now, base->delta); -- -- pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n", -- base - alarms, ktime_to_ns(now)); -- -- while (base->first) { -- alarm = container_of(base->first, struct android_alarm, node); -- if (alarm->softexpires.tv64 > now.tv64) { -- pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n", -- alarm->function, ktime_to_ns(alarm->expires), -- ktime_to_ns(alarm->softexpires)); -- break; -- } -- base->first = rb_next(&alarm->node); -- rb_erase(&alarm->node, &base->alarms); -- RB_CLEAR_NODE(&alarm->node); -- pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n", -- alarm->type, alarm->function, -- ktime_to_ns(alarm->expires), -- ktime_to_ns(alarm->softexpires)); -- spin_unlock_irqrestore(&alarm_slock, flags); -- alarm->function(alarm); -- spin_lock_irqsave(&alarm_slock, flags); -- } -- if (!base->first) -- pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms); -- update_timer_locked(base, true); -- spin_unlock_irqrestore(&alarm_slock, flags); -- return HRTIMER_NORESTART; --} -- --static void alarm_triggered_func(void *p) --{ -- struct rtc_device *rtc = alarm_rtc_dev; -- if (!(rtc->irq_data & RTC_AF)) -- return; -- pr_alarm(INT, "rtc alarm triggered\n"); -- wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); --} -- --static int alarm_suspend(struct platform_device *pdev, pm_message_t state) --{ -- int err = 0; -- unsigned long flags; -- struct rtc_wkalrm rtc_alarm; -- struct rtc_time rtc_current_rtc_time; -- unsigned long rtc_current_time; -- unsigned long rtc_alarm_time; -- struct timespec rtc_delta; -- struct timespec wall_time; -- struct alarm_queue *wakeup_queue = NULL; -- struct alarm_queue *tmp_queue = NULL; -- -- pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event); -- -- spin_lock_irqsave(&alarm_slock, flags); -- suspended = true; -- spin_unlock_irqrestore(&alarm_slock, flags); -- -- hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer); -- hrtimer_cancel(&alarms[ -- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer); -- -- tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP]; -- if (tmp_queue->first) -- wakeup_queue = tmp_queue; -- tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; -- if (tmp_queue->first && (!wakeup_queue || -- hrtimer_get_expires(&tmp_queue->timer).tv64 < -- hrtimer_get_expires(&wakeup_queue->timer).tv64)) -- wakeup_queue = tmp_queue; -- if (wakeup_queue) { -- rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); -- getnstimeofday(&wall_time); -- rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); -- set_normalized_timespec(&rtc_delta, -- wall_time.tv_sec - rtc_current_time, -- wall_time.tv_nsec); -- -- rtc_alarm_time = timespec_sub(ktime_to_timespec( -- hrtimer_get_expires(&wakeup_queue->timer)), -- rtc_delta).tv_sec; -- -- rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time); -- rtc_alarm.enabled = 1; -- rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); -- rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); -- rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); -- pr_alarm(SUSPEND, -- "rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n", -- rtc_alarm_time, rtc_current_time, -- rtc_delta.tv_sec, rtc_delta.tv_nsec); -- if (rtc_current_time + 1 >= rtc_alarm_time) { -- pr_alarm(SUSPEND, "alarm about to go off\n"); -- memset(&rtc_alarm, 0, sizeof(rtc_alarm)); -- rtc_alarm.enabled = 0; -- rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); -- -- spin_lock_irqsave(&alarm_slock, flags); -- suspended = false; -- wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ); -- update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], -- false); -- update_timer_locked(&alarms[ -- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false); -- err = -EBUSY; -- spin_unlock_irqrestore(&alarm_slock, flags); -- } -- } -- return err; --} -- --static int alarm_resume(struct platform_device *pdev) --{ -- struct rtc_wkalrm alarm; -- unsigned long flags; -- -- pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev); -- -- memset(&alarm, 0, sizeof(alarm)); -- alarm.enabled = 0; -- rtc_set_alarm(alarm_rtc_dev, &alarm); -- -- spin_lock_irqsave(&alarm_slock, flags); -- suspended = false; -- update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false); -- update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], -- false); -- spin_unlock_irqrestore(&alarm_slock, flags); -- -- return 0; --} -- --static struct rtc_task alarm_rtc_task = { -- .func = alarm_triggered_func --}; -- --static int rtc_alarm_add_device(struct device *dev, -- struct class_interface *class_intf) --{ -- int err; -- struct rtc_device *rtc = to_rtc_device(dev); -- -- mutex_lock(&alarm_setrtc_mutex); -- -- if (alarm_rtc_dev) { -- err = -EBUSY; -- goto err1; -- } -- -- alarm_platform_dev = -- platform_device_register_simple("alarm", -1, NULL, 0); -- if (IS_ERR(alarm_platform_dev)) { -- err = PTR_ERR(alarm_platform_dev); -- goto err2; -- } -- err = rtc_irq_register(rtc, &alarm_rtc_task); -- if (err) -- goto err3; -- alarm_rtc_dev = rtc; -- pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name); -- mutex_unlock(&alarm_setrtc_mutex); -- -- return 0; -- --err3: -- platform_device_unregister(alarm_platform_dev); --err2: --err1: -- mutex_unlock(&alarm_setrtc_mutex); -- return err; --} -- --static void rtc_alarm_remove_device(struct device *dev, -- struct class_interface *class_intf) --{ -- if (dev == &alarm_rtc_dev->dev) { -- pr_alarm(INIT_STATUS, "lost rtc device for alarms"); -- rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task); -- platform_device_unregister(alarm_platform_dev); -- alarm_rtc_dev = NULL; -- } --} -- --static struct class_interface rtc_alarm_interface = { -- .add_dev = &rtc_alarm_add_device, -- .remove_dev = &rtc_alarm_remove_device, --}; -- --static struct platform_driver alarm_driver = { -- .suspend = alarm_suspend, -- .resume = alarm_resume, -- .driver = { -- .name = "alarm" -- } --}; -- --static int __init alarm_late_init(void) --{ -- unsigned long flags; -- struct timespec tmp_time, system_time; -- -- /* this needs to run after the rtc is read at boot */ -- spin_lock_irqsave(&alarm_slock, flags); -- /* We read the current rtc and system time so we can later calulate -- * elasped realtime to be (boot_systemtime + rtc - boot_rtc) == -- * (rtc - (boot_rtc - boot_systemtime)) -- */ -- getnstimeofday(&tmp_time); -- ktime_get_ts(&system_time); -- alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = -- alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = -- timespec_to_ktime(timespec_sub(tmp_time, system_time)); -- -- spin_unlock_irqrestore(&alarm_slock, flags); -- return 0; --} -- --static int __init alarm_driver_init(void) --{ -- int err; -- int i; -- -- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { -- hrtimer_init(&alarms[i].timer, -- CLOCK_REALTIME, HRTIMER_MODE_ABS); -- alarms[i].timer.function = alarm_timer_triggered; -- } -- hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer, -- CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -- alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered; -- err = platform_driver_register(&alarm_driver); -- if (err < 0) -- goto err1; -- wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc"); -- rtc_alarm_interface.class = rtc_class; -- err = class_interface_register(&rtc_alarm_interface); -- if (err < 0) -- goto err2; -- -- return 0; -- --err2: -- wake_lock_destroy(&alarm_rtc_wake_lock); -- platform_driver_unregister(&alarm_driver); --err1: -- return err; --} -- --static void __exit alarm_exit(void) --{ -- class_interface_unregister(&rtc_alarm_interface); -- wake_lock_destroy(&alarm_rtc_wake_lock); -- platform_driver_unregister(&alarm_driver); --} -- --late_initcall(alarm_late_init); --module_init(alarm_driver_init); --module_exit(alarm_exit); -- -diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h -index 6eecbde2..d0cafd63 100644 ---- a/drivers/staging/android/android_alarm.h -+++ b/drivers/staging/android/android_alarm.h -@@ -33,65 +33,6 @@ enum android_alarm_type { - /* ANDROID_ALARM_TIME_CHANGE = 16 */ - }; - --#ifdef __KERNEL__ -- --#include <linux/ktime.h> --#include <linux/rbtree.h> -- --/* -- * The alarm interface is similar to the hrtimer interface but adds support -- * for wakeup from suspend. It also adds an elapsed realtime clock that can -- * be used for periodic timers that need to keep runing while the system is -- * suspended and not be disrupted when the wall time is set. -- */ -- --/** -- * struct alarm - the basic alarm structure -- * @node: red black tree node for time ordered insertion -- * @type: alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup. -- * @softexpires: the absolute earliest expiry time of the alarm. -- * @expires: the absolute expiry time. -- * @function: alarm expiry callback function -- * -- * The alarm structure must be initialized by alarm_init() -- * -- */ -- --struct android_alarm { -- struct rb_node node; -- enum android_alarm_type type; -- ktime_t softexpires; -- ktime_t expires; -- void (*function)(struct android_alarm *); --}; -- --void android_alarm_init(struct android_alarm *alarm, -- enum android_alarm_type type, void (*function)(struct android_alarm *)); --void android_alarm_start_range(struct android_alarm *alarm, ktime_t start, -- ktime_t end); --int android_alarm_try_to_cancel(struct android_alarm *alarm); --int android_alarm_cancel(struct android_alarm *alarm); --ktime_t alarm_get_elapsed_realtime(void); -- --/* set rtc while preserving elapsed realtime */ --int android_alarm_set_rtc(const struct timespec ts); -- --#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT --/* -- * Some older drivers depend on the old API, -- * so provide compatability macros for now. -- */ --#define alarm android_alarm --#define alarm_init(x, y, z) android_alarm_init(x, y, z) --#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z) --#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x) --#define alarm_cancel(x) android_alarm_cancel(x) --#define alarm_set_rtc(x) android_alarm_set_rtc(x) --#endif -- -- --#endif -- - enum android_alarm_return_flags { - ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP, - ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC, -diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c -index 9f1f27e7..bda20bf1 100644 ---- a/drivers/staging/android/ashmem.c -+++ b/drivers/staging/android/ashmem.c -@@ -314,21 +314,13 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) - } - get_file(asma->file); - -- /* -- * XXX - Reworked to use shmem_zero_setup() instead of -- * shmem_set_file while we're in staging. -jstultz -- */ -- if (vma->vm_flags & VM_SHARED) { -- ret = shmem_zero_setup(vma); -- if (ret) { -- fput(asma->file); -- goto out; -- } -+ if (vma->vm_flags & VM_SHARED) -+ shmem_set_file(vma, asma->file); -+ else { -+ if (vma->vm_file) -+ fput(vma->vm_file); -+ vma->vm_file = asma->file; - } -- -- if (vma->vm_file) -- fput(vma->vm_file); -- vma->vm_file = asma->file; - vma->vm_flags |= VM_CAN_NONLINEAR; - - out: -diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c -index 223639a7..a7a5f2ae 100644 ---- a/drivers/staging/android/binder.c -+++ b/drivers/staging/android/binder.c -@@ -33,10 +33,12 @@ - #include <linux/uaccess.h> - #include <linux/vmalloc.h> - #include <linux/slab.h> -+#include <linux/security.h> - - #include "binder.h" -+#include "binder_trace.h" - --static DEFINE_MUTEX(binder_lock); -+static DEFINE_MUTEX(binder_main_lock); - static DEFINE_MUTEX(binder_deferred_lock); - static DEFINE_MUTEX(binder_mmap_lock); - -@@ -499,6 +501,19 @@ out_unlock: - return -EBADF; - } - -+static inline void binder_lock(const char *tag) -+{ -+ trace_binder_lock(tag); -+ mutex_lock(&binder_main_lock); -+ trace_binder_locked(tag); -+} -+ -+static inline void binder_unlock(const char *tag) -+{ -+ trace_binder_unlock(tag); -+ mutex_unlock(&binder_main_lock); -+} -+ - static void binder_set_nice(long nice) - { - long min_nice; -@@ -625,6 +640,8 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, - if (end <= start) - return 0; - -+ trace_binder_update_page_range(proc, allocate, start, end); -+ - if (vma) - mm = NULL; - else -@@ -1473,6 +1490,10 @@ static void binder_transaction(struct binder_proc *proc, - return_error = BR_DEAD_REPLY; - goto err_dead_binder; - } -+ if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { -+ return_error = BR_FAILED_REPLY; -+ goto err_invalid_target_handle; -+ } - if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { - struct binder_transaction *tmp; - tmp = thread->transaction_stack; -@@ -1549,6 +1570,9 @@ static void binder_transaction(struct binder_proc *proc, - t->code = tr->code; - t->flags = tr->flags; - t->priority = task_nice(current); -+ -+ trace_binder_transaction(reply, t, target_node); -+ - t->buffer = binder_alloc_buf(target_proc, tr->data_size, - tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); - if (t->buffer == NULL) { -@@ -1559,6 +1583,7 @@ static void binder_transaction(struct binder_proc *proc, - t->buffer->debug_id = t->debug_id; - t->buffer->transaction = t; - t->buffer->target_node = target_node; -+ trace_binder_transaction_alloc_buf(t->buffer); - if (target_node) - binder_inc_node(target_node, 1, 0, NULL); - -@@ -1618,6 +1643,10 @@ static void binder_transaction(struct binder_proc *proc, - fp->cookie, node->cookie); - goto err_binder_get_ref_for_node_failed; - } -+ if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { -+ return_error = BR_FAILED_REPLY; -+ goto err_binder_get_ref_for_node_failed; -+ } - ref = binder_get_ref_for_node(target_proc, node); - if (ref == NULL) { - return_error = BR_FAILED_REPLY; -@@ -1631,6 +1660,7 @@ static void binder_transaction(struct binder_proc *proc, - binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, - &thread->todo); - -+ trace_binder_transaction_node_to_ref(t, node, ref); - binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p -> ref %d desc %d\n", - node->debug_id, node->ptr, ref->debug_id, -@@ -1647,6 +1677,10 @@ static void binder_transaction(struct binder_proc *proc, - return_error = BR_FAILED_REPLY; - goto err_binder_get_ref_failed; - } -+ if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { -+ return_error = BR_FAILED_REPLY; -+ goto err_binder_get_ref_failed; -+ } - if (ref->node->proc == target_proc) { - if (fp->type == BINDER_TYPE_HANDLE) - fp->type = BINDER_TYPE_BINDER; -@@ -1655,6 +1689,7 @@ static void binder_transaction(struct binder_proc *proc, - fp->binder = ref->node->ptr; - fp->cookie = ref->node->cookie; - binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); -+ trace_binder_transaction_ref_to_node(t, ref); - binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d -> node %d u%p\n", - ref->debug_id, ref->desc, ref->node->debug_id, -@@ -1668,6 +1703,8 @@ static void binder_transaction(struct binder_proc *proc, - } - fp->handle = new_ref->desc; - binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); -+ trace_binder_transaction_ref_to_ref(t, ref, -+ new_ref); - binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d -> ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, new_ref->debug_id, -@@ -1700,6 +1737,11 @@ static void binder_transaction(struct binder_proc *proc, - return_error = BR_FAILED_REPLY; - goto err_fget_failed; - } -+ if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) { -+ fput(file); -+ return_error = BR_FAILED_REPLY; -+ goto err_get_unused_fd_failed; -+ } - target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC); - if (target_fd < 0) { - fput(file); -@@ -1707,6 +1749,7 @@ static void binder_transaction(struct binder_proc *proc, - goto err_get_unused_fd_failed; - } - task_fd_install(target_proc, target_fd, file); -+ trace_binder_transaction_fd(t, fp->handle, target_fd); - binder_debug(BINDER_DEBUG_TRANSACTION, - " fd %ld -> %d\n", fp->handle, target_fd); - /* TODO: fput? */ -@@ -1755,6 +1798,7 @@ err_binder_new_node_failed: - err_bad_object_type: - err_bad_offset: - err_copy_data_failed: -+ trace_binder_transaction_failed_buffer_release(t->buffer); - binder_transaction_buffer_release(target_proc, t->buffer, offp); - t->buffer->transaction = NULL; - binder_free_buf(target_proc, t->buffer); -@@ -1800,6 +1844,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - if (get_user(cmd, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); -+ trace_binder_command(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { - binder_stats.bc[_IOC_NR(cmd)]++; - proc->stats.bc[_IOC_NR(cmd)]++; -@@ -1969,6 +2014,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - else - list_move_tail(buffer->target_node->async_todo.next, &thread->todo); - } -+ trace_binder_transaction_buffer_release(buffer); - binder_transaction_buffer_release(proc, buffer, NULL); - binder_free_buf(proc, buffer); - break; -@@ -2177,6 +2223,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, - uint32_t cmd) - { -+ trace_binder_return(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { - binder_stats.br[_IOC_NR(cmd)]++; - proc->stats.br[_IOC_NR(cmd)]++; -@@ -2223,6 +2270,7 @@ retry: - if (put_user(thread->return_error2, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); -+ binder_stat_br(proc, thread, thread->return_error2); - if (ptr == end) - goto done; - thread->return_error2 = BR_OK; -@@ -2230,6 +2278,7 @@ retry: - if (put_user(thread->return_error, (uint32_t __user *)ptr)) - return -EFAULT; - ptr += sizeof(uint32_t); -+ binder_stat_br(proc, thread, thread->return_error); - thread->return_error = BR_OK; - goto done; - } -@@ -2238,7 +2287,12 @@ retry: - thread->looper |= BINDER_LOOPER_STATE_WAITING; - if (wait_for_proc_work) - proc->ready_threads++; -- mutex_unlock(&binder_lock); -+ -+ binder_unlock(__func__); -+ -+ trace_binder_wait_for_work(wait_for_proc_work, -+ !!thread->transaction_stack, -+ !list_empty(&thread->todo)); - if (wait_for_proc_work) { - if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | - BINDER_LOOPER_STATE_ENTERED))) { -@@ -2262,7 +2316,9 @@ retry: - } else - ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread)); - } -- mutex_lock(&binder_lock); -+ -+ binder_lock(__func__); -+ - if (wait_for_proc_work) - proc->ready_threads--; - thread->looper &= ~BINDER_LOOPER_STATE_WAITING; -@@ -2385,6 +2441,7 @@ retry: - if (put_user(death->cookie, (void * __user *)ptr)) - return -EFAULT; - ptr += sizeof(void *); -+ binder_stat_br(proc, thread, cmd); - binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "binder: %d:%d %s %p\n", - proc->pid, thread->pid, -@@ -2452,6 +2509,7 @@ retry: - return -EFAULT; - ptr += sizeof(tr); - -+ trace_binder_transaction_received(t); - binder_stat_br(proc, thread, cmd); - binder_debug(BINDER_DEBUG_TRANSACTION, - "binder: %d:%d %s %d %d:%d, cmd %d" -@@ -2492,6 +2550,7 @@ done: - proc->pid, thread->pid); - if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) - return -EFAULT; -+ binder_stat_br(proc, thread, BR_SPAWN_LOOPER); - } - return 0; - } -@@ -2628,12 +2687,14 @@ static unsigned int binder_poll(struct file *filp, - struct binder_thread *thread = NULL; - int wait_for_proc_work; - -- mutex_lock(&binder_lock); -+ binder_lock(__func__); -+ - thread = binder_get_thread(proc); - - wait_for_proc_work = thread->transaction_stack == NULL && - list_empty(&thread->todo) && thread->return_error == BR_OK; -- mutex_unlock(&binder_lock); -+ -+ binder_unlock(__func__); - - if (wait_for_proc_work) { - if (binder_has_proc_work(proc, thread)) -@@ -2661,11 +2722,13 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - - /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ - -+ trace_binder_ioctl(cmd, arg); -+ - ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); - if (ret) -- return ret; -+ goto err_unlocked; - -- mutex_lock(&binder_lock); -+ binder_lock(__func__); - thread = binder_get_thread(proc); - if (thread == NULL) { - ret = -ENOMEM; -@@ -2690,6 +2753,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - - if (bwr.write_size > 0) { - ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); -+ trace_binder_write_done(ret); - if (ret < 0) { - bwr.read_consumed = 0; - if (copy_to_user(ubuf, &bwr, sizeof(bwr))) -@@ -2699,6 +2763,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - } - if (bwr.read_size > 0) { - ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); -+ trace_binder_read_done(ret); - if (!list_empty(&proc->todo)) - wake_up_interruptible(&proc->wait); - if (ret < 0) { -@@ -2729,6 +2794,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - ret = -EBUSY; - goto err; - } -+ ret = security_binder_set_context_mgr(proc->tsk); -+ if (ret < 0) -+ goto err; - if (binder_context_mgr_uid != -1) { - if (binder_context_mgr_uid != current->cred->euid) { - printk(KERN_ERR "binder: BINDER_SET_" -@@ -2774,10 +2842,12 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - err: - if (thread) - thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; -- mutex_unlock(&binder_lock); -+ binder_unlock(__func__); - wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); - if (ret && ret != -ERESTARTSYS) - printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); -+err_unlocked: -+ trace_binder_ioctl_done(ret); - return ret; - } - -@@ -2920,13 +2990,16 @@ static int binder_open(struct inode *nodp, struct file *filp) - INIT_LIST_HEAD(&proc->todo); - init_waitqueue_head(&proc->wait); - proc->default_priority = task_nice(current); -- mutex_lock(&binder_lock); -+ -+ binder_lock(__func__); -+ - binder_stats_created(BINDER_STAT_PROC); - hlist_add_head(&proc->proc_node, &binder_procs); - proc->pid = current->group_leader->pid; - INIT_LIST_HEAD(&proc->delivered_death); - filp->private_data = proc; -- mutex_unlock(&binder_lock); -+ -+ binder_unlock(__func__); - - if (binder_debugfs_dir_entry_proc) { - char strbuf[11]; -@@ -3108,7 +3181,7 @@ static void binder_deferred_func(struct work_struct *work) - - int defer; - do { -- mutex_lock(&binder_lock); -+ binder_lock(__func__); - mutex_lock(&binder_deferred_lock); - if (!hlist_empty(&binder_deferred_list)) { - proc = hlist_entry(binder_deferred_list.first, -@@ -3135,7 +3208,7 @@ static void binder_deferred_func(struct work_struct *work) - if (defer & BINDER_DEFERRED_RELEASE) - binder_deferred_release(proc); /* frees proc */ - -- mutex_unlock(&binder_lock); -+ binder_unlock(__func__); - if (files) - put_files_struct(files); - } while (proc); -@@ -3476,7 +3549,7 @@ static int binder_state_show(struct seq_file *m, void *unused) - int do_lock = !binder_debug_no_lock; - - if (do_lock) -- mutex_lock(&binder_lock); -+ binder_lock(__func__); - - seq_puts(m, "binder state:\n"); - -@@ -3488,7 +3561,7 @@ static int binder_state_show(struct seq_file *m, void *unused) - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) - print_binder_proc(m, proc, 1); - if (do_lock) -- mutex_unlock(&binder_lock); -+ binder_unlock(__func__); - return 0; - } - -@@ -3499,7 +3572,7 @@ static int binder_stats_show(struct seq_file *m, void *unused) - int do_lock = !binder_debug_no_lock; - - if (do_lock) -- mutex_lock(&binder_lock); -+ binder_lock(__func__); - - seq_puts(m, "binder stats:\n"); - -@@ -3508,7 +3581,7 @@ static int binder_stats_show(struct seq_file *m, void *unused) - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) - print_binder_proc_stats(m, proc); - if (do_lock) -- mutex_unlock(&binder_lock); -+ binder_unlock(__func__); - return 0; - } - -@@ -3519,13 +3592,13 @@ static int binder_transactions_show(struct seq_file *m, void *unused) - int do_lock = !binder_debug_no_lock; - - if (do_lock) -- mutex_lock(&binder_lock); -+ binder_lock(__func__); - - seq_puts(m, "binder transactions:\n"); - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) - print_binder_proc(m, proc, 0); - if (do_lock) -- mutex_unlock(&binder_lock); -+ binder_unlock(__func__); - return 0; - } - -@@ -3535,11 +3608,11 @@ static int binder_proc_show(struct seq_file *m, void *unused) - int do_lock = !binder_debug_no_lock; - - if (do_lock) -- mutex_lock(&binder_lock); -+ binder_lock(__func__); - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, proc, 1); - if (do_lock) -- mutex_unlock(&binder_lock); -+ binder_unlock(__func__); - return 0; - } - -@@ -3634,4 +3707,7 @@ static int __init binder_init(void) - - device_initcall(binder_init); - -+#define CREATE_TRACE_POINTS -+#include "binder_trace.h" -+ - MODULE_LICENSE("GPL v2"); -diff --git a/drivers/staging/android/binder_trace.h b/drivers/staging/android/binder_trace.h -new file mode 100644 -index 00000000..82a567c2 ---- /dev/null -+++ b/drivers/staging/android/binder_trace.h -@@ -0,0 +1,327 @@ -+/* -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM binder -+ -+#if !defined(_BINDER_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _BINDER_TRACE_H -+ -+#include <linux/tracepoint.h> -+ -+struct binder_buffer; -+struct binder_node; -+struct binder_proc; -+struct binder_ref; -+struct binder_thread; -+struct binder_transaction; -+ -+TRACE_EVENT(binder_ioctl, -+ TP_PROTO(unsigned int cmd, unsigned long arg), -+ TP_ARGS(cmd, arg), -+ -+ TP_STRUCT__entry( -+ __field(unsigned int, cmd) -+ __field(unsigned long, arg) -+ ), -+ TP_fast_assign( -+ __entry->cmd = cmd; -+ __entry->arg = arg; -+ ), -+ TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg) -+); -+ -+DECLARE_EVENT_CLASS(binder_lock_class, -+ TP_PROTO(const char *tag), -+ TP_ARGS(tag), -+ TP_STRUCT__entry( -+ __field(const char *, tag) -+ ), -+ TP_fast_assign( -+ __entry->tag = tag; -+ ), -+ TP_printk("tag=%s", __entry->tag) -+); -+ -+#define DEFINE_BINDER_LOCK_EVENT(name) \ -+DEFINE_EVENT(binder_lock_class, name, \ -+ TP_PROTO(const char *func), \ -+ TP_ARGS(func)) -+ -+DEFINE_BINDER_LOCK_EVENT(binder_lock); -+DEFINE_BINDER_LOCK_EVENT(binder_locked); -+DEFINE_BINDER_LOCK_EVENT(binder_unlock); -+ -+DECLARE_EVENT_CLASS(binder_function_return_class, -+ TP_PROTO(int ret), -+ TP_ARGS(ret), -+ TP_STRUCT__entry( -+ __field(int, ret) -+ ), -+ TP_fast_assign( -+ __entry->ret = ret; -+ ), -+ TP_printk("ret=%d", __entry->ret) -+); -+ -+#define DEFINE_BINDER_FUNCTION_RETURN_EVENT(name) \ -+DEFINE_EVENT(binder_function_return_class, name, \ -+ TP_PROTO(int ret), \ -+ TP_ARGS(ret)) -+ -+DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done); -+DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done); -+DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done); -+ -+TRACE_EVENT(binder_wait_for_work, -+ TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo), -+ TP_ARGS(proc_work, transaction_stack, thread_todo), -+ -+ TP_STRUCT__entry( -+ __field(bool, proc_work) -+ __field(bool, transaction_stack) -+ __field(bool, thread_todo) -+ ), -+ TP_fast_assign( -+ __entry->proc_work = proc_work; -+ __entry->transaction_stack = transaction_stack; -+ __entry->thread_todo = thread_todo; -+ ), -+ TP_printk("proc_work=%d transaction_stack=%d thread_todo=%d", -+ __entry->proc_work, __entry->transaction_stack, -+ __entry->thread_todo) -+); -+ -+TRACE_EVENT(binder_transaction, -+ TP_PROTO(bool reply, struct binder_transaction *t, -+ struct binder_node *target_node), -+ TP_ARGS(reply, t, target_node), -+ TP_STRUCT__entry( -+ __field(int, debug_id) -+ __field(int, target_node) -+ __field(int, to_proc) -+ __field(int, to_thread) -+ __field(int, reply) -+ __field(unsigned int, code) -+ __field(unsigned int, flags) -+ ), -+ TP_fast_assign( -+ __entry->debug_id = t->debug_id; -+ __entry->target_node = target_node ? target_node->debug_id : 0; -+ __entry->to_proc = t->to_proc->pid; -+ __entry->to_thread = t->to_thread ? t->to_thread->pid : 0; -+ __entry->reply = reply; -+ __entry->code = t->code; -+ __entry->flags = t->flags; -+ ), -+ TP_printk("transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x code=0x%x", -+ __entry->debug_id, __entry->target_node, -+ __entry->to_proc, __entry->to_thread, -+ __entry->reply, __entry->flags, __entry->code) -+); -+ -+TRACE_EVENT(binder_transaction_received, -+ TP_PROTO(struct binder_transaction *t), -+ TP_ARGS(t), -+ -+ TP_STRUCT__entry( -+ __field(int, debug_id) -+ ), -+ TP_fast_assign( -+ __entry->debug_id = t->debug_id; -+ ), -+ TP_printk("transaction=%d", __entry->debug_id) -+); -+ -+TRACE_EVENT(binder_transaction_node_to_ref, -+ TP_PROTO(struct binder_transaction *t, struct binder_node *node, -+ struct binder_ref *ref), -+ TP_ARGS(t, node, ref), -+ -+ TP_STRUCT__entry( -+ __field(int, debug_id) -+ __field(int, node_debug_id) -+ __field(void __user *, node_ptr) -+ __field(int, ref_debug_id) -+ __field(uint32_t, ref_desc) -+ ), -+ TP_fast_assign( -+ __entry->debug_id = t->debug_id; -+ __entry->node_debug_id = node->debug_id; -+ __entry->node_ptr = node->ptr; -+ __entry->ref_debug_id = ref->debug_id; -+ __entry->ref_desc = ref->desc; -+ ), -+ TP_printk("transaction=%d node=%d src_ptr=0x%p ==> dest_ref=%d dest_desc=%d", -+ __entry->debug_id, __entry->node_debug_id, __entry->node_ptr, -+ __entry->ref_debug_id, __entry->ref_desc) -+); -+ -+TRACE_EVENT(binder_transaction_ref_to_node, -+ TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), -+ TP_ARGS(t, ref), -+ -+ TP_STRUCT__entry( -+ __field(int, debug_id) -+ __field(int, ref_debug_id) -+ __field(uint32_t, ref_desc) -+ __field(int, node_debug_id) -+ __field(void __user *, node_ptr) -+ ), -+ TP_fast_assign( -+ __entry->debug_id = t->debug_id; -+ __entry->ref_debug_id = ref->debug_id; -+ __entry->ref_desc = ref->desc; -+ __entry->node_debug_id = ref->node->debug_id; -+ __entry->node_ptr = ref->node->ptr; -+ ), -+ TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%p", -+ __entry->debug_id, __entry->node_debug_id, -+ __entry->ref_debug_id, __entry->ref_desc, __entry->node_ptr) -+); -+ -+TRACE_EVENT(binder_transaction_ref_to_ref, -+ TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, -+ struct binder_ref *dest_ref), -+ TP_ARGS(t, src_ref, dest_ref), -+ -+ TP_STRUCT__entry( -+ __field(int, debug_id) -+ __field(int, node_debug_id) -+ __field(int, src_ref_debug_id) -+ __field(uint32_t, src_ref_desc) -+ __field(int, dest_ref_debug_id) -+ __field(uint32_t, dest_ref_desc) -+ ), -+ TP_fast_assign( -+ __entry->debug_id = t->debug_id; -+ __entry->node_debug_id = src_ref->node->debug_id; -+ __entry->src_ref_debug_id = src_ref->debug_id; -+ __entry->src_ref_desc = src_ref->desc; -+ __entry->dest_ref_debug_id = dest_ref->debug_id; -+ __entry->dest_ref_desc = dest_ref->desc; -+ ), -+ TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ref=%d dest_desc=%d", -+ __entry->debug_id, __entry->node_debug_id, -+ __entry->src_ref_debug_id, __entry->src_ref_desc, -+ __entry->dest_ref_debug_id, __entry->dest_ref_desc) -+); -+ -+TRACE_EVENT(binder_transaction_fd, -+ TP_PROTO(struct binder_transaction *t, int src_fd, int dest_fd), -+ TP_ARGS(t, src_fd, dest_fd), -+ -+ TP_STRUCT__entry( -+ __field(int, debug_id) -+ __field(int, src_fd) -+ __field(int, dest_fd) -+ ), -+ TP_fast_assign( -+ __entry->debug_id = t->debug_id; -+ __entry->src_fd = src_fd; -+ __entry->dest_fd = dest_fd; -+ ), -+ TP_printk("transaction=%d src_fd=%d ==> dest_fd=%d", -+ __entry->debug_id, __entry->src_fd, __entry->dest_fd) -+); -+ -+DECLARE_EVENT_CLASS(binder_buffer_class, -+ TP_PROTO(struct binder_buffer *buf), -+ TP_ARGS(buf), -+ TP_STRUCT__entry( -+ __field(int, debug_id) -+ __field(size_t, data_size) -+ __field(size_t, offsets_size) -+ ), -+ TP_fast_assign( -+ __entry->debug_id = buf->debug_id; -+ __entry->data_size = buf->data_size; -+ __entry->offsets_size = buf->offsets_size; -+ ), -+ TP_printk("transaction=%d data_size=%zd offsets_size=%zd", -+ __entry->debug_id, __entry->data_size, __entry->offsets_size) -+); -+ -+DEFINE_EVENT(binder_buffer_class, binder_transaction_alloc_buf, -+ TP_PROTO(struct binder_buffer *buffer), -+ TP_ARGS(buffer)); -+ -+DEFINE_EVENT(binder_buffer_class, binder_transaction_buffer_release, -+ TP_PROTO(struct binder_buffer *buffer), -+ TP_ARGS(buffer)); -+ -+DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, -+ TP_PROTO(struct binder_buffer *buffer), -+ TP_ARGS(buffer)); -+ -+TRACE_EVENT(binder_update_page_range, -+ TP_PROTO(struct binder_proc *proc, bool allocate, -+ void *start, void *end), -+ TP_ARGS(proc, allocate, start, end), -+ TP_STRUCT__entry( -+ __field(int, proc) -+ __field(bool, allocate) -+ __field(size_t, offset) -+ __field(size_t, size) -+ ), -+ TP_fast_assign( -+ __entry->proc = proc->pid; -+ __entry->allocate = allocate; -+ __entry->offset = start - proc->buffer; -+ __entry->size = end - start; -+ ), -+ TP_printk("proc=%d allocate=%d offset=%zu size=%zu", -+ __entry->proc, __entry->allocate, -+ __entry->offset, __entry->size) -+); -+ -+TRACE_EVENT(binder_command, -+ TP_PROTO(uint32_t cmd), -+ TP_ARGS(cmd), -+ TP_STRUCT__entry( -+ __field(uint32_t, cmd) -+ ), -+ TP_fast_assign( -+ __entry->cmd = cmd; -+ ), -+ TP_printk("cmd=0x%x %s", -+ __entry->cmd, -+ _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_command_strings) ? -+ binder_command_strings[_IOC_NR(__entry->cmd)] : -+ "unknown") -+); -+ -+TRACE_EVENT(binder_return, -+ TP_PROTO(uint32_t cmd), -+ TP_ARGS(cmd), -+ TP_STRUCT__entry( -+ __field(uint32_t, cmd) -+ ), -+ TP_fast_assign( -+ __entry->cmd = cmd; -+ ), -+ TP_printk("cmd=0x%x %s", -+ __entry->cmd, -+ _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_return_strings) ? -+ binder_return_strings[_IOC_NR(__entry->cmd)] : -+ "unknown") -+); -+ -+#endif /* _BINDER_TRACE_H */ -+ -+#undef TRACE_INCLUDE_PATH -+#undef TRACE_INCLUDE_FILE -+#define TRACE_INCLUDE_PATH . -+#define TRACE_INCLUDE_FILE binder_trace -+#include <trace/define_trace.h> -diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c -index ea69b6a7..3813c743 100644 ---- a/drivers/staging/android/logger.c -+++ b/drivers/staging/android/logger.c -@@ -57,6 +57,8 @@ struct logger_reader { - struct logger_log *log; /* associated log */ - struct list_head list; /* entry in logger_log's list */ - size_t r_off; /* current read head offset */ -+ bool r_all; /* reader can read all entries */ -+ int r_ver; /* reader ABI version */ - }; - - /* logger_offset - returns index 'n' into the log via (optimized) modulus */ -@@ -90,8 +92,29 @@ static inline struct logger_log *file_get_log(struct file *file) - } - - /* -- * get_entry_len - Grabs the length of the payload of the next entry starting -- * from 'off'. -+ * get_entry_header - returns a pointer to the logger_entry header within -+ * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must -+ * be provided. Typically the return value will be a pointer within -+ * 'logger->buf'. However, a pointer to 'scratch' may be returned if -+ * the log entry spans the end and beginning of the circular buffer. -+ */ -+static struct logger_entry *get_entry_header(struct logger_log *log, -+ size_t off, struct logger_entry *scratch) -+{ -+ size_t len = min(sizeof(struct logger_entry), log->size - off); -+ if (len != sizeof(struct logger_entry)) { -+ memcpy(((void *) scratch), log->buffer + off, len); -+ memcpy(((void *) scratch) + len, log->buffer, -+ sizeof(struct logger_entry) - len); -+ return scratch; -+ } -+ -+ return (struct logger_entry *) (log->buffer + off); -+} -+ -+/* -+ * get_entry_msg_len - Grabs the length of the message of the entry -+ * starting from from 'off'. - * - * An entry length is 2 bytes (16 bits) in host endian order. - * In the log, the length does not include the size of the log entry structure. -@@ -99,20 +122,45 @@ static inline struct logger_log *file_get_log(struct file *file) - * - * Caller needs to hold log->mutex. - */ --static __u32 get_entry_len(struct logger_log *log, size_t off) -+static __u32 get_entry_msg_len(struct logger_log *log, size_t off) - { -- __u16 val; -+ struct logger_entry scratch; -+ struct logger_entry *entry; - -- /* copy 2 bytes from buffer, in memcpy order, */ -- /* handling possible wrap at end of buffer */ -+ entry = get_entry_header(log, off, &scratch); -+ return entry->len; -+} - -- ((__u8 *)&val)[0] = log->buffer[off]; -- if (likely(off+1 < log->size)) -- ((__u8 *)&val)[1] = log->buffer[off+1]; -+static size_t get_user_hdr_len(int ver) -+{ -+ if (ver < 2) -+ return sizeof(struct user_logger_entry_compat); - else -- ((__u8 *)&val)[1] = log->buffer[0]; -+ return sizeof(struct logger_entry); -+} - -- return sizeof(struct logger_entry) + val; -+static ssize_t copy_header_to_user(int ver, struct logger_entry *entry, -+ char __user *buf) -+{ -+ void *hdr; -+ size_t hdr_len; -+ struct user_logger_entry_compat v1; -+ -+ if (ver < 2) { -+ v1.len = entry->len; -+ v1.__pad = 0; -+ v1.pid = entry->pid; -+ v1.tid = entry->tid; -+ v1.sec = entry->sec; -+ v1.nsec = entry->nsec; -+ hdr = &v1; -+ hdr_len = sizeof(struct user_logger_entry_compat); -+ } else { -+ hdr = entry; -+ hdr_len = sizeof(struct logger_entry); -+ } -+ -+ return copy_to_user(buf, hdr, hdr_len); - } - - /* -@@ -126,15 +174,31 @@ static ssize_t do_read_log_to_user(struct logger_log *log, - char __user *buf, - size_t count) - { -+ struct logger_entry scratch; -+ struct logger_entry *entry; - size_t len; -+ size_t msg_start; - - /* -- * We read from the log in two disjoint operations. First, we read from -- * the current read head offset up to 'count' bytes or to the end of -+ * First, copy the header to userspace, using the version of -+ * the header requested -+ */ -+ entry = get_entry_header(log, reader->r_off, &scratch); -+ if (copy_header_to_user(reader->r_ver, entry, buf)) -+ return -EFAULT; -+ -+ count -= get_user_hdr_len(reader->r_ver); -+ buf += get_user_hdr_len(reader->r_ver); -+ msg_start = logger_offset(log, -+ reader->r_off + sizeof(struct logger_entry)); -+ -+ /* -+ * We read from the msg in two disjoint operations. First, we read from -+ * the current msg head offset up to 'count' bytes or to the end of - * the log, whichever comes first. - */ -- len = min(count, log->size - reader->r_off); -- if (copy_to_user(buf, log->buffer + reader->r_off, len)) -+ len = min(count, log->size - msg_start); -+ if (copy_to_user(buf, log->buffer + msg_start, len)) - return -EFAULT; - - /* -@@ -145,9 +209,34 @@ static ssize_t do_read_log_to_user(struct logger_log *log, - if (copy_to_user(buf + len, log->buffer, count - len)) - return -EFAULT; - -- reader->r_off = logger_offset(log, reader->r_off + count); -+ reader->r_off = logger_offset(log, reader->r_off + -+ sizeof(struct logger_entry) + count); - -- return count; -+ return count + get_user_hdr_len(reader->r_ver); -+} -+ -+/* -+ * get_next_entry_by_uid - Starting at 'off', returns an offset into -+ * 'log->buffer' which contains the first entry readable by 'euid' -+ */ -+static size_t get_next_entry_by_uid(struct logger_log *log, -+ size_t off, uid_t euid) -+{ -+ while (off != log->w_off) { -+ struct logger_entry *entry; -+ struct logger_entry scratch; -+ size_t next_len; -+ -+ entry = get_entry_header(log, off, &scratch); -+ -+ if (entry->euid == euid) -+ return off; -+ -+ next_len = sizeof(struct logger_entry) + entry->len; -+ off = logger_offset(log, off + next_len); -+ } -+ -+ return off; - } - - /* -@@ -159,7 +248,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log, - * - If there are no log entries to read, blocks until log is written to - * - Atomically reads exactly one log entry - * -- * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read -+ * Will set errno to EINVAL if read - * buffer is insufficient to hold next entry. - */ - static ssize_t logger_read(struct file *file, char __user *buf, -@@ -200,6 +289,10 @@ start: - - mutex_lock(&log->mutex); - -+ if (!reader->r_all) -+ reader->r_off = get_next_entry_by_uid(log, -+ reader->r_off, current_euid()); -+ - /* is there still something to read or did we race? */ - if (unlikely(log->w_off == reader->r_off)) { - mutex_unlock(&log->mutex); -@@ -207,7 +300,8 @@ start: - } - - /* get the size of the next entry */ -- ret = get_entry_len(log, reader->r_off); -+ ret = get_user_hdr_len(reader->r_ver) + -+ get_entry_msg_len(log, reader->r_off); - if (count < ret) { - ret = -EINVAL; - goto out; -@@ -233,7 +327,8 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len) - size_t count = 0; - - do { -- size_t nr = get_entry_len(log, off); -+ size_t nr = sizeof(struct logger_entry) + -+ get_entry_msg_len(log, off); - off = logger_offset(log, off + nr); - count += nr; - } while (count < len); -@@ -363,7 +458,9 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, - header.tid = current->pid; - header.sec = now.tv_sec; - header.nsec = now.tv_nsec; -+ header.euid = current_euid(); - header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD); -+ header.hdr_size = sizeof(struct logger_entry); - - /* null writes succeed, return zero */ - if (unlikely(!header.len)) -@@ -436,6 +533,10 @@ static int logger_open(struct inode *inode, struct file *file) - return -ENOMEM; - - reader->log = log; -+ reader->r_ver = 1; -+ reader->r_all = in_egroup_p(inode->i_gid) || -+ capable(CAP_SYSLOG); -+ - INIT_LIST_HEAD(&reader->list); - - mutex_lock(&log->mutex); -@@ -495,6 +596,10 @@ static unsigned int logger_poll(struct file *file, poll_table *wait) - poll_wait(file, &log->wq, wait); - - mutex_lock(&log->mutex); -+ if (!reader->r_all) -+ reader->r_off = get_next_entry_by_uid(log, -+ reader->r_off, current_euid()); -+ - if (log->w_off != reader->r_off) - ret |= POLLIN | POLLRDNORM; - mutex_unlock(&log->mutex); -@@ -502,11 +607,25 @@ static unsigned int logger_poll(struct file *file, poll_table *wait) - return ret; - } - -+static long logger_set_version(struct logger_reader *reader, void __user *arg) -+{ -+ int version; -+ if (copy_from_user(&version, arg, sizeof(int))) -+ return -EFAULT; -+ -+ if ((version < 1) || (version > 2)) -+ return -EINVAL; -+ -+ reader->r_ver = version; -+ return 0; -+} -+ - static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - { - struct logger_log *log = file_get_log(file); - struct logger_reader *reader; -- long ret = -ENOTTY; -+ long ret = -EINVAL; -+ void __user *argp = (void __user *) arg; - - mutex_lock(&log->mutex); - -@@ -531,8 +650,14 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - break; - } - reader = file->private_data; -+ -+ if (!reader->r_all) -+ reader->r_off = get_next_entry_by_uid(log, -+ reader->r_off, current_euid()); -+ - if (log->w_off != reader->r_off) -- ret = get_entry_len(log, reader->r_off); -+ ret = get_user_hdr_len(reader->r_ver) + -+ get_entry_msg_len(log, reader->r_off); - else - ret = 0; - break; -@@ -541,11 +666,32 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - ret = -EBADF; - break; - } -+ if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) || -+ capable(CAP_SYSLOG))) { -+ ret = -EPERM; -+ break; -+ } - list_for_each_entry(reader, &log->readers, list) - reader->r_off = log->w_off; - log->head = log->w_off; - ret = 0; - break; -+ case LOGGER_GET_VERSION: -+ if (!(file->f_mode & FMODE_READ)) { -+ ret = -EBADF; -+ break; -+ } -+ reader = file->private_data; -+ ret = reader->r_ver; -+ break; -+ case LOGGER_SET_VERSION: -+ if (!(file->f_mode & FMODE_READ)) { -+ ret = -EBADF; -+ break; -+ } -+ reader = file->private_data; -+ ret = logger_set_version(reader, argp); -+ break; - } - - mutex_unlock(&log->mutex); -@@ -566,8 +712,8 @@ static const struct file_operations logger_fops = { - - /* - * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which -- * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than -- * LONG_MAX minus LOGGER_ENTRY_MAX_LEN. -+ * must be a power of two, and greater than -+ * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)). - */ - #define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \ - static unsigned char _buf_ ## VAR[SIZE]; \ -diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h -index 2cb06e9d..3f612a3b 100644 ---- a/drivers/staging/android/logger.h -+++ b/drivers/staging/android/logger.h -@@ -20,7 +20,12 @@ - #include <linux/types.h> - #include <linux/ioctl.h> - --struct logger_entry { -+/* -+ * The userspace structure for version 1 of the logger_entry ABI. -+ * This structure is returned to userspace unless the caller requests -+ * an upgrade to a newer ABI version. -+ */ -+struct user_logger_entry_compat { - __u16 len; /* length of the payload */ - __u16 __pad; /* no matter what, we get 2 bytes of padding */ - __s32 pid; /* generating process's pid */ -@@ -30,14 +35,28 @@ struct logger_entry { - char msg[0]; /* the entry's payload */ - }; - -+/* -+ * The structure for version 2 of the logger_entry ABI. -+ * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION) -+ * is called with version >= 2 -+ */ -+struct logger_entry { -+ __u16 len; /* length of the payload */ -+ __u16 hdr_size; /* sizeof(struct logger_entry_v2) */ -+ __s32 pid; /* generating process's pid */ -+ __s32 tid; /* generating process's tid */ -+ __s32 sec; /* seconds since Epoch */ -+ __s32 nsec; /* nanoseconds */ -+ uid_t euid; /* effective UID of logger */ -+ char msg[0]; /* the entry's payload */ -+}; -+ - #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ - #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ - #define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */ - #define LOGGER_LOG_MAIN "log_main" /* everything else */ - --#define LOGGER_ENTRY_MAX_LEN (4*1024) --#define LOGGER_ENTRY_MAX_PAYLOAD \ -- (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry)) -+#define LOGGER_ENTRY_MAX_PAYLOAD 4076 - - #define __LOGGERIO 0xAE - -@@ -45,5 +64,7 @@ struct logger_entry { - #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ - #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ - #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ -+#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */ -+#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */ - - #endif /* _LINUX_LOGGER_H */ -diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c -index b91e4bc3..12f0a13a 100644 ---- a/drivers/staging/android/lowmemorykiller.c -+++ b/drivers/staging/android/lowmemorykiller.c -@@ -35,11 +35,11 @@ - #include <linux/mm.h> - #include <linux/oom.h> - #include <linux/sched.h> -+#include <linux/swap.h> - #include <linux/rcupdate.h> --#include <linux/profile.h> - #include <linux/notifier.h> - --static uint32_t lowmem_debug_level = 2; -+static uint32_t lowmem_debug_level = 1; - static int lowmem_adj[6] = { - 0, - 1, -@@ -74,7 +74,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) - int selected_tasksize = 0; - int selected_oom_score_adj; - int array_size = ARRAY_SIZE(lowmem_adj); -- int other_free = global_page_state(NR_FREE_PAGES); -+ int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages; - int other_file = global_page_state(NR_FILE_PAGES) - - global_page_state(NR_SHMEM); - -@@ -175,9 +175,94 @@ static void __exit lowmem_exit(void) - unregister_shrinker(&lowmem_shrinker); - } - -+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES -+static int lowmem_oom_adj_to_oom_score_adj(int oom_adj) -+{ -+ if (oom_adj == OOM_ADJUST_MAX) -+ return OOM_SCORE_ADJ_MAX; -+ else -+ return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; -+} -+ -+static void lowmem_autodetect_oom_adj_values(void) -+{ -+ int i; -+ int oom_adj; -+ int oom_score_adj; -+ int array_size = ARRAY_SIZE(lowmem_adj); -+ -+ if (lowmem_adj_size < array_size) -+ array_size = lowmem_adj_size; -+ -+ if (array_size <= 0) -+ return; -+ -+ oom_adj = lowmem_adj[array_size - 1]; -+ if (oom_adj > OOM_ADJUST_MAX) -+ return; -+ -+ oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj); -+ if (oom_score_adj <= OOM_ADJUST_MAX) -+ return; -+ -+ lowmem_print(1, "lowmem_shrink: convert oom_adj to oom_score_adj:\n"); -+ for (i = 0; i < array_size; i++) { -+ oom_adj = lowmem_adj[i]; -+ oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj); -+ lowmem_adj[i] = oom_score_adj; -+ lowmem_print(1, "oom_adj %d => oom_score_adj %d\n", -+ oom_adj, oom_score_adj); -+ } -+} -+ -+static int lowmem_adj_array_set(const char *val, const struct kernel_param *kp) -+{ -+ int ret; -+ -+ ret = param_array_ops.set(val, kp); -+ -+ /* HACK: Autodetect oom_adj values in lowmem_adj array */ -+ lowmem_autodetect_oom_adj_values(); -+ -+ return ret; -+} -+ -+static int lowmem_adj_array_get(char *buffer, const struct kernel_param *kp) -+{ -+ return param_array_ops.get(buffer, kp); -+} -+ -+static void lowmem_adj_array_free(void *arg) -+{ -+ param_array_ops.free(arg); -+} -+ -+static struct kernel_param_ops lowmem_adj_array_ops = { -+ .set = lowmem_adj_array_set, -+ .get = lowmem_adj_array_get, -+ .free = lowmem_adj_array_free, -+}; -+ -+static const struct kparam_array __param_arr_adj = { -+ .max = ARRAY_SIZE(lowmem_adj), -+ .num = &lowmem_adj_size, -+ .ops = ¶m_ops_int, -+ .elemsize = sizeof(lowmem_adj[0]), -+ .elem = lowmem_adj, -+}; -+#endif -+ - module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); -+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES -+__module_param_call(MODULE_PARAM_PREFIX, adj, -+ &lowmem_adj_array_ops, -+ .arr = &__param_arr_adj, -+ S_IRUGO | S_IWUSR, -1); -+__MODULE_PARM_TYPE(adj, "array of int"); -+#else - module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, - S_IRUGO | S_IWUSR); -+#endif - module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, - S_IRUGO | S_IWUSR); - module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); -diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c -index 3d986ce5..e9e08fd0 100644 ---- a/drivers/staging/android/persistent_ram.c -+++ b/drivers/staging/android/persistent_ram.c -@@ -20,10 +20,10 @@ - #include <linux/io.h> - #include <linux/list.h> - #include <linux/memblock.h> -+#include <linux/persistent_ram.h> - #include <linux/rslib.h> - #include <linux/slab.h> - #include <linux/vmalloc.h> --#include "persistent_ram.h" - - struct persistent_ram_buffer { - uint32_t sig; -@@ -34,7 +34,7 @@ struct persistent_ram_buffer { - - #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ - --static __initdata LIST_HEAD(persistent_ram_list); -+static __devinitdata LIST_HEAD(persistent_ram_list); - - static inline size_t buffer_size(struct persistent_ram_zone *prz) - { -@@ -173,7 +173,7 @@ static void persistent_ram_ecc_old(struct persistent_ram_zone *prz) - } - - static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, -- size_t buffer_size) -+ size_t buffer_size, struct persistent_ram *ram) - { - int numerr; - struct persistent_ram_buffer *buffer = prz->buffer; -@@ -182,12 +182,13 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, - if (!prz->ecc) - return 0; - -- prz->ecc_block_size = 128; -- prz->ecc_size = 16; -- prz->ecc_symsize = 8; -- prz->ecc_poly = 0x11d; -+ prz->ecc_block_size = ram->ecc_block_size ?: 128; -+ prz->ecc_size = ram->ecc_size ?: 16; -+ prz->ecc_symsize = ram->ecc_symsize ?: 8; -+ prz->ecc_poly = ram->ecc_poly ?: 0x11d; - -- ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size); -+ ecc_blocks = DIV_ROUND_UP(prz->buffer_size - prz->ecc_size, -+ prz->ecc_block_size + prz->ecc_size); - prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size; - - if (prz->buffer_size > buffer_size) { -@@ -249,7 +250,7 @@ static void notrace persistent_ram_update(struct persistent_ram_zone *prz, - persistent_ram_update_ecc(prz, start, count); - } - --static void __init -+static void __devinit - persistent_ram_save_old(struct persistent_ram_zone *prz) - { - struct persistent_ram_buffer *buffer = prz->buffer; -@@ -356,8 +357,8 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, - return 0; - } - --static int __init persistent_ram_buffer_init(const char *name, -- struct persistent_ram_zone *prz) -+static int __devinit persistent_ram_buffer_init(const char *name, -+ struct persistent_ram_zone *prz, struct persistent_ram **ramp) - { - int i; - struct persistent_ram *ram; -@@ -368,9 +369,11 @@ static int __init persistent_ram_buffer_init(const char *name, - start = ram->start; - for (i = 0; i < ram->num_descs; i++) { - desc = &ram->descs[i]; -- if (!strcmp(desc->name, name)) -+ if (!strcmp(desc->name, name)) { -+ *ramp = ram; - return persistent_ram_buffer_map(start, - desc->size, prz); -+ } - start += desc->size; - } - } -@@ -378,9 +381,10 @@ static int __init persistent_ram_buffer_init(const char *name, - return -EINVAL; - } - --static __init -+static __devinit - struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) - { -+ struct persistent_ram *ram; - struct persistent_ram_zone *prz; - int ret = -ENOMEM; - -@@ -392,14 +396,14 @@ struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) - - INIT_LIST_HEAD(&prz->node); - -- ret = persistent_ram_buffer_init(dev_name(dev), prz); -+ ret = persistent_ram_buffer_init(dev_name(dev), prz, &ram); - if (ret) { - pr_err("persistent_ram: failed to initialize buffer\n"); - goto err; - } - - prz->ecc = ecc; -- ret = persistent_ram_init_ecc(prz, prz->buffer_size); -+ ret = persistent_ram_init_ecc(prz, prz->buffer_size, ram); - if (ret) - goto err; - -@@ -407,11 +411,11 @@ struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) - if (buffer_size(prz) > prz->buffer_size || - buffer_start(prz) > buffer_size(prz)) - pr_info("persistent_ram: found existing invalid buffer," -- " size %ld, start %ld\n", -+ " size %zu, start %zu\n", - buffer_size(prz), buffer_start(prz)); - else { - pr_info("persistent_ram: found existing buffer," -- " size %ld, start %ld\n", -+ " size %zu, start %zu\n", - buffer_size(prz), buffer_start(prz)); - persistent_ram_save_old(prz); - } -@@ -430,7 +434,7 @@ err: - return ERR_PTR(ret); - } - --struct persistent_ram_zone * __init -+struct persistent_ram_zone * __devinit - persistent_ram_init_ringbuffer(struct device *dev, bool ecc) - { - return __persistent_ram_init(dev, ecc); -diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c -index ce140ffc..cf0f8fb4 100644 ---- a/drivers/staging/android/ram_console.c -+++ b/drivers/staging/android/ram_console.c -@@ -16,12 +16,12 @@ - #include <linux/console.h> - #include <linux/init.h> - #include <linux/module.h> -+#include <linux/persistent_ram.h> - #include <linux/platform_device.h> - #include <linux/proc_fs.h> - #include <linux/string.h> - #include <linux/uaccess.h> - #include <linux/io.h> --#include "persistent_ram.h" - #include "ram_console.h" - - static struct persistent_ram_zone *ram_console_zone; -@@ -50,7 +50,7 @@ void ram_console_enable_console(int enabled) - ram_console.flags &= ~CON_ENABLED; - } - --static int __init ram_console_probe(struct platform_device *pdev) -+static int __devinit ram_console_probe(struct platform_device *pdev) - { - struct ram_console_platform_data *pdata = pdev->dev.platform_data; - struct persistent_ram_zone *prz; -@@ -78,11 +78,12 @@ static struct platform_driver ram_console_driver = { - .driver = { - .name = "ram_console", - }, -+ .probe = ram_console_probe, - }; - - static int __init ram_console_module_init(void) - { -- return platform_driver_probe(&ram_console_driver, ram_console_probe); -+ return platform_driver_register(&ram_console_driver); - } - - #ifndef CONFIG_PRINTK -@@ -100,9 +101,6 @@ static ssize_t ram_console_read_old(struct file *file, char __user *buf, - char *str; - int ret; - -- if (dmesg_restrict && !capable(CAP_SYSLOG)) -- return -EPERM; -- - /* Main last_kmsg log */ - if (pos < old_log_size) { - count = min(len, (size_t)(old_log_size - pos)); -diff --git a/drivers/staging/android/trace_persistent.c b/drivers/staging/android/trace_persistent.c -new file mode 100644 -index 00000000..7c3e9499 ---- /dev/null -+++ b/drivers/staging/android/trace_persistent.c -@@ -0,0 +1,242 @@ -+/* -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/debugfs.h> -+#include <linux/errno.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/persistent_ram.h> -+#include <linux/platform_device.h> -+#include <linux/seq_file.h> -+#include <linux/slab.h> -+ -+#include "../../../kernel/trace/trace.h" -+ -+struct persistent_trace_record { -+ unsigned long ip; -+ unsigned long parent_ip; -+}; -+ -+#define REC_SIZE sizeof(struct persistent_trace_record) -+ -+static struct persistent_ram_zone *persistent_trace; -+ -+static int persistent_trace_enabled; -+ -+static struct trace_array *persistent_trace_array; -+ -+static struct ftrace_ops trace_ops; -+ -+static int persistent_tracer_init(struct trace_array *tr) -+{ -+ persistent_trace_array = tr; -+ tr->cpu = get_cpu(); -+ put_cpu(); -+ -+ tracing_start_cmdline_record(); -+ -+ persistent_trace_enabled = 0; -+ smp_wmb(); -+ -+ register_ftrace_function(&trace_ops); -+ -+ smp_wmb(); -+ persistent_trace_enabled = 1; -+ -+ return 0; -+} -+ -+static void persistent_trace_reset(struct trace_array *tr) -+{ -+ persistent_trace_enabled = 0; -+ smp_wmb(); -+ -+ unregister_ftrace_function(&trace_ops); -+ -+ tracing_stop_cmdline_record(); -+} -+ -+static void persistent_trace_start(struct trace_array *tr) -+{ -+ tracing_reset_online_cpus(tr); -+} -+ -+static void persistent_trace_call(unsigned long ip, unsigned long parent_ip) -+{ -+ struct trace_array *tr = persistent_trace_array; -+ struct trace_array_cpu *data; -+ long disabled; -+ struct persistent_trace_record rec; -+ unsigned long flags; -+ int cpu; -+ -+ smp_rmb(); -+ if (unlikely(!persistent_trace_enabled)) -+ return; -+ -+ if (unlikely(oops_in_progress)) -+ return; -+ -+ /* -+ * Need to use raw, since this must be called before the -+ * recursive protection is performed. -+ */ -+ local_irq_save(flags); -+ cpu = raw_smp_processor_id(); -+ data = tr->data[cpu]; -+ disabled = atomic_inc_return(&data->disabled); -+ -+ if (likely(disabled == 1)) { -+ rec.ip = ip; -+ rec.parent_ip = parent_ip; -+ rec.ip |= cpu; -+ persistent_ram_write(persistent_trace, &rec, sizeof(rec)); -+ } -+ -+ atomic_dec(&data->disabled); -+ local_irq_restore(flags); -+} -+ -+static struct ftrace_ops trace_ops __read_mostly = { -+ .func = persistent_trace_call, -+ .flags = FTRACE_OPS_FL_GLOBAL, -+}; -+ -+static struct tracer persistent_tracer __read_mostly = { -+ .name = "persistent", -+ .init = persistent_tracer_init, -+ .reset = persistent_trace_reset, -+ .start = persistent_trace_start, -+ .wait_pipe = poll_wait_pipe, -+}; -+ -+struct persistent_trace_seq_data { -+ const void *ptr; -+ size_t off; -+ size_t size; -+}; -+ -+void *persistent_trace_seq_start(struct seq_file *s, loff_t *pos) -+{ -+ struct persistent_trace_seq_data *data; -+ -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return NULL; -+ -+ data->ptr = persistent_ram_old(persistent_trace); -+ data->size = persistent_ram_old_size(persistent_trace); -+ data->off = data->size % REC_SIZE; -+ -+ data->off += *pos * REC_SIZE; -+ -+ if (data->off + REC_SIZE > data->size) { -+ kfree(data); -+ return NULL; -+ } -+ -+ return data; -+ -+} -+void persistent_trace_seq_stop(struct seq_file *s, void *v) -+{ -+ kfree(v); -+} -+ -+void *persistent_trace_seq_next(struct seq_file *s, void *v, loff_t *pos) -+{ -+ struct persistent_trace_seq_data *data = v; -+ -+ data->off += REC_SIZE; -+ -+ if (data->off + REC_SIZE > data->size) -+ return NULL; -+ -+ (*pos)++; -+ -+ return data; -+} -+ -+int persistent_trace_seq_show(struct seq_file *s, void *v) -+{ -+ struct persistent_trace_seq_data *data = v; -+ struct persistent_trace_record *rec; -+ -+ rec = (struct persistent_trace_record *)(data->ptr + data->off); -+ -+ seq_printf(s, "%ld %08lx %08lx %pf <- %pF\n", -+ rec->ip & 3, rec->ip, rec->parent_ip, -+ (void *)rec->ip, (void *)rec->parent_ip); -+ -+ return 0; -+} -+ -+static const struct seq_operations persistent_trace_seq_ops = { -+ .start = persistent_trace_seq_start, -+ .next = persistent_trace_seq_next, -+ .stop = persistent_trace_seq_stop, -+ .show = persistent_trace_seq_show, -+}; -+ -+static int persistent_trace_old_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &persistent_trace_seq_ops); -+} -+ -+static const struct file_operations persistent_trace_old_fops = { -+ .open = persistent_trace_old_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+static int __devinit persistent_trace_probe(struct platform_device *pdev) -+{ -+ struct dentry *d; -+ int ret; -+ -+ persistent_trace = persistent_ram_init_ringbuffer(&pdev->dev, false); -+ if (IS_ERR(persistent_trace)) { -+ pr_err("persistent_trace: failed to init ringbuffer: %ld\n", -+ PTR_ERR(persistent_trace)); -+ return PTR_ERR(persistent_trace); -+ } -+ -+ ret = register_tracer(&persistent_tracer); -+ if (ret) -+ pr_err("persistent_trace: failed to register tracer"); -+ -+ if (persistent_ram_old_size(persistent_trace) > 0) { -+ d = debugfs_create_file("persistent_trace", S_IRUGO, NULL, -+ NULL, &persistent_trace_old_fops); -+ if (IS_ERR_OR_NULL(d)) -+ pr_err("persistent_trace: failed to create old file\n"); -+ } -+ -+ return 0; -+} -+ -+static struct platform_driver persistent_trace_driver = { -+ .probe = persistent_trace_probe, -+ .driver = { -+ .name = "persistent_trace", -+ }, -+}; -+ -+static int __init persistent_trace_init(void) -+{ -+ return platform_driver_register(&persistent_trace_driver); -+} -+core_initcall(persistent_trace_init); -diff --git a/drivers/staging/iio/industrialio-event.c b/drivers/staging/iio/industrialio-event.c -index 5fdf739e..68ef8264 100644 ---- a/drivers/staging/iio/industrialio-event.c -+++ b/drivers/staging/iio/industrialio-event.c -@@ -35,6 +35,7 @@ - */ - struct iio_event_interface { - wait_queue_head_t wait; -+ struct mutex read_lock; - DECLARE_KFIFO(det_events, struct iio_event_data, 16); - - struct list_head dev_attr_list; -@@ -96,14 +97,16 @@ static ssize_t iio_event_chrdev_read(struct file *filep, - if (count < sizeof(struct iio_event_data)) - return -EINVAL; - -- spin_lock(&ev_int->wait.lock); -+ if (mutex_lock_interruptible(&ev_int->read_lock)) -+ return -ERESTARTSYS; -+ - if (kfifo_is_empty(&ev_int->det_events)) { - if (filep->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto error_unlock; - } - /* Blocking on device; waiting for something to be there */ -- ret = wait_event_interruptible_locked(ev_int->wait, -+ ret = wait_event_interruptible(ev_int->wait, - !kfifo_is_empty(&ev_int->det_events)); - if (ret) - goto error_unlock; -@@ -113,7 +116,7 @@ static ssize_t iio_event_chrdev_read(struct file *filep, - ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied); - - error_unlock: -- spin_unlock(&ev_int->wait.lock); -+ mutex_unlock(&ev_int->read_lock); - - return ret ? ret : copied; - } -@@ -376,6 +379,7 @@ static void iio_setup_ev_int(struct iio_event_interface *ev_int) - { - INIT_KFIFO(ev_int->det_events); - init_waitqueue_head(&ev_int->wait); -+ mutex_init(&ev_int->read_lock); - } - - static const char *iio_event_group_name = "events"; -@@ -437,6 +441,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) - - error_free_setup_event_lines: - __iio_remove_event_config_attrs(indio_dev); -+ mutex_destroy(&indio_dev->event_interface->read_lock); - kfree(indio_dev->event_interface); - error_ret: - -@@ -449,5 +454,6 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev) - return; - __iio_remove_event_config_attrs(indio_dev); - kfree(indio_dev->event_interface->group.attrs); -+ mutex_destroy(&indio_dev->event_interface->read_lock); - kfree(indio_dev->event_interface); - } -diff --git a/drivers/switch/Kconfig b/drivers/switch/Kconfig -new file mode 100644 -index 00000000..52385914 ---- /dev/null -+++ b/drivers/switch/Kconfig -@@ -0,0 +1,15 @@ -+menuconfig SWITCH -+ tristate "Switch class support" -+ help -+ Say Y here to enable switch class support. This allows -+ monitoring switches by userspace via sysfs and uevent. -+ -+if SWITCH -+ -+config SWITCH_GPIO -+ tristate "GPIO Swith support" -+ depends on GENERIC_GPIO -+ help -+ Say Y here to enable GPIO based switch support. -+ -+endif # SWITCH -diff --git a/drivers/switch/Makefile b/drivers/switch/Makefile -new file mode 100644 -index 00000000..f7606ed4 ---- /dev/null -+++ b/drivers/switch/Makefile -@@ -0,0 +1,4 @@ -+# Switch Class Driver -+obj-$(CONFIG_SWITCH) += switch_class.o -+obj-$(CONFIG_SWITCH_GPIO) += switch_gpio.o -+ -diff --git a/drivers/switch/switch_class.c b/drivers/switch/switch_class.c -new file mode 100644 -index 00000000..e05fc259 ---- /dev/null -+++ b/drivers/switch/switch_class.c -@@ -0,0 +1,174 @@ -+/* -+ * drivers/switch/switch_class.c -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+*/ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/fs.h> -+#include <linux/err.h> -+#include <linux/switch.h> -+ -+struct class *switch_class; -+static atomic_t device_count; -+ -+static ssize_t state_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct switch_dev *sdev = (struct switch_dev *) -+ dev_get_drvdata(dev); -+ -+ if (sdev->print_state) { -+ int ret = sdev->print_state(sdev, buf); -+ if (ret >= 0) -+ return ret; -+ } -+ return sprintf(buf, "%d\n", sdev->state); -+} -+ -+static ssize_t name_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct switch_dev *sdev = (struct switch_dev *) -+ dev_get_drvdata(dev); -+ -+ if (sdev->print_name) { -+ int ret = sdev->print_name(sdev, buf); -+ if (ret >= 0) -+ return ret; -+ } -+ return sprintf(buf, "%s\n", sdev->name); -+} -+ -+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL); -+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL); -+ -+void switch_set_state(struct switch_dev *sdev, int state) -+{ -+ char name_buf[120]; -+ char state_buf[120]; -+ char *prop_buf; -+ char *envp[3]; -+ int env_offset = 0; -+ int length; -+ -+ if (sdev->state != state) { -+ sdev->state = state; -+ -+ prop_buf = (char *)get_zeroed_page(GFP_KERNEL); -+ if (prop_buf) { -+ length = name_show(sdev->dev, NULL, prop_buf); -+ if (length > 0) { -+ if (prop_buf[length - 1] == '\n') -+ prop_buf[length - 1] = 0; -+ snprintf(name_buf, sizeof(name_buf), -+ "SWITCH_NAME=%s", prop_buf); -+ envp[env_offset++] = name_buf; -+ } -+ length = state_show(sdev->dev, NULL, prop_buf); -+ if (length > 0) { -+ if (prop_buf[length - 1] == '\n') -+ prop_buf[length - 1] = 0; -+ snprintf(state_buf, sizeof(state_buf), -+ "SWITCH_STATE=%s", prop_buf); -+ envp[env_offset++] = state_buf; -+ } -+ envp[env_offset] = NULL; -+ kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp); -+ free_page((unsigned long)prop_buf); -+ } else { -+ printk(KERN_ERR "out of memory in switch_set_state\n"); -+ kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE); -+ } -+ } -+} -+EXPORT_SYMBOL_GPL(switch_set_state); -+ -+static int create_switch_class(void) -+{ -+ if (!switch_class) { -+ switch_class = class_create(THIS_MODULE, "switch"); -+ if (IS_ERR(switch_class)) -+ return PTR_ERR(switch_class); -+ atomic_set(&device_count, 0); -+ } -+ -+ return 0; -+} -+ -+int switch_dev_register(struct switch_dev *sdev) -+{ -+ int ret; -+ -+ if (!switch_class) { -+ ret = create_switch_class(); -+ if (ret < 0) -+ return ret; -+ } -+ -+ sdev->index = atomic_inc_return(&device_count); -+ sdev->dev = device_create(switch_class, NULL, -+ MKDEV(0, sdev->index), NULL, sdev->name); -+ if (IS_ERR(sdev->dev)) -+ return PTR_ERR(sdev->dev); -+ -+ ret = device_create_file(sdev->dev, &dev_attr_state); -+ if (ret < 0) -+ goto err_create_file_1; -+ ret = device_create_file(sdev->dev, &dev_attr_name); -+ if (ret < 0) -+ goto err_create_file_2; -+ -+ dev_set_drvdata(sdev->dev, sdev); -+ sdev->state = 0; -+ return 0; -+ -+err_create_file_2: -+ device_remove_file(sdev->dev, &dev_attr_state); -+err_create_file_1: -+ device_destroy(switch_class, MKDEV(0, sdev->index)); -+ printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(switch_dev_register); -+ -+void switch_dev_unregister(struct switch_dev *sdev) -+{ -+ device_remove_file(sdev->dev, &dev_attr_name); -+ device_remove_file(sdev->dev, &dev_attr_state); -+ device_destroy(switch_class, MKDEV(0, sdev->index)); -+ dev_set_drvdata(sdev->dev, NULL); -+} -+EXPORT_SYMBOL_GPL(switch_dev_unregister); -+ -+static int __init switch_class_init(void) -+{ -+ return create_switch_class(); -+} -+ -+static void __exit switch_class_exit(void) -+{ -+ class_destroy(switch_class); -+} -+ -+module_init(switch_class_init); -+module_exit(switch_class_exit); -+ -+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); -+MODULE_DESCRIPTION("Switch class driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/switch/switch_gpio.c b/drivers/switch/switch_gpio.c -new file mode 100644 -index 00000000..7e9faa21 ---- /dev/null -+++ b/drivers/switch/switch_gpio.c -@@ -0,0 +1,172 @@ -+/* -+ * drivers/switch/switch_gpio.c -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+*/ -+ -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/switch.h> -+#include <linux/workqueue.h> -+#include <linux/gpio.h> -+ -+struct gpio_switch_data { -+ struct switch_dev sdev; -+ unsigned gpio; -+ const char *name_on; -+ const char *name_off; -+ const char *state_on; -+ const char *state_off; -+ int irq; -+ struct work_struct work; -+}; -+ -+static void gpio_switch_work(struct work_struct *work) -+{ -+ int state; -+ struct gpio_switch_data *data = -+ container_of(work, struct gpio_switch_data, work); -+ -+ state = gpio_get_value(data->gpio); -+ switch_set_state(&data->sdev, state); -+} -+ -+static irqreturn_t gpio_irq_handler(int irq, void *dev_id) -+{ -+ struct gpio_switch_data *switch_data = -+ (struct gpio_switch_data *)dev_id; -+ -+ schedule_work(&switch_data->work); -+ return IRQ_HANDLED; -+} -+ -+static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf) -+{ -+ struct gpio_switch_data *switch_data = -+ container_of(sdev, struct gpio_switch_data, sdev); -+ const char *state; -+ if (switch_get_state(sdev)) -+ state = switch_data->state_on; -+ else -+ state = switch_data->state_off; -+ -+ if (state) -+ return sprintf(buf, "%s\n", state); -+ return -1; -+} -+ -+static int gpio_switch_probe(struct platform_device *pdev) -+{ -+ struct gpio_switch_platform_data *pdata = pdev->dev.platform_data; -+ struct gpio_switch_data *switch_data; -+ int ret = 0; -+ -+ if (!pdata) -+ return -EBUSY; -+ -+ switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL); -+ if (!switch_data) -+ return -ENOMEM; -+ -+ switch_data->sdev.name = pdata->name; -+ switch_data->gpio = pdata->gpio; -+ switch_data->name_on = pdata->name_on; -+ switch_data->name_off = pdata->name_off; -+ switch_data->state_on = pdata->state_on; -+ switch_data->state_off = pdata->state_off; -+ switch_data->sdev.print_state = switch_gpio_print_state; -+ -+ ret = switch_dev_register(&switch_data->sdev); -+ if (ret < 0) -+ goto err_switch_dev_register; -+ -+ ret = gpio_request(switch_data->gpio, pdev->name); -+ if (ret < 0) -+ goto err_request_gpio; -+ -+ ret = gpio_direction_input(switch_data->gpio); -+ if (ret < 0) -+ goto err_set_gpio_input; -+ -+ INIT_WORK(&switch_data->work, gpio_switch_work); -+ -+ switch_data->irq = gpio_to_irq(switch_data->gpio); -+ if (switch_data->irq < 0) { -+ ret = switch_data->irq; -+ goto err_detect_irq_num_failed; -+ } -+ -+ ret = request_irq(switch_data->irq, gpio_irq_handler, -+ IRQF_TRIGGER_LOW, pdev->name, switch_data); -+ if (ret < 0) -+ goto err_request_irq; -+ -+ /* Perform initial detection */ -+ gpio_switch_work(&switch_data->work); -+ -+ return 0; -+ -+err_request_irq: -+err_detect_irq_num_failed: -+err_set_gpio_input: -+ gpio_free(switch_data->gpio); -+err_request_gpio: -+ switch_dev_unregister(&switch_data->sdev); -+err_switch_dev_register: -+ kfree(switch_data); -+ -+ return ret; -+} -+ -+static int __devexit gpio_switch_remove(struct platform_device *pdev) -+{ -+ struct gpio_switch_data *switch_data = platform_get_drvdata(pdev); -+ -+ cancel_work_sync(&switch_data->work); -+ gpio_free(switch_data->gpio); -+ switch_dev_unregister(&switch_data->sdev); -+ kfree(switch_data); -+ -+ return 0; -+} -+ -+static struct platform_driver gpio_switch_driver = { -+ .probe = gpio_switch_probe, -+ .remove = __devexit_p(gpio_switch_remove), -+ .driver = { -+ .name = "switch-gpio", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init gpio_switch_init(void) -+{ -+ return platform_driver_register(&gpio_switch_driver); -+} -+ -+static void __exit gpio_switch_exit(void) -+{ -+ platform_driver_unregister(&gpio_switch_driver); -+} -+ -+module_init(gpio_switch_init); -+module_exit(gpio_switch_exit); -+ -+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); -+MODULE_DESCRIPTION("GPIO Switch driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig -index 070b442c..296b412f 100644 ---- a/drivers/tty/serial/Kconfig -+++ b/drivers/tty/serial/Kconfig -@@ -1360,4 +1360,34 @@ config SERIAL_EFM32_UART_CONSOLE - depends on SERIAL_EFM32_UART=y - select SERIAL_CORE_CONSOLE - -+config SERIAL_AK39_UART -+ tristate "AK39xx serial port support" -+ select SERIAL_CORE -+ depends on ARCH_AK39 -+ help -+ AK98 Uart support. -+ -+config SERIAL_AK39_CONSOLE -+ bool "Console on AK39 serial port" -+ depends on SERIAL_AK39_UART -+ select SERIAL_CORE_CONSOLE -+ help -+ Say Y here if you want enable console support on AK39xx serial port. -+ -+config SERIAL_GPIO_UART -+ tristate "GPIO serial port support" -+ select SERIAL_CORE -+ depends on ARCH_AK39 -+ default n -+ help -+ AK39 GPIO simulate UART support. -+ -+config SERIAL_GPIO_CONSOLE -+ bool "Console on GPIO serial port" -+ depends on SERIAL_GPIO_UART -+ select SERIAL_CORE_CONSOLE -+ help -+ AK39 GPIO simulate UART console support. -+ -+ - endmenu -diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile -index 7257c5d8..e0d7f32f 100644 ---- a/drivers/tty/serial/Makefile -+++ b/drivers/tty/serial/Makefile -@@ -79,3 +79,6 @@ obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o - obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o - obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o - obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o -+obj-$(CONFIG_SERIAL_AK39_UART) += ak39_uart.o -+obj-$(CONFIG_SERIAL_GPIO_UART) += gpio_uart.o -+ -diff --git a/drivers/tty/serial/ak39_uart.c b/drivers/tty/serial/ak39_uart.c -new file mode 100755 -index 00000000..08401cec ---- /dev/null -+++ b/drivers/tty/serial/ak39_uart.c -@@ -0,0 +1,1242 @@ -+/* -+ * driver/tty/serial/ak39_uart.c -+ */ -+ -+#if defined(CONFIG_SERIAL_AK39_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -+#define SUPPORT_SYSRQ -+#endif -+ -+#include <linux/module.h> -+#include <linux/ioport.h> -+#include <linux/platform_device.h> -+#include <linux/init.h> -+#include <linux/sysrq.h> -+#include <linux/console.h> -+#include <linux/tty.h> -+#include <linux/tty_flip.h> -+#include <linux/serial_core.h> -+#include <linux/serial.h> -+#include <linux/delay.h> -+#include <linux/clk.h> -+#include <linux/cpufreq.h> -+ -+#include <asm/io.h> -+#include <mach/irqs.h> -+#include <mach/gpio.h> -+#include <mach/clock.h> -+ -+#include "ak39_uart.h" -+ -+extern void printch(char); -+extern void printascii(const char *); -+ -+ -+#if 0 -+#define dbg(x...) printk(x) -+#else -+#define dbg(x...) do {} while(0) -+#endif -+ -+/* UART name and device definitions */ -+#define NR_PORTS 2 -+ -+#define AK39_SERIAL_NAME "ttySAK" -+#define AK39_SERIAL_MAJOR 204 -+#define AK39_SERIAL_MINOR 64 -+ -+ -+#ifdef CONFIG_SERIAL_AK39_CONSOLE -+ -+static struct console ak39_serial_console; -+ -+#define AK39_SERIAL_CONSOLE &ak39_serial_console -+#else -+#define AK39_SERIAL_CONSOLE NULL -+#endif -+ -+struct ak39_uart_port { -+ char *name; -+ struct uart_port port; -+ -+ unsigned char __iomem *rxfifo_base; -+ unsigned char __iomem *txfifo_base; -+ -+ unsigned int rxfifo_offset; -+ unsigned int nbr_to_read; -+ unsigned int timeout_cnt; -+ -+ unsigned char claimed; -+ struct clk *clk; -+#ifdef CONFIG_CPU_FREQ -+ struct notifier_block freq_transition; -+#endif -+}; -+ -+/* macros to change one thing to another */ -+#define tx_enabled(port) ((port)->unused[0]) -+#define rx_enabled(port) ((port)->unused[1]) -+ -+static int uart_intevent_decode(unsigned long status, unsigned int maskbit, unsigned int statusbit) -+{ -+ if ((status & 1<<maskbit) && (status & 1<<statusbit)) -+ return 1; -+ else -+ return 0; -+} -+ -+static inline void uart_subint_disable(struct ak39_uart_port *ourport, unsigned long mask) -+{ -+ unsigned long uart_reg; -+ -+ /* disable tx_end interrupt */ -+ uart_reg = __raw_readl(ourport->port.membase + UART_CONF2); -+ uart_reg &= ~mask; -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+} -+ -+static inline void uart_subint_enable(struct ak39_uart_port *ourport, unsigned long unmask) -+{ -+ unsigned long uart_reg; -+ -+ /* enable tx_end interrupt */ -+ uart_reg = __raw_readl(ourport->port.membase + UART_CONF2); -+ uart_reg |= unmask; -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+} -+ -+static void uart_subint_clear(struct ak39_uart_port *ourport, unsigned int subint) -+{ -+ unsigned long uart_reg; -+ -+ switch (subint) { -+ -+ case TX_THR_INT: -+ uart_reg = __raw_readl(ourport->port.membase + UART_CONF2); -+ uart_reg |= (1<<subint); -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+ break; -+ -+ case RX_THR_INT: -+ uart_reg = __raw_readl(ourport->port.membase + UART_CONF2); -+ uart_reg &= AKUART_INT_MASK; -+ uart_reg |= (1<<subint); -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+ break; -+ -+ case RECVDATA_ERR_INT: -+ uart_reg = __raw_readl(ourport->port.membase + UART_CONF2); -+ uart_reg &= AKUART_INT_MASK; -+ uart_reg |= (0x1 << subint); -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+ break; -+ -+ case RX_TIMEOUT: -+ uart_reg = __raw_readl(ourport->port.membase + UART_CONF2); -+ uart_reg |= (0x1 << subint); -+ uart_reg &= ~( 0x1<<3 ); -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+ -+ /* start to receive data */ -+ uart_reg = __raw_readl(ourport->port.membase + BUF_THRESHOLD); -+ uart_reg |= (1 << 31); -+ __raw_writel(uart_reg, ourport->port.membase + BUF_THRESHOLD); -+ break; -+ -+ default: -+ printk(KERN_ERR "ak39xx 9xx 9xx 9xx 9xx 9xx 9xx 9xx 9xx kown subint type: %d\n", subint); -+ break; -+ } -+ -+ return; -+} -+ -+static inline struct ak39_uart_port *to_ourport(struct uart_port *port) -+{ -+ return container_of(port, struct ak39_uart_port, port); -+} -+ -+static inline void uart_txend_interrupt(struct ak39_uart_port *ourport, unsigned short status) -+{ -+ unsigned long uart_reg; -+ -+ /*handle Tx_end end interrupt */ -+ uart_reg = __raw_readl(ourport->port.membase + UART_CONF2); -+ switch(status) -+ { -+ case ENABLE: -+ uart_reg |= (UARTN_CONFIG2_TX_END_INT_EN); -+ break; -+ -+ case DISABLE: -+ uart_reg &= ~(UARTN_CONFIG2_TX_END_INT_EN); -+ break; -+ -+ default: -+ break; -+ } -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+} -+ -+/* clear a UARTn buffer status flag */ -+static inline void clear_uart_buf_status(struct ak39_uart_port *ourport, unsigned short status) -+{ -+ unsigned long regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = __raw_readl(AK_VA_L2CTRL + 0x8C); -+ switch(status) -+ { -+ case RX_STATUS: -+ regval |= (0x1 << (17 + ourport->port.line * 2)); -+ break; -+ -+ case TX_STATUS: -+ regval |= (0x1 << (16 + ourport->port.line * 2)); -+ break; -+ -+ default: -+ break; -+ } -+ __raw_writel(regval, AK_VA_L2CTRL + 0x8C); -+ -+ local_irq_restore(flags); -+} -+ -+/* clear TX and RX internal status */ -+static inline void clear_internal_status(struct ak39_uart_port *ourport, unsigned short status) -+{ -+ unsigned long regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = __raw_readl(ourport->port.membase + UART_CONF1); -+ switch(status) -+ { -+ case RX_STATUS: -+ __raw_writel(regval | (0x1 << 29), ourport->port.membase + UART_CONF1); -+ break; -+ -+ case TX_STATUS: -+ __raw_writel(regval | (0x1 << 28), ourport->port.membase + UART_CONF1); -+ break; -+ -+ default: -+ break; -+ } -+ -+ local_irq_restore(flags); -+} -+ -+/* clear TX_th and RX_th count interrupt */ -+static inline void clear_Int_status(struct ak39_uart_port *ourport, unsigned short status) -+{ -+ unsigned long regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = __raw_readl(ourport->port.membase + BUF_THRESHOLD); -+ switch(status) -+ { -+ case RX_STATUS: -+ __raw_writel(regval | (0x1 << 5), ourport->port.membase + BUF_THRESHOLD); -+ break; -+ -+ case TX_STATUS: -+ __raw_writel(regval | (0x1 << 11), ourport->port.membase + BUF_THRESHOLD); -+ break; -+ -+ default: -+ break; -+ } -+ -+ local_irq_restore(flags); -+} -+ -+ -+/* enable/disable interrupt of RX_th */ -+static inline void uart_Rx_interrupt(struct ak39_uart_port *ourport, unsigned short status) -+{ -+ unsigned long regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = __raw_readl(ourport->port.membase + UART_CONF2); -+ if(status) -+ __raw_writel(regval | (0x1 << RX_INTTERUPT), ourport->port.membase + UART_CONF2); -+ else -+ __raw_writel(regval & ~(0x1 << RX_INTTERUPT), ourport->port.membase + UART_CONF2); -+ -+ local_irq_restore(flags); -+} -+ -+static inline int uart_hwport_init(struct ak39_uart_port *ourport) -+{ -+ /* set share pin to UARTn, and disable pull-up */ -+ switch (ourport->port.line) { -+ case 0: -+ ak_group_config(ePIN_AS_UART1); -+ -+ /* clear tx/rx buffer status flag */ -+ rL2_CONBUF8_15 |= (0x3 << 16); -+ /* enable buffer status bit may be changed */ -+ rL2_FRACDMAADDR |= (0x1 << 29); -+ break; -+ -+ case 1: -+ /* set share pin */ -+ ak_group_config(ePIN_AS_UART2); -+ -+ rL2_CONBUF8_15 |= (0x3 << 18); -+ rL2_FRACDMAADDR |= (0x1 << 29); -+ break; -+ -+ default: -+ printk(KERN_ERR "unknown uart port\n"); -+ return -1; -+ break; -+ } -+ -+ return 0; -+} -+ -+static int uart_enable_clock(struct ak39_uart_port *ourport, int enable) -+{ -+ unsigned long regval; -+ -+ regval = __raw_readl(AK_VA_SYSCTRL + 0x1C); -+ -+ switch (ourport->port.line) { -+ case 0: -+ if (enable) -+ regval &= ~(1 << 7); -+ else -+ regval |= (1 << 7); -+ -+ case 1: -+ if (enable) -+ regval &= ~(1 << 8); -+ else -+ regval |= (1 << 8); -+ break; -+ -+ default: -+ printk(KERN_ERR "unknown uart port\n"); -+ return -1; -+ } -+ __raw_writel(regval, AK_VA_SYSCTRL + 0x1C); -+ -+ return 0; -+} -+ -+/* power management control */ -+static void ak39_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) -+{ -+ switch (level) { -+ case 3: /* disable */ -+ //dbg("%s: enterring pm level: %d\n", __FUNCTION__, level); -+ break; -+ -+ case 0: /* enable */ -+ //dbg("%s: enterring pm level: %d\n", __FUNCTION__, level); -+ break; -+ -+ default: -+ dbg(KERN_ERR "ak39xx serial: unknown pm %d\n", level); -+ break; -+ } -+} -+ -+/* is tx fifo empty */ -+static unsigned int ak39_serial_tx_empty(struct uart_port *port) -+{ -+ unsigned long uart_reg; -+ -+ uart_reg = __raw_readl(port->membase + UART_CONF2); -+ -+ if (uart_reg & (1 << TXFIFO_EMPTY)) -+ return 1; -+ -+ return 0; -+} -+ -+/* no modem control lines */ -+static unsigned int ak39_serial_get_mctrl(struct uart_port *port) -+{ -+ /* FIXME */ -+ dbg("%s\n", __FUNCTION__); -+ return 0; -+} -+ -+static void ak39_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+ /* todo - possibly remove AFC and do manual CTS */ -+ dbg("%s\n", __FUNCTION__); -+} -+ -+ -+static void ak39_serial_start_tx(struct uart_port *port) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ -+ dbg("%s\n", __FUNCTION__); -+ -+ if (!tx_enabled(port)) -+ { -+ uart_txend_interrupt(ourport, ENABLE); -+ tx_enabled(port) = 1; -+ } -+} -+ -+static void ak39_serial_stop_tx(struct uart_port *port) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ -+ dbg("%s\n", __FUNCTION__); -+ -+ if (tx_enabled(port)) -+ { -+ uart_txend_interrupt(ourport, DISABLE); -+ tx_enabled(port) = 0; -+ } -+} -+ -+static void ak39_serial_stop_rx(struct uart_port *port) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ -+ dbg("%s\n", __FUNCTION__); -+ -+ if (rx_enabled(port)) -+ { -+ uart_Rx_interrupt(ourport, DISABLE); -+ rx_enabled(port) = 0; -+ } -+} -+ -+static void ak39_serial_enable_ms(struct uart_port *port) -+{ -+ dbg("%s\n", __FUNCTION__); -+} -+ -+static void ak39_serial_break_ctl(struct uart_port *port, int break_state) -+{ -+ dbg("%s\n", __FUNCTION__); -+} -+ -+static irqreturn_t ak39_uart_irqhandler(int irq, void *dev_id) -+{ -+ struct ak39_uart_port *ourport = dev_id; -+ struct uart_port *port = &ourport->port; -+ struct circ_buf *xmit = &port->state->xmit; //&port->info->xmit; -+ struct tty_struct *tty = port->state->port.tty; //port->info->tty; -+ unsigned int flag= TTY_NORMAL; -+ -+ unsigned char __iomem *pbuf; -+ unsigned char *pxmitbuf; -+ unsigned long uart_status; -+ unsigned int rxcount = 0; -+ unsigned char ch = 0; -+ unsigned int i; -+ int txcount , tx_tail; -+ unsigned int l2_offset = 0; -+ unsigned long regval; -+ -+ uart_status = __raw_readl(ourport->port.membase + UART_CONF2); -+ -+ /* clear R_err interrupt */ -+ if ( uart_intevent_decode(uart_status, RECVDATA_ERR_INT_ENABLE, RECVDATA_ERR_INT) ) -+ { -+ uart_subint_clear(ourport, RECVDATA_ERR_INT); -+ } -+ -+ if ( uart_intevent_decode(uart_status, TX_END_INTERRUPT, TX_END_STATUS) ) -+ { -+ /* if there is not anything more to transmit, or the uart is now -+ * stopped, disable the uart and exit -+ */ -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) -+ { -+ ak39_serial_stop_tx(port); -+ goto rx_irq; -+ } -+ -+ txcount = uart_circ_chars_pending(xmit); -+ -+ if(txcount > 32) -+ txcount = 32; -+ pbuf = ourport->txfifo_base; -+ pxmitbuf = xmit->buf; -+ -+ /* clear a uartx buffer status */ -+ clear_uart_buf_status(ourport, TX_STATUS); -+ -+ /* clear the tx internal status */ -+ clear_internal_status(ourport, TX_STATUS); -+ -+ __raw_writel(0x0, ourport->txfifo_base + 0x3C); -+ -+ l2_offset = 0; -+ tx_tail = xmit->tail; -+ regval = 0; -+ for(i = 0; i < txcount; i++) -+ { -+ regval |= pxmitbuf[tx_tail]<<((i & 3) * 8 ); -+ if((i & 3) == 3) -+ { -+ __raw_writel(regval, pbuf + l2_offset); -+ l2_offset = l2_offset + 4; -+ regval = 0; -+ } -+ tx_tail = (tx_tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx += 1; -+ } -+ if(i & 3) -+ { -+ __raw_writel(regval, pbuf + l2_offset); -+ } -+ -+ regval = (__raw_readl(ourport->port.membase + UART_CONF2)&(~UARTN_CONFIG2_TX_BYT_CNT_MASK)) | (UARTN_CONFIG2_TX_BYT_CNT(txcount)) | (UARTN_CONFIG2_TX_BYT_CNT_VLD); -+ __raw_writel(regval, ourport->port.membase + UART_CONF2); -+ xmit->tail = tx_tail; -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(port); -+ -+ if (uart_circ_empty(xmit)) -+ ak39_serial_stop_tx(port); -+ } -+ -+rx_irq: -+ -+ /* rx threshold interrupt */ -+ if ( uart_intevent_decode(uart_status, RX_THR_INT_ENABLE, RX_THR_INT) || -+ uart_intevent_decode(uart_status, RX_TIMEOUT_INT_ENABLE, RX_TIMEOUT)) -+ { -+ if ( uart_intevent_decode(uart_status, RX_THR_INT_ENABLE, RX_THR_INT)) -+ uart_subint_clear(ourport, RX_THR_INT); -+ else { -+ uart_subint_clear(ourport, RX_TIMEOUT); -+ } -+ -+ while(__raw_readl(ourport->port.membase + UART_CONF2) & (UARTN_CONFIG2_MEM_RDY)); -+ -+ ourport->nbr_to_read = (__raw_readl(ourport->port.membase + DATA_CONF)>>13) & 0x7f; -+ -+ if (ourport->nbr_to_read != ourport->rxfifo_offset) { -+ l2_offset = ourport->rxfifo_offset; -+ pbuf = ourport->rxfifo_base + l2_offset; -+ -+ /* copy data */ -+ if (ourport->nbr_to_read > l2_offset) { -+ rxcount = ourport->nbr_to_read - l2_offset; -+ for (i=0; i<rxcount; i++) { -+ ch = __raw_readb(pbuf + i); -+ uart_insert_char(port, 0, 0, ch, flag); -+ } -+ } else { -+ rxcount = (UART_RX_FIFO_SIZE - l2_offset); -+ for (i=0; i<rxcount; i++) { -+ ch = __raw_readb(pbuf + i); -+ uart_insert_char(port, 0, 0, ch, flag); -+ } -+ -+ pbuf = ourport->rxfifo_base; -+ for (i=0; i < ourport->nbr_to_read; i++) { -+ ch = __raw_readb(pbuf + i); -+ uart_insert_char(port, 0, 0, ch, flag); -+ } -+ } -+ ourport->rxfifo_offset = ourport->nbr_to_read; -+ } -+ -+ tty_flip_buffer_push(tty); -+ } -+ -+ return IRQ_HANDLED; -+ -+} -+ -+static void ak39_serial_shutdown(struct uart_port *port) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ unsigned int uart_reg = 0; -+ -+ /* -+ * 1st, free irq. -+ * 2nd, disable/mask hw uart setting. -+ * 3rd, close uart clock. -+ */ -+ -+ /* mask all interrupt */ -+ __raw_writel(0, ourport->port.membase + UART_CONF2); -+ -+ uart_reg = __raw_readl(ourport->port.membase + 0xc); -+ uart_reg &= (~(1<<5)); -+ __raw_writel(uart_reg, ourport->port.membase + 0xc); -+ uart_reg = __raw_readl(ourport->port.membase + 0x0); -+ uart_reg &= (~(1<<29)); -+ __raw_writel(uart_reg, ourport->port.membase + 0x0); -+ /* clear uartx interrupt */ -+ uart_reg &= (~1<<21); -+ __raw_writel(uart_reg, ourport->port.membase + 0x0); -+ -+ /* clear uartn TX/RX buf status flag and call ak_setpin_as_gpio() */ -+ switch(ourport->port.line) { -+ case 0: -+ rL2_CONBUF8_15 |= (0x3<<16); -+ break; -+ case 1: -+ rL2_CONBUF8_15 |= (0x3<<18); -+ break; -+ } -+ free_irq(port->irq, ourport); -+ uart_enable_clock(ourport, 0); -+} -+ -+/* -+ * 1, setup gpio. -+ * 2, enable clock. -+ * 3, request irq and setting up uart control. -+ * 4, enable subirq. -+ */ -+static int ak39_serial_startup(struct uart_port *port) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ unsigned long uart_reg; -+ int ret; -+ -+ if ( rx_enabled(port) && tx_enabled(port)) -+ return 0; -+ -+ /* enable uart clock */ -+ uart_enable_clock(ourport, 1); -+ -+ /* set share pin to UARTn */ -+ uart_hwport_init(ourport); -+ -+ //clear L2 Buffer -+ clear_uart_buf_status(ourport, RX_STATUS); -+ -+ uart_reg = UARTN_CONFIG1_RTS_EN_BY_CIRCUIT | UARTN_CONFIG1_EN |UARTN_CONFIG1_RX_STA_CLR|UARTN_CONFIG1_TX_STA_CLR|UARTN_CONFIG1_TIMEOUT_EN; -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF1); -+ -+ /* mask all interrupt */ -+ __raw_writel(0, ourport->port.membase + UART_CONF2); -+ -+ /* -+ * config stop bit and timeout value -+ * set timeout = 32, stop bit = 1; -+ */ -+ uart_reg = (0x1f << 16); -+ __raw_writel(uart_reg, ourport->port.membase + UART_STOPBIT_TIMEOUT); -+ -+ -+ /* -+ * set threshold to 32bytes -+ * set RX_th_cfg_h = 0, set RX_th_cfg_l = 31 -+ */ -+ uart_reg = __raw_readl(ourport->port.membase + DATA_CONF); -+ uart_reg &= ~UARTN_RX_TH_CFG_H_MASK; -+ __raw_writel(uart_reg, ourport->port.membase + DATA_CONF); -+ uart_reg = __raw_readl(ourport->port.membase + BUF_THRESHOLD); -+ uart_reg &= ~(UARTN_RX_TH_CFG_L_MASK); -+ uart_reg |= UARTN_RX_TH_CFG_L(0x1F); /* 32 Bytes */ -+ //uart_reg |= (1 << 11); -+ __raw_writel(uart_reg, ourport->port.membase + BUF_THRESHOLD); -+ -+ clear_internal_status(ourport, RX_STATUS); -+ -+ /* ourport->rxfifo_offset = 0; */ -+ ourport->rxfifo_offset = 0; -+ -+ /* to clear RX_th count interrupt */ -+ uart_reg = __raw_readl(ourport->port.membase + BUF_THRESHOLD); -+ uart_reg |= (UARTN_RX_TH_CLR); -+ __raw_writel(uart_reg, ourport->port.membase + BUF_THRESHOLD); -+ udelay(10); -+ uart_reg = __raw_readl(ourport->port.membase + BUF_THRESHOLD); -+ uart_reg &= ~(UARTN_RX_TH_CLR); -+ __raw_writel(uart_reg, ourport->port.membase + BUF_THRESHOLD); -+ udelay(10); -+ uart_reg = __raw_readl(ourport->port.membase + BUF_THRESHOLD); -+ uart_reg |= (UARTN_RX_START); -+ __raw_writel(uart_reg, ourport->port.membase + BUF_THRESHOLD); -+ -+ -+ /* -+ * enable timeout, rx mem_rdy and rx_th tx_end interrupt -+ */ -+ uart_reg = (UARTN_CONFIG2_RX_TH_INT_EN|UARTN_CONFIG2_RX_BUF_FULL_INT_EN|UARTN_CONFIG2_TIMEOUT_INT_EN|UARTN_CONFIG2_R_ERR_INT_EN); -+ __raw_writel(uart_reg, ourport->port.membase + UART_CONF2); -+ -+ rx_enabled(port) = 1; -+ tx_enabled(port) = 0; -+ -+ //ourport->rxfifo_offset =0; -+ -+ /* register interrupt */ -+ ret = request_irq(port->irq, ak39_uart_irqhandler, IRQF_DISABLED, ourport->name, ourport); -+ if (ret) { -+ printk(KERN_ERR "can't request irq %d for %s\n", port->irq, ourport->name); -+ goto startup_err; -+ } -+ return 0; -+ -+startup_err: -+ ak39_serial_shutdown(port); -+ return ret; -+} -+ -+static void ak39_serial_set_termios(struct uart_port *port, -+ struct ktermios *termios, struct ktermios *old) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ unsigned int baud; -+ unsigned long flags; -+ unsigned long regval; -+ unsigned long asic_clk; -+ -+ asic_clk = ak_get_asic_clk(); -+ -+ termios->c_cflag &= ~(HUPCL | CMSPAR); -+ termios->c_cflag |= CLOCAL; -+ -+ /* -+ * Ask the core to calculate the divisor for us. -+ * min: 2.4kbps, max: 2.4Mbps -+ */ -+ baud = uart_get_baud_rate(port, termios, old, 2400, 115200*20); -+ -+ spin_lock_irqsave(&port->lock, flags); -+ -+ /* baudrate setting */ -+ regval = __raw_readl(port->membase + UART_CONF1); -+ regval &= ~(0xffff); -+ regval &= ~(0x1 << 22); -+ regval |= ((asic_clk / baud - 1) & 0xffff); -+ regval |= (1 << 28) | (1 << 29); -+ -+ if (asic_clk % baud) -+ regval |= (0x1 << 22); -+ -+ ourport->rxfifo_offset = 0; -+ -+ /* flow control setting */ -+ if(port->line != 0) -+ { -+ if((termios->c_cflag & CRTSCTS)) /* directly */ -+ { -+ switch (port->line) { -+ case 1: -+ AK_GPIO_UART1_FLOW(1); -+ break; -+ } -+ regval &= ~(1<<18|1<<19); -+ } -+ else /* inversly */ -+ { -+ switch(port->line) { -+ case 1: -+ ak_setpin_as_gpio(6); -+ ak_setpin_as_gpio(7); -+ break; -+ } -+ regval |= (1<<18|1<<19); -+ } -+ } -+ -+ /* parity setting */ -+ if (termios->c_cflag & PARENB) { -+ if (termios->c_cflag & PARODD) -+ regval |= (0x2 << 25); /* odd parity */ -+ else -+ regval |= (0x3 << 25); /* evnt parity*/ -+ } -+ __raw_writel(regval, port->membase + UART_CONF1); -+ -+ /* -+ * Update the per-port timeout. -+ */ -+ uart_update_timeout(port, termios->c_cflag, baud); -+ -+ /* -+ * Which character status flags should we ignore? -+ */ -+ port->ignore_status_mask = 0; -+ -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static const char *ak39_serial_type(struct uart_port *port) -+{ -+ switch (port->type) -+ { -+ case PORT_AK39: -+ return "AK39"; -+ default: -+ return NULL; -+ } -+} -+ -+static void ak39_serial_release_port(struct uart_port *port) -+{ -+ dbg("%s\n", __FUNCTION__); -+} -+ -+static int ak39_serial_request_port(struct uart_port *port) -+{ -+ dbg("%s\n", __FUNCTION__); -+ return 0; -+} -+ -+static void ak39_serial_config_port(struct uart_port *port, int flags) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ -+ port->type = PORT_AK39; -+ ourport->rxfifo_offset = 0; -+} -+ -+/* -+ * verify the new serial_struct (for TIOCSSERIAL). -+ */ -+static int -+ak39_serial_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ dbg("%s\n", __FUNCTION__); -+ -+ return 0; -+} -+ -+ -+static struct uart_ops ak39_serial_ops = { -+ .pm = ak39_serial_pm, -+ .tx_empty = ak39_serial_tx_empty, -+ .get_mctrl = ak39_serial_get_mctrl, -+ .set_mctrl = ak39_serial_set_mctrl, -+ .stop_tx = ak39_serial_stop_tx, -+ .start_tx = ak39_serial_start_tx, -+ .stop_rx = ak39_serial_stop_rx, -+ .enable_ms = ak39_serial_enable_ms, -+ .break_ctl = ak39_serial_break_ctl, -+ .startup = ak39_serial_startup, -+ .shutdown = ak39_serial_shutdown, -+ .set_termios = ak39_serial_set_termios, -+ .type = ak39_serial_type, -+ .release_port = ak39_serial_release_port, -+ .request_port = ak39_serial_request_port, -+ .config_port = ak39_serial_config_port, -+ .verify_port = ak39_serial_verify_port, -+}; -+ -+ -+static struct ak39_uart_port ak39_serial_ports[NR_PORTS] = { -+ [0] = { -+ .name = "uart0", -+ .rxfifo_base = AK39_UART0_RXBUF_BASE, -+ .txfifo_base = AK39_UART0_TXBUF_BASE, -+ .port = { -+ .lock = __SPIN_LOCK_UNLOCKED(ak39_serial_ports[0].port.lock), -+ .iotype = UPIO_MEM, -+ .mapbase = AK39_UART0_PA_BASE, -+ .membase = AK39_UART0_BASE, -+ .irq = IRQ_UART0, -+ .uartclk = 0, -+ .fifosize = 64, -+ .ops = &ak39_serial_ops, -+ .flags = UPF_BOOT_AUTOCONF, -+ .line = 0, -+ }, -+ #ifdef CONFIG_CPU_FREQ -+ .freq_transition = { -+ .priority = INT_MAX -1, -+ }, -+ #endif -+ }, -+ [1] = { -+ .name = "uart1", -+ .rxfifo_base = AK39_UART1_RXBUF_BASE, -+ .txfifo_base = AK39_UART1_TXBUF_BASE, -+ .port = { -+ .lock = __SPIN_LOCK_UNLOCKED(ak39_serial_ports[1].port.lock), -+ .iotype = UPIO_MEM, -+ .mapbase = AK39_UART1_PA_BASE, -+ .membase = AK39_UART1_BASE, -+ .irq = IRQ_UART1, -+ .uartclk = 0, -+ .fifosize = 64, -+ .ops = &ak39_serial_ops, -+ .flags = UPF_BOOT_AUTOCONF, -+ .line = 1, -+ }, -+ }, -+}; -+ -+static struct uart_driver ak39_uart_drv = { -+ .owner = THIS_MODULE, -+ .dev_name = AK39_SERIAL_NAME, -+ .driver_name = AK39_SERIAL_NAME, -+ .nr = NR_PORTS, -+ .major = AK39_SERIAL_MAJOR, -+ .minor = AK39_SERIAL_MINOR, -+ .cons = AK39_SERIAL_CONSOLE, -+}; -+ -+#ifdef CONFIG_CPU_FREQ -+ -+static int ak39_serial_cpufreq_transition(struct notifier_block *nb, -+ unsigned long val, void *data) -+{ -+ struct ak39_uart_port *port; -+ struct uart_port *uport; -+ -+ port = container_of(nb, struct ak39_uart_port, freq_transition); -+ uport = &port->port; -+ -+ if(val == CPUFREQ_PRECHANGE){ -+ /* we should really shut the port down whilst the -+ * frequency change is in progress. */ -+ } -+ else if(val == CPUFREQ_POSTCHANGE) { -+ -+ struct ktermios *termios; -+ struct tty_struct *tty; -+ -+ if (uport->state == NULL) -+ goto exit; -+ -+ tty = uport->state->port.tty; -+ if (tty == NULL) -+ goto exit; -+ -+ termios = tty->termios; -+ if (termios == NULL) { -+ printk(KERN_WARNING "%s: no termios?\n", __func__); -+ goto exit; -+ } -+ -+ ak39_serial_set_termios(uport, termios, NULL); -+ } -+exit: -+ return 0; -+ -+} -+ -+static inline int ak39_serial_cpufreq_register(struct ak39_uart_port *port) -+{ -+ port->freq_transition.notifier_call = ak39_serial_cpufreq_transition; -+ -+ return cpufreq_register_notifier(&port->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+static inline void ak39_serial_cpufreq_unregister(struct ak39_uart_port *port) -+{ -+ cpufreq_unregister_notifier(&port->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+#else -+static inline int ak39_serial_cpufreq_register(struct ak39_uart_port *port) -+{ -+ return 0; -+} -+ -+static inline void ak39_serial_cpufreq_unregister(struct ak39_uart_port *port) -+{ -+} -+ -+#endif -+ -+ -+/* ak39_serial_init_port -+ * -+ * initialise a single serial port from the platform device given -+ */ -+static int ak39_serial_init_port(struct ak39_uart_port *ourport, -+ struct platform_device *platdev) -+{ -+ struct uart_port *port = &ourport->port; -+ -+ if (platdev == NULL) -+ return -ENODEV; -+ -+ /* setup info for port */ -+ port->dev = &platdev->dev; -+ -+ ourport->clk = clk_get(port->dev, "asic_clk"); -+ -+ return 0; -+} -+ -+static int ak39_serial_probe(struct platform_device *dev) -+{ -+ struct ak39_uart_port *ourport; -+ int ret = 0; -+ -+ ourport = &ak39_serial_ports[dev->id]; -+ -+ ret = ak39_serial_init_port(ourport, dev); -+ if (ret < 0) -+ goto probe_err; -+ -+ uart_add_one_port(&ak39_uart_drv, &ourport->port); -+ -+ platform_set_drvdata(dev, &ourport->port); -+ -+ ret = ak39_serial_cpufreq_register(ourport); -+ if(ret < 0) -+ dev_err(&dev->dev, "faild to add cpufreq notifier\n"); -+ return 0; -+ -+probe_err: -+ return ret; -+} -+ -+static int ak39_serial_remove(struct platform_device *dev) -+{ -+ struct uart_port *port = (struct uart_port *)dev_get_drvdata(&dev->dev); -+ -+ if (port) { -+ ak39_serial_cpufreq_unregister(to_ourport(port)); -+ uart_remove_one_port(&ak39_uart_drv, port); -+ } -+ return 0; -+} -+ -+/* UART power management code */ -+ -+#ifdef CONFIG_PM -+ -+static int ak39_serial_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct uart_port *port = (struct uart_port *)dev_get_drvdata(&dev->dev); -+ -+ if (port) -+ uart_suspend_port(&ak39_uart_drv, port); -+ return 0; -+} -+ -+static int ak39_serial_resume(struct platform_device *dev) -+{ -+ struct uart_port *port = (struct uart_port *)dev_get_drvdata(&dev->dev); -+ -+ if (port) -+ uart_resume_port(&ak39_uart_drv, port); -+ return 0; -+} -+#else -+#define ak39_serial_suspend NULL -+#define ak39_serial_resume NULL -+#endif -+ -+static struct platform_driver ak39_serial_drv = { -+ .probe = ak39_serial_probe, -+ .remove = ak39_serial_remove, -+ .suspend = ak39_serial_suspend, -+ .resume = ak39_serial_resume, -+ .driver = { -+ .name = "ak39-uart", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+ -+/* module initialisation code */ -+static int __init ak39_serial_modinit(void) -+{ -+ int ret; -+ -+ printk("AK39xx uart driver init, (c) 2013 ANYKA\n"); -+ -+ //register -+ ret = uart_register_driver(&ak39_uart_drv); -+ if (ret < 0) { -+ printk(KERN_ERR "failed to register UART driver\n"); -+ return -1; -+ } -+ -+ platform_driver_register(&ak39_serial_drv); -+ -+ return 0; -+} -+ -+static void __exit ak39_serial_modexit(void) -+{ -+ platform_driver_unregister(&ak39_serial_drv); -+ -+ uart_unregister_driver(&ak39_uart_drv); -+} -+ -+module_init(ak39_serial_modinit); -+module_exit(ak39_serial_modexit); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("anyka"); -+MODULE_DESCRIPTION("Anyka Serial port driver"); -+ -+ -+/************* Console code ************/ -+#ifdef CONFIG_SERIAL_AK39_CONSOLE -+ -+static struct uart_port *cons_uart; -+ -+static inline void ak39_uart_putchar(struct ak39_uart_port *ourport, unsigned char ch) -+{ -+ unsigned long regval; -+ -+ /* clear the tx internal status */ -+ clear_internal_status(ourport, TX_STATUS); -+ -+ /* clear a uartx buffer status */ -+ clear_uart_buf_status(ourport, TX_STATUS); -+ -+ /*to inform the buf is full*/ -+ __raw_writel(ch, ourport->txfifo_base); -+ __raw_writel(0x0, ourport->txfifo_base + 0x3C); -+ -+ /* to clear TX_th count interrupt */ -+ clear_Int_status(ourport, TX_STATUS); -+ -+ /* start to transmit */ -+ regval = __raw_readl(ourport->port.membase + UART_CONF2); -+ regval &= AKUART_INT_MASK; -+ regval |= (0x1<<4) | (0x1<<16); -+ __raw_writel(regval, ourport->port.membase + UART_CONF2); -+ -+ -+ /* wait for tx end */ -+ while (!(__raw_readl(ourport->port.membase + UART_CONF2) & (1 << TX_END_STATUS))) -+ ; -+} -+ -+static inline void ak39_wait_for_txend(struct ak39_uart_port *ourport) -+{ -+ unsigned int timeout = 10000; -+ -+ /* -+ * Wait up to 10ms for the character(s) to be sent -+ */ -+ while (!(__raw_readl(ourport->port.membase + UART_CONF2) & (1 << TX_END_STATUS))) { -+ if (--timeout == 0) -+ break; -+ udelay(1); -+ } -+} -+ -+static void -+ak39_serial_console_putchar(struct uart_port *port, int ch) -+{ -+ struct ak39_uart_port *ourport = to_ourport(port); -+ -+ ak39_wait_for_txend(ourport); -+ -+ ak39_uart_putchar(ourport, ch); -+} -+ -+static void -+ak39_serial_console_write(struct console *co, const char *s, unsigned int count) -+{ -+ uart_console_write(cons_uart, s, count, ak39_serial_console_putchar); -+} -+ -+static void __init -+ak39_serial_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -+{ -+ -+#if 0 -+ unsigned long regval; -+ struct clk *clk; -+ -+ *bits = 8; -+ -+ regval = __raw_readl(port->membase + UART_CONF1); -+ -+ if (regval & 0x1<<26) { -+ if (regval & 0x1<<25) -+ *parity = 'e'; -+ else -+ *parity = 'o'; -+ } -+ else -+ *parity = 'n'; -+ -+ clk = clk_get(port->dev, "asic_clk"); -+ if (!IS_ERR(clk) && clk != NULL) -+ *baud = clk_get_rate(clk) / ((regval & 0xFFFF) + 1); -+ -+ printk("calculated baudrate: %d\n", *baud); -+#endif -+} -+ -+ -+static int __init -+ak39_serial_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = 115200; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ -+ dbg("ak39_serial_console_setup: co=%p (%d), %s\n", co, co->index, options); -+ -+ port = &ak39_serial_ports[co->index].port; -+ -+ /* is this a valid port */ -+ -+ if (co->index == -1 || co->index >= NR_PORTS) -+ co->index = 0; -+ -+ dbg("ak39_serial_console_setup: port=%p (%d)\n", port, co->index); -+ -+ cons_uart = port; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ ak39_serial_get_options(port, &baud, &parity, &bits); -+ -+ dbg("ak39_serial_console_setup: baud %d\n", baud); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+} -+ -+ -+static struct console ak39_serial_console = { -+ .name = AK39_SERIAL_NAME, -+ .device = uart_console_device, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+ .write = ak39_serial_console_write, -+ .setup = ak39_serial_console_setup -+}; -+ -+ -+/* ak39_serial_initconsole -+ * -+ * initialise the console from one of the uart drivers -+*/ -+static int ak39_serial_initconsole(void) -+{ -+ printk("AK39 console driver initial\n"); -+ -+ ak39_serial_console.data = &ak39_uart_drv; -+ -+ register_console(&ak39_serial_console); -+ -+ return 0; -+} -+ -+console_initcall(ak39_serial_initconsole); -+ -+#endif /* CONFIG_SERIAL_AK39_CONSOLE */ -+ -diff --git a/drivers/tty/serial/ak39_uart.h b/drivers/tty/serial/ak39_uart.h -new file mode 100755 -index 00000000..20f5b76d ---- /dev/null -+++ b/drivers/tty/serial/ak39_uart.h -@@ -0,0 +1,125 @@ -+#ifndef __AK39_UART_H_ -+#define __AK39_UART_H_ -+ -+#define AK39_UART0_TXBUF_BASE REG_VA_ADDR(AK_VA_L2MEM, 0x1000) -+#define AK39_UART0_RXBUF_BASE REG_VA_ADDR(AK_VA_L2MEM, 0x1080) -+#define AK39_UART1_TXBUF_BASE REG_VA_ADDR(AK_VA_L2MEM, 0x1100) -+#define AK39_UART1_RXBUF_BASE REG_VA_ADDR(AK_VA_L2MEM, 0x1180) -+ -+#define AK39_UART0_BASE REG_VA_ADDR(AK_VA_UART, 0x0000) -+#define AK39_UART1_BASE REG_VA_ADDR(AK_VA_UART, 0x8000) -+ -+#define AK39_UART0_PA_BASE REG_PA_ADDR(AK_PA_UART, 0x0000) -+#define AK39_UART1_PA_BASE REG_PA_ADDR(AK_PA_UART, 0x8000) -+ -+ -+#define UART_CONF1 0x00 -+#define UART_CONF2 0x04 -+#define DATA_CONF 0x08 -+#define BUF_THRESHOLD 0x0C -+#define UART_RXBUF 0x10 -+#define UART_STOPBIT_TIMEOUT (0x18) -+ -+#define RX_THR_INT_ENABLE (28) -+#define TX_END_INTERRUPT (27) -+#define TXBUF_EMP_INT_ENABLE (24) -+#define RECVDATA_ERR_INT_ENABLE (23) -+#define RX_TIMEOUT_INT_ENABLE (22) -+#define MEM_RDY_INT_ENABLE (21) -+#define TX_THR_INT (31) -+#define RX_THR_INT (30) -+#define TX_END_STATUS (19) -+#define RX_OV (18) -+#define MEM_RDY_INT (17) -+#define TX_BYT_CNT_VLD (16) -+#define RECVDATA_ERR_INT (3) -+#define RX_TIMEOUT (2) -+#define RXBUF_FULL (1) -+#define TXFIFO_EMPTY (0) -+ -+#define TX_INTTERUPT (29) -+#define RX_INTTERUPT (28) -+ -+#define TX_STATUS (1) -+#define RX_STATUS (0) -+#define DISABLE (0) -+#define ENABLE (1) -+#define AKUART_INT_MASK 0x3FE00000 -+#define UART_RX_FIFO_SIZE 128 -+ -+// Configuration Register 1 of UARTn -+#define UARTN_CONFIG1_DIV_CNT(cnt) ((cnt) & 0xffff) -+#define UARTN_CONFIG1_UTD_INVERSELY (1 << 16) -+#define UARTN_CONFIG1_URD_INVERSELY (1 << 17) -+#define UARTN_CONFIG1_CTS_INVERSELY (1 << 18) -+#define UARTN_CONFIG1_RTS_INVERSELY (1 << 19) -+#define UARTN_CONFIG1_RTS_EN_BY_CIRCUIT (1 << 20) -+#define UARTN_CONFIG1_EN (1 << 21) -+#define UARTN_CONFIG1_DIV_ADJ_EN (1 << 22) -+#define UARTN_CONFIG1_TIMEOUT_EN (1 << 23) -+#define UARTN_CONFIG1_PAR_EVEN (1 << 25) -+#define UARTN_CONFIG1_PAR_EN (1 << 26) -+#define UARTN_CONFIG1_ENDIAN_BIG (1 << 27) -+#define UARTN_CONFIG1_TX_STA_CLR (1 << 28) -+#define UARTN_CONFIG1_RX_STA_CLR (1 << 29) -+#define UARTN_RX_ADDR_CLR (1 << 30) -+#define UARTN_TX_ADDR_CLR (1 << 31) -+ -+// Configuration Register 2 of UARTn -+#define UARTN_CONFIG2_TX_FIFO_EMPTY (1 << 0) // read only -+#define UARTN_CONFIG2_RX_BUF_FULL (1 << 1) // write clear -+#define UARTN_CONFIG2_TIMEOUT (1 << 2) // write clear -+#define UARTN_CONFIG2_R_ERR (1 << 3) // write clear -+#define UARTN_CONFIG2_TX_BYT_CNT(cnt) (cnt << 4) -+#define UARTN_CONFIG2_TX_BYT_CNT_MASK (0xfff << 4) -+#define UARTN_CONFIG2_TX_BYT_CNT_VLD (1 << 16) // auto clear -+#define UARTN_CONFIG2_MEM_RDY (1 << 17) // read only -+ -+#define UARTN_CONFIG2_TX_END (1 << 19) // read only -+ -+#define UARTN_CONFIG2_RX_BUF_FULL_INT_EN (1 << 21) -+#define UARTN_CONFIG2_TIMEOUT_INT_EN (1 << 22) -+#define UARTN_CONFIG2_R_ERR_INT_EN (1 << 23) -+#define UARTN_CONFIG2_TX_BUF_EMP_INT_EN (1 << 24) -+ -+#define UARTN_CONFIG2_TX_END_INT_EN (1 << 27) -+#define UARTN_CONFIG2_RX_TH_INT_EN (1 << 28) -+#define UARTN_CONFIG2_TX_TH_INT_EN (1 << 29) -+ -+#define UARTN_CONFIG2_RX_TH_STA (1 << 30) // write clear -+#define UARTN_CONFIG2_TX_TH_STA (1 << 31) // write clear -+ -+// Data Configuration Register of UARTn -+#define UARTN_DATACONFIG_TX_BYT_SUM(rval) ((rval) & 0x1FFF) -+#define UARTN_DATACONFIG_RX_ADR(rval) (((rval) >> 13) & 0x7F) -+#define UARTN_DATACONFIG_TX_ADR(rval) (((rval) >> 20) & 0x1F) -+#define UARTN_RX_TH_CFG_H_MASK (0x7f >> 25) -+#define UARTN_RX_TH_CFG_H(value) (((value & 0x7f) >> 25)) -+ -+ -+// TX RX Data Threshold Resgister -+#define UARTN_RX_TH_CFG_L_MASK (0x1f) -+#define UARTN_RX_TH_CFG_L(value) (value) -+ -+#define UARTN_RX_TH_CLR (1 << 5) -+#define UARTN_TX_TH_CFG(value) (((value) & 0x1f) << 6) -+#define UARTN_TX_TH_CLR (1 << 11) -+#define UARTN_RX_TH_CNT(rvalue) (((rvalue) >> 12) & 0xFFF) // read only -+#define UARTN_TX_TH_CNT(rvalue) (((rvalue) >> 24) & 0x1F) // read only -+#define UARTN_BFIFO_BYTE_NUM(rvalue) (((rvalue) >> 29) & 0x03) // read only -+#define UARTN_RX_START (1 <<31) -+ -+ -+//Stop Bit Timeout Configuration Register -+ -+#define UARTN_BIT_CFG(value) ((value) & 0x1ff) -+#define UARTN_TIME_OUT_CFG(value) (((value) >> 16) & 0x0ffff) -+ -+ -+#undef REG_VA_VAL -+#define REG_VA_VAL(base_addr, offset) (*(volatile unsigned long *)((base_addr) + (offset))) -+ -+#define rL2_FRACDMAADDR REG_VA_VAL(AK_VA_L2CTRL, 0x84) -+#define rL2_CONBUF8_15 REG_VA_VAL(AK_VA_L2CTRL, 0x8C) -+ -+#endif /* end __AK39_UART_H_ */ -diff --git a/drivers/tty/serial/gpio_uart.c b/drivers/tty/serial/gpio_uart.c -new file mode 100644 -index 00000000..534b0191 ---- /dev/null -+++ b/drivers/tty/serial/gpio_uart.c -@@ -0,0 +1,393 @@ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/console.h> -+#include <linux/tty.h> -+#include <linux/tty_flip.h> -+#include <linux/serial_core.h> -+#include <linux/circ_buf.h> -+#include <mach/gpio.h> -+#include <linux/delay.h> -+ -+#include <mach/pwm_timer.h> -+ -+#define TIMER_CLOCK (12000000) /* Hz */ -+#define GPIO_SERIAL_NAME ("ttySAK") -+#define GPIO_SERIAL_NR_PORTS (1) -+#define FAKE_PORT_MEMBASE ((unsigned char __iomem*)(0xffffffff)) -+#define FAKE_PORT_MAPBASE ((resource_size_t)(0xffffffff)) -+ -+struct gpio_uart { -+ int baud; -+ int parity; -+ int bits; -+ int flow; -+ -+ int timer_count; -+ int correction; /* correction coefficient */ -+ -+ struct ak_pwm_timer *timer; -+ struct completion comp; -+ struct gpio_info tx_pin; -+}; -+ -+static struct gpio_uart guart = { -+ /* UART configure: 115200/75, 38400/80, 19200/80, 9600/80 */ -+ .baud = 115200, -+ .parity = 'n', -+ .bits = 8, -+ .flow = 'n', -+ .correction = 55, -+ -+ /* TX GPIO pin configure */ -+ .tx_pin = { -+ .pin = AK_GPIO_2, -+ .dir = AK_GPIO_DIR_OUTPUT, -+ .pullup = AK_PULLUP_DISABLE, -+ .pulldown = -1, -+ .value = AK_GPIO_OUT_HIGH, -+ .int_pol = -1, -+ }, -+}; -+ -+#ifdef CONFIG_SERIAL_CORE_CONSOLE -+#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) -+#else -+#define uart_console(port) (0) -+#endif -+ -+#ifdef CONFIG_SERIAL_GPIO_CONSOLE -+static struct uart_port port; -+static struct uart_driver gpio_uart_driver; -+static void gpio_putchar(unsigned char value); -+ -+ -+static void gpio_uart_console_write(struct console *co, const char *s, unsigned count) -+{ -+ unsigned int i; -+ const char *ts = s; -+ -+ for (i = 0; i < count; i++, ts++) { -+ if (*ts == '\n') -+ gpio_putchar('\r'); -+ gpio_putchar(*ts); -+ } -+} -+ -+static struct tty_driver *gpio_uart_console_device(struct console *co, int *index) -+{ -+ struct uart_driver *p = co->data; -+ -+ *index = co->index; -+ return p->tty_driver; -+} -+ -+static int gpio_uart_console_setup(struct console *co, char *options) -+{ -+ int baud; -+ int bits; -+ int parity; -+ int flow; -+ -+ ak_gpio_set(&guart.tx_pin); -+ guart.timer_count = TIMER_CLOCK / guart.baud - guart.correction; -+ port.mapbase = FAKE_PORT_MAPBASE; -+ port.membase = FAKE_PORT_MEMBASE; -+ -+ if (options) { -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ } else { -+ baud = guart.baud; -+ bits = guart.bits; -+ parity = guart.parity; -+ flow = guart.flow; -+ } -+ -+ return uart_set_options(&port, co, baud, parity, bits, flow); -+} -+ -+static struct console gpio_serial_console = { -+ .name = GPIO_SERIAL_NAME, -+ .write = gpio_uart_console_write, -+ .device = gpio_uart_console_device, -+ .setup = gpio_uart_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+ .data = &gpio_uart_driver, -+}; -+ -+static int __init gpio_serial_console_init(void) -+{ -+ guart.timer = ak_timer_request(AK_PWM_TIMER2, 0, NULL); -+ -+ register_console(&gpio_serial_console); -+ return 0; -+} -+console_initcall(gpio_serial_console_init); -+ -+#define GPIO_SERIAL_CONSOLE &gpio_serial_console -+#else -+#define GPIO_SERIAL_CONSOLE NULL -+#endif -+#if 0 -+static void gpio_delay(int count) -+{ -+#if 0 -+ int delay = 1000*1000/115200; -+ udelay(delay); -+ return; -+#endif -+ -+ REG32(guart.membase) = (count << 0); -+ -+ REG32(guart.membase+0x04) = (1 << 30); -+ REG32(guart.membase+0x04) |= (1 << 24); -+ REG32(guart.membase+0x04) |= (1 << 29) | (1 << 28); -+ -+ while(!(REG32(guart.membase+0x04) & (1 << 27))) -+ ; -+} -+#else -+ -+static void gpio_delay(int count) -+{ -+ init_completion(&guart.comp); -+ -+ ak_timer_config(guart.timer, count, 0); -+ ak_timer_enable_sync(guart.timer); -+} -+ -+#endif -+ -+static void gpio_putchar(unsigned char value) -+{ -+ int count = 8; -+ -+ /* send start bit */ -+ ak_gpio_setpin(guart.tx_pin.pin, AK_GPIO_OUT_LOW); -+ gpio_delay(guart.timer_count); -+ -+ /* send data, no parity */ -+ while(count--) { -+ ak_gpio_setpin(guart.tx_pin.pin, (value & 0x1)); -+ gpio_delay(guart.timer_count); -+ value >>= 1; -+ } -+ -+ /* send stop bit */ -+ ak_gpio_setpin(guart.tx_pin.pin, AK_GPIO_OUT_HIGH); -+ gpio_delay(guart.timer_count); -+} -+ -+static void gpio_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) -+{ -+ switch (state) { -+ case 3: -+ break; -+ case 0: -+ break; -+ default: -+ break; -+ } -+} -+ -+static unsigned int gpio_uart_tx_empty(struct uart_port *port) -+{ -+ return 1; -+} -+ -+static unsigned int gpio_uart_get_mctrl(struct uart_port *port) -+{ -+ return 0; -+} -+ -+static void gpio_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+} -+ -+static void gpio_uart_stop_tx(struct uart_port *port) -+{ -+} -+ -+static void gpio_uart_start_tx(struct uart_port *port) -+{ -+ struct uart_state *state = port->state; -+ struct circ_buf *circ = &state->xmit; -+ int txcount = uart_circ_chars_pending(circ); -+ unsigned char value = 0; -+ int i; -+ -+ for (i = 0; i < txcount; i++) { -+ value = circ->buf[circ->tail]; -+ gpio_putchar(value); -+ circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1); -+ } -+} -+ -+static void gpio_uart_stop_rx(struct uart_port *port) -+{ -+} -+ -+static void gpio_uart_enable_ms(struct uart_port *port) -+{ -+} -+ -+static void gpio_uart_break_ctl(struct uart_port *port, int break_state) -+{ -+} -+ -+static int gpio_uart_startup(struct uart_port *port) -+{ -+ return 0; -+} -+ -+static void gpio_uart_shutdown(struct uart_port *port) -+{ -+} -+ -+static void gpio_uart_set_termios(struct uart_port *port, -+ struct ktermios *termios, struct ktermios *old) -+{ -+} -+ -+static const char *gpio_uart_type(struct uart_port *port) -+{ -+ if (port->type == PORT_GPIO) -+ return "GPIO"; -+ else -+ return NULL; -+} -+ -+static void gpio_uart_release_port(struct uart_port *port) -+{ -+} -+ -+static int gpio_uart_request_port(struct uart_port *port) -+{ -+ return 0; -+} -+ -+static void gpio_uart_config_port(struct uart_port *port, int flags) -+{ -+ port->type = PORT_GPIO; -+} -+ -+static int gpio_uart_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ return 0; -+} -+ -+static struct uart_ops gpio_uart_ops = { -+ .pm = gpio_uart_pm, -+ .tx_empty = gpio_uart_tx_empty, -+ .get_mctrl = gpio_uart_get_mctrl, -+ .set_mctrl = gpio_uart_set_mctrl, -+ .stop_tx = gpio_uart_stop_tx, -+ .start_tx = gpio_uart_start_tx, -+ .stop_rx = gpio_uart_stop_rx, -+ .enable_ms = gpio_uart_enable_ms, -+ .break_ctl = gpio_uart_break_ctl, -+ .startup = gpio_uart_startup, -+ .shutdown = gpio_uart_shutdown, -+ .set_termios = gpio_uart_set_termios, -+ .type = gpio_uart_type, -+ .release_port = gpio_uart_release_port, -+ .request_port = gpio_uart_request_port, -+ .config_port = gpio_uart_config_port, -+ .verify_port = gpio_uart_verify_port, -+}; -+ -+static struct uart_port port = { -+ .iotype = UPIO_MEM, -+ .ops = &gpio_uart_ops, -+ .flags = UPF_BOOT_AUTOCONF, -+ .line = 0, -+ .cons = GPIO_SERIAL_CONSOLE, -+}; -+ -+static struct uart_driver gpio_uart_driver = { -+ .owner = THIS_MODULE, -+ .driver_name = "gpio-uart", -+ .dev_name = GPIO_SERIAL_NAME, -+ .major = 0, -+ .minor = 0, -+ .nr = GPIO_SERIAL_NR_PORTS, -+ .cons = GPIO_SERIAL_CONSOLE, -+}; -+ -+static int gpio_uart_probe(struct platform_device *pdev) -+{ -+ int ret; -+ -+ if (!uart_console(&port)) { -+ port.membase = FAKE_PORT_MEMBASE; -+ port.mapbase = FAKE_PORT_MAPBASE; -+ guart.timer_count = TIMER_CLOCK / guart.baud - guart.correction; -+ ak_gpio_set(&guart.tx_pin); -+ guart.timer = ak_timer_request(AK_PWM_TIMER2, 0, NULL); -+ } -+ -+ ret = uart_register_driver(&gpio_uart_driver); -+ if (ret) { -+ printk("UART register driver failed\n"); -+ return ret; -+ } -+ -+ port.dev = &pdev->dev; -+ ret = uart_add_one_port(&gpio_uart_driver, &port); -+ if (ret) { -+ printk("Add gpio uart port failed\n"); -+ return ret; -+ } -+ -+ platform_set_drvdata(pdev, &port); -+ -+ printk("ak gpio uart initialize success.\n"); -+ return 0; -+} -+ -+static int gpio_uart_remove(struct platform_device *pdev) -+{ -+ platform_set_drvdata(pdev, NULL); -+ uart_remove_one_port(&gpio_uart_driver, &port); -+ uart_unregister_driver(&gpio_uart_driver); -+ return 0; -+} -+ -+static int gpio_uart_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ return 0; -+} -+ -+static int gpio_uart_resume(struct platform_device *pdev) -+{ -+ return 0; -+} -+ -+static struct platform_driver gpio_uart_pdrv = { -+ .probe = gpio_uart_probe, -+ .remove = gpio_uart_remove, -+ .suspend = gpio_uart_suspend, -+ .resume = gpio_uart_resume, -+ .driver = { -+ .name = "gpio-uart", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init gpio_uart_init(void) -+{ -+ printk("AK GPIO UART Driver (c) 2013 ANYKA.\n"); -+ return platform_driver_register(&gpio_uart_pdrv); -+} -+ -+static void __exit gpio_uart_exit(void) -+{ -+ platform_driver_unregister(&gpio_uart_pdrv); -+} -+module_init(gpio_uart_init); -+module_exit(gpio_uart_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("J.C.Zhong <zhong_junchao@anyka.com>"); -+MODULE_DESCRIPTION("GPIO simulate UART driver"); -diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c -index d8b0aee3..c49f3bf6 100644 ---- a/drivers/tty/serial/samsung.c -+++ b/drivers/tty/serial/samsung.c -@@ -427,6 +427,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) - if (ourport->tx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->tx_irq, ourport); -+ else -+ free_irq(port->irq, ourport); - tx_enabled(port) = 0; - ourport->tx_claimed = 0; - } -@@ -434,6 +436,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) - if (ourport->rx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->rx_irq, ourport); -+ /* else already freed above as the s3c64xx_serial_startup() -+ * will have set both tx_claimed and rx_claimed */ - ourport->rx_claimed = 0; - rx_enabled(port) = 0; - } -diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c -index 246b823c..a4895dcc 100644 ---- a/drivers/tty/serial/serial_core.c -+++ b/drivers/tty/serial/serial_core.c -@@ -94,6 +94,9 @@ static void __uart_start(struct tty_struct *tty) - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - -+ if (port->ops->wake_peer) -+ port->ops->wake_peer(port); -+ - if (!uart_circ_empty(&state->xmit) && state->xmit.buf && - !tty->stopped && !tty->hw_stopped) - port->ops->start_tx(port); -diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig -index 6f3ea9bb..19b1ab55 100644 ---- a/drivers/uio/Kconfig -+++ b/drivers/uio/Kconfig -@@ -111,4 +111,12 @@ config UIO_PRUSS - To compile this driver as a module, choose M here: the module - will be called uio_pruss. - -+config UIO_VCODEC -+ tristate "Anyka Video Codec support" -+ help -+ This driver supports Video HW Codec on Anyka SoC. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called uio_video_codec. -+ - endif -diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile -index d4dd9a55..9da3159e 100644 ---- a/drivers/uio/Makefile -+++ b/drivers/uio/Makefile -@@ -7,3 +7,4 @@ obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o - obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o - obj-$(CONFIG_UIO_NETX) += uio_netx.o - obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o -+obj-$(CONFIG_UIO_VCODEC) += uio_video_codec.o -\ No newline at end of file -diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c -index a783d533..c3612cf3 100644 ---- a/drivers/uio/uio.c -+++ b/drivers/uio/uio.c -@@ -503,6 +503,19 @@ static int uio_release(struct inode *inode, struct file *filep) - return ret; - } - -+static long uio_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ struct uio_listener *listener = filep->private_data; -+ struct uio_device *idev = listener->dev; -+ int ret; -+ -+ ret = EINVAL; -+ if (idev->info->ioctl) -+ ret = idev->info->ioctl(idev->info, cmd, arg); -+ -+ return ret; -+} -+ - static unsigned int uio_poll(struct file *filep, poll_table *wait) - { - struct uio_listener *listener = filep->private_data; -@@ -721,6 +734,7 @@ static const struct file_operations uio_fops = { - .poll = uio_poll, - .fasync = uio_fasync, - .llseek = noop_llseek, -+ .unlocked_ioctl = uio_ioctl, - }; - - static int uio_major_init(void) -diff --git a/drivers/uio/uio_video_codec.c b/drivers/uio/uio_video_codec.c -new file mode 100644 -index 00000000..10431f88 ---- /dev/null -+++ b/drivers/uio/uio_video_codec.c -@@ -0,0 +1,344 @@ -+/** -+ * drivers/uio/uio_video_codec.c -+ * -+ * Userspace I/O driver for anyka soc video hardware codec. -+ * Based on uio_pdrv.c by Uwe Kleine-Koenig, -+ * -+ * Jacky Lau -+ * 2011-07-05 -+ * -+ * Copyright (C) 2011 by Anyka Inc. -+ * All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ */ -+ -+#include <linux/platform_device.h> -+#include <linux/uio_driver.h> -+#include <linux/semaphore.h> -+#include <linux/slab.h> -+#include <asm/uaccess.h> -+#include <asm/cacheflush.h> -+ -+#include <linux/akuio_driver.h> -+#include <mach/reg.h> -+#include <mach/l2cache.h> -+ -+#define DRIVER_NAME "uio_vcodec" -+ -+#define init_MUTEX(sem) sema_init(sem, 1) -+#define init_MUTEX_LOCKED(sem) sema_init(sem, 0) -+ -+/* IRQs of hw codec */ -+const unsigned VIDEO_IRQ_MASK = (1 << IRQ_VIDEO_ENCODER); -+const int MASK_BITS_NUM = sizeof(VIDEO_IRQ_MASK) * 8; -+ -+/* platform data of this driver */ -+struct uio_platdata { -+ struct uio_info *uioinfo; -+ struct semaphore vcodec_sem; -+ unsigned int open_count; -+}; -+ -+/** -+ * @brief Handle hw codec irq -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param [in] irq : irq id -+ * @param [in] dev_id : platform data -+ * @return irqreturn_t : return handle result -+ * @retval IRQ_HANDLE : irq handled successful. -+ */ -+static irqreturn_t uio_vcodec_irq_handler(int irq, void *dev_id) -+{ -+ struct uio_platdata *pdata = dev_id; -+ int i; -+ -+ for (i = 0; i < MASK_BITS_NUM; i++) -+ { -+ if ((1 << i) & VIDEO_IRQ_MASK) -+ disable_irq_nosync(i); -+ } -+ -+ up (&(pdata->vcodec_sem)); -+ -+ return IRQ_HANDLED; -+} -+ -+/** -+ * @brief Handle hw codec ioctl -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param [in] uioinfo : information of uio driver -+ * @param [in] cmd : ioctl request code -+ * @param [in] arg : argument -+ * @return int : return 0 when handle successful, otherwise return negative -+ * @retval 0 : handled successful. -+ * @retval <0 : handle failed. -+ */ -+static int uio_vcodec_ioctl(struct uio_info *uioinfo, unsigned int cmd, unsigned long arg) -+{ -+ struct uio_platdata *pdata = uioinfo->priv; -+ int err; -+ -+ switch (cmd) { -+ case AKUIO_SYSREG_WRITE: -+ { -+ struct akuio_sysreg_write_t reg_write; -+ -+ if (copy_from_user(®_write, (void __user *)arg, sizeof(struct akuio_sysreg_write_t))) -+ return -EFAULT; -+ -+ sys_ctrl_reg_set(reg_write.paddr, reg_write.mask, reg_write.val); -+ -+ err = 0; -+ } -+ break; -+ -+ case AKUIO_WAIT_IRQ: -+ { -+ int i; -+ -+ for (i = 0; i < MASK_BITS_NUM; i++) -+ { -+ if ((1 << i) & VIDEO_IRQ_MASK) -+ enable_irq(i); -+ } -+ -+ down (&pdata->vcodec_sem); -+ err = 0; -+ } -+ break; -+ -+ case AKUIO_INVALIDATE_L2CACHE: -+ l2cache_invalidate (); -+ flush_cache_all(); -+ err = 0; -+ break; -+ -+ case AKUIO_INVALIDATE_L1CACHE: -+// flush_cache_all(); -+ err = 0; -+ break; -+ -+ default: -+ err = -EINVAL; -+ break; -+ }; -+ -+ return err; -+} -+ -+/** -+ * @brief When application open the akuio device, request all irq of the hw codec and disable the irq immediately -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param [in] uioinfo : information of uio driver -+ * @param [in] inode : inode of the device -+ * @return int : return 0 when handle successful, otherwise return negative -+ * @retval 0 : handled successful. -+ * @retval <0 : handle failed. -+ */ -+static int uio_vcodec_open(struct uio_info *uioinfo, struct inode *inode) -+{ -+ struct uio_platdata *pdata = uioinfo->priv; -+ int i; -+ int ret = 0; -+ -+ //Add code here to make sure uio0 can be multi-opened. -+ if( pdata->open_count++ > 0 ) { -+ DBG("uio0 has opened! open_count=%d\n", pdata->open_count ); -+ return 0; -+ } -+ -+ init_MUTEX_LOCKED(&(pdata->vcodec_sem)); -+ -+ for (i = 0; i < MASK_BITS_NUM; i++) -+ { -+ if ((1 << i) & VIDEO_IRQ_MASK) { -+ ret = request_irq(i, uio_vcodec_irq_handler, IRQF_DISABLED, "VIDEO HW CODEC", pdata); -+ disable_irq_nosync(i); -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief When application close the akuio device, free all irq of the hw codec -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param [in] uioinfo : information of uio driver -+ * @param [in] inode : inode of the device -+ * @return int : return 0 when handle successful, otherwise return negative -+ * @retval 0 : handled successful. -+ * @retval <0 : handle failed. -+ */ -+static int uio_vcodec_release(struct uio_info *uioinfo, struct inode *inode) -+{ -+ struct uio_platdata *pdata = uioinfo->priv; -+ int i; -+ -+ //Add code here to make sure uio0 can be multi-opened. -+ if(--pdata->open_count != 0) { -+ DBG("uio0 does's closed to 0! open_count=%d\n", pdata->open_count ); -+ return 0; -+ } -+ -+ for (i = 0; i < MASK_BITS_NUM; i++) -+ { -+ if ((1 << i) & VIDEO_IRQ_MASK) -+ free_irq(i, pdata); -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief Init the device which was probed -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param [in] pdev : the device definition -+ * @return int : return 0 when handle successful, otherwise return negative -+ * @retval 0 : handled successful. -+ * @retval <0 : handle failed. -+ */ -+static int uio_vcodec_probe(struct platform_device *pdev) -+{ -+ struct uio_info *uioinfo = pdev->dev.platform_data; -+ struct uio_platdata *pdata; -+ struct uio_mem *uiomem; -+ int ret = -ENODEV; -+ int i; -+ -+ if (!uioinfo || !uioinfo->name || !uioinfo->version) { -+ dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__); -+ goto err_uioinfo; -+ } -+ -+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); -+ if (!pdata) { -+ ret = -ENOMEM; -+ dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__); -+ goto err_alloc_pdata; -+ } -+ -+ pdata->uioinfo = uioinfo; -+ -+ uiomem = &uioinfo->mem[0]; -+ -+ for (i = 0; i < pdev->num_resources; ++i) { -+ struct resource *r = &pdev->resource[i]; -+ if (r->flags != IORESOURCE_MEM) -+ continue; -+ -+ if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { -+ dev_warn(&pdev->dev, "device has more than " -+ __stringify(MAX_UIO_MAPS) -+ " I/O memory resources.\n"); -+ break; -+ } -+ -+ uiomem->memtype = UIO_MEM_PHYS; -+ uiomem->addr = r->start; -+ uiomem->size = r->end - r->start + 1; -+ ++uiomem; -+ } -+ -+ while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { -+ uiomem->size = 0; -+ ++uiomem; -+ } -+ -+ /* open count */ -+ pdata->open_count = 0; -+ -+ /* irq */ -+ pdata->uioinfo->irq = UIO_IRQ_CUSTOM; -+ -+ /* file handle */ -+ pdata->uioinfo->open = uio_vcodec_open; -+ pdata->uioinfo->release = uio_vcodec_release; -+ pdata->uioinfo->ioctl = uio_vcodec_ioctl; -+ -+ pdata->uioinfo->priv = pdata; -+ -+ ret = uio_register_device(&pdev->dev, pdata->uioinfo); -+ -+ if (ret) { -+ kfree(pdata); -+err_alloc_pdata: -+err_uioinfo: -+ return ret; -+ } -+ -+ platform_set_drvdata(pdev, pdata); -+ -+ return 0; -+} -+ -+/** -+ * @brief De-init the device which will be removed -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param [in] pdev : the device definition -+ * @return int : return 0 when handle successful, otherwise return negative -+ * @retval 0 : handled successful. -+ * @retval <0 : handle failed. -+ */ -+static int uio_vcodec_remove(struct platform_device *pdev) -+{ -+ struct uio_platdata *pdata = platform_get_drvdata(pdev); -+ -+ uio_unregister_device(pdata->uioinfo); -+ -+ kfree(pdata); -+ -+ return 0; -+} -+ -+/* driver definition */ -+static struct platform_driver uio_vcodec = { -+ .probe = uio_vcodec_probe, -+ .remove = uio_vcodec_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+/** -+ * @brief kernel module init function, register the driver to kernel -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param -+ * @return int : return 0 when handle successful, otherwise return negative -+ * @retval 0 : handled successful. -+ * @retval <0 : handle failed. -+ */ -+static int __init uio_vcodec_init(void) -+{ -+ return platform_driver_register(&uio_vcodec); -+} -+ -+/** -+ * @brief kernel module finally function, unregister the driver from kernel -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @param -+ * @return void -+ * @retval -+ */ -+static void __exit uio_vcodec_exit(void) -+{ -+ platform_driver_unregister(&uio_vcodec); -+} -+module_init(uio_vcodec_init); -+module_exit(uio_vcodec_exit); -+ -+MODULE_AUTHOR("Jacky Lau"); -+MODULE_DESCRIPTION("Userspace driver for anyka video hw codec"); -+MODULE_LICENSE("GPL v2"); -+ -diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile -index 53a7bc07..e10b0f3e 100644 ---- a/drivers/usb/Makefile -+++ b/drivers/usb/Makefile -@@ -27,6 +27,7 @@ obj-$(CONFIG_USB_HWA_HCD) += host/ - obj-$(CONFIG_USB_ISP1760_HCD) += host/ - obj-$(CONFIG_USB_IMX21_HCD) += host/ - obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/ -+obj-$(CONFIG_USB_ANYKA_HCD) += host/ - - obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ - -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 67dda0db..1497207f 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -3156,7 +3156,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, - udev->tt = &hub->tt; - udev->ttport = port1; - } -- -+ - /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? - * Because device hardware and firmware is sometimes buggy in - * this area, and this is how Linux has done it for ages. -diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig -index 2633f759..228f22d8 100644 ---- a/drivers/usb/gadget/Kconfig -+++ b/drivers/usb/gadget/Kconfig -@@ -316,6 +316,8 @@ config USB_MV_UDC - USB2.0 OTG controller, which can be configured as high speed or - full speed USB peripheral. - -+source "drivers/usb/gadget/plat-anyka/Kconfig" -+ - # - # Controllers available in both integrated and discrete versions - # -@@ -846,6 +848,15 @@ config USB_G_PRINTER - For more information, see Documentation/usb/gadget_printer.txt - which includes sample code for accessing the device file. - -+config USB_G_ANDROID -+ boolean "Android Composite Gadget" -+ help -+ The Android Composite Gadget supports multiple USB -+ functions: adb, acm, mass storage, mtp, accessory -+ and rndis. -+ Each function can be configured and enabled/disabled -+ dynamically from userspace through a sysfs interface. -+ - config USB_CDC_COMPOSITE - tristate "CDC Composite Device (Ethernet and ACM)" - depends on NET -diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile -index b7f6eefc..a92bbbe8 100644 ---- a/drivers/usb/gadget/Makefile -+++ b/drivers/usb/gadget/Makefile -@@ -31,6 +31,8 @@ obj-$(CONFIG_USB_MV_UDC) += mv_udc.o - mv_udc-y := mv_udc_core.o - obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o - obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o -+obj-$(CONFIG_USB_AKUDC) += plat-anyka/ -+obj-$(CONFIG_USB_AKUDC_PRODUCER) += plat-anyka/ - - # - # USB gadget drivers -@@ -52,6 +54,7 @@ g_nokia-y := nokia.o - g_webcam-y := webcam.o - g_ncm-y := ncm.o - g_acm_ms-y := acm_ms.o -+g_android-y := android.o - - obj-$(CONFIG_USB_ZERO) += g_zero.o - obj-$(CONFIG_USB_AUDIO) += g_audio.o -@@ -71,3 +74,4 @@ obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o - obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o - obj-$(CONFIG_USB_G_NCM) += g_ncm.o - obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o -+obj-$(CONFIG_USB_G_ANDROID) += g_android.o -diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c -new file mode 100644 -index 00000000..4e73bf1a ---- /dev/null -+++ b/drivers/usb/gadget/android.c -@@ -0,0 +1,1565 @@ -+/* -+ * Gadget Driver for Android -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * Benoit Goby <benoit@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/fs.h> -+#include <linux/delay.h> -+#include <linux/kernel.h> -+#include <linux/utsname.h> -+#include <linux/platform_device.h> -+ -+#include <linux/usb/ch9.h> -+#include <linux/usb/composite.h> -+#include <linux/usb/gadget.h> -+ -+#include "gadget_chips.h" -+ -+/* -+ * Kbuild is not very cooperative with respect to linking separately -+ * compiled library objects into one module. So for now we won't use -+ * separate compilation ... ensuring init/exit sections work to shrink -+ * the runtime footprint, and giving us at least some parts of what -+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would. -+ */ -+#include "usbstring.c" -+#include "config.c" -+#include "epautoconf.c" -+#include "composite.c" -+ -+#include "f_fs.c" -+#include "f_audio_source.c" -+#include "f_mass_storage.c" -+#include "u_serial.c" -+#include "f_acm.c" -+#include "f_adb.c" -+#include "f_mtp.c" -+#include "f_accessory.c" -+#define USB_ETH_RNDIS y -+#include "f_rndis.c" -+#include "rndis.c" -+#include "u_ether.c" -+ -+MODULE_AUTHOR("Mike Lockwood"); -+MODULE_DESCRIPTION("Android Composite USB Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION("1.0"); -+ -+static const char longname[] = "Gadget Android"; -+ -+/* Default vendor and product IDs, overridden by userspace */ -+#define VENDOR_ID 0x18D1 -+#define PRODUCT_ID 0x0001 -+ -+struct android_usb_function { -+ char *name; -+ void *config; -+ -+ struct device *dev; -+ char *dev_name; -+ struct device_attribute **attributes; -+ -+ /* for android_dev.enabled_functions */ -+ struct list_head enabled_list; -+ -+ /* Optional: initialization during gadget bind */ -+ int (*init)(struct android_usb_function *, struct usb_composite_dev *); -+ /* Optional: cleanup during gadget unbind */ -+ void (*cleanup)(struct android_usb_function *); -+ /* Optional: called when the function is added the list of -+ * enabled functions */ -+ void (*enable)(struct android_usb_function *); -+ /* Optional: called when it is removed */ -+ void (*disable)(struct android_usb_function *); -+ -+ int (*bind_config)(struct android_usb_function *, -+ struct usb_configuration *); -+ -+ /* Optional: called when the configuration is removed */ -+ void (*unbind_config)(struct android_usb_function *, -+ struct usb_configuration *); -+ /* Optional: handle ctrl requests before the device is configured */ -+ int (*ctrlrequest)(struct android_usb_function *, -+ struct usb_composite_dev *, -+ const struct usb_ctrlrequest *); -+}; -+ -+struct android_dev { -+ struct android_usb_function **functions; -+ struct list_head enabled_functions; -+ struct usb_composite_dev *cdev; -+ struct device *dev; -+ -+ bool enabled; -+ int disable_depth; -+ struct mutex mutex; -+ bool connected; -+ bool sw_connected; -+ struct work_struct work; -+ char ffs_aliases[256]; -+}; -+ -+static struct class *android_class; -+static struct android_dev *_android_dev; -+static int android_bind_config(struct usb_configuration *c); -+static void android_unbind_config(struct usb_configuration *c); -+ -+/* string IDs are assigned dynamically */ -+#define STRING_MANUFACTURER_IDX 0 -+#define STRING_PRODUCT_IDX 1 -+#define STRING_SERIAL_IDX 2 -+ -+static char manufacturer_string[256]; -+static char product_string[256]; -+static char serial_string[256]; -+ -+/* String Table */ -+static struct usb_string strings_dev[] = { -+ [STRING_MANUFACTURER_IDX].s = manufacturer_string, -+ [STRING_PRODUCT_IDX].s = product_string, -+ [STRING_SERIAL_IDX].s = serial_string, -+ { } /* end of list */ -+}; -+ -+static struct usb_gadget_strings stringtab_dev = { -+ .language = 0x0409, /* en-us */ -+ .strings = strings_dev, -+}; -+ -+static struct usb_gadget_strings *dev_strings[] = { -+ &stringtab_dev, -+ NULL, -+}; -+ -+static struct usb_device_descriptor device_desc = { -+ .bLength = sizeof(device_desc), -+ .bDescriptorType = USB_DT_DEVICE, -+ .bcdUSB = __constant_cpu_to_le16(0x0200), -+ .bDeviceClass = USB_CLASS_PER_INTERFACE, -+ .idVendor = __constant_cpu_to_le16(VENDOR_ID), -+ .idProduct = __constant_cpu_to_le16(PRODUCT_ID), -+ .bcdDevice = __constant_cpu_to_le16(0xffff), -+ .bNumConfigurations = 1, -+}; -+ -+static struct usb_configuration android_config_driver = { -+ .label = "android", -+ .unbind = android_unbind_config, -+ .bConfigurationValue = 1, -+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, -+ .bMaxPower = 0xFA, /* 500ma */ -+}; -+ -+static void android_work(struct work_struct *data) -+{ -+ struct android_dev *dev = container_of(data, struct android_dev, work); -+ struct usb_composite_dev *cdev = dev->cdev; -+ char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; -+ char *connected[2] = { "USB_STATE=CONNECTED", NULL }; -+ char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; -+ char **uevent_envp = NULL; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&cdev->lock, flags); -+ if (cdev->config) -+ uevent_envp = configured; -+ else if (dev->connected != dev->sw_connected) -+ uevent_envp = dev->connected ? connected : disconnected; -+ dev->sw_connected = dev->connected; -+ spin_unlock_irqrestore(&cdev->lock, flags); -+ -+ if (uevent_envp) { -+ kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp); -+ pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]); -+ } else { -+ pr_info("%s: did not send uevent (%d %d %p)\n", __func__, -+ dev->connected, dev->sw_connected, cdev->config); -+ } -+} -+ -+static void android_enable(struct android_dev *dev) -+{ -+ struct usb_composite_dev *cdev = dev->cdev; -+ -+ if (WARN_ON(!dev->disable_depth)) -+ return; -+ -+ if (--dev->disable_depth == 0) { -+ usb_add_config(cdev, &android_config_driver, -+ android_bind_config); -+ usb_gadget_connect(cdev->gadget); -+ } -+} -+ -+static void android_disable(struct android_dev *dev) -+{ -+ struct usb_composite_dev *cdev = dev->cdev; -+ -+ if (dev->disable_depth++ == 0) { -+ usb_gadget_disconnect(cdev->gadget); -+ /* Cancel pending control requests */ -+ usb_ep_dequeue(cdev->gadget->ep0, cdev->req); -+ usb_remove_config(cdev, &android_config_driver); -+ } -+} -+ -+/*-------------------------------------------------------------------------*/ -+/* Supported functions initialization */ -+ -+struct functionfs_config { -+ bool opened; -+ bool enabled; -+ struct ffs_data *data; -+}; -+ -+static int ffs_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ f->config = kzalloc(sizeof(struct functionfs_config), GFP_KERNEL); -+ if (!f->config) -+ return -ENOMEM; -+ -+ return functionfs_init(); -+} -+ -+static void ffs_function_cleanup(struct android_usb_function *f) -+{ -+ functionfs_cleanup(); -+ kfree(f->config); -+} -+ -+static void ffs_function_enable(struct android_usb_function *f) -+{ -+ struct android_dev *dev = _android_dev; -+ struct functionfs_config *config = f->config; -+ -+ config->enabled = true; -+ -+ /* Disable the gadget until the function is ready */ -+ if (!config->opened) -+ android_disable(dev); -+} -+ -+static void ffs_function_disable(struct android_usb_function *f) -+{ -+ struct android_dev *dev = _android_dev; -+ struct functionfs_config *config = f->config; -+ -+ config->enabled = false; -+ -+ /* Balance the disable that was called in closed_callback */ -+ if (!config->opened) -+ android_enable(dev); -+} -+ -+static int ffs_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ struct functionfs_config *config = f->config; -+ return functionfs_bind_config(c->cdev, c, config->data); -+} -+ -+static ssize_t -+ffs_aliases_show(struct device *pdev, struct device_attribute *attr, char *buf) -+{ -+ struct android_dev *dev = _android_dev; -+ int ret; -+ -+ mutex_lock(&dev->mutex); -+ ret = sprintf(buf, "%s\n", dev->ffs_aliases); -+ mutex_unlock(&dev->mutex); -+ -+ return ret; -+} -+ -+static ssize_t -+ffs_aliases_store(struct device *pdev, struct device_attribute *attr, -+ const char *buf, size_t size) -+{ -+ struct android_dev *dev = _android_dev; -+ char buff[256]; -+ -+ mutex_lock(&dev->mutex); -+ -+ if (dev->enabled) { -+ mutex_unlock(&dev->mutex); -+ return -EBUSY; -+ } -+ -+ strlcpy(buff, buf, sizeof(buff)); -+ strlcpy(dev->ffs_aliases, strim(buff), sizeof(dev->ffs_aliases)); -+ -+ mutex_unlock(&dev->mutex); -+ -+ return size; -+} -+ -+static DEVICE_ATTR(aliases, S_IRUGO | S_IWUSR, ffs_aliases_show, -+ ffs_aliases_store); -+static struct device_attribute *ffs_function_attributes[] = { -+ &dev_attr_aliases, -+ NULL -+}; -+ -+static struct android_usb_function ffs_function = { -+ .name = "ffs", -+ .init = ffs_function_init, -+ .enable = ffs_function_enable, -+ .disable = ffs_function_disable, -+ .cleanup = ffs_function_cleanup, -+ .bind_config = ffs_function_bind_config, -+ .attributes = ffs_function_attributes, -+}; -+ -+static int functionfs_ready_callback(struct ffs_data *ffs) -+{ -+ struct android_dev *dev = _android_dev; -+ struct functionfs_config *config = ffs_function.config; -+ int ret = 0; -+ -+ mutex_lock(&dev->mutex); -+ -+ ret = functionfs_bind(ffs, dev->cdev); -+ if (ret) -+ goto err; -+ -+ config->data = ffs; -+ config->opened = true; -+ -+ if (config->enabled) -+ android_enable(dev); -+ -+err: -+ mutex_unlock(&dev->mutex); -+ return ret; -+} -+ -+static void functionfs_closed_callback(struct ffs_data *ffs) -+{ -+ struct android_dev *dev = _android_dev; -+ struct functionfs_config *config = ffs_function.config; -+ -+ mutex_lock(&dev->mutex); -+ -+ if (config->enabled) -+ android_disable(dev); -+ -+ config->opened = false; -+ config->data = NULL; -+ -+ functionfs_unbind(ffs); -+ -+ mutex_unlock(&dev->mutex); -+} -+ -+static int functionfs_check_dev_callback(const char *dev_name) -+{ -+ return 0; -+} -+ -+ -+struct adb_data { -+ bool opened; -+ bool enabled; -+}; -+ -+static int -+adb_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ f->config = kzalloc(sizeof(struct adb_data), GFP_KERNEL); -+ if (!f->config) -+ return -ENOMEM; -+ -+ return adb_setup(); -+} -+ -+static void adb_function_cleanup(struct android_usb_function *f) -+{ -+ adb_cleanup(); -+ kfree(f->config); -+} -+ -+static int -+adb_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ return adb_bind_config(c); -+} -+ -+static void adb_android_function_enable(struct android_usb_function *f) -+{ -+ struct android_dev *dev = _android_dev; -+ struct adb_data *data = f->config; -+ -+ data->enabled = true; -+ -+ /* Disable the gadget until adbd is ready */ -+ if (!data->opened) -+ android_disable(dev); -+} -+ -+static void adb_android_function_disable(struct android_usb_function *f) -+{ -+ struct android_dev *dev = _android_dev; -+ struct adb_data *data = f->config; -+ -+ data->enabled = false; -+ -+ /* Balance the disable that was called in closed_callback */ -+ if (!data->opened) -+ android_enable(dev); -+} -+ -+static struct android_usb_function adb_function = { -+ .name = "adb", -+ .enable = adb_android_function_enable, -+ .disable = adb_android_function_disable, -+ .init = adb_function_init, -+ .cleanup = adb_function_cleanup, -+ .bind_config = adb_function_bind_config, -+}; -+ -+static void adb_ready_callback(void) -+{ -+ struct android_dev *dev = _android_dev; -+ struct adb_data *data = adb_function.config; -+ -+ mutex_lock(&dev->mutex); -+ -+ data->opened = true; -+ -+ if (data->enabled) -+ android_enable(dev); -+ -+ mutex_unlock(&dev->mutex); -+} -+ -+static void adb_closed_callback(void) -+{ -+ struct android_dev *dev = _android_dev; -+ struct adb_data *data = adb_function.config; -+ -+ mutex_lock(&dev->mutex); -+ -+ data->opened = false; -+ -+ if (data->enabled) -+ android_disable(dev); -+ -+ mutex_unlock(&dev->mutex); -+} -+ -+ -+#define MAX_ACM_INSTANCES 4 -+struct acm_function_config { -+ int instances; -+}; -+ -+static int -+acm_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL); -+ if (!f->config) -+ return -ENOMEM; -+ -+ return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES); -+} -+ -+static void acm_function_cleanup(struct android_usb_function *f) -+{ -+ gserial_cleanup(); -+ kfree(f->config); -+ f->config = NULL; -+} -+ -+static int -+acm_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ int i; -+ int ret = 0; -+ struct acm_function_config *config = f->config; -+ -+ for (i = 0; i < config->instances; i++) { -+ ret = acm_bind_config(c, i); -+ if (ret) { -+ pr_err("Could not bind acm%u config\n", i); -+ break; -+ } -+ } -+ -+ return ret; -+} -+ -+static ssize_t acm_instances_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct acm_function_config *config = f->config; -+ return sprintf(buf, "%d\n", config->instances); -+} -+ -+static ssize_t acm_instances_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct acm_function_config *config = f->config; -+ int value; -+ -+ sscanf(buf, "%d", &value); -+ if (value > MAX_ACM_INSTANCES) -+ value = MAX_ACM_INSTANCES; -+ config->instances = value; -+ return size; -+} -+ -+static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show, -+ acm_instances_store); -+static struct device_attribute *acm_function_attributes[] = { -+ &dev_attr_instances, -+ NULL -+}; -+ -+static struct android_usb_function acm_function = { -+ .name = "acm", -+ .init = acm_function_init, -+ .cleanup = acm_function_cleanup, -+ .bind_config = acm_function_bind_config, -+ .attributes = acm_function_attributes, -+}; -+ -+ -+static int -+mtp_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ return mtp_setup(); -+} -+ -+static void mtp_function_cleanup(struct android_usb_function *f) -+{ -+ mtp_cleanup(); -+} -+ -+static int -+mtp_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ return mtp_bind_config(c, false); -+} -+ -+static int -+ptp_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ /* nothing to do - initialization is handled by mtp_function_init */ -+ return 0; -+} -+ -+static void ptp_function_cleanup(struct android_usb_function *f) -+{ -+ /* nothing to do - cleanup is handled by mtp_function_cleanup */ -+} -+ -+static int -+ptp_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ return mtp_bind_config(c, true); -+} -+ -+static int mtp_function_ctrlrequest(struct android_usb_function *f, -+ struct usb_composite_dev *cdev, -+ const struct usb_ctrlrequest *c) -+{ -+ return mtp_ctrlrequest(cdev, c); -+} -+ -+static struct android_usb_function mtp_function = { -+ .name = "mtp", -+ .init = mtp_function_init, -+ .cleanup = mtp_function_cleanup, -+ .bind_config = mtp_function_bind_config, -+ .ctrlrequest = mtp_function_ctrlrequest, -+}; -+ -+/* PTP function is same as MTP with slightly different interface descriptor */ -+static struct android_usb_function ptp_function = { -+ .name = "ptp", -+ .init = ptp_function_init, -+ .cleanup = ptp_function_cleanup, -+ .bind_config = ptp_function_bind_config, -+}; -+ -+ -+struct rndis_function_config { -+ u8 ethaddr[ETH_ALEN]; -+ u32 vendorID; -+ char manufacturer[256]; -+ /* "Wireless" RNDIS; auto-detected by Windows */ -+ bool wceis; -+}; -+ -+static int -+rndis_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL); -+ if (!f->config) -+ return -ENOMEM; -+ return 0; -+} -+ -+static void rndis_function_cleanup(struct android_usb_function *f) -+{ -+ kfree(f->config); -+ f->config = NULL; -+} -+ -+static int -+rndis_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ int ret; -+ struct rndis_function_config *rndis = f->config; -+ -+ if (!rndis) { -+ pr_err("%s: rndis_pdata\n", __func__); -+ return -1; -+ } -+ -+ pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__, -+ rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], -+ rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); -+ -+ ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); -+ if (ret) { -+ pr_err("%s: gether_setup failed\n", __func__); -+ return ret; -+ } -+ -+ if (rndis->wceis) { -+ /* "Wireless" RNDIS; auto-detected by Windows */ -+ rndis_iad_descriptor.bFunctionClass = -+ USB_CLASS_WIRELESS_CONTROLLER; -+ rndis_iad_descriptor.bFunctionSubClass = 0x01; -+ rndis_iad_descriptor.bFunctionProtocol = 0x03; -+ rndis_control_intf.bInterfaceClass = -+ USB_CLASS_WIRELESS_CONTROLLER; -+ rndis_control_intf.bInterfaceSubClass = 0x01; -+ rndis_control_intf.bInterfaceProtocol = 0x03; -+ } -+ -+ return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID, -+ rndis->manufacturer); -+} -+ -+static void rndis_function_unbind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ gether_cleanup(); -+} -+ -+static ssize_t rndis_manufacturer_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *config = f->config; -+ return sprintf(buf, "%s\n", config->manufacturer); -+} -+ -+static ssize_t rndis_manufacturer_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *config = f->config; -+ -+ if (size >= sizeof(config->manufacturer)) -+ return -EINVAL; -+ if (sscanf(buf, "%s", config->manufacturer) == 1) -+ return size; -+ return -1; -+} -+ -+static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show, -+ rndis_manufacturer_store); -+ -+static ssize_t rndis_wceis_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *config = f->config; -+ return sprintf(buf, "%d\n", config->wceis); -+} -+ -+static ssize_t rndis_wceis_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *config = f->config; -+ int value; -+ -+ if (sscanf(buf, "%d", &value) == 1) { -+ config->wceis = value; -+ return size; -+ } -+ return -EINVAL; -+} -+ -+static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show, -+ rndis_wceis_store); -+ -+static ssize_t rndis_ethaddr_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *rndis = f->config; -+ return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", -+ rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], -+ rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); -+} -+ -+static ssize_t rndis_ethaddr_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *rndis = f->config; -+ -+ if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", -+ (int *)&rndis->ethaddr[0], (int *)&rndis->ethaddr[1], -+ (int *)&rndis->ethaddr[2], (int *)&rndis->ethaddr[3], -+ (int *)&rndis->ethaddr[4], (int *)&rndis->ethaddr[5]) == 6) -+ return size; -+ return -EINVAL; -+} -+ -+static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show, -+ rndis_ethaddr_store); -+ -+static ssize_t rndis_vendorID_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *config = f->config; -+ return sprintf(buf, "%04x\n", config->vendorID); -+} -+ -+static ssize_t rndis_vendorID_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct rndis_function_config *config = f->config; -+ int value; -+ -+ if (sscanf(buf, "%04x", &value) == 1) { -+ config->vendorID = value; -+ return size; -+ } -+ return -EINVAL; -+} -+ -+static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show, -+ rndis_vendorID_store); -+ -+static struct device_attribute *rndis_function_attributes[] = { -+ &dev_attr_manufacturer, -+ &dev_attr_wceis, -+ &dev_attr_ethaddr, -+ &dev_attr_vendorID, -+ NULL -+}; -+ -+static struct android_usb_function rndis_function = { -+ .name = "rndis", -+ .init = rndis_function_init, -+ .cleanup = rndis_function_cleanup, -+ .bind_config = rndis_function_bind_config, -+ .unbind_config = rndis_function_unbind_config, -+ .attributes = rndis_function_attributes, -+}; -+ -+ -+struct mass_storage_function_config { -+ struct fsg_config fsg; -+ struct fsg_common *common; -+}; -+ -+static int mass_storage_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ struct mass_storage_function_config *config; -+ struct fsg_common *common; -+ int err; -+ -+ config = kzalloc(sizeof(struct mass_storage_function_config), -+ GFP_KERNEL); -+ if (!config) -+ return -ENOMEM; -+ -+ config->fsg.nluns = 1; -+ config->fsg.luns[0].removable = 1; -+ -+ common = fsg_common_init(NULL, cdev, &config->fsg); -+ if (IS_ERR(common)) { -+ kfree(config); -+ return PTR_ERR(common); -+ } -+ -+ err = sysfs_create_link(&f->dev->kobj, -+ &common->luns[0].dev.kobj, -+ "lun"); -+ if (err) { -+ kfree(config); -+ return err; -+ } -+ -+ config->common = common; -+ f->config = config; -+ return 0; -+} -+ -+static void mass_storage_function_cleanup(struct android_usb_function *f) -+{ -+ kfree(f->config); -+ f->config = NULL; -+} -+ -+static int mass_storage_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ struct mass_storage_function_config *config = f->config; -+ return fsg_bind_config(c->cdev, c, config->common); -+} -+ -+static ssize_t mass_storage_inquiry_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct mass_storage_function_config *config = f->config; -+ return sprintf(buf, "%s\n", config->common->inquiry_string); -+} -+ -+static ssize_t mass_storage_inquiry_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct mass_storage_function_config *config = f->config; -+ if (size >= sizeof(config->common->inquiry_string)) -+ return -EINVAL; -+ if (sscanf(buf, "%s", config->common->inquiry_string) != 1) -+ return -EINVAL; -+ return size; -+} -+ -+static DEVICE_ATTR(inquiry_string, S_IRUGO | S_IWUSR, -+ mass_storage_inquiry_show, -+ mass_storage_inquiry_store); -+ -+static struct device_attribute *mass_storage_function_attributes[] = { -+ &dev_attr_inquiry_string, -+ NULL -+}; -+ -+static struct android_usb_function mass_storage_function = { -+ .name = "mass_storage", -+ .init = mass_storage_function_init, -+ .cleanup = mass_storage_function_cleanup, -+ .bind_config = mass_storage_function_bind_config, -+ .attributes = mass_storage_function_attributes, -+}; -+ -+ -+static int accessory_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ return acc_setup(); -+} -+ -+static void accessory_function_cleanup(struct android_usb_function *f) -+{ -+ acc_cleanup(); -+} -+ -+static int accessory_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ return acc_bind_config(c); -+} -+ -+static int accessory_function_ctrlrequest(struct android_usb_function *f, -+ struct usb_composite_dev *cdev, -+ const struct usb_ctrlrequest *c) -+{ -+ return acc_ctrlrequest(cdev, c); -+} -+ -+static struct android_usb_function accessory_function = { -+ .name = "accessory", -+ .init = accessory_function_init, -+ .cleanup = accessory_function_cleanup, -+ .bind_config = accessory_function_bind_config, -+ .ctrlrequest = accessory_function_ctrlrequest, -+}; -+ -+static int audio_source_function_init(struct android_usb_function *f, -+ struct usb_composite_dev *cdev) -+{ -+ struct audio_source_config *config; -+ -+ config = kzalloc(sizeof(struct audio_source_config), GFP_KERNEL); -+ if (!config) -+ return -ENOMEM; -+ config->card = -1; -+ config->device = -1; -+ f->config = config; -+ return 0; -+} -+ -+static void audio_source_function_cleanup(struct android_usb_function *f) -+{ -+ kfree(f->config); -+} -+ -+static int audio_source_function_bind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ struct audio_source_config *config = f->config; -+ -+ return audio_source_bind_config(c, config); -+} -+ -+static void audio_source_function_unbind_config(struct android_usb_function *f, -+ struct usb_configuration *c) -+{ -+ struct audio_source_config *config = f->config; -+ -+ config->card = -1; -+ config->device = -1; -+} -+ -+static ssize_t audio_source_pcm_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct android_usb_function *f = dev_get_drvdata(dev); -+ struct audio_source_config *config = f->config; -+ -+ /* print PCM card and device numbers */ -+ return sprintf(buf, "%d %d\n", config->card, config->device); -+} -+ -+static DEVICE_ATTR(pcm, S_IRUGO | S_IWUSR, audio_source_pcm_show, NULL); -+ -+static struct device_attribute *audio_source_function_attributes[] = { -+ &dev_attr_pcm, -+ NULL -+}; -+ -+static struct android_usb_function audio_source_function = { -+ .name = "audio_source", -+ .init = audio_source_function_init, -+ .cleanup = audio_source_function_cleanup, -+ .bind_config = audio_source_function_bind_config, -+ .unbind_config = audio_source_function_unbind_config, -+ .attributes = audio_source_function_attributes, -+}; -+ -+static struct android_usb_function *supported_functions[] = { -+ &ffs_function, -+ &adb_function, -+ &acm_function, -+ &mtp_function, -+ &ptp_function, -+ &rndis_function, -+ &mass_storage_function, -+ &accessory_function, -+ &audio_source_function, -+ NULL -+}; -+ -+ -+static int android_init_functions(struct android_usb_function **functions, -+ struct usb_composite_dev *cdev) -+{ -+ struct android_dev *dev = _android_dev; -+ struct android_usb_function *f; -+ struct device_attribute **attrs; -+ struct device_attribute *attr; -+ int err; -+ int index = 0; -+ -+ for (; (f = *functions++); index++) { -+ f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); -+ f->dev = device_create(android_class, dev->dev, -+ MKDEV(0, index), f, f->dev_name); -+ if (IS_ERR(f->dev)) { -+ pr_err("%s: Failed to create dev %s", __func__, -+ f->dev_name); -+ err = PTR_ERR(f->dev); -+ goto err_create; -+ } -+ -+ if (f->init) { -+ err = f->init(f, cdev); -+ if (err) { -+ pr_err("%s: Failed to init %s", __func__, -+ f->name); -+ goto err_out; -+ } -+ } -+ -+ attrs = f->attributes; -+ if (attrs) { -+ while ((attr = *attrs++) && !err) -+ err = device_create_file(f->dev, attr); -+ } -+ if (err) { -+ pr_err("%s: Failed to create function %s attributes", -+ __func__, f->name); -+ goto err_out; -+ } -+ } -+ return 0; -+ -+err_out: -+ device_destroy(android_class, f->dev->devt); -+err_create: -+ kfree(f->dev_name); -+ return err; -+} -+ -+static void android_cleanup_functions(struct android_usb_function **functions) -+{ -+ struct android_usb_function *f; -+ -+ while (*functions) { -+ f = *functions++; -+ -+ if (f->dev) { -+ device_destroy(android_class, f->dev->devt); -+ kfree(f->dev_name); -+ } -+ -+ if (f->cleanup) -+ f->cleanup(f); -+ } -+} -+ -+static int -+android_bind_enabled_functions(struct android_dev *dev, -+ struct usb_configuration *c) -+{ -+ struct android_usb_function *f; -+ int ret; -+ -+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) { -+ ret = f->bind_config(f, c); -+ if (ret) { -+ pr_err("%s: %s failed", __func__, f->name); -+ return ret; -+ } -+ } -+ return 0; -+} -+ -+static void -+android_unbind_enabled_functions(struct android_dev *dev, -+ struct usb_configuration *c) -+{ -+ struct android_usb_function *f; -+ -+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) { -+ if (f->unbind_config) -+ f->unbind_config(f, c); -+ } -+} -+ -+static int android_enable_function(struct android_dev *dev, char *name) -+{ -+ struct android_usb_function **functions = dev->functions; -+ struct android_usb_function *f; -+ while ((f = *functions++)) { -+ if (!strcmp(name, f->name)) { -+ list_add_tail(&f->enabled_list, -+ &dev->enabled_functions); -+ return 0; -+ } -+ } -+ return -EINVAL; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/* /sys/class/android_usb/android%d/ interface */ -+ -+static ssize_t -+functions_show(struct device *pdev, struct device_attribute *attr, char *buf) -+{ -+ struct android_dev *dev = dev_get_drvdata(pdev); -+ struct android_usb_function *f; -+ char *buff = buf; -+ -+ mutex_lock(&dev->mutex); -+ -+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) -+ buff += sprintf(buff, "%s,", f->name); -+ -+ mutex_unlock(&dev->mutex); -+ -+ if (buff != buf) -+ *(buff-1) = '\n'; -+ return buff - buf; -+} -+ -+static ssize_t -+functions_store(struct device *pdev, struct device_attribute *attr, -+ const char *buff, size_t size) -+{ -+ struct android_dev *dev = dev_get_drvdata(pdev); -+ char *name; -+ char buf[256], *b; -+ char aliases[256], *a; -+ int err; -+ int is_ffs; -+ int ffs_enabled = 0; -+ -+ mutex_lock(&dev->mutex); -+ -+ if (dev->enabled) { -+ mutex_unlock(&dev->mutex); -+ return -EBUSY; -+ } -+ -+ INIT_LIST_HEAD(&dev->enabled_functions); -+ -+ strlcpy(buf, buff, sizeof(buf)); -+ b = strim(buf); -+ -+ while (b) { -+ name = strsep(&b, ","); -+ if (!name) -+ continue; -+ -+ is_ffs = 0; -+ strlcpy(aliases, dev->ffs_aliases, sizeof(aliases)); -+ a = aliases; -+ -+ while (a) { -+ char *alias = strsep(&a, ","); -+ if (alias && !strcmp(name, alias)) { -+ is_ffs = 1; -+ break; -+ } -+ } -+ -+ if (is_ffs) { -+ if (ffs_enabled) -+ continue; -+ err = android_enable_function(dev, "ffs"); -+ if (err) -+ pr_err("android_usb: Cannot enable ffs (%d)", -+ err); -+ else -+ ffs_enabled = 1; -+ continue; -+ } -+ -+ err = android_enable_function(dev, name); -+ if (err) -+ pr_err("android_usb: Cannot enable '%s' (%d)", -+ name, err); -+ } -+ -+ mutex_unlock(&dev->mutex); -+ -+ return size; -+} -+ -+static ssize_t enable_show(struct device *pdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct android_dev *dev = dev_get_drvdata(pdev); -+ return sprintf(buf, "%d\n", dev->enabled); -+} -+ -+static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, -+ const char *buff, size_t size) -+{ -+ struct android_dev *dev = dev_get_drvdata(pdev); -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct android_usb_function *f; -+ int enabled = 0; -+ -+ -+ if (!cdev) -+ return -ENODEV; -+ -+ mutex_lock(&dev->mutex); -+ -+ sscanf(buff, "%d", &enabled); -+ if (enabled && !dev->enabled) { -+ /* -+ * Update values in composite driver's copy of -+ * device descriptor. -+ */ -+ cdev->desc.idVendor = device_desc.idVendor; -+ cdev->desc.idProduct = device_desc.idProduct; -+ cdev->desc.bcdDevice = device_desc.bcdDevice; -+ cdev->desc.bDeviceClass = device_desc.bDeviceClass; -+ cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass; -+ cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol; -+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) { -+ if (f->enable) -+ f->enable(f); -+ } -+ android_enable(dev); -+ dev->enabled = true; -+ } else if (!enabled && dev->enabled) { -+ android_disable(dev); -+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) { -+ if (f->disable) -+ f->disable(f); -+ } -+ dev->enabled = false; -+ } else { -+ pr_err("android_usb: already %s\n", -+ dev->enabled ? "enabled" : "disabled"); -+ } -+ -+ mutex_unlock(&dev->mutex); -+ return size; -+} -+ -+static ssize_t state_show(struct device *pdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct android_dev *dev = dev_get_drvdata(pdev); -+ struct usb_composite_dev *cdev = dev->cdev; -+ char *state = "DISCONNECTED"; -+ unsigned long flags; -+ -+ if (!cdev) -+ goto out; -+ -+ spin_lock_irqsave(&cdev->lock, flags); -+ if (cdev->config) -+ state = "CONFIGURED"; -+ else if (dev->connected) -+ state = "CONNECTED"; -+ spin_unlock_irqrestore(&cdev->lock, flags); -+out: -+ return sprintf(buf, "%s\n", state); -+} -+ -+#define DESCRIPTOR_ATTR(field, format_string) \ -+static ssize_t \ -+field ## _show(struct device *dev, struct device_attribute *attr, \ -+ char *buf) \ -+{ \ -+ return sprintf(buf, format_string, device_desc.field); \ -+} \ -+static ssize_t \ -+field ## _store(struct device *dev, struct device_attribute *attr, \ -+ const char *buf, size_t size) \ -+{ \ -+ int value; \ -+ if (sscanf(buf, format_string, &value) == 1) { \ -+ device_desc.field = value; \ -+ return size; \ -+ } \ -+ return -1; \ -+} \ -+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); -+ -+#define DESCRIPTOR_STRING_ATTR(field, buffer) \ -+static ssize_t \ -+field ## _show(struct device *dev, struct device_attribute *attr, \ -+ char *buf) \ -+{ \ -+ return sprintf(buf, "%s", buffer); \ -+} \ -+static ssize_t \ -+field ## _store(struct device *dev, struct device_attribute *attr, \ -+ const char *buf, size_t size) \ -+{ \ -+ if (size >= sizeof(buffer)) \ -+ return -EINVAL; \ -+ return strlcpy(buffer, buf, sizeof(buffer)); \ -+} \ -+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); -+ -+ -+DESCRIPTOR_ATTR(idVendor, "%04x\n") -+DESCRIPTOR_ATTR(idProduct, "%04x\n") -+DESCRIPTOR_ATTR(bcdDevice, "%04x\n") -+DESCRIPTOR_ATTR(bDeviceClass, "%d\n") -+DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n") -+DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n") -+DESCRIPTOR_STRING_ATTR(iManufacturer, manufacturer_string) -+DESCRIPTOR_STRING_ATTR(iProduct, product_string) -+DESCRIPTOR_STRING_ATTR(iSerial, serial_string) -+ -+static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, -+ functions_store); -+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); -+static DEVICE_ATTR(state, S_IRUGO, state_show, NULL); -+ -+static struct device_attribute *android_usb_attributes[] = { -+ &dev_attr_idVendor, -+ &dev_attr_idProduct, -+ &dev_attr_bcdDevice, -+ &dev_attr_bDeviceClass, -+ &dev_attr_bDeviceSubClass, -+ &dev_attr_bDeviceProtocol, -+ &dev_attr_iManufacturer, -+ &dev_attr_iProduct, -+ &dev_attr_iSerial, -+ &dev_attr_functions, -+ &dev_attr_enable, -+ &dev_attr_state, -+ NULL -+}; -+ -+/*-------------------------------------------------------------------------*/ -+/* Composite driver */ -+ -+static int android_bind_config(struct usb_configuration *c) -+{ -+ struct android_dev *dev = _android_dev; -+ int ret = 0; -+ -+ ret = android_bind_enabled_functions(dev, c); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static void android_unbind_config(struct usb_configuration *c) -+{ -+ struct android_dev *dev = _android_dev; -+ -+ android_unbind_enabled_functions(dev, c); -+} -+ -+static int android_bind(struct usb_composite_dev *cdev) -+{ -+ struct android_dev *dev = _android_dev; -+ struct usb_gadget *gadget = cdev->gadget; -+ int gcnum, id, ret; -+ -+ /* -+ * Start disconnected. Userspace will connect the gadget once -+ * it is done configuring the functions. -+ */ -+ usb_gadget_disconnect(gadget); -+ -+ ret = android_init_functions(dev->functions, cdev); -+ if (ret) -+ return ret; -+ -+ /* Allocate string descriptor numbers ... note that string -+ * contents can be overridden by the composite_dev glue. -+ */ -+ id = usb_string_id(cdev); -+ if (id < 0) -+ return id; -+ strings_dev[STRING_MANUFACTURER_IDX].id = id; -+ device_desc.iManufacturer = id; -+ -+ id = usb_string_id(cdev); -+ if (id < 0) -+ return id; -+ strings_dev[STRING_PRODUCT_IDX].id = id; -+ device_desc.iProduct = id; -+ -+ /* Default strings - should be updated by userspace */ -+ strncpy(manufacturer_string, "Android", sizeof(manufacturer_string)-1); -+ strncpy(product_string, "Android", sizeof(product_string) - 1); -+ strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); -+ -+ id = usb_string_id(cdev); -+ if (id < 0) -+ return id; -+ strings_dev[STRING_SERIAL_IDX].id = id; -+ device_desc.iSerialNumber = id; -+ -+ gcnum = usb_gadget_controller_number(gadget); -+ if (gcnum >= 0) -+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); -+ else { -+ pr_warning("%s: controller '%s' not recognized\n", -+ longname, gadget->name); -+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); -+ } -+ -+ usb_gadget_set_selfpowered(gadget); -+ dev->cdev = cdev; -+ -+ return 0; -+} -+ -+static int android_usb_unbind(struct usb_composite_dev *cdev) -+{ -+ struct android_dev *dev = _android_dev; -+ -+ cancel_work_sync(&dev->work); -+ android_cleanup_functions(dev->functions); -+ return 0; -+} -+ -+static struct usb_composite_driver android_usb_driver = { -+ .name = "android_usb", -+ .dev = &device_desc, -+ .strings = dev_strings, -+ .unbind = android_usb_unbind, -+ .max_speed = USB_SPEED_HIGH, -+}; -+ -+static int -+android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) -+{ -+ struct android_dev *dev = _android_dev; -+ struct usb_composite_dev *cdev = get_gadget_data(gadget); -+ struct usb_request *req = cdev->req; -+ struct android_usb_function *f; -+ int value = -EOPNOTSUPP; -+ unsigned long flags; -+ -+ req->zero = 0; -+ req->complete = composite_setup_complete; -+ req->length = 0; -+ gadget->ep0->driver_data = cdev; -+ -+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) { -+ if (f->ctrlrequest) { -+ value = f->ctrlrequest(f, cdev, c); -+ if (value >= 0) -+ break; -+ } -+ } -+ -+ /* Special case the accessory function. -+ * It needs to handle control requests before it is enabled. -+ */ -+ if (value < 0) -+ value = acc_ctrlrequest(cdev, c); -+ -+ if (value < 0) -+ value = composite_setup(gadget, c); -+ -+ spin_lock_irqsave(&cdev->lock, flags); -+ if (!dev->connected) { -+ dev->connected = 1; -+ schedule_work(&dev->work); -+ } else if (c->bRequest == USB_REQ_SET_CONFIGURATION && -+ cdev->config) { -+ schedule_work(&dev->work); -+ } -+ spin_unlock_irqrestore(&cdev->lock, flags); -+ -+ return value; -+} -+ -+static void android_disconnect(struct usb_gadget *gadget) -+{ -+ struct android_dev *dev = _android_dev; -+ struct usb_composite_dev *cdev = get_gadget_data(gadget); -+ unsigned long flags; -+ -+ composite_disconnect(gadget); -+ /* accessory HID support can be active while the -+ accessory function is not actually enabled, -+ so we need to inform it when we are disconnected. -+ */ -+ acc_disconnect(); -+ -+ spin_lock_irqsave(&cdev->lock, flags); -+ dev->connected = 0; -+ schedule_work(&dev->work); -+ spin_unlock_irqrestore(&cdev->lock, flags); -+} -+ -+static int android_create_device(struct android_dev *dev) -+{ -+ struct device_attribute **attrs = android_usb_attributes; -+ struct device_attribute *attr; -+ int err; -+ -+ dev->dev = device_create(android_class, NULL, -+ MKDEV(0, 0), NULL, "android0"); -+ if (IS_ERR(dev->dev)) -+ return PTR_ERR(dev->dev); -+ -+ dev_set_drvdata(dev->dev, dev); -+ -+ while ((attr = *attrs++)) { -+ err = device_create_file(dev->dev, attr); -+ if (err) { -+ device_destroy(android_class, dev->dev->devt); -+ return err; -+ } -+ } -+ return 0; -+} -+ -+ -+static int __init init(void) -+{ -+ struct android_dev *dev; -+ int err; -+ -+ android_class = class_create(THIS_MODULE, "android_usb"); -+ if (IS_ERR(android_class)) -+ return PTR_ERR(android_class); -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ dev->disable_depth = 1; -+ dev->functions = supported_functions; -+ INIT_LIST_HEAD(&dev->enabled_functions); -+ INIT_WORK(&dev->work, android_work); -+ mutex_init(&dev->mutex); -+ -+ err = android_create_device(dev); -+ if (err) { -+ class_destroy(android_class); -+ kfree(dev); -+ return err; -+ } -+ -+ _android_dev = dev; -+ -+ /* Override composite driver functions */ -+ composite_driver.setup = android_setup; -+ composite_driver.disconnect = android_disconnect; -+ -+ return usb_composite_probe(&android_usb_driver, android_bind); -+} -+module_init(init); -+ -+static void __exit cleanup(void) -+{ -+ usb_composite_unregister(&android_usb_driver); -+ class_destroy(android_class); -+ kfree(_android_dev); -+ _android_dev = NULL; -+} -+module_exit(cleanup); -diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c -index baaebf28..8f82fc0e 100644 ---- a/drivers/usb/gadget/composite.c -+++ b/drivers/usb/gadget/composite.c -@@ -734,6 +734,7 @@ int usb_add_config(struct usb_composite_dev *cdev, - - INIT_LIST_HEAD(&config->functions); - config->next_interface_id = 0; -+ memset(config->interface, 0, sizeof(config->interface)); - - status = bind(config); - if (status < 0) { -@@ -774,6 +775,55 @@ done: - return status; - } - -+static int unbind_config(struct usb_composite_dev *cdev, -+ struct usb_configuration *config) -+{ -+ while (!list_empty(&config->functions)) { -+ struct usb_function *f; -+ -+ f = list_first_entry(&config->functions, -+ struct usb_function, list); -+ list_del(&f->list); -+ if (f->unbind) { -+ DBG(cdev, "unbind function '%s'/%p\n", f->name, f); -+ f->unbind(config, f); -+ /* may free memory for "f" */ -+ } -+ } -+ if (config->unbind) { -+ DBG(cdev, "unbind config '%s'/%p\n", config->label, config); -+ config->unbind(config); -+ /* may free memory for "c" */ -+ } -+ return 0; -+} -+ -+/** -+ * usb_remove_config() - remove a configuration from a device. -+ * @cdev: wraps the USB gadget -+ * @config: the configuration -+ * -+ * Drivers must call usb_gadget_disconnect before calling this function -+ * to disconnect the device from the host and make sure the host will not -+ * try to enumerate the device while we are changing the config list. -+ */ -+int usb_remove_config(struct usb_composite_dev *cdev, -+ struct usb_configuration *config) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&cdev->lock, flags); -+ -+ if (cdev->config == config) -+ reset_config(cdev); -+ -+ list_del(&config->list); -+ -+ spin_unlock_irqrestore(&cdev->lock, flags); -+ -+ return unbind_config(cdev, config); -+} -+ - /*-------------------------------------------------------------------------*/ - - /* We support strings in multiple languages ... string descriptor zero -@@ -1328,28 +1378,10 @@ composite_unbind(struct usb_gadget *gadget) - - while (!list_empty(&cdev->configs)) { - struct usb_configuration *c; -- - c = list_first_entry(&cdev->configs, - struct usb_configuration, list); -- while (!list_empty(&c->functions)) { -- struct usb_function *f; -- -- f = list_first_entry(&c->functions, -- struct usb_function, list); -- list_del(&f->list); -- if (f->unbind) { -- DBG(cdev, "unbind function '%s'/%p\n", -- f->name, f); -- f->unbind(c, f); -- /* may free memory for "f" */ -- } -- } - list_del(&c->list); -- if (c->unbind) { -- DBG(cdev, "unbind config '%s'/%p\n", c->label, c); -- c->unbind(c); -- /* may free memory for "c" */ -- } -+ unbind_config(cdev, c); - } - if (composite->unbind) - composite->unbind(cdev); -diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c -new file mode 100644 -index 00000000..a244265c ---- /dev/null -+++ b/drivers/usb/gadget/f_accessory.c -@@ -0,0 +1,1180 @@ -+/* -+ * Gadget Function Driver for Android USB accessories -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+/* #define DEBUG */ -+/* #define VERBOSE_DEBUG */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/poll.h> -+#include <linux/delay.h> -+#include <linux/wait.h> -+#include <linux/err.h> -+#include <linux/interrupt.h> -+#include <linux/kthread.h> -+#include <linux/freezer.h> -+ -+#include <linux/types.h> -+#include <linux/file.h> -+#include <linux/device.h> -+#include <linux/miscdevice.h> -+ -+#include <linux/hid.h> -+#include <linux/hiddev.h> -+#include <linux/usb.h> -+#include <linux/usb/ch9.h> -+#include <linux/usb/f_accessory.h> -+ -+#define BULK_BUFFER_SIZE 16384 -+#define ACC_STRING_SIZE 256 -+ -+#define PROTOCOL_VERSION 2 -+ -+/* String IDs */ -+#define INTERFACE_STRING_INDEX 0 -+ -+/* number of tx and rx requests to allocate */ -+#define TX_REQ_MAX 4 -+#define RX_REQ_MAX 2 -+ -+struct acc_hid_dev { -+ struct list_head list; -+ struct hid_device *hid; -+ struct acc_dev *dev; -+ /* accessory defined ID */ -+ int id; -+ /* HID report descriptor */ -+ u8 *report_desc; -+ /* length of HID report descriptor */ -+ int report_desc_len; -+ /* number of bytes of report_desc we have received so far */ -+ int report_desc_offset; -+}; -+ -+struct acc_dev { -+ struct usb_function function; -+ struct usb_composite_dev *cdev; -+ spinlock_t lock; -+ -+ struct usb_ep *ep_in; -+ struct usb_ep *ep_out; -+ -+ /* set to 1 when we connect */ -+ int online:1; -+ /* Set to 1 when we disconnect. -+ * Not cleared until our file is closed. -+ */ -+ int disconnected:1; -+ -+ /* strings sent by the host */ -+ char manufacturer[ACC_STRING_SIZE]; -+ char model[ACC_STRING_SIZE]; -+ char description[ACC_STRING_SIZE]; -+ char version[ACC_STRING_SIZE]; -+ char uri[ACC_STRING_SIZE]; -+ char serial[ACC_STRING_SIZE]; -+ -+ /* for acc_complete_set_string */ -+ int string_index; -+ -+ /* set to 1 if we have a pending start request */ -+ int start_requested; -+ -+ int audio_mode; -+ -+ /* synchronize access to our device file */ -+ atomic_t open_excl; -+ -+ struct list_head tx_idle; -+ -+ wait_queue_head_t read_wq; -+ wait_queue_head_t write_wq; -+ struct usb_request *rx_req[RX_REQ_MAX]; -+ int rx_done; -+ -+ /* delayed work for handling ACCESSORY_START */ -+ struct delayed_work start_work; -+ -+ /* worker for registering and unregistering hid devices */ -+ struct work_struct hid_work; -+ -+ /* list of active HID devices */ -+ struct list_head hid_list; -+ -+ /* list of new HID devices to register */ -+ struct list_head new_hid_list; -+ -+ /* list of dead HID devices to unregister */ -+ struct list_head dead_hid_list; -+}; -+ -+static struct usb_interface_descriptor acc_interface_desc = { -+ .bLength = USB_DT_INTERFACE_SIZE, -+ .bDescriptorType = USB_DT_INTERFACE, -+ .bInterfaceNumber = 0, -+ .bNumEndpoints = 2, -+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, -+ .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, -+ .bInterfaceProtocol = 0, -+}; -+ -+static struct usb_endpoint_descriptor acc_highspeed_in_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = __constant_cpu_to_le16(512), -+}; -+ -+static struct usb_endpoint_descriptor acc_highspeed_out_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_OUT, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = __constant_cpu_to_le16(512), -+}; -+ -+static struct usb_endpoint_descriptor acc_fullspeed_in_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+}; -+ -+static struct usb_endpoint_descriptor acc_fullspeed_out_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_OUT, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+}; -+ -+static struct usb_descriptor_header *fs_acc_descs[] = { -+ (struct usb_descriptor_header *) &acc_interface_desc, -+ (struct usb_descriptor_header *) &acc_fullspeed_in_desc, -+ (struct usb_descriptor_header *) &acc_fullspeed_out_desc, -+ NULL, -+}; -+ -+static struct usb_descriptor_header *hs_acc_descs[] = { -+ (struct usb_descriptor_header *) &acc_interface_desc, -+ (struct usb_descriptor_header *) &acc_highspeed_in_desc, -+ (struct usb_descriptor_header *) &acc_highspeed_out_desc, -+ NULL, -+}; -+ -+static struct usb_string acc_string_defs[] = { -+ [INTERFACE_STRING_INDEX].s = "Android Accessory Interface", -+ { }, /* end of list */ -+}; -+ -+static struct usb_gadget_strings acc_string_table = { -+ .language = 0x0409, /* en-US */ -+ .strings = acc_string_defs, -+}; -+ -+static struct usb_gadget_strings *acc_strings[] = { -+ &acc_string_table, -+ NULL, -+}; -+ -+/* temporary variable used between acc_open() and acc_gadget_bind() */ -+static struct acc_dev *_acc_dev; -+ -+static inline struct acc_dev *func_to_dev(struct usb_function *f) -+{ -+ return container_of(f, struct acc_dev, function); -+} -+ -+static struct usb_request *acc_request_new(struct usb_ep *ep, int buffer_size) -+{ -+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); -+ if (!req) -+ return NULL; -+ -+ /* now allocate buffers for the requests */ -+ req->buf = kmalloc(buffer_size, GFP_KERNEL); -+ if (!req->buf) { -+ usb_ep_free_request(ep, req); -+ return NULL; -+ } -+ -+ return req; -+} -+ -+static void acc_request_free(struct usb_request *req, struct usb_ep *ep) -+{ -+ if (req) { -+ kfree(req->buf); -+ usb_ep_free_request(ep, req); -+ } -+} -+ -+/* add a request to the tail of a list */ -+static void req_put(struct acc_dev *dev, struct list_head *head, -+ struct usb_request *req) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ list_add_tail(&req->list, head); -+ spin_unlock_irqrestore(&dev->lock, flags); -+} -+ -+/* remove a request from the head of a list */ -+static struct usb_request *req_get(struct acc_dev *dev, struct list_head *head) -+{ -+ unsigned long flags; -+ struct usb_request *req; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ if (list_empty(head)) { -+ req = 0; -+ } else { -+ req = list_first_entry(head, struct usb_request, list); -+ list_del(&req->list); -+ } -+ spin_unlock_irqrestore(&dev->lock, flags); -+ return req; -+} -+ -+static void acc_set_disconnected(struct acc_dev *dev) -+{ -+ dev->online = 0; -+ dev->disconnected = 1; -+} -+ -+static void acc_complete_in(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct acc_dev *dev = _acc_dev; -+ -+ if (req->status != 0) -+ acc_set_disconnected(dev); -+ -+ req_put(dev, &dev->tx_idle, req); -+ -+ wake_up(&dev->write_wq); -+} -+ -+static void acc_complete_out(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct acc_dev *dev = _acc_dev; -+ -+ dev->rx_done = 1; -+ if (req->status != 0) -+ acc_set_disconnected(dev); -+ -+ wake_up(&dev->read_wq); -+} -+ -+static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct acc_dev *dev = ep->driver_data; -+ char *string_dest = NULL; -+ int length = req->actual; -+ -+ if (req->status != 0) { -+ pr_err("acc_complete_set_string, err %d\n", req->status); -+ return; -+ } -+ -+ switch (dev->string_index) { -+ case ACCESSORY_STRING_MANUFACTURER: -+ string_dest = dev->manufacturer; -+ break; -+ case ACCESSORY_STRING_MODEL: -+ string_dest = dev->model; -+ break; -+ case ACCESSORY_STRING_DESCRIPTION: -+ string_dest = dev->description; -+ break; -+ case ACCESSORY_STRING_VERSION: -+ string_dest = dev->version; -+ break; -+ case ACCESSORY_STRING_URI: -+ string_dest = dev->uri; -+ break; -+ case ACCESSORY_STRING_SERIAL: -+ string_dest = dev->serial; -+ break; -+ } -+ if (string_dest) { -+ unsigned long flags; -+ -+ if (length >= ACC_STRING_SIZE) -+ length = ACC_STRING_SIZE - 1; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ memcpy(string_dest, req->buf, length); -+ /* ensure zero termination */ -+ string_dest[length] = 0; -+ spin_unlock_irqrestore(&dev->lock, flags); -+ } else { -+ pr_err("unknown accessory string index %d\n", -+ dev->string_index); -+ } -+} -+ -+static void acc_complete_set_hid_report_desc(struct usb_ep *ep, -+ struct usb_request *req) -+{ -+ struct acc_hid_dev *hid = req->context; -+ struct acc_dev *dev = hid->dev; -+ int length = req->actual; -+ -+ if (req->status != 0) { -+ pr_err("acc_complete_set_hid_report_desc, err %d\n", -+ req->status); -+ return; -+ } -+ -+ memcpy(hid->report_desc + hid->report_desc_offset, req->buf, length); -+ hid->report_desc_offset += length; -+ if (hid->report_desc_offset == hid->report_desc_len) { -+ /* After we have received the entire report descriptor -+ * we schedule work to initialize the HID device -+ */ -+ schedule_work(&dev->hid_work); -+ } -+} -+ -+static void acc_complete_send_hid_event(struct usb_ep *ep, -+ struct usb_request *req) -+{ -+ struct acc_hid_dev *hid = req->context; -+ int length = req->actual; -+ -+ if (req->status != 0) { -+ pr_err("acc_complete_send_hid_event, err %d\n", req->status); -+ return; -+ } -+ -+ hid_report_raw_event(hid->hid, HID_INPUT_REPORT, req->buf, length, 1); -+} -+ -+static int acc_hid_parse(struct hid_device *hid) -+{ -+ struct acc_hid_dev *hdev = hid->driver_data; -+ -+ hid_parse_report(hid, hdev->report_desc, hdev->report_desc_len); -+ return 0; -+} -+ -+static int acc_hid_start(struct hid_device *hid) -+{ -+ return 0; -+} -+ -+static void acc_hid_stop(struct hid_device *hid) -+{ -+} -+ -+static int acc_hid_open(struct hid_device *hid) -+{ -+ return 0; -+} -+ -+static void acc_hid_close(struct hid_device *hid) -+{ -+} -+ -+static struct hid_ll_driver acc_hid_ll_driver = { -+ .parse = acc_hid_parse, -+ .start = acc_hid_start, -+ .stop = acc_hid_stop, -+ .open = acc_hid_open, -+ .close = acc_hid_close, -+}; -+ -+static struct acc_hid_dev *acc_hid_new(struct acc_dev *dev, -+ int id, int desc_len) -+{ -+ struct acc_hid_dev *hdev; -+ -+ hdev = kzalloc(sizeof(*hdev), GFP_ATOMIC); -+ if (!hdev) -+ return NULL; -+ hdev->report_desc = kzalloc(desc_len, GFP_ATOMIC); -+ if (!hdev->report_desc) { -+ kfree(hdev); -+ return NULL; -+ } -+ hdev->dev = dev; -+ hdev->id = id; -+ hdev->report_desc_len = desc_len; -+ -+ return hdev; -+} -+ -+static struct acc_hid_dev *acc_hid_get(struct list_head *list, int id) -+{ -+ struct acc_hid_dev *hid; -+ -+ list_for_each_entry(hid, list, list) { -+ if (hid->id == id) -+ return hid; -+ } -+ return NULL; -+} -+ -+static int acc_register_hid(struct acc_dev *dev, int id, int desc_length) -+{ -+ struct acc_hid_dev *hid; -+ unsigned long flags; -+ -+ /* report descriptor length must be > 0 */ -+ if (desc_length <= 0) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ /* replace HID if one already exists with this ID */ -+ hid = acc_hid_get(&dev->hid_list, id); -+ if (!hid) -+ hid = acc_hid_get(&dev->new_hid_list, id); -+ if (hid) -+ list_move(&hid->list, &dev->dead_hid_list); -+ -+ hid = acc_hid_new(dev, id, desc_length); -+ if (!hid) { -+ spin_unlock_irqrestore(&dev->lock, flags); -+ return -ENOMEM; -+ } -+ -+ list_add(&hid->list, &dev->new_hid_list); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ /* schedule work to register the HID device */ -+ schedule_work(&dev->hid_work); -+ return 0; -+} -+ -+static int acc_unregister_hid(struct acc_dev *dev, int id) -+{ -+ struct acc_hid_dev *hid; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ hid = acc_hid_get(&dev->hid_list, id); -+ if (!hid) -+ hid = acc_hid_get(&dev->new_hid_list, id); -+ if (!hid) { -+ spin_unlock_irqrestore(&dev->lock, flags); -+ return -EINVAL; -+ } -+ -+ list_move(&hid->list, &dev->dead_hid_list); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ schedule_work(&dev->hid_work); -+ return 0; -+} -+ -+static int create_bulk_endpoints(struct acc_dev *dev, -+ struct usb_endpoint_descriptor *in_desc, -+ struct usb_endpoint_descriptor *out_desc) -+{ -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct usb_request *req; -+ struct usb_ep *ep; -+ int i; -+ -+ DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); -+ -+ ep = usb_ep_autoconfig(cdev->gadget, in_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_in = ep; -+ -+ ep = usb_ep_autoconfig(cdev->gadget, out_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_out = ep; -+ -+ ep = usb_ep_autoconfig(cdev->gadget, out_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_out = ep; -+ -+ /* now allocate requests for our endpoints */ -+ for (i = 0; i < TX_REQ_MAX; i++) { -+ req = acc_request_new(dev->ep_in, BULK_BUFFER_SIZE); -+ if (!req) -+ goto fail; -+ req->complete = acc_complete_in; -+ req_put(dev, &dev->tx_idle, req); -+ } -+ for (i = 0; i < RX_REQ_MAX; i++) { -+ req = acc_request_new(dev->ep_out, BULK_BUFFER_SIZE); -+ if (!req) -+ goto fail; -+ req->complete = acc_complete_out; -+ dev->rx_req[i] = req; -+ } -+ -+ return 0; -+ -+fail: -+ pr_err("acc_bind() could not allocate requests\n"); -+ while ((req = req_get(dev, &dev->tx_idle))) -+ acc_request_free(req, dev->ep_in); -+ for (i = 0; i < RX_REQ_MAX; i++) -+ acc_request_free(dev->rx_req[i], dev->ep_out); -+ return -1; -+} -+ -+static ssize_t acc_read(struct file *fp, char __user *buf, -+ size_t count, loff_t *pos) -+{ -+ struct acc_dev *dev = fp->private_data; -+ struct usb_request *req; -+ int r = count, xfer; -+ int ret = 0; -+ -+ pr_debug("acc_read(%d)\n", count); -+ -+ if (dev->disconnected) -+ return -ENODEV; -+ -+ if (count > BULK_BUFFER_SIZE) -+ count = BULK_BUFFER_SIZE; -+ -+ /* we will block until we're online */ -+ pr_debug("acc_read: waiting for online\n"); -+ ret = wait_event_interruptible(dev->read_wq, dev->online); -+ if (ret < 0) { -+ r = ret; -+ goto done; -+ } -+ -+requeue_req: -+ /* queue a request */ -+ req = dev->rx_req[0]; -+ req->length = count; -+ dev->rx_done = 0; -+ ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); -+ if (ret < 0) { -+ r = -EIO; -+ goto done; -+ } else { -+ pr_debug("rx %p queue\n", req); -+ } -+ -+ /* wait for a request to complete */ -+ ret = wait_event_interruptible(dev->read_wq, dev->rx_done); -+ if (ret < 0) { -+ r = ret; -+ usb_ep_dequeue(dev->ep_out, req); -+ goto done; -+ } -+ if (dev->online) { -+ /* If we got a 0-len packet, throw it back and try again. */ -+ if (req->actual == 0) -+ goto requeue_req; -+ -+ pr_debug("rx %p %d\n", req, req->actual); -+ xfer = (req->actual < count) ? req->actual : count; -+ r = xfer; -+ if (copy_to_user(buf, req->buf, xfer)) -+ r = -EFAULT; -+ } else -+ r = -EIO; -+ -+done: -+ pr_debug("acc_read returning %d\n", r); -+ return r; -+} -+ -+static ssize_t acc_write(struct file *fp, const char __user *buf, -+ size_t count, loff_t *pos) -+{ -+ struct acc_dev *dev = fp->private_data; -+ struct usb_request *req = 0; -+ int r = count, xfer; -+ int ret; -+ -+ pr_debug("acc_write(%d)\n", count); -+ -+ if (!dev->online || dev->disconnected) -+ return -ENODEV; -+ -+ while (count > 0) { -+ if (!dev->online) { -+ pr_debug("acc_write dev->error\n"); -+ r = -EIO; -+ break; -+ } -+ -+ /* get an idle tx request to use */ -+ req = 0; -+ ret = wait_event_interruptible(dev->write_wq, -+ ((req = req_get(dev, &dev->tx_idle)) || !dev->online)); -+ if (!req) { -+ r = ret; -+ break; -+ } -+ -+ if (count > BULK_BUFFER_SIZE) -+ xfer = BULK_BUFFER_SIZE; -+ else -+ xfer = count; -+ if (copy_from_user(req->buf, buf, xfer)) { -+ r = -EFAULT; -+ break; -+ } -+ -+ req->length = xfer; -+ ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); -+ if (ret < 0) { -+ pr_debug("acc_write: xfer error %d\n", ret); -+ r = -EIO; -+ break; -+ } -+ -+ buf += xfer; -+ count -= xfer; -+ -+ /* zero this so we don't try to free it on error exit */ -+ req = 0; -+ } -+ -+ if (req) -+ req_put(dev, &dev->tx_idle, req); -+ -+ pr_debug("acc_write returning %d\n", r); -+ return r; -+} -+ -+static long acc_ioctl(struct file *fp, unsigned code, unsigned long value) -+{ -+ struct acc_dev *dev = fp->private_data; -+ char *src = NULL; -+ int ret; -+ -+ switch (code) { -+ case ACCESSORY_GET_STRING_MANUFACTURER: -+ src = dev->manufacturer; -+ break; -+ case ACCESSORY_GET_STRING_MODEL: -+ src = dev->model; -+ break; -+ case ACCESSORY_GET_STRING_DESCRIPTION: -+ src = dev->description; -+ break; -+ case ACCESSORY_GET_STRING_VERSION: -+ src = dev->version; -+ break; -+ case ACCESSORY_GET_STRING_URI: -+ src = dev->uri; -+ break; -+ case ACCESSORY_GET_STRING_SERIAL: -+ src = dev->serial; -+ break; -+ case ACCESSORY_IS_START_REQUESTED: -+ return dev->start_requested; -+ case ACCESSORY_GET_AUDIO_MODE: -+ return dev->audio_mode; -+ } -+ if (!src) -+ return -EINVAL; -+ -+ ret = strlen(src) + 1; -+ if (copy_to_user((void __user *)value, src, ret)) -+ ret = -EFAULT; -+ return ret; -+} -+ -+static int acc_open(struct inode *ip, struct file *fp) -+{ -+ printk(KERN_INFO "acc_open\n"); -+ if (atomic_xchg(&_acc_dev->open_excl, 1)) -+ return -EBUSY; -+ -+ _acc_dev->disconnected = 0; -+ fp->private_data = _acc_dev; -+ return 0; -+} -+ -+static int acc_release(struct inode *ip, struct file *fp) -+{ -+ printk(KERN_INFO "acc_release\n"); -+ -+ WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0)); -+ _acc_dev->disconnected = 0; -+ return 0; -+} -+ -+/* file operations for /dev/usb_accessory */ -+static const struct file_operations acc_fops = { -+ .owner = THIS_MODULE, -+ .read = acc_read, -+ .write = acc_write, -+ .unlocked_ioctl = acc_ioctl, -+ .open = acc_open, -+ .release = acc_release, -+}; -+ -+static int acc_hid_probe(struct hid_device *hdev, -+ const struct hid_device_id *id) -+{ -+ int ret; -+ -+ ret = hid_parse(hdev); -+ if (ret) -+ return ret; -+ return hid_hw_start(hdev, HID_CONNECT_DEFAULT); -+} -+ -+static struct miscdevice acc_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "usb_accessory", -+ .fops = &acc_fops, -+}; -+ -+static const struct hid_device_id acc_hid_table[] = { -+ { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) }, -+ { } -+}; -+ -+static struct hid_driver acc_hid_driver = { -+ .name = "USB accessory", -+ .id_table = acc_hid_table, -+ .probe = acc_hid_probe, -+}; -+ -+static int acc_ctrlrequest(struct usb_composite_dev *cdev, -+ const struct usb_ctrlrequest *ctrl) -+{ -+ struct acc_dev *dev = _acc_dev; -+ int value = -EOPNOTSUPP; -+ struct acc_hid_dev *hid; -+ int offset; -+ u8 b_requestType = ctrl->bRequestType; -+ u8 b_request = ctrl->bRequest; -+ u16 w_index = le16_to_cpu(ctrl->wIndex); -+ u16 w_value = le16_to_cpu(ctrl->wValue); -+ u16 w_length = le16_to_cpu(ctrl->wLength); -+ unsigned long flags; -+ -+/* -+ printk(KERN_INFO "acc_ctrlrequest " -+ "%02x.%02x v%04x i%04x l%u\n", -+ b_requestType, b_request, -+ w_value, w_index, w_length); -+*/ -+ -+ if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { -+ if (b_request == ACCESSORY_START) { -+ dev->start_requested = 1; -+ schedule_delayed_work( -+ &dev->start_work, msecs_to_jiffies(10)); -+ value = 0; -+ } else if (b_request == ACCESSORY_SEND_STRING) { -+ dev->string_index = w_index; -+ cdev->gadget->ep0->driver_data = dev; -+ cdev->req->complete = acc_complete_set_string; -+ value = w_length; -+ } else if (b_request == ACCESSORY_SET_AUDIO_MODE && -+ w_index == 0 && w_length == 0) { -+ dev->audio_mode = w_value; -+ value = 0; -+ } else if (b_request == ACCESSORY_REGISTER_HID) { -+ value = acc_register_hid(dev, w_value, w_index); -+ } else if (b_request == ACCESSORY_UNREGISTER_HID) { -+ value = acc_unregister_hid(dev, w_value); -+ } else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) { -+ spin_lock_irqsave(&dev->lock, flags); -+ hid = acc_hid_get(&dev->new_hid_list, w_value); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ if (!hid) { -+ value = -EINVAL; -+ goto err; -+ } -+ offset = w_index; -+ if (offset != hid->report_desc_offset -+ || offset + w_length > hid->report_desc_len) { -+ value = -EINVAL; -+ goto err; -+ } -+ cdev->req->context = hid; -+ cdev->req->complete = acc_complete_set_hid_report_desc; -+ value = w_length; -+ } else if (b_request == ACCESSORY_SEND_HID_EVENT) { -+ spin_lock_irqsave(&dev->lock, flags); -+ hid = acc_hid_get(&dev->hid_list, w_value); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ if (!hid) { -+ value = -EINVAL; -+ goto err; -+ } -+ cdev->req->context = hid; -+ cdev->req->complete = acc_complete_send_hid_event; -+ value = w_length; -+ } -+ } else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) { -+ if (b_request == ACCESSORY_GET_PROTOCOL) { -+ *((u16 *)cdev->req->buf) = PROTOCOL_VERSION; -+ value = sizeof(u16); -+ -+ /* clear any string left over from a previous session */ -+ memset(dev->manufacturer, 0, sizeof(dev->manufacturer)); -+ memset(dev->model, 0, sizeof(dev->model)); -+ memset(dev->description, 0, sizeof(dev->description)); -+ memset(dev->version, 0, sizeof(dev->version)); -+ memset(dev->uri, 0, sizeof(dev->uri)); -+ memset(dev->serial, 0, sizeof(dev->serial)); -+ dev->start_requested = 0; -+ dev->audio_mode = 0; -+ } -+ } -+ -+ if (value >= 0) { -+ cdev->req->zero = 0; -+ cdev->req->length = value; -+ value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); -+ if (value < 0) -+ ERROR(cdev, "%s setup response queue error\n", -+ __func__); -+ } -+ -+err: -+ if (value == -EOPNOTSUPP) -+ VDBG(cdev, -+ "unknown class-specific control req " -+ "%02x.%02x v%04x i%04x l%u\n", -+ ctrl->bRequestType, ctrl->bRequest, -+ w_value, w_index, w_length); -+ return value; -+} -+ -+static int -+acc_function_bind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct usb_composite_dev *cdev = c->cdev; -+ struct acc_dev *dev = func_to_dev(f); -+ int id; -+ int ret; -+ -+ DBG(cdev, "acc_function_bind dev: %p\n", dev); -+ -+ ret = hid_register_driver(&acc_hid_driver); -+ if (ret) -+ return ret; -+ -+ dev->start_requested = 0; -+ -+ /* allocate interface ID(s) */ -+ id = usb_interface_id(c, f); -+ if (id < 0) -+ return id; -+ acc_interface_desc.bInterfaceNumber = id; -+ -+ /* allocate endpoints */ -+ ret = create_bulk_endpoints(dev, &acc_fullspeed_in_desc, -+ &acc_fullspeed_out_desc); -+ if (ret) -+ return ret; -+ -+ /* support high speed hardware */ -+ if (gadget_is_dualspeed(c->cdev->gadget)) { -+ acc_highspeed_in_desc.bEndpointAddress = -+ acc_fullspeed_in_desc.bEndpointAddress; -+ acc_highspeed_out_desc.bEndpointAddress = -+ acc_fullspeed_out_desc.bEndpointAddress; -+ } -+ -+ DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", -+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", -+ f->name, dev->ep_in->name, dev->ep_out->name); -+ return 0; -+} -+ -+static void -+kill_all_hid_devices(struct acc_dev *dev) -+{ -+ struct acc_hid_dev *hid; -+ struct list_head *entry, *temp; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ list_for_each_safe(entry, temp, &dev->hid_list) { -+ hid = list_entry(entry, struct acc_hid_dev, list); -+ list_del(&hid->list); -+ list_add(&hid->list, &dev->dead_hid_list); -+ } -+ list_for_each_safe(entry, temp, &dev->new_hid_list) { -+ hid = list_entry(entry, struct acc_hid_dev, list); -+ list_del(&hid->list); -+ list_add(&hid->list, &dev->dead_hid_list); -+ } -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ schedule_work(&dev->hid_work); -+} -+ -+static void -+acc_hid_unbind(struct acc_dev *dev) -+{ -+ hid_unregister_driver(&acc_hid_driver); -+ kill_all_hid_devices(dev); -+} -+ -+static void -+acc_function_unbind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct acc_dev *dev = func_to_dev(f); -+ struct usb_request *req; -+ int i; -+ -+ while ((req = req_get(dev, &dev->tx_idle))) -+ acc_request_free(req, dev->ep_in); -+ for (i = 0; i < RX_REQ_MAX; i++) -+ acc_request_free(dev->rx_req[i], dev->ep_out); -+ -+ acc_hid_unbind(dev); -+} -+ -+static void acc_start_work(struct work_struct *data) -+{ -+ char *envp[2] = { "ACCESSORY=START", NULL }; -+ kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp); -+} -+ -+static int acc_hid_init(struct acc_hid_dev *hdev) -+{ -+ struct hid_device *hid; -+ int ret; -+ -+ hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ -+ hid->ll_driver = &acc_hid_ll_driver; -+ hid->dev.parent = acc_device.this_device; -+ -+ hid->bus = BUS_USB; -+ hid->vendor = HID_ANY_ID; -+ hid->product = HID_ANY_ID; -+ hid->driver_data = hdev; -+ ret = hid_add_device(hid); -+ if (ret) { -+ pr_err("can't add hid device: %d\n", ret); -+ hid_destroy_device(hid); -+ return ret; -+ } -+ -+ hdev->hid = hid; -+ return 0; -+} -+ -+static void acc_hid_delete(struct acc_hid_dev *hid) -+{ -+ kfree(hid->report_desc); -+ kfree(hid); -+} -+ -+static void acc_hid_work(struct work_struct *data) -+{ -+ struct acc_dev *dev = _acc_dev; -+ struct list_head *entry, *temp; -+ struct acc_hid_dev *hid; -+ struct list_head new_list, dead_list; -+ unsigned long flags; -+ -+ INIT_LIST_HEAD(&new_list); -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ -+ /* copy hids that are ready for initialization to new_list */ -+ list_for_each_safe(entry, temp, &dev->new_hid_list) { -+ hid = list_entry(entry, struct acc_hid_dev, list); -+ if (hid->report_desc_offset == hid->report_desc_len) -+ list_move(&hid->list, &new_list); -+ } -+ -+ if (list_empty(&dev->dead_hid_list)) { -+ INIT_LIST_HEAD(&dead_list); -+ } else { -+ /* move all of dev->dead_hid_list to dead_list */ -+ dead_list.prev = dev->dead_hid_list.prev; -+ dead_list.next = dev->dead_hid_list.next; -+ dead_list.next->prev = &dead_list; -+ dead_list.prev->next = &dead_list; -+ INIT_LIST_HEAD(&dev->dead_hid_list); -+ } -+ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ /* register new HID devices */ -+ list_for_each_safe(entry, temp, &new_list) { -+ hid = list_entry(entry, struct acc_hid_dev, list); -+ if (acc_hid_init(hid)) { -+ pr_err("can't add HID device %p\n", hid); -+ acc_hid_delete(hid); -+ } else { -+ spin_lock_irqsave(&dev->lock, flags); -+ list_move(&hid->list, &dev->hid_list); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ } -+ } -+ -+ /* remove dead HID devices */ -+ list_for_each_safe(entry, temp, &dead_list) { -+ hid = list_entry(entry, struct acc_hid_dev, list); -+ list_del(&hid->list); -+ if (hid->hid) -+ hid_destroy_device(hid->hid); -+ acc_hid_delete(hid); -+ } -+} -+ -+static int acc_function_set_alt(struct usb_function *f, -+ unsigned intf, unsigned alt) -+{ -+ struct acc_dev *dev = func_to_dev(f); -+ struct usb_composite_dev *cdev = f->config->cdev; -+ int ret; -+ -+ DBG(cdev, "acc_function_set_alt intf: %d alt: %d\n", intf, alt); -+ -+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); -+ if (ret) -+ return ret; -+ -+ ret = usb_ep_enable(dev->ep_in); -+ if (ret) -+ return ret; -+ -+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); -+ if (ret) -+ return ret; -+ -+ ret = usb_ep_enable(dev->ep_out); -+ if (ret) { -+ usb_ep_disable(dev->ep_in); -+ return ret; -+ } -+ -+ dev->online = 1; -+ -+ /* readers may be blocked waiting for us to go online */ -+ wake_up(&dev->read_wq); -+ return 0; -+} -+ -+static void acc_function_disable(struct usb_function *f) -+{ -+ struct acc_dev *dev = func_to_dev(f); -+ struct usb_composite_dev *cdev = dev->cdev; -+ -+ DBG(cdev, "acc_function_disable\n"); -+ acc_set_disconnected(dev); -+ usb_ep_disable(dev->ep_in); -+ usb_ep_disable(dev->ep_out); -+ -+ /* readers may be blocked waiting for us to go online */ -+ wake_up(&dev->read_wq); -+ -+ VDBG(cdev, "%s disabled\n", dev->function.name); -+} -+ -+static int acc_bind_config(struct usb_configuration *c) -+{ -+ struct acc_dev *dev = _acc_dev; -+ int ret; -+ -+ printk(KERN_INFO "acc_bind_config\n"); -+ -+ /* allocate a string ID for our interface */ -+ if (acc_string_defs[INTERFACE_STRING_INDEX].id == 0) { -+ ret = usb_string_id(c->cdev); -+ if (ret < 0) -+ return ret; -+ acc_string_defs[INTERFACE_STRING_INDEX].id = ret; -+ acc_interface_desc.iInterface = ret; -+ } -+ -+ dev->cdev = c->cdev; -+ dev->function.name = "accessory"; -+ dev->function.strings = acc_strings, -+ dev->function.descriptors = fs_acc_descs; -+ dev->function.hs_descriptors = hs_acc_descs; -+ dev->function.bind = acc_function_bind; -+ dev->function.unbind = acc_function_unbind; -+ dev->function.set_alt = acc_function_set_alt; -+ dev->function.disable = acc_function_disable; -+ -+ return usb_add_function(c, &dev->function); -+} -+ -+static int acc_setup(void) -+{ -+ struct acc_dev *dev; -+ int ret; -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ spin_lock_init(&dev->lock); -+ init_waitqueue_head(&dev->read_wq); -+ init_waitqueue_head(&dev->write_wq); -+ atomic_set(&dev->open_excl, 0); -+ INIT_LIST_HEAD(&dev->tx_idle); -+ INIT_LIST_HEAD(&dev->hid_list); -+ INIT_LIST_HEAD(&dev->new_hid_list); -+ INIT_LIST_HEAD(&dev->dead_hid_list); -+ INIT_DELAYED_WORK(&dev->start_work, acc_start_work); -+ INIT_WORK(&dev->hid_work, acc_hid_work); -+ -+ /* _acc_dev must be set before calling usb_gadget_register_driver */ -+ _acc_dev = dev; -+ -+ ret = misc_register(&acc_device); -+ if (ret) -+ goto err; -+ -+ return 0; -+ -+err: -+ kfree(dev); -+ pr_err("USB accessory gadget driver failed to initialize\n"); -+ return ret; -+} -+ -+static void acc_disconnect(void) -+{ -+ /* unregister all HID devices if USB is disconnected */ -+ kill_all_hid_devices(_acc_dev); -+} -+ -+static void acc_cleanup(void) -+{ -+ misc_deregister(&acc_device); -+ kfree(_acc_dev); -+ _acc_dev = NULL; -+} -diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c -new file mode 100644 -index 00000000..1629ffb5 ---- /dev/null -+++ b/drivers/usb/gadget/f_adb.c -@@ -0,0 +1,619 @@ -+/* -+ * Gadget Driver for Android ADB -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/poll.h> -+#include <linux/delay.h> -+#include <linux/wait.h> -+#include <linux/err.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+#include <linux/types.h> -+#include <linux/device.h> -+#include <linux/miscdevice.h> -+ -+#define ADB_BULK_BUFFER_SIZE 4096 -+ -+/* number of tx requests to allocate */ -+#define TX_REQ_MAX 4 -+ -+static const char adb_shortname[] = "android_adb"; -+ -+struct adb_dev { -+ struct usb_function function; -+ struct usb_composite_dev *cdev; -+ spinlock_t lock; -+ -+ struct usb_ep *ep_in; -+ struct usb_ep *ep_out; -+ -+ int online; -+ int error; -+ -+ atomic_t read_excl; -+ atomic_t write_excl; -+ atomic_t open_excl; -+ -+ struct list_head tx_idle; -+ -+ wait_queue_head_t read_wq; -+ wait_queue_head_t write_wq; -+ struct usb_request *rx_req; -+ int rx_done; -+}; -+ -+static struct usb_interface_descriptor adb_interface_desc = { -+ .bLength = USB_DT_INTERFACE_SIZE, -+ .bDescriptorType = USB_DT_INTERFACE, -+ .bInterfaceNumber = 0, -+ .bNumEndpoints = 2, -+ .bInterfaceClass = 0xFF, -+ .bInterfaceSubClass = 0x42, -+ .bInterfaceProtocol = 1, -+}; -+ -+static struct usb_endpoint_descriptor adb_highspeed_in_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = __constant_cpu_to_le16(512), -+}; -+ -+static struct usb_endpoint_descriptor adb_highspeed_out_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_OUT, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = __constant_cpu_to_le16(512), -+}; -+ -+static struct usb_endpoint_descriptor adb_fullspeed_in_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+}; -+ -+static struct usb_endpoint_descriptor adb_fullspeed_out_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_OUT, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+}; -+ -+static struct usb_descriptor_header *fs_adb_descs[] = { -+ (struct usb_descriptor_header *) &adb_interface_desc, -+ (struct usb_descriptor_header *) &adb_fullspeed_in_desc, -+ (struct usb_descriptor_header *) &adb_fullspeed_out_desc, -+ NULL, -+}; -+ -+static struct usb_descriptor_header *hs_adb_descs[] = { -+ (struct usb_descriptor_header *) &adb_interface_desc, -+ (struct usb_descriptor_header *) &adb_highspeed_in_desc, -+ (struct usb_descriptor_header *) &adb_highspeed_out_desc, -+ NULL, -+}; -+ -+static void adb_ready_callback(void); -+static void adb_closed_callback(void); -+ -+/* temporary variable used between adb_open() and adb_gadget_bind() */ -+static struct adb_dev *_adb_dev; -+ -+static inline struct adb_dev *func_to_adb(struct usb_function *f) -+{ -+ return container_of(f, struct adb_dev, function); -+} -+ -+ -+static struct usb_request *adb_request_new(struct usb_ep *ep, int buffer_size) -+{ -+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); -+ if (!req) -+ return NULL; -+ -+ /* now allocate buffers for the requests */ -+ req->buf = kmalloc(buffer_size, GFP_KERNEL); -+ if (!req->buf) { -+ usb_ep_free_request(ep, req); -+ return NULL; -+ } -+ -+ return req; -+} -+ -+static void adb_request_free(struct usb_request *req, struct usb_ep *ep) -+{ -+ if (req) { -+ kfree(req->buf); -+ usb_ep_free_request(ep, req); -+ } -+} -+ -+static inline int adb_lock(atomic_t *excl) -+{ -+ if (atomic_inc_return(excl) == 1) { -+ return 0; -+ } else { -+ atomic_dec(excl); -+ return -1; -+ } -+} -+ -+static inline void adb_unlock(atomic_t *excl) -+{ -+ atomic_dec(excl); -+} -+ -+/* add a request to the tail of a list */ -+void adb_req_put(struct adb_dev *dev, struct list_head *head, -+ struct usb_request *req) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ list_add_tail(&req->list, head); -+ spin_unlock_irqrestore(&dev->lock, flags); -+} -+ -+/* remove a request from the head of a list */ -+struct usb_request *adb_req_get(struct adb_dev *dev, struct list_head *head) -+{ -+ unsigned long flags; -+ struct usb_request *req; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ if (list_empty(head)) { -+ req = 0; -+ } else { -+ req = list_first_entry(head, struct usb_request, list); -+ list_del(&req->list); -+ } -+ spin_unlock_irqrestore(&dev->lock, flags); -+ return req; -+} -+ -+static void adb_complete_in(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct adb_dev *dev = _adb_dev; -+ -+ if (req->status != 0) -+ dev->error = 1; -+ -+ adb_req_put(dev, &dev->tx_idle, req); -+ -+ wake_up(&dev->write_wq); -+} -+ -+static void adb_complete_out(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct adb_dev *dev = _adb_dev; -+ -+ dev->rx_done = 1; -+ if (req->status != 0 && req->status != -ECONNRESET) -+ dev->error = 1; -+ -+ wake_up(&dev->read_wq); -+} -+ -+static int adb_create_bulk_endpoints(struct adb_dev *dev, -+ struct usb_endpoint_descriptor *in_desc, -+ struct usb_endpoint_descriptor *out_desc) -+{ -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct usb_request *req; -+ struct usb_ep *ep; -+ int i; -+ -+ DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); -+ -+ ep = usb_ep_autoconfig(cdev->gadget, in_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_in = ep; -+ -+ ep = usb_ep_autoconfig(cdev->gadget, out_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for adb ep_out got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_out = ep; -+ -+ /* now allocate requests for our endpoints */ -+ req = adb_request_new(dev->ep_out, ADB_BULK_BUFFER_SIZE); -+ if (!req) -+ goto fail; -+ req->complete = adb_complete_out; -+ dev->rx_req = req; -+ -+ for (i = 0; i < TX_REQ_MAX; i++) { -+ req = adb_request_new(dev->ep_in, ADB_BULK_BUFFER_SIZE); -+ if (!req) -+ goto fail; -+ req->complete = adb_complete_in; -+ adb_req_put(dev, &dev->tx_idle, req); -+ } -+ -+ return 0; -+ -+fail: -+ printk(KERN_ERR "adb_bind() could not allocate requests\n"); -+ return -1; -+} -+ -+static ssize_t adb_read(struct file *fp, char __user *buf, -+ size_t count, loff_t *pos) -+{ -+ struct adb_dev *dev = fp->private_data; -+ struct usb_request *req; -+ int r = count, xfer; -+ int ret; -+ -+ pr_debug("adb_read(%d)\n", count); -+ if (!_adb_dev) -+ return -ENODEV; -+ -+ if (count > ADB_BULK_BUFFER_SIZE) -+ return -EINVAL; -+ -+ if (adb_lock(&dev->read_excl)) -+ return -EBUSY; -+ -+ /* we will block until we're online */ -+ while (!(dev->online || dev->error)) { -+ pr_debug("adb_read: waiting for online state\n"); -+ ret = wait_event_interruptible(dev->read_wq, -+ (dev->online || dev->error)); -+ if (ret < 0) { -+ adb_unlock(&dev->read_excl); -+ return ret; -+ } -+ } -+ if (dev->error) { -+ r = -EIO; -+ goto done; -+ } -+ -+requeue_req: -+ /* queue a request */ -+ req = dev->rx_req; -+ req->length = count; -+ dev->rx_done = 0; -+ ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); -+ if (ret < 0) { -+ pr_debug("adb_read: failed to queue req %p (%d)\n", req, ret); -+ r = -EIO; -+ dev->error = 1; -+ goto done; -+ } else { -+ pr_debug("rx %p queue\n", req); -+ } -+ -+ /* wait for a request to complete */ -+ ret = wait_event_interruptible(dev->read_wq, dev->rx_done); -+ if (ret < 0) { -+ if (ret != -ERESTARTSYS) -+ dev->error = 1; -+ r = ret; -+ usb_ep_dequeue(dev->ep_out, req); -+ goto done; -+ } -+ if (!dev->error) { -+ /* If we got a 0-len packet, throw it back and try again. */ -+ if (req->actual == 0) -+ goto requeue_req; -+ -+ pr_debug("rx %p %d\n", req, req->actual); -+ xfer = (req->actual < count) ? req->actual : count; -+ if (copy_to_user(buf, req->buf, xfer)) -+ r = -EFAULT; -+ -+ } else -+ r = -EIO; -+ -+done: -+ adb_unlock(&dev->read_excl); -+ pr_debug("adb_read returning %d\n", r); -+ return r; -+} -+ -+static ssize_t adb_write(struct file *fp, const char __user *buf, -+ size_t count, loff_t *pos) -+{ -+ struct adb_dev *dev = fp->private_data; -+ struct usb_request *req = 0; -+ int r = count, xfer; -+ int ret; -+ -+ if (!_adb_dev) -+ return -ENODEV; -+ pr_debug("adb_write(%d)\n", count); -+ -+ if (adb_lock(&dev->write_excl)) -+ return -EBUSY; -+ -+ while (count > 0) { -+ if (dev->error) { -+ pr_debug("adb_write dev->error\n"); -+ r = -EIO; -+ break; -+ } -+ -+ /* get an idle tx request to use */ -+ req = 0; -+ ret = wait_event_interruptible(dev->write_wq, -+ (req = adb_req_get(dev, &dev->tx_idle)) || dev->error); -+ -+ if (ret < 0) { -+ r = ret; -+ break; -+ } -+ -+ if (req != 0) { -+ if (count > ADB_BULK_BUFFER_SIZE) -+ xfer = ADB_BULK_BUFFER_SIZE; -+ else -+ xfer = count; -+ if (copy_from_user(req->buf, buf, xfer)) { -+ r = -EFAULT; -+ break; -+ } -+ -+ req->length = xfer; -+ ret = usb_ep_queue(dev->ep_in, req, GFP_ATOMIC); -+ if (ret < 0) { -+ pr_debug("adb_write: xfer error %d\n", ret); -+ dev->error = 1; -+ r = -EIO; -+ break; -+ } -+ -+ buf += xfer; -+ count -= xfer; -+ -+ /* zero this so we don't try to free it on error exit */ -+ req = 0; -+ } -+ } -+ -+ if (req) -+ adb_req_put(dev, &dev->tx_idle, req); -+ -+ adb_unlock(&dev->write_excl); -+ pr_debug("adb_write returning %d\n", r); -+ return r; -+} -+ -+static int adb_open(struct inode *ip, struct file *fp) -+{ -+ pr_info("adb_open\n"); -+ if (!_adb_dev) -+ return -ENODEV; -+ -+ if (adb_lock(&_adb_dev->open_excl)) -+ return -EBUSY; -+ -+ fp->private_data = _adb_dev; -+ -+ /* clear the error latch */ -+ _adb_dev->error = 0; -+ -+ adb_ready_callback(); -+ -+ return 0; -+} -+ -+static int adb_release(struct inode *ip, struct file *fp) -+{ -+ pr_info("adb_release\n"); -+ -+ adb_closed_callback(); -+ -+ adb_unlock(&_adb_dev->open_excl); -+ return 0; -+} -+ -+/* file operations for ADB device /dev/android_adb */ -+static const struct file_operations adb_fops = { -+ .owner = THIS_MODULE, -+ .read = adb_read, -+ .write = adb_write, -+ .open = adb_open, -+ .release = adb_release, -+}; -+ -+static struct miscdevice adb_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = adb_shortname, -+ .fops = &adb_fops, -+}; -+ -+ -+ -+ -+static int -+adb_function_bind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct usb_composite_dev *cdev = c->cdev; -+ struct adb_dev *dev = func_to_adb(f); -+ int id; -+ int ret; -+ -+ dev->cdev = cdev; -+ DBG(cdev, "adb_function_bind dev: %p\n", dev); -+ -+ /* allocate interface ID(s) */ -+ id = usb_interface_id(c, f); -+ if (id < 0) -+ return id; -+ adb_interface_desc.bInterfaceNumber = id; -+ -+ /* allocate endpoints */ -+ ret = adb_create_bulk_endpoints(dev, &adb_fullspeed_in_desc, -+ &adb_fullspeed_out_desc); -+ if (ret) -+ return ret; -+ -+ /* support high speed hardware */ -+ if (gadget_is_dualspeed(c->cdev->gadget)) { -+ adb_highspeed_in_desc.bEndpointAddress = -+ adb_fullspeed_in_desc.bEndpointAddress; -+ adb_highspeed_out_desc.bEndpointAddress = -+ adb_fullspeed_out_desc.bEndpointAddress; -+ } -+ -+ DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", -+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", -+ f->name, dev->ep_in->name, dev->ep_out->name); -+ return 0; -+} -+ -+static void -+adb_function_unbind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct adb_dev *dev = func_to_adb(f); -+ struct usb_request *req; -+ -+ -+ dev->online = 0; -+ dev->error = 1; -+ -+ wake_up(&dev->read_wq); -+ -+ adb_request_free(dev->rx_req, dev->ep_out); -+ while ((req = adb_req_get(dev, &dev->tx_idle))) -+ adb_request_free(req, dev->ep_in); -+} -+ -+static int adb_function_set_alt(struct usb_function *f, -+ unsigned intf, unsigned alt) -+{ -+ struct adb_dev *dev = func_to_adb(f); -+ struct usb_composite_dev *cdev = f->config->cdev; -+ int ret; -+ -+ DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt); -+ -+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); -+ if (ret) -+ return ret; -+ -+ ret = usb_ep_enable(dev->ep_in); -+ if (ret) -+ return ret; -+ -+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); -+ if (ret) -+ return ret; -+ -+ ret = usb_ep_enable(dev->ep_out); -+ if (ret) { -+ usb_ep_disable(dev->ep_in); -+ return ret; -+ } -+ dev->online = 1; -+ -+ /* readers may be blocked waiting for us to go online */ -+ wake_up(&dev->read_wq); -+ return 0; -+} -+ -+static void adb_function_disable(struct usb_function *f) -+{ -+ struct adb_dev *dev = func_to_adb(f); -+ struct usb_composite_dev *cdev = dev->cdev; -+ -+ DBG(cdev, "adb_function_disable cdev %p\n", cdev); -+ dev->online = 0; -+ dev->error = 1; -+ usb_ep_disable(dev->ep_in); -+ usb_ep_disable(dev->ep_out); -+ -+ /* readers may be blocked waiting for us to go online */ -+ wake_up(&dev->read_wq); -+ -+ VDBG(cdev, "%s disabled\n", dev->function.name); -+} -+ -+static int adb_bind_config(struct usb_configuration *c) -+{ -+ struct adb_dev *dev = _adb_dev; -+ -+ printk(KERN_INFO "adb_bind_config\n"); -+ -+ dev->cdev = c->cdev; -+ dev->function.name = "adb"; -+ dev->function.descriptors = fs_adb_descs; -+ dev->function.hs_descriptors = hs_adb_descs; -+ dev->function.bind = adb_function_bind; -+ dev->function.unbind = adb_function_unbind; -+ dev->function.set_alt = adb_function_set_alt; -+ dev->function.disable = adb_function_disable; -+ -+ return usb_add_function(c, &dev->function); -+} -+ -+static int adb_setup(void) -+{ -+ struct adb_dev *dev; -+ int ret; -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ spin_lock_init(&dev->lock); -+ -+ init_waitqueue_head(&dev->read_wq); -+ init_waitqueue_head(&dev->write_wq); -+ -+ atomic_set(&dev->open_excl, 0); -+ atomic_set(&dev->read_excl, 0); -+ atomic_set(&dev->write_excl, 0); -+ -+ INIT_LIST_HEAD(&dev->tx_idle); -+ -+ _adb_dev = dev; -+ -+ ret = misc_register(&adb_device); -+ if (ret) -+ goto err; -+ -+ return 0; -+ -+err: -+ kfree(dev); -+ printk(KERN_ERR "adb gadget driver failed to initialize\n"); -+ return ret; -+} -+ -+static void adb_cleanup(void) -+{ -+ misc_deregister(&adb_device); -+ -+ kfree(_adb_dev); -+ _adb_dev = NULL; -+} -diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c -new file mode 100644 -index 00000000..c757409e ---- /dev/null -+++ b/drivers/usb/gadget/f_audio_source.c -@@ -0,0 +1,828 @@ -+/* -+ * Gadget Function Driver for USB audio source device -+ * -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/device.h> -+#include <linux/usb/audio.h> -+#include <linux/wait.h> -+#include <sound/core.h> -+#include <sound/initval.h> -+#include <sound/pcm.h> -+ -+#define SAMPLE_RATE 44100 -+#define FRAMES_PER_MSEC (SAMPLE_RATE / 1000) -+ -+#define IN_EP_MAX_PACKET_SIZE 384 -+ -+/* Number of requests to allocate */ -+#define IN_EP_REQ_COUNT 4 -+ -+#define AUDIO_AC_INTERFACE 0 -+#define AUDIO_AS_INTERFACE 1 -+#define AUDIO_NUM_INTERFACES 2 -+ -+/* B.3.1 Standard AC Interface Descriptor */ -+static struct usb_interface_descriptor ac_interface_desc = { -+ .bLength = USB_DT_INTERFACE_SIZE, -+ .bDescriptorType = USB_DT_INTERFACE, -+ .bNumEndpoints = 0, -+ .bInterfaceClass = USB_CLASS_AUDIO, -+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, -+}; -+ -+DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); -+ -+#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(AUDIO_NUM_INTERFACES) -+/* 1 input terminal, 1 output terminal and 1 feature unit */ -+#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ -+ + UAC_DT_INPUT_TERMINAL_SIZE + UAC_DT_OUTPUT_TERMINAL_SIZE \ -+ + UAC_DT_FEATURE_UNIT_SIZE(0)) -+/* B.3.2 Class-Specific AC Interface Descriptor */ -+static struct uac1_ac_header_descriptor_2 ac_header_desc = { -+ .bLength = UAC_DT_AC_HEADER_LENGTH, -+ .bDescriptorType = USB_DT_CS_INTERFACE, -+ .bDescriptorSubtype = UAC_HEADER, -+ .bcdADC = __constant_cpu_to_le16(0x0100), -+ .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH), -+ .bInCollection = AUDIO_NUM_INTERFACES, -+ .baInterfaceNr = { -+ [0] = AUDIO_AC_INTERFACE, -+ [1] = AUDIO_AS_INTERFACE, -+ } -+}; -+ -+#define INPUT_TERMINAL_ID 1 -+static struct uac_input_terminal_descriptor input_terminal_desc = { -+ .bLength = UAC_DT_INPUT_TERMINAL_SIZE, -+ .bDescriptorType = USB_DT_CS_INTERFACE, -+ .bDescriptorSubtype = UAC_INPUT_TERMINAL, -+ .bTerminalID = INPUT_TERMINAL_ID, -+ .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE, -+ .bAssocTerminal = 0, -+ .wChannelConfig = 0x3, -+}; -+ -+DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0); -+ -+#define FEATURE_UNIT_ID 2 -+static struct uac_feature_unit_descriptor_0 feature_unit_desc = { -+ .bLength = UAC_DT_FEATURE_UNIT_SIZE(0), -+ .bDescriptorType = USB_DT_CS_INTERFACE, -+ .bDescriptorSubtype = UAC_FEATURE_UNIT, -+ .bUnitID = FEATURE_UNIT_ID, -+ .bSourceID = INPUT_TERMINAL_ID, -+ .bControlSize = 2, -+}; -+ -+#define OUTPUT_TERMINAL_ID 3 -+static struct uac1_output_terminal_descriptor output_terminal_desc = { -+ .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, -+ .bDescriptorType = USB_DT_CS_INTERFACE, -+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, -+ .bTerminalID = OUTPUT_TERMINAL_ID, -+ .wTerminalType = UAC_TERMINAL_STREAMING, -+ .bAssocTerminal = FEATURE_UNIT_ID, -+ .bSourceID = FEATURE_UNIT_ID, -+}; -+ -+/* B.4.1 Standard AS Interface Descriptor */ -+static struct usb_interface_descriptor as_interface_alt_0_desc = { -+ .bLength = USB_DT_INTERFACE_SIZE, -+ .bDescriptorType = USB_DT_INTERFACE, -+ .bAlternateSetting = 0, -+ .bNumEndpoints = 0, -+ .bInterfaceClass = USB_CLASS_AUDIO, -+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, -+}; -+ -+static struct usb_interface_descriptor as_interface_alt_1_desc = { -+ .bLength = USB_DT_INTERFACE_SIZE, -+ .bDescriptorType = USB_DT_INTERFACE, -+ .bAlternateSetting = 1, -+ .bNumEndpoints = 1, -+ .bInterfaceClass = USB_CLASS_AUDIO, -+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, -+}; -+ -+/* B.4.2 Class-Specific AS Interface Descriptor */ -+static struct uac1_as_header_descriptor as_header_desc = { -+ .bLength = UAC_DT_AS_HEADER_SIZE, -+ .bDescriptorType = USB_DT_CS_INTERFACE, -+ .bDescriptorSubtype = UAC_AS_GENERAL, -+ .bTerminalLink = INPUT_TERMINAL_ID, -+ .bDelay = 1, -+ .wFormatTag = UAC_FORMAT_TYPE_I_PCM, -+}; -+ -+DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1); -+ -+static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = { -+ .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), -+ .bDescriptorType = USB_DT_CS_INTERFACE, -+ .bDescriptorSubtype = UAC_FORMAT_TYPE, -+ .bFormatType = UAC_FORMAT_TYPE_I, -+ .bSubframeSize = 2, -+ .bBitResolution = 16, -+ .bSamFreqType = 1, -+}; -+ -+/* Standard ISO IN Endpoint Descriptor for highspeed */ -+static struct usb_endpoint_descriptor hs_as_in_ep_desc = { -+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC -+ | USB_ENDPOINT_XFER_ISOC, -+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE), -+ .bInterval = 4, /* poll 1 per millisecond */ -+}; -+ -+/* Standard ISO IN Endpoint Descriptor for highspeed */ -+static struct usb_endpoint_descriptor fs_as_in_ep_desc = { -+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC -+ | USB_ENDPOINT_XFER_ISOC, -+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE), -+ .bInterval = 1, /* poll 1 per millisecond */ -+}; -+ -+/* Class-specific AS ISO OUT Endpoint Descriptor */ -+static struct uac_iso_endpoint_descriptor as_iso_in_desc = { -+ .bLength = UAC_ISO_ENDPOINT_DESC_SIZE, -+ .bDescriptorType = USB_DT_CS_ENDPOINT, -+ .bDescriptorSubtype = UAC_EP_GENERAL, -+ .bmAttributes = 1, -+ .bLockDelayUnits = 1, -+ .wLockDelay = __constant_cpu_to_le16(1), -+}; -+ -+static struct usb_descriptor_header *hs_audio_desc[] = { -+ (struct usb_descriptor_header *)&ac_interface_desc, -+ (struct usb_descriptor_header *)&ac_header_desc, -+ -+ (struct usb_descriptor_header *)&input_terminal_desc, -+ (struct usb_descriptor_header *)&output_terminal_desc, -+ (struct usb_descriptor_header *)&feature_unit_desc, -+ -+ (struct usb_descriptor_header *)&as_interface_alt_0_desc, -+ (struct usb_descriptor_header *)&as_interface_alt_1_desc, -+ (struct usb_descriptor_header *)&as_header_desc, -+ -+ (struct usb_descriptor_header *)&as_type_i_desc, -+ -+ (struct usb_descriptor_header *)&hs_as_in_ep_desc, -+ (struct usb_descriptor_header *)&as_iso_in_desc, -+ NULL, -+}; -+ -+static struct usb_descriptor_header *fs_audio_desc[] = { -+ (struct usb_descriptor_header *)&ac_interface_desc, -+ (struct usb_descriptor_header *)&ac_header_desc, -+ -+ (struct usb_descriptor_header *)&input_terminal_desc, -+ (struct usb_descriptor_header *)&output_terminal_desc, -+ (struct usb_descriptor_header *)&feature_unit_desc, -+ -+ (struct usb_descriptor_header *)&as_interface_alt_0_desc, -+ (struct usb_descriptor_header *)&as_interface_alt_1_desc, -+ (struct usb_descriptor_header *)&as_header_desc, -+ -+ (struct usb_descriptor_header *)&as_type_i_desc, -+ -+ (struct usb_descriptor_header *)&fs_as_in_ep_desc, -+ (struct usb_descriptor_header *)&as_iso_in_desc, -+ NULL, -+}; -+ -+static struct snd_pcm_hardware audio_hw_info = { -+ .info = SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID | -+ SNDRV_PCM_INFO_BATCH | -+ SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_BLOCK_TRANSFER, -+ -+ .formats = SNDRV_PCM_FMTBIT_S16_LE, -+ .channels_min = 2, -+ .channels_max = 2, -+ .rate_min = SAMPLE_RATE, -+ .rate_max = SAMPLE_RATE, -+ -+ .buffer_bytes_max = 1024 * 1024, -+ .period_bytes_min = 64, -+ .period_bytes_max = 512 * 1024, -+ .periods_min = 2, -+ .periods_max = 1024, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+struct audio_source_config { -+ int card; -+ int device; -+}; -+ -+struct audio_dev { -+ struct usb_function func; -+ struct snd_card *card; -+ struct snd_pcm *pcm; -+ struct snd_pcm_substream *substream; -+ -+ struct list_head idle_reqs; -+ struct usb_ep *in_ep; -+ -+ spinlock_t lock; -+ -+ /* beginning, end and current position in our buffer */ -+ void *buffer_start; -+ void *buffer_end; -+ void *buffer_pos; -+ -+ /* byte size of a "period" */ -+ unsigned int period; -+ /* bytes sent since last call to snd_pcm_period_elapsed */ -+ unsigned int period_offset; -+ /* time we started playing */ -+ ktime_t start_time; -+ /* number of frames sent since start_time */ -+ s64 frames_sent; -+}; -+ -+static inline struct audio_dev *func_to_audio(struct usb_function *f) -+{ -+ return container_of(f, struct audio_dev, func); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size) -+{ -+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); -+ if (!req) -+ return NULL; -+ -+ req->buf = kmalloc(buffer_size, GFP_KERNEL); -+ if (!req->buf) { -+ usb_ep_free_request(ep, req); -+ return NULL; -+ } -+ req->length = buffer_size; -+ return req; -+} -+ -+static void audio_request_free(struct usb_request *req, struct usb_ep *ep) -+{ -+ if (req) { -+ kfree(req->buf); -+ usb_ep_free_request(ep, req); -+ } -+} -+ -+static void audio_req_put(struct audio_dev *audio, struct usb_request *req) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&audio->lock, flags); -+ list_add_tail(&req->list, &audio->idle_reqs); -+ spin_unlock_irqrestore(&audio->lock, flags); -+} -+ -+static struct usb_request *audio_req_get(struct audio_dev *audio) -+{ -+ unsigned long flags; -+ struct usb_request *req; -+ -+ spin_lock_irqsave(&audio->lock, flags); -+ if (list_empty(&audio->idle_reqs)) { -+ req = 0; -+ } else { -+ req = list_first_entry(&audio->idle_reqs, struct usb_request, -+ list); -+ list_del(&req->list); -+ } -+ spin_unlock_irqrestore(&audio->lock, flags); -+ return req; -+} -+ -+/* send the appropriate number of packets to match our bitrate */ -+static void audio_send(struct audio_dev *audio) -+{ -+ struct snd_pcm_runtime *runtime; -+ struct usb_request *req; -+ int length, length1, length2, ret; -+ s64 msecs; -+ s64 frames; -+ ktime_t now; -+ -+ /* audio->substream will be null if we have been closed */ -+ if (!audio->substream) -+ return; -+ /* audio->buffer_pos will be null if we have been stopped */ -+ if (!audio->buffer_pos) -+ return; -+ -+ runtime = audio->substream->runtime; -+ -+ /* compute number of frames to send */ -+ now = ktime_get(); -+ msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time); -+ do_div(msecs, 1000000); -+ frames = msecs * SAMPLE_RATE; -+ do_div(frames, 1000); -+ -+ /* Readjust our frames_sent if we fall too far behind. -+ * If we get too far behind it is better to drop some frames than -+ * to keep sending data too fast in an attempt to catch up. -+ */ -+ if (frames - audio->frames_sent > 10 * FRAMES_PER_MSEC) -+ audio->frames_sent = frames - FRAMES_PER_MSEC; -+ -+ frames -= audio->frames_sent; -+ -+ /* We need to send something to keep the pipeline going */ -+ if (frames <= 0) -+ frames = FRAMES_PER_MSEC; -+ -+ while (frames > 0) { -+ req = audio_req_get(audio); -+ if (!req) -+ break; -+ -+ length = frames_to_bytes(runtime, frames); -+ if (length > IN_EP_MAX_PACKET_SIZE) -+ length = IN_EP_MAX_PACKET_SIZE; -+ -+ if (audio->buffer_pos + length > audio->buffer_end) -+ length1 = audio->buffer_end - audio->buffer_pos; -+ else -+ length1 = length; -+ memcpy(req->buf, audio->buffer_pos, length1); -+ if (length1 < length) { -+ /* Wrap around and copy remaining length -+ * at beginning of buffer. -+ */ -+ length2 = length - length1; -+ memcpy(req->buf + length1, audio->buffer_start, -+ length2); -+ audio->buffer_pos = audio->buffer_start + length2; -+ } else { -+ audio->buffer_pos += length1; -+ if (audio->buffer_pos >= audio->buffer_end) -+ audio->buffer_pos = audio->buffer_start; -+ } -+ -+ req->length = length; -+ ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC); -+ if (ret < 0) { -+ pr_err("usb_ep_queue failed ret: %d\n", ret); -+ audio_req_put(audio, req); -+ break; -+ } -+ -+ frames -= bytes_to_frames(runtime, length); -+ audio->frames_sent += bytes_to_frames(runtime, length); -+ } -+} -+ -+static void audio_control_complete(struct usb_ep *ep, struct usb_request *req) -+{ -+ /* nothing to do here */ -+} -+ -+static void audio_data_complete(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct audio_dev *audio = req->context; -+ -+ pr_debug("audio_data_complete req->status %d req->actual %d\n", -+ req->status, req->actual); -+ -+ audio_req_put(audio, req); -+ -+ if (!audio->buffer_start || req->status) -+ return; -+ -+ audio->period_offset += req->actual; -+ if (audio->period_offset >= audio->period) { -+ snd_pcm_period_elapsed(audio->substream); -+ audio->period_offset = 0; -+ } -+ audio_send(audio); -+} -+ -+static int audio_set_endpoint_req(struct usb_function *f, -+ const struct usb_ctrlrequest *ctrl) -+{ -+ int value = -EOPNOTSUPP; -+ u16 ep = le16_to_cpu(ctrl->wIndex); -+ u16 len = le16_to_cpu(ctrl->wLength); -+ u16 w_value = le16_to_cpu(ctrl->wValue); -+ -+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", -+ ctrl->bRequest, w_value, len, ep); -+ -+ switch (ctrl->bRequest) { -+ case UAC_SET_CUR: -+ case UAC_SET_MIN: -+ case UAC_SET_MAX: -+ case UAC_SET_RES: -+ value = len; -+ break; -+ default: -+ break; -+ } -+ -+ return value; -+} -+ -+static int audio_get_endpoint_req(struct usb_function *f, -+ const struct usb_ctrlrequest *ctrl) -+{ -+ struct usb_composite_dev *cdev = f->config->cdev; -+ int value = -EOPNOTSUPP; -+ u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); -+ u16 len = le16_to_cpu(ctrl->wLength); -+ u16 w_value = le16_to_cpu(ctrl->wValue); -+ u8 *buf = cdev->req->buf; -+ -+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", -+ ctrl->bRequest, w_value, len, ep); -+ -+ if (w_value == UAC_EP_CS_ATTR_SAMPLE_RATE << 8) { -+ switch (ctrl->bRequest) { -+ case UAC_GET_CUR: -+ case UAC_GET_MIN: -+ case UAC_GET_MAX: -+ case UAC_GET_RES: -+ /* return our sample rate */ -+ buf[0] = (u8)SAMPLE_RATE; -+ buf[1] = (u8)(SAMPLE_RATE >> 8); -+ buf[2] = (u8)(SAMPLE_RATE >> 16); -+ value = 3; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ return value; -+} -+ -+static int -+audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -+{ -+ struct usb_composite_dev *cdev = f->config->cdev; -+ struct usb_request *req = cdev->req; -+ int value = -EOPNOTSUPP; -+ u16 w_index = le16_to_cpu(ctrl->wIndex); -+ u16 w_value = le16_to_cpu(ctrl->wValue); -+ u16 w_length = le16_to_cpu(ctrl->wLength); -+ -+ /* composite driver infrastructure handles everything; interface -+ * activation uses set_alt(). -+ */ -+ switch (ctrl->bRequestType) { -+ case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: -+ value = audio_set_endpoint_req(f, ctrl); -+ break; -+ -+ case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: -+ value = audio_get_endpoint_req(f, ctrl); -+ break; -+ } -+ -+ /* respond with data transfer or status phase? */ -+ if (value >= 0) { -+ pr_debug("audio req%02x.%02x v%04x i%04x l%d\n", -+ ctrl->bRequestType, ctrl->bRequest, -+ w_value, w_index, w_length); -+ req->zero = 0; -+ req->length = value; -+ req->complete = audio_control_complete; -+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); -+ if (value < 0) -+ pr_err("audio response on err %d\n", value); -+ } -+ -+ /* device either stalls (value < 0) or reports success */ -+ return value; -+} -+ -+static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -+{ -+ struct audio_dev *audio = func_to_audio(f); -+ struct usb_composite_dev *cdev = f->config->cdev; -+ int ret; -+ -+ pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt); -+ -+ ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep); -+ if (ret) -+ return ret; -+ -+ usb_ep_enable(audio->in_ep); -+ return 0; -+} -+ -+static void audio_disable(struct usb_function *f) -+{ -+ struct audio_dev *audio = func_to_audio(f); -+ -+ pr_debug("audio_disable\n"); -+ usb_ep_disable(audio->in_ep); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void audio_build_desc(struct audio_dev *audio) -+{ -+ u8 *sam_freq; -+ int rate; -+ -+ /* Set channel numbers */ -+ input_terminal_desc.bNrChannels = 2; -+ as_type_i_desc.bNrChannels = 2; -+ -+ /* Set sample rates */ -+ rate = SAMPLE_RATE; -+ sam_freq = as_type_i_desc.tSamFreq[0]; -+ memcpy(sam_freq, &rate, 3); -+} -+ -+/* audio function driver setup/binding */ -+static int -+audio_bind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct usb_composite_dev *cdev = c->cdev; -+ struct audio_dev *audio = func_to_audio(f); -+ int status; -+ struct usb_ep *ep; -+ struct usb_request *req; -+ int i; -+ -+ audio_build_desc(audio); -+ -+ /* allocate instance-specific interface IDs, and patch descriptors */ -+ status = usb_interface_id(c, f); -+ if (status < 0) -+ goto fail; -+ ac_interface_desc.bInterfaceNumber = status; -+ -+ status = usb_interface_id(c, f); -+ if (status < 0) -+ goto fail; -+ as_interface_alt_0_desc.bInterfaceNumber = status; -+ as_interface_alt_1_desc.bInterfaceNumber = status; -+ -+ status = -ENODEV; -+ -+ /* allocate our endpoint */ -+ ep = usb_ep_autoconfig(cdev->gadget, &fs_as_in_ep_desc); -+ if (!ep) -+ goto fail; -+ audio->in_ep = ep; -+ ep->driver_data = audio; /* claim */ -+ -+ if (gadget_is_dualspeed(c->cdev->gadget)) -+ hs_as_in_ep_desc.bEndpointAddress = -+ fs_as_in_ep_desc.bEndpointAddress; -+ -+ f->descriptors = fs_audio_desc; -+ f->hs_descriptors = hs_audio_desc; -+ -+ for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) { -+ req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE); -+ if (req) { -+ req->context = audio; -+ req->complete = audio_data_complete; -+ audio_req_put(audio, req); -+ } else -+ status = -ENOMEM; -+ } -+ -+fail: -+ return status; -+} -+ -+static void -+audio_unbind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct audio_dev *audio = func_to_audio(f); -+ struct usb_request *req; -+ -+ while ((req = audio_req_get(audio))) -+ audio_request_free(req, audio->in_ep); -+ -+ snd_card_free_when_closed(audio->card); -+ audio->card = NULL; -+ audio->pcm = NULL; -+ audio->substream = NULL; -+ audio->in_ep = NULL; -+} -+ -+static void audio_pcm_playback_start(struct audio_dev *audio) -+{ -+ audio->start_time = ktime_get(); -+ audio->frames_sent = 0; -+ audio_send(audio); -+} -+ -+static void audio_pcm_playback_stop(struct audio_dev *audio) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&audio->lock, flags); -+ audio->buffer_start = 0; -+ audio->buffer_end = 0; -+ audio->buffer_pos = 0; -+ spin_unlock_irqrestore(&audio->lock, flags); -+} -+ -+static int audio_pcm_open(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct audio_dev *audio = substream->private_data; -+ -+ runtime->private_data = audio; -+ runtime->hw = audio_hw_info; -+ snd_pcm_limit_hw_rates(runtime); -+ runtime->hw.channels_max = 2; -+ -+ audio->substream = substream; -+ return 0; -+} -+ -+static int audio_pcm_close(struct snd_pcm_substream *substream) -+{ -+ struct audio_dev *audio = substream->private_data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&audio->lock, flags); -+ audio->substream = NULL; -+ spin_unlock_irqrestore(&audio->lock, flags); -+ -+ return 0; -+} -+ -+static int audio_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ unsigned int channels = params_channels(params); -+ unsigned int rate = params_rate(params); -+ -+ if (rate != SAMPLE_RATE) -+ return -EINVAL; -+ if (channels != 2) -+ return -EINVAL; -+ -+ return snd_pcm_lib_alloc_vmalloc_buffer(substream, -+ params_buffer_bytes(params)); -+} -+ -+static int audio_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_lib_free_vmalloc_buffer(substream); -+} -+ -+static int audio_pcm_prepare(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct audio_dev *audio = runtime->private_data; -+ -+ audio->period = snd_pcm_lib_period_bytes(substream); -+ audio->period_offset = 0; -+ audio->buffer_start = runtime->dma_area; -+ audio->buffer_end = audio->buffer_start -+ + snd_pcm_lib_buffer_bytes(substream); -+ audio->buffer_pos = audio->buffer_start; -+ -+ return 0; -+} -+ -+static snd_pcm_uframes_t audio_pcm_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct audio_dev *audio = runtime->private_data; -+ ssize_t bytes = audio->buffer_pos - audio->buffer_start; -+ -+ /* return offset of next frame to fill in our buffer */ -+ return bytes_to_frames(runtime, bytes); -+} -+ -+static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream, -+ int cmd) -+{ -+ struct audio_dev *audio = substream->runtime->private_data; -+ int ret = 0; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ audio_pcm_playback_start(audio); -+ break; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ audio_pcm_playback_stop(audio); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static struct audio_dev _audio_dev = { -+ .func = { -+ .name = "audio_source", -+ .bind = audio_bind, -+ .unbind = audio_unbind, -+ .set_alt = audio_set_alt, -+ .setup = audio_setup, -+ .disable = audio_disable, -+ }, -+ .lock = __SPIN_LOCK_UNLOCKED(_audio_dev.lock), -+ .idle_reqs = LIST_HEAD_INIT(_audio_dev.idle_reqs), -+}; -+ -+static struct snd_pcm_ops audio_playback_ops = { -+ .open = audio_pcm_open, -+ .close = audio_pcm_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = audio_pcm_hw_params, -+ .hw_free = audio_pcm_hw_free, -+ .prepare = audio_pcm_prepare, -+ .trigger = audio_pcm_playback_trigger, -+ .pointer = audio_pcm_pointer, -+}; -+ -+int audio_source_bind_config(struct usb_configuration *c, -+ struct audio_source_config *config) -+{ -+ struct audio_dev *audio; -+ struct snd_card *card; -+ struct snd_pcm *pcm; -+ int err; -+ -+ config->card = -1; -+ config->device = -1; -+ -+ audio = &_audio_dev; -+ -+ err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, -+ THIS_MODULE, 0, &card); -+ if (err) -+ return err; -+ -+ snd_card_set_dev(card, &c->cdev->gadget->dev); -+ -+ err = snd_pcm_new(card, "USB audio source", 0, 1, 0, &pcm); -+ if (err) -+ goto pcm_fail; -+ pcm->private_data = audio; -+ pcm->info_flags = 0; -+ audio->pcm = pcm; -+ -+ strlcpy(pcm->name, "USB gadget audio", sizeof(pcm->name)); -+ -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &audio_playback_ops); -+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, -+ NULL, 0, 64 * 1024); -+ -+ strlcpy(card->driver, "audio_source", sizeof(card->driver)); -+ strlcpy(card->shortname, card->driver, sizeof(card->shortname)); -+ strlcpy(card->longname, "USB accessory audio source", -+ sizeof(card->longname)); -+ -+ err = snd_card_register(card); -+ if (err) -+ goto register_fail; -+ -+ err = usb_add_function(c, &audio->func); -+ if (err) -+ goto add_fail; -+ -+ config->card = pcm->card->number; -+ config->device = pcm->device; -+ audio->card = card; -+ return 0; -+ -+add_fail: -+register_fail: -+pcm_fail: -+ snd_card_free(audio->card); -+ return err; -+} -diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c -index f52cb1ae..7a86f350 100644 ---- a/drivers/usb/gadget/f_fs.c -+++ b/drivers/usb/gadget/f_fs.c -@@ -1519,7 +1519,12 @@ static int ffs_func_eps_enable(struct ffs_function *func) - spin_lock_irqsave(&func->ffs->eps_lock, flags); - do { - struct usb_endpoint_descriptor *ds; -- ds = ep->descs[ep->descs[1] ? 1 : 0]; -+ int desc_idx = ffs->gadget->speed == USB_SPEED_HIGH ? 1 : 0; -+ ds = ep->descs[desc_idx]; -+ if (!ds) { -+ ret = -EINVAL; -+ break; -+ } - - ep->ep->driver_data = ep; - ep->ep->desc = ds; -diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c -new file mode 100644 -index 00000000..1638977a ---- /dev/null -+++ b/drivers/usb/gadget/f_mtp.c -@@ -0,0 +1,1283 @@ -+/* -+ * Gadget Function Driver for MTP -+ * -+ * Copyright (C) 2010 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+/* #define DEBUG */ -+/* #define VERBOSE_DEBUG */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/poll.h> -+#include <linux/delay.h> -+#include <linux/wait.h> -+#include <linux/err.h> -+#include <linux/interrupt.h> -+ -+#include <linux/types.h> -+#include <linux/file.h> -+#include <linux/device.h> -+#include <linux/miscdevice.h> -+ -+#include <linux/usb.h> -+#include <linux/usb_usual.h> -+#include <linux/usb/ch9.h> -+#include <linux/usb/f_mtp.h> -+ -+#define MTP_BULK_BUFFER_SIZE 16384 -+#define INTR_BUFFER_SIZE 28 -+ -+/* String IDs */ -+#define INTERFACE_STRING_INDEX 0 -+ -+/* values for mtp_dev.state */ -+#define STATE_OFFLINE 0 /* initial state, disconnected */ -+#define STATE_READY 1 /* ready for userspace calls */ -+#define STATE_BUSY 2 /* processing userspace calls */ -+#define STATE_CANCELED 3 /* transaction canceled by host */ -+#define STATE_ERROR 4 /* error from completion routine */ -+ -+/* number of tx and rx requests to allocate */ -+#define TX_REQ_MAX 4 -+#define RX_REQ_MAX 2 -+#define INTR_REQ_MAX 5 -+ -+/* ID for Microsoft MTP OS String */ -+#define MTP_OS_STRING_ID 0xEE -+ -+/* MTP class reqeusts */ -+#define MTP_REQ_CANCEL 0x64 -+#define MTP_REQ_GET_EXT_EVENT_DATA 0x65 -+#define MTP_REQ_RESET 0x66 -+#define MTP_REQ_GET_DEVICE_STATUS 0x67 -+ -+/* constants for device status */ -+#define MTP_RESPONSE_OK 0x2001 -+#define MTP_RESPONSE_DEVICE_BUSY 0x2019 -+ -+static const char mtp_shortname[] = "mtp_usb"; -+ -+struct mtp_dev { -+ struct usb_function function; -+ struct usb_composite_dev *cdev; -+ spinlock_t lock; -+ -+ struct usb_ep *ep_in; -+ struct usb_ep *ep_out; -+ struct usb_ep *ep_intr; -+ -+ int state; -+ -+ /* synchronize access to our device file */ -+ atomic_t open_excl; -+ /* to enforce only one ioctl at a time */ -+ atomic_t ioctl_excl; -+ -+ struct list_head tx_idle; -+ struct list_head intr_idle; -+ -+ wait_queue_head_t read_wq; -+ wait_queue_head_t write_wq; -+ wait_queue_head_t intr_wq; -+ struct usb_request *rx_req[RX_REQ_MAX]; -+ int rx_done; -+ -+ /* for processing MTP_SEND_FILE, MTP_RECEIVE_FILE and -+ * MTP_SEND_FILE_WITH_HEADER ioctls on a work queue -+ */ -+ struct workqueue_struct *wq; -+ struct work_struct send_file_work; -+ struct work_struct receive_file_work; -+ struct file *xfer_file; -+ loff_t xfer_file_offset; -+ int64_t xfer_file_length; -+ unsigned xfer_send_header; -+ uint16_t xfer_command; -+ uint32_t xfer_transaction_id; -+ int xfer_result; -+}; -+ -+static struct usb_interface_descriptor mtp_interface_desc = { -+ .bLength = USB_DT_INTERFACE_SIZE, -+ .bDescriptorType = USB_DT_INTERFACE, -+ .bInterfaceNumber = 0, -+ .bNumEndpoints = 3, -+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, -+ .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, -+ .bInterfaceProtocol = 0, -+}; -+ -+static struct usb_interface_descriptor ptp_interface_desc = { -+ .bLength = USB_DT_INTERFACE_SIZE, -+ .bDescriptorType = USB_DT_INTERFACE, -+ .bInterfaceNumber = 0, -+ .bNumEndpoints = 3, -+ .bInterfaceClass = USB_CLASS_STILL_IMAGE, -+ .bInterfaceSubClass = 1, -+ .bInterfaceProtocol = 1, -+}; -+ -+static struct usb_endpoint_descriptor mtp_highspeed_in_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = __constant_cpu_to_le16(512), -+}; -+ -+static struct usb_endpoint_descriptor mtp_highspeed_out_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_OUT, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = __constant_cpu_to_le16(512), -+}; -+ -+static struct usb_endpoint_descriptor mtp_fullspeed_in_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+}; -+ -+static struct usb_endpoint_descriptor mtp_fullspeed_out_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_OUT, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+}; -+ -+static struct usb_endpoint_descriptor mtp_intr_desc = { -+ .bLength = USB_DT_ENDPOINT_SIZE, -+ .bDescriptorType = USB_DT_ENDPOINT, -+ .bEndpointAddress = USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_INT, -+ .wMaxPacketSize = __constant_cpu_to_le16(INTR_BUFFER_SIZE), -+ .bInterval = 6, -+}; -+ -+static struct usb_descriptor_header *fs_mtp_descs[] = { -+ (struct usb_descriptor_header *) &mtp_interface_desc, -+ (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, -+ (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, -+ (struct usb_descriptor_header *) &mtp_intr_desc, -+ NULL, -+}; -+ -+static struct usb_descriptor_header *hs_mtp_descs[] = { -+ (struct usb_descriptor_header *) &mtp_interface_desc, -+ (struct usb_descriptor_header *) &mtp_highspeed_in_desc, -+ (struct usb_descriptor_header *) &mtp_highspeed_out_desc, -+ (struct usb_descriptor_header *) &mtp_intr_desc, -+ NULL, -+}; -+ -+static struct usb_descriptor_header *fs_ptp_descs[] = { -+ (struct usb_descriptor_header *) &ptp_interface_desc, -+ (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, -+ (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, -+ (struct usb_descriptor_header *) &mtp_intr_desc, -+ NULL, -+}; -+ -+static struct usb_descriptor_header *hs_ptp_descs[] = { -+ (struct usb_descriptor_header *) &ptp_interface_desc, -+ (struct usb_descriptor_header *) &mtp_highspeed_in_desc, -+ (struct usb_descriptor_header *) &mtp_highspeed_out_desc, -+ (struct usb_descriptor_header *) &mtp_intr_desc, -+ NULL, -+}; -+ -+static struct usb_string mtp_string_defs[] = { -+ /* Naming interface "MTP" so libmtp will recognize us */ -+ [INTERFACE_STRING_INDEX].s = "MTP", -+ { }, /* end of list */ -+}; -+ -+static struct usb_gadget_strings mtp_string_table = { -+ .language = 0x0409, /* en-US */ -+ .strings = mtp_string_defs, -+}; -+ -+static struct usb_gadget_strings *mtp_strings[] = { -+ &mtp_string_table, -+ NULL, -+}; -+ -+/* Microsoft MTP OS String */ -+static u8 mtp_os_string[] = { -+ 18, /* sizeof(mtp_os_string) */ -+ USB_DT_STRING, -+ /* Signature field: "MSFT100" */ -+ 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, -+ /* vendor code */ -+ 1, -+ /* padding */ -+ 0 -+}; -+ -+/* Microsoft Extended Configuration Descriptor Header Section */ -+struct mtp_ext_config_desc_header { -+ __le32 dwLength; -+ __u16 bcdVersion; -+ __le16 wIndex; -+ __u8 bCount; -+ __u8 reserved[7]; -+}; -+ -+/* Microsoft Extended Configuration Descriptor Function Section */ -+struct mtp_ext_config_desc_function { -+ __u8 bFirstInterfaceNumber; -+ __u8 bInterfaceCount; -+ __u8 compatibleID[8]; -+ __u8 subCompatibleID[8]; -+ __u8 reserved[6]; -+}; -+ -+/* MTP Extended Configuration Descriptor */ -+struct { -+ struct mtp_ext_config_desc_header header; -+ struct mtp_ext_config_desc_function function; -+} mtp_ext_config_desc = { -+ .header = { -+ .dwLength = __constant_cpu_to_le32(sizeof(mtp_ext_config_desc)), -+ .bcdVersion = __constant_cpu_to_le16(0x0100), -+ .wIndex = __constant_cpu_to_le16(4), -+ .bCount = __constant_cpu_to_le16(1), -+ }, -+ .function = { -+ .bFirstInterfaceNumber = 0, -+ .bInterfaceCount = 1, -+ .compatibleID = { 'M', 'T', 'P' }, -+ }, -+}; -+ -+struct mtp_device_status { -+ __le16 wLength; -+ __le16 wCode; -+}; -+ -+/* temporary variable used between mtp_open() and mtp_gadget_bind() */ -+static struct mtp_dev *_mtp_dev; -+ -+static inline struct mtp_dev *func_to_mtp(struct usb_function *f) -+{ -+ return container_of(f, struct mtp_dev, function); -+} -+ -+static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) -+{ -+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); -+ if (!req) -+ return NULL; -+ -+ /* now allocate buffers for the requests */ -+ req->buf = kmalloc(buffer_size, GFP_KERNEL); -+ if (!req->buf) { -+ usb_ep_free_request(ep, req); -+ return NULL; -+ } -+ -+ return req; -+} -+ -+static void mtp_request_free(struct usb_request *req, struct usb_ep *ep) -+{ -+ if (req) { -+ kfree(req->buf); -+ usb_ep_free_request(ep, req); -+ } -+} -+ -+static inline int mtp_lock(atomic_t *excl) -+{ -+ if (atomic_inc_return(excl) == 1) { -+ return 0; -+ } else { -+ atomic_dec(excl); -+ return -1; -+ } -+} -+ -+static inline void mtp_unlock(atomic_t *excl) -+{ -+ atomic_dec(excl); -+} -+ -+/* add a request to the tail of a list */ -+static void mtp_req_put(struct mtp_dev *dev, struct list_head *head, -+ struct usb_request *req) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ list_add_tail(&req->list, head); -+ spin_unlock_irqrestore(&dev->lock, flags); -+} -+ -+/* remove a request from the head of a list */ -+static struct usb_request -+*mtp_req_get(struct mtp_dev *dev, struct list_head *head) -+{ -+ unsigned long flags; -+ struct usb_request *req; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ if (list_empty(head)) { -+ req = 0; -+ } else { -+ req = list_first_entry(head, struct usb_request, list); -+ list_del(&req->list); -+ } -+ spin_unlock_irqrestore(&dev->lock, flags); -+ return req; -+} -+ -+static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct mtp_dev *dev = _mtp_dev; -+ -+ if (req->status != 0) -+ dev->state = STATE_ERROR; -+ -+ mtp_req_put(dev, &dev->tx_idle, req); -+ -+ wake_up(&dev->write_wq); -+} -+ -+static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct mtp_dev *dev = _mtp_dev; -+ -+ dev->rx_done = 1; -+ if (req->status != 0) -+ dev->state = STATE_ERROR; -+ -+ wake_up(&dev->read_wq); -+} -+ -+static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct mtp_dev *dev = _mtp_dev; -+ -+ if (req->status != 0) -+ dev->state = STATE_ERROR; -+ -+ mtp_req_put(dev, &dev->intr_idle, req); -+ -+ wake_up(&dev->intr_wq); -+} -+ -+static int mtp_create_bulk_endpoints(struct mtp_dev *dev, -+ struct usb_endpoint_descriptor *in_desc, -+ struct usb_endpoint_descriptor *out_desc, -+ struct usb_endpoint_descriptor *intr_desc) -+{ -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct usb_request *req; -+ struct usb_ep *ep; -+ int i; -+ -+ DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); -+ -+ ep = usb_ep_autoconfig(cdev->gadget, in_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_in = ep; -+ -+ ep = usb_ep_autoconfig(cdev->gadget, out_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_out = ep; -+ -+ ep = usb_ep_autoconfig(cdev->gadget, out_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_out = ep; -+ -+ ep = usb_ep_autoconfig(cdev->gadget, intr_desc); -+ if (!ep) { -+ DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n"); -+ return -ENODEV; -+ } -+ DBG(cdev, "usb_ep_autoconfig for mtp ep_intr got %s\n", ep->name); -+ ep->driver_data = dev; /* claim the endpoint */ -+ dev->ep_intr = ep; -+ -+ /* now allocate requests for our endpoints */ -+ for (i = 0; i < TX_REQ_MAX; i++) { -+ req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE); -+ if (!req) -+ goto fail; -+ req->complete = mtp_complete_in; -+ mtp_req_put(dev, &dev->tx_idle, req); -+ } -+ for (i = 0; i < RX_REQ_MAX; i++) { -+ req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE); -+ if (!req) -+ goto fail; -+ req->complete = mtp_complete_out; -+ dev->rx_req[i] = req; -+ } -+ for (i = 0; i < INTR_REQ_MAX; i++) { -+ req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE); -+ if (!req) -+ goto fail; -+ req->complete = mtp_complete_intr; -+ mtp_req_put(dev, &dev->intr_idle, req); -+ } -+ -+ return 0; -+ -+fail: -+ printk(KERN_ERR "mtp_bind() could not allocate requests\n"); -+ return -1; -+} -+ -+static ssize_t mtp_read(struct file *fp, char __user *buf, -+ size_t count, loff_t *pos) -+{ -+ struct mtp_dev *dev = fp->private_data; -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct usb_request *req; -+ int r = count, xfer; -+ int ret = 0; -+ -+ DBG(cdev, "mtp_read(%d)\n", count); -+ -+ if (count > MTP_BULK_BUFFER_SIZE) -+ return -EINVAL; -+ -+ /* we will block until we're online */ -+ DBG(cdev, "mtp_read: waiting for online state\n"); -+ ret = wait_event_interruptible(dev->read_wq, -+ dev->state != STATE_OFFLINE); -+ if (ret < 0) { -+ r = ret; -+ goto done; -+ } -+ spin_lock_irq(&dev->lock); -+ if (dev->state == STATE_CANCELED) { -+ /* report cancelation to userspace */ -+ dev->state = STATE_READY; -+ spin_unlock_irq(&dev->lock); -+ return -ECANCELED; -+ } -+ dev->state = STATE_BUSY; -+ spin_unlock_irq(&dev->lock); -+ -+requeue_req: -+ /* queue a request */ -+ req = dev->rx_req[0]; -+ req->length = count; -+ dev->rx_done = 0; -+ ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); -+ if (ret < 0) { -+ r = -EIO; -+ goto done; -+ } else { -+ DBG(cdev, "rx %p queue\n", req); -+ } -+ -+ /* wait for a request to complete */ -+ ret = wait_event_interruptible(dev->read_wq, dev->rx_done); -+ if (ret < 0) { -+ r = ret; -+ usb_ep_dequeue(dev->ep_out, req); -+ goto done; -+ } -+ if (dev->state == STATE_BUSY) { -+ /* If we got a 0-len packet, throw it back and try again. */ -+ if (req->actual == 0) -+ goto requeue_req; -+ -+ DBG(cdev, "rx %p %d\n", req, req->actual); -+ xfer = (req->actual < count) ? req->actual : count; -+ r = xfer; -+ if (copy_to_user(buf, req->buf, xfer)) -+ r = -EFAULT; -+ } else -+ r = -EIO; -+ -+done: -+ spin_lock_irq(&dev->lock); -+ if (dev->state == STATE_CANCELED) -+ r = -ECANCELED; -+ else if (dev->state != STATE_OFFLINE) -+ dev->state = STATE_READY; -+ spin_unlock_irq(&dev->lock); -+ -+ DBG(cdev, "mtp_read returning %d\n", r); -+ return r; -+} -+ -+static ssize_t mtp_write(struct file *fp, const char __user *buf, -+ size_t count, loff_t *pos) -+{ -+ struct mtp_dev *dev = fp->private_data; -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct usb_request *req = 0; -+ int r = count, xfer; -+ int sendZLP = 0; -+ int ret; -+ -+ DBG(cdev, "mtp_write(%d)\n", count); -+ -+ spin_lock_irq(&dev->lock); -+ if (dev->state == STATE_CANCELED) { -+ /* report cancelation to userspace */ -+ dev->state = STATE_READY; -+ spin_unlock_irq(&dev->lock); -+ return -ECANCELED; -+ } -+ if (dev->state == STATE_OFFLINE) { -+ spin_unlock_irq(&dev->lock); -+ return -ENODEV; -+ } -+ dev->state = STATE_BUSY; -+ spin_unlock_irq(&dev->lock); -+ -+ /* we need to send a zero length packet to signal the end of transfer -+ * if the transfer size is aligned to a packet boundary. -+ */ -+ if ((count & (dev->ep_in->maxpacket - 1)) == 0) -+ sendZLP = 1; -+ -+ while (count > 0 || sendZLP) { -+ /* so we exit after sending ZLP */ -+ if (count == 0) -+ sendZLP = 0; -+ -+ if (dev->state != STATE_BUSY) { -+ DBG(cdev, "mtp_write dev->error\n"); -+ r = -EIO; -+ break; -+ } -+ -+ /* get an idle tx request to use */ -+ req = 0; -+ ret = wait_event_interruptible(dev->write_wq, -+ ((req = mtp_req_get(dev, &dev->tx_idle)) -+ || dev->state != STATE_BUSY)); -+ if (!req) { -+ r = ret; -+ break; -+ } -+ -+ if (count > MTP_BULK_BUFFER_SIZE) -+ xfer = MTP_BULK_BUFFER_SIZE; -+ else -+ xfer = count; -+ if (xfer && copy_from_user(req->buf, buf, xfer)) { -+ r = -EFAULT; -+ break; -+ } -+ -+ req->length = xfer; -+ ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); -+ if (ret < 0) { -+ DBG(cdev, "mtp_write: xfer error %d\n", ret); -+ r = -EIO; -+ break; -+ } -+ -+ buf += xfer; -+ count -= xfer; -+ -+ /* zero this so we don't try to free it on error exit */ -+ req = 0; -+ } -+ -+ if (req) -+ mtp_req_put(dev, &dev->tx_idle, req); -+ -+ spin_lock_irq(&dev->lock); -+ if (dev->state == STATE_CANCELED) -+ r = -ECANCELED; -+ else if (dev->state != STATE_OFFLINE) -+ dev->state = STATE_READY; -+ spin_unlock_irq(&dev->lock); -+ -+ DBG(cdev, "mtp_write returning %d\n", r); -+ return r; -+} -+ -+/* read from a local file and write to USB */ -+static void send_file_work(struct work_struct *data) -+{ -+ struct mtp_dev *dev = container_of(data, struct mtp_dev, -+ send_file_work); -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct usb_request *req = 0; -+ struct mtp_data_header *header; -+ struct file *filp; -+ loff_t offset; -+ int64_t count; -+ int xfer, ret, hdr_size; -+ int r = 0; -+ int sendZLP = 0; -+ -+ /* read our parameters */ -+ smp_rmb(); -+ filp = dev->xfer_file; -+ offset = dev->xfer_file_offset; -+ count = dev->xfer_file_length; -+ -+ DBG(cdev, "send_file_work(%lld %lld)\n", offset, count); -+ -+ if (dev->xfer_send_header) { -+ hdr_size = sizeof(struct mtp_data_header); -+ count += hdr_size; -+ } else { -+ hdr_size = 0; -+ } -+ -+ /* we need to send a zero length packet to signal the end of transfer -+ * if the transfer size is aligned to a packet boundary. -+ */ -+ if ((count & (dev->ep_in->maxpacket - 1)) == 0) -+ sendZLP = 1; -+ -+ while (count > 0 || sendZLP) { -+ /* so we exit after sending ZLP */ -+ if (count == 0) -+ sendZLP = 0; -+ -+ /* get an idle tx request to use */ -+ req = 0; -+ ret = wait_event_interruptible(dev->write_wq, -+ (req = mtp_req_get(dev, &dev->tx_idle)) -+ || dev->state != STATE_BUSY); -+ if (dev->state == STATE_CANCELED) { -+ r = -ECANCELED; -+ break; -+ } -+ if (!req) { -+ r = ret; -+ break; -+ } -+ -+ if (count > MTP_BULK_BUFFER_SIZE) -+ xfer = MTP_BULK_BUFFER_SIZE; -+ else -+ xfer = count; -+ -+ if (hdr_size) { -+ /* prepend MTP data header */ -+ header = (struct mtp_data_header *)req->buf; -+ header->length = __cpu_to_le32(count); -+ header->type = __cpu_to_le16(2); /* data packet */ -+ header->command = __cpu_to_le16(dev->xfer_command); -+ header->transaction_id = -+ __cpu_to_le32(dev->xfer_transaction_id); -+ } -+ -+ ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size, -+ &offset); -+ if (ret < 0) { -+ r = ret; -+ break; -+ } -+ xfer = ret + hdr_size; -+ hdr_size = 0; -+ -+ req->length = xfer; -+ ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); -+ if (ret < 0) { -+ DBG(cdev, "send_file_work: xfer error %d\n", ret); -+ dev->state = STATE_ERROR; -+ r = -EIO; -+ break; -+ } -+ -+ count -= xfer; -+ -+ /* zero this so we don't try to free it on error exit */ -+ req = 0; -+ } -+ -+ if (req) -+ mtp_req_put(dev, &dev->tx_idle, req); -+ -+ DBG(cdev, "send_file_work returning %d\n", r); -+ /* write the result */ -+ dev->xfer_result = r; -+ smp_wmb(); -+} -+ -+/* read from USB and write to a local file */ -+static void receive_file_work(struct work_struct *data) -+{ -+ struct mtp_dev *dev = container_of(data, struct mtp_dev, -+ receive_file_work); -+ struct usb_composite_dev *cdev = dev->cdev; -+ struct usb_request *read_req = NULL, *write_req = NULL; -+ struct file *filp; -+ loff_t offset; -+ int64_t count; -+ int ret, cur_buf = 0; -+ int r = 0; -+ -+ /* read our parameters */ -+ smp_rmb(); -+ filp = dev->xfer_file; -+ offset = dev->xfer_file_offset; -+ count = dev->xfer_file_length; -+ -+ DBG(cdev, "receive_file_work(%lld)\n", count); -+ -+ while (count > 0 || write_req) { -+ if (count > 0) { -+ /* queue a request */ -+ read_req = dev->rx_req[cur_buf]; -+ cur_buf = (cur_buf + 1) % RX_REQ_MAX; -+ -+ read_req->length = (count > MTP_BULK_BUFFER_SIZE -+ ? MTP_BULK_BUFFER_SIZE : count); -+ dev->rx_done = 0; -+ ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); -+ if (ret < 0) { -+ r = -EIO; -+ dev->state = STATE_ERROR; -+ break; -+ } -+ } -+ -+ if (write_req) { -+ DBG(cdev, "rx %p %d\n", write_req, write_req->actual); -+ ret = vfs_write(filp, write_req->buf, write_req->actual, -+ &offset); -+ DBG(cdev, "vfs_write %d\n", ret); -+ if (ret != write_req->actual) { -+ r = -EIO; -+ dev->state = STATE_ERROR; -+ break; -+ } -+ write_req = NULL; -+ } -+ -+ if (read_req) { -+ /* wait for our last read to complete */ -+ ret = wait_event_interruptible(dev->read_wq, -+ dev->rx_done || dev->state != STATE_BUSY); -+ if (dev->state == STATE_CANCELED) { -+ r = -ECANCELED; -+ if (!dev->rx_done) -+ usb_ep_dequeue(dev->ep_out, read_req); -+ break; -+ } -+ /* if xfer_file_length is 0xFFFFFFFF, then we read until -+ * we get a zero length packet -+ */ -+ if (count != 0xFFFFFFFF) -+ count -= read_req->actual; -+ if (read_req->actual < read_req->length) { -+ /* -+ * short packet is used to signal EOF for -+ * sizes > 4 gig -+ */ -+ DBG(cdev, "got short packet\n"); -+ count = 0; -+ } -+ -+ write_req = read_req; -+ read_req = NULL; -+ } -+ } -+ -+ DBG(cdev, "receive_file_work returning %d\n", r); -+ /* write the result */ -+ dev->xfer_result = r; -+ smp_wmb(); -+} -+ -+static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) -+{ -+ struct usb_request *req = NULL; -+ int ret; -+ int length = event->length; -+ -+ DBG(dev->cdev, "mtp_send_event(%d)\n", event->length); -+ -+ if (length < 0 || length > INTR_BUFFER_SIZE) -+ return -EINVAL; -+ if (dev->state == STATE_OFFLINE) -+ return -ENODEV; -+ -+ ret = wait_event_interruptible_timeout(dev->intr_wq, -+ (req = mtp_req_get(dev, &dev->intr_idle)), -+ msecs_to_jiffies(1000)); -+ if (!req) -+ return -ETIME; -+ -+ if (copy_from_user(req->buf, (void __user *)event->data, length)) { -+ mtp_req_put(dev, &dev->intr_idle, req); -+ return -EFAULT; -+ } -+ req->length = length; -+ ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL); -+ if (ret) -+ mtp_req_put(dev, &dev->intr_idle, req); -+ -+ return ret; -+} -+ -+static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) -+{ -+ struct mtp_dev *dev = fp->private_data; -+ struct file *filp = NULL; -+ int ret = -EINVAL; -+ -+ if (mtp_lock(&dev->ioctl_excl)) -+ return -EBUSY; -+ -+ switch (code) { -+ case MTP_SEND_FILE: -+ case MTP_RECEIVE_FILE: -+ case MTP_SEND_FILE_WITH_HEADER: -+ { -+ struct mtp_file_range mfr; -+ struct work_struct *work; -+ -+ spin_lock_irq(&dev->lock); -+ if (dev->state == STATE_CANCELED) { -+ /* report cancelation to userspace */ -+ dev->state = STATE_READY; -+ spin_unlock_irq(&dev->lock); -+ ret = -ECANCELED; -+ goto out; -+ } -+ if (dev->state == STATE_OFFLINE) { -+ spin_unlock_irq(&dev->lock); -+ ret = -ENODEV; -+ goto out; -+ } -+ dev->state = STATE_BUSY; -+ spin_unlock_irq(&dev->lock); -+ -+ if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { -+ ret = -EFAULT; -+ goto fail; -+ } -+ /* hold a reference to the file while we are working with it */ -+ filp = fget(mfr.fd); -+ if (!filp) { -+ ret = -EBADF; -+ goto fail; -+ } -+ -+ /* write the parameters */ -+ dev->xfer_file = filp; -+ dev->xfer_file_offset = mfr.offset; -+ dev->xfer_file_length = mfr.length; -+ smp_wmb(); -+ -+ if (code == MTP_SEND_FILE_WITH_HEADER) { -+ work = &dev->send_file_work; -+ dev->xfer_send_header = 1; -+ dev->xfer_command = mfr.command; -+ dev->xfer_transaction_id = mfr.transaction_id; -+ } else if (code == MTP_SEND_FILE) { -+ work = &dev->send_file_work; -+ dev->xfer_send_header = 0; -+ } else { -+ work = &dev->receive_file_work; -+ } -+ -+ /* We do the file transfer on a work queue so it will run -+ * in kernel context, which is necessary for vfs_read and -+ * vfs_write to use our buffers in the kernel address space. -+ */ -+ queue_work(dev->wq, work); -+ /* wait for operation to complete */ -+ flush_workqueue(dev->wq); -+ fput(filp); -+ -+ /* read the result */ -+ smp_rmb(); -+ ret = dev->xfer_result; -+ break; -+ } -+ case MTP_SEND_EVENT: -+ { -+ struct mtp_event event; -+ /* return here so we don't change dev->state below, -+ * which would interfere with bulk transfer state. -+ */ -+ if (copy_from_user(&event, (void __user *)value, sizeof(event))) -+ ret = -EFAULT; -+ else -+ ret = mtp_send_event(dev, &event); -+ goto out; -+ } -+ } -+ -+fail: -+ spin_lock_irq(&dev->lock); -+ if (dev->state == STATE_CANCELED) -+ ret = -ECANCELED; -+ else if (dev->state != STATE_OFFLINE) -+ dev->state = STATE_READY; -+ spin_unlock_irq(&dev->lock); -+out: -+ mtp_unlock(&dev->ioctl_excl); -+ DBG(dev->cdev, "ioctl returning %d\n", ret); -+ return ret; -+} -+ -+static int mtp_open(struct inode *ip, struct file *fp) -+{ -+ printk(KERN_INFO "mtp_open\n"); -+ if (mtp_lock(&_mtp_dev->open_excl)) -+ return -EBUSY; -+ -+ /* clear any error condition */ -+ if (_mtp_dev->state != STATE_OFFLINE) -+ _mtp_dev->state = STATE_READY; -+ -+ fp->private_data = _mtp_dev; -+ return 0; -+} -+ -+static int mtp_release(struct inode *ip, struct file *fp) -+{ -+ printk(KERN_INFO "mtp_release\n"); -+ -+ mtp_unlock(&_mtp_dev->open_excl); -+ return 0; -+} -+ -+/* file operations for /dev/mtp_usb */ -+static const struct file_operations mtp_fops = { -+ .owner = THIS_MODULE, -+ .read = mtp_read, -+ .write = mtp_write, -+ .unlocked_ioctl = mtp_ioctl, -+ .open = mtp_open, -+ .release = mtp_release, -+}; -+ -+static struct miscdevice mtp_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = mtp_shortname, -+ .fops = &mtp_fops, -+}; -+ -+static int mtp_ctrlrequest(struct usb_composite_dev *cdev, -+ const struct usb_ctrlrequest *ctrl) -+{ -+ struct mtp_dev *dev = _mtp_dev; -+ int value = -EOPNOTSUPP; -+ u16 w_index = le16_to_cpu(ctrl->wIndex); -+ u16 w_value = le16_to_cpu(ctrl->wValue); -+ u16 w_length = le16_to_cpu(ctrl->wLength); -+ unsigned long flags; -+ -+ VDBG(cdev, "mtp_ctrlrequest " -+ "%02x.%02x v%04x i%04x l%u\n", -+ ctrl->bRequestType, ctrl->bRequest, -+ w_value, w_index, w_length); -+ -+ /* Handle MTP OS string */ -+ if (ctrl->bRequestType == -+ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) -+ && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR -+ && (w_value >> 8) == USB_DT_STRING -+ && (w_value & 0xFF) == MTP_OS_STRING_ID) { -+ value = (w_length < sizeof(mtp_os_string) -+ ? w_length : sizeof(mtp_os_string)); -+ memcpy(cdev->req->buf, mtp_os_string, value); -+ } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { -+ /* Handle MTP OS descriptor */ -+ DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n", -+ ctrl->bRequest, w_index, w_value, w_length); -+ -+ if (ctrl->bRequest == 1 -+ && (ctrl->bRequestType & USB_DIR_IN) -+ && (w_index == 4 || w_index == 5)) { -+ value = (w_length < sizeof(mtp_ext_config_desc) ? -+ w_length : sizeof(mtp_ext_config_desc)); -+ memcpy(cdev->req->buf, &mtp_ext_config_desc, value); -+ } -+ } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { -+ DBG(cdev, "class request: %d index: %d value: %d length: %d\n", -+ ctrl->bRequest, w_index, w_value, w_length); -+ -+ if (ctrl->bRequest == MTP_REQ_CANCEL && w_index == 0 -+ && w_value == 0) { -+ DBG(cdev, "MTP_REQ_CANCEL\n"); -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ if (dev->state == STATE_BUSY) { -+ dev->state = STATE_CANCELED; -+ wake_up(&dev->read_wq); -+ wake_up(&dev->write_wq); -+ } -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ /* We need to queue a request to read the remaining -+ * bytes, but we don't actually need to look at -+ * the contents. -+ */ -+ value = w_length; -+ } else if (ctrl->bRequest == MTP_REQ_GET_DEVICE_STATUS -+ && w_index == 0 && w_value == 0) { -+ struct mtp_device_status *status = cdev->req->buf; -+ status->wLength = -+ __constant_cpu_to_le16(sizeof(*status)); -+ -+ DBG(cdev, "MTP_REQ_GET_DEVICE_STATUS\n"); -+ spin_lock_irqsave(&dev->lock, flags); -+ /* device status is "busy" until we report -+ * the cancelation to userspace -+ */ -+ if (dev->state == STATE_CANCELED) -+ status->wCode = -+ __cpu_to_le16(MTP_RESPONSE_DEVICE_BUSY); -+ else -+ status->wCode = -+ __cpu_to_le16(MTP_RESPONSE_OK); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ value = sizeof(*status); -+ } -+ } -+ -+ /* respond with data transfer or status phase? */ -+ if (value >= 0) { -+ int rc; -+ cdev->req->zero = value < w_length; -+ cdev->req->length = value; -+ rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); -+ if (rc < 0) -+ ERROR(cdev, "%s: response queue error\n", __func__); -+ } -+ return value; -+} -+ -+static int -+mtp_function_bind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct usb_composite_dev *cdev = c->cdev; -+ struct mtp_dev *dev = func_to_mtp(f); -+ int id; -+ int ret; -+ -+ dev->cdev = cdev; -+ DBG(cdev, "mtp_function_bind dev: %p\n", dev); -+ -+ /* allocate interface ID(s) */ -+ id = usb_interface_id(c, f); -+ if (id < 0) -+ return id; -+ mtp_interface_desc.bInterfaceNumber = id; -+ -+ /* allocate endpoints */ -+ ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc, -+ &mtp_fullspeed_out_desc, &mtp_intr_desc); -+ if (ret) -+ return ret; -+ -+ /* support high speed hardware */ -+ if (gadget_is_dualspeed(c->cdev->gadget)) { -+ mtp_highspeed_in_desc.bEndpointAddress = -+ mtp_fullspeed_in_desc.bEndpointAddress; -+ mtp_highspeed_out_desc.bEndpointAddress = -+ mtp_fullspeed_out_desc.bEndpointAddress; -+ } -+ -+ DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", -+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", -+ f->name, dev->ep_in->name, dev->ep_out->name); -+ return 0; -+} -+ -+static void -+mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) -+{ -+ struct mtp_dev *dev = func_to_mtp(f); -+ struct usb_request *req; -+ int i; -+ -+ while ((req = mtp_req_get(dev, &dev->tx_idle))) -+ mtp_request_free(req, dev->ep_in); -+ for (i = 0; i < RX_REQ_MAX; i++) -+ mtp_request_free(dev->rx_req[i], dev->ep_out); -+ while ((req = mtp_req_get(dev, &dev->intr_idle))) -+ mtp_request_free(req, dev->ep_intr); -+ dev->state = STATE_OFFLINE; -+} -+ -+static int mtp_function_set_alt(struct usb_function *f, -+ unsigned intf, unsigned alt) -+{ -+ struct mtp_dev *dev = func_to_mtp(f); -+ struct usb_composite_dev *cdev = f->config->cdev; -+ int ret; -+ -+ DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt); -+ -+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); -+ if (ret) -+ return ret; -+ -+ ret = usb_ep_enable(dev->ep_in); -+ if (ret) -+ return ret; -+ -+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); -+ if (ret) -+ return ret; -+ -+ ret = usb_ep_enable(dev->ep_out); -+ if (ret) { -+ usb_ep_disable(dev->ep_in); -+ return ret; -+ } -+ -+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_intr); -+ if (ret) -+ return ret; -+ -+ ret = usb_ep_enable(dev->ep_intr); -+ if (ret) { -+ usb_ep_disable(dev->ep_out); -+ usb_ep_disable(dev->ep_in); -+ return ret; -+ } -+ dev->state = STATE_READY; -+ -+ /* readers may be blocked waiting for us to go online */ -+ wake_up(&dev->read_wq); -+ return 0; -+} -+ -+static void mtp_function_disable(struct usb_function *f) -+{ -+ struct mtp_dev *dev = func_to_mtp(f); -+ struct usb_composite_dev *cdev = dev->cdev; -+ -+ DBG(cdev, "mtp_function_disable\n"); -+ dev->state = STATE_OFFLINE; -+ usb_ep_disable(dev->ep_in); -+ usb_ep_disable(dev->ep_out); -+ usb_ep_disable(dev->ep_intr); -+ -+ /* readers may be blocked waiting for us to go online */ -+ wake_up(&dev->read_wq); -+ -+ VDBG(cdev, "%s disabled\n", dev->function.name); -+} -+ -+static int mtp_bind_config(struct usb_configuration *c, bool ptp_config) -+{ -+ struct mtp_dev *dev = _mtp_dev; -+ int ret = 0; -+ -+ printk(KERN_INFO "mtp_bind_config\n"); -+ -+ /* allocate a string ID for our interface */ -+ if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) { -+ ret = usb_string_id(c->cdev); -+ if (ret < 0) -+ return ret; -+ mtp_string_defs[INTERFACE_STRING_INDEX].id = ret; -+ mtp_interface_desc.iInterface = ret; -+ } -+ -+ dev->cdev = c->cdev; -+ dev->function.name = "mtp"; -+ dev->function.strings = mtp_strings; -+ if (ptp_config) { -+ dev->function.descriptors = fs_ptp_descs; -+ dev->function.hs_descriptors = hs_ptp_descs; -+ } else { -+ dev->function.descriptors = fs_mtp_descs; -+ dev->function.hs_descriptors = hs_mtp_descs; -+ } -+ dev->function.bind = mtp_function_bind; -+ dev->function.unbind = mtp_function_unbind; -+ dev->function.set_alt = mtp_function_set_alt; -+ dev->function.disable = mtp_function_disable; -+ -+ return usb_add_function(c, &dev->function); -+} -+ -+static int mtp_setup(void) -+{ -+ struct mtp_dev *dev; -+ int ret; -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ spin_lock_init(&dev->lock); -+ init_waitqueue_head(&dev->read_wq); -+ init_waitqueue_head(&dev->write_wq); -+ init_waitqueue_head(&dev->intr_wq); -+ atomic_set(&dev->open_excl, 0); -+ atomic_set(&dev->ioctl_excl, 0); -+ INIT_LIST_HEAD(&dev->tx_idle); -+ INIT_LIST_HEAD(&dev->intr_idle); -+ -+ dev->wq = create_singlethread_workqueue("f_mtp"); -+ if (!dev->wq) { -+ ret = -ENOMEM; -+ goto err1; -+ } -+ INIT_WORK(&dev->send_file_work, send_file_work); -+ INIT_WORK(&dev->receive_file_work, receive_file_work); -+ -+ _mtp_dev = dev; -+ -+ ret = misc_register(&mtp_device); -+ if (ret) -+ goto err2; -+ -+ return 0; -+ -+err2: -+ destroy_workqueue(dev->wq); -+err1: -+ _mtp_dev = NULL; -+ kfree(dev); -+ printk(KERN_ERR "mtp gadget driver failed to initialize\n"); -+ return ret; -+} -+ -+static void mtp_cleanup(void) -+{ -+ struct mtp_dev *dev = _mtp_dev; -+ -+ if (!dev) -+ return; -+ -+ misc_deregister(&mtp_device); -+ destroy_workqueue(dev->wq); -+ _mtp_dev = NULL; -+ kfree(dev); -+} -diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c -index 345f8388..9d26ef09 100644 ---- a/drivers/usb/gadget/f_rndis.c -+++ b/drivers/usb/gadget/f_rndis.c -@@ -71,6 +71,8 @@ struct f_rndis { - struct gether port; - u8 ctrl_id, data_id; - u8 ethaddr[ETH_ALEN]; -+ u32 vendorID; -+ const char *manufacturer; - int config; - - struct usb_ep *notify; -@@ -768,12 +770,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); - rndis_set_host_mac(rndis->config, rndis->ethaddr); - --#if 0 --// FIXME -- if (rndis_set_param_vendor(rndis->config, vendorID, -- manufacturer)) -- goto fail0; --#endif -+ if (rndis->manufacturer && rndis->vendorID && -+ rndis_set_param_vendor(rndis->config, rndis->vendorID, -+ rndis->manufacturer)) -+ goto fail; - - /* NOTE: all that is done without knowing or caring about - * the network link ... which is unavailable to this code -@@ -854,6 +854,13 @@ static inline bool can_support_rndis(struct usb_configuration *c) - */ - int - rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) -+{ -+ return rndis_bind_config_vendor(c, ethaddr, 0, NULL); -+} -+ -+int -+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -+ u32 vendorID, const char *manufacturer) - { - struct f_rndis *rndis; - int status; -@@ -861,14 +868,14 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) - if (!can_support_rndis(c) || !ethaddr) - return -EINVAL; - -+ /* setup RNDIS itself */ -+ status = rndis_init(); -+ if (status < 0) -+ return status; -+ - /* maybe allocate device-global string IDs */ - if (rndis_string_defs[0].id == 0) { - -- /* ... and setup RNDIS itself */ -- status = rndis_init(); -- if (status < 0) -- return status; -- - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) -@@ -898,6 +905,8 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) - goto fail; - - memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); -+ rndis->vendorID = vendorID; -+ rndis->manufacturer = manufacturer; - - /* RNDIS activates when the host changes this filter */ - rndis->port.cdc_filter = 0; -diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c -index a896d73f..ab443a09 100644 ---- a/drivers/usb/gadget/file_storage.c -+++ b/drivers/usb/gadget/file_storage.c -@@ -257,7 +257,6 @@ - #include "gadget_chips.h" - - -- - /* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use -@@ -335,7 +334,11 @@ static struct { - .vendor = FSG_VENDOR_ID, - .product = FSG_PRODUCT_ID, - .release = 0xffff, // Use controller chip type -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ .buflen = 65536 -+#else - .buflen = 16384, -+#endif - }; - - -@@ -555,10 +558,15 @@ device_desc = { - .idVendor = cpu_to_le16(FSG_VENDOR_ID), - .idProduct = cpu_to_le16(FSG_PRODUCT_ID), - .bcdDevice = cpu_to_le16(0xffff), -- -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ .iManufacturer = 0,//STRING_MANUFACTURER, -+ .iProduct = 0,//STRING_PRODUCT, -+ .iSerialNumber = 0,//STRING_SERIAL, -+#else - .iManufacturer = FSG_STRING_MANUFACTURER, - .iProduct = FSG_STRING_PRODUCT, - .iSerialNumber = FSG_STRING_SERIAL, -+#endif - .bNumConfigurations = 1, - }; - -@@ -2360,6 +2368,10 @@ static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, - mask, needs_medium, name); - } - -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+#include "plat-anyka/anyka_usbburn.c" //modified by anyka Zhang Jingyuan -+#endif -+ - static int do_scsi_command(struct fsg_dev *fsg) - { - struct fsg_buffhd *bh; -@@ -2563,6 +2575,23 @@ static int do_scsi_command(struct fsg_dev *fsg) - "WRITE(12)")) == 0) - reply = do_write(fsg); - break; -+ -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ case SCSI_ANYKA_UBOOT: -+ fsg->data_size_from_cmnd = fsg->data_size; -+ if ((reply = check_anyka_command(fsg, 1)) == 0) -+ reply = usbburn_write(fsg->cmnd, 16 + 8); -+ if (fsg->data_size_from_cmnd > 0) { -+ if (fsg->data_dir == DATA_DIR_TO_HOST) -+ reply = do_anyka_read(fsg); -+ else -+ reply = do_anyka_write(fsg); -+ } -+ down(&sense_data_lock); -+ fsg->curlun->sense_data = sense_data; -+ break; -+ //end of modified by anyka Zhang Jingyuan -+#endif - - /* Some mandatory commands that we recognize but don't implement. - * They don't mean much in this setting. It's left as an exercise -diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h -index a8855d0b..941b498a 100644 ---- a/drivers/usb/gadget/gadget_chips.h -+++ b/drivers/usb/gadget/gadget_chips.h -@@ -50,6 +50,7 @@ - #define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) - #define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name)) - #define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name)) -+#define gadget_is_ak_hsudc(g) (!strcmp("ak-hsudc", (g)->name)) - - /** - * usb_gadget_controller_number - support bcdDevice id convention -@@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) - return 0x31; - else if (gadget_is_dwc3(gadget)) - return 0x32; -+ else if (gadget_is_ak_hsudc(gadget)) -+ return 0x33; - - return -ENOENT; - } -diff --git a/drivers/usb/gadget/plat-anyka/Kconfig b/drivers/usb/gadget/plat-anyka/Kconfig -new file mode 100644 -index 00000000..da55d4ab ---- /dev/null -+++ b/drivers/usb/gadget/plat-anyka/Kconfig -@@ -0,0 +1,37 @@ -+config USB_GADGET_AKUDC_PRODUCER -+ bool "Anyka usb device Port for PRODUCER" -+ depends on ARCH_AK39 -+ select USB_GADGET_DUALSPEED -+ help -+ Anyka USB-OTG device support for producer -+ -+if USB_GADGET_AKUDC_PRODUCER -+config USB_AKUDC_PRODUCER -+ tristate -+ default y -+endif -+ -+config USB_GADGET_AKUDC -+ bool "Anyka usb device Port" -+ depends on ARCH_AK39 -+ select USB_GADGET_DUALSPEED -+ help -+ Anyka USB-OTG gadget device support -+ -+config USB_AKUDC -+ tristate "udc driver support(usb-otg)" -+ depends on USB_GADGET_AKUDC -+ default USB_GADGET -+ help -+ udc driver in ak39xx platfrom -+ -+config USB_AKUDC_DEBUG_FS -+ bool "Debugging information files (DEVELOPMENT)" -+ depends on USB_AKUDC -+ help -+ Some of the drivers in the "gadget" framework can expose debugging information -+ in files such as /proc/driver/udc (for a peripheral controller). The information in these -+ files may help when you're troubleshooting or bringing up a driver on a new board. -+ -+ Enable these files by choosing "Y" here. If in doubt, or to conserve kernel memory, say "N". -+ -diff --git a/drivers/usb/gadget/plat-anyka/Makefile b/drivers/usb/gadget/plat-anyka/Makefile -new file mode 100644 -index 00000000..4534ddec ---- /dev/null -+++ b/drivers/usb/gadget/plat-anyka/Makefile -@@ -0,0 +1,8 @@ -+ -+obj-$(CONFIG_USB_AKUDC_PRODUCER) += udc.o -+ifdef CONFIG_USB_AKUDC_PRODUCER -+obj-y += usbburn.o -+endif -+ -+obj-$(CONFIG_USB_AKUDC) += udc.o -+ -diff --git a/drivers/usb/gadget/plat-anyka/anyka_usbburn.c b/drivers/usb/gadget/plat-anyka/anyka_usbburn.c -new file mode 100644 -index 00000000..5685a1b8 ---- /dev/null -+++ b/drivers/usb/gadget/plat-anyka/anyka_usbburn.c -@@ -0,0 +1,188 @@ -+#include <plat-anyka/usbburn.h> -+ -+/* -+ * to check whether the anyka command is correct -+ * modify from check_command in file_storage.c -+ */ -+static int check_anyka_command(struct fsg_dev *fsg, int needs_medium) -+{ -+ struct fsg_lun *curlun; -+ -+ fsg->residue = fsg->usb_amount_left = fsg->data_size; -+ -+ /* Check the LUN */ -+ if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { -+ fsg->curlun = curlun = &fsg->luns[fsg->lun]; -+ curlun->sense_data = SS_NO_SENSE; -+ curlun->sense_data_info = 0; -+ curlun->info_valid = 0; -+ } else { -+ fsg->curlun = curlun = NULL; -+ fsg->bad_lun_okay = 0; -+ -+ DBG(fsg, "unsupported LUN %d\n", fsg->lun); -+ return -EINVAL; -+ } -+ -+ if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { -+ curlun->sense_data = SS_MEDIUM_NOT_PRESENT; -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* -+ * to read data in akudc_usbburn char dev that come from producer -+ * modify from do_read in file_storage.c -+ */ -+static int do_anyka_read(struct fsg_dev *fsg) -+{ -+ struct fsg_buffhd *bh; -+ int rc; -+ u32 amount_left; -+ unsigned int amount; -+ ssize_t nread; -+ -+ /* Carry out the file reads */ -+ amount_left = fsg->data_size_from_cmnd; -+ if (unlikely(amount_left == 0)) -+ return -EIO; // No default reply -+ -+ for (;;) { -+ -+ /* Figure out how much we need to read: -+ * Try to read the remaining amount. -+ * But don't read more than the buffer size. -+ * And don't try to read past the end of the file. -+ * Finally, if we're not at a page boundary, don't read past -+ * the next page. -+ * If this means reading 0 then we were asked to read past -+ * the end of file. */ -+ amount = min((unsigned int) amount_left, mod_data.buflen); -+ -+ /* Wait for the next buffer to become available */ -+ bh = fsg->next_buffhd_to_fill; -+ while (bh->state != BUF_STATE_EMPTY) { -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ -+ nread = usbburn_read(bh->buf + nread, amount); -+ -+ amount_left -= nread; -+ fsg->residue -= nread; -+ bh->inreq->length = nread; -+ bh->state = BUF_STATE_FULL; -+ -+ if (nread < amount) -+ break; -+ if (amount_left == 0) -+ break; // No more left to read -+ -+ /* Send this buffer and go read some more */ -+ bh->inreq->zero = 0; -+ start_transfer(fsg, fsg->bulk_in, bh->inreq, -+ &bh->inreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ } -+ -+ return -EIO; // No default reply -+} -+ -+/* -+ * to write data to akudc_usbburn char dev that can be read by producer -+ * modify from do_write in file_storage.c -+ */ -+static int do_anyka_write(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ struct fsg_buffhd *bh; -+ int get_some_more; -+ u32 amount_left_to_req, amount_left_to_write; -+ loff_t file_offset; -+ unsigned int amount; -+ ssize_t nwritten; -+ int rc; -+ -+ /* Carry out the file writes */ -+ get_some_more = 1; -+ file_offset = 0; -+ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; -+ -+ while (amount_left_to_write > 0) { -+ -+ /* Queue a request for more data from the host */ -+ bh = fsg->next_buffhd_to_fill; -+ if (bh->state == BUF_STATE_EMPTY && get_some_more) { -+ -+ amount = min(amount_left_to_req, mod_data.buflen); -+ -+ /* Get the next buffer */ -+ fsg->usb_amount_left -= amount; -+ amount_left_to_req -= amount; -+ if (amount_left_to_req == 0) -+ get_some_more = 0; -+ -+ /* amount is always divisible by 512, hence by -+ * the bulk-out maxpacket size */ -+ bh->outreq->length = bh->bulk_out_intended_length = -+ amount; -+ bh->outreq->short_not_ok = 1; -+ start_transfer(fsg, fsg->bulk_out, bh->outreq, -+ &bh->outreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ continue; -+ } -+ -+ /* Write the received data to the backing file */ -+ bh = fsg->next_buffhd_to_drain; -+ if (bh->state == BUF_STATE_EMPTY && !get_some_more) -+ break; // We stopped early -+ if (bh->state == BUF_STATE_FULL) { -+ smp_rmb(); -+ fsg->next_buffhd_to_drain = bh->next; -+ bh->state = BUF_STATE_EMPTY; -+ -+ /* Did something go wrong with the transfer? */ -+ if (bh->outreq->status != 0) { -+ curlun->sense_data = SS_COMMUNICATION_FAILURE; -+ // curlun->sense_data_info = file_offset >> 9; -+ curlun->info_valid = 1; -+ break; -+ } -+ -+ amount = bh->outreq->actual; -+ if (fsg->data_size_from_cmnd - file_offset < amount) { -+ LERROR(curlun, -+ "write %u @ %llu beyond end %llu\n", -+ amount, (unsigned long long) file_offset, -+ (unsigned long long) curlun->file_length); -+ amount = curlun->file_length - file_offset; -+ } -+ -+ /* Perform the write */ -+ nwritten = 0; -+ nwritten = usbburn_write(bh->buf + nwritten, amount); -+ -+ file_offset += nwritten; -+ amount_left_to_write -= nwritten; -+ fsg->residue -= nwritten; -+ -+ /* Did the host decide to stop early? */ -+ if (bh->outreq->actual != bh->outreq->length) { -+ fsg->short_packet_received = 1; -+ break; -+ } -+ continue; -+ } -+ -+ /* Wait for something to happen */ -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ -+ return -EIO; // No default reply -+} -diff --git a/drivers/usb/gadget/plat-anyka/udc.c b/drivers/usb/gadget/plat-anyka/udc.c -new file mode 100755 -index 00000000..37494006 ---- /dev/null -+++ b/drivers/usb/gadget/plat-anyka/udc.c -@@ -0,0 +1,2664 @@ -+/* -+ * akudc_udc -- driver for anyka USB peripheral controller -+ * Features -+ * The USB 2.0 HS OTG has following features: -+ * �? compliant with USB Specification Version 2.0 (HS) and On-The-Go supplement to -+ * the USB 2.0 specification -+ * �? operating as the host in point-to-point communications with another USB function -+ * or as a function controller for a USB peripheral -+ * �? supporting UTMI+ Level 2 Transceiver Interface -+ * �? 4 Transmit/Receive endpoints in addition to Endpoint 0 -+ * �? 3 DMA channels -+ * AUTHOR ANYKA Zhang Jingyuan -+ * 09-11-14 10:45:03 -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/delay.h> -+#include <linux/ioport.h> -+#include <linux/slab.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/proc_fs.h> -+#include <linux/clk.h> -+#include <linux/usb/ch9.h> -+#include <linux/usb/gadget.h> -+#include <linux/workqueue.h> -+#include <linux/dma-mapping.h> -+ -+#include <asm/io.h> -+#include <asm/irq.h> -+#include <asm/dma-mapping.h> -+ -+#include <plat/l2.h> -+#include <plat-anyka/udc.h> -+#include <plat-anyka/notify.h> -+#include <mach/reg.h> -+#include <mach/reset.h> -+#include <mach/l2cache.h> -+ -+#define DRIVER_VERSION "30-May-2013" -+#define DRIVER_DESC "ANYKA AK39 USB Device Controller driver" -+ -+#if 0 -+#define dbg(fmt, arg...) printk("%s(%d): " fmt "\n", __func__, __LINE__, ##arg) -+#else -+#define dbg(fmt, arg...) -+#endif -+ -+static const char ep0name[] = "ep0"; -+static const char driver_name[] = "ak-hsudc"; -+ -+#define udc_readb(reg) __raw_readb(udc->baseaddr + (reg)) -+#define udc_readw(reg) __raw_readw(udc->baseaddr + (reg)) -+#define udc_readl(reg) __raw_readl(udc->baseaddr + (reg)) -+#define udc_writeb(reg, val) __raw_writeb(val, udc->baseaddr + (reg)) -+#define udc_writew(reg, val) __raw_writew(val, udc->baseaddr + (reg)) -+#define udc_writel(reg, val) __raw_writel(val, udc->baseaddr + (reg)) -+ -+static struct akudc_udc controller; -+struct workqueue_struct *ep_wqueue; //the workqueue for non-ep0 endpoint transmission -+ -+volatile int usb_detect; -+ -+unsigned int dma_rx; -+unsigned int dma_tx; -+dma_addr_t phys_rx; -+dma_addr_t phys_tx; -+ -+static volatile char flag = 0; -+static atomic_t udc_clk = ATOMIC_INIT(0); //the clk condition for udc -+static atomic_t usb_enable_flag = ATOMIC_INIT(0); //the current status of udc -+ -+#ifdef CONFIG_USB_AKUDC_DEBUG_FS -+#include <linux/seq_file.h> -+#include <linux/debugfs.h> -+ -+#define akudc_udc_read(udc, reg) \ -+ __raw_readl((udc)->baseaddr + (reg)) -+#define akudc_udc_write(udc, reg, val) \ -+ __raw_writel((val), (udc)->baseaddr + (reg)) -+ -+static const char debug_filename[] = "driver/udc"; -+ -+static char *parse_linestate(unsigned long value) -+{ -+ char *str; -+ -+ switch(value & USB_LINESTATE_WP) { -+ case 0: -+ str = "SE0"; -+ break; -+ case 1: -+ str = "'J'State"; -+ break; -+ case 2: -+ str = "'K'State"; -+ break; -+ case 3: -+ str = "SE1"; -+ break; -+ } -+ return str; -+} -+ -+static int parse_state(unsigned int val1, unsigned int val2) -+{ -+ if (val1 == val2) -+ return 1; -+ return 0; -+} -+ -+static int udc_seq_show(struct seq_file *s, void *data) -+{ -+ struct akudc_udc *udc = s->private; -+ unsigned long flags; -+ int i; -+ unsigned long tmp; -+ -+ seq_printf(s, "%s: version %s\n", "akudc", DRIVER_VERSION); -+ -+ local_irq_save(flags); -+ tmp = __raw_readl(USB_OP_MOD_REG); -+ seq_printf(s, "usb opmod control:0x%08x, linestate:%s,%s,%s,%s,%s\n\n", tmp, -+ parse_linestate(tmp), -+ (tmp & USB_DP_PU_EN) ? " DP en pullup" : " DP dis pullup", -+ parse_state(((tmp & USB_ID_CFG) >> 12), USB_ID_CLIENT) ? " slave" : " host", -+ parse_state(((tmp & USB_PHY_CFG) >> 6), USB_PHY_CLIENT) ? " slave" : " host", -+ (tmp & USB_SUSPEND_EN) ? "en suspend controller & transceiver" : " en suspend transceiver"); -+ -+ tmp = akudc_udc_read(udc, USB_POWER_CTRL); -+ seq_printf(s, "usb power control:0x%08x %s,%s,%s,%s,%s,%s\n\n", tmp, -+ (tmp & USB_ISO_UPDATE) ? " ISO" : " invalid", -+ (tmp & USB_HSPEED_EN) ? " Hspeed mode" : " Fspeed mode", -+ (tmp & USB_HSPEED_MODE) ? " HSmode success" : "", -+ (tmp & USB_RESUME_EN) ? " en resume" : " invalid", -+ (tmp & USB_SUSPEND_MODE)? " en suspend controller & transceiver" : "", -+ (tmp & USB_SUSPENDM_EN) ? " en suspendm" : " invalid"); -+ -+ tmp = akudc_udc_read(udc, USB_FRAME_NUM); -+ seq_printf(s, "frame=%d\n", tmp); -+ -+ tmp = akudc_udc_read(udc, USB_FUNCTION_ADDR); -+ seq_printf(s, "faddr=0x%p\n", tmp); -+ -+ tmp = __raw_readl(AK_VA_SYSCTRL + 0x1C); -+ seq_printf(s, "usb clock:%s\n", -+ (tmp & (1<<15)) ? " disable" : " enable"); -+ -+ local_irq_restore(flags); -+ return 0; -+} -+static int udc_debugfs_open(struct inode *inode, struct file *file) -+{ -+ single_open(file, udc_seq_show, PDE(inode)->data); -+} -+ -+static const struct file_operations proc_ops = { -+ .owner = THIS_MODULE, -+ .open = udc_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+void create_debugfs_files(struct akudc_udc *udc) -+{ -+ udc->pde = proc_create_data(debug_filename, S_IRUGO, NULL, &proc_ops, udc); -+} -+ -+void remove_debugfs_files(struct akudc_udc *udc) -+{ -+ if(udc->pde) -+ remove_proc_entry(debug_filename, NULL); -+} -+#else -+static inline void create_debugfs_files(struct akudc_udc *udc) {} -+static inline void remove_debugfs_files(struct akudc_udc *udc) {} -+#endif -+ -+static void udc_reg_writel(unsigned long __iomem *__reg, -+ unsigned long value, int bits, int index) -+{ -+ unsigned long tmp; -+ tmp = __raw_readl(__reg); -+ tmp &= ~(((1 << bits)-1) << index); -+ tmp |= (value << index); -+ __raw_writel(tmp, __reg); -+} -+ -+#if 0 -+static unsigned long udc_reg_readl(unsigned long __iomem *__reg, -+ int bits, int index) -+{ -+ unsigned long tmp; -+ tmp = __raw_readl(__reg); -+ tmp = (tmp&(((1 << bits)-1) << index)) >> index; -+ return tmp; -+} -+#endif -+ -+static inline int whether_enable(void) -+{ -+ /* -+ * if all of the udc condition is 1 and it is disable, -+ * return 1 -+ */ -+ if ((atomic_read(&udc_clk) == 1) -+ && (atomic_read(&usb_enable_flag) == 0)) { -+ -+ atomic_set(&usb_enable_flag, 1); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static inline int whether_disable(void) -+{ -+ /* -+ * if any of the udc condition is 0 and it is enable, -+ * return 1 -+ */ -+ if ((atomic_read(&udc_clk) == 0) -+ && (atomic_read(&usb_enable_flag) == 1)) { -+ -+ atomic_set(&usb_enable_flag, 0); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* enable the ep interrupt */ -+static void ep_irq_enable(struct usb_ep *_ep) -+{ -+ static struct akudc_udc *udc = &controller; -+ -+ /* enable ep1 rx */ -+ if (!strcmp(_ep->name, udc->ep[1].ep.name)) -+ //udc_writew(USB_INTERRUPT_RX, udc_readw(USB_INTERRUPT_RX) | (0x1<<1)); -+ udc_writew(USB_INTERRUPT_TX, udc_readw(USB_INTERRUPT_TX) | (0x1<<1)); -+ -+ /* enable ep2 tx */ -+ if (!strcmp(_ep->name, udc->ep[2].ep.name)) -+ udc_writew(USB_INTERRUPT_TX, udc_readw(USB_INTERRUPT_TX) | (0x1<<2)); -+ -+ /* enable ep3 rx */ -+ if (!strcmp(_ep->name, udc->ep[3].ep.name)) -+ udc_writew(USB_INTERRUPT_RX, udc_readw(USB_INTERRUPT_RX) | (0x1<<3)); -+ -+ /* enable ep4 tx */ -+ if (!strcmp(_ep->name, udc->ep[4].ep.name)) -+ udc_writew(USB_INTERRUPT_TX, udc_readw(USB_INTERRUPT_TX) | (0x1<<4)); -+ -+ /* enable ep5 rx */ -+ if (!strcmp(_ep->name, udc->ep[5].ep.name)) -+ udc_writew(USB_INTERRUPT_RX, udc_readw(USB_INTERRUPT_RX) | (0x1<<5)); -+} -+ -+/* disable the ep interrupt */ -+static void ep_irq_disable(struct usb_ep *_ep) -+{ -+ static struct akudc_udc *udc = &controller; -+ -+ /* disable ep1 rx */ -+ if (!strcmp(_ep->name, udc->ep[1].ep.name)) -+ //udc_writew(USB_INTERRUPT_RX, udc_readw(USB_INTERRUPT_RX) & ~(0x1<<1)); -+ udc_writew(USB_INTERRUPT_TX, udc_readw(USB_INTERRUPT_TX) & ~(0x1<<1)); -+ -+ /* disable ep2 tx */ -+ if (!strcmp(_ep->name, udc->ep[2].ep.name)) -+ udc_writew(USB_INTERRUPT_TX, udc_readw(USB_INTERRUPT_TX) & ~(0x1<<2)); -+ -+ /* disable ep3 rx */ -+ if (!strcmp(_ep->name, udc->ep[3].ep.name)) -+ udc_writew(USB_INTERRUPT_RX, udc_readw(USB_INTERRUPT_RX) & ~(0x1<<3)); -+ -+ /* disable ep4 tx */ -+ if (!strcmp(_ep->name, udc->ep[4].ep.name)) -+ udc_writew(USB_INTERRUPT_TX, udc_readw(USB_INTERRUPT_TX) & ~(0x1<<4)); -+ -+ /* disable ep5 rx */ -+ if (!strcmp(_ep->name, udc->ep[5].ep.name)) -+ udc_writew(USB_INTERRUPT_RX, udc_readw(USB_INTERRUPT_RX) & ~(0x1<<5)); -+} -+ -+ -+/* -+ * enable or disable the udc controller -+ * @enable: if 1, enable. if 0, disable -+ */ -+void usbcontroller_enable(int enable) -+{ -+ struct akudc_udc *udc = &controller; -+ if (enable) { -+ clk_enable(udc->clk); //enable clk for udc -+ /* reset usb phy and suspend transceiver, and power up(ak98) */ -+ udc_reg_writel(USB_OP_MOD_REG, 0x6, 3, 0); -+ set_usb_as_slave(); -+ -+ udc_writeb(USB_POWER_CTRL, 1<<5); // enable high speed negotiation -+ udc_writeb(USB_INTERRUPT_TX, 0x1<<0); // enable ep0 interrupt and disable other tx endpoint -+ udc_writeb(USB_INTERRUPT_RX, 0); // disable rx endpoint inttrupt -+ } else { -+ clk_disable(udc->clk); //disable clk for udc -+ /* reset usb phy */ -+ udc_reg_writel(USB_OP_MOD_REG, 0x1, 3, 0); -+ udc_writeb(USB_POWER_CTRL, 0); -+ ak_soft_reset(AK_SRESET_USBHS); //reset the udc controller -+ } -+} -+ -+/* -+ * set the udc condition, and judge whether the udc -+ * can be enabled, if is , enable it -+ */ -+void set_condition(atomic_t *cond) { -+ atomic_set(cond, 1); -+ if (whether_enable()) -+ usbcontroller_enable(1); -+} -+ -+/* -+ * clear the udc condition, and judge whether the udc -+ * can be disabled, if is , disable it -+ */ -+void clear_condition(atomic_t *cond) { -+ atomic_set(cond, 0); -+ if (whether_disable()) -+ usbcontroller_enable(0); -+} -+ -+/* -+ * enable the udc -+ */ -+ -+/* -+ * when the req is complete, call this function -+ * @ep: which ep's request is complete -+ * @req: the request which is complete -+ * @status: the request's status -+ */ -+static void done(struct akudc_ep *ep, struct akudc_request *req, int status) -+{ -+ unsigned stopped = ep->stopped; -+ -+ /* delete req from ep queue */ -+ list_del_init(&req->queue); -+ -+ if (likely (req->req.status == -EINPROGRESS)) -+ req->req.status = status; -+ else -+ status = req->req.status; -+ -+ ep->stopped = 1; -+ /* call complete callback before return */ -+ req->req.complete(&ep->ep, &req->req); -+ ep->stopped = stopped; -+ -+ dbg("%s done, req.status(%d)", ep->ep.name, req->req.status); -+} -+ -+/* -+ * send data to pc in ep0 -+ * @ep: point to ep0 -+ * @req: the request which is doing -+ * return: 0 = still running, 1 = completed, negative = errno -+ */ -+static int write_ep0_fifo(struct akudc_ep *ep, struct akudc_request *req) -+{ -+ int i; -+ unsigned total, count, is_last; -+ struct akudc_udc *udc = ep->udc; -+ unsigned char *buf; -+ -+ total = req->req.length - req->req.actual; -+ -+ if (ep->ep.maxpacket < total) { /* if this transition is not last */ -+ count = ep->ep.maxpacket; -+ is_last = 0; -+ } else { /* if this transition is last */ -+ count = total; -+ /* -+ * if the req zero flag not set, the "count == ep->ep.maxpacket" -+ * is the last -+ */ -+ is_last = (count < ep->ep.maxpacket) || !req->req.zero; -+ } -+ -+ dbg("is_last(%d), count(%d), total(%d), actual(%d), length(%d)", -+ is_last, count, total, req->req.actual, req->req.length); -+ -+ udc_writeb(USB_EP_INDEX, 0); -+ /* send zero packet */ -+ if (count == 0) { -+ dbg(" count == 0 "); -+ udc_writel(USB_EP0_NUM, count&0x7f); -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<1); -+ udc->ep0state = EP0_IDLE; -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ buf = req->req.buf + req->req.actual; -+ for (i = 0; i < count; i++) { -+ /* write data to the ep0 fifo */ -+ udc_writeb(USB_EP0_FIFO, buf[i]); -+ } -+ -+ udc_writel(USB_EP0_NUM, count&0x7f); /* 7bits */ -+ if (is_last) /* if last, set data end */ -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<1); -+ else -+ udc_writeb(USB_CTRL_1, 0x1<<1); -+ -+ req->req.actual += count; -+ if (is_last) { /* if last ,done the req with status 0 */ -+ udc->ep0state = EP0_IDLE; -+ done(ep, req, 0); -+ } -+ -+ ep->done = is_last; -+ return is_last; -+ /* return 1; */ -+} -+ -+/* -+ * read data from pc in ep0 -+ * @ep: point to ep0 -+ * @req: the request which is doing -+ * return: 0 = still running, 1 = completed, negative = errno -+ */ -+static int read_ep0_fifo(struct akudc_ep *ep, struct akudc_request *req) -+{ -+ int i; -+ unsigned total, count, is_last; -+ struct akudc_udc *udc = ep->udc; -+ unsigned char *buf; -+ -+ total = req->req.length - req->req.actual; -+ -+ if (ep->ep.maxpacket < total) { -+ count = ep->ep.maxpacket; -+ is_last = 0; -+ } else { -+ count = total; -+ is_last = (count < ep->ep.maxpacket) || !req->req.zero; -+ } -+ -+ dbg("is_last(%d), count(%d), total(%d), actual(%d), length(%d)", -+ is_last, count, total, req->req.actual, req->req.length); -+ -+ udc_writeb(USB_EP_INDEX, 0); -+ /* read zero packet */ -+ if (count == 0) { -+ dbg(" count == 0 "); -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<6); -+ udc->ep0state = EP0_IDLE; -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ buf = req->req.buf + req->req.actual; -+ for (i = 0; i < count; i++) { -+ /* read data from ep0 fifo */ -+ buf[i] = udc_readb(USB_EP0_FIFO); -+ } -+ -+ if (is_last) /* if last, set data end */ -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<6); -+ else -+ udc_writeb(USB_CTRL_1, 0x1<<6); -+ -+ req->req.actual += count; -+ if (is_last) { /* if last ,done the req with status 0 */ -+ udc->ep0state = EP0_IDLE; -+ done(ep, req, 0); -+ } -+ -+ ep->done = is_last; -+ return is_last; -+ /* return 1; */ -+} -+ -+/* the ep1 is not used */ -+static int write_ep1_fifo(struct akudc_ep *ep, struct akudc_request *req) -+{ -+ struct akudc_udc *udc = ep->udc; -+ unsigned total, count, is_last; -+ unsigned char *buf; -+ int dma = 0, i; -+ -+ total = req->req.length - req->req.actual; -+ if (ep->ep.maxpacket <= total) { -+ count = ep->ep.maxpacket; -+ is_last = (total == ep->ep.maxpacket) && !req->req.zero; -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ if (udc->high_speed) -+ dma = 1; -+#endif -+#endif -+ } else { -+ count = total; -+ is_last = count < ep->ep.maxpacket; -+ dma = 0; -+ } -+ dbg("total(%d), count(%d), is_last(%d)", total, count, is_last); -+ -+ if (count == 0) { /* not support command */ -+ dbg("count == 0\n"); -+ ep->done = 1; -+ udc_writeb(USB_EP_INDEX, 1); -+ udc_writeb(USB_CTRL_1, 0x1); -+ return 0; -+ } -+ udc_writeb(USB_EP_INDEX, 1); -+ -+ buf = req->req.buf + req->req.actual; -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ dbg("producer"); -+ if (udc->high_speed && (dma == 1)) { -+ dma_tx = total - (total % ep->ep.maxpacket); -+ /* map the dma buffer */ -+ phys_tx = dma_map_single(NULL, buf, dma_tx, DMA_TO_DEVICE); -+ if (phys_tx == 0) { -+ printk("tx dma_map_single error!\n"); -+ goto cpu; -+ } -+ -+ udc_writeb(USB_CTRL_1_2, (1<<2) | (1<<4) | (1<<5) | (1<<7)); -+ -+ //send data to l2 -+ l2_clr_status(ep->l2_buf_id); -+ l2_combuf_dma(phys_tx, ep->l2_buf_id, dma_tx, MEM2BUF, false); -+ udc_writel(USB_DMA_ADDR3, 0x72000000); -+ udc_writel(USB_DMA_COUNT3, dma_tx); -+ udc_writel(USB_DMA_CTRL3, (USB_ENABLE_DMA | USB_DIRECTION_TX | USB_DMA_MODE1 | USB_DMA_INT_ENABLE| (USB_EP4_INDEX<<4) | USB_DMA_BUS_MODE3)); -+ -+ ep->done = 0; -+ return 0; -+ } -+#endif -+cpu: -+#endif -+ -+ for (i = 0; i < count; i++) { -+ /* send data to ep4 fifo without dma */ -+ udc_writeb(USB_EP1_FIFO, buf[i]); -+ } -+ -+ udc_writeb(USB_CTRL_1, 0x1); -+ -+ req->req.actual += count; -+ /* wait a tx complete int */ -+ if (is_last) -+ done(ep, req, 0); -+ -+ return is_last; -+} -+ -+/* -+ * send data to pc in ep2 -+ * @ep: point to ep2 -+ * @req: the request which is doing -+ */ -+static int write_ep2_fifo(struct akudc_ep *ep, struct akudc_request *req) /* ep2 */ -+{ -+ struct akudc_udc *udc = ep->udc; -+ unsigned total, count, is_last; -+ unsigned char *buf; -+ int dma = 0, i; -+ -+ total = req->req.length - req->req.actual; -+ if (ep->ep.maxpacket <= total) { -+ count = ep->ep.maxpacket; -+ is_last = (total == ep->ep.maxpacket) && !req->req.zero; -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ if (udc->high_speed) -+ dma = 1; -+#endif -+#endif -+ } else { -+ count = total; -+ is_last = count < ep->ep.maxpacket; -+ dma = 0; -+ } -+ dbg("total(%d), count(%d), is_last(%d)", total, count, is_last); -+ -+ if (count == 0) { /* not support command */ -+ dbg("count == 0\n"); -+ ep->done = 1; -+ udc_writeb(USB_EP_INDEX, 2); -+ udc_writeb(USB_CTRL_1, 0x1); -+ return 0; -+ } -+ udc_writeb(USB_EP_INDEX, 2); -+ -+ buf = req->req.buf + req->req.actual; -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ if (udc->high_speed && (dma == 1)) { -+ dma_tx = total - (total % ep->ep.maxpacket); -+ /* map the dma buffer */ -+ phys_tx = dma_map_single(NULL, buf, dma_tx, DMA_TO_DEVICE); -+ if (phys_tx == 0) { -+ printk("tx dma_map_single error!\n"); -+ goto cpu; -+ } -+ -+ udc_writeb(USB_CTRL_1_2, (1<<2) | (1<<4) | (1<<5) | (1<<7)); -+ -+ //send data to l2 -+ l2_clr_status(ep->l2_buf_id); -+ l2_combuf_dma(phys_tx, ep->l2_buf_id, dma_tx, MEM2BUF, false); -+ udc_writel(USB_DMA_ADDR1, 0x70000000); -+ udc_writel(USB_DMA_COUNT1, dma_tx); -+ udc_writel(USB_DMA_CTRL1, (USB_ENABLE_DMA | USB_DIRECTION_TX | USB_DMA_MODE1 | USB_DMA_INT_ENABLE| (USB_EP2_INDEX<<4) | USB_DMA_BUS_MODE3)); -+ -+ ep->done = 0; -+ return 0; -+ } -+#endif -+cpu: -+#endif -+ -+ for (i = 0; i < count; i++) { -+ /* send data to ep2 fifo without dma */ -+ udc_writeb(USB_EP2_FIFO, buf[i]); -+ } -+ udc_writeb(USB_CTRL_1, 0x1); -+ -+ req->req.actual += count; -+ /* wait a tx complete int */ -+ /* -+ * if (is_last) -+ * done(ep, req, 0); -+ */ -+ -+ /* return is_last; */ -+ ep->done = is_last; -+ -+ return 0; -+} -+ -+/* -+ * read data from pc in ep3 -+ * @ep: point to ep3 -+ * @req: the request which is doing -+ */ -+static int read_ep3_fifo(struct akudc_ep *ep, struct akudc_request *req) /* ep3 */ -+{ -+ struct akudc_udc *udc = ep->udc; -+ unsigned char *buf; -+ unsigned int csr, i; -+ unsigned int count, bufferspace, is_done; -+ -+ if (flag == 1) -+ return 0; -+ -+ bufferspace = req->req.length - req->req.actual; -+ -+ udc_writeb(USB_EP_INDEX, 3); -+ csr = udc_readb(USB_CTRL_2); -+ if ((csr & 0x1) == 0) { -+ dbg("waiting bulkout data"); -+ return 0; -+ } -+ -+ count = udc_readw(USB_EP_COUNT); -+ if (count == 0) { -+ dbg("USB_CTRL_2(0x%x), USB_EP_COUNT(%d), bufferspace(%d)", -+ csr, count, bufferspace); -+ goto stall; -+ } else if (count > ep->ep.maxpacket) -+ count = ep->ep.maxpacket; -+ -+ if (count > bufferspace) { -+ dbg("%s buffer overflow\n", ep->ep.name); -+ req->req.status = -EOVERFLOW; -+ count = bufferspace; -+ } -+ dbg("USB_CTRL_2(0x%x), USB_EP_COUNT(%d), bufferspace(%d)", csr, count, bufferspace); -+ -+ buf = req->req.buf + req->req.actual; -+ -+ for (i = 0; i < count; i++) { -+ /* read data from ep3 fifo without dma */ -+ buf[i] = udc_readb(USB_EP3_FIFO); -+ } -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ if (udc->high_speed) { -+ dma_rx = bufferspace - count; -+ if (dma_rx >= ep->ep.maxpacket) { -+ dma_rx -= (dma_rx % ep->ep.maxpacket); -+ -+ buf = req->req.buf + req->req.actual + count; -+ /* send data to ep2 fifo without dma */ -+ phys_rx = dma_map_single(NULL, buf, dma_rx, DMA_FROM_DEVICE); -+ if (phys_rx == 0) { -+ printk("rx dma_map_single error!\n"); -+ goto stall; -+ } -+ -+ req->req.actual += count; -+ flag = 1; -+ udc_writeb(USB_CTRL_2_2, udc_readb(USB_CTRL_2_2) | (1<<3) | (1<<5) | (1<<7)); -+ l2_combuf_dma(phys_rx, ep->l2_buf_id, dma_rx, BUF2MEM, false); -+ udc_writel(USB_DMA_ADDR2, 0x71000000); -+ udc_writel(USB_DMA_COUNT2, dma_rx); -+ udc_writel(USB_DMA_CTRL2, (USB_ENABLE_DMA|USB_DIRECTION_RX|USB_DMA_MODE1|USB_DMA_INT_ENABLE|(USB_EP3_INDEX<<4)|USB_DMA_BUS_MODE3)); -+ udc_writeb(USB_EP_INDEX, 3); -+ udc_writeb(USB_CTRL_2, csr & ~0x1); -+ ep->done = 0; -+ -+ return 0; -+ } -+ } -+#endif -+#endif -+stall: -+ udc_writeb(USB_CTRL_2, csr & ~0x1); -+ -+ req->req.actual += count; -+ is_done = (count < ep->ep.maxpacket); -+ if (count == bufferspace) -+ is_done = 1; -+ -+ ep->done = is_done; -+ if (is_done) { -+ done(ep, req, 0); -+ } -+ -+ return is_done; -+} -+ -+/* -+ * send data to pc in ep4 -+ * @ep: point to ep4 -+ * @req: the request which is doing -+ */ -+static int write_ep4_fifo(struct akudc_ep *ep, struct akudc_request *req) /* ep4 */ -+{ -+ struct akudc_udc *udc = ep->udc; -+ unsigned total, count, is_last; -+ unsigned char *buf; -+ int dma = 0, i; -+ -+ total = req->req.length - req->req.actual; -+ if (ep->ep.maxpacket <= total) { -+ count = ep->ep.maxpacket; -+ is_last = (total == ep->ep.maxpacket) && !req->req.zero; -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ if (udc->high_speed) -+ dma = 1; -+#endif -+#endif -+ } else { -+ count = total; -+ is_last = count < ep->ep.maxpacket; -+ dma = 0; -+ } -+ dbg("total(%d), count(%d), is_last(%d)", total, count, is_last); -+ -+ if (count == 0) { /* not support command */ -+ dbg("count == 0\n"); -+ ep->done = 1; -+ udc_writeb(USB_EP_INDEX, 4); -+ udc_writeb(USB_CTRL_1, 0x1); -+ return 0; -+ } -+ udc_writeb(USB_EP_INDEX, 4); -+ -+ buf = req->req.buf + req->req.actual; -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ if (udc->high_speed && (dma == 1)) { -+ dma_tx = total - (total % ep->ep.maxpacket); -+ /* map the dma buffer */ -+ phys_tx = dma_map_single(NULL, buf, dma_tx, DMA_TO_DEVICE); -+ if (phys_tx == 0) { -+ printk("tx dma_map_single error!\n"); -+ goto cpu; -+ } -+ -+ udc_writeb(USB_CTRL_1_2, (1<<2) | (1<<4) | (1<<5) | (1<<7)); -+ -+ //send data to l2 -+ l2_clr_status(ep->l2_buf_id); -+ l2_combuf_dma(phys_tx, ep->l2_buf_id, dma_tx, MEM2BUF, false); -+ udc_writel(USB_DMA_ADDR3, 0x72000000); -+ udc_writel(USB_DMA_COUNT3, dma_tx); -+ udc_writel(USB_DMA_CTRL3, (USB_ENABLE_DMA | USB_DIRECTION_TX | USB_DMA_MODE1 | USB_DMA_INT_ENABLE| (USB_EP4_INDEX<<4) | USB_DMA_BUS_MODE3)); -+ -+ ep->done = 0; -+ return 0; -+ } -+#endif -+cpu: -+#endif -+ -+ for (i = 0; i < count; i++) { -+ /* send data to ep4 fifo without dma */ -+ udc_writeb(USB_EP4_FIFO, buf[i]); -+ } -+ -+ udc_writeb(USB_CTRL_1, 0x1); -+ -+ req->req.actual += count; -+ /* wait a tx complete int */ -+ /* -+ * if (is_last) -+ * done(ep, req, 0); -+ */ -+ -+ /* return is_last; */ -+ ep->done = is_last; -+ -+ return 0; -+} -+ -+/* -+ * read data from pc in ep5 -+ * @ep: point to ep5 -+ * @req: the request which is doing -+ */ -+static int read_ep5_fifo(struct akudc_ep *ep, struct akudc_request *req) /* ep5 */ -+{ -+ struct akudc_udc *udc = ep->udc; -+ unsigned char *buf; -+ unsigned int csr, i; -+ unsigned int count, bufferspace, is_done; -+ -+ if (flag == 1) -+ return 0; -+ -+ bufferspace = req->req.length - req->req.actual; -+ -+ udc_writeb(USB_EP_INDEX, 5); -+ csr = udc_readb(USB_CTRL_2); -+ if ((csr & 0x1) == 0) { -+ dbg("waiting bulkout data"); -+ return 0; -+ } -+ -+ count = udc_readw(USB_EP_COUNT); -+ if (count == 0) { -+ dbg("USB_CTRL_2(0x%x), USB_EP_COUNT(%d), bufferspace(%d)", -+ csr, count, bufferspace); -+ goto stall; -+ } else if (count > ep->ep.maxpacket) -+ count = ep->ep.maxpacket; -+ -+ if (count > bufferspace) { -+ dbg("%s buffer overflow\n", ep->ep.name); -+ req->req.status = -EOVERFLOW; -+ count = bufferspace; -+ } -+ dbg("USB_CTRL_2(0x%x), USB_EP_COUNT(%d), bufferspace(%d)", csr, count, bufferspace); -+ -+ buf = req->req.buf + req->req.actual; -+ -+ for (i = 0; i < count; i++) { -+ /* read data from ep5 fifo without dma */ -+ buf[i] = udc_readb(USB_EP5_FIFO); -+ } -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ if (udc->high_speed) { -+ dma_rx = bufferspace - count; -+ if (dma_rx >= ep->ep.maxpacket) { -+ dma_rx -= (dma_rx % ep->ep.maxpacket); -+ -+ buf = req->req.buf + req->req.actual + count; -+ /* map the dma buffer */ -+ phys_rx = dma_map_single(NULL, buf, dma_rx, DMA_FROM_DEVICE); -+ if (phys_rx == 0) { -+ printk("rx dma_map_single error!\n"); -+ goto stall; -+ } -+ -+ req->req.actual += count; -+ flag = 1; -+ udc_writeb(USB_CTRL_2_2, udc_readb(USB_CTRL_2_2) | (1<<3) | (1<<5) | (1<<7)); -+ l2_combuf_dma(phys_rx, ep->l2_buf_id, dma_rx, BUF2MEM, false); -+ udc_writel(USB_DMA_ADDR4, 0x73000000); -+ udc_writel(USB_DMA_COUNT4, dma_rx); -+ udc_writel(USB_DMA_CTRL4, (USB_ENABLE_DMA|USB_DIRECTION_RX|USB_DMA_MODE1|USB_DMA_INT_ENABLE|(USB_EP5_INDEX<<4)|USB_DMA_BUS_MODE3)); -+ udc_writeb(USB_EP_INDEX, 5); -+ udc_writeb(USB_CTRL_2, csr & ~0x1); -+ ep->done = 0; -+ -+ return 0; -+ } -+ } -+#endif -+#endif -+ -+stall: -+ udc_writeb(USB_CTRL_2, csr & ~0x1); -+ -+ req->req.actual += count; -+ is_done = (count < ep->ep.maxpacket); -+ if (count == bufferspace) -+ is_done = 1; -+ -+ ep->done = is_done; -+ if (is_done) { -+ done(ep, req, 0); -+ } -+ -+ return is_done; -+} -+ -+ -+/* the funciton is not used */ -+static int akudc_get_frame(struct usb_gadget *gadget) -+{ -+ dbg(""); -+ return 0; -+} -+ -+/* the funciton is not used */ -+static int akudc_wakeup(struct usb_gadget *gadget) -+{ -+ dbg(""); -+ return 0; -+} -+ -+/* -+ * the function to enable or disable the udc -+ * @is_on: 1,enable 0,disable -+ */ -+static int akudc_pullup(struct usb_gadget *gadget, int is_on) -+{ -+ if (is_on) -+ set_condition(&udc_clk); -+ else -+ clear_condition(&udc_clk); -+ return 0; -+} -+ -+/* the function is not used */ -+static int akudc_vbus_session(struct usb_gadget *gadget, int is_active) -+{ -+ dbg(""); -+ return 0; -+} -+ -+/* -+ * the function set the device power status -+ * @value: 1,selfpowered 0,powered by usb cable -+ */ -+static int akudc_set_selfpowered(struct usb_gadget *gadget, int value) -+{ -+ struct akudc_udc *udc = &controller; -+ -+ dbg("%d", value); -+ if (value) -+ udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED); -+ else -+ udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); -+ -+ return 0; -+} -+ -+static int akudc_start(struct usb_gadget_driver *driver, -+ int (*bind)(struct usb_gadget *)); -+static int akudc_stop(struct usb_gadget_driver *driver); -+ -+/* the operation struct for gadget */ -+static const struct usb_gadget_ops akudc_udc_ops = { -+ .get_frame = akudc_get_frame, -+ .wakeup = akudc_wakeup, -+ .set_selfpowered = akudc_set_selfpowered, -+ .vbus_session = akudc_vbus_session, -+ .pullup = akudc_pullup, -+ .start = akudc_start, -+ .stop = akudc_stop, -+}; -+ -+static void ep1_work(struct work_struct *work) -+{ -+ struct akudc_request *req = NULL; -+ struct akudc_udc *udc = &controller; -+ struct akudc_ep *ep = &udc->ep[1]; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ /* if the queue is not empty, get the head of the queue */ -+ if (!list_empty(&ep->queue)){ -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ } -+ -+ if (req) -+ req->status = write_ep1_fifo(ep, req); -+ else -+ dbg("something happend"); -+ local_irq_restore(flags); -+} -+ -+static void ep2_work(struct work_struct *work) -+{ -+ struct akudc_request *req = NULL; -+ struct akudc_udc *udc = &controller; -+ struct akudc_ep *ep = &udc->ep[2]; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ /* if the queue is not empty, get the head of the queue */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) -+ req->status = write_ep2_fifo(ep, req); -+ else -+ dbg("something happend"); -+ local_irq_restore(flags); -+} -+ -+static void ep3_work(struct work_struct *work) -+{ -+ struct akudc_request *req = NULL; -+ struct akudc_udc *udc = &controller; -+ struct akudc_ep *ep = &udc->ep[3]; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ /* if the queue is not empty, get the head of the queue */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) -+ req->status = read_ep3_fifo(ep, req); -+ else -+ dbg("something happend"); -+ local_irq_restore(flags); -+} -+ -+static void ep4_work(struct work_struct *work) -+{ -+ struct akudc_request *req = NULL; -+ struct akudc_udc *udc = &controller; -+ struct akudc_ep *ep = &udc->ep[4]; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ /* if the queue is not empty, get the head of the queue */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) -+ req->status = write_ep4_fifo(ep, req); -+ else -+ dbg("something happend"); -+ local_irq_restore(flags); -+} -+ -+static void ep5_work(struct work_struct *work) -+{ -+ struct akudc_request *req = NULL; -+ struct akudc_udc *udc = &controller; -+ struct akudc_ep *ep = &udc->ep[5]; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ /* if the queue is not empty, get the head of the queue */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) -+ req->status = read_ep5_fifo(ep, req); -+ else -+ dbg("something happend"); -+ local_irq_restore(flags); -+} -+ -+/* -+ * enable the ep, include enable the irq for the ep -+ * init the fifo and toggle for ep -+ * @ep: the ep which is enable -+ * @desc: the ep descriptor -+ */ -+static int akudc_ep_enable(struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct akudc_ep *ep = container_of(_ep, struct akudc_ep, ep); -+ struct akudc_udc *udc = ep->udc; -+ int tmp, maxpacket; -+ unsigned long flags; -+ -+ if (!_ep || !ep -+ || !desc || ep->desc -+ || _ep->name == ep0name -+ || desc->bDescriptorType != USB_DT_ENDPOINT -+ || (maxpacket = usb_endpoint_maxp(desc)) == 0 -+ || maxpacket > ep->maxpacket) { -+ dbg("bad ep or descriptor"); -+ dbg("%p, %p, %p, %p", _ep, ep, desc, ep->desc); -+ return -EINVAL; -+ } -+ -+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { -+ dbg("bogus udcice state\n"); -+ return -ESHUTDOWN; -+ } -+ -+ local_irq_save (flags); -+ -+ tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ switch (tmp) { -+ case USB_ENDPOINT_XFER_CONTROL: -+ dbg("only one control endpoint\n"); -+ return -EINVAL; -+ case USB_ENDPOINT_XFER_INT: -+ if (maxpacket > EP1_FIFO_SIZE) -+ dbg("maxpacket too large"); -+ break; -+ case USB_ENDPOINT_XFER_BULK: -+ switch (maxpacket) { -+ case 8: -+ case 16: -+ case 32: -+ case 64: -+ case 512: /* for usb20 */ -+ _ep->maxpacket = maxpacket & 0x7ff; -+ break; -+ default: -+ dbg("bogus maxpacket %d\n", maxpacket); -+ return -EINVAL; -+ } -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ dbg("USB_ENDPOINT_XFER_ISOC"); -+ break; -+ } -+ ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; -+ ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); -+ -+ ep->stopped = 0; -+ ep->desc = (struct usb_endpoint_descriptor *)desc; -+ -+ dbg("%s, maxpacket(%d), desc->bEndpointAddress (0x%x) is_in(%d)", -+ _ep->name, maxpacket, desc->bEndpointAddress, ep->is_in); -+ -+ if (!strcmp(_ep->name, udc->ep[1].ep.name)) { /* ep1 -- int */ -+ dbg(""); -+ udc_writeb(USB_EP_INDEX, 1); -+ udc_writeb(USB_CTRL_1, (1<<3) | (1<<6)); // flush fifo and clear toggle -+ udc_writeb(USB_CTRL_1_2, 1<<5); //set tx -+ udc_writew(USB_TX_MAX, 64); //set maxpacket size -+ } else if (!strcmp(_ep->name, udc->ep[2].ep.name)) { /* ep2 -- tx */ -+ dbg(""); -+ udc_writeb(USB_EP_INDEX, 2); -+ udc_writeb(USB_CTRL_1, (1<<3) | (1<<6)); // flush fifo and clear toggle -+ udc_writeb(USB_CTRL_1_2, 1<<5); //set tx -+ udc_writew(USB_TX_MAX, 512); //set maxpacket size -+ } else if (!strcmp(_ep->name, udc->ep[3].ep.name)){ /* ep3 -- rx */ -+ udc_writeb(USB_EP_INDEX, 3); -+ udc_writeb(USB_CTRL_1, 1<<6); // clear tx toggle -+ udc_writeb(USB_CTRL_1_2, 0); // set rx -+ udc_writew(USB_RX_MAX, 512); // set maxpacket size -+ udc_writeb(USB_CTRL_2, udc_readb(USB_CTRL_2) & ~(0x1)); -+ udc_writeb(USB_CTRL_2, (1<<4) | (1<<7)); // flush fifo and clear rx toggle -+ udc_writeb(USB_CTRL_2_2, 0); //enable rx endpint -+ } else if (!strcmp(_ep->name, udc->ep[4].ep.name)) { /* ep4 -- tx */ -+ udc_writeb(USB_EP_INDEX, 4); -+ udc_writeb(USB_CTRL_1, (1<<3) | (1<<6)); // flush fifo and clear toggle -+ udc_writeb(USB_CTRL_1_2, 1<<5); //set tx -+ udc_writew(USB_TX_MAX, 512); //set maxpacket size -+ } else if (!strcmp(_ep->name, udc->ep[5].ep.name)){ /* ep5 -- rx */ -+ udc_writeb(USB_EP_INDEX, 5); -+ udc_writeb(USB_CTRL_1, 1<<6); // clear tx toggle -+ udc_writeb(USB_CTRL_1_2, 0); // set rx -+ udc_writew(USB_RX_MAX, 512); //set maxpacket size -+ udc_writeb(USB_CTRL_2, udc_readb(USB_CTRL_2) & ~(0x1)); -+ udc_writeb(USB_CTRL_2, (1<<4) | (1<<7)); // flush fifo and clear rx toggle -+ udc_writeb(USB_CTRL_2_2, 0); //enable rx endpint -+ } else { -+ printk("Invalid ep"); -+ return -EINVAL; -+ } -+ -+ ep_irq_enable(_ep); -+ local_irq_restore (flags); -+ -+ return 0; -+} -+ -+/* -+ * disable the ep, include disable the irq for the ep -+ * @ep: the ep which is disable -+ */ -+static int akudc_ep_disable (struct usb_ep * _ep) -+{ -+ struct akudc_ep *ep = container_of(_ep, struct akudc_ep, ep); -+ struct akudc_request *req; -+ unsigned long flags; -+ -+ if (!_ep || !ep->desc) { -+ dbg("%s not enabled\n", -+ _ep ? ep->ep.name : NULL); -+ return -EINVAL; -+ } -+ -+ local_irq_save(flags); -+ dbg("%s", _ep->name); -+ ep->desc = NULL; -+ ep->stopped = 1; -+ -+ /* -+ * delete every req in the endpoint queue -+ * dont it by status -ESHUTDOWN -+ */ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ done(ep, req, -ESHUTDOWN); -+ } -+ ep_irq_disable(_ep); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+/* -+ * alloc the request for function driver -+ * @ep: the ep which the request deal with -+ */ -+static struct usb_request * -+ akudc_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -+{ -+ struct akudc_request *req; -+ -+ dbg("%s", _ep->name); -+ req = kzalloc(sizeof (struct akudc_request), gfp_flags); -+ if (!req) -+ return NULL; -+ -+ INIT_LIST_HEAD(&req->queue); -+ return &req->req; -+} -+ -+/* -+ * free the request for function driver -+ * @ep: the ep which the request deal with -+ */ -+static void akudc_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct akudc_request *req; -+ -+ dbg("%s", _ep->name); -+ req = container_of(_req, struct akudc_request, req); -+ WARN_ON(!list_empty(&req->queue)); -+ kfree(req); -+} -+ -+/* -+ * add the request to the ep request queue -+ * @ep: the ep which the request deal with -+ */ -+static int akudc_ep_queue(struct usb_ep *_ep, -+ struct usb_request *_req, gfp_t gfp_flags) -+{ -+ struct akudc_request *req; -+ struct akudc_ep *ep; -+ struct akudc_udc *udc; -+ int status = 0; -+ unsigned long flags; -+ -+ req = container_of(_req, struct akudc_request, req); -+ ep = container_of(_ep, struct akudc_ep, ep); -+ -+ if (!_ep || (!ep->desc && ep->ep.name != ep0name)) { -+ dbg("invalid ep\n"); -+ return -EINVAL; -+ } -+ -+ udc = ep->udc; -+ if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { -+ printk("invalid device\n"); -+ return -EINVAL; -+ } -+ -+ local_irq_save(flags); -+ -+ if (!_req || !_req->complete -+ || !_req->buf || !list_empty(&req->queue)) { -+ printk("%s invalid request\n", _ep->name); -+ local_irq_restore(flags); -+ return -EINVAL; -+ } -+ -+ _req->status = -EINPROGRESS; -+ _req->actual = 0; -+ -+ dbg("%s queue is_in(%d)", ep->ep.name, ep->is_in); -+ -+ /* -+ * if the queue is empty and the ep is not stopped, -+ * do the request -+ */ -+ if (list_empty(&ep->queue) && !ep->stopped) { -+ if (ep->ep.name == ep0name) { -+ udc_writeb(USB_EP_INDEX, 0); -+ -+ switch (udc->ep0state) { -+ case EP0_IN_DATA_PHASE: -+ if ((udc_readb(USB_CTRL_1) & (1 << 1)) == 0 -+ && write_ep0_fifo(ep, req)) { -+ udc->ep0state = EP0_IDLE; -+ req = NULL; -+ } -+ break; -+ -+ case EP0_OUT_DATA_PHASE: -+ if ((!_req->length) || -+ ((udc_readb(USB_CTRL_1) & (1 << 0)) -+ && read_ep0_fifo(ep, req))) { -+ udc->ep0state = EP0_IDLE; -+ req = NULL; -+ } -+ break; -+ -+ default: -+ local_irq_restore(flags); -+ return -EL2HLT; -+ } -+ if (req) -+ list_add_tail(&req->queue, &ep->queue); -+ } else { -+ list_add_tail(&req->queue, &ep->queue); -+ if (!strcmp(_ep->name, udc->ep[1].ep.name)) { /* ep1 */ -+ dbg("ep1"); -+ //status = write_ep1_fifo(ep, req); -+ udc_writeb(USB_EP_INDEX, 1); -+ if ((udc_readb(USB_CTRL_1) & 1) == 0) -+ queue_work(ep_wqueue, &ep->work); -+ } else if (!strcmp(_ep->name, udc->ep[2].ep.name)) { /* ep2 */ -+ udc_writeb(USB_EP_INDEX, 2); -+ if ((udc_readb(USB_CTRL_1) & 1) == 0) -+ queue_work(ep_wqueue, &ep->work); -+ } else if (!strcmp(_ep->name, udc->ep[3].ep.name)){ /* ep3 */ -+ udc_writeb(USB_EP_INDEX, 3); -+ if (udc_readb(USB_CTRL_2) & 1) -+ queue_work(ep_wqueue, &ep->work); -+ } else if (!strcmp(_ep->name, udc->ep[4].ep.name)) { /* ep4 */ -+ udc_writeb(USB_EP_INDEX, 4); -+ if ((udc_readb(USB_CTRL_1) & 1) == 0) -+ queue_work(ep_wqueue, &ep->work); -+ } else if (!strcmp(_ep->name, udc->ep[5].ep.name)){ /* ep5 */ -+ udc_writeb(USB_EP_INDEX, 5); -+ if (udc_readb(USB_CTRL_2) & 1) -+ queue_work(ep_wqueue, &ep->work); -+ } else { -+ printk("Invalid ep"); -+ status = -EINVAL; -+ goto stall; -+ } -+ } -+ } else { -+ /* -+ * if the queue is not empty, add the req to the queue only -+ */ -+ status = 0; -+ list_add_tail(&req->queue, &ep->queue); -+ dbg("waiting for %s int", ep->ep.name); -+ } -+ -+stall: -+ local_irq_restore(flags); -+ /* return (status < 0) ? status : 0; */ -+ return status; -+} -+ -+/* -+ * delete the request from the ep request queue -+ * @ep: the ep which the request deal with -+ */ -+static int akudc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct akudc_ep *ep; -+ struct akudc_request *req; -+ unsigned long flags; -+ struct akudc_udc *udc = &controller; -+ -+ dbg("dequeue"); -+ -+ if (!udc->driver) -+ return -ESHUTDOWN; -+ -+ ep = container_of(_ep, struct akudc_ep, ep); -+ if (!_ep || !_req) -+ return -EINVAL; -+ -+ local_irq_save(flags); -+ /* find the req from head */ -+ list_for_each_entry (req, &ep->queue, queue) { -+ if (&req->req == _req) -+ break; -+ } -+ /* if cannot find, return error */ -+ if (&req->req != _req) { -+ local_irq_restore(flags); -+ return -EINVAL; -+ } -+ /* delete the req and set the req status -ECONNRESET */ -+ done(ep, req, -ECONNRESET); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+/* -+ * set or clear the stall function for ep -+ * @ep: which ep is being setting -+ * @value: 1 stall, 0 clear stall -+ */ -+static int akudc_ep_set_halt(struct usb_ep *_ep, int value) -+{ -+ struct akudc_ep *ep = container_of(_ep, struct akudc_ep, ep); -+ unsigned int csr = 0; -+ unsigned long flags; -+ struct akudc_udc *udc = &controller; -+ -+ if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { -+ dbg("inval 2"); -+ return -EINVAL; -+ } -+ -+ local_irq_save (flags); -+ -+ if ((ep->ep.name == ep0name) && value) { -+ udc_writeb(USB_EP_INDEX, 0); -+ udc_writeb(USB_CTRL_1, 1<<5); -+ udc_writeb(USB_CTRL_1, 1<<6 | 1<<3); -+ }else if(!strcmp(ep->ep.name, udc->ep[1].ep.name)){/* ep1 */ -+ udc_writeb(USB_EP_INDEX, 1); -+ csr = udc_readw(USB_CTRL_1); -+ if (value) -+ udc_writew(USB_CTRL_1, csr | 1<<4); -+ else { -+ csr &= ~(1<<4 | 1<<5); -+ udc_writew(USB_CTRL_1, csr); -+ csr |= 1<<6; -+ udc_writew(USB_CTRL_1, csr); -+ } -+ } else if (ep->is_in) { /* ep2 or ep4*/ -+ if (!strcmp(ep->ep.name, udc->ep[2].ep.name)) -+ udc_writeb(USB_EP_INDEX, 2); -+ else -+ udc_writeb(USB_EP_INDEX, 4); -+ -+ csr = udc_readw(USB_CTRL_1); -+ if (value) -+ udc_writew(USB_CTRL_1, csr | 1<<4); -+ else { -+ csr &= ~(1<<4 | 1<<5); -+ udc_writew(USB_CTRL_1, csr); -+ csr |= 1<<6; -+ udc_writew(USB_CTRL_1, csr); -+ } -+ } else { /* ep3 or ep5*/ -+ if (!strcmp(ep->ep.name, udc->ep[3].ep.name)) -+ udc_writeb(USB_EP_INDEX, 3); -+ else -+ udc_writeb(USB_EP_INDEX, 5); -+ -+ csr = udc_readw(USB_CTRL_2); -+ if (value) -+ udc_writew(USB_CTRL_2, csr | 1<<5); -+ else { -+ csr &= ~(1<<5 | 1<<6); -+ udc_writew(USB_CTRL_2, csr); -+ csr |= 1<<7; -+ udc_writew(USB_CTRL_2, csr); -+ } -+ } -+ -+ ep->stopped= value ? 1 : 0; -+ local_irq_restore (flags); -+ -+ return 0; -+} -+ -+/* the operation struct for ep */ -+static const struct usb_ep_ops akudc_ep_ops = { -+ .enable = akudc_ep_enable, -+ .disable = akudc_ep_disable, -+ .alloc_request = akudc_ep_alloc_request, -+ .free_request = akudc_ep_free_request, -+ .queue = akudc_ep_queue, -+ .dequeue = akudc_ep_dequeue, -+ .set_halt = akudc_ep_set_halt, -+ // there's only imprecise fifo status reporting -+}; -+ -+static void nop_release(struct device *dev) -+{ -+ /* nothing to free */ -+} -+ -+/* the core struct for udc that include many important struct */ -+static struct akudc_udc controller = { -+ /* the gadget , include ep0 info*/ -+ .gadget = { -+ .ops = &akudc_udc_ops, -+ .ep0 = &controller.ep[0].ep, -+ .name = driver_name, -+ .dev = { -+ .init_name = "gadget", -+ .release = nop_release, -+ } -+ }, -+ /* the array of endpoint */ -+ .ep[0] = { -+ .ep = { -+ .name = ep0name,//ep_name[0], -+ .ops = &akudc_ep_ops, -+ }, -+ .udc = &controller, -+ .maxpacket = EP0_FIFO_SIZE, -+ }, -+ .ep[1] = { -+ .ep = { -+ .name = "ep1-int",//ep_name[1], -+ .ops = &akudc_ep_ops, -+ }, -+ .udc = &controller, -+ .maxpacket = EP1_FIFO_SIZE, -+ }, -+ .ep[2] = { -+ .ep = { -+ .name = "ep2in-bulk",//ep_name[2], -+ .ops = &akudc_ep_ops, -+ }, -+ .udc = &controller, -+ .maxpacket = EP2_FIFO_SIZE, -+ }, -+ .ep[3] = { -+ .ep = { -+ /* could actually do bulk too */ -+ .name = "ep3out-bulk",//ep_name[3], -+ .ops = &akudc_ep_ops, -+ }, -+ .udc = &controller, -+ .maxpacket = EP3_FIFO_SIZE, -+ }, -+ .ep[4] = { -+ .ep = { -+ .name = "ep4in-bulk",//ep_name[4], -+ .ops = &akudc_ep_ops, -+ }, -+ .udc = &controller, -+ .maxpacket = EP4_FIFO_SIZE, -+ }, -+ .ep[5] = { -+ .ep = { -+ .name = "ep5out-bulk",//ep_name[5], -+ .ops = &akudc_ep_ops, -+ }, -+ .udc = &controller, -+ .maxpacket = EP5_FIFO_SIZE, -+ }, -+}; -+ -+/** -+ * akudc_udc_get_status - process request GET_STATUS -+ * @udc: The device state -+ * @ctrl: USB control request -+ */ -+static int akudc_udc_get_status(struct akudc_udc *udc, -+ struct usb_ctrlrequest *ctrl) -+{ -+ u16 status = 0; -+ u8 ep_num = ctrl->wIndex & 0x7F; -+ u8 is_in = ctrl->wIndex & USB_DIR_IN; -+ -+ switch (ctrl->bRequestType & USB_RECIP_MASK) { -+ case USB_RECIP_DEVICE: -+ status = udc->devstatus; -+ break; -+ -+ case USB_RECIP_INTERFACE: -+ /* currently, the data result should be zero */ -+ break; -+ -+ case USB_RECIP_ENDPOINT: -+ if (ep_num > 5 || ctrl->wLength > 2) -+ return 1; -+ -+ if (ep_num == 0) { -+ udc_writeb(USB_EP_INDEX, 0); -+ status = udc_readb(USB_CTRL_1); -+ status = status & (1<<5); -+ } else { -+ udc_writeb(USB_EP_INDEX, ep_num); -+ if (is_in) { -+ status = udc_readb(USB_CTRL_1); -+ status = status & (1<<4); -+ } else { -+ status = udc_readb(USB_CTRL_2); -+ status = status & (1<<5); -+ } -+ } -+ -+ status = status ? 1 : 0; -+ break; -+ default: -+ return 1; -+ } -+ -+ udc_writeb(USB_EP0_FIFO, status & 0xff); -+ udc_writeb(USB_EP0_FIFO, status >> 8); -+ -+ udc_writel(USB_EP0_NUM, 2); /* 7bits */ -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<1); -+ -+ udc->ep0state = EP0_END_XFER; -+ -+ return 0; -+} -+ -+/* function for ep0 setup phase */ -+static void akudc_udc_handle_ep0_idle(struct akudc_udc *udc, -+ struct akudc_ep *ep, u32 ep0csr) -+{ -+ struct usb_ctrlrequest crq; -+ int i, len, ret, tmp, timeout; -+ unsigned char *buf; -+ -+ /* start control request? */ -+ if (!(ep0csr & 1)) -+ return; -+ -+ len = udc_readw(USB_EP_COUNT); -+ buf = (unsigned char *)&crq; -+ if (len > sizeof(struct usb_ctrlrequest)) -+ len = sizeof(struct usb_ctrlrequest); -+ for (i = 0; i < len; i++) { -+ /* read the setup data from ep0 fifo */ -+ buf[i] = udc_readb(USB_EP0_FIFO); -+ } -+ if (len != sizeof(crq)) { -+ dbg("setup begin: fifo READ ERROR" -+ " wanted %d bytes got %d. Stalling out...", -+ sizeof(crq), len); -+ udc_writeb(USB_CTRL_1, 1<<5); -+ return; -+ } -+ -+ dbg("bRequest = %d bRequestType %d wLength = %d", -+ crq.bRequest, crq.bRequestType, crq.wLength); -+ -+ /* cope with automagic for some standard requests. */ -+ udc->req_std = (crq.bRequestType & USB_TYPE_MASK) -+ == USB_TYPE_STANDARD; -+ udc->req_config = 0; -+ udc->req_pending = 1; -+ -+ switch (crq.bRequest) { -+ case USB_REQ_SET_CONFIGURATION: -+ if (crq.bRequestType == USB_RECIP_DEVICE) { -+ udc->req_config = 1; -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<6); -+ } -+ break; -+ -+ case USB_REQ_SET_INTERFACE: -+ if (crq.bRequestType == USB_RECIP_INTERFACE) { -+ udc->req_config = 1; -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<6); -+ } -+ break; -+ -+ case USB_REQ_SET_ADDRESS: -+ if (crq.bRequestType == USB_RECIP_DEVICE) { -+ tmp = crq.wValue & 0x7F; -+ udc_writeb(USB_CTRL_1, 0x1<<3 | 0x1<<6); -+ timeout = 20000; -+ /* waiting for next interrupt */ -+ while (!(udc_readb(USB_INTERRUPT_1) & 0x1) && timeout) {timeout--;} -+ udc_writeb(USB_FUNCTION_ADDR, tmp); -+ udc->addr = tmp; -+ return; -+ } -+ break; -+ -+ case USB_REQ_GET_STATUS: -+ udc_writeb(USB_CTRL_1, 0x1<<6); -+ -+ if (udc->req_std) { -+ if (!akudc_udc_get_status(udc, &crq)) { -+ return; -+ } -+ } -+ break; -+ -+ case USB_REQ_CLEAR_FEATURE: -+ udc_writeb(USB_CTRL_1, 0x1<<6); -+ -+ if (crq.bRequestType != USB_RECIP_ENDPOINT) -+ break; -+ -+ if (crq.wValue != USB_ENDPOINT_HALT || crq.wLength != 0) -+ break; -+ -+ akudc_ep_set_halt(&udc->ep[crq.wIndex & 0x7f].ep, 0); -+ udc_writeb(USB_CTRL_1, 0x1<<6 | 0x1<<3); -+ -+ return; -+ -+ case USB_REQ_SET_FEATURE: -+ udc_writeb(USB_CTRL_1, 0x1<<6); -+ -+ if (crq.bRequestType != USB_RECIP_ENDPOINT) -+ break; -+ -+ if (crq.wValue != USB_ENDPOINT_HALT || crq.wLength != 0) -+ break; -+ -+ akudc_ep_set_halt(&udc->ep[crq.wIndex & 0x7f].ep, 1); -+ udc_writeb(USB_CTRL_1, 0x1<<6 | 0x1<<3); -+ return; -+ -+ default: -+ udc_writeb(USB_CTRL_1, 0x1<<6); -+ break; -+ } -+ -+ /* set ep0state according to the command */ -+ if (crq.bRequestType & USB_DIR_IN) -+ udc->ep0state = EP0_IN_DATA_PHASE; -+ else -+ udc->ep0state = EP0_OUT_DATA_PHASE; -+ -+ /* call the function drvier setup */ -+ ret = udc->driver->setup(&udc->gadget, &crq); -+ /* -+ * if the setup failed, sent stall ep0 -+ */ -+ if (ret < 0) { -+ if (udc->req_config) { -+ dbg("config change %02x fail %d?", -+ crq.bRequest, ret); -+ return; -+ } -+ -+ if (ret == -EOPNOTSUPP) -+ dbg("Operation not supported"); -+ else -+ dbg("udc->driver->setup failed. (%d)", ret); -+ -+ udc_writeb(USB_CTRL_1, 1<<5); -+ udc_writeb(USB_CTRL_1, 1<<3 | 1<<6); -+ udc->ep0state = EP0_IDLE; -+ /* deferred i/o == no response yet */ -+ } else if (udc->req_pending) { -+ dbg("dev->req_pending... what now?"); -+ udc->req_pending=0; -+ } -+} -+ -+/* deal with interrupt for ep0 */ -+static void handle_ep0(struct akudc_udc *udc) -+{ -+ int csr, error = 0; -+ struct akudc_ep *ep0 = &udc->ep[0]; -+ struct akudc_request *req = NULL; -+ -+ if (!list_empty(&ep0->queue)) -+ req = list_entry(ep0->queue.next, struct akudc_request, queue); -+ -+ udc_writeb(USB_EP_INDEX, 0); -+ csr = udc_readb(USB_CTRL_1); -+ dbg("csr(0x%x)", csr); -+ -+ if (csr & 0x1<<3) { -+ dbg("data end"); -+ } -+ if (csr & 0x1<<4) { -+ dbg("A control transaction ends before the DataEnd bit has been set"); -+ udc_writeb(USB_CTRL_1, 0x1<<7); -+ /* do something else? */ -+ udc->ep0state = EP0_IDLE; -+ error = 1; -+ } -+ if (csr & 0x1<<2) { -+ udc_writeb(USB_CTRL_1, udc_readb(USB_CTRL_1) & ~(1 << 2)); -+ udc->ep0state = EP0_IDLE; -+ error = 1; -+ } -+ switch (udc->ep0state) { -+ case EP0_IDLE: -+ akudc_udc_handle_ep0_idle(udc, ep0, csr); -+ break; -+ -+ case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ -+ dbg("EP0_IN_DATA_PHASE ... what now?"); -+ if (!(csr & (1<<1)) && req && error == 0) -+ write_ep0_fifo(ep0, req); -+ break; -+ -+ case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ -+ dbg("EP0_OUT_DATA_PHASE ... what now?"); -+ if ((csr & (1<<0)) && req) -+ read_ep0_fifo(ep0, req); -+ break; -+ -+ case EP0_END_XFER: -+ dbg("EP0_END_XFER ... what now?"); -+ udc->ep0state = EP0_IDLE; -+ break; -+ -+ case EP0_STALL: -+ dbg("EP0_STALL ... what now?"); -+ udc->ep0state = EP0_IDLE; -+ break; -+ } -+} -+ -+/* not ep0 */ -+static void handle_ep(struct akudc_ep *ep) -+{ -+ struct akudc_request *req; -+ struct akudc_udc *udc = ep->udc; -+ unsigned int csr; -+ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, -+ struct akudc_request, queue); -+ else { -+ dbg("%s: no req waiting", ep->ep.name); -+ req = NULL; -+ } -+ -+ if (!strcmp(ep->ep.name, udc->ep[1].ep.name)) { /* ep1 */ -+ dbg("ep1"); -+ udc_writeb(USB_EP_INDEX, 1); -+ -+ /* read the epx status */ -+ csr = udc_readb(USB_CTRL_1); -+ dbg("ep1 csr(0x%x), req(0x%p)", csr, req); -+ -+ if (csr & 0x1<<2) { /* clear underrun */ -+ udc_writeb(USB_CTRL_1, csr & ~(0x1<<2)); -+ } -+ if (csr & 0x1<<5) { /* clear sentstall */ -+ udc_writeb(USB_CTRL_1, csr & ~(0x1<<5)); -+ return; -+ } -+ -+ if (req) { -+ /* -+ * if the current req is complete, done it with status 0 -+ * and if the next req is being, and the epx can be written -+ * data, do it with work queue -+ * else do the current req with work queue if the epx can be written -+ */ -+ if (ep->done) { -+ done(ep, req, 0); -+ if (!list_empty(&ep->queue)) { -+ dbg("do next queue"); -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ if ((csr & 1) == 0) -+ queue_work(ep_wqueue, &ep->work); -+ } -+ } else { -+ if ((csr & 1) == 0) -+ queue_work(ep_wqueue, &ep->work); -+ } -+ -+ } -+ } else if (ep->is_in) { /* ep2 or ep4*/ -+ -+ if (!strcmp(ep->ep.name, udc->ep[2].ep.name)) -+ udc_writeb(USB_EP_INDEX, 2); -+ else -+ udc_writeb(USB_EP_INDEX, 4); -+ -+ /* read the epx status */ -+ csr = udc_readb(USB_CTRL_1); -+ dbg("ep2 or ep4 csr(0x%x), req(0x%p)", csr, req); -+ -+ /* udc_writeb(USB_CTRL_1, 0x1); */ -+ if (csr & 0x1<<2) { /* clear underrun */ -+ udc_writeb(USB_CTRL_1, csr & ~(0x1<<2)); -+ } -+ if (csr & 0x1<<5) { /* clear sentstall */ -+ udc_writeb(USB_CTRL_1, csr & ~(0x1<<5)); -+ return; -+ } -+ -+ if (req) { -+ /* -+ * if the current req is complete, done it with status 0 -+ * and if the next req is being, and the epx can be written -+ * data, do it with work queue -+ * else do the current req with work queue if the epx can be written -+ */ -+ if (ep->done) { -+ done(ep, req, 0); -+ if (!list_empty(&ep->queue)) { -+ dbg("do next queue"); -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ if ((csr & 1) == 0) -+ queue_work(ep_wqueue, &ep->work); -+ } -+ } else { -+ if ((csr & 1) == 0) -+ queue_work(ep_wqueue, &ep->work); -+ } -+ -+ } -+ } else { /* ep3 or ep 5*/ -+ if (!strcmp(ep->ep.name, udc->ep[3].ep.name)) -+ udc_writeb(USB_EP_INDEX, 3); -+ else -+ udc_writeb(USB_EP_INDEX, 5); -+ -+ /* read the epx status */ -+ csr = udc_readb(USB_CTRL_2); -+ dbg("ep3 or ep5 csr(0x%x)", csr); -+ -+ if (csr & 0x1<<6) { /* clear sentstall */ -+ udc_writeb(USB_CTRL_2, csr & ~(0x1<<6)); -+ } -+ /* -+ * if the req is being and the data come to the endpoint fifo -+ * do the current req with work queue -+ */ -+ if (req && (csr & 0x1<<0)) -+ queue_work(ep_wqueue, &ep->work); -+ } -+} -+ -+/* -+ * the function execute when the suspend signal come -+ * or the system is being suspend -+ */ -+static void udc_disconnect(struct akudc_udc *udc) -+{ -+ struct usb_gadget_driver *driver = udc->driver; -+ int i; -+ -+ if (udc->gadget.speed == USB_SPEED_UNKNOWN) -+ driver = NULL; -+ -+ for (i = 0; i < ENDPOINTS_NUM; i++) { -+ struct akudc_ep *ep = &udc->ep[i]; -+ struct akudc_request *req; -+ -+ /* sign every endpoint stop */ -+ ep->stopped = 1; -+ -+ // terminer chaque requete dans la queue -+ if (list_empty(&ep->queue)) -+ continue; -+ -+ /* -+ * delete every req in every endpoint queue -+ * dont it by status -ESHUTDOWN -+ */ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ done(ep, req, -ESHUTDOWN); -+ } -+ } -+ -+ /* if the driver exist, call the function drvier disconnect */ -+ if (driver) -+ driver->disconnect(&udc->gadget); -+ -+ /* init the udc */ -+ udc_reinit(udc); -+} -+ -+#if 0 -+static void akudc_udc_fun(void *data) -+{ -+ struct akudc_udc *udc = data; -+ -+ msleep(500); -+ clk_enable(udc->clk); -+ udc_reg_writel(USB_OP_MOD_REG, 0x6, 3, 0); -+ udc_writeb(USB_POWER_CTRL, 0x1<<5); -+} -+#endif -+ -+static void akudc_conctrol_reset(struct akudc_udc *udc) -+{ -+ // reset the udc controller module -+ ak_soft_reset(AK_SRESET_USBHS); -+ REG32(AK_VA_SYSCTRL + 0x58) &= ~(0xff << 0); -+} -+ -+/* the function execute when the reset signal come */ -+static void udc_reset(struct akudc_udc *udc) -+{ -+ int i ,temp; -+ -+ udc_writeb(USB_FUNCTION_ADDR, 0); // set the usb device addr 0 -+ udc_writeb(USB_INTERRUPT_USB, ~(0x1<<3)); // clear SOF interrupt -+ udc_writeb(USB_INTERRUPT_TX, 0x1<<0); // enable ep0 interrupt and disable other tx endpoint -+ udc_writeb(USB_INTERRUPT_RX, 0); // disable rx endpoint inttrupt -+ -+ /* negotiated high speed */ -+ if ((udc_readb(USB_POWER_CTRL) & (0x1 << 4)) == (0x1 << 4)) { -+ udc_writel(USB_MODE_STATUS, udc_readl(USB_MODE_STATUS) & (~0x1)); -+ /* enable high speed for udc */ -+ udc_writeb(USB_POWER_CTRL, 0x1<<5); -+ udc->gadget.speed = USB_SPEED_HIGH; -+ udc->high_speed = 1; -+ } else { /* negotiated full speed */ -+ udc_writeb(USB_POWER_CTRL, 0); -+ udc_writel(USB_MODE_STATUS, udc_readl(USB_MODE_STATUS) | 0x1); -+ udc->gadget.speed = USB_SPEED_FULL; -+ udc->high_speed = 0; -+ } -+ -+ /* read and clear the common interrupt status */ -+ temp = udc_readw(USB_INTERRUPT_COMM); -+ /* read and clear the ep0 and all tx ep interrupt status */ -+ temp = udc_readw(USB_INTERRUPT_1); -+ /* read and clear all rx ep interrupt status */ -+ temp = udc_readw(USB_INTERRUPT_2); -+ -+ /* init the ep0 status */ -+ udc->ep0state = EP0_IDLE; -+ -+ for (i = 0; i < ENDPOINTS_NUM; i++) { -+ struct akudc_ep *ep = &udc->ep[i]; -+ struct akudc_request *req; -+ -+ if (list_empty(&ep->queue)) -+ continue; -+ -+ /* -+ * delete every req in every endpoint queue -+ * dont it by status -ECONNRESET -+ */ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ done(ep, req, -ECONNRESET); -+ } -+ } -+} -+ -+ -+/* the udc irq irqhandler */ -+static irqreturn_t udc_irqhandler(int irq, void *_udc) -+{ -+ struct akudc_udc *udc = _udc; -+ short status_1, status_2; -+ char status_int; -+ -+ status_int = udc_readb(USB_INTERRUPT_COMM); -+ if (status_int & 0x1<<2) { -+ /* dbg("status_int(0x%x), reset", status_int); */ -+ printk("\n\nstatus_int(0x%x), reset\n\n", status_int); -+ if (usb_detect) { -+ usb_detect = 0; -+ if (!udc->driver) { -+ panic("If you see this, come to find Zhang Jingyuan\n"); -+ akudc_disable(udc); -+ return IRQ_HANDLED; -+ } -+ } -+ udc_reset(udc); -+ goto done; -+ } else if(status_int & 0x1<<1) { /* resume */ -+ dbg("status_int(0x%x)", status_int); -+ goto done; -+ } else if(status_int & 0x1<<0) { /* suspend */ -+ dbg("status_int(0x%x)", status_int); -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ pm_power_off(); -+#endif -+#endif -+ udc_disconnect(udc); -+ goto done; -+ } -+ -+ status_1 = udc_readb(USB_INTERRUPT_1); -+ status_2 = udc_readb(USB_INTERRUPT_2); -+ /* ep0 */ -+ if (status_1 & 0x1<<0) { -+ handle_ep0(udc); -+ } -+ /* ep2 */ -+ if (status_1 & 0x1<<2) { -+ dbg("endpoint2"); -+ handle_ep(&udc->ep[2]); -+ } -+ /* ep4 */ -+ if (status_1 & 0x1<<4) { -+ dbg("endpoint4"); -+ handle_ep(&udc->ep[4]); -+ } -+ -+ /* ep1 */ -+ if (status_2 & 0x1<<1) { -+ dbg("endpoint 1"); -+ handle_ep(&udc->ep[1]); -+ } -+ /* ep3 */ -+ if (status_2 & 0x1<<3) { -+ dbg("endpoint3"); -+ handle_ep(&udc->ep[3]); -+ } -+ /* ep5 */ -+ if (status_2 & 0x1<<5) { -+ dbg("endpoint5"); -+ handle_ep(&udc->ep[5]); -+ } -+ -+done: -+ return IRQ_HANDLED; -+} -+ -+#if 0 -+/* the l2 buffer dma irqhandler */ -+static irqreturn_t udc_dmahandler(int irq, void *_udc) -+{ -+ struct akudc_request *req = NULL; -+ struct akudc_udc *udc = _udc; -+ struct akudc_ep *ep; -+ unsigned int is_done = 0; -+ -+ u32 usb_dma_int = udc_readl(USB_DMA_INTR); -+ -+ /* -+ * affirm which channel's interrupt -+ * channel1 -- ep2 -+ * channel2 -- ep3 -+ * channel3 -- ep4 -+ * channel4 -- ep5 -+ */ -+ if ((usb_dma_int & DMA_CHANNEL1_INT) == DMA_CHANNEL1_INT) { -+ ep = &udc->ep[2]; -+ udc_writeb(USB_EP_INDEX, USB_EP2_INDEX); -+ udc_writeb(USB_CTRL_1_2, USB_TXCSR_MODE1); -+ udc_writel(USB_DMA_CTRL1, 0); -+ -+ l2_combuf_wait_dma_finish(ep->l2_buf_id); -+ -+ /* if the queue is not empty, get the head req */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) { -+ /* -+ * judge whether the req is complete -+ * if it is, done the req and do next req transmission -+ * else do the current req transmission -+ */ -+ if (dma_tx == req->req.length - req->req.actual && !req->req.zero) -+ is_done = 1; -+ req->req.actual += dma_tx; -+ ep->done = is_done; -+ if (is_done) { -+ done(ep, req, 0); -+ if (!list_empty(&ep->queue)) { -+ dbg("do next queue"); -+ queue_work(ep_wqueue, &ep->work); -+ } -+ } else { -+ queue_work(ep_wqueue, &ep->work); -+ } -+ /* unmap the buffer */ -+ dma_unmap_single(NULL, phys_tx, dma_tx, DMA_TO_DEVICE); -+ dma_tx = 0; -+ -+ req->status = is_done; -+ } -+ else -+ dbg("something happend"); -+ } -+ -+ if ((usb_dma_int & DMA_CHANNEL2_INT) == DMA_CHANNEL2_INT) { -+ ep = &udc->ep[3]; -+ -+ udc_writeb(USB_EP_INDEX, USB_EP3_INDEX); -+ udc_writeb(USB_CTRL_2_2, 0); -+ udc_writel(USB_DMA_CTRL2, 0); -+ -+ l2_combuf_wait_dma_finish(ep->l2_buf_id); -+ -+ req = NULL; -+ is_done = 0; -+ /* if the queue is not empty, get the head req */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) { -+ /* -+ * judge whether the req is complete -+ * if it is, done the req -+ */ -+ if (dma_rx == req->req.length - req->req.actual) -+ is_done = 1; -+ req->req.actual += dma_rx; -+ ep->done = is_done; -+ if (is_done) -+ done(ep, req, 0); -+ /* unmap the buffer */ -+ dma_unmap_single(NULL, phys_rx, dma_rx, DMA_FROM_DEVICE); -+ req->status = is_done; -+ dma_rx = 0; -+ -+ flag = 0; -+ } -+ else -+ dbg("something happend"); -+ } -+ -+ if ((usb_dma_int & DMA_CHANNEL3_INT) == DMA_CHANNEL3_INT) { -+ ep = &udc->ep[4]; -+ udc_writeb(USB_EP_INDEX, USB_EP4_INDEX); -+ udc_writeb(USB_CTRL_1_2, USB_TXCSR_MODE1); -+ udc_writel(USB_DMA_CTRL1, 0); -+ -+ l2_combuf_wait_dma_finish(ep->l2_buf_id); -+ -+ /* if the queue is not empty, get the head req */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) { -+ /* -+ * judge whether the req is complete -+ * if it is, done the req and do next req transmission -+ * else do the current req transmission -+ */ -+ if (dma_tx == req->req.length - req->req.actual && !req->req.zero) -+ is_done = 1; -+ req->req.actual += dma_tx; -+ ep->done = is_done; -+ if (is_done) { -+ done(ep, req, 0); -+ if (!list_empty(&ep->queue)) { -+ dbg("do next queue"); -+ queue_work(ep_wqueue, &ep->work); -+ } -+ } else { -+ queue_work(ep_wqueue, &ep->work); -+ } -+ /* unmap the buffer */ -+ dma_unmap_single(NULL, phys_tx, dma_tx, DMA_TO_DEVICE); -+ dma_tx = 0; -+ -+ req->status = is_done; -+ } -+ else -+ dbg("something happend"); -+ } -+ -+ if ((usb_dma_int & DMA_CHANNEL4_INT) == DMA_CHANNEL4_INT) { -+ ep = &udc->ep[5]; -+ -+ udc_writeb(USB_EP_INDEX, USB_EP5_INDEX); -+ udc_writeb(USB_CTRL_2_2, 0); -+ udc_writel(USB_DMA_CTRL2, 0); -+ -+ l2_combuf_wait_dma_finish(ep->l2_buf_id); -+ -+ req = NULL; -+ is_done = 0; -+ /* if the queue is not empty, get the head req */ -+ if (!list_empty(&ep->queue)) -+ req = list_entry(ep->queue.next, struct akudc_request, queue); -+ -+ if (req) { -+ /* -+ * judge whether the req is complete -+ * if it is, done the req -+ */ -+ if (dma_rx == req->req.length - req->req.actual) -+ is_done = 1; -+ req->req.actual += dma_rx; -+ ep->done = is_done; -+ if (is_done) -+ done(ep, req, 0); -+ /* unmap the buffer */ -+ dma_unmap_single(NULL, phys_rx, dma_rx, DMA_FROM_DEVICE); -+ req->status = is_done; -+ dma_rx = 0; -+ -+ flag = 0; -+ } -+ else -+ dbg("something happend"); -+ } -+ -+ return IRQ_HANDLED; -+} -+#endif -+ -+void akudc_enable(struct akudc_udc *udc) -+{ -+ set_condition(&udc_clk); -+} -+ -+void akudc_disable(struct akudc_udc *udc) -+{ -+ clear_condition(&udc_clk); -+} -+ -+/* -+ * usb_gadget_register_driver for upper function driver -+ */ -+static int akudc_start(struct usb_gadget_driver *driver, -+ int (*bind)(struct usb_gadget *)) -+{ -+ struct akudc_udc *udc = &controller; -+ int retval; -+ -+ printk("akudc start() '%s'\n", driver->driver.name); -+ -+ if (!bind || !driver->setup -+ || driver->max_speed < USB_SPEED_FULL) { -+ printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", -+ bind, driver->setup, driver->max_speed); -+ return -EINVAL; -+ } -+ -+#if defined(MODULE) -+ if (!driver->unbind) { -+ printk(KERN_ERR "Invalid driver: no unbind method\n"); -+ return -EINVAL; -+ } -+#endif -+ -+ udc->driver = driver; -+ udc->gadget.dev.driver = &driver->driver; -+ -+ /* -+ * bind the gadget to function driver -+ * give the gadget point to function driver -+ */ -+ retval = bind(&udc->gadget); -+ if (retval) { -+ dbg("driver->bind() returned %d\n", retval); -+ udc->driver = NULL; -+ udc->gadget.dev.driver = NULL; -+ return retval; -+ } -+ -+ /* init work for every endpoint */ -+ INIT_WORK(&udc->ep[1].work, ep1_work); -+ INIT_WORK(&udc->ep[2].work, ep2_work); -+ INIT_WORK(&udc->ep[3].work, ep3_work); -+ INIT_WORK(&udc->ep[4].work, ep4_work); -+ INIT_WORK(&udc->ep[5].work, ep5_work); -+ -+ disable_irq(udc->mcu_irq); -+ akudc_enable(udc); -+ enable_irq(udc->mcu_irq); -+ -+ printk("binding gadget driver '%s'\n", driver->driver.name); -+ return 0; -+} -+ -+ -+/* -+ * usb_gadget_unregister_driver for upper function driver -+ */ -+static int akudc_stop(struct usb_gadget_driver *driver) -+{ -+ struct akudc_udc *udc = &controller; -+ -+ printk("akudc_stop() '%s'\n", driver->driver.name); -+ -+ if (!driver || driver != udc->driver || !driver->unbind) -+ return -EINVAL; -+ -+ /* report disconnect */ -+ if(driver->disconnect) -+ driver->disconnect(&udc->gadget); -+ -+ /* unbind the gadget for function driver */ -+ driver->unbind(&udc->gadget); -+ udc->gadget.dev.driver = NULL; -+ //udc->gadget.dev.driver_data = NULL; -+ udc->driver = NULL; -+ -+ disable_irq(udc->mcu_irq); -+ -+ akudc_disable(udc); -+ -+ /*cacel work for every endpoint */ -+ cancel_work_sync(&udc->ep[1].work); -+ cancel_work_sync(&udc->ep[2].work); -+ cancel_work_sync(&udc->ep[3].work); -+ cancel_work_sync(&udc->ep[4].work); -+ cancel_work_sync(&udc->ep[5].work); -+ -+ flush_workqueue(ep_wqueue); -+ -+ enable_irq(udc->mcu_irq); -+ -+ dbg("unbound from '%s'\n", driver->driver.name); -+ udc_reinit(udc); -+ return 0; -+} -+ -+/* reinit == restore initial software state */ -+static void udc_reinit(struct akudc_udc *udc) -+{ -+ u32 i; -+ -+ /* init non-ep0 endpint list and ep0 list */ -+ INIT_LIST_HEAD(&udc->gadget.ep_list); -+ INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); -+ udc->ep0state = EP0_IDLE; -+ -+ for (i = 0; i < ENDPOINTS_NUM; i++) { -+ struct akudc_ep *ep = &udc->ep[i]; -+ /* add every non-ep0 endpoint to gadget endpoint list */ -+ if (i != 0) -+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); -+ ep->desc = NULL; -+ ep->stopped = 0; -+ ep->ep.maxpacket = ep->maxpacket; -+ /* initialize one queue per endpoint */ -+ INIT_LIST_HEAD(&ep->queue); -+ } -+} -+ -+static int __init akudc_udc_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct akudc_udc *udc = &controller; -+ struct resource *res; -+ int retval; -+ -+ if (pdev->num_resources < 2) { -+ dbg("invalid num_resources\n"); -+ return -ENODEV; -+ } -+ if ((pdev->resource[0].flags != IORESOURCE_MEM) -+ || (pdev->resource[1].flags != IORESOURCE_IRQ)) { -+ dbg("invalid resource type\n"); -+ return -ENODEV; -+ } -+ -+ /* get the mem resoure */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) -+ return -ENXIO; -+ -+ if (!request_mem_region(res->start, resource_size(res), driver_name)) { -+ dbg("someone's using UDC memory\n"); -+ return -EBUSY; -+ } -+ -+ /* map the physical mem to virtual for register */ -+ udc->baseaddr = ioremap_nocache(res->start, resource_size(res)); -+ if (!udc->baseaddr) { -+ retval = -ENOMEM; -+ goto fail0a; -+ } -+ /* init software state */ -+ udc->gadget.dev.parent = dev; //is null, -+ -+ /* get interface and function clocks */ -+ udc->clk = clk_get(dev, "usb-slave"); -+ if (IS_ERR(udc->clk)) { -+ dbg("clocks missing\n"); -+ retval = -ENODEV; -+ /* NOTE: we "know" here that refcounts on these are NOPs */ -+ goto fail0b; -+ } -+ -+ akudc_conctrol_reset(udc); -+ udc_reinit(udc); -+ -+ retval = device_register(&udc->gadget.dev); -+ if (retval < 0) -+ goto fail0b; -+ -+ /* creat the work queue for every ep */ -+ ep_wqueue = create_workqueue("akudc"); -+ -+ /* request UDC and maybe VBUS irqs */ -+ udc->mcu_irq = platform_get_irq(pdev, 0); -+ /* register the udc irq handler */ -+ retval = request_irq(udc->mcu_irq, udc_irqhandler, -+ 0, driver_name, udc); -+ if (retval < 0) { -+ dbg("request irq %d failed\n", udc->mcu_irq); -+ goto fail1; -+ } -+ -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ /* request DMA irqs */ -+ udc->dma_irq = platform_get_irq(pdev, 1); -+ retval = request_irq(udc->dma_irq, udc_dmahandler, -+ 0, driver_name, udc); -+ if (retval < 0) { -+ dbg("request irq %d failed\n", udc->dma_irq); -+ goto fail1; -+ } -+ -+ /* USB slave L2 buffer initialization */ -+ udc->ep[2].l2_buf_id = l2_alloc(ADDR_USB_EP2); -+ udc->ep[3].l2_buf_id = l2_alloc(ADDR_USB_EP3); -+ udc->ep[4].l2_buf_id = l2_alloc(ADDR_USB_EP4); -+ udc->ep[5].l2_buf_id = l2_alloc(ADDR_USB_EP5); -+#endif -+#endif -+ -+ /* set the udc pointer to pdev private pointer */ -+ platform_set_drvdata(pdev, udc); -+ -+ create_debugfs_files(udc); -+ -+ retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); -+ if (retval) -+ goto fail1; -+ -+ return 0; -+ -+ free_irq(udc->mcu_irq, udc); -+fail1: -+ device_unregister(&udc->gadget.dev); -+fail0b: -+ iounmap(udc->baseaddr); -+fail0a: -+ release_mem_region(res->start, resource_size(res)); -+ -+ return retval; -+} -+ -+static int __exit akudc_udc_remove(struct platform_device *pdev) -+{ -+ struct akudc_udc *udc = platform_get_drvdata(pdev); -+ struct resource *res; -+ -+ if (udc->driver) -+ return -EBUSY; -+ -+ usb_del_gadget_udc(&udc->gadget); -+ -+ /* clear the udc_clk condition for udc */ -+ clear_condition(&udc_clk); -+ -+ create_debugfs_files(udc); -+ -+ free_irq(udc->mcu_irq, udc); -+ device_unregister(&udc->gadget.dev); -+ -+ destroy_workqueue(ep_wqueue); -+ -+ iounmap(udc->baseaddr); -+ -+#if 0 -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+ free_irq(udc->dma_irq, udc); -+ -+ /* USB slave L2 buffer initialization */ -+ l2_free(ADDR_USB_EP2); -+ l2_free(ADDR_USB_EP3); -+ l2_free(ADDR_USB_EP4); -+ l2_free(ADDR_USB_EP5); -+#endif -+#endif -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ release_mem_region(res->start, resource_size(res)); -+ -+ return 0; -+} -+ -+static void akudc_udc_shutdown(struct platform_device *dev) -+{ -+} -+ -+#ifdef CONFIG_PM -+static int akudc_udc_suspend(struct platform_device *pdev, pm_message_t mesg) -+{ -+ struct akudc_udc *udc = platform_get_drvdata(pdev); -+ -+ /*cacel work for every endpoint */ -+ cancel_work_sync(&udc->ep[1].work); -+ cancel_work_sync(&udc->ep[2].work); -+ cancel_work_sync(&udc->ep[3].work); -+ cancel_work_sync(&udc->ep[4].work); -+ cancel_work_sync(&udc->ep[5].work); -+ -+ flush_workqueue(ep_wqueue); -+ -+ /* enable usb vbus wakeup function before enter standby */ -+ usb_vbus_wakeup(true); -+ -+ /* clear the udc_clk condition for udc */ -+ clear_condition(&udc_clk); -+ -+ udc_disconnect(udc); -+ -+ return 0; -+} -+ -+static int akudc_udc_resume(struct platform_device *pdev) -+{ -+ struct akudc_udc *udc = platform_get_drvdata(pdev); -+ -+ /* disable usb vbus wakeup function after wakeup */ -+ usb_vbus_wakeup(false); -+ -+ /* if we have the function driver, we set the udc_clk condition */ -+ if (udc->driver) -+ set_condition(&udc_clk); -+ -+ return 0; -+} -+#else -+#define akudc_udc_suspend NULL -+#define akudc_udc_resume NULL -+#endif -+ -+static struct platform_driver akudc_udc_driver = { -+ .remove = __exit_p(akudc_udc_remove), -+ .shutdown = akudc_udc_shutdown, -+ .suspend = akudc_udc_suspend, -+ .resume = akudc_udc_resume, -+ .driver = { -+ .name = (char *) driver_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init udc_init_module(void) -+{ -+ printk("udc driver initialize, (c) 2013 Anyka\n"); -+ -+ return platform_driver_probe(&akudc_udc_driver, akudc_udc_probe); -+} -+module_init(udc_init_module); -+ -+static void __exit udc_exit_module(void) -+{ -+ platform_driver_unregister(&akudc_udc_driver); -+} -+module_exit(udc_exit_module); -+ -+MODULE_DESCRIPTION("Anyka udc driver"); -+MODULE_AUTHOR("Anyka"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform: usb-slave"); -diff --git a/drivers/usb/gadget/plat-anyka/usbburn.c b/drivers/usb/gadget/plat-anyka/usbburn.c -new file mode 100644 -index 00000000..a5551da0 ---- /dev/null -+++ b/drivers/usb/gadget/plat-anyka/usbburn.c -@@ -0,0 +1,356 @@ -+/* -+ * akudc_usbburn -- driver for Anyka USB burntool; -+ * Features -+ * AUTHOR Zhang Jingyuan -+ * 10-09-27 16:28:08 -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/fs.h> -+#include <linux/init.h> -+#include <linux/cdev.h> -+#include <linux/slab.h> -+#include <linux/wait.h> -+#include <linux/sched.h> -+#include <asm/uaccess.h> -+#include <linux/module.h> -+#include <linux/device.h> -+ -+#include <linux/delay.h> -+#include <asm/io.h> -+ -+#define DEVICE_NAME "akudc_usbburn" -+ -+#define AK_USBBURN_STALL _IO('U', 0xf0) // set stall feature command for producer -+#define AK_USBBURN_STATUS _IO('U', 0xf1) // set CSW status command -+#define AK_GET_CHANNEL_ID _IOR('U', 0xf2, __u32) //get channel id command -+ -+#define CHANNEL_ID_ADDR (CONFIG_RAM_BASE + SZ_1M) /* the address for abtain channel id for burntool */ -+ -+unsigned int sense_data; // the CSW status -+struct semaphore sense_data_lock; // synchronization sense_data -+ -+EXPORT_SYMBOL(sense_data); -+EXPORT_SYMBOL(sense_data_lock); -+ -+static int major = 0; -+struct usbburn_dev { -+ struct cdev cdev; -+ wait_queue_head_t rq_rbuf, wq_rbuf; /* read and write queues for rbuf */ -+ wait_queue_head_t rq_wbuf, wq_wbuf; /* read and write queues for wbuf */ -+ void *rbuf; /* This buffer is used for user reading */ -+ size_t rlen; /* The length of rbuf */ -+ void *wbuf; /* This buffer is used for user writing */ -+ size_t wlen; /* The length of wbuf */ -+ struct semaphore r_sem, w_sem; /* mutual exclusion semaphore for rbuf and wbuf; */ -+ int r_stall; /* The flag of stop of rbuf */ -+ int w_stall; /* The flag of sotp of wbuf */ -+} *b_dev; -+struct class *usbburn_class; -+ -+static int akudc_usbburn_open(struct inode *inode, struct file *file) -+{ -+ printk("akudc_usbburn device is open\n"); -+ -+ return 0; -+} -+ -+static int akudc_usbburn_close(struct inode *inode, struct file *file) -+{ -+ printk("akudc_usbburn device is closed\n"); -+ -+ return 0; -+} -+ -+/* the read function for the producer */ -+ssize_t akudc_usbburn_read(struct file *filp, char __user *buf, -+ size_t count, loff_t *f_pos) -+{ -+ /* -+ * count is used to record the number of data to read; -+ * count1 is used to record the total number of data been read, -+ * readn is used to record the number of data been read each time. -+ */ -+ size_t count1 = 0, readn; -+ -+ while (count != 0) /* when the all data has been read, return. */ -+ { -+ down(&b_dev->r_sem); /* before access the rbuf member of b_dev, down the r_sem */ -+ while (b_dev->rbuf == NULL) { /* when there is no data to read, sleep to wait. */ -+ up(&b_dev->r_sem); /* up the r_sem */ -+ wait_event(b_dev->rq_rbuf, b_dev->rbuf != NULL); /* to sleep until some data is coming. */ -+ down(&b_dev->r_sem); -+ } -+ readn = min(count, b_dev->rlen); -+ -+ /* copy the data to user space */ -+ if (copy_to_user(buf + count1, b_dev->rbuf, readn)) { -+ up(&b_dev->r_sem); -+ return -EFAULT; -+ } -+ count1 += readn; -+ count -= readn; -+ -+ /* the number of data which has been read is less than b_dev->rlen */ -+ if (readn < b_dev->rlen) { -+ b_dev->rbuf += readn; -+ b_dev->rlen -= readn; -+ up(&b_dev->r_sem); -+ } else { /* wake up the wq_rbuf if the all data in rbuf has been read. */ -+ b_dev->rbuf = NULL; -+ up(&b_dev->r_sem); -+ wake_up(&b_dev->wq_rbuf); -+ -+ /* if the r_stall is set, return */ -+ if (b_dev->r_stall == 1) { -+ b_dev->r_stall = 0; -+ break; -+ } -+ } -+ } -+ -+ return count1; -+} -+ -+/* the write function for the usb file_storage */ -+int usbburn_write(void *buf, size_t count) -+{ -+ down(&b_dev->r_sem); /* down the r_sem before access the rbuf member of b_dev. */ -+ b_dev->rbuf = buf; -+ b_dev->rlen = count; -+ -+ /* sleep until the all data in rbuf has been read. */ -+ while (b_dev->rbuf != NULL) { -+ up(&b_dev->r_sem); -+ wake_up(&b_dev->rq_rbuf); -+ wait_event(b_dev->wq_rbuf, b_dev->rbuf == NULL); -+ down(&b_dev->r_sem); -+ } -+ up(&b_dev->r_sem); -+ -+ return count; -+} -+EXPORT_SYMBOL(usbburn_write); -+ -+/* the write function for the producer */ -+ssize_t akudc_usbburn_write(struct file *filp, const char __user *buf, -+ size_t count, loff_t *f_pos) -+{ -+ /* -+ * count is used to record the number of data to write; -+ * count1 is used to record the total number of data been written, -+ * written is used to record the number of data been written each time. -+ */ -+ size_t count1 = 0, written; -+ -+ while (count != 0) { -+ down(&b_dev->w_sem); /* before access the wbuf member of b_dev, down the w_sem. */ -+ while (b_dev->wbuf == NULL) { -+ up(&b_dev->w_sem); /* up the w_sem. */ -+ wait_event(b_dev->wq_wbuf, b_dev->wbuf != NULL); /* sleep until wbuf can be written. */ -+ down(&b_dev->w_sem); -+ } -+ written = min(count, b_dev->wlen); -+ -+ /* copy the user space buffer to the kernel. */ -+ if (copy_from_user(b_dev->wbuf, buf + count1, written)) { -+ up(&b_dev->w_sem); -+ return -EFAULT; -+ } -+ count1 += written; -+ count -= written; -+ -+ /* if written if less than b_dev->wlen. */ -+ if (written < b_dev->wlen) { -+ b_dev->wbuf += written; -+ b_dev->wlen -= written; -+ -+ /* if w_stall is set, wake up the rq_buf and return. */ -+ if (b_dev->w_stall == 1) { -+ b_dev->wbuf = NULL; -+ b_dev->wlen = written; -+ b_dev->w_stall = 0; -+ up(&b_dev->w_sem); -+ wake_up(&b_dev->rq_wbuf); -+ break; -+ } -+ up(&b_dev->w_sem); -+ } else { /* wake up rq_wbuf if the wbuf is full written. */ -+ b_dev->wbuf = NULL; -+ up(&b_dev->w_sem); -+ wake_up(&b_dev->rq_wbuf); -+ } -+ } -+ -+ return count1; -+} -+ -+/* the read function for the usb file_storage */ -+int usbburn_read(void *buf, size_t count) -+{ -+ down(&b_dev->w_sem); -+ b_dev->wbuf = buf; -+ b_dev->wlen = count; -+ -+ /* sleep until wbuf has been written. */ -+ while (b_dev->wbuf != NULL) { -+ up(&b_dev->w_sem); -+ wake_up(&b_dev->wq_wbuf); -+ wait_event(b_dev->rq_wbuf, b_dev->wbuf == NULL); -+ down(&b_dev->w_sem); -+ } -+ count = b_dev->wlen; -+ up(&b_dev->w_sem); -+ -+ return count; -+} -+EXPORT_SYMBOL(usbburn_read); -+ -+int akudc_usbburn_ioctl(struct file *filp, unsigned int cmd, -+ unsigned long arg) -+{ -+ unsigned long *channel_id; -+ -+ switch (cmd) { -+ case AK_USBBURN_STALL: -+ down(&b_dev->w_sem); -+ b_dev->w_stall = 1; /*set the w_stall flag for wbuf. */ -+ up(&b_dev->w_sem); -+ break; -+ case AK_USBBURN_STATUS: -+ sense_data = arg; -+ up(&sense_data_lock); -+ break; -+ case AK_GET_CHANNEL_ID: -+ channel_id = ioremap(CHANNEL_ID_ADDR, sizeof (*channel_id)); -+ if (channel_id == NULL) { -+ printk("ioremap error\n"); -+ return -1; -+ } -+ if (copy_to_user((void __user *)arg, channel_id, sizeof (*channel_id))) { -+ printk("copy id to user space failed!\n"); -+ iounmap(channel_id); -+ return -1; -+ } -+ iounmap(channel_id); -+ break; -+ default: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+void usbburn_ioctl(void) -+{ -+ down(&b_dev->r_sem); -+ b_dev->r_stall = 1; /*set the r_stall flag for rbuf. */ -+ up(&b_dev->r_sem); -+} -+EXPORT_SYMBOL(usbburn_ioctl); -+ -+/* The file operation for the usbburn device.*/ -+static struct file_operations akudc_usbburn_fops = { -+ .owner = THIS_MODULE, -+ .read = akudc_usbburn_read, -+ .write = akudc_usbburn_write, -+ .unlocked_ioctl = akudc_usbburn_ioctl, -+ .open = akudc_usbburn_open, -+ .release = akudc_usbburn_close, -+}; -+ -+int __init akudc_usbburn_init(void) -+{ -+ int ret = 0; -+ struct device *device; -+ dev_t dev = MKDEV(major, 0); -+ -+ /* allocate the burn device. */ -+ b_dev = kmalloc(sizeof(*b_dev), GFP_KERNEL); -+ if (unlikely (!b_dev)) { -+ ret = -ENOMEM; -+ printk("error, out of memory\n"); -+ goto out1; -+ } -+ memset(b_dev, 0, sizeof(*b_dev)); -+ -+ /* Register device major, and accept a dynamic number. */ -+ if (major) -+ ret = register_chrdev_region(dev, 1, DEVICE_NAME); -+ else { -+ ret = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); -+ major = MAJOR(dev); -+ } -+ if (ret < 0) { -+ printk("register chrdev major and minor number failed\n"); -+ goto out1; -+ } -+ -+ cdev_init(&b_dev->cdev, &akudc_usbburn_fops); -+ b_dev->cdev.owner = THIS_MODULE; -+ ret = cdev_add(&b_dev->cdev, dev, 1); -+ /* Fail gracefully if need be */ -+ if (ret) { -+ printk("Error %d adding akudc_usbburn_dev", ret); -+ goto out1; -+ } -+ -+ /* create the usbburn char device's class */ -+ usbburn_class = class_create(THIS_MODULE, "usbburn"); -+ if (IS_ERR(usbburn_class)) { -+ ret = PTR_ERR(usbburn_class); -+ printk("create usbburn class failed\n"); -+ goto out2; -+ } -+ -+ /* create the usbburn char device node in /dev/akudc_usbburn */ -+ device = device_create(usbburn_class, NULL, dev, NULL,"akudc_usbburn"); -+ if (IS_ERR(device)) { -+ printk("akudc_usbburn chrdev create failed! %x\n", ret); -+ ret = PTR_ERR(device); -+ goto out2; -+ } -+ else -+ printk("akudc_usbburn chrdev create success!\n"); -+ -+ /* init the waitqueue head for the rbuf and wbuf */ -+ init_waitqueue_head(&b_dev->rq_rbuf); -+ init_waitqueue_head(&b_dev->wq_rbuf); -+ init_waitqueue_head(&b_dev->rq_wbuf); -+ init_waitqueue_head(&b_dev->wq_wbuf); -+ -+ /* init the r_sem and w_sem with 1 */ -+ sema_init(&b_dev->r_sem, 1); -+ sema_init(&b_dev->w_sem, 1); -+ -+ /* init the sense_data_lock with 0 */ -+ memset(&sense_data_lock, 0, sizeof(sense_data_lock)); -+ sema_init(&sense_data_lock, 0); -+ -+ return ret; -+out2: -+ cdev_del(&b_dev->cdev); -+out1: -+ kfree(b_dev); -+ -+ return ret; -+} -+ -+void __exit akudc_usbburn_exit(void) -+{ -+ /* delete the device node */ -+ device_destroy(usbburn_class, MKDEV(major, 0)); -+ /* delete the class for usbburn */ -+ class_destroy(usbburn_class); -+ cdev_del(&b_dev->cdev); -+ kfree(b_dev); -+ unregister_chrdev_region(MKDEV(major, 0), 1); -+} -+ -+module_init(akudc_usbburn_init); -+module_exit(akudc_usbburn_exit); -+ -+MODULE_DESCRIPTION("AKudc usbburn driver"); -+MODULE_AUTHOR("Anyka"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c -index 73a934a1..0cb21218 100644 ---- a/drivers/usb/gadget/rndis.c -+++ b/drivers/usb/gadget/rndis.c -@@ -1146,11 +1146,15 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; - - #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -+static bool rndis_initialized; - - int rndis_init(void) - { - u8 i; - -+ if (rndis_initialized) -+ return 0; -+ - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { - #ifdef CONFIG_USB_GADGET_DEBUG_FILES - char name [20]; -@@ -1177,6 +1181,7 @@ int rndis_init(void) - INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); - } - -+ rndis_initialized = true; - return 0; - } - -@@ -1185,7 +1190,13 @@ void rndis_exit(void) - #ifdef CONFIG_USB_GADGET_DEBUG_FILES - u8 i; - char name[20]; -+#endif - -+ if (!rndis_initialized) -+ return; -+ rndis_initialized = false; -+ -+#ifdef CONFIG_USB_GADGET_DEBUG_FILES - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { - sprintf(name, NAME_TEMPLATE, i); - remove_proc_entry(name, NULL); -diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c -index 9a2a1ae9..dd2615a3 100644 ---- a/drivers/usb/gadget/u_ether.c -+++ b/drivers/usb/gadget/u_ether.c -@@ -763,6 +763,26 @@ static struct device_type gadget_type = { - * Returns negative errno, or zero on success - */ - int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) -+{ -+ return gether_setup_name(g, ethaddr, "usb"); -+} -+ -+/** -+ * gether_setup_name - initialize one ethernet-over-usb link -+ * @g: gadget to associated with these links -+ * @ethaddr: NULL, or a buffer in which the ethernet address of the -+ * host side of the link is recorded -+ * @netname: name for network device (for example, "usb") -+ * Context: may sleep -+ * -+ * This sets up the single network link that may be exported by a -+ * gadget driver using this framework. The link layer addresses are -+ * set up using module parameters. -+ * -+ * Returns negative errno, or zero on success -+ */ -+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], -+ const char *netname) - { - struct eth_dev *dev; - struct net_device *net; -@@ -786,7 +806,7 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) - - /* network device setup */ - dev->net = net; -- strcpy(net->name, "usb%d"); -+ snprintf(net->name, sizeof(net->name), "%s%%d", netname); - - if (get_ether_addr(dev_addr, net->dev_addr)) - dev_warn(&g->dev, -diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h -index 8012357e..37431f52 100644 ---- a/drivers/usb/gadget/u_ether.h -+++ b/drivers/usb/gadget/u_ether.h -@@ -73,6 +73,9 @@ struct gether { - /* netdev setup/teardown as directed by the gadget driver */ - int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]); - void gether_cleanup(void); -+/* variant of gether_setup that allows customizing network device name */ -+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], -+ const char *netname); - - /* connect/disconnect is handled by individual functions */ - struct net_device *gether_connect(struct gether *); -@@ -100,6 +103,8 @@ int eem_bind_config(struct usb_configuration *c); - #ifdef USB_ETH_RNDIS - - int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -+int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -+ u32 vendorID, const char *manufacturer); - - #else - -@@ -109,6 +114,13 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) - return 0; - } - -+static inline int -+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -+ u32 vendorID, const char *manufacturer) -+{ -+ return 0; -+} -+ - #endif - - #endif /* __U_ETHER_H */ -diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c -index 6c23938d..380a87f6 100644 ---- a/drivers/usb/gadget/u_serial.c -+++ b/drivers/usb/gadget/u_serial.c -@@ -1025,7 +1025,7 @@ static const struct tty_operations gs_tty_ops = { - - static struct tty_driver *gs_tty_driver; - --static int __init -+static int - gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) - { - struct gs_port *port; -@@ -1071,7 +1071,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) - * - * Returns negative errno or zero. - */ --int __init gserial_setup(struct usb_gadget *g, unsigned count) -+int gserial_setup(struct usb_gadget *g, unsigned count) - { - unsigned i; - struct usb_cdc_line_coding coding; -diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index f788eb86..056a1ccf 100644 ---- a/drivers/usb/host/Kconfig -+++ b/drivers/usb/host/Kconfig -@@ -638,3 +638,6 @@ config USB_OCTEON_OHCI - config USB_OCTEON2_COMMON - bool - default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI -+ -+source "drivers/usb/host/plat-anyka/Kconfig" -+ -diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 0982bcc1..33a6dc12 100644 ---- a/drivers/usb/host/Makefile -+++ b/drivers/usb/host/Makefile -@@ -41,3 +41,4 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o - obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o - obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o - obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o -+obj-$(CONFIG_USB_ANYKA_HCD) += plat-anyka/ -diff --git a/drivers/usb/host/plat-anyka/Kconfig b/drivers/usb/host/plat-anyka/Kconfig -new file mode 100644 -index 00000000..f58dc4ee ---- /dev/null -+++ b/drivers/usb/host/plat-anyka/Kconfig -@@ -0,0 +1,26 @@ -+config USB_ANYKA_HCD -+ bool "Anyka on-chip HCD support" -+ depends on USB && ARCH_AK39 -+ help -+ Enable support for the ANYKA on-chip HCD, It is support full speed and high speed -+ -+config USB_AKOTG_HS_HCD -+ tristate "USB(otg) High-Speed HCD support" -+ depends on USB_ANYKA_HCD -+ help -+ The ANYKA chips inner USB otg high speed host controllers. Enable this -+ option if your board has this chip. If unsure, say N. -+ -+ This driver does not support isochronous transfers. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called otg-hs. -+ -+config USB_AKOTG_DMA -+ bool "USB(otg) support for DMA transfer" -+ depends on USB_AKOTG_HS_HCD -+ help -+ Say 'Y' to turn on dma support for anyka otg host. -+ -+ If no need, say N. -+ -diff --git a/drivers/usb/host/plat-anyka/Makefile b/drivers/usb/host/plat-anyka/Makefile -new file mode 100644 -index 00000000..f749f649 ---- /dev/null -+++ b/drivers/usb/host/plat-anyka/Makefile -@@ -0,0 +1,7 @@ -+# -+# Makefile for USB Host Controller Drivers -+# -+ -+obj-$(CONFIG_USB_AKOTG_HS_HCD) += otg-hs.o -+ otg-hs-objs := otg-hshcd.o usb-hc.o -+ -diff --git a/drivers/usb/host/plat-anyka/otg-hshcd.c b/drivers/usb/host/plat-anyka/otg-hshcd.c -new file mode 100755 -index 00000000..f7d5ed14 ---- /dev/null -+++ b/drivers/usb/host/plat-anyka/otg-hshcd.c -@@ -0,0 +1,337 @@ -+/* -+ * Anyka OTG HS HCD (Full-Speed Host Controller Driver) for USB. -+ * -+ * Derived from the SL811 HCD, rewritten for AKOTG HS HCD. -+ * Copyright (C) 2010 ANYKA LTD. -+ * -+ * Periodic scheduling is based on Roman's OHCI code -+ * Copyright (C) 1999 Roman Weissgaerber -+ * -+ * The AK OTG HS Host controller handles host side USB. For Documentation, -+ * refer to chapter 22 USB Controllers of Anyka chip Mobile Multimedia Application -+ * Processor Programmer's Guide. -+ * -+ */ -+ -+/* -+ * Status: Enumeration of USB Optical Mouse, USB Keyboard, USB Flash Disk, Ralink 2070/3070 USB WiFi OK. -+ * Pass basic test with USB Optical Mouse/USB Keyboard/USB Flash Disk. -+ * Ralink 2070/3070 USB WiFI Scanning/WEP basic test OK. Full Functions TBD. -+ * -+ * TODO: -+ * - Use up to 6 active queues of FS HC(for now only 2 queues: EP0 & EPX(1-6)) -+ * - USB Suspend/Resume support -+ * - Use urb->iso_frame_desc[] with ISO transfers -+ * - Optimize USB FIFO data transfer/receive(4B->2B->1B) -+ */ -+ -+#include <linux/module.h> -+#include <linux/interrupt.h> -+#include <linux/usb.h> -+#include <linux/usb/hcd.h> -+#include <linux/platform_device.h> -+#include <linux/clk.h> -+ -+#include <plat-anyka/otg-hshcd.h> -+#include <plat-anyka/usb-hc.h> -+ -+#include <mach/clock.h> -+ -+static char *host_sw = "onboard"; -+module_param(host_sw, charp, S_IRUGO); -+ -+static const char hcd_name[] = "usb-host"; -+extern struct akotghc_epfifo_mapping akotg_epfifo_mapping;; -+ -+ -+static struct hc_driver akhs_otg_driver = { -+ .description = hcd_name, -+ .product_desc = "Anyka usb host controller", -+ .hcd_priv_size = sizeof(struct akotg_usbhc), -+ -+ /* -+ * generic hardware linkage -+ */ -+ .irq = akotg_usbhc_irq, -+ .flags = HCD_USB2 | HCD_MEMORY, -+ -+ /* Basic lifecycle operations */ -+ .start = akotg_usbhc_start, -+ .stop = akotg_usbhc_stop, -+ -+ /* -+ * managing i/o requests and associated device resources -+ */ -+ -+ .urb_dequeue = akotg_usbhc_urb_dequeue, -+ .urb_enqueue = akotg_usbhc_urb_enqueue, -+ .endpoint_reset = akotg_usbhc_endpoint_reset, -+ .endpoint_disable = akotg_usbhc_endpoint_disable, -+ -+ /* -+ * periodic schedule support -+ */ -+ .get_frame_number = akotg_usbhc_get_frame, -+ -+ /* -+ * root hub support -+ */ -+ .hub_status_data = akotg_usbhc_hub_status_data, -+ .hub_control = akotg_usbhc_hub_control, -+ #ifdef CONFIG_PM -+ .bus_suspend = akotg_usbhc_bus_suspend, -+ .bus_resume = akotg_usbhc_bus_resume, -+ #else -+ .bus_suspend = NULL, -+ .bus_resume = NULL, -+ #endif -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void usb_poweron_for_device(struct akotghc_usb_platform_data *pdata) -+{ -+ /* power on for usb device */ -+ if(pdata->gpio_pwr_on.pin >= 0) -+ pdata->gpio_init(&pdata->gpio_pwr_on); -+ -+ /* ust otg host port switch */ -+ if((pdata->switch_onboard.pin >= 0)&&(pdata->switch_extport.pin >= 0) -+ && (pdata->switch_onboard.pin == pdata->switch_extport.pin)) { -+ if (!strcmp(host_sw, "extport")) -+ pdata->gpio_init(&pdata->switch_extport); -+ else -+ pdata->gpio_init(&pdata->switch_onboard); -+ -+ } -+} -+ -+static void usb_poweroff_for_device(struct akotghc_usb_platform_data *pdata) -+{ -+ /* ust otg host port switch */ -+ if((pdata->switch_onboard.pin >= 0)&&(pdata->switch_extport.pin >= 0) -+ && (pdata->switch_onboard.pin == pdata->switch_extport.pin)) { -+ if (!strcmp(host_sw, "onboard")) -+ pdata->gpio_init(&pdata->switch_extport); -+ else -+ pdata->gpio_init(&pdata->switch_onboard); -+ } -+ -+ /* power off for usb device */ -+ if(pdata->gpio_pwr_off.pin >= 0) -+ pdata->gpio_init(&pdata->gpio_pwr_off); -+} -+ -+static int __devexit -+akotg_hc_remove(struct platform_device *pdev) -+{ -+ struct usb_hcd *hcd = platform_get_drvdata(pdev); -+ struct akotghc_usb_platform_data *pdata = NULL; -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ struct akotg_usbhc *akotghc; -+#endif -+ -+ pdata = pdev->dev.platform_data; -+ if (pdata != NULL) -+ /* hwinit power off */ -+ usb_poweroff_for_device(pdata); -+ -+ usb_remove_hcd(hcd); -+ usb_put_hcd(hcd); -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ -+ //free dma irq -+ akotghc = hcd_to_akotg_usbhc(hcd); -+ if(akotghc->dma_irq > 0) -+ { -+ free_irq(akotghc->dma_irq, hcd); -+ akotghc->dma_irq = -1; -+ } -+ -+#endif -+ -+ return 0; -+} -+ -+static int __devinit -+akotg_hc_probe(struct platform_device *pdev) -+{ -+ struct usb_hcd *hcd; -+ struct akotg_usbhc *akotghc; -+ struct resource *res; -+ struct akotghc_usb_platform_data *pdata = NULL; -+ int irq; -+ int retval = 0; -+ unsigned long irqflags; -+ int i, j; -+ -+ pdata = pdev->dev.platform_data; -+ if (pdata == NULL) -+ return -ENODEV; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if(!res) -+ return -ENODEV; -+ -+ /* allocate and initialize hcd */ -+ hcd = usb_create_hcd(&akhs_otg_driver, &pdev->dev, akhs_otg_driver.product_desc); -+ if (!hcd) { -+ retval = -ENOMEM; -+ goto err_nomem; -+ } -+ -+ hcd->rsrc_start = res->start; -+ hcd->rsrc_len = resource_size(res); -+ akotghc = hcd_to_akotg_usbhc(hcd); -+ -+ usb_poweron_for_device(pdata); -+ -+ akotghc->clk = clk_get(&pdev->dev, "usb-host"); -+ if (IS_ERR(akotghc->clk)) { -+ dbg("usb otg hs clocks missing\n"); -+ akotghc->clk = NULL; -+ goto err_nomem; -+ } -+ -+ /* basic sanity checks first. board-specific init logic should -+ * have initialized these three resources and probably board -+ * specific platform_data. we don't probe for IRQs, and do only -+ * minimal sanity checking. -+ */ -+ irq = platform_get_irq(pdev, 0); -+ if (irq <= 0) { -+ dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n", -+ dev_name(&pdev->dev)); -+ retval = -ENODEV; -+ goto err_nodev; -+ } -+ akotghc->mcu_irq = irq; -+ -+ spin_lock_init(&akotghc->lock); -+ INIT_LIST_HEAD(&akotghc->async_ep0); -+ for(i=0; i<MAX_EP_NUM; i++) -+ INIT_LIST_HEAD(&akotghc->async_epx[i]); -+ -+ akotghc->active_ep0 = NULL; -+ for(j=0; j<MAX_EP_NUM; j++) -+ akotghc->active_epx[j] = NULL; -+ -+ init_timer(&akotghc->timer); -+ akotghc->timer.function = akotg_usbhc_timer; -+ akotghc->timer.data = (unsigned long) akotghc; -+ -+ hcd->speed = HCD_USB2; -+ //hcd->power_budget = 0; //or get from platfrom data -+ -+ /* The chip's IRQ is level triggered, active high. A requirement -+ * for platform device setup is to cope with things like signal -+ * inverters (e.g. CF is active low) or working only with edge -+ * triggers (e.g. most ARM CPUs). Initial driver stress testing -+ * was on a system with single edge triggering, so most sorts of -+ * triggering arrangement should work. -+ * -+ * Use resource IRQ flags if set by platform device setup. -+ */ -+ irqflags = IRQF_SHARED; -+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | irqflags); -+ if (retval != 0) -+ goto err_addhcd; -+ -+ init_epfifo_mapping(&akotg_epfifo_mapping); -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ -+ akotg_dma_init(akotghc); -+ -+ //request dma irq -+ irq = platform_get_irq(pdev, 1); -+ retval = request_irq(irq, akotg_dma_irq, IRQF_DISABLED, "otgdma", hcd); -+ if (retval < 0){ -+ akotghc->dma_irq = -1; -+ printk("request irq %d failed\n", irq); -+ } -+ else { -+ akotghc->dma_irq = irq; -+ } -+ -+#endif -+ -+ printk("Usb otg-hs controller driver initialized\n"); -+ return retval; -+ -+ err_addhcd: -+ usb_put_hcd(hcd); -+ err_nomem: -+ err_nodev: -+ -+ return retval; -+} -+ -+#ifdef CONFIG_PM -+ -+/* for this device there's no useful distinction between the controller -+ * and its root hub, except that the root hub only gets direct PM calls -+ * when CONFIG_USB_SUSPEND is enabled. -+ */ -+static int -+akotg_hc_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ int retval = 0; -+ -+ switch (state.event) { -+ case PM_EVENT_FREEZE: -+ break; -+ case PM_EVENT_SUSPEND: -+ case PM_EVENT_HIBERNATE: -+ case PM_EVENT_PRETHAW: /* explicitly discard hw state */ -+ break; -+ } -+ return retval; -+} -+ -+static int -+akotg_hc_resume(struct platform_device *dev) -+{ -+ return 0; -+} -+ -+#else -+#define akotg_hc_suspend NULL -+#define akotg_hc_resume NULL -+#endif -+ -+ -+struct platform_driver akotg_hc_driver = { -+ .probe = akotg_hc_probe, -+ .remove = __devexit_p(akotg_hc_remove), -+ -+ .suspend = akotg_hc_suspend, -+ .resume = akotg_hc_resume, -+ .driver = { -+ .name = (char *) hcd_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int __init akotg_hc_init(void) -+{ -+ -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ return platform_driver_register(&akotg_hc_driver); -+} -+module_init(akotg_hc_init); -+ -+static void __exit akotg_hc_cleanup(void) -+{ -+ platform_driver_unregister(&akotg_hc_driver); -+} -+module_exit(akotg_hc_cleanup); -+MODULE_DESCRIPTION("Anyka Host Controller Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ak_hcd"); -diff --git a/drivers/usb/host/plat-anyka/usb-hc.c b/drivers/usb/host/plat-anyka/usb-hc.c -new file mode 100755 -index 00000000..370f87a8 ---- /dev/null -+++ b/drivers/usb/host/plat-anyka/usb-hc.c -@@ -0,0 +1,1802 @@ -+ -+#include <linux/delay.h> -+#include <linux/module.h> -+#include <linux/interrupt.h> -+#include <linux/slab.h> -+#include <linux/usb.h> -+#include <linux/usb/hcd.h> -+#include <linux/platform_device.h> -+#include <linux/clk.h> -+#include <linux/dma-mapping.h> -+ -+#include <asm/unaligned.h> -+#include <plat-anyka/usb-hc.h> -+#include <mach/clock.h> -+#include <mach/reset.h> -+ -+#ifdef AKOTG_HS_DEBUG -+#define HDBG(stuff...) printk("USBHS: " stuff) -+#else -+#define HDBG(fmt, args...) do{}while(0) -+#endif -+ -+#ifdef AKOTG_HS_VERBOSE_DEBUG -+#define VDBG HDBG -+#else -+#define VDBG(fmt, args...) do{}while(0) -+#endif -+ -+ -+static int period_epfifo; -+static struct workqueue_struct *g_otghc_wq; -+static struct delayed_work g_otg_rest; -+//static char *trans_desc[4] = {"iso", "intterrup", "conroller", "bulk"}; -+static u8 ep_fifos[] = { USB_FIFO_EP0, USB_FIFO_EP1, USB_FIFO_EP2, USB_FIFO_EP3, USB_FIFO_EP4, USB_FIFO_EP5}; -+struct akotghc_epfifo_mapping akotg_epfifo_mapping; -+ -+static inline int get_ep_type(int pipe) -+{ -+ int eptype = 0; -+ -+ switch(usb_pipetype(pipe)) { -+ case PIPE_ISOCHRONOUS: -+ eptype = 1; -+ break; -+ case PIPE_BULK: -+ eptype = 2; -+ break; -+ case PIPE_INTERRUPT: -+ eptype = 3; -+ break; -+ } -+ return eptype; -+} -+ -+void port_power(struct akotg_usbhc *akotghc, int is_on) -+{ -+ /*Anyka usb host is self power currently.*/ -+ struct usb_hcd *hcd = akotg_usbhc_to_hcd(akotghc); -+ -+ /* hub is inactive unless the port is powered */ -+ if (is_on) { -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_POWER)) -+ return; -+ -+ akotghc->port_status = (1 << USB_PORT_FEAT_POWER); -+ } else { -+ akotghc->port_status = 0; -+ hcd->state = HC_STATE_HALT; -+ } -+ -+ /* reset as thoroughly as we can */ -+ ak_soft_reset(AK_SRESET_USBHS); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* This is a PIO-only HCD. Queueing appends URBs to the endpoint's queue, -+ * and may start I/O. Endpoint queues are scanned during completion irq -+ * handlers (one per packet: ACK, NAK, faults, etc) and urb cancellation. -+ * -+ * Using an external DMA engine to copy a packet at a time could work, -+ * though setup/teardown costs may be too big to make it worthwhile. -+ */ -+ -+/* SETUP starts a new control request. Devices are not allowed to -+ * STALL or NAK these; they must cancel any pending control requests. -+ */ -+static void setup_packet( -+ struct akotg_usbhc *akotghc, -+ struct akotghc_ep *ep, -+ struct urb *urb -+) -+{ -+ int i; -+ unsigned int fifo_val; -+ u8 len; -+ unsigned char *buf = urb->setup_packet; -+ -+ HDBG("Packet: Setup Packet (EP %d)\n", ep->epnum); -+ -+ len = sizeof(struct usb_ctrlrequest); -+ -+ hc_index_writeb(0, 0, USB_REG_TXCSR1); -+ hc_writeb(usb_pipedevice(urb->pipe), USB_REG_FADDR); -+ for (i = 0; i < len; i += 4) { -+ fifo_val = (*(buf+i) | ( *(buf+i+1)<<8 ) -+ | ( *(buf+i+2)<<16 ) | ( *(buf+i+3)<<24 )); -+ hc_writel(fifo_val, USB_FIFO_EP0); -+ } -+ hc_index_writeb(0, USB_TXCSR1_FLUSHFIFO |USB_TXCSR1_FIFONOTEMPTY, USB_REG_TXCSR1); -+ -+ ep->length = 0; -+} -+ -+/* STATUS finishes control requests, often after IN or OUT data packets */ -+static void status_packet( -+ struct akotg_usbhc *akotghc, -+ struct akotghc_ep *ep, -+ struct urb *urb -+) -+{ -+ int is_in; -+ -+ HDBG("Packet: Status Packet (EP %d)\n", ep->epnum); -+ -+ is_in = urb->transfer_buffer_length && usb_pipein(urb->pipe); -+ //if (!epnum_to_epfifo(&akotg_epfifo_mapping, ep->epnum, !usb_pipein(urb->pipe), &epfifo)) -+ // BUG(); /* Impossible, USB Device Endpoint *MUST* have been mapped to EPFIFO */ -+ -+ hc_writeb(usb_pipedevice(urb->pipe), USB_REG_FADDR); -+ -+ if (is_in) { -+ /* send a state packet when IN transaction is finished */ -+ hc_index_writeb(ep->epfifo, 0x42, USB_REG_TXCSR1); -+ } else { -+ /* request a state packet when OUT transaction is finished */ -+ hc_index_writeb(ep->epfifo, 0x60, USB_REG_TXCSR1); -+ } -+ -+ ep->length = 0; -+} -+ -+/* IN packets can be used with any type of endpoint. here we just -+ * start the transfer, data from the peripheral may arrive later. -+ * urb->iso_frame_desc is currently ignored here... -+ */ -+static void in_packet( -+ struct akotg_usbhc *akotghc, -+ struct akotghc_ep *ep, -+ struct urb *urb -+) -+{ -+ u16 len; -+ u32 remain; -+ -+ bool bDMA = false; -+ -+ HDBG("Packet: IN Packet (EP %d), Length=%d,ep->maxpacket=%d\n", -+ ep->epnum, urb->transfer_buffer_length - urb->actual_length, ep->maxpacket); -+ -+ /* avoid losing data on overflow */ -+ len = ep->maxpacket; -+ remain = urb->transfer_buffer_length - urb->actual_length; -+ -+ ep->length = min_t(u32, len, remain); -+ -+ hc_writeb(usb_pipedevice(urb->pipe), USB_REG_FADDR); -+ if (ep->epnum == 0) { -+ hc_index_writeb(0, USB_TXCSR1_H_RXSTALL, USB_REG_TXCSR1); -+ } else { -+ int eptype = 0; -+ //if (!epnum_to_epfifo(&akotg_epfifo_mapping, ep->epnum, 0, &epfifo)) -+ // BUG(); /* Impossible, USB Device Endpoint *MUST* have been mapped to EPFIFO */ -+ -+ eptype = get_ep_type(urb->pipe); -+ -+ /** -+ dma condition: -+ 1. high speed and ep size >= 512 -+ 2. data leng >= 512 -+ 3. l2 buffer is alloced for epfifo -+ */ -+#ifdef CONFIG_USB_AKOTG_DMA -+ if((len == 512) && (remain >= len)) -+ { -+ struct akotg_dma *usbdma; -+ u8 regvalue; -+ u32 pktnum = remain / 512; -+ u32 count = remain - remain%512; -+ unsigned char *buf; -+ dma_addr_t phyaddr; -+ u8 l2buffer; -+ -+ if(count < remain){ -+ count += 512; -+ } -+ -+ do -+ { -+ //map dma buffer -+ buf = urb->transfer_buffer + urb->actual_length; -+ phyaddr = dma_map_single(NULL, buf, count, DMA_FROM_DEVICE); -+ if (phyaddr == 0) { -+ printk("tx dma_map_single error!\n"); -+ break; -+ } -+ -+ //alloc dma channel -+ usbdma = akotg_dma_alloc(akotghc, ep->epfifo); -+ if(!usbdma){ -+ //printk("dma alloc fail for in_packet\n"); -+ dma_unmap_single(NULL, phyaddr, count, DMA_FROM_DEVICE); -+ break; -+ } -+ -+ l2buffer = usbdma->l2buffer; -+ -+ //config rx reg -+ regvalue = hc_index_readb(ep->epfifo, USB_REG_RXCSR2); -+ regvalue |= (USB_RXCSR2_AUTOCLEAR | USB_RXCSR2_AUTOREQ | USB_RXCSR2_DMAENAB | USB_RXCSR2_DMAMODE); -+ hc_index_writeb(ep->epfifo, regvalue, USB_REG_RXCSR2); -+ -+ hc_writew(pktnum, USB_REG_REQPKTCNT(ep->epfifo)); -+ -+ //config l2 -+ l2_clr_status(l2buffer); -+ l2_combuf_dma(phyaddr, l2buffer, count, BUF2MEM, AK_FALSE); -+ -+ //config dma -+ akotg_dma_set_struct(usbdma, USB_DIRECTION_RX, ep->epfifo, l2buffer, count, phyaddr); -+ akotg_dma_config(usbdma); -+ -+ ep->length = count; -+ -+ bDMA = true; -+ } -+ while(0); -+ -+ } -+#endif -+ ep->bdma = bDMA; -+ -+ hc_index_writeb(ep->epfifo, USB_RXCSR1_H_REQPKT, USB_REG_RXCSR1); -+ } -+} -+ -+/* OUT packets can be used with any type of endpoint. -+ * urb->iso_frame_desc is currently ignored here... -+ */ -+static void out_packet( -+ struct akotg_usbhc *akotghc, -+ struct akotghc_ep *ep, -+ struct urb *urb -+) -+{ -+ int i; -+ unsigned char *buf; -+ u16 len; -+ u32 remain; -+ -+ bool bDMA = false; -+ -+ HDBG("Packet: OUT Packet (EP %d), Length=%d\n", ep->epnum, urb->transfer_buffer_length - urb->actual_length); -+ -+ buf = (unsigned char *)(urb->transfer_buffer + urb->actual_length); -+ prefetch(buf); -+ -+ remain = urb->transfer_buffer_length - urb->actual_length; -+ len = min_t(u32, ep->maxpacket, remain); -+ -+ //if (!epnum_to_epfifo(&akotg_epfifo_mapping, ep->epnum, 1, &epfifo)) -+ // BUG(); /* Impossible, USB Device Endpoint *MUST* have been mapped to EPFIFO */ -+ -+ /** -+ dma condition: -+ 1. high speed and ep size >= 512 -+ 2. data leng >= 512 -+ 3. l2 buffer is alloced for epfifo -+ */ -+#ifdef CONFIG_USB_AKOTG_DMA -+ if((len == 512) && (remain >= len)) -+ { -+ struct akotg_dma *usbdma; -+ u8 regvalue; -+ u32 count = remain - remain%512; -+ unsigned char *buf; -+ dma_addr_t phyaddr; -+ u8 l2buffer; -+ -+ do -+ { -+ //map dma buffer -+ buf = urb->transfer_buffer + urb->actual_length; -+ phyaddr = dma_map_single(NULL, buf, count, DMA_TO_DEVICE); -+ if (phyaddr == 0) { -+ printk("rx dma_map_single error!\n"); -+ break; -+ } -+ -+ //alloc dma channel -+ usbdma = akotg_dma_alloc(akotghc, ep->epfifo); -+ if(!usbdma){ -+ //printk("dma alloc fail for out_packet\n"); -+ dma_unmap_single(NULL, phyaddr, count, DMA_TO_DEVICE); -+ break; -+ } -+ -+ l2buffer = usbdma->l2buffer; -+ -+ -+ //config tx reg -+ regvalue = hc_index_readb(ep->epfifo, USB_REG_TXCSR2); -+ regvalue |= (USB_TXCSR2_DMAMODE1|USB_TXCSR2_DMAENAB|USB_TXCSR2_MODE|USB_TXCSR2_AUTOSET); -+ hc_index_writeb(ep->epfifo, regvalue, USB_REG_TXCSR2); -+ -+ //config l2 -+ l2_clr_status(l2buffer); -+ l2_combuf_dma(phyaddr, l2buffer, count, MEM2BUF, AK_FALSE); -+ -+ //config dma -+ akotg_dma_set_struct(usbdma, USB_DIRECTION_TX, ep->epfifo, l2buffer, count, phyaddr); -+ akotg_dma_config(usbdma); -+ -+ ep->length = count; -+ -+ bDMA = true; -+ } -+ while(0); -+ -+ } -+#endif -+ ep->bdma = bDMA; -+ -+ if(!bDMA) -+ { -+ hc_index_writeb(ep->epfifo, 0, USB_REG_TXCSR1); -+ hc_writeb(usb_pipedevice(urb->pipe), USB_REG_FADDR); -+ for (i = 0; i < len; i ++) { -+ hc_writeb(buf[i], ep_fifos[ep->epfifo]); -+ } -+ if (ep->epnum == 0) { -+ hc_index_writeb(0, 0x02, USB_REG_TXCSR1); -+ } else { -+ -+ hc_index_writeb(ep->epfifo, USB_TXCSR1_TXPKTRDY, USB_REG_TXCSR1); -+ } -+ -+ ep->length = len; -+ } -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* caller updates on-chip enables later */ -+static inline void sofirq_on(struct akotg_usbhc *akotghc) -+{ -+ unsigned int regval; -+ -+ regval = hc_readb(USB_REG_INTRUSBE); -+ regval |= USB_INTR_SOF; -+ hc_writeb(regval, USB_REG_INTRUSBE); -+} -+ -+static inline void sofirq_off(struct akotg_usbhc *akotghc) -+{ -+ unsigned int regval; -+ -+ regval = hc_readb(USB_REG_INTRUSBE); -+ regval &= ~USB_INTR_SOF; -+ hc_writeb(regval, USB_REG_INTRUSBE); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct akotghc_ep *start_ep0(struct akotg_usbhc *akotghc) -+{ -+ struct akotghc_ep *ep; -+ struct urb *urb; -+ -+ /* use endpoint at schedule head */ -+ if (akotghc->next_async_ep0) -+ ep = akotghc->next_async_ep0; -+ else if (!list_empty(&akotghc->async_ep0)) { -+ ep = container_of(akotghc->async_ep0.next, -+ struct akotghc_ep, schedule); -+ } else { -+ /* could set up the first fullspeed periodic -+ * transfer for the next frame ... -+ */ -+ return NULL; -+ } -+ -+ if (ep->schedule.next == &akotghc->async_ep0) -+ akotghc->next_async_ep0 = NULL; -+ else -+ akotghc->next_async_ep0 = container_of(ep->schedule.next, -+ struct akotghc_ep, schedule); -+ -+ if (unlikely(list_empty(&ep->hep->urb_list))) { -+ HDBG("empty %p queue?\n", ep); -+ return NULL; -+ } -+ -+ urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); -+ -+ switch (ep->nextpid) { -+ case USB_PID_IN: -+ in_packet(akotghc, ep, urb); -+ break; -+ case USB_PID_OUT: -+ out_packet(akotghc, ep, urb); -+ break; -+ case USB_PID_SETUP: -+ setup_packet(akotghc, ep, urb); -+ break; -+ case USB_PID_ACK: /* for control status */ -+ status_packet(akotghc, ep, urb); -+ break; -+ default: -+ HDBG("bad ep%p pid %02x\n", ep, ep->nextpid); -+ ep = NULL; -+ } -+ return ep; -+} -+ -+ -+/* pick the next endpoint for a transaction, and issue it. -+ * frames start with periodic transfers (after whatever is pending -+ * from the previous frame), and the rest of the time is async -+ * transfers, scheduled round-robin. -+ */ -+static struct akotghc_ep *start_epx(struct akotg_usbhc *akotghc, int epfifo) -+{ -+ struct akotghc_ep *ep; -+ struct urb *urb; -+ -+ -+ /* use endpoint at schedule head */ -+ if (akotghc->next_periodic) { -+ ep = akotghc->next_periodic; -+ akotghc->next_periodic = ep->next; -+ } else { -+ if (akotghc->next_async_epx[epfifo-1]) -+ ep = akotghc->next_async_epx[epfifo-1]; -+ else if (!list_empty(&akotghc->async_epx[epfifo-1])) { -+ ep = container_of(akotghc->async_epx[epfifo-1].next, -+ struct akotghc_ep, schedule); -+ -+ } else { -+ /* could set up the first fullspeed periodic -+ * transfer for the next frame ... -+ */ -+ return NULL; -+ } -+ -+ if (ep->schedule.next == &akotghc->async_epx[epfifo-1]) -+ akotghc->next_async_epx[epfifo-1] = NULL; -+ else { -+ akotghc->next_async_epx[epfifo-1] = container_of(ep->schedule.next, -+ struct akotghc_ep, schedule); -+ } -+ } -+ -+ if (unlikely(list_empty(&ep->hep->urb_list))) { -+ HDBG("empty %p queue?\n", ep); -+ return NULL; -+ } -+ urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); -+ switch (ep->nextpid) { -+ case USB_PID_IN: -+ in_packet(akotghc, ep, urb); -+ break; -+ case USB_PID_OUT: -+ out_packet(akotghc, ep, urb); -+ break; -+ case USB_PID_SETUP: -+ setup_packet(akotghc, ep, urb); -+ break; -+ case USB_PID_ACK: -+ status_packet(akotghc, ep, urb); -+ break; -+ default: -+ HDBG("bad ep%p pid %02x\n", ep, ep->nextpid); -+ ep = NULL; -+ } -+ return ep; -+} -+ -+#define MIN_JIFFIES ((msecs_to_jiffies(2) > 1) ? msecs_to_jiffies(2) : 2) -+ -+static inline void start_transfer_ep0(struct akotg_usbhc *akotghc) -+{ -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_SUSPEND)) -+ return; -+ if (akotghc->active_ep0 == NULL) { -+ akotghc->active_ep0 = start_ep0(akotghc); -+ if (akotghc->active_ep0 != NULL) -+ akotghc->jiffies_ep0 = jiffies + MIN_JIFFIES; -+ } -+} -+ -+static inline void start_transfer_epx(struct akotg_usbhc *akotghc, int epfifo) -+{ -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_SUSPEND)) -+ return; -+ if (akotghc->active_epx[epfifo-1] == NULL) { -+ akotghc->active_epx[epfifo-1] = start_epx(akotghc, epfifo); -+ if (akotghc->active_epx[epfifo-1] != NULL) -+ akotghc->jiffies_epx[epfifo-1] = jiffies + MIN_JIFFIES; -+ } -+} -+ -+static inline void start_transfer(struct akotg_usbhc *akotghc, int epfifo) -+{ -+ -+ if(epfifo == 0) -+ start_transfer_ep0(akotghc); -+ else -+ start_transfer_epx(akotghc, epfifo); -+ -+} -+ -+static void finish_request_ep0( -+ struct akotg_usbhc *akotghc, -+ struct akotghc_ep *ep, -+ struct urb *urb, -+ int status -+) __releases(akotghc->lock) __acquires(akotghc->lock) -+{ -+ VDBG("Finishing EP0 URB Request...\n"); -+ -+ if (usb_pipecontrol(urb->pipe)) -+ ep->nextpid = USB_PID_SETUP; -+ -+ usb_hcd_unlink_urb_from_ep(akotg_usbhc_to_hcd(akotghc), urb); -+ spin_unlock(&akotghc->lock); -+ usb_hcd_giveback_urb(akotg_usbhc_to_hcd(akotghc), urb, status); -+ spin_lock(&akotghc->lock); -+ -+ /* leave active endpoints in the schedule */ -+ if (!list_empty(&ep->hep->urb_list)) -+ return; -+ -+ /* async deschedule? */ -+ if (!list_empty(&ep->schedule)) { -+ list_del_init(&ep->schedule); -+ if (ep == akotghc->next_async_ep0) -+ akotghc->next_async_ep0 = NULL; -+ return; -+ } -+} -+ -+ -+static void finish_request_epx( -+ struct akotg_usbhc *akotghc, -+ struct akotghc_ep *ep, -+ struct urb *urb, -+ int status -+) __releases(akotghc->lock) __acquires(akotghc->lock) -+{ -+ unsigned i; -+ int is_out; -+ is_out = usb_pipeout(urb->pipe); -+ -+ VDBG("Finishing EPx URB Request...\n"); -+ -+ if (usb_pipecontrol(urb->pipe)) -+ ep->nextpid = USB_PID_SETUP; -+ -+ usb_hcd_unlink_urb_from_ep(akotg_usbhc_to_hcd(akotghc), urb); -+ spin_unlock(&akotghc->lock); -+ usb_hcd_giveback_urb(akotg_usbhc_to_hcd(akotghc), urb, status); -+ spin_lock(&akotghc->lock); -+ -+ /* leave active endpoints in the schedule */ -+ if (!list_empty(&ep->hep->urb_list)) -+ return; -+ -+ -+ /* async deschedule? */ -+ //if(epnum_to_epfifo(&akotg_epfifo_mapping, ep->epnum, is_out, &epfifo) && !list_empty(&ep->schedule)) { -+ if (!list_empty(&ep->schedule)) { -+ list_del_init(&ep->schedule); -+ if (ep == akotghc->next_async_epx[ep->epfifo-1]) { -+ akotghc->next_async_epx[ep->epfifo-1] = NULL; -+ } -+ return; -+ } -+ -+ switch(usb_pipetype(urb->pipe)) { -+ case PIPE_ISOCHRONOUS: -+ case PIPE_INTERRUPT: -+ /* periodic deschedule */ -+ HDBG("%s(): deschedule qh%d/%p branch %d\n", -+ __func__, ep->period, ep, ep->branch); -+ for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { -+ struct akotghc_ep *temp; -+ struct akotghc_ep **prev = &akotghc->periodic[i]; -+ -+ while (*prev && ((temp = *prev) != ep)) -+ prev = &temp->next; -+ if (*prev) -+ *prev = ep->next; -+ akotghc->load[i] -= ep->load; -+ } -+ ep->branch = PERIODIC_SIZE; -+ akotghc->periodic_count--; -+ -+ akotg_usbhc_to_hcd(akotghc)->self.bandwidth_allocated -+ -= ep->load / ep->period; -+ if (ep == akotghc->next_periodic) -+ akotghc->next_periodic = ep->next; -+ -+ /* we might turn SOFs back on again for the async schedule */ -+ if (akotghc->periodic_count == 0) -+ sofirq_off(akotghc); -+ } -+} -+ -+static void -+done(struct akotg_usbhc *akotghc, struct akotghc_ep *ep) -+{ -+ int i; -+ int err_occurred = 0; -+ int epfifo; -+ u8 status; -+ u8 rxstatus; -+ struct urb *urb; -+ unsigned int pipe; -+ int is_out; -+ int urbstat = -EINPROGRESS; -+ -+ if (unlikely(!ep)) { -+ return; -+ } -+ -+ urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); -+ pipe = urb->pipe; -+ is_out = usb_pipeout(pipe); -+ if (!epnum_to_epfifo(&akotg_epfifo_mapping, ep->epnum, is_out, &epfifo)) -+ BUG(); /* Impossible, USB Device Endpoint *MUST* have been mapped to EPFIFO */ -+ -+ status = hc_index_readw(epfifo, USB_REG_TXCSR1); -+ rxstatus = hc_index_readw(epfifo, USB_REG_RXCSR1); -+ -+ //STALL -+ if (((epfifo != 0) && ((status & (1 << 5)) || rxstatus & (1 << 6))) -+ || ((epfifo == 0) && (status & (1 << 2)))) { -+ ep->error_count = 0; -+ urbstat = -EPIPE; -+ err_occurred = 1; -+ } -+ -+ //NAK timeout -+ if ((usb_pipebulk(pipe)) -+ &&((status & (1 << 7))||(rxstatus & (1 << 3)))) { -+ if (!ep->period) -+ ep->nak_count++; -+ ep->error_count = 0; -+ err_occurred = 1; -+ } -+ -+ //Error, times expired -+ if (((epfifo == 0) && (status & (1 << 4))) -+ ||((epfifo != 0)&&((status || rxstatus) & (1 << 2)) -+ &&(usb_pipeint(pipe)||usb_pipebulk(pipe)))) { -+ urbstat = -EPROTO; -+ ep->error_count = 0; -+ err_occurred = 1; -+ } -+ -+ if (err_occurred) { -+ if (epfifo == 0) -+ hc_index_writew(0, 0, USB_REG_TXCSR1); -+ else if (is_out) -+ if (urbstat == -EPIPE) -+ // clear stall bit and clear toggle -+ hc_index_writew(epfifo, (1 << 6), USB_REG_TXCSR1); -+ else -+ hc_index_writew(epfifo, 0, USB_REG_TXCSR1); -+ else -+ if (urbstat == -EPIPE) -+ // clear stall bit and clear toggle -+ hc_index_writew(epfifo, (1 << 7), USB_REG_RXCSR1); -+ else -+ hc_index_writew(epfifo, 0, USB_REG_RXCSR1); -+ } -+ else { -+ -+ struct usb_device *udev = urb->dev; -+ int len; -+ unsigned char *buf; -+ -+ /* urb->iso_frame_desc is currently ignored here... */ -+ -+ ep->nak_count = ep->error_count = 0; -+ switch (ep->nextpid) { -+ case USB_PID_OUT: -+ urb->actual_length += ep->length; -+ usb_dotoggle(udev, ep->epnum, 1); -+ if (urb->actual_length == urb->transfer_buffer_length) { -+ if (usb_pipecontrol(urb->pipe)) { -+ VDBG("NEXT Packet: Status Packet.\n"); -+ ep->nextpid = USB_PID_ACK; -+ } -+ -+ /* some bulk protocols terminate OUT transfers -+ * by a short packet, using ZLPs not padding. -+ */ -+ else if (ep->length < ep->maxpacket -+ || !(urb->transfer_flags & URB_ZERO_PACKET)) -+ urbstat = 0; -+ } -+ break; -+ case USB_PID_IN: -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ if(ep->bdma){ -+ urb->actual_length += akotg_dma_get_trans_length(akotghc, epfifo); -+ -+ akotg_dma_clear(akotghc, epfifo); -+ ep->bdma = false; -+ } -+#endif -+ -+ buf = urb->transfer_buffer + urb->actual_length; -+ -+ prefetchw(buf); -+ len = hc_index_readw(epfifo, USB_REG_COUNT0); -+ if (len > ep->length) { -+ printk(" USB_PID_IN(OverFlow): len=%d, ep->length=%d\n", -+ len, ep->length); -+ len = ep->length; -+ urbstat = -EOVERFLOW; -+ } -+ // read data from fifo -+ urb->actual_length += len; -+ for (i = 0; i < len; i++) -+ *buf++ = hc_readb(ep_fifos[epfifo]); -+ -+ if (ep->epnum == 0) { -+ u8 regval = hc_index_readb(epfifo, USB_REG_TXCSR1); -+ regval &= ~USB_TXCSR1_TXPKTRDY; -+ hc_index_writeb(epfifo, regval, USB_REG_TXCSR1); -+ } else { -+ u8 regval = hc_index_readb(epfifo, USB_REG_RXCSR1); -+ regval &= ~USB_RXCSR1_RXPKTRDY; -+ hc_index_writeb(epfifo, regval, USB_REG_RXCSR1); -+ } -+ -+ usb_dotoggle(udev, ep->epnum, 0); -+ if (urbstat == -EINPROGRESS && -+ (len < ep->maxpacket || -+ urb->actual_length == urb->transfer_buffer_length)) { -+ if (usb_pipecontrol(urb->pipe)) { -+ VDBG("NEXT Packet: Status Packet.\n"); -+ ep->nextpid = USB_PID_ACK; -+ } -+ else -+ urbstat = 0; -+ } -+ break; -+ case USB_PID_SETUP: -+ if (urb->transfer_buffer_length == urb->actual_length) { -+ VDBG("NEXT Packet: Status Packet.\n"); -+ ep->nextpid = USB_PID_ACK; -+ } -+ else if (usb_pipeout(urb->pipe)) { -+ VDBG("NEXT Packet: OUT Packet.\n"); -+ usb_settoggle(udev, 0, 1, 1); -+ ep->nextpid = USB_PID_OUT; -+ } else { -+ VDBG("NEXT Packet: IN Packet.\n"); -+ usb_settoggle(udev, 0, 0, 1); -+ ep->nextpid = USB_PID_IN; -+ } -+ break; -+ case USB_PID_ACK: -+ if (!is_out) { -+ u8 regval = hc_index_readb(epfifo, USB_REG_RXCSR1); -+ regval &= ~USB_RXCSR1_RXPKTRDY; -+ hc_index_writeb(epfifo, regval, USB_REG_RXCSR1); -+ } -+ urbstat = 0; -+ break; -+ } -+ } -+ -+ if (urbstat != -EINPROGRESS || urb->unlinked) { -+ if (ep->epnum == 0) -+ finish_request_ep0(akotghc, ep, urb, urbstat); -+ else -+ finish_request_epx(akotghc, ep, urb, urbstat); -+ } -+} -+ -+static int balance(struct akotg_usbhc *akotghc, u16 period, u16 load) -+{ -+ int i, branch = -ENOSPC; -+ -+ /* search for the least loaded schedule branch of that period -+ * which has enough bandwidth left unreserved. -+ */ -+ for (i = 0; i < period ; i++) { -+ if (branch < 0 || akotghc->load[branch] > akotghc->load[i]) { -+ int j; -+ -+ for (j = i; j < PERIODIC_SIZE; j += period) { -+ if ((akotghc->load[j] + load) -+ > MAX_PERIODIC_LOAD) -+ break; -+ } -+ if (j < PERIODIC_SIZE) -+ continue; -+ branch = i; -+ } -+ } -+ return branch; -+} -+ -+static void reset_otg(struct work_struct *work) -+{ -+ unsigned long con; -+ -+ /* power up and set usb suspend bit */ -+ con = __raw_readl(USB_OP_MOD_REG); -+ con &= ~(0x7 << 0); -+ con |= (0x3 << 1); -+ __raw_writel(con, USB_OP_MOD_REG); -+ -+ set_usb_as_host(); -+ -+ /* start fs host session*/ -+ hc_writeb(USB_DEVCTL_SESSION, USB_REG_DEVCTL); -+} -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ -+static bool handle_dma_irq(struct akotg_usbhc *akotghc, struct akotg_dma *dma) -+{ -+ u8 epfifo = dma->epfifo; -+ u8 channel = dma->channel; -+ u32 regtmp; -+ u32 trans_len; -+ int urbstat = -EINPROGRESS; -+ -+ struct akotghc_ep *ep; -+ struct urb *urb; -+ -+ if(!akotghc || !dma) -+ return false; -+ -+ if(USB_DIRECTION_RX == dma->dir){ -+ hc_index_writeb(epfifo, 0, USB_REG_RXCSR2); -+ -+ regtmp = hc_readl(USB_DMA_ADDR(channel)); -+ trans_len = regtmp - dma->addr; -+ -+ dma_unmap_single(NULL, dma->phyaddr, dma->count, DMA_FROM_DEVICE); -+ } -+ else{ -+ hc_index_writeb(epfifo, USB_TXCSR2_MODE, USB_REG_TXCSR2); -+ -+ trans_len = dma->count; -+ -+ dma_unmap_single(NULL, dma->phyaddr, dma->count, DMA_TO_DEVICE); -+ } -+ -+ -+ hc_writel(0, USB_DMA_COUNT(channel)); -+ -+ //wait dma finish -+ l2_combuf_wait_dma_finish(dma->l2buffer); -+ -+ //free l2 buffer -+ akotg_free_l2_buffer(epfifo); -+ dma->l2buffer = BUF_NULL; -+ -+ //change status -+ dma->status = USB_DMA_CHANNEL_IDLE; -+ -+ //get urb -+ ep = akotghc->active_epx[epfifo-1]; -+ -+ ep->bdma = false; -+ urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); -+ -+ urb->actual_length += trans_len; -+ -+ //done -+ if((urb->actual_length == urb->transfer_buffer_length) || urb->unlinked) -+ { -+ urbstat = 0; -+ finish_request_epx(akotghc, ep, urb, urbstat); -+ } -+ -+ akotghc->active_epx[epfifo-1] = NULL; -+ -+ return true; -+ -+} -+ -+irqreturn_t akotg_dma_irq(int irqnum, void *__hcd) -+{ -+ struct usb_hcd *hcd = __hcd; -+ unsigned long flags; -+ irqreturn_t rc; -+ -+ local_irq_save(flags); -+ -+ if (unlikely(hcd->state == HC_STATE_HALT || -+ !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { -+ rc = IRQ_NONE; -+ } else if (akotg_usbhc_irq(hcd) == IRQ_NONE) { -+ rc = IRQ_NONE; -+ } else { -+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); // ??? -+ -+ if (unlikely(hcd->state == HC_STATE_HALT)) -+ usb_hc_died(hcd); -+ rc = IRQ_HANDLED; -+ } -+ -+ //rc = akotg_usbhc_irq(hcd); -+ -+ local_irq_restore(flags); -+ -+ return rc; -+} -+ -+#endif -+ -+irqreturn_t akotg_usbhc_irq(struct usb_hcd *hcd) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ irqreturn_t ret = IRQ_NONE; -+ struct urb *urb; -+ struct akotghc_ep *ep; -+ int epnum[MAX_EP_NUM + 1] = { 0 }; -+ int i; -+ unsigned index = 0; -+ -+ char rINTCOM; -+ unsigned short rINTTX, rINTRX; -+ -+ u32 rINTDMA; -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ struct akotg_dma *dma; -+#endif -+ -+ spin_lock(&akotghc->lock); -+ -+ /*Read & Clear all interrupt status.*/ -+ rINTCOM = hc_readb(USB_REG_INTRUSB); -+ rINTTX =hc_readw(USB_REG_INTRTX); -+ rINTRX = hc_readw(USB_REG_INTRRX); -+ rINTDMA =hc_readl(USB_DMA_INTR); -+ -+ if (rINTTX &USB_INTR_EP0) { -+ epnum[0] = 1; -+ done(akotghc, akotghc->active_ep0); -+ akotghc->active_ep0 = NULL; -+ } -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ if(rINTDMA) -+ { -+ //printk("|%x|", rINTDMA); -+ //printk("C[%x,%x]", hcd, m_hcd); -+ for(i = 0; i < USBDMA_CHANNEL_NUM; i++) -+ { -+ if(rINTDMA & (1<<i)) -+ { -+ dma = akotg_dma_get_struct(akotghc, i); -+ handle_dma_irq(akotghc, dma); -+ } -+ } -+ } -+#endif -+ -+ for(i=0; i<MAX_EP_NUM; i++) -+ if((rINTTX & (1<<(i+1))) || (rINTRX & (1<<(i+1)))) { -+ epnum[i + 1] = 1; -+ done(akotghc, akotghc->active_epx[i]); -+ akotghc->active_epx[i] = NULL; -+ } -+ -+ if (rINTCOM & USB_INTR_SOF) { -+ index = akotghc->frame++ & (PERIODIC_SIZE - 1); -+ -+ -+ /* be graceful about almost-inevitable periodic schedule -+ * overruns: continue the previous frame's transfers iff -+ * this one has nothing scheduled. -+ */ -+ -+ if (akotghc->periodic[index]) { -+ akotghc->next_periodic = akotghc->periodic[index]; -+ } -+ } -+ -+ /* manages debouncing and wakeup */ -+ if(rINTCOM & (USB_INTR_CONNECT | USB_INTR_DISCONNECT)) { -+ -+ /* most stats are reset for each VBUS session */ -+ -+ /* usbcore nukes other pending transactions on disconnect */ -+ if (akotghc->active_ep0) { -+ VDBG("Finishing EP0 Active URBs...\n"); -+ ep = akotghc->active_ep0; -+ hc_index_writeb(ep->epfifo, 0, USB_REG_TXCSR1); -+ hc_index_writeb(ep->epfifo, USB_CSR02_FLUSHFIFO, USB_REG_TXCSR2); -+ -+ finish_request_ep0(akotghc, akotghc->active_ep0, -+ container_of(akotghc->active_ep0->hep->urb_list.next, struct urb, urb_list), -+ -ESHUTDOWN); -+ akotghc->active_ep0 = NULL; -+ } -+ -+ for(i=0; i<MAX_EP_NUM; i++) -+ if (akotghc->active_epx[i]) { -+ VDBG("Finishing EPx Active URBs...\n"); -+ ep = akotghc->active_epx[i]; -+ urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); -+ //if (!epnum_to_epfifo(&akotg_epfifo_mapping, ep->epnum, is_out, &epfifo)) -+ // BUG(); -+ if (usb_pipeout(urb->pipe)) { -+ hc_index_writeb(ep->epfifo, USB_TXCSR1_FLUSHFIFO, USB_REG_TXCSR1); -+ } else { -+ hc_index_writeb(ep->epfifo, USB_RXCSR1_FLUSHFIFO, USB_REG_RXCSR1); -+ } -+ -+ finish_request_epx(akotghc, akotghc->active_epx[i], -+ container_of(akotghc->active_epx[i]->hep->urb_list.next, struct urb, urb_list), -+ -ESHUTDOWN); -+ akotghc->active_epx[i] = NULL; -+ } -+ -+ /* port status seems weird until after reset, so -+ * force the reset and make khubd clean up later. -+ */ -+ if (rINTCOM & USB_INTR_CONNECT) { -+ akotghc->port_status |= 1 << USB_PORT_FEAT_CONNECTION; -+ akotghc->port_status |= 1 << USB_PORT_FEAT_C_CONNECTION; -+ } else { -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ //clear all dma -+ akotg_dma_clear(akotghc, 0); -+#endif -+ period_epfifo = 0; -+ akotghc->port_status &= ~(1 << USB_PORT_FEAT_CONNECTION); -+ akotghc->port_status |= 1 << USB_PORT_FEAT_C_CONNECTION; -+ init_epfifo_mapping(&akotg_epfifo_mapping); -+ reset_endpoints(); -+ REG32(USB_OP_MOD_REG) &= ~(0xff << 6); -+ REG32(USB_OP_MOD_REG) |= (0x1f << 6); -+ hc_writeb(0x0, USB_REG_DEVCTL); -+ hc_writeb(0x0, USB_REG_FADDR); -+ -+ queue_delayed_work(g_otghc_wq, &g_otg_rest, 0); -+ } -+ } -+ -+ if (rINTCOM & USB_INTR_RESUME) { -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { -+ HDBG("wakeup\n"); -+ akotghc->port_status |= 1 << USB_PORT_FEAT_C_SUSPEND; -+ -+ } -+ rINTCOM &= ~(USB_INTR_RESUME); -+ } -+ -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_ENABLE)) { -+ if (epnum[0]) { -+ start_transfer(akotghc, 0); -+ ret = IRQ_HANDLED; -+ } -+ if((rINTCOM & USB_INTR_SOF) && akotghc->periodic[index] && period_epfifo){ -+ start_transfer(akotghc, period_epfifo); -+ ret = IRQ_HANDLED; -+ } -+ for(i = 0; i < MAX_EP_NUM; i++) { -+ if(epnum[i + 1]) { -+ start_transfer(akotghc, i + 1); -+ ret = IRQ_HANDLED; -+ } -+ } -+ -+#ifdef CONFIG_USB_AKOTG_DMA -+ for(i = 0; i < USBDMA_CHANNEL_NUM; i++) -+ { -+ if(rINTDMA & (1<<i)) -+ { -+ dma = akotg_dma_get_struct(akotghc, i); -+ start_transfer(akotghc, dma->epfifo); -+ ret = IRQ_HANDLED; -+ } -+ } -+#endif -+ } -+ -+ if(akotghc->periodic_count == 0 && list_empty(&akotghc->async_ep0)) { -+ for(i = 0; i < MAX_EP_NUM; i++) { -+ if(!list_empty(&akotghc->async_epx[i])) -+ break; -+ } -+ if(i == MAX_EP_NUM) -+ sofirq_off(akotghc); -+ } -+ -+ spin_unlock(&akotghc->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(akotg_usbhc_irq); -+ -+int akotg_usbhc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ struct usb_host_endpoint *hep; -+ unsigned long flags; -+ struct akotghc_ep *ep; -+ int retval, i; -+ int is_out = usb_pipeout(urb->pipe); -+ -+ HDBG("Dequeue: Direction=%s, Type=%s, EP Num=%d, urb=%p\n", -+ is_out ? "OUT" : "IN", trans_desc[usb_pipetype(urb->pipe)], -+ usb_pipeendpoint(urb->pipe), urb); -+ -+ spin_lock_irqsave(&akotghc->lock, flags); -+ -+ retval = usb_hcd_check_unlink_urb(hcd, urb, status); -+ if (retval) { -+ printk("Dequeue: check and unlink urb failed!\n"); -+ goto fail; -+ } -+ -+ hep = urb->hcpriv; -+ ep = hep->hcpriv; -+ if (ep) { -+ /* finish right away if this urb can't be active ... -+ * note that some drivers wrongly expect delays -+ */ -+ if (ep->hep->urb_list.next != &urb->urb_list) { -+ /* not front of queue? never active */ -+ -+ /* for active transfers, we expect an IRQ */ -+ } else if (akotghc->active_ep0 == ep) { -+ if (time_before_eq(akotghc->jiffies_ep0, jiffies)) { -+ hc_index_writeb(0, 0, USB_REG_TXCSR1); -+ hc_index_writeb(0, 1 << 0, USB_REG_TXCSR2); -+ akotghc->active_ep0 = NULL; -+ } else -+ urb = NULL; -+ -+ } else { -+ for(i=0; i<MAX_EP_NUM; i++) { -+ if(akotghc->active_epx[i] == ep) { -+ if(time_before_eq(akotghc->jiffies_epx[i], jiffies)) { -+ //if(!epnum_to_epfifo(&akotg_epfifo_mapping, ep->epnum, is_out, &epfifo)) -+ // BUG(); -+ if (is_out) { -+ hc_index_writeb(ep->epfifo, USB_TXCSR1_FLUSHFIFO, USB_REG_TXCSR1); -+ } else { -+ hc_index_writeb(ep->epfifo, USB_RXCSR1_FLUSHFIFO, USB_REG_RXCSR1); -+ } -+ akotghc->active_epx[i] = NULL; -+ } else -+ urb = NULL; -+ -+ } -+ } -+ /* front of queue for inactive endpoint */ -+ } -+ -+ if (urb) { -+ if (akotghc->active_ep0 == ep) -+ finish_request_ep0(akotghc, ep, urb, 0); -+ else -+ finish_request_epx(akotghc, ep, urb, 0); -+ } else { -+ HDBG("dequeue, urb %p active, wait for irq.\n", urb); -+ } -+ } else -+ retval = -EINVAL; -+ fail: -+ spin_unlock_irqrestore(&akotghc->lock, flags); -+ -+ return retval; -+} -+ -+ -+ -+int -+akotg_usbhc_urb_enqueue( -+ struct usb_hcd *hcd, -+ struct urb *urb, -+ gfp_t mem_flags -+) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ struct usb_device *udev = urb->dev; -+ int is_out = usb_pipeout(urb->pipe); -+ int type = usb_pipetype(urb->pipe); -+ int epnum = usb_pipeendpoint(urb->pipe); -+ int epfifo = 0; -+ -+ struct akotghc_ep *ep = NULL; -+ unsigned long flags; -+ int i; -+ int retval; -+ struct usb_host_endpoint *hep = urb->ep; -+ -+ HDBG("Enqueue: Direction=%s, Type=%s, EP Num=%d, urb=%p" -+ " urb->transfer_buffer_length=%d\n", -+ is_out ? "OUT" : "IN", trans_desc[type], epnum, urb, -+ urb->transfer_buffer_length); -+ -+ if (usb_pipeisoc(urb->pipe)) -+ return -ENOSPC; -+ -+ spin_lock_irqsave(&akotg_epfifo_mapping.lock,flags); -+ if (!__is_epnum_mapped(&akotg_epfifo_mapping, epnum, is_out)) { -+ if (!__map_epnum_to_epfifo(&akotg_epfifo_mapping, epnum, is_out, &epfifo)) { -+ spin_unlock_irqrestore(&akotg_epfifo_mapping.lock, flags); -+ return -ENOSPC; -+ } -+ -+ if (epnum != 0) { -+ -+ int eptype = get_ep_type(urb->pipe); -+ -+ if (is_out) { -+ disable_epx_tx_interrupt(epfifo); -+ set_epx_tx_type(epfifo, epnum, eptype); -+ hc_index_writew(epfifo, hep->desc.wMaxPacketSize, USB_REG_TXMAXP); -+ hc_index_writeb(epfifo, 16, USB_REG_TXINTERVAL); /* Tx Interval */ -+ clear_epx_tx_data_toggle(epfifo); -+ set_epx_tx_mode(epfifo); -+ flush_epx_tx_fifo(epfifo); -+ enable_epx_tx_interrupt(epfifo); -+ } else { -+ disable_epx_rx_interrupt(epfifo); -+ set_epx_rx_type(epfifo, epnum, eptype); -+ hc_index_writew(epfifo, hep->desc.wMaxPacketSize, USB_REG_RXMAXP); -+ if (usb_endpoint_xfer_isoc(&hep->desc) || usb_endpoint_xfer_int(&hep->desc)) -+ hc_index_writeb(epfifo, hep->desc.bInterval, USB_REG_RXINTERVAL); -+ else -+ hc_index_writeb(epfifo, 0, USB_REG_RXINTERVAL); -+ set_epx_rx_mode(epfifo); -+ clear_epx_rx_data_toggle(epfifo); -+ flush_epx_rx_fifo(epfifo); -+ enable_epx_rx_interrupt(epfifo); -+ } -+ } -+ } else { -+ if(!epnum_to_epfifo(&akotg_epfifo_mapping, epnum, is_out, &epfifo)) -+ BUG(); -+ } -+ -+ spin_unlock_irqrestore(&akotg_epfifo_mapping.lock, flags); -+ -+ spin_lock_irqsave(&akotghc->lock, flags); -+ -+ /* don't submit to a dead or disabled port */ -+ if (!(akotghc->port_status & (1 << USB_PORT_FEAT_ENABLE)) -+ || !HC_IS_RUNNING(hcd->state)) { -+ retval = -ENODEV; -+ goto fail_not_linked; -+ } -+ -+ retval = usb_hcd_link_urb_to_ep(hcd, urb); -+ if (retval) { -+ goto fail_not_linked; -+ } -+ -+ /* avoid all allocations within spinlocks */ -+ if (hep->hcpriv) { -+ ep = hep->hcpriv; -+ } else { -+ ep = kzalloc(sizeof *ep, mem_flags); -+ if (ep == NULL) { -+ retval = -ENOMEM; -+ goto fail; -+ } -+ -+ INIT_LIST_HEAD(&ep->schedule); -+ ep->udev = udev; -+ ep->epnum = epnum; -+ ep->epfifo = epfifo; -+ ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); -+ -+ usb_settoggle(udev, epnum, is_out, 0); -+ -+ if (type == PIPE_CONTROL) -+ ep->nextpid = USB_PID_SETUP; -+ else if (is_out) -+ ep->nextpid = USB_PID_OUT; -+ else -+ ep->nextpid = USB_PID_IN; -+ -+ if (ep->maxpacket > H_MAXPACKET) { -+ /* iso packets up to 240 bytes could work... */ -+ HDBG("dev %d ep%d maxpacket %d\n", -+ udev->devnum, epnum, ep->maxpacket); -+ retval = -EINVAL; -+ goto fail; -+ } -+ -+ switch (type) { -+ case PIPE_ISOCHRONOUS: -+ case PIPE_INTERRUPT: -+ if (urb->interval > PERIODIC_SIZE) -+ urb->interval = PERIODIC_SIZE; -+ ep->period = urb->interval; -+ ep->branch = PERIODIC_SIZE; -+ ep->load = usb_calc_bus_time(udev->speed, !is_out, -+ (type == PIPE_ISOCHRONOUS), -+ usb_maxpacket(udev, urb->pipe, is_out)) / 1000; -+ period_epfifo = epfifo; -+ break; -+ } -+ -+ ep->hep = hep; -+ hep->hcpriv = ep; -+ } -+ -+ /* maybe put endpoint into schedule */ -+ switch (type) { -+ case PIPE_CONTROL: -+ case PIPE_BULK: -+ if (list_empty(&ep->schedule)) { -+ if (epnum == 0) -+ list_add_tail(&ep->schedule, &akotghc->async_ep0); -+ else -+ list_add_tail(&ep->schedule, &akotghc->async_epx[epfifo-1]); -+ } -+ break; -+ case PIPE_ISOCHRONOUS: -+ case PIPE_INTERRUPT: -+ urb->interval = ep->period; -+ if (ep->branch < PERIODIC_SIZE) { -+ /* NOTE: the phase is correct here, but the value -+ * needs offsetting by the transfer queue depth. -+ * All current drivers ignore start_frame, so this -+ * is unlikely to ever matter... -+ */ -+ urb->start_frame = (akotghc->frame & (PERIODIC_SIZE - 1)) -+ + ep->branch; -+ break; -+ } -+ -+ retval = balance(akotghc, ep->period, ep->load); -+ if (retval < 0) -+ goto fail; -+ ep->branch = retval; -+ retval = 0; -+ urb->start_frame = (akotghc->frame & (PERIODIC_SIZE - 1)) -+ + ep->branch; -+ -+ /* sort each schedule branch by period (slow before fast) -+ * to share the faster parts of the tree without needing -+ * dummy/placeholder nodes -+ */ -+ VDBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); -+ for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { -+ struct akotghc_ep **prev = &akotghc->periodic[i]; -+ struct akotghc_ep *here = *prev; -+ -+ while (here && ep != here) { -+ if (ep->period > here->period) -+ break; -+ prev = &here->next; -+ here = *prev; -+ } -+ if (ep != here) { -+ ep->next = here; -+ *prev = ep; -+ } -+ akotghc->load[i] += ep->load; -+ } -+ akotghc->periodic_count++; -+ hcd->self.bandwidth_allocated += ep->load / ep->period; -+ sofirq_on(akotghc); -+ } -+ -+ urb->hcpriv = hep; -+ start_transfer(akotghc, epfifo); -+ -+fail: -+ if (retval) -+ usb_hcd_unlink_urb_from_ep(hcd, urb); -+fail_not_linked: -+ spin_unlock_irqrestore(&akotghc->lock, flags); -+ return retval; -+} -+ -+ -+void -+akotg_usbhc_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *hep) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ int epnum = usb_endpoint_num(&hep->desc); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&akotghc->lock, flags); -+ -+ HDBG("Resetting EP %d, Type=%s, Dir=%s\n", -+ epnum, xfer_name[usb_endpoint_type(&hep->desc)], usb_endpoint_dir_out(&hep->desc)? "OUT" : "IN"); -+ -+ if (epnum == 0) { -+ hc_index_writeb(0, 0, USB_REG_TXINTERVAL); -+ hc_index_writew(0, 0, USB_REG_TXCSR1); -+ flush_ep0_fifo(); -+ enable_ep0_interrupt(); -+ } else { -+ -+ } -+ -+ spin_unlock_irqrestore(&akotghc->lock, flags); -+} -+ -+void -+akotg_usbhc_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) -+{ -+ struct akotghc_ep *ep = hep->hcpriv; -+ -+ int epnum = usb_endpoint_num(&hep->desc); -+ int is_out = usb_endpoint_dir_out(&hep->desc); -+ -+ int epfifo = 0; -+ -+ -+ if (!ep) { -+ return; -+ } -+ -+ if (is_epnum_mapped(&akotg_epfifo_mapping, epnum, is_out)) { -+ -+ disable_ep_interrupt(epfifo); -+ flush_ep_fifo(epfifo); -+ } -+ /* assume we'd just wait for the irq */ -+ if (!list_empty(&hep->urb_list)) -+ msleep(3); -+ if (!list_empty(&hep->urb_list)) -+ HDBG("ep %p not empty?\n", ep); -+ -+ kfree(ep); -+ hep->hcpriv = NULL; -+ -+} -+ -+int -+akotg_usbhc_get_frame(struct usb_hcd *hcd) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ -+ /* wrong except while periodic transfers are scheduled; -+ * never matches the on-the-wire frame; -+ * subject to overruns. -+ */ -+ return akotghc->frame; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* the virtual root hub timer IRQ checks for hub status */ -+int -+akotg_usbhc_hub_status_data(struct usb_hcd *hcd, char *buf) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ unsigned long flags; -+ -+ /* non-SMP HACK: use root hub timer as i/o watchdog -+ * this seems essential when SOF IRQs aren't in use... -+ */ -+ local_irq_save(flags); -+ if (!timer_pending(&akotghc->timer)) { -+ if (akotg_usbhc_irq( /* ~0, */ hcd) != IRQ_NONE) -+ ;//akotghc->stat_lost++; -+ } -+ local_irq_restore(flags); -+ -+ if (!(akotghc->port_status & (0xffff << 16))) { -+ return 0; -+ } -+ -+ /* tell khubd port 1 changed */ -+ *buf = (1 << 1); -+ -+ return 1; -+} -+ -+void -+akotg_usbhc_hub_descriptor ( -+ struct akotg_usbhc *akotghc, -+ struct usb_hub_descriptor *desc -+) { -+ u16 temp = 0; -+ -+ desc->bDescriptorType = 0x29; -+ desc->bHubContrCurrent = 0; -+ -+ desc->bNbrPorts = 1; -+ desc->bDescLength = 9; -+ -+ /* per-port power switching (gang of one!), or none */ -+ desc->bPwrOn2PwrGood = 0; -+ -+ /* no over current errors detection/handling */ -+ temp |= HUB_CHAR_COMMON_LPSM|HUB_CHAR_NO_OCPM; -+ -+ desc->wHubCharacteristics = cpu_to_le16(temp); -+ -+ /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ -+ desc->u.hs.DeviceRemovable[0] = 0 << 1; -+ desc->u.hs.DeviceRemovable[1] = ~0; -+} -+ -+void -+akotg_usbhc_timer(unsigned long _akotghs) -+{ -+ struct akotg_usbhc *akotghc = (void *) _akotghs; -+ unsigned long flags; -+ const u32 mask = (1 << USB_PORT_FEAT_CONNECTION) -+ | (1 << USB_PORT_FEAT_ENABLE); -+ -+ -+ spin_lock_irqsave(&akotghc->lock, flags); -+ -+ if (akotghc->port_status & USB_PORT_STAT_RESET) { -+ akotghc->port_status = (1 << USB_PORT_FEAT_C_RESET) -+ | (1 << USB_PORT_FEAT_POWER); -+ akotghc->port_status |= mask; -+ -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_CONNECTION)) { -+ if ((hc_readb(USB_REG_DEVCTL) & USB_DEVCTL_FSDEV)) { -+ akotghc->port_status |= USB_PORT_STAT_HIGH_SPEED; -+ } else { -+ /* Plug-in & plug-out quickly could lead to this... */ -+ akotghc->port_status &= ~mask; -+ } -+ } -+ } else { -+ /* NOT IMPLEMENTED YET */ -+ BUG(); -+ } -+ -+ -+ spin_unlock_irqrestore(&akotghc->lock, flags); -+ -+} -+ -+int -+akotg_usbhc_hub_control( -+ struct usb_hcd *hcd, -+ u16 typeReq, -+ u16 wValue, -+ u16 wIndex, -+ char *buf, -+ u16 wLength -+) { -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ int retval = 0; -+ unsigned long flags; -+ char reg8val; -+ -+ HDBG("%s(): typeReq=0x%x, wValue=%d, wIndex=%d, wLength=%d\t", -+ __func__, typeReq, wValue, wIndex, wLength); -+ -+ spin_lock_irqsave(&akotghc->lock, flags); -+ -+ switch (typeReq) { -+ case ClearHubFeature: -+ case SetHubFeature: -+ switch (wValue) { -+ case C_HUB_OVER_CURRENT: -+ case C_HUB_LOCAL_POWER: -+ break; -+ default: -+ goto error; -+ } -+ break; -+ case ClearPortFeature: -+ if (wIndex != 1 || wLength != 0) -+ goto error; -+ switch (wValue) { -+ case USB_PORT_FEAT_ENABLE: -+ HDBG("ClearPortFeature: USB_PORT_FEAT_ENABLE\n"); -+ akotghc->port_status &= (1 << USB_PORT_FEAT_POWER); -+ break; -+ case USB_PORT_FEAT_SUSPEND: -+ HDBG("ClearPortFeature: USB_PORT_FEAT_SUSPEND\n"); -+ if (!(akotghc->port_status & (1 << USB_PORT_FEAT_SUSPEND))) -+ break; -+ -+ /* 20 msec of resume/K signaling, other irqs blocked */ -+ HDBG(" start resume...\n"); -+ hc_writeb(0x0, USB_REG_INTRUSBE); -+ reg8val = hc_readb(USB_REG_POWER); -+ reg8val |= USB_POWER_RESUME; -+ hc_writeb(reg8val, USB_REG_POWER); -+ -+ mod_timer(&akotghc->timer, jiffies + msecs_to_jiffies(20)); -+ break; -+ case USB_PORT_FEAT_POWER: -+ port_power(akotghc, 0); -+ break; -+ case USB_PORT_FEAT_C_ENABLE: -+ case USB_PORT_FEAT_C_SUSPEND: -+ case USB_PORT_FEAT_C_CONNECTION: -+ break; -+ case USB_PORT_FEAT_C_OVER_CURRENT: -+ case USB_PORT_FEAT_C_RESET: -+ break; -+ default: -+ goto error; -+ } -+ akotghc->port_status &= ~(1 << wValue); -+ break; -+ case GetHubDescriptor: -+ akotg_usbhc_hub_descriptor(akotghc, (struct usb_hub_descriptor *) buf); -+ break; -+ case GetHubStatus: -+ put_unaligned_le32(0, buf); -+ break; -+ case GetPortStatus: -+ if (wIndex != 1) -+ goto error; -+ put_unaligned_le32(akotghc->port_status, buf); -+ if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ -+ HDBG(" GetPortStatus 0x%04x\n", akotghc->port_status); -+ break; -+ case SetPortFeature: -+ if (wIndex != 1 || wLength != 0) -+ goto error; -+ switch (wValue) { -+ case USB_PORT_FEAT_SUSPEND: -+ HDBG("SetPortFeature: USB_PORT_FEAT_SUSPEND\n"); -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_RESET)) -+ goto error; -+ if (!(akotghc->port_status & (1 << USB_PORT_FEAT_ENABLE))) -+ goto error; -+ /*to suspend the usb host controller.*/ -+ reg8val = hc_readb(USB_REG_POWER); -+ reg8val |= USB_POWER_SUSPENDM; -+ hc_writeb(reg8val, USB_REG_POWER); -+ break; -+ case USB_PORT_FEAT_POWER: -+ HDBG("SetPortFeature: USB_PORT_FEAT_POWER\n"); -+ port_power(akotghc, 1); -+ break; -+ case USB_PORT_FEAT_RESET: -+ HDBG("SetPortFeature: USB_PORT_FEAT_RESET, Port Status=0x%04x\n", -+ akotghc->port_status); -+ if (akotghc->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { -+ HDBG(" USB_PORT_FEAT_SUSPEND ....\n"); -+ goto error; -+ } -+ if (!(akotghc->port_status & (1 << USB_PORT_FEAT_POWER))) { -+ HDBG(" USB_PORT_FEAT_POWER NOT SET.\n"); -+ break; -+ } -+ clear_all_interrupts(); -+ -+ /* 50 msec of reset/SE0 signaling, irqs blocked */ -+ /*reset device.*/ -+ reg8val = hc_readb(USB_REG_POWER); -+ reg8val |= USB_POWER_RESET; -+ hc_writeb(reg8val, USB_REG_POWER); -+ mdelay(30); -+ reg8val &= ~USB_POWER_RESET; -+ hc_writeb(reg8val, USB_REG_POWER); -+ -+ hc_writeb(0xF7, USB_REG_INTRUSBE); -+ -+ akotghc->port_status |= (1 << USB_PORT_FEAT_RESET); -+ mod_timer(&akotghc->timer, jiffies + msecs_to_jiffies(50)); -+ break; -+ default: -+ goto error; -+ } -+ -+ akotghc->port_status |= 1 << wValue; -+ break; -+error: -+ /* "protocol stall" on error */ -+ retval = -EPIPE; -+ } -+ -+ spin_unlock_irqrestore(&akotghc->lock, flags); -+ return retval; -+} -+ -+ -+ int -+akotg_usbhc_bus_suspend(struct usb_hcd *hcd) -+{ -+ u8 reg; -+ unsigned long flags; -+ msleep(10); -+ local_irq_save(flags); -+ reg = hc_readb(USB_REG_POWER); -+ reg |= USB_POWER_SUSPENDM; -+ hc_writeb(reg, USB_REG_POWER); -+ local_irq_restore(flags); -+ msleep(20); -+ return 0; -+} -+ -+ int -+akotg_usbhc_bus_resume(struct usb_hcd *hcd) -+{ -+ u8 reg; -+ unsigned long flags; -+ local_irq_save(flags); -+ reg = hc_readb(USB_REG_POWER); -+ reg |= USB_POWER_RESUME; -+ hc_writeb(reg, USB_REG_POWER); -+ local_irq_restore(flags); -+ msleep(20); -+ local_irq_save(flags); -+ reg = hc_readb(USB_REG_POWER); -+ reg &= ~USB_POWER_RESUME; -+ hc_writeb(reg, USB_REG_POWER); -+ local_irq_restore(flags); -+ msleep(100); -+ return 0; -+} -+ -+void akotg_usbhc_stop(struct usb_hcd *hcd) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ unsigned long flags; -+ -+ del_timer_sync(&hcd->rh_timer); -+ clk_disable(akotghc->clk); -+ -+ /* reset usb phy */ -+ usb_reset_phy(akotghc); -+ -+ //rMULFUN_CON2 &= ~(0x1 << 18); //iddig is invalid -+ //REG32(USB_OP_MOD_REG) |= (0x3 << 12); -+ -+ spin_lock_irqsave(&akotghc->lock, flags); -+ port_power(akotghc, 0); -+ spin_unlock_irqrestore(&akotghc->lock, flags); -+} -+ -+static void usb_hwinit_control(struct akotg_usbhc *otghc) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&otghc->lock, flags); -+ -+ port_power(otghc, 1); -+ set_usb_as_host(); -+ /* reset usb phy */ -+ usb_reset_phy(otghc); -+ -+ clear_all_interrupts(); -+ reset_endpoints(); -+ hc_writeb(0x0, USB_REG_FADDR); -+ -+ usb_power_up(otghc); -+ -+ hc_writeb(USB_POWER_ENSUSPEND|USB_HOSG_HIGH_SPEED, USB_REG_POWER); -+ hc_writeb(0xF7, USB_REG_INTRUSBE); -+ -+ spin_unlock_irqrestore(&otghc->lock, flags); -+} -+ -+int akotg_usbhc_start(struct usb_hcd *hcd) -+{ -+ struct akotg_usbhc *akotghc = hcd_to_akotg_usbhc(hcd); -+ -+ g_otghc_wq = create_singlethread_workqueue("usb_otg_wq"); -+ INIT_DELAYED_WORK(&g_otg_rest, reset_otg); -+ /*after reset usbhc, set stat to running.*/ -+ hcd->state = HC_STATE_RUNNING; -+ -+ /* chip has been reset, VBUS power is off */ -+ disable_irq(akotghc->mcu_irq); -+ //disable_irq(akotghc->dma_irq); -+ -+ clk_enable(akotghc->clk); -+ -+ usb_hwinit_control(akotghc); -+ -+ /* start host session*/ // is end session ? -+ hc_writeb(USB_DEVCTL_SESSION, USB_REG_DEVCTL); -+ -+ enable_irq(akotghc->mcu_irq); -+ //enable_irq(akotghc->dma_irq); -+ -+ return 0; -+} -+ -diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig -index 5c87db06..c2902a86 100644 ---- a/drivers/usb/otg/Kconfig -+++ b/drivers/usb/otg/Kconfig -@@ -12,6 +12,14 @@ config USB_OTG_UTILS - Select this to make sure the build includes objects from - the OTG infrastructure directory. - -+config USB_OTG_WAKELOCK -+ bool "Hold a wakelock when USB connected" -+ depends on WAKELOCK -+ select USB_OTG_UTILS -+ help -+ Select this to automatically hold a wakelock when USB is -+ connected, preventing suspend. -+ - if USB || USB_GADGET - - # -diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile -index 41aa5098..638d040c 100644 ---- a/drivers/usb/otg/Makefile -+++ b/drivers/usb/otg/Makefile -@@ -7,6 +7,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG - - # infrastructure - obj-$(CONFIG_USB_OTG_UTILS) += otg.o -+obj-$(CONFIG_USB_OTG_WAKELOCK) += otg-wakelock.o - - # transceiver drivers - obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o -diff --git a/drivers/usb/otg/otg-wakelock.c b/drivers/usb/otg/otg-wakelock.c -new file mode 100644 -index 00000000..e17e2729 ---- /dev/null -+++ b/drivers/usb/otg/otg-wakelock.c -@@ -0,0 +1,170 @@ -+/* -+ * otg-wakelock.c -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/device.h> -+#include <linux/module.h> -+#include <linux/notifier.h> -+#include <linux/wakelock.h> -+#include <linux/spinlock.h> -+#include <linux/usb/otg.h> -+ -+#define TEMPORARY_HOLD_TIME 2000 -+ -+static bool enabled = true; -+static struct usb_phy *otgwl_xceiv; -+static struct notifier_block otgwl_nb; -+ -+/* -+ * otgwl_spinlock is held while the VBUS lock is grabbed or dropped and the -+ * held field is updated to match. -+ */ -+ -+static DEFINE_SPINLOCK(otgwl_spinlock); -+ -+/* -+ * Only one lock, but since these 3 fields are associated with each other... -+ */ -+ -+struct otgwl_lock { -+ char name[40]; -+ struct wake_lock wakelock; -+ bool held; -+}; -+ -+/* -+ * VBUS present lock. Also used as a timed lock on charger -+ * connect/disconnect and USB host disconnect, to allow the system -+ * to react to the change in power. -+ */ -+ -+static struct otgwl_lock vbus_lock; -+ -+static void otgwl_hold(struct otgwl_lock *lock) -+{ -+ if (!lock->held) { -+ wake_lock(&lock->wakelock); -+ lock->held = true; -+ } -+} -+ -+static void otgwl_temporary_hold(struct otgwl_lock *lock) -+{ -+ wake_lock_timeout(&lock->wakelock, -+ msecs_to_jiffies(TEMPORARY_HOLD_TIME)); -+ lock->held = false; -+} -+ -+static void otgwl_drop(struct otgwl_lock *lock) -+{ -+ if (lock->held) { -+ wake_unlock(&lock->wakelock); -+ lock->held = false; -+ } -+} -+ -+static void otgwl_handle_event(unsigned long event) -+{ -+ unsigned long irqflags; -+ -+ spin_lock_irqsave(&otgwl_spinlock, irqflags); -+ -+ if (!enabled) { -+ otgwl_drop(&vbus_lock); -+ spin_unlock_irqrestore(&otgwl_spinlock, irqflags); -+ return; -+ } -+ -+ switch (event) { -+ case USB_EVENT_VBUS: -+ case USB_EVENT_ENUMERATED: -+ otgwl_hold(&vbus_lock); -+ break; -+ -+ case USB_EVENT_NONE: -+ case USB_EVENT_ID: -+ case USB_EVENT_CHARGER: -+ otgwl_temporary_hold(&vbus_lock); -+ break; -+ -+ default: -+ break; -+ } -+ -+ spin_unlock_irqrestore(&otgwl_spinlock, irqflags); -+} -+ -+static int otgwl_otg_notifications(struct notifier_block *nb, -+ unsigned long event, void *unused) -+{ -+ otgwl_handle_event(event); -+ return NOTIFY_OK; -+} -+ -+static int set_enabled(const char *val, const struct kernel_param *kp) -+{ -+ int rv = param_set_bool(val, kp); -+ -+ if (rv) -+ return rv; -+ -+ if (otgwl_xceiv) -+ otgwl_handle_event(otgwl_xceiv->last_event); -+ -+ return 0; -+} -+ -+static struct kernel_param_ops enabled_param_ops = { -+ .set = set_enabled, -+ .get = param_get_bool, -+}; -+ -+module_param_cb(enabled, &enabled_param_ops, &enabled, 0644); -+MODULE_PARM_DESC(enabled, "enable wakelock when VBUS present"); -+ -+static int __init otg_wakelock_init(void) -+{ -+ int ret; -+ -+ otgwl_xceiv = usb_get_transceiver(); -+ -+ if (!otgwl_xceiv) { -+ pr_err("%s: No USB transceiver found\n", __func__); -+ return -ENODEV; -+ } -+ -+ snprintf(vbus_lock.name, sizeof(vbus_lock.name), "vbus-%s", -+ dev_name(otgwl_xceiv->dev)); -+ wake_lock_init(&vbus_lock.wakelock, WAKE_LOCK_SUSPEND, -+ vbus_lock.name); -+ -+ otgwl_nb.notifier_call = otgwl_otg_notifications; -+ ret = usb_register_notifier(otgwl_xceiv, &otgwl_nb); -+ -+ if (ret) { -+ pr_err("%s: usb_register_notifier on transceiver %s" -+ " failed\n", __func__, -+ dev_name(otgwl_xceiv->dev)); -+ otgwl_xceiv = NULL; -+ wake_lock_destroy(&vbus_lock.wakelock); -+ return ret; -+ } -+ -+ otgwl_handle_event(otgwl_xceiv->last_event); -+ return ret; -+} -+ -+late_initcall(otg_wakelock_init); -diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index a290be51..65b07f4d 100644 ---- a/drivers/video/Kconfig -+++ b/drivers/video/Kconfig -@@ -23,6 +23,8 @@ source "drivers/gpu/drm/Kconfig" - - source "drivers/gpu/stub/Kconfig" - -+source "drivers/gpu/ion/Kconfig" -+ - config VGASTATE - tristate - default n -diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c -index e5f74416..d409352f 100644 ---- a/drivers/w1/masters/ds2482.c -+++ b/drivers/w1/masters/ds2482.c -@@ -18,6 +18,8 @@ - #include <linux/slab.h> - #include <linux/i2c.h> - #include <linux/delay.h> -+#include <linux/gpio.h> -+#include <linux/platform_data/ds2482.h> - #include <asm/delay.h> - - #include "../w1.h" -@@ -84,7 +86,8 @@ static const u8 ds2482_chan_rd[8] = - static int ds2482_probe(struct i2c_client *client, - const struct i2c_device_id *id); - static int ds2482_remove(struct i2c_client *client); -- -+static int ds2482_suspend(struct device *dev); -+static int ds2482_resume(struct device *dev); - - /** - * Driver data (common to all clients) -@@ -94,10 +97,16 @@ static const struct i2c_device_id ds2482_id[] = { - { } - }; - -+static const struct dev_pm_ops ds2482_pm_ops = { -+ .suspend = ds2482_suspend, -+ .resume = ds2482_resume, -+}; -+ - static struct i2c_driver ds2482_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "ds2482", -+ .pm = &ds2482_pm_ops, - }, - .probe = ds2482_probe, - .remove = ds2482_remove, -@@ -119,6 +128,7 @@ struct ds2482_w1_chan { - struct ds2482_data { - struct i2c_client *client; - struct mutex access_lock; -+ int slpz_gpio; - - /* 1-wire interface(s) */ - int w1_count; /* 1 or 8 */ -@@ -407,11 +417,31 @@ static u8 ds2482_w1_reset_bus(void *data) - return retval; - } - -+static int ds2482_suspend(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct ds2482_data *data = i2c_get_clientdata(client); -+ -+ if (data->slpz_gpio >= 0) -+ gpio_set_value(data->slpz_gpio, 0); -+ return 0; -+} -+ -+static int ds2482_resume(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct ds2482_data *data = i2c_get_clientdata(client); -+ -+ if (data->slpz_gpio >= 0) -+ gpio_set_value(data->slpz_gpio, 1); -+ return 0; -+} - - static int ds2482_probe(struct i2c_client *client, - const struct i2c_device_id *id) - { - struct ds2482_data *data; -+ struct ds2482_platform_data *pdata; - int err = -ENODEV; - int temp1; - int idx; -@@ -476,6 +506,16 @@ static int ds2482_probe(struct i2c_client *client, - } - } - -+ pdata = client->dev.platform_data; -+ data->slpz_gpio = pdata ? pdata->slpz_gpio : -1; -+ -+ if (data->slpz_gpio >= 0) { -+ err = gpio_request_one(data->slpz_gpio, GPIOF_OUT_INIT_HIGH, -+ "ds2482.slpz"); -+ if (err < 0) -+ goto exit_w1_remove; -+ } -+ - return 0; - - exit_w1_remove: -@@ -500,6 +540,11 @@ static int ds2482_remove(struct i2c_client *client) - w1_remove_master_device(&data->w1_ch[idx].w1_bm); - } - -+ if (data->slpz_gpio >= 0) { -+ gpio_set_value(data->slpz_gpio, 0); -+ gpio_free(data->slpz_gpio); -+ } -+ - /* Free the memory */ - kfree(data); - return 0; -diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 37096246..fe518917 100644 ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -349,6 +349,12 @@ config IMX2_WDT - To compile this driver as a module, choose M here: the - module will be called imx2_wdt. - -+config AK39_WATCHDOG -+ tristate "ANYKA ak39 watchdog" -+ depends on ARCH_AK39 -+ help -+ Say Y here if you want support for the watchdog timer on ANYKA ak39 boards. -+ - # AVR32 Architecture - - config AT32AP700X_WDT -diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index e8f479a1..5a4917d6 100644 ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -167,3 +167,4 @@ obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o - obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o - obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o - obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o -+obj-$(CONFIG_AK39_WATCHDOG) += ak39_wdt.o -diff --git a/drivers/watchdog/ak39_wdt.c b/drivers/watchdog/ak39_wdt.c -new file mode 100755 -index 00000000..9622ab99 ---- /dev/null -+++ b/drivers/watchdog/ak39_wdt.c -@@ -0,0 +1,347 @@ -+/* -+ * drivers/char/watchdog/ak98_wdt.c -+ * -+ * Watchdog driver for ANYKA ak98 processors -+ * -+ * Author: Wenyong Zhou -+ * -+ * Adapted from the IXP2000 watchdog driver by Lennert Buytenhek. -+ * The original version carries these notices: -+ * -+ * Author: Deepak Saxena <dsaxena@plexity.net> -+ * -+ * Copyright 2004 (c) MontaVista, Software, Inc. -+ * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu> -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/watchdog.h> -+#include <linux/init.h> -+#include <linux/bitops.h> -+#include <linux/uaccess.h> -+#include <linux/reboot.h> -+ -+#include <mach/hardware.h> -+#include <mach/gpio.h> -+#include <plat/rtc.h> -+ -+#define SELECT_WTC 1 -+#define SELECT_RTC 0 -+ -+#define WDT_DEBUG -+#undef PDEBUG -+#ifdef WDT_DEBUG -+#define PDEBUG(fmt, args...) printk(KERN_INFO fmt,## args) -+#else -+#define PDEBUG(fmt, args...) -+#endif -+ -+static int nowayout = WATCHDOG_NOWAYOUT; -+static unsigned int def_heartbeat = (0x1FFF); /* Default is 8 seconds */ -+static unsigned int now_heartbeat = (0x1FFF); -+ -+static unsigned long in_use; -+static atomic_t in_write = ATOMIC_INIT(0); -+static DEFINE_SPINLOCK(wdt_lock); -+ -+static int ak98_wdt_disable_nb(struct notifier_block *n, unsigned long state,void *cmd); -+static struct notifier_block ak98_wdt_nb = { -+ .notifier_call = ak98_wdt_disable_nb, -+}; -+ -+module_param(def_heartbeat, int, 0); -+MODULE_PARM_DESC(def_heartbeat, "Watchdog heartbeat in seconds (default 8s)"); -+ -+module_param(nowayout, int, 0); -+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); -+ -+static void select_wdt_rtc(int which) -+{ -+ unsigned long val; -+ -+ val = ak_rtc_read(AK_RTC_SETTING); -+ if (which == 0) -+ val &= ~(1 << 10); -+ else -+ val |= (1 << 10); -+ ak_rtc_write(AK_RTC_SETTING, val); -+} -+ -+void wdt_enable(void) -+{ -+ unsigned long val; -+ -+ spin_lock(&wdt_lock); -+ select_wdt_rtc(SELECT_WTC); -+ -+ //enable watchdog timer -+ val = ak_rtc_read(AK_WDT_RTC_TIMER_CONF); -+ val |= (1<<13); -+ ak_rtc_write(AK_WDT_RTC_TIMER_CONF, val); -+ -+ //set timer -+ val = ak_rtc_read(AK_WDT_RTC_TIMER_CONF); -+ val &= (1<<13); -+ val |= (def_heartbeat & 0x1FFF); -+ ak_rtc_write(AK_WDT_RTC_TIMER_CONF, val); -+ -+ //open watchdog and watchdog output -+ val = ak_rtc_read(AK_RTC_SETTING); -+ val |= ((1<<5) | (1<<2)); -+ val &= ~(1<<11); -+ ak_rtc_write(AK_RTC_SETTING, val); -+ -+ select_wdt_rtc(SELECT_RTC); -+ spin_unlock(&wdt_lock); -+} -+ -+static void wdt_disable(void) -+{ -+ unsigned long val; -+ -+ spin_lock(&wdt_lock); -+ select_wdt_rtc(SELECT_WTC); -+ -+ //clear watchdog timer -+ val = ak_rtc_read(AK_RTC_SETTING); -+ val |= (1<<6); -+ ak_rtc_write(AK_RTC_SETTING, val); -+ -+ //disable watchdog timer -+ val = ak_rtc_read(AK_WDT_RTC_TIMER_CONF); -+ val &= ~(1<<13); -+ ak_rtc_write(AK_WDT_RTC_TIMER_CONF, val); -+ -+ //close watchdog and watchdog output -+ val = ak_rtc_read(AK_RTC_SETTING); -+ val &= ~((1<<2) | (1<<5)); -+ ak_rtc_write(AK_RTC_SETTING, val); -+ -+ select_wdt_rtc(SELECT_RTC); -+ spin_unlock(&wdt_lock); -+} -+ -+void wdt_keepalive(unsigned int heartbeat) -+{ -+ unsigned long val; -+ -+ PDEBUG("heartbeat = %x\n", heartbeat); -+ spin_lock(&wdt_lock); -+ select_wdt_rtc(SELECT_WTC); -+ -+ //clear watchdog timer -+ val = ak_rtc_read(AK_RTC_SETTING); -+ val |= (1<<6); -+ ak_rtc_write(AK_RTC_SETTING, val); -+ -+ val = ak_rtc_read(AK_WDT_RTC_TIMER_CONF); -+ val &= (1<<13); -+ val |= (heartbeat & 0x1FFF); -+ ak_rtc_write(AK_WDT_RTC_TIMER_CONF, val); -+ -+ select_wdt_rtc(SELECT_RTC); -+ spin_unlock(&wdt_lock); -+} -+ -+/** -+ * @brief: ak98_wdt_disable_nb -+ * @author: zhongjunchao -+ * @date: 2011-10-11 -+ * -+ * @note: Sometimes, system reboot and doesn`t disable watchdog. we disable it -+ * for safe. -+ */ -+static int ak98_wdt_disable_nb(struct notifier_block *n, unsigned long state,void *cmd) -+{ -+ wdt_disable(); -+ return NOTIFY_DONE; -+} -+ -+static struct watchdog_info ident = { -+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, -+ .identity = "ANYKA ak98 Watchdog", -+}; -+ -+/** -+ * @brief: ak98_wdt_ioctl -+ * @author: zhouwenyong -+ * @modify: zhongjunchao -+ * @date: 2011-9-26 -+ * -+ * @note: WDIOC_GETSUPPORT,return struct watchdog_info. -+ * WDIOC_KEEPALIVE, set a default timeout (8s). -+ * WDIOC_SETTIMEOUT, set a timeout value what you want (max 8s). -+ * WDIOC_GETTIMEOUT, query the current timeout. -+ * More detail, refer to kernel/Documentation/watchdog/watchdog-api.txt -+ */ -+static long ak98_wdt_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ int __user *p = argp; -+ int ret = -ENOTTY; -+ int time; -+ -+ switch (cmd) { -+ -+ case WDIOC_GETSUPPORT: -+ return copy_to_user((struct watchdog_info *)argp, &ident, -+ sizeof(ident)) ? -EFAULT : 0; -+ case WDIOC_GETSTATUS: -+ case WDIOC_GETBOOTSTATUS: -+ return put_user(0, p); -+ -+ case WDIOC_KEEPALIVE: -+ wdt_keepalive(def_heartbeat); -+ now_heartbeat = def_heartbeat; -+ return 0; -+ -+ case WDIOC_SETTIMEOUT: -+ if (get_user(time, p)) -+ return -EFAULT; -+ -+ PDEBUG("timeout = %d\n", time); -+ if (time <= 0 || time > 8) -+ return -EINVAL; -+ -+ now_heartbeat = time * 1024 - 1; -+ wdt_keepalive(now_heartbeat); -+ return 0; -+ -+ case WDIOC_GETTIMEOUT: -+ return put_user((now_heartbeat + 1)/1024, p); -+ -+ default: -+ return -ENOTTY; -+ } -+ -+ return ret; -+} -+ -+/** -+ * @brief: ak98_wdt_write -+ * @author: zhouwenyong -+ * @modify: zhongjunchao -+ * @date: 2011-9-26 -+ * -+ * @note: We support "Magic Close" that driver will not disable the watchdog unless -+ * a specific magic character 'V' has been sent to /dev/watchdog just before -+ * closing the file. -+ */ -+static ssize_t ak98_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) -+{ -+ if (len) { -+ size_t i; -+ -+ atomic_set(&in_write, 1); -+ for (i = 0; i != len; i++) { -+ char c; -+ -+ if (get_user(c, data + i)) -+ return -EFAULT; -+ if (c == 'V') { -+ PDEBUG("Detect \"V\" Magic Character\n"); -+ atomic_set(&in_write, 0); -+ } -+ } -+ wdt_keepalive(def_heartbeat); -+ } -+ -+ return len; -+} -+ -+/** -+ * @brief: ak98_wdt_open -+ * @author: zhouwenyong -+ * @modify: zhongjunchao -+ * @date: 2011-9-26 -+ * -+ * @note: We only support one process open /dev/watchdog, to avoid overwrite watchdog -+ * timeout value. -+ */ -+static int ak98_wdt_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit(0, &in_use)) -+ return -EBUSY; -+ -+ if (nowayout) -+ __module_get(THIS_MODULE); -+ -+ wdt_enable(); -+ -+ return nonseekable_open(inode, file); -+} -+ -+/** -+ * @brief: ak98_wdt_release -+ * @author: zhouwenyong -+ * @modify: zhongjunchao -+ * @date: 2011-9-26 -+ * -+ * @note: When open CONFIG_WATCHDOG_NOWAYOUT option, nowayout = 1. -+ * When you open and write to /dev/watchdog, please write magic character 'V' -+ * before close the file. If not, watchdog will not disable after close -+ * /dev/watchdog. -+ */ -+static int ak98_wdt_release(struct inode *inode, struct file *file) -+{ -+ if (nowayout) -+ printk(KERN_INFO "WATCHDOG: Driver support nowayout option -" -+ "no way to disable watchdog\n"); -+ else if (atomic_read(&in_write)) -+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " -+ "timer will not stop\n"); -+ else -+ wdt_disable(); -+ clear_bit(0, &in_use); -+ -+ return 0; -+} -+ -+static const struct file_operations ak98_wdt_fops = { -+ .owner = THIS_MODULE, -+ .llseek = no_llseek, -+ .write = ak98_wdt_write, -+ .unlocked_ioctl = ak98_wdt_ioctl, -+ .open = ak98_wdt_open, -+ .release = ak98_wdt_release, -+}; -+ -+static struct miscdevice ak98_wdt_miscdev = { -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &ak98_wdt_fops, -+}; -+ -+static int __init ak98_wdt_init(void) -+{ -+ spin_lock(&wdt_lock); -+ ak_rtc_power(RTC_ON); -+ spin_unlock(&wdt_lock); -+ register_reboot_notifier(&ak98_wdt_nb); -+ -+ return misc_register(&ak98_wdt_miscdev); -+} -+ -+static void __exit ak98_wdt_exit(void) -+{ -+ unregister_reboot_notifier(&ak98_wdt_nb); -+ ak_rtc_power(RTC_OFF); -+ -+ misc_deregister(&ak98_wdt_miscdev); -+} -+module_init(ak98_wdt_init); -+module_exit(ak98_wdt_exit); -+ -+MODULE_DESCRIPTION("ANYKA ak98 Watchdog"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -diff --git a/fs/Kconfig b/fs/Kconfig -index f95ae3a0..1dd49481 100644 ---- a/fs/Kconfig -+++ b/fs/Kconfig -@@ -203,6 +203,10 @@ source "fs/hfsplus/Kconfig" - source "fs/befs/Kconfig" - source "fs/bfs/Kconfig" - source "fs/efs/Kconfig" -+ -+# Patched by YAFFS -+source "fs/yaffs2/Kconfig" -+ - source "fs/jffs2/Kconfig" - # UBIFS File system configuration - source "fs/ubifs/Kconfig" -diff --git a/fs/Makefile b/fs/Makefile -index 2fb97793..95cf9de6 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -125,3 +125,6 @@ obj-$(CONFIG_GFS2_FS) += gfs2/ - obj-y += exofs/ # Multiple modules - obj-$(CONFIG_CEPH_FS) += ceph/ - obj-$(CONFIG_PSTORE) += pstore/ -+ -+# Patched by YAFFS -+obj-$(CONFIG_YAFFS_FS) += yaffs2/ -diff --git a/fs/eventpoll.c b/fs/eventpoll.c -index 33c9599c..0863bab4 100644 ---- a/fs/eventpoll.c -+++ b/fs/eventpoll.c -@@ -33,6 +33,7 @@ - #include <linux/bitops.h> - #include <linux/mutex.h> - #include <linux/anon_inodes.h> -+#include <linux/device.h> - #include <asm/uaccess.h> - #include <asm/io.h> - #include <asm/mman.h> -@@ -87,7 +88,7 @@ - */ - - /* Epoll private bits inside the event mask */ --#define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET) -+#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET) - - /* Maximum number of nesting allowed inside epoll sets */ - #define EP_MAX_NESTS 4 -@@ -154,6 +155,9 @@ struct epitem { - /* List header used to link this item to the "struct file" items list */ - struct list_head fllink; - -+ /* wakeup_source used when EPOLLWAKEUP is set */ -+ struct wakeup_source *ws; -+ - /* The structure that describe the interested events and the source fd */ - struct epoll_event event; - }; -@@ -194,6 +198,9 @@ struct eventpoll { - */ - struct epitem *ovflist; - -+ /* wakeup_source used when ep_scan_ready_list is running */ -+ struct wakeup_source *ws; -+ - /* The user that created the eventpoll descriptor */ - struct user_struct *user; - -@@ -588,8 +595,10 @@ static int ep_scan_ready_list(struct eventpoll *ep, - * queued into ->ovflist but the "txlist" might already - * contain them, and the list_splice() below takes care of them. - */ -- if (!ep_is_linked(&epi->rdllink)) -+ if (!ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); -+ __pm_stay_awake(epi->ws); -+ } - } - /* - * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after -@@ -602,6 +611,7 @@ static int ep_scan_ready_list(struct eventpoll *ep, - * Quickly re-inject items left on "txlist". - */ - list_splice(&txlist, &ep->rdllist); -+ __pm_relax(ep->ws); - - if (!list_empty(&ep->rdllist)) { - /* -@@ -656,6 +666,8 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) - list_del_init(&epi->rdllink); - spin_unlock_irqrestore(&ep->lock, flags); - -+ wakeup_source_unregister(epi->ws); -+ - /* At this point it is safe to free the eventpoll item */ - kmem_cache_free(epi_cache, epi); - -@@ -706,6 +718,7 @@ static void ep_free(struct eventpoll *ep) - mutex_unlock(&epmutex); - mutex_destroy(&ep->mtx); - free_uid(ep->user); -+ wakeup_source_unregister(ep->ws); - kfree(ep); - } - -@@ -737,6 +750,7 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, - * callback, but it's not actually ready, as far as - * caller requested events goes. We can remove it here. - */ -+ __pm_relax(epi->ws); - list_del_init(&epi->rdllink); - } - } -@@ -927,13 +941,23 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k - if (epi->next == EP_UNACTIVE_PTR) { - epi->next = ep->ovflist; - ep->ovflist = epi; -+ if (epi->ws) { -+ /* -+ * Activate ep->ws since epi->ws may get -+ * deactivated at any time. -+ */ -+ __pm_stay_awake(ep->ws); -+ } -+ - } - goto out_unlock; - } - - /* If this file is already in the ready list we exit soon */ -- if (!ep_is_linked(&epi->rdllink)) -+ if (!ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); -+ __pm_stay_awake(epi->ws); -+ } - - /* - * Wake up ( if active ) both the eventpoll wait list and the ->poll() -@@ -1091,6 +1115,30 @@ static int reverse_path_check(void) - return error; - } - -+static int ep_create_wakeup_source(struct epitem *epi) -+{ -+ const char *name; -+ -+ if (!epi->ep->ws) { -+ epi->ep->ws = wakeup_source_register("eventpoll"); -+ if (!epi->ep->ws) -+ return -ENOMEM; -+ } -+ -+ name = epi->ffd.file->f_path.dentry->d_name.name; -+ epi->ws = wakeup_source_register(name); -+ if (!epi->ws) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+static void ep_destroy_wakeup_source(struct epitem *epi) -+{ -+ wakeup_source_unregister(epi->ws); -+ epi->ws = NULL; -+} -+ - /* - * Must be called with "mtx" held. - */ -@@ -1118,6 +1166,13 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, - epi->event = *event; - epi->nwait = 0; - epi->next = EP_UNACTIVE_PTR; -+ if (epi->event.events & EPOLLWAKEUP) { -+ error = ep_create_wakeup_source(epi); -+ if (error) -+ goto error_create_wakeup_source; -+ } else { -+ epi->ws = NULL; -+ } - - /* Initialize the poll table using the queue callback */ - epq.epi = epi; -@@ -1164,6 +1219,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, - /* If the file is already "ready" we drop it inside the ready list */ - if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); -+ __pm_stay_awake(epi->ws); - - /* Notify waiting tasks that events are available */ - if (waitqueue_active(&ep->wq)) -@@ -1204,6 +1260,9 @@ error_unregister: - list_del_init(&epi->rdllink); - spin_unlock_irqrestore(&ep->lock, flags); - -+ wakeup_source_unregister(epi->ws); -+ -+error_create_wakeup_source: - kmem_cache_free(epi_cache, epi); - - return error; -@@ -1229,6 +1288,12 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even - epi->event.events = event->events; /* need barrier below */ - pt._key = event->events; - epi->event.data = event->data; /* protected by mtx */ -+ if (epi->event.events & EPOLLWAKEUP) { -+ if (!epi->ws) -+ ep_create_wakeup_source(epi); -+ } else if (epi->ws) { -+ ep_destroy_wakeup_source(epi); -+ } - - /* - * The following barrier has two effects: -@@ -1264,6 +1329,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even - spin_lock_irq(&ep->lock); - if (!ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); -+ __pm_stay_awake(epi->ws); - - /* Notify waiting tasks that events are available */ - if (waitqueue_active(&ep->wq)) -@@ -1302,6 +1368,18 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, - !list_empty(head) && eventcnt < esed->maxevents;) { - epi = list_first_entry(head, struct epitem, rdllink); - -+ /* -+ * Activate ep->ws before deactivating epi->ws to prevent -+ * triggering auto-suspend here (in case we reactive epi->ws -+ * below). -+ * -+ * This could be rearranged to delay the deactivation of epi->ws -+ * instead, but then epi->ws would temporarily be out of sync -+ * with ep_is_linked(). -+ */ -+ if (epi->ws && epi->ws->active) -+ __pm_stay_awake(ep->ws); -+ __pm_relax(epi->ws); - list_del_init(&epi->rdllink); - - pt._key = epi->event.events; -@@ -1318,6 +1396,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, - if (__put_user(revents, &uevent->events) || - __put_user(epi->event.data, &uevent->data)) { - list_add(&epi->rdllink, head); -+ __pm_stay_awake(epi->ws); - return eventcnt ? eventcnt : -EFAULT; - } - eventcnt++; -@@ -1337,6 +1416,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, - * poll callback will queue them in ep->ovflist. - */ - list_add_tail(&epi->rdllink, &ep->rdllist); -+ __pm_stay_awake(epi->ws); - } - } - } -@@ -1649,6 +1729,10 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, - if (!tfile->f_op || !tfile->f_op->poll) - goto error_tgt_fput; - -+ /* Check if EPOLLWAKEUP is allowed */ -+ if ((epds.events & EPOLLWAKEUP) && !capable(CAP_EPOLLWAKEUP)) -+ epds.events &= ~EPOLLWAKEUP; -+ - /* - * We have to check that the file structure underneath the file descriptor - * the user passed to us _is_ an eventpoll file. And also we do not permit -diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c -index 902544e7..8b15179b 100644 ---- a/fs/ext4/ialloc.c -+++ b/fs/ext4/ialloc.c -@@ -778,7 +778,10 @@ got: - ext4_itable_unused_set(sb, gdp, - (EXT4_INODES_PER_GROUP(sb) - ino)); - up_read(&grp->alloc_sem); -+ } else { -+ ext4_lock_group(sb, group); - } -+ - ext4_free_inodes_set(sb, gdp, ext4_free_inodes_count(sb, gdp) - 1); - if (S_ISDIR(mode)) { - ext4_used_dirs_set(sb, gdp, ext4_used_dirs_count(sb, gdp) + 1); -@@ -790,8 +793,8 @@ got: - } - if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { - gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); -- ext4_unlock_group(sb, group); - } -+ ext4_unlock_group(sb, group); - - BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh); -diff --git a/fs/fat/dir.c b/fs/fat/dir.c -index aca191bd..65e174bd 100644 ---- a/fs/fat/dir.c -+++ b/fs/fat/dir.c -@@ -754,6 +754,13 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp, - return ret; - } - -+static int fat_ioctl_volume_id(struct inode *dir) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct msdos_sb_info *sbi = MSDOS_SB(sb); -+ return sbi->vol_id; -+} -+ - static long fat_dir_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) - { -@@ -770,6 +777,8 @@ static long fat_dir_ioctl(struct file *filp, unsigned int cmd, - short_only = 0; - both = 1; - break; -+ case VFAT_IOCTL_GET_VOLUME_ID: -+ return fat_ioctl_volume_id(inode); - default: - return fat_generic_ioctl(filp, cmd, arg); - } -diff --git a/fs/fat/fat.h b/fs/fat/fat.h -index 66994f31..341f7537 100644 ---- a/fs/fat/fat.h -+++ b/fs/fat/fat.h -@@ -78,6 +78,7 @@ struct msdos_sb_info { - const void *dir_ops; /* Opaque; default directory operations */ - int dir_per_block; /* dir entries per block */ - int dir_per_block_bits; /* log2(dir_per_block) */ -+ unsigned long vol_id; /* volume ID */ - - int fatent_shift; - struct fatent_operations *fatent_ops; -diff --git a/fs/fat/inode.c b/fs/fat/inode.c -index 21687e31..d403f76c 100644 ---- a/fs/fat/inode.c -+++ b/fs/fat/inode.c -@@ -1246,6 +1246,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, - struct inode *root_inode = NULL, *fat_inode = NULL; - struct buffer_head *bh; - struct fat_boot_sector *b; -+ struct fat_boot_bsx *bsx; - struct msdos_sb_info *sbi; - u16 logical_sector_size; - u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors; -@@ -1390,6 +1391,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, - goto out_fail; - } - -+ bsx = (struct fat_boot_bsx *)(bh->b_data + FAT32_BSX_OFFSET); -+ - fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; - if (!IS_FSINFO(fsinfo)) { - fat_msg(sb, KERN_WARNING, "Invalid FSINFO signature: " -@@ -1405,8 +1408,14 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, - } - - brelse(fsinfo_bh); -+ } else { -+ bsx = (struct fat_boot_bsx *)(bh->b_data + FAT16_BSX_OFFSET); - } - -+ /* interpret volume ID as a little endian 32 bit integer */ -+ sbi->vol_id = (((u32)bsx->vol_id[0]) | ((u32)bsx->vol_id[1] << 8) | -+ ((u32)bsx->vol_id[2] << 16) | ((u32)bsx->vol_id[3] << 24)); -+ - sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry); - sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1; - -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index b35bd64f..1b21e0a0 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -1083,7 +1083,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) - if ((inode->i_state & flags) == flags) - return; - -- if (unlikely(block_dump)) -+ if (unlikely(block_dump > 1)) - block_dump___mark_inode_dirty(inode); - - spin_lock(&inode->i_lock); -diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c -index f4246cfc..1f81f70d 100644 ---- a/fs/fuse/dev.c -+++ b/fs/fuse/dev.c -@@ -19,6 +19,7 @@ - #include <linux/pipe_fs_i.h> - #include <linux/swap.h> - #include <linux/splice.h> -+#include <linux/freezer.h> - - MODULE_ALIAS_MISCDEV(FUSE_MINOR); - MODULE_ALIAS("devname:fuse"); -@@ -387,7 +388,10 @@ __acquires(fc->lock) - * Wait it out. - */ - spin_unlock(&fc->lock); -- wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); -+ -+ while (req->state != FUSE_REQ_FINISHED) -+ wait_event_freezable(req->waitq, -+ req->state == FUSE_REQ_FINISHED); - spin_lock(&fc->lock); - - if (!req->aborted) -diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c -index 8608f877..d77910e3 100644 ---- a/fs/jffs2/file.c -+++ b/fs/jffs2/file.c -@@ -148,6 +148,10 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, - jffs2_dbg(1, "%s()\n", __func__); - - if (pageofs > inode->i_size) { -+ /* FIXME -+ * How about a huage hole ? -+ * If i make it happy, system will crash! -+ */ - ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) -diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c -index dc0437e8..17f709f0 100644 ---- a/fs/jffs2/readinode.c -+++ b/fs/jffs2/readinode.c -@@ -228,6 +228,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, - node with highest version -- i.e. the one which will end up as f->metadata. - Note that such nodes won't be REF_UNCHECKED since there are no data to - check anyway. */ -+ /* FIXME: But sometimes it is a regular file node, create by O_TRUNC flag */ - if (!tn->fn->size) { - if (rii->mdata_tn) { - if (rii->mdata_tn->version < tn->version) { -@@ -455,9 +456,12 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, - - if (rii->mdata_tn) { - dbg_readinode("potential mdata is ver %d at %p\n", rii->mdata_tn->version, rii->mdata_tn); -- high_ver = rii->mdata_tn->version; -+ /* FIXME: When it is not a regular file node, just do it. Otherwise, skip it */ -+ if (rii->fds) -+ high_ver = rii->mdata_tn->version; - rii->latest_ref = rii->mdata_tn->fn->raw; - } -+ - #ifdef JFFS2_DBG_READINODE_MESSAGES - this = tn_last(&rii->tn_root); - while (this) { -@@ -505,6 +509,8 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, - highest_version, because this one is only - counting _valid_ nodes which could give the - latest inode metadata */ -+ /* FIXME: Make sure latest_ref point to valid node, -+ * but not empty node */ - high_ver = this->version; - rii->latest_ref = this->fn->raw; - } -diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c -index f9916f31..a05e4b78 100644 ---- a/fs/jffs2/super.c -+++ b/fs/jffs2/super.c -@@ -355,6 +355,7 @@ static struct file_system_type jffs2_fs_type = { - .name = "jffs2", - .mount = jffs2_mount, - .kill_sb = jffs2_kill_sb, -+ .fs_flags = FS_REQUIRES_DEV, - }; - - static int __init init_jffs2_fs(void) -diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c -index 6bec5c0b..ac15a4f5 100644 ---- a/fs/jffs2/wbuf.c -+++ b/fs/jffs2/wbuf.c -@@ -1263,7 +1263,7 @@ void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { - int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { - /* Cleanmarker currently occupies whole programming regions, - * either one or 2 for 8Byte STMicro flashes. */ -- c->cleanmarker_size = max(16u, c->mtd->writesize); -+ //c->cleanmarker_size = max(16u, c->mtd->writesize); - - /* Initialize write buffer */ - init_rwsem(&c->wbuf_sem); -diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c -index b634de4c..7d01a5bd 100644 ---- a/fs/jffs2/write.c -+++ b/fs/jffs2/write.c -@@ -359,7 +359,16 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - jffs2_dbg(2, "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", - writelen, offset); - -- ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, -+ /* FIXME -+ * Make one write op as atomic, less data frag lose when power off. -+ * But, still lose some data when the file huge enough. -+ * And, wasted more space case of biger minisize. -+ * And, GC will work harder. -+ * And, performance is bad -+ */ -+ //ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, -+ //&alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); -+ ret = jffs2_reserve_space(c, writelen, - &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) { - jffs2_dbg(1, "jffs2_reserve_space returned %d\n", ret); -diff --git a/fs/proc/base.c b/fs/proc/base.c -index 9fc77b41..c8cb15dc 100644 ---- a/fs/proc/base.c -+++ b/fs/proc/base.c -@@ -137,6 +137,12 @@ struct pid_entry { - - static int proc_fd_permission(struct inode *inode, int mask); - -+/* ANDROID is for special files in /proc. */ -+#define ANDROID(NAME, MODE, OTYPE) \ -+ NOD(NAME, (S_IFREG|(MODE)), \ -+ &proc_##OTYPE##_inode_operations, \ -+ &proc_##OTYPE##_operations, {}) -+ - /* - * Count the number of hardlinks for the pid_entry table, excluding the . - * and .. links. -@@ -969,6 +975,35 @@ out: - return err < 0 ? err : count; - } - -+static int oom_adjust_permission(struct inode *inode, int mask) -+{ -+ uid_t uid; -+ struct task_struct *p; -+ -+ p = get_proc_task(inode); -+ if(p) { -+ uid = task_uid(p); -+ put_task_struct(p); -+ } -+ -+ /* -+ * System Server (uid == 1000) is granted access to oom_adj of all -+ * android applications (uid > 10000) as and services (uid >= 1000) -+ */ -+ if (p && (current_fsuid() == 1000) && (uid >= 1000)) { -+ if (inode->i_mode >> 6 & mask) { -+ return 0; -+ } -+ } -+ -+ /* Fall back to default. */ -+ return generic_permission(inode, mask); -+} -+ -+static const struct inode_operations proc_oom_adjust_inode_operations = { -+ .permission = oom_adjust_permission, -+}; -+ - static const struct file_operations proc_oom_adjust_operations = { - .read = oom_adjust_read, - .write = oom_adjust_write, -@@ -3011,7 +3046,7 @@ static const struct pid_entry tgid_base_stuff[] = { - REG("cgroup", S_IRUGO, proc_cgroup_operations), - #endif - INF("oom_score", S_IRUGO, proc_oom_score), -- REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations), -+ ANDROID("oom_adj",S_IRUGO|S_IWUSR, oom_adjust), - REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), - #ifdef CONFIG_AUDITSYSCALL - REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), -diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig -new file mode 100644 -index 00000000..63541405 ---- /dev/null -+++ b/fs/yaffs2/Kconfig -@@ -0,0 +1,161 @@ -+# -+# YAFFS file system configurations -+# -+ -+config YAFFS_FS -+ tristate "YAFFS2 file system support" -+ default n -+ depends on MTD_BLOCK -+ select YAFFS_YAFFS1 -+ select YAFFS_YAFFS2 -+ help -+ YAFFS2, or Yet Another Flash Filing System, is a filing system -+ optimised for NAND Flash chips. -+ -+ To compile the YAFFS2 file system support as a module, choose M -+ here: the module will be called yaffs2. -+ -+ If unsure, say N. -+ -+ Further information on YAFFS2 is available at -+ <http://www.aleph1.co.uk/yaffs/>. -+ -+config YAFFS_YAFFS1 -+ bool "512 byte / page devices" -+ depends on YAFFS_FS -+ default y -+ help -+ Enable YAFFS1 support -- yaffs for 512 byte / page devices -+ -+ Not needed for 2K-page devices. -+ -+ If unsure, say Y. -+ -+config YAFFS_9BYTE_TAGS -+ bool "Use older-style on-NAND data format with pageStatus byte" -+ depends on YAFFS_YAFFS1 -+ default n -+ help -+ -+ Older-style on-NAND data format has a "pageStatus" byte to record -+ chunk/page state. This byte is zero when the page is discarded. -+ Choose this option if you have existing on-NAND data using this -+ format that you need to continue to support. New data written -+ also uses the older-style format. Note: Use of this option -+ generally requires that MTD's oob layout be adjusted to use the -+ older-style format. See notes on tags formats and MTD versions -+ in yaffs_mtdif1.c. -+ -+ If unsure, say N. -+ -+config YAFFS_DOES_ECC -+ bool "Lets Yaffs do its own ECC" -+ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS -+ default n -+ help -+ This enables Yaffs to use its own ECC functions instead of using -+ the ones from the generic MTD-NAND driver. -+ -+ If unsure, say N. -+ -+config YAFFS_ECC_WRONG_ORDER -+ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" -+ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS -+ default n -+ help -+ This makes yaffs_ecc.c use the same ecc byte order as Steven -+ Hill's nand_ecc.c. If not set, then you get the same ecc byte -+ order as SmartMedia. -+ -+ If unsure, say N. -+ -+config YAFFS_YAFFS2 -+ bool "2048 byte (or larger) / page devices" -+ depends on YAFFS_FS -+ default y -+ help -+ Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices -+ -+ If unsure, say Y. -+ -+config YAFFS_AUTO_YAFFS2 -+ bool "Autoselect yaffs2 format" -+ depends on YAFFS_YAFFS2 -+ default y -+ help -+ Without this, you need to explicitely use yaffs2 as the file -+ system type. With this, you can say "yaffs" and yaffs or yaffs2 -+ will be used depending on the device page size (yaffs on -+ 512-byte page devices, yaffs2 on 2K page devices). -+ -+ If unsure, say Y. -+ -+config YAFFS_DISABLE_TAGS_ECC -+ bool "Disable YAFFS from doing ECC on tags by default" -+ depends on YAFFS_FS && YAFFS_YAFFS2 -+ default n -+ help -+ This defaults Yaffs to using its own ECC calculations on tags instead of -+ just relying on the MTD. -+ This behavior can also be overridden with tags_ecc_on and -+ tags_ecc_off mount options. -+ -+ If unsure, say N. -+ -+config YAFFS_ALWAYS_CHECK_CHUNK_ERASED -+ bool "Force chunk erase check" -+ depends on YAFFS_FS -+ default n -+ help -+ Normally YAFFS only checks chunks before writing until an erased -+ chunk is found. This helps to detect any partially written -+ chunks that might have happened due to power loss. -+ -+ Enabling this forces on the test that chunks are erased in flash -+ before writing to them. This takes more time but is potentially -+ a bit more secure. -+ -+ Suggest setting Y during development and ironing out driver -+ issues etc. Suggest setting to N if you want faster writing. -+ -+ If unsure, say Y. -+ -+config YAFFS_EMPTY_LOST_AND_FOUND -+ bool "Empty lost and found on boot" -+ depends on YAFFS_FS -+ default n -+ help -+ If this is enabled then the contents of lost and found is -+ automatically dumped at mount. -+ -+ If unsure, say N. -+ -+config YAFFS_DISABLE_BLOCK_REFRESHING -+ bool "Disable yaffs2 block refreshing" -+ depends on YAFFS_FS -+ default n -+ help -+ If this is set, then block refreshing is disabled. -+ Block refreshing infrequently refreshes the oldest block in -+ a yaffs2 file system. This mechanism helps to refresh flash to -+ mitigate against data loss. This is particularly useful for MLC. -+ -+ If unsure, say N. -+ -+config YAFFS_DISABLE_BACKGROUND -+ bool "Disable yaffs2 background processing" -+ depends on YAFFS_FS -+ default n -+ help -+ If this is set, then background processing is disabled. -+ Background processing makes many foreground activities faster. -+ -+ If unsure, say N. -+ -+config YAFFS_XATTR -+ bool "Enable yaffs2 xattr support" -+ depends on YAFFS_FS -+ default y -+ help -+ If this is set then yaffs2 will provide xattr support. -+ If unsure, say Y. -diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile -new file mode 100644 -index 00000000..e63a28aa ---- /dev/null -+++ b/fs/yaffs2/Makefile -@@ -0,0 +1,17 @@ -+# -+# Makefile for the linux YAFFS filesystem routines. -+# -+ -+obj-$(CONFIG_YAFFS_FS) += yaffs.o -+ -+yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o -+yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o -+yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o -+yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o -+yaffs-y += yaffs_nameval.o yaffs_attribs.o -+yaffs-y += yaffs_allocator.o -+yaffs-y += yaffs_yaffs1.o -+yaffs-y += yaffs_yaffs2.o -+yaffs-y += yaffs_bitmap.o -+yaffs-y += yaffs_verify.o -+ -diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c -new file mode 100644 -index 00000000..f9cd5bec ---- /dev/null -+++ b/fs/yaffs2/yaffs_allocator.c -@@ -0,0 +1,396 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_allocator.h" -+#include "yaffs_guts.h" -+#include "yaffs_trace.h" -+#include "yportenv.h" -+ -+#ifdef CONFIG_YAFFS_KMALLOC_ALLOCATOR -+ -+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) -+{ -+ dev = dev; -+} -+ -+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) -+{ -+ dev = dev; -+} -+ -+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) -+{ -+ return (struct yaffs_tnode *)kmalloc(dev->tnode_size, GFP_NOFS); -+} -+ -+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) -+{ -+ dev = dev; -+ kfree(tn); -+} -+ -+void yaffs_init_raw_objs(struct yaffs_dev *dev) -+{ -+ dev = dev; -+} -+ -+void yaffs_deinit_raw_objs(struct yaffs_dev *dev) -+{ -+ dev = dev; -+} -+ -+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) -+{ -+ dev = dev; -+ return (struct yaffs_obj *)kmalloc(sizeof(struct yaffs_obj)); -+} -+ -+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) -+{ -+ -+ dev = dev; -+ kfree(obj); -+} -+ -+#else -+ -+struct yaffs_tnode_list { -+ struct yaffs_tnode_list *next; -+ struct yaffs_tnode *tnodes; -+}; -+ -+struct yaffs_obj_list { -+ struct yaffs_obj_list *next; -+ struct yaffs_obj *objects; -+}; -+ -+struct yaffs_allocator { -+ int n_tnodes_created; -+ struct yaffs_tnode *free_tnodes; -+ int n_free_tnodes; -+ struct yaffs_tnode_list *alloc_tnode_list; -+ -+ int n_obj_created; -+ struct yaffs_obj *free_objs; -+ int n_free_objects; -+ -+ struct yaffs_obj_list *allocated_obj_list; -+}; -+ -+static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev) -+{ -+ -+ struct yaffs_allocator *allocator = -+ (struct yaffs_allocator *)dev->allocator; -+ -+ struct yaffs_tnode_list *tmp; -+ -+ if (!allocator) { -+ YBUG(); -+ return; -+ } -+ -+ while (allocator->alloc_tnode_list) { -+ tmp = allocator->alloc_tnode_list->next; -+ -+ kfree(allocator->alloc_tnode_list->tnodes); -+ kfree(allocator->alloc_tnode_list); -+ allocator->alloc_tnode_list = tmp; -+ -+ } -+ -+ allocator->free_tnodes = NULL; -+ allocator->n_free_tnodes = 0; -+ allocator->n_tnodes_created = 0; -+} -+ -+static void yaffs_init_raw_tnodes(struct yaffs_dev *dev) -+{ -+ struct yaffs_allocator *allocator = dev->allocator; -+ -+ if (allocator) { -+ allocator->alloc_tnode_list = NULL; -+ allocator->free_tnodes = NULL; -+ allocator->n_free_tnodes = 0; -+ allocator->n_tnodes_created = 0; -+ } else { -+ YBUG(); -+ } -+} -+ -+static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes) -+{ -+ struct yaffs_allocator *allocator = -+ (struct yaffs_allocator *)dev->allocator; -+ int i; -+ struct yaffs_tnode *new_tnodes; -+ u8 *mem; -+ struct yaffs_tnode *curr; -+ struct yaffs_tnode *next; -+ struct yaffs_tnode_list *tnl; -+ -+ if (!allocator) { -+ YBUG(); -+ return YAFFS_FAIL; -+ } -+ -+ if (n_tnodes < 1) -+ return YAFFS_OK; -+ -+ /* make these things */ -+ -+ new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS); -+ mem = (u8 *) new_tnodes; -+ -+ if (!new_tnodes) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs: Could not allocate Tnodes"); -+ return YAFFS_FAIL; -+ } -+ -+ /* New hookup for wide tnodes */ -+ for (i = 0; i < n_tnodes - 1; i++) { -+ curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; -+ next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size]; -+ curr->internal[0] = next; -+ } -+ -+ curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size]; -+ curr->internal[0] = allocator->free_tnodes; -+ allocator->free_tnodes = (struct yaffs_tnode *)mem; -+ -+ allocator->n_free_tnodes += n_tnodes; -+ allocator->n_tnodes_created += n_tnodes; -+ -+ /* Now add this bunch of tnodes to a list for freeing up. -+ * NB If we can't add this to the management list it isn't fatal -+ * but it just means we can't free this bunch of tnodes later. -+ */ -+ -+ tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS); -+ if (!tnl) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "Could not add tnodes to management list"); -+ return YAFFS_FAIL; -+ } else { -+ tnl->tnodes = new_tnodes; -+ tnl->next = allocator->alloc_tnode_list; -+ allocator->alloc_tnode_list = tnl; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_ALLOCATE,"Tnodes added"); -+ -+ return YAFFS_OK; -+} -+ -+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) -+{ -+ struct yaffs_allocator *allocator = -+ (struct yaffs_allocator *)dev->allocator; -+ struct yaffs_tnode *tn = NULL; -+ -+ if (!allocator) { -+ YBUG(); -+ return NULL; -+ } -+ -+ /* If there are none left make more */ -+ if (!allocator->free_tnodes) -+ yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); -+ -+ if (allocator->free_tnodes) { -+ tn = allocator->free_tnodes; -+ allocator->free_tnodes = allocator->free_tnodes->internal[0]; -+ allocator->n_free_tnodes--; -+ } -+ -+ return tn; -+} -+ -+/* FreeTnode frees up a tnode and puts it back on the free list */ -+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) -+{ -+ struct yaffs_allocator *allocator = dev->allocator; -+ -+ if (!allocator) { -+ YBUG(); -+ return; -+ } -+ -+ if (tn) { -+ tn->internal[0] = allocator->free_tnodes; -+ allocator->free_tnodes = tn; -+ allocator->n_free_tnodes++; -+ } -+ dev->checkpoint_blocks_required = 0; /* force recalculation */ -+} -+ -+static void yaffs_init_raw_objs(struct yaffs_dev *dev) -+{ -+ struct yaffs_allocator *allocator = dev->allocator; -+ -+ if (allocator) { -+ allocator->allocated_obj_list = NULL; -+ allocator->free_objs = NULL; -+ allocator->n_free_objects = 0; -+ } else { -+ YBUG(); -+ } -+} -+ -+static void yaffs_deinit_raw_objs(struct yaffs_dev *dev) -+{ -+ struct yaffs_allocator *allocator = dev->allocator; -+ struct yaffs_obj_list *tmp; -+ -+ if (!allocator) { -+ YBUG(); -+ return; -+ } -+ -+ while (allocator->allocated_obj_list) { -+ tmp = allocator->allocated_obj_list->next; -+ kfree(allocator->allocated_obj_list->objects); -+ kfree(allocator->allocated_obj_list); -+ -+ allocator->allocated_obj_list = tmp; -+ } -+ -+ allocator->free_objs = NULL; -+ allocator->n_free_objects = 0; -+ allocator->n_obj_created = 0; -+} -+ -+static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj) -+{ -+ struct yaffs_allocator *allocator = dev->allocator; -+ -+ int i; -+ struct yaffs_obj *new_objs; -+ struct yaffs_obj_list *list; -+ -+ if (!allocator) { -+ YBUG(); -+ return YAFFS_FAIL; -+ } -+ -+ if (n_obj < 1) -+ return YAFFS_OK; -+ -+ /* make these things */ -+ new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS); -+ list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS); -+ -+ if (!new_objs || !list) { -+ if (new_objs) { -+ kfree(new_objs); -+ new_objs = NULL; -+ } -+ if (list) { -+ kfree(list); -+ list = NULL; -+ } -+ yaffs_trace(YAFFS_TRACE_ALLOCATE, -+ "Could not allocate more objects"); -+ return YAFFS_FAIL; -+ } -+ -+ /* Hook them into the free list */ -+ for (i = 0; i < n_obj - 1; i++) { -+ new_objs[i].siblings.next = -+ (struct list_head *)(&new_objs[i + 1]); -+ } -+ -+ new_objs[n_obj - 1].siblings.next = (void *)allocator->free_objs; -+ allocator->free_objs = new_objs; -+ allocator->n_free_objects += n_obj; -+ allocator->n_obj_created += n_obj; -+ -+ /* Now add this bunch of Objects to a list for freeing up. */ -+ -+ list->objects = new_objs; -+ list->next = allocator->allocated_obj_list; -+ allocator->allocated_obj_list = list; -+ -+ return YAFFS_OK; -+} -+ -+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) -+{ -+ struct yaffs_obj *obj = NULL; -+ struct yaffs_allocator *allocator = dev->allocator; -+ -+ if (!allocator) { -+ YBUG(); -+ return obj; -+ } -+ -+ /* If there are none left make more */ -+ if (!allocator->free_objs) -+ yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); -+ -+ if (allocator->free_objs) { -+ obj = allocator->free_objs; -+ allocator->free_objs = -+ (struct yaffs_obj *)(allocator->free_objs->siblings.next); -+ allocator->n_free_objects--; -+ } -+ -+ return obj; -+} -+ -+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) -+{ -+ -+ struct yaffs_allocator *allocator = dev->allocator; -+ -+ if (!allocator) -+ YBUG(); -+ else { -+ /* Link into the free list. */ -+ obj->siblings.next = (struct list_head *)(allocator->free_objs); -+ allocator->free_objs = obj; -+ allocator->n_free_objects++; -+ } -+} -+ -+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) -+{ -+ if (dev->allocator) { -+ yaffs_deinit_raw_tnodes(dev); -+ yaffs_deinit_raw_objs(dev); -+ -+ kfree(dev->allocator); -+ dev->allocator = NULL; -+ } else { -+ YBUG(); -+ } -+} -+ -+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) -+{ -+ struct yaffs_allocator *allocator; -+ -+ if (!dev->allocator) { -+ allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS); -+ if (allocator) { -+ dev->allocator = allocator; -+ yaffs_init_raw_tnodes(dev); -+ yaffs_init_raw_objs(dev); -+ } -+ } else { -+ YBUG(); -+ } -+} -+ -+#endif -diff --git a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h -new file mode 100644 -index 00000000..4d5f2aec ---- /dev/null -+++ b/fs/yaffs2/yaffs_allocator.h -@@ -0,0 +1,30 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_ALLOCATOR_H__ -+#define __YAFFS_ALLOCATOR_H__ -+ -+#include "yaffs_guts.h" -+ -+void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev); -+void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev); -+ -+struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev); -+void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn); -+ -+struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev); -+void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_attribs.c b/fs/yaffs2/yaffs_attribs.c -new file mode 100644 -index 00000000..9b47d376 ---- /dev/null -+++ b/fs/yaffs2/yaffs_attribs.c -@@ -0,0 +1,124 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_guts.h" -+#include "yaffs_attribs.h" -+ -+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) -+{ -+ obj->yst_uid = oh->yst_uid; -+ obj->yst_gid = oh->yst_gid; -+ obj->yst_atime = oh->yst_atime; -+ obj->yst_mtime = oh->yst_mtime; -+ obj->yst_ctime = oh->yst_ctime; -+ obj->yst_rdev = oh->yst_rdev; -+} -+ -+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj) -+{ -+ oh->yst_uid = obj->yst_uid; -+ oh->yst_gid = obj->yst_gid; -+ oh->yst_atime = obj->yst_atime; -+ oh->yst_mtime = obj->yst_mtime; -+ oh->yst_ctime = obj->yst_ctime; -+ oh->yst_rdev = obj->yst_rdev; -+ -+} -+ -+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c) -+{ -+ obj->yst_mtime = Y_CURRENT_TIME; -+ if (do_a) -+ obj->yst_atime = obj->yst_mtime; -+ if (do_c) -+ obj->yst_ctime = obj->yst_mtime; -+} -+ -+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev) -+{ -+ yaffs_load_current_time(obj, 1, 1); -+ obj->yst_rdev = rdev; -+ obj->yst_uid = uid; -+ obj->yst_gid = gid; -+} -+ -+loff_t yaffs_get_file_size(struct yaffs_obj *obj) -+{ -+ YCHAR *alias = NULL; -+ obj = yaffs_get_equivalent_obj(obj); -+ -+ switch (obj->variant_type) { -+ case YAFFS_OBJECT_TYPE_FILE: -+ return obj->variant.file_variant.file_size; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ alias = obj->variant.symlink_variant.alias; -+ if (!alias) -+ return 0; -+ return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH); -+ default: -+ return 0; -+ } -+} -+ -+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr) -+{ -+ unsigned int valid = attr->ia_valid; -+ -+ if (valid & ATTR_MODE) -+ obj->yst_mode = attr->ia_mode; -+ if (valid & ATTR_UID) -+ obj->yst_uid = attr->ia_uid; -+ if (valid & ATTR_GID) -+ obj->yst_gid = attr->ia_gid; -+ -+ if (valid & ATTR_ATIME) -+ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); -+ if (valid & ATTR_CTIME) -+ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); -+ if (valid & ATTR_MTIME) -+ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); -+ -+ if (valid & ATTR_SIZE) -+ yaffs_resize_file(obj, attr->ia_size); -+ -+ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); -+ -+ return YAFFS_OK; -+ -+} -+ -+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr) -+{ -+ unsigned int valid = 0; -+ -+ attr->ia_mode = obj->yst_mode; -+ valid |= ATTR_MODE; -+ attr->ia_uid = obj->yst_uid; -+ valid |= ATTR_UID; -+ attr->ia_gid = obj->yst_gid; -+ valid |= ATTR_GID; -+ -+ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; -+ valid |= ATTR_ATIME; -+ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; -+ valid |= ATTR_CTIME; -+ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; -+ valid |= ATTR_MTIME; -+ -+ attr->ia_size = yaffs_get_file_size(obj); -+ valid |= ATTR_SIZE; -+ -+ attr->ia_valid = valid; -+ -+ return YAFFS_OK; -+} -diff --git a/fs/yaffs2/yaffs_attribs.h b/fs/yaffs2/yaffs_attribs.h -new file mode 100644 -index 00000000..33d541d6 ---- /dev/null -+++ b/fs/yaffs2/yaffs_attribs.h -@@ -0,0 +1,28 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_ATTRIBS_H__ -+#define __YAFFS_ATTRIBS_H__ -+ -+#include "yaffs_guts.h" -+ -+void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); -+void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj); -+void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev); -+void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c); -+int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr); -+int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c -new file mode 100644 -index 00000000..7df42cd0 ---- /dev/null -+++ b/fs/yaffs2/yaffs_bitmap.c -@@ -0,0 +1,98 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_bitmap.h" -+#include "yaffs_trace.h" -+/* -+ * Chunk bitmap manipulations -+ */ -+ -+static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk) -+{ -+ if (blk < dev->internal_start_block || blk > dev->internal_end_block) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "BlockBits block %d is not valid", -+ blk); -+ YBUG(); -+ } -+ return dev->chunk_bits + -+ (dev->chunk_bit_stride * (blk - dev->internal_start_block)); -+} -+ -+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk) -+{ -+ if (blk < dev->internal_start_block || blk > dev->internal_end_block || -+ chunk < 0 || chunk >= dev->param.chunks_per_block) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "Chunk Id (%d:%d) invalid", -+ blk, chunk); -+ YBUG(); -+ } -+} -+ -+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk) -+{ -+ u8 *blk_bits = yaffs_block_bits(dev, blk); -+ -+ memset(blk_bits, 0, dev->chunk_bit_stride); -+} -+ -+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) -+{ -+ u8 *blk_bits = yaffs_block_bits(dev, blk); -+ -+ yaffs_verify_chunk_bit_id(dev, blk, chunk); -+ -+ blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); -+} -+ -+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) -+{ -+ u8 *blk_bits = yaffs_block_bits(dev, blk); -+ -+ yaffs_verify_chunk_bit_id(dev, blk, chunk); -+ -+ blk_bits[chunk / 8] |= (1 << (chunk & 7)); -+} -+ -+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) -+{ -+ u8 *blk_bits = yaffs_block_bits(dev, blk); -+ yaffs_verify_chunk_bit_id(dev, blk, chunk); -+ -+ return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; -+} -+ -+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk) -+{ -+ u8 *blk_bits = yaffs_block_bits(dev, blk); -+ int i; -+ for (i = 0; i < dev->chunk_bit_stride; i++) { -+ if (*blk_bits) -+ return 1; -+ blk_bits++; -+ } -+ return 0; -+} -+ -+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk) -+{ -+ u8 *blk_bits = yaffs_block_bits(dev, blk); -+ int i; -+ int n = 0; -+ -+ for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++) -+ n += hweight8(*blk_bits); -+ -+ return n; -+} -diff --git a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h -new file mode 100644 -index 00000000..cf9ea58d ---- /dev/null -+++ b/fs/yaffs2/yaffs_bitmap.h -@@ -0,0 +1,33 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+/* -+ * Chunk bitmap manipulations -+ */ -+ -+#ifndef __YAFFS_BITMAP_H__ -+#define __YAFFS_BITMAP_H__ -+ -+#include "yaffs_guts.h" -+ -+void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk); -+void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk); -+void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); -+void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); -+int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); -+int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk); -+int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c -new file mode 100644 -index 00000000..4e40f437 ---- /dev/null -+++ b/fs/yaffs2/yaffs_checkptrw.c -@@ -0,0 +1,415 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_checkptrw.h" -+#include "yaffs_getblockinfo.h" -+ -+static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev) -+{ -+ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "checkpt blocks_avail = %d", blocks_avail); -+ -+ return (blocks_avail <= 0) ? 0 : 1; -+} -+ -+static int yaffs_checkpt_erase(struct yaffs_dev *dev) -+{ -+ int i; -+ -+ if (!dev->param.erase_fn) -+ return 0; -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "checking blocks %d to %d", -+ dev->internal_start_block, dev->internal_end_block); -+ -+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { -+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); -+ if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "erasing checkpt block %d", i); -+ -+ dev->n_erasures++; -+ -+ if (dev->param. -+ erase_fn(dev, -+ i - dev->block_offset /* realign */ )) { -+ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; -+ dev->n_erased_blocks++; -+ dev->n_free_chunks += -+ dev->param.chunks_per_block; -+ } else { -+ dev->param.bad_block_fn(dev, i); -+ bi->block_state = YAFFS_BLOCK_STATE_DEAD; -+ } -+ } -+ } -+ -+ dev->blocks_in_checkpt = 0; -+ -+ return 1; -+} -+ -+static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev) -+{ -+ int i; -+ int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "allocating checkpt block: erased %d reserved %d avail %d next %d ", -+ dev->n_erased_blocks, dev->param.n_reserved_blocks, -+ blocks_avail, dev->checkpt_next_block); -+ -+ if (dev->checkpt_next_block >= 0 && -+ dev->checkpt_next_block <= dev->internal_end_block && -+ blocks_avail > 0) { -+ -+ for (i = dev->checkpt_next_block; i <= dev->internal_end_block; -+ i++) { -+ struct yaffs_block_info *bi = -+ yaffs_get_block_info(dev, i); -+ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { -+ dev->checkpt_next_block = i + 1; -+ dev->checkpt_cur_block = i; -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "allocating checkpt block %d", i); -+ return; -+ } -+ } -+ } -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks"); -+ -+ dev->checkpt_next_block = -1; -+ dev->checkpt_cur_block = -1; -+} -+ -+static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) -+{ -+ int i; -+ struct yaffs_ext_tags tags; -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "find next checkpt block: start: blocks %d next %d", -+ dev->blocks_in_checkpt, dev->checkpt_next_block); -+ -+ if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) -+ for (i = dev->checkpt_next_block; i <= dev->internal_end_block; -+ i++) { -+ int chunk = i * dev->param.chunks_per_block; -+ int realigned_chunk = chunk - dev->chunk_offset; -+ -+ dev->param.read_chunk_tags_fn(dev, realigned_chunk, -+ NULL, &tags); -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "find next checkpt block: search: block %d oid %d seq %d eccr %d", -+ i, tags.obj_id, tags.seq_number, -+ tags.ecc_result); -+ -+ if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) { -+ /* Right kind of block */ -+ dev->checkpt_next_block = tags.obj_id; -+ dev->checkpt_cur_block = i; -+ dev->checkpt_block_list[dev-> -+ blocks_in_checkpt] = i; -+ dev->blocks_in_checkpt++; -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "found checkpt block %d", i); -+ return; -+ } -+ } -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); -+ -+ dev->checkpt_next_block = -1; -+ dev->checkpt_cur_block = -1; -+} -+ -+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing) -+{ -+ -+ dev->checkpt_open_write = writing; -+ -+ /* Got the functions we need? */ -+ if (!dev->param.write_chunk_tags_fn || -+ !dev->param.read_chunk_tags_fn || -+ !dev->param.erase_fn || !dev->param.bad_block_fn) -+ return 0; -+ -+ if (writing && !yaffs2_checkpt_space_ok(dev)) -+ return 0; -+ -+ if (!dev->checkpt_buffer) -+ dev->checkpt_buffer = -+ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); -+ if (!dev->checkpt_buffer) -+ return 0; -+ -+ dev->checkpt_page_seq = 0; -+ dev->checkpt_byte_count = 0; -+ dev->checkpt_sum = 0; -+ dev->checkpt_xor = 0; -+ dev->checkpt_cur_block = -1; -+ dev->checkpt_cur_chunk = -1; -+ dev->checkpt_next_block = dev->internal_start_block; -+ -+ /* Erase all the blocks in the checkpoint area */ -+ if (writing) { -+ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); -+ dev->checkpt_byte_offs = 0; -+ return yaffs_checkpt_erase(dev); -+ } else { -+ int i; -+ /* Set to a value that will kick off a read */ -+ dev->checkpt_byte_offs = dev->data_bytes_per_chunk; -+ /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully) -+ * going to be way more than we need */ -+ dev->blocks_in_checkpt = 0; -+ dev->checkpt_max_blocks = -+ (dev->internal_end_block - dev->internal_start_block) / 16 + -+ 2; -+ dev->checkpt_block_list = -+ kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS); -+ if (!dev->checkpt_block_list) -+ return 0; -+ -+ for (i = 0; i < dev->checkpt_max_blocks; i++) -+ dev->checkpt_block_list[i] = -1; -+ } -+ -+ return 1; -+} -+ -+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum) -+{ -+ u32 composite_sum; -+ composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF); -+ *sum = composite_sum; -+ return 1; -+} -+ -+static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) -+{ -+ int chunk; -+ int realigned_chunk; -+ -+ struct yaffs_ext_tags tags; -+ -+ if (dev->checkpt_cur_block < 0) { -+ yaffs2_checkpt_find_erased_block(dev); -+ dev->checkpt_cur_chunk = 0; -+ } -+ -+ if (dev->checkpt_cur_block < 0) -+ return 0; -+ -+ tags.is_deleted = 0; -+ tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ -+ tags.chunk_id = dev->checkpt_page_seq + 1; -+ tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; -+ tags.n_bytes = dev->data_bytes_per_chunk; -+ if (dev->checkpt_cur_chunk == 0) { -+ /* First chunk we write for the block? Set block state to -+ checkpoint */ -+ struct yaffs_block_info *bi = -+ yaffs_get_block_info(dev, dev->checkpt_cur_block); -+ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; -+ dev->blocks_in_checkpt++; -+ } -+ -+ chunk = -+ dev->checkpt_cur_block * dev->param.chunks_per_block + -+ dev->checkpt_cur_chunk; -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", -+ chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, -+ tags.obj_id, tags.chunk_id); -+ -+ realigned_chunk = chunk - dev->chunk_offset; -+ -+ dev->n_page_writes++; -+ -+ dev->param.write_chunk_tags_fn(dev, realigned_chunk, -+ dev->checkpt_buffer, &tags); -+ dev->checkpt_byte_offs = 0; -+ dev->checkpt_page_seq++; -+ dev->checkpt_cur_chunk++; -+ if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { -+ dev->checkpt_cur_chunk = 0; -+ dev->checkpt_cur_block = -1; -+ } -+ memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); -+ -+ return 1; -+} -+ -+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes) -+{ -+ int i = 0; -+ int ok = 1; -+ -+ u8 *data_bytes = (u8 *) data; -+ -+ if (!dev->checkpt_buffer) -+ return 0; -+ -+ if (!dev->checkpt_open_write) -+ return -1; -+ -+ while (i < n_bytes && ok) { -+ dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; -+ dev->checkpt_sum += *data_bytes; -+ dev->checkpt_xor ^= *data_bytes; -+ -+ dev->checkpt_byte_offs++; -+ i++; -+ data_bytes++; -+ dev->checkpt_byte_count++; -+ -+ if (dev->checkpt_byte_offs < 0 || -+ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) -+ ok = yaffs2_checkpt_flush_buffer(dev); -+ } -+ -+ return i; -+} -+ -+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) -+{ -+ int i = 0; -+ int ok = 1; -+ struct yaffs_ext_tags tags; -+ -+ int chunk; -+ int realigned_chunk; -+ -+ u8 *data_bytes = (u8 *) data; -+ -+ if (!dev->checkpt_buffer) -+ return 0; -+ -+ if (dev->checkpt_open_write) -+ return -1; -+ -+ while (i < n_bytes && ok) { -+ -+ if (dev->checkpt_byte_offs < 0 || -+ dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { -+ -+ if (dev->checkpt_cur_block < 0) { -+ yaffs2_checkpt_find_block(dev); -+ dev->checkpt_cur_chunk = 0; -+ } -+ -+ if (dev->checkpt_cur_block < 0) -+ ok = 0; -+ else { -+ chunk = dev->checkpt_cur_block * -+ dev->param.chunks_per_block + -+ dev->checkpt_cur_chunk; -+ -+ realigned_chunk = chunk - dev->chunk_offset; -+ -+ dev->n_page_reads++; -+ -+ /* read in the next chunk */ -+ dev->param.read_chunk_tags_fn(dev, -+ realigned_chunk, -+ dev-> -+ checkpt_buffer, -+ &tags); -+ -+ if (tags.chunk_id != (dev->checkpt_page_seq + 1) -+ || tags.ecc_result > YAFFS_ECC_RESULT_FIXED -+ || tags.seq_number != -+ YAFFS_SEQUENCE_CHECKPOINT_DATA) -+ ok = 0; -+ -+ dev->checkpt_byte_offs = 0; -+ dev->checkpt_page_seq++; -+ dev->checkpt_cur_chunk++; -+ -+ if (dev->checkpt_cur_chunk >= -+ dev->param.chunks_per_block) -+ dev->checkpt_cur_block = -1; -+ } -+ } -+ -+ if (ok) { -+ *data_bytes = -+ dev->checkpt_buffer[dev->checkpt_byte_offs]; -+ dev->checkpt_sum += *data_bytes; -+ dev->checkpt_xor ^= *data_bytes; -+ dev->checkpt_byte_offs++; -+ i++; -+ data_bytes++; -+ dev->checkpt_byte_count++; -+ } -+ } -+ -+ return i; -+} -+ -+int yaffs_checkpt_close(struct yaffs_dev *dev) -+{ -+ -+ if (dev->checkpt_open_write) { -+ if (dev->checkpt_byte_offs != 0) -+ yaffs2_checkpt_flush_buffer(dev); -+ } else if (dev->checkpt_block_list) { -+ int i; -+ for (i = 0; -+ i < dev->blocks_in_checkpt -+ && dev->checkpt_block_list[i] >= 0; i++) { -+ int blk = dev->checkpt_block_list[i]; -+ struct yaffs_block_info *bi = NULL; -+ if (dev->internal_start_block <= blk -+ && blk <= dev->internal_end_block) -+ bi = yaffs_get_block_info(dev, blk); -+ if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) -+ bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; -+ else { -+ /* Todo this looks odd... */ -+ } -+ } -+ kfree(dev->checkpt_block_list); -+ dev->checkpt_block_list = NULL; -+ } -+ -+ dev->n_free_chunks -= -+ dev->blocks_in_checkpt * dev->param.chunks_per_block; -+ dev->n_erased_blocks -= dev->blocks_in_checkpt; -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT,"checkpoint byte count %d", -+ dev->checkpt_byte_count); -+ -+ if (dev->checkpt_buffer) { -+ /* free the buffer */ -+ kfree(dev->checkpt_buffer); -+ dev->checkpt_buffer = NULL; -+ return 1; -+ } else { -+ return 0; -+ } -+} -+ -+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev) -+{ -+ /* Erase the checkpoint data */ -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "checkpoint invalidate of %d blocks", -+ dev->blocks_in_checkpt); -+ -+ return yaffs_checkpt_erase(dev); -+} -diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h -new file mode 100644 -index 00000000..361c6067 ---- /dev/null -+++ b/fs/yaffs2/yaffs_checkptrw.h -@@ -0,0 +1,33 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_CHECKPTRW_H__ -+#define __YAFFS_CHECKPTRW_H__ -+ -+#include "yaffs_guts.h" -+ -+int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing); -+ -+int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes); -+ -+int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes); -+ -+int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum); -+ -+int yaffs_checkpt_close(struct yaffs_dev *dev); -+ -+int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c -new file mode 100644 -index 00000000..e95a8069 ---- /dev/null -+++ b/fs/yaffs2/yaffs_ecc.c -@@ -0,0 +1,298 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+/* -+ * This code implements the ECC algorithm used in SmartMedia. -+ * -+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. -+ * The two unused bit are set to 1. -+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC -+ * blocks are used on a 512-byte NAND page. -+ * -+ */ -+ -+/* Table generated by gen-ecc.c -+ * Using a table means we do not have to calculate p1..p4 and p1'..p4' -+ * for each byte of data. These are instead provided in a table in bits7..2. -+ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore -+ * this bytes influence on the line parity. -+ */ -+ -+#include "yportenv.h" -+ -+#include "yaffs_ecc.h" -+ -+static const unsigned char column_parity_table[] = { -+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, -+ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, -+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, -+ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, -+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, -+ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, -+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, -+ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, -+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, -+ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, -+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, -+ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, -+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, -+ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, -+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, -+ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, -+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, -+ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, -+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, -+ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, -+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, -+ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, -+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, -+ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, -+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, -+ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, -+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, -+ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, -+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, -+ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, -+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, -+ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, -+}; -+ -+ -+/* Calculate the ECC for a 256-byte block of data */ -+void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc) -+{ -+ unsigned int i; -+ -+ unsigned char col_parity = 0; -+ unsigned char line_parity = 0; -+ unsigned char line_parity_prime = 0; -+ unsigned char t; -+ unsigned char b; -+ -+ for (i = 0; i < 256; i++) { -+ b = column_parity_table[*data++]; -+ col_parity ^= b; -+ -+ if (b & 0x01) { /* odd number of bits in the byte */ -+ line_parity ^= i; -+ line_parity_prime ^= ~i; -+ } -+ } -+ -+ ecc[2] = (~col_parity) | 0x03; -+ -+ t = 0; -+ if (line_parity & 0x80) -+ t |= 0x80; -+ if (line_parity_prime & 0x80) -+ t |= 0x40; -+ if (line_parity & 0x40) -+ t |= 0x20; -+ if (line_parity_prime & 0x40) -+ t |= 0x10; -+ if (line_parity & 0x20) -+ t |= 0x08; -+ if (line_parity_prime & 0x20) -+ t |= 0x04; -+ if (line_parity & 0x10) -+ t |= 0x02; -+ if (line_parity_prime & 0x10) -+ t |= 0x01; -+ ecc[1] = ~t; -+ -+ t = 0; -+ if (line_parity & 0x08) -+ t |= 0x80; -+ if (line_parity_prime & 0x08) -+ t |= 0x40; -+ if (line_parity & 0x04) -+ t |= 0x20; -+ if (line_parity_prime & 0x04) -+ t |= 0x10; -+ if (line_parity & 0x02) -+ t |= 0x08; -+ if (line_parity_prime & 0x02) -+ t |= 0x04; -+ if (line_parity & 0x01) -+ t |= 0x02; -+ if (line_parity_prime & 0x01) -+ t |= 0x01; -+ ecc[0] = ~t; -+ -+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER -+ /* Swap the bytes into the wrong order */ -+ t = ecc[0]; -+ ecc[0] = ecc[1]; -+ ecc[1] = t; -+#endif -+} -+ -+/* Correct the ECC on a 256 byte block of data */ -+ -+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, -+ const unsigned char *test_ecc) -+{ -+ unsigned char d0, d1, d2; /* deltas */ -+ -+ d0 = read_ecc[0] ^ test_ecc[0]; -+ d1 = read_ecc[1] ^ test_ecc[1]; -+ d2 = read_ecc[2] ^ test_ecc[2]; -+ -+ if ((d0 | d1 | d2) == 0) -+ return 0; /* no error */ -+ -+ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && -+ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && -+ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { -+ /* Single bit (recoverable) error in data */ -+ -+ unsigned byte; -+ unsigned bit; -+ -+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER -+ /* swap the bytes to correct for the wrong order */ -+ unsigned char t; -+ -+ t = d0; -+ d0 = d1; -+ d1 = t; -+#endif -+ -+ bit = byte = 0; -+ -+ if (d1 & 0x80) -+ byte |= 0x80; -+ if (d1 & 0x20) -+ byte |= 0x40; -+ if (d1 & 0x08) -+ byte |= 0x20; -+ if (d1 & 0x02) -+ byte |= 0x10; -+ if (d0 & 0x80) -+ byte |= 0x08; -+ if (d0 & 0x20) -+ byte |= 0x04; -+ if (d0 & 0x08) -+ byte |= 0x02; -+ if (d0 & 0x02) -+ byte |= 0x01; -+ -+ if (d2 & 0x80) -+ bit |= 0x04; -+ if (d2 & 0x20) -+ bit |= 0x02; -+ if (d2 & 0x08) -+ bit |= 0x01; -+ -+ data[byte] ^= (1 << bit); -+ -+ return 1; /* Corrected the error */ -+ } -+ -+ if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) { -+ /* Reccoverable error in ecc */ -+ -+ read_ecc[0] = test_ecc[0]; -+ read_ecc[1] = test_ecc[1]; -+ read_ecc[2] = test_ecc[2]; -+ -+ return 1; /* Corrected the error */ -+ } -+ -+ /* Unrecoverable error */ -+ -+ return -1; -+ -+} -+ -+/* -+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data -+ */ -+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, -+ struct yaffs_ecc_other *ecc_other) -+{ -+ unsigned int i; -+ -+ unsigned char col_parity = 0; -+ unsigned line_parity = 0; -+ unsigned line_parity_prime = 0; -+ unsigned char b; -+ -+ for (i = 0; i < n_bytes; i++) { -+ b = column_parity_table[*data++]; -+ col_parity ^= b; -+ -+ if (b & 0x01) { -+ /* odd number of bits in the byte */ -+ line_parity ^= i; -+ line_parity_prime ^= ~i; -+ } -+ -+ } -+ -+ ecc_other->col_parity = (col_parity >> 2) & 0x3f; -+ ecc_other->line_parity = line_parity; -+ ecc_other->line_parity_prime = line_parity_prime; -+} -+ -+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, -+ struct yaffs_ecc_other *read_ecc, -+ const struct yaffs_ecc_other *test_ecc) -+{ -+ unsigned char delta_col; /* column parity delta */ -+ unsigned delta_line; /* line parity delta */ -+ unsigned delta_line_prime; /* line parity delta */ -+ unsigned bit; -+ -+ delta_col = read_ecc->col_parity ^ test_ecc->col_parity; -+ delta_line = read_ecc->line_parity ^ test_ecc->line_parity; -+ delta_line_prime = -+ read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; -+ -+ if ((delta_col | delta_line | delta_line_prime) == 0) -+ return 0; /* no error */ -+ -+ if (delta_line == ~delta_line_prime && -+ (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) { -+ /* Single bit (recoverable) error in data */ -+ -+ bit = 0; -+ -+ if (delta_col & 0x20) -+ bit |= 0x04; -+ if (delta_col & 0x08) -+ bit |= 0x02; -+ if (delta_col & 0x02) -+ bit |= 0x01; -+ -+ if (delta_line >= n_bytes) -+ return -1; -+ -+ data[delta_line] ^= (1 << bit); -+ -+ return 1; /* corrected */ -+ } -+ -+ if ((hweight32(delta_line) + -+ hweight32(delta_line_prime) + -+ hweight8(delta_col)) == 1) { -+ /* Reccoverable error in ecc */ -+ -+ *read_ecc = *test_ecc; -+ return 1; /* corrected */ -+ } -+ -+ /* Unrecoverable error */ -+ -+ return -1; -+} -diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h -new file mode 100644 -index 00000000..b0c461d6 ---- /dev/null -+++ b/fs/yaffs2/yaffs_ecc.h -@@ -0,0 +1,44 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+/* -+ * This code implements the ECC algorithm used in SmartMedia. -+ * -+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. -+ * The two unused bit are set to 1. -+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC -+ * blocks are used on a 512-byte NAND page. -+ * -+ */ -+ -+#ifndef __YAFFS_ECC_H__ -+#define __YAFFS_ECC_H__ -+ -+struct yaffs_ecc_other { -+ unsigned char col_parity; -+ unsigned line_parity; -+ unsigned line_parity_prime; -+}; -+ -+void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc); -+int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, -+ const unsigned char *test_ecc); -+ -+void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, -+ struct yaffs_ecc_other *ecc); -+int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, -+ struct yaffs_ecc_other *read_ecc, -+ const struct yaffs_ecc_other *test_ecc); -+#endif -diff --git a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h -new file mode 100644 -index 00000000..d87acbde ---- /dev/null -+++ b/fs/yaffs2/yaffs_getblockinfo.h -@@ -0,0 +1,35 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_GETBLOCKINFO_H__ -+#define __YAFFS_GETBLOCKINFO_H__ -+ -+#include "yaffs_guts.h" -+#include "yaffs_trace.h" -+ -+/* Function to manipulate block info */ -+static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev -+ *dev, int blk) -+{ -+ if (blk < dev->internal_start_block || blk > dev->internal_end_block) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>> yaffs: get_block_info block %d is not valid", -+ blk); -+ YBUG(); -+ } -+ return &dev->block_info[blk - dev->internal_start_block]; -+} -+ -+#endif -diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c -new file mode 100644 -index 00000000..f4ae9dee ---- /dev/null -+++ b/fs/yaffs2/yaffs_guts.c -@@ -0,0 +1,5164 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yportenv.h" -+#include "yaffs_trace.h" -+ -+#include "yaffs_guts.h" -+#include "yaffs_tagsvalidity.h" -+#include "yaffs_getblockinfo.h" -+ -+#include "yaffs_tagscompat.h" -+ -+#include "yaffs_nand.h" -+ -+#include "yaffs_yaffs1.h" -+#include "yaffs_yaffs2.h" -+#include "yaffs_bitmap.h" -+#include "yaffs_verify.h" -+ -+#include "yaffs_nand.h" -+#include "yaffs_packedtags2.h" -+ -+#include "yaffs_nameval.h" -+#include "yaffs_allocator.h" -+ -+#include "yaffs_attribs.h" -+ -+/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ -+#define YAFFS_GC_GOOD_ENOUGH 2 -+#define YAFFS_GC_PASSIVE_THRESHOLD 4 -+ -+#include "yaffs_ecc.h" -+ -+/* Forward declarations */ -+ -+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, -+ const u8 * buffer, int n_bytes, int use_reserve); -+ -+ -+ -+/* Function to calculate chunk and offset */ -+ -+static void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, -+ int *chunk_out, u32 * offset_out) -+{ -+ int chunk; -+ u32 offset; -+ -+ chunk = (u32) (addr >> dev->chunk_shift); -+ -+ if (dev->chunk_div == 1) { -+ /* easy power of 2 case */ -+ offset = (u32) (addr & dev->chunk_mask); -+ } else { -+ /* Non power-of-2 case */ -+ -+ loff_t chunk_base; -+ -+ chunk /= dev->chunk_div; -+ -+ chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk; -+ offset = (u32) (addr - chunk_base); -+ } -+ -+ *chunk_out = chunk; -+ *offset_out = offset; -+} -+ -+/* Function to return the number of shifts for a power of 2 greater than or -+ * equal to the given number -+ * Note we don't try to cater for all possible numbers and this does not have to -+ * be hellishly efficient. -+ */ -+ -+static u32 calc_shifts_ceiling(u32 x) -+{ -+ int extra_bits; -+ int shifts; -+ -+ shifts = extra_bits = 0; -+ -+ while (x > 1) { -+ if (x & 1) -+ extra_bits++; -+ x >>= 1; -+ shifts++; -+ } -+ -+ if (extra_bits) -+ shifts++; -+ -+ return shifts; -+} -+ -+/* Function to return the number of shifts to get a 1 in bit 0 -+ */ -+ -+static u32 calc_shifts(u32 x) -+{ -+ u32 shifts; -+ -+ shifts = 0; -+ -+ if (!x) -+ return 0; -+ -+ while (!(x & 1)) { -+ x >>= 1; -+ shifts++; -+ } -+ -+ return shifts; -+} -+ -+/* -+ * Temporary buffer manipulations. -+ */ -+ -+static int yaffs_init_tmp_buffers(struct yaffs_dev *dev) -+{ -+ int i; -+ u8 *buf = (u8 *) 1; -+ -+ memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer)); -+ -+ for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { -+ dev->temp_buffer[i].line = 0; /* not in use */ -+ dev->temp_buffer[i].buffer = buf = -+ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); -+ } -+ -+ return buf ? YAFFS_OK : YAFFS_FAIL; -+} -+ -+u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev, int line_no) -+{ -+ int i, j; -+ -+ dev->temp_in_use++; -+ if (dev->temp_in_use > dev->max_temp) -+ dev->max_temp = dev->temp_in_use; -+ -+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { -+ if (dev->temp_buffer[i].line == 0) { -+ dev->temp_buffer[i].line = line_no; -+ if ((i + 1) > dev->max_temp) { -+ dev->max_temp = i + 1; -+ for (j = 0; j <= i; j++) -+ dev->temp_buffer[j].max_line = -+ dev->temp_buffer[j].line; -+ } -+ -+ return dev->temp_buffer[i].buffer; -+ } -+ } -+ -+ yaffs_trace(YAFFS_TRACE_BUFFERS, -+ "Out of temp buffers at line %d, other held by lines:", -+ line_no); -+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) -+ yaffs_trace(YAFFS_TRACE_BUFFERS," %d", dev->temp_buffer[i].line); -+ -+ /* -+ * If we got here then we have to allocate an unmanaged one -+ * This is not good. -+ */ -+ -+ dev->unmanaged_buffer_allocs++; -+ return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS); -+ -+} -+ -+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 * buffer, int line_no) -+{ -+ int i; -+ -+ dev->temp_in_use--; -+ -+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { -+ if (dev->temp_buffer[i].buffer == buffer) { -+ dev->temp_buffer[i].line = 0; -+ return; -+ } -+ } -+ -+ if (buffer) { -+ /* assume it is an unmanaged one. */ -+ yaffs_trace(YAFFS_TRACE_BUFFERS, -+ "Releasing unmanaged temp buffer in line %d", -+ line_no); -+ kfree(buffer); -+ dev->unmanaged_buffer_deallocs++; -+ } -+ -+} -+ -+/* -+ * Determine if we have a managed buffer. -+ */ -+int yaffs_is_managed_tmp_buffer(struct yaffs_dev *dev, const u8 * buffer) -+{ -+ int i; -+ -+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { -+ if (dev->temp_buffer[i].buffer == buffer) -+ return 1; -+ } -+ -+ for (i = 0; i < dev->param.n_caches; i++) { -+ if (dev->cache[i].data == buffer) -+ return 1; -+ } -+ -+ if (buffer == dev->checkpt_buffer) -+ return 1; -+ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs: unmaged buffer detected."); -+ return 0; -+} -+ -+/* -+ * Functions for robustisizing TODO -+ * -+ */ -+ -+static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk, -+ const u8 * data, -+ const struct yaffs_ext_tags *tags) -+{ -+ dev = dev; -+ nand_chunk = nand_chunk; -+ data = data; -+ tags = tags; -+} -+ -+static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk, -+ const struct yaffs_ext_tags *tags) -+{ -+ dev = dev; -+ nand_chunk = nand_chunk; -+ tags = tags; -+} -+ -+void yaffs_handle_chunk_error(struct yaffs_dev *dev, -+ struct yaffs_block_info *bi) -+{ -+ if (!bi->gc_prioritise) { -+ bi->gc_prioritise = 1; -+ dev->has_pending_prioritised_gc = 1; -+ bi->chunk_error_strikes++; -+ -+ if (bi->chunk_error_strikes > 3) { -+ bi->needs_retiring = 1; /* Too many stikes, so retire this */ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "yaffs: Block struck out"); -+ -+ } -+ } -+} -+ -+static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk, -+ int erased_ok) -+{ -+ int flash_block = nand_chunk / dev->param.chunks_per_block; -+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); -+ -+ yaffs_handle_chunk_error(dev, bi); -+ -+ if (erased_ok) { -+ /* Was an actual write failure, so mark the block for retirement */ -+ bi->needs_retiring = 1; -+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, -+ "**>> Block %d needs retiring", flash_block); -+ } -+ -+ /* Delete the chunk */ -+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); -+ yaffs_skip_rest_of_block(dev); -+} -+ -+/* -+ * Verification code -+ */ -+ -+/* -+ * Simple hash function. Needs to have a reasonable spread -+ */ -+ -+static inline int yaffs_hash_fn(int n) -+{ -+ n = abs(n); -+ return n % YAFFS_NOBJECT_BUCKETS; -+} -+ -+/* -+ * Access functions to useful fake objects. -+ * Note that root might have a presence in NAND if permissions are set. -+ */ -+ -+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev) -+{ -+ return dev->root_dir; -+} -+ -+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev) -+{ -+ return dev->lost_n_found; -+} -+ -+/* -+ * Erased NAND checking functions -+ */ -+ -+int yaffs_check_ff(u8 * buffer, int n_bytes) -+{ -+ /* Horrible, slow implementation */ -+ while (n_bytes--) { -+ if (*buffer != 0xFF) -+ return 0; -+ buffer++; -+ } -+ return 1; -+} -+ -+static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk) -+{ -+ int retval = YAFFS_OK; -+ u8 *data = yaffs_get_temp_buffer(dev, __LINE__); -+ struct yaffs_ext_tags tags; -+ int result; -+ -+ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags); -+ -+ if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR) -+ retval = YAFFS_FAIL; -+ -+ if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || -+ tags.chunk_used) { -+ yaffs_trace(YAFFS_TRACE_NANDACCESS, "Chunk %d not erased", nand_chunk); -+ retval = YAFFS_FAIL; -+ } -+ -+ yaffs_release_temp_buffer(dev, data, __LINE__); -+ -+ return retval; -+ -+} -+ -+static int yaffs_verify_chunk_written(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 * data, -+ struct yaffs_ext_tags *tags) -+{ -+ int retval = YAFFS_OK; -+ struct yaffs_ext_tags temp_tags; -+ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); -+ int result; -+ -+ result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags); -+ if (memcmp(buffer, data, dev->data_bytes_per_chunk) || -+ temp_tags.obj_id != tags->obj_id || -+ temp_tags.chunk_id != tags->chunk_id || -+ temp_tags.n_bytes != tags->n_bytes) -+ retval = YAFFS_FAIL; -+ -+ yaffs_release_temp_buffer(dev, buffer, __LINE__); -+ -+ return retval; -+} -+ -+ -+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks) -+{ -+ int reserved_chunks; -+ int reserved_blocks = dev->param.n_reserved_blocks; -+ int checkpt_blocks; -+ -+ checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev); -+ -+ reserved_chunks = -+ ((reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block); -+ -+ return (dev->n_free_chunks > (reserved_chunks + n_chunks)); -+} -+ -+static int yaffs_find_alloc_block(struct yaffs_dev *dev) -+{ -+ int i; -+ -+ struct yaffs_block_info *bi; -+ -+ if (dev->n_erased_blocks < 1) { -+ /* Hoosterman we've got a problem. -+ * Can't get space to gc -+ */ -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy: no more erased blocks" ); -+ -+ return -1; -+ } -+ -+ /* Find an empty block. */ -+ -+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { -+ dev->alloc_block_finder++; -+ if (dev->alloc_block_finder < dev->internal_start_block -+ || dev->alloc_block_finder > dev->internal_end_block) { -+ dev->alloc_block_finder = dev->internal_start_block; -+ } -+ -+ bi = yaffs_get_block_info(dev, dev->alloc_block_finder); -+ -+ if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { -+ bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING; -+ dev->seq_number++; -+ bi->seq_number = dev->seq_number; -+ dev->n_erased_blocks--; -+ yaffs_trace(YAFFS_TRACE_ALLOCATE, -+ "Allocated block %d, seq %d, %d left" , -+ dev->alloc_block_finder, dev->seq_number, -+ dev->n_erased_blocks); -+ return dev->alloc_block_finder; -+ } -+ } -+ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs tragedy: no more erased blocks, but there should have been %d", -+ dev->n_erased_blocks); -+ -+ return -1; -+} -+ -+static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, -+ struct yaffs_block_info **block_ptr) -+{ -+ int ret_val; -+ struct yaffs_block_info *bi; -+ -+ if (dev->alloc_block < 0) { -+ /* Get next block to allocate off */ -+ dev->alloc_block = yaffs_find_alloc_block(dev); -+ dev->alloc_page = 0; -+ } -+ -+ if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) { -+ /* Not enough space to allocate unless we're allowed to use the reserve. */ -+ return -1; -+ } -+ -+ if (dev->n_erased_blocks < dev->param.n_reserved_blocks -+ && dev->alloc_page == 0) -+ yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve"); -+ -+ /* Next page please.... */ -+ if (dev->alloc_block >= 0) { -+ bi = yaffs_get_block_info(dev, dev->alloc_block); -+ -+ ret_val = (dev->alloc_block * dev->param.chunks_per_block) + -+ dev->alloc_page; -+ bi->pages_in_use++; -+ yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page); -+ -+ dev->alloc_page++; -+ -+ dev->n_free_chunks--; -+ -+ /* If the block is full set the state to full */ -+ if (dev->alloc_page >= dev->param.chunks_per_block) { -+ bi->block_state = YAFFS_BLOCK_STATE_FULL; -+ dev->alloc_block = -1; -+ } -+ -+ if (block_ptr) -+ *block_ptr = bi; -+ -+ return ret_val; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_ERROR, "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" ); -+ -+ return -1; -+} -+ -+static int yaffs_get_erased_chunks(struct yaffs_dev *dev) -+{ -+ int n; -+ -+ n = dev->n_erased_blocks * dev->param.chunks_per_block; -+ -+ if (dev->alloc_block > 0) -+ n += (dev->param.chunks_per_block - dev->alloc_page); -+ -+ return n; -+ -+} -+ -+/* -+ * yaffs_skip_rest_of_block() skips over the rest of the allocation block -+ * if we don't want to write to it. -+ */ -+void yaffs_skip_rest_of_block(struct yaffs_dev *dev) -+{ -+ if (dev->alloc_block > 0) { -+ struct yaffs_block_info *bi = -+ yaffs_get_block_info(dev, dev->alloc_block); -+ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { -+ bi->block_state = YAFFS_BLOCK_STATE_FULL; -+ dev->alloc_block = -1; -+ } -+ } -+} -+ -+static int yaffs_write_new_chunk(struct yaffs_dev *dev, -+ const u8 * data, -+ struct yaffs_ext_tags *tags, int use_reserver) -+{ -+ int attempts = 0; -+ int write_ok = 0; -+ int chunk; -+ -+ yaffs2_checkpt_invalidate(dev); -+ -+ do { -+ struct yaffs_block_info *bi = 0; -+ int erased_ok = 0; -+ -+ chunk = yaffs_alloc_chunk(dev, use_reserver, &bi); -+ if (chunk < 0) { -+ /* no space */ -+ break; -+ } -+ -+ /* First check this chunk is erased, if it needs -+ * checking. The checking policy (unless forced -+ * always on) is as follows: -+ * -+ * Check the first page we try to write in a block. -+ * If the check passes then we don't need to check any -+ * more. If the check fails, we check again... -+ * If the block has been erased, we don't need to check. -+ * -+ * However, if the block has been prioritised for gc, -+ * then we think there might be something odd about -+ * this block and stop using it. -+ * -+ * Rationale: We should only ever see chunks that have -+ * not been erased if there was a partially written -+ * chunk due to power loss. This checking policy should -+ * catch that case with very few checks and thus save a -+ * lot of checks that are most likely not needed. -+ * -+ * Mods to the above -+ * If an erase check fails or the write fails we skip the -+ * rest of the block. -+ */ -+ -+ /* let's give it a try */ -+ attempts++; -+ -+ if (dev->param.always_check_erased) -+ bi->skip_erased_check = 0; -+ -+ if (!bi->skip_erased_check) { -+ erased_ok = yaffs_check_chunk_erased(dev, chunk); -+ if (erased_ok != YAFFS_OK) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>> yaffs chunk %d was not erased", -+ chunk); -+ -+ /* If not erased, delete this one, -+ * skip rest of block and -+ * try another chunk */ -+ yaffs_chunk_del(dev, chunk, 1, __LINE__); -+ yaffs_skip_rest_of_block(dev); -+ continue; -+ } -+ } -+ -+ write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags); -+ -+ if (!bi->skip_erased_check) -+ write_ok = -+ yaffs_verify_chunk_written(dev, chunk, data, tags); -+ -+ if (write_ok != YAFFS_OK) { -+ /* Clean up aborted write, skip to next block and -+ * try another chunk */ -+ yaffs_handle_chunk_wr_error(dev, chunk, erased_ok); -+ continue; -+ } -+ -+ bi->skip_erased_check = 1; -+ -+ /* Copy the data into the robustification buffer */ -+ yaffs_handle_chunk_wr_ok(dev, chunk, data, tags); -+ -+ } while (write_ok != YAFFS_OK && -+ (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); -+ -+ if (!write_ok) -+ chunk = -1; -+ -+ if (attempts > 1) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>> yaffs write required %d attempts", -+ attempts); -+ dev->n_retired_writes += (attempts - 1); -+ } -+ -+ return chunk; -+} -+ -+/* -+ * Block retiring for handling a broken block. -+ */ -+ -+static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block) -+{ -+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); -+ -+ yaffs2_checkpt_invalidate(dev); -+ -+ yaffs2_clear_oldest_dirty_seq(dev, bi); -+ -+ if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) { -+ if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs: Failed to mark bad and erase block %d", -+ flash_block); -+ } else { -+ struct yaffs_ext_tags tags; -+ int chunk_id = -+ flash_block * dev->param.chunks_per_block; -+ -+ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ memset(buffer, 0xff, dev->data_bytes_per_chunk); -+ yaffs_init_tags(&tags); -+ tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; -+ if (dev->param.write_chunk_tags_fn(dev, chunk_id - -+ dev->chunk_offset, -+ buffer, -+ &tags) != YAFFS_OK) -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs: Failed to write bad block marker to block %d", -+ flash_block); -+ -+ yaffs_release_temp_buffer(dev, buffer, __LINE__); -+ } -+ } -+ -+ bi->block_state = YAFFS_BLOCK_STATE_DEAD; -+ bi->gc_prioritise = 0; -+ bi->needs_retiring = 0; -+ -+ dev->n_retired_blocks++; -+} -+ -+/*---------------- Name handling functions ------------*/ -+ -+static u16 yaffs_calc_name_sum(const YCHAR * name) -+{ -+ u16 sum = 0; -+ u16 i = 1; -+ -+ const YUCHAR *bname = (const YUCHAR *)name; -+ if (bname) { -+ while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH / 2))) { -+ -+ /* 0x1f mask is case insensitive */ -+ sum += ((*bname) & 0x1f) * i; -+ i++; -+ bname++; -+ } -+ } -+ return sum; -+} -+ -+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) -+{ -+#ifndef CONFIG_YAFFS_NO_SHORT_NAMES -+ memset(obj->short_name, 0, sizeof(obj->short_name)); -+ if (name && -+ strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= -+ YAFFS_SHORT_NAME_LENGTH) -+ strcpy(obj->short_name, name); -+ else -+ obj->short_name[0] = _Y('\0'); -+#endif -+ obj->sum = yaffs_calc_name_sum(name); -+} -+ -+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, -+ const struct yaffs_obj_hdr *oh) -+{ -+#ifdef CONFIG_YAFFS_AUTO_UNICODE -+ YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1]; -+ memset(tmp_name, 0, sizeof(tmp_name)); -+ yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name, -+ YAFFS_MAX_NAME_LENGTH + 1); -+ yaffs_set_obj_name(obj, tmp_name); -+#else -+ yaffs_set_obj_name(obj, oh->name); -+#endif -+} -+ -+/*-------------------- TNODES ------------------- -+ -+ * List of spare tnodes -+ * The list is hooked together using the first pointer -+ * in the tnode. -+ */ -+ -+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev) -+{ -+ struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev); -+ if (tn) { -+ memset(tn, 0, dev->tnode_size); -+ dev->n_tnodes++; -+ } -+ -+ dev->checkpoint_blocks_required = 0; /* force recalculation */ -+ -+ return tn; -+} -+ -+/* FreeTnode frees up a tnode and puts it back on the free list */ -+static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) -+{ -+ yaffs_free_raw_tnode(dev, tn); -+ dev->n_tnodes--; -+ dev->checkpoint_blocks_required = 0; /* force recalculation */ -+} -+ -+static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev) -+{ -+ yaffs_deinit_raw_tnodes_and_objs(dev); -+ dev->n_obj = 0; -+ dev->n_tnodes = 0; -+} -+ -+void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn, -+ unsigned pos, unsigned val) -+{ -+ u32 *map = (u32 *) tn; -+ u32 bit_in_map; -+ u32 bit_in_word; -+ u32 word_in_map; -+ u32 mask; -+ -+ pos &= YAFFS_TNODES_LEVEL0_MASK; -+ val >>= dev->chunk_grp_bits; -+ -+ bit_in_map = pos * dev->tnode_width; -+ word_in_map = bit_in_map / 32; -+ bit_in_word = bit_in_map & (32 - 1); -+ -+ mask = dev->tnode_mask << bit_in_word; -+ -+ map[word_in_map] &= ~mask; -+ map[word_in_map] |= (mask & (val << bit_in_word)); -+ -+ if (dev->tnode_width > (32 - bit_in_word)) { -+ bit_in_word = (32 - bit_in_word); -+ word_in_map++;; -+ mask = -+ dev->tnode_mask >> ( /*dev->tnode_width - */ bit_in_word); -+ map[word_in_map] &= ~mask; -+ map[word_in_map] |= (mask & (val >> bit_in_word)); -+ } -+} -+ -+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, -+ unsigned pos) -+{ -+ u32 *map = (u32 *) tn; -+ u32 bit_in_map; -+ u32 bit_in_word; -+ u32 word_in_map; -+ u32 val; -+ -+ pos &= YAFFS_TNODES_LEVEL0_MASK; -+ -+ bit_in_map = pos * dev->tnode_width; -+ word_in_map = bit_in_map / 32; -+ bit_in_word = bit_in_map & (32 - 1); -+ -+ val = map[word_in_map] >> bit_in_word; -+ -+ if (dev->tnode_width > (32 - bit_in_word)) { -+ bit_in_word = (32 - bit_in_word); -+ word_in_map++;; -+ val |= (map[word_in_map] << bit_in_word); -+ } -+ -+ val &= dev->tnode_mask; -+ val <<= dev->chunk_grp_bits; -+ -+ return val; -+} -+ -+/* ------------------- End of individual tnode manipulation -----------------*/ -+ -+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ -+ * The look up tree is represented by the top tnode and the number of top_level -+ * in the tree. 0 means only the level 0 tnode is in the tree. -+ */ -+ -+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ -+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, -+ struct yaffs_file_var *file_struct, -+ u32 chunk_id) -+{ -+ struct yaffs_tnode *tn = file_struct->top; -+ u32 i; -+ int required_depth; -+ int level = file_struct->top_level; -+ -+ dev = dev; -+ -+ /* Check sane level and chunk Id */ -+ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) -+ return NULL; -+ -+ if (chunk_id > YAFFS_MAX_CHUNK_ID) -+ return NULL; -+ -+ /* First check we're tall enough (ie enough top_level) */ -+ -+ i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; -+ required_depth = 0; -+ while (i) { -+ i >>= YAFFS_TNODES_INTERNAL_BITS; -+ required_depth++; -+ } -+ -+ if (required_depth > file_struct->top_level) -+ return NULL; /* Not tall enough, so we can't find it */ -+ -+ /* Traverse down to level 0 */ -+ while (level > 0 && tn) { -+ tn = tn->internal[(chunk_id >> -+ (YAFFS_TNODES_LEVEL0_BITS + -+ (level - 1) * -+ YAFFS_TNODES_INTERNAL_BITS)) & -+ YAFFS_TNODES_INTERNAL_MASK]; -+ level--; -+ } -+ -+ return tn; -+} -+ -+/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. -+ * This happens in two steps: -+ * 1. If the tree isn't tall enough, then make it taller. -+ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. -+ * -+ * Used when modifying the tree. -+ * -+ * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will -+ * be plugged into the ttree. -+ */ -+ -+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, -+ struct yaffs_file_var *file_struct, -+ u32 chunk_id, -+ struct yaffs_tnode *passed_tn) -+{ -+ int required_depth; -+ int i; -+ int l; -+ struct yaffs_tnode *tn; -+ -+ u32 x; -+ -+ /* Check sane level and page Id */ -+ if (file_struct->top_level < 0 -+ || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL) -+ return NULL; -+ -+ if (chunk_id > YAFFS_MAX_CHUNK_ID) -+ return NULL; -+ -+ /* First check we're tall enough (ie enough top_level) */ -+ -+ x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; -+ required_depth = 0; -+ while (x) { -+ x >>= YAFFS_TNODES_INTERNAL_BITS; -+ required_depth++; -+ } -+ -+ if (required_depth > file_struct->top_level) { -+ /* Not tall enough, gotta make the tree taller */ -+ for (i = file_struct->top_level; i < required_depth; i++) { -+ -+ tn = yaffs_get_tnode(dev); -+ -+ if (tn) { -+ tn->internal[0] = file_struct->top; -+ file_struct->top = tn; -+ file_struct->top_level++; -+ } else { -+ yaffs_trace(YAFFS_TRACE_ERROR, "yaffs: no more tnodes"); -+ return NULL; -+ } -+ } -+ } -+ -+ /* Traverse down to level 0, adding anything we need */ -+ -+ l = file_struct->top_level; -+ tn = file_struct->top; -+ -+ if (l > 0) { -+ while (l > 0 && tn) { -+ x = (chunk_id >> -+ (YAFFS_TNODES_LEVEL0_BITS + -+ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & -+ YAFFS_TNODES_INTERNAL_MASK; -+ -+ if ((l > 1) && !tn->internal[x]) { -+ /* Add missing non-level-zero tnode */ -+ tn->internal[x] = yaffs_get_tnode(dev); -+ if (!tn->internal[x]) -+ return NULL; -+ } else if (l == 1) { -+ /* Looking from level 1 at level 0 */ -+ if (passed_tn) { -+ /* If we already have one, then release it. */ -+ if (tn->internal[x]) -+ yaffs_free_tnode(dev, -+ tn-> -+ internal[x]); -+ tn->internal[x] = passed_tn; -+ -+ } else if (!tn->internal[x]) { -+ /* Don't have one, none passed in */ -+ tn->internal[x] = yaffs_get_tnode(dev); -+ if (!tn->internal[x]) -+ return NULL; -+ } -+ } -+ -+ tn = tn->internal[x]; -+ l--; -+ } -+ } else { -+ /* top is level 0 */ -+ if (passed_tn) { -+ memcpy(tn, passed_tn, -+ (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8); -+ yaffs_free_tnode(dev, passed_tn); -+ } -+ } -+ -+ return tn; -+} -+ -+static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id, -+ int chunk_obj) -+{ -+ return (tags->chunk_id == chunk_obj && -+ tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0; -+ -+} -+ -+static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, -+ struct yaffs_ext_tags *tags, int obj_id, -+ int inode_chunk) -+{ -+ int j; -+ -+ for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) { -+ if (yaffs_check_chunk_bit -+ (dev, the_chunk / dev->param.chunks_per_block, -+ the_chunk % dev->param.chunks_per_block)) { -+ -+ if (dev->chunk_grp_size == 1) -+ return the_chunk; -+ else { -+ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, -+ tags); -+ if (yaffs_tags_match(tags, obj_id, inode_chunk)) { -+ /* found it; */ -+ return the_chunk; -+ } -+ } -+ } -+ the_chunk++; -+ } -+ return -1; -+} -+ -+static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, -+ struct yaffs_ext_tags *tags) -+{ -+ /*Get the Tnode, then get the level 0 offset chunk offset */ -+ struct yaffs_tnode *tn; -+ int the_chunk = -1; -+ struct yaffs_ext_tags local_tags; -+ int ret_val = -1; -+ -+ struct yaffs_dev *dev = in->my_dev; -+ -+ if (!tags) { -+ /* Passed a NULL, so use our own tags space */ -+ tags = &local_tags; -+ } -+ -+ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); -+ -+ if (tn) { -+ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); -+ -+ ret_val = -+ yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, -+ inode_chunk); -+ } -+ return ret_val; -+} -+ -+static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk, -+ struct yaffs_ext_tags *tags) -+{ -+ /* Get the Tnode, then get the level 0 offset chunk offset */ -+ struct yaffs_tnode *tn; -+ int the_chunk = -1; -+ struct yaffs_ext_tags local_tags; -+ -+ struct yaffs_dev *dev = in->my_dev; -+ int ret_val = -1; -+ -+ if (!tags) { -+ /* Passed a NULL, so use our own tags space */ -+ tags = &local_tags; -+ } -+ -+ tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); -+ -+ if (tn) { -+ -+ the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); -+ -+ ret_val = -+ yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, -+ inode_chunk); -+ -+ /* Delete the entry in the filestructure (if found) */ -+ if (ret_val != -1) -+ yaffs_load_tnode_0(dev, tn, inode_chunk, 0); -+ } -+ -+ return ret_val; -+} -+ -+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, -+ int nand_chunk, int in_scan) -+{ -+ /* NB in_scan is zero unless scanning. -+ * For forward scanning, in_scan is > 0; -+ * for backward scanning in_scan is < 0 -+ * -+ * nand_chunk = 0 is a dummy insert to make sure the tnodes are there. -+ */ -+ -+ struct yaffs_tnode *tn; -+ struct yaffs_dev *dev = in->my_dev; -+ int existing_cunk; -+ struct yaffs_ext_tags existing_tags; -+ struct yaffs_ext_tags new_tags; -+ unsigned existing_serial, new_serial; -+ -+ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) { -+ /* Just ignore an attempt at putting a chunk into a non-file during scanning -+ * If it is not during Scanning then something went wrong! -+ */ -+ if (!in_scan) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy:attempt to put data chunk into a non-file" -+ ); -+ YBUG(); -+ } -+ -+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); -+ return YAFFS_OK; -+ } -+ -+ tn = yaffs_add_find_tnode_0(dev, -+ &in->variant.file_variant, -+ inode_chunk, NULL); -+ if (!tn) -+ return YAFFS_FAIL; -+ -+ if (!nand_chunk) -+ /* Dummy insert, bail now */ -+ return YAFFS_OK; -+ -+ existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk); -+ -+ if (in_scan != 0) { -+ /* If we're scanning then we need to test for duplicates -+ * NB This does not need to be efficient since it should only ever -+ * happen when the power fails during a write, then only one -+ * chunk should ever be affected. -+ * -+ * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO -+ * Update: For backward scanning we don't need to re-read tags so this is quite cheap. -+ */ -+ -+ if (existing_cunk > 0) { -+ /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1 -+ * thus we have to do a FindChunkInFile to get the real chunk id. -+ * -+ * We have a duplicate now we need to decide which one to use: -+ * -+ * Backwards scanning YAFFS2: The old one is what we use, dump the new one. -+ * Forward scanning YAFFS2: The new one is what we use, dump the old one. -+ * YAFFS1: Get both sets of tags and compare serial numbers. -+ */ -+ -+ if (in_scan > 0) { -+ /* Only do this for forward scanning */ -+ yaffs_rd_chunk_tags_nand(dev, -+ nand_chunk, -+ NULL, &new_tags); -+ -+ /* Do a proper find */ -+ existing_cunk = -+ yaffs_find_chunk_in_file(in, inode_chunk, -+ &existing_tags); -+ } -+ -+ if (existing_cunk <= 0) { -+ /*Hoosterman - how did this happen? */ -+ -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy: existing chunk < 0 in scan" -+ ); -+ -+ } -+ -+ /* NB The deleted flags should be false, otherwise the chunks will -+ * not be loaded during a scan -+ */ -+ -+ if (in_scan > 0) { -+ new_serial = new_tags.serial_number; -+ existing_serial = existing_tags.serial_number; -+ } -+ -+ if ((in_scan > 0) && -+ (existing_cunk <= 0 || -+ ((existing_serial + 1) & 3) == new_serial)) { -+ /* Forward scanning. -+ * Use new -+ * Delete the old one and drop through to update the tnode -+ */ -+ yaffs_chunk_del(dev, existing_cunk, 1, -+ __LINE__); -+ } else { -+ /* Backward scanning or we want to use the existing one -+ * Use existing. -+ * Delete the new one and return early so that the tnode isn't changed -+ */ -+ yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); -+ return YAFFS_OK; -+ } -+ } -+ -+ } -+ -+ if (existing_cunk == 0) -+ in->n_data_chunks++; -+ -+ yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk); -+ -+ return YAFFS_OK; -+} -+ -+static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk) -+{ -+ struct yaffs_block_info *the_block; -+ unsigned block_no; -+ -+ yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk); -+ -+ block_no = chunk / dev->param.chunks_per_block; -+ the_block = yaffs_get_block_info(dev, block_no); -+ if (the_block) { -+ the_block->soft_del_pages++; -+ dev->n_free_chunks++; -+ yaffs2_update_oldest_dirty_seq(dev, block_no, the_block); -+ } -+} -+ -+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. -+ * All soft deleting does is increment the block's softdelete count and pulls the chunk out -+ * of the tnode. -+ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. -+ */ -+ -+static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn, -+ u32 level, int chunk_offset) -+{ -+ int i; -+ int the_chunk; -+ int all_done = 1; -+ struct yaffs_dev *dev = in->my_dev; -+ -+ if (tn) { -+ if (level > 0) { -+ -+ for (i = YAFFS_NTNODES_INTERNAL - 1; all_done && i >= 0; -+ i--) { -+ if (tn->internal[i]) { -+ all_done = -+ yaffs_soft_del_worker(in, -+ tn->internal -+ [i], -+ level - 1, -+ (chunk_offset -+ << -+ YAFFS_TNODES_INTERNAL_BITS) -+ + i); -+ if (all_done) { -+ yaffs_free_tnode(dev, -+ tn->internal -+ [i]); -+ tn->internal[i] = NULL; -+ } else { -+ /* Hoosterman... how could this happen? */ -+ } -+ } -+ } -+ return (all_done) ? 1 : 0; -+ } else if (level == 0) { -+ -+ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { -+ the_chunk = yaffs_get_group_base(dev, tn, i); -+ if (the_chunk) { -+ /* Note this does not find the real chunk, only the chunk group. -+ * We make an assumption that a chunk group is not larger than -+ * a block. -+ */ -+ yaffs_soft_del_chunk(dev, the_chunk); -+ yaffs_load_tnode_0(dev, tn, i, 0); -+ } -+ -+ } -+ return 1; -+ -+ } -+ -+ } -+ -+ return 1; -+ -+} -+ -+static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj) -+{ -+ struct yaffs_dev *dev = obj->my_dev; -+ struct yaffs_obj *parent; -+ -+ yaffs_verify_obj_in_dir(obj); -+ parent = obj->parent; -+ -+ yaffs_verify_dir(parent); -+ -+ if (dev && dev->param.remove_obj_fn) -+ dev->param.remove_obj_fn(obj); -+ -+ list_del_init(&obj->siblings); -+ obj->parent = NULL; -+ -+ yaffs_verify_dir(parent); -+} -+ -+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj) -+{ -+ if (!directory) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "tragedy: Trying to add an object to a null pointer directory" -+ ); -+ YBUG(); -+ return; -+ } -+ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "tragedy: Trying to add an object to a non-directory" -+ ); -+ YBUG(); -+ } -+ -+ if (obj->siblings.prev == NULL) { -+ /* Not initialised */ -+ YBUG(); -+ } -+ -+ yaffs_verify_dir(directory); -+ -+ yaffs_remove_obj_from_dir(obj); -+ -+ /* Now add it */ -+ list_add(&obj->siblings, &directory->variant.dir_variant.children); -+ obj->parent = directory; -+ -+ if (directory == obj->my_dev->unlinked_dir -+ || directory == obj->my_dev->del_dir) { -+ obj->unlinked = 1; -+ obj->my_dev->n_unlinked_files++; -+ obj->rename_allowed = 0; -+ } -+ -+ yaffs_verify_dir(directory); -+ yaffs_verify_obj_in_dir(obj); -+} -+ -+static int yaffs_change_obj_name(struct yaffs_obj *obj, -+ struct yaffs_obj *new_dir, -+ const YCHAR * new_name, int force, int shadows) -+{ -+ int unlink_op; -+ int del_op; -+ -+ struct yaffs_obj *existing_target; -+ -+ if (new_dir == NULL) -+ new_dir = obj->parent; /* use the old directory */ -+ -+ if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "tragedy: yaffs_change_obj_name: new_dir is not a directory" -+ ); -+ YBUG(); -+ } -+ -+ /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ -+ if (obj->my_dev->param.is_yaffs2) -+ unlink_op = (new_dir == obj->my_dev->unlinked_dir); -+ else -+ unlink_op = (new_dir == obj->my_dev->unlinked_dir -+ && obj->variant_type == YAFFS_OBJECT_TYPE_FILE); -+ -+ del_op = (new_dir == obj->my_dev->del_dir); -+ -+ existing_target = yaffs_find_by_name(new_dir, new_name); -+ -+ /* If the object is a file going into the unlinked directory, -+ * then it is OK to just stuff it in since duplicate names are allowed. -+ * else only proceed if the new name does not exist and if we're putting -+ * it into a directory. -+ */ -+ if ((unlink_op || -+ del_op || -+ force || -+ (shadows > 0) || -+ !existing_target) && -+ new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_set_obj_name(obj, new_name); -+ obj->dirty = 1; -+ -+ yaffs_add_obj_to_dir(new_dir, obj); -+ -+ if (unlink_op) -+ obj->unlinked = 1; -+ -+ /* If it is a deletion then we mark it as a shrink for gc purposes. */ -+ if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= -+ 0) -+ return YAFFS_OK; -+ } -+ -+ return YAFFS_FAIL; -+} -+ -+/*------------------------ Short Operations Cache ---------------------------------------- -+ * In many situations where there is no high level buffering a lot of -+ * reads might be short sequential reads, and a lot of writes may be short -+ * sequential writes. eg. scanning/writing a jpeg file. -+ * In these cases, a short read/write cache can provide a huge perfomance -+ * benefit with dumb-as-a-rock code. -+ * In Linux, the page cache provides read buffering and the short op cache -+ * provides write buffering. -+ * -+ * There are a limited number (~10) of cache chunks per device so that we don't -+ * need a very intelligent search. -+ */ -+ -+static int yaffs_obj_cache_dirty(struct yaffs_obj *obj) -+{ -+ struct yaffs_dev *dev = obj->my_dev; -+ int i; -+ struct yaffs_cache *cache; -+ int n_caches = obj->my_dev->param.n_caches; -+ -+ for (i = 0; i < n_caches; i++) { -+ cache = &dev->cache[i]; -+ if (cache->object == obj && cache->dirty) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static void yaffs_flush_file_cache(struct yaffs_obj *obj) -+{ -+ struct yaffs_dev *dev = obj->my_dev; -+ int lowest = -99; /* Stop compiler whining. */ -+ int i; -+ struct yaffs_cache *cache; -+ int chunk_written = 0; -+ int n_caches = obj->my_dev->param.n_caches; -+ -+ if (n_caches > 0) { -+ do { -+ cache = NULL; -+ -+ /* Find the dirty cache for this object with the lowest chunk id. */ -+ for (i = 0; i < n_caches; i++) { -+ if (dev->cache[i].object == obj && -+ dev->cache[i].dirty) { -+ if (!cache -+ || dev->cache[i].chunk_id < -+ lowest) { -+ cache = &dev->cache[i]; -+ lowest = cache->chunk_id; -+ } -+ } -+ } -+ -+ if (cache && !cache->locked) { -+ /* Write it out and free it up */ -+ -+ chunk_written = -+ yaffs_wr_data_obj(cache->object, -+ cache->chunk_id, -+ cache->data, -+ cache->n_bytes, 1); -+ cache->dirty = 0; -+ cache->object = NULL; -+ } -+ -+ } while (cache && chunk_written > 0); -+ -+ if (cache) -+ /* Hoosterman, disk full while writing cache out. */ -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy: no space during cache write"); -+ -+ } -+ -+} -+ -+/*yaffs_flush_whole_cache(dev) -+ * -+ * -+ */ -+ -+void yaffs_flush_whole_cache(struct yaffs_dev *dev) -+{ -+ struct yaffs_obj *obj; -+ int n_caches = dev->param.n_caches; -+ int i; -+ -+ /* Find a dirty object in the cache and flush it... -+ * until there are no further dirty objects. -+ */ -+ do { -+ obj = NULL; -+ for (i = 0; i < n_caches && !obj; i++) { -+ if (dev->cache[i].object && dev->cache[i].dirty) -+ obj = dev->cache[i].object; -+ -+ } -+ if (obj) -+ yaffs_flush_file_cache(obj); -+ -+ } while (obj); -+ -+} -+ -+/* Grab us a cache chunk for use. -+ * First look for an empty one. -+ * Then look for the least recently used non-dirty one. -+ * Then look for the least recently used dirty one...., flush and look again. -+ */ -+static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev) -+{ -+ int i; -+ -+ if (dev->param.n_caches > 0) { -+ for (i = 0; i < dev->param.n_caches; i++) { -+ if (!dev->cache[i].object) -+ return &dev->cache[i]; -+ } -+ } -+ -+ return NULL; -+} -+ -+static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev) -+{ -+ struct yaffs_cache *cache; -+ struct yaffs_obj *the_obj; -+ int usage; -+ int i; -+ int pushout; -+ -+ if (dev->param.n_caches > 0) { -+ /* Try find a non-dirty one... */ -+ -+ cache = yaffs_grab_chunk_worker(dev); -+ -+ if (!cache) { -+ /* They were all dirty, find the last recently used object and flush -+ * its cache, then find again. -+ * NB what's here is not very accurate, we actually flush the object -+ * the last recently used page. -+ */ -+ -+ /* With locking we can't assume we can use entry zero */ -+ -+ the_obj = NULL; -+ usage = -1; -+ cache = NULL; -+ pushout = -1; -+ -+ for (i = 0; i < dev->param.n_caches; i++) { -+ if (dev->cache[i].object && -+ !dev->cache[i].locked && -+ (dev->cache[i].last_use < usage -+ || !cache)) { -+ usage = dev->cache[i].last_use; -+ the_obj = dev->cache[i].object; -+ cache = &dev->cache[i]; -+ pushout = i; -+ } -+ } -+ -+ if (!cache || cache->dirty) { -+ /* Flush and try again */ -+ yaffs_flush_file_cache(the_obj); -+ cache = yaffs_grab_chunk_worker(dev); -+ } -+ -+ } -+ return cache; -+ } else { -+ return NULL; -+ } -+} -+ -+/* Find a cached chunk */ -+static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj, -+ int chunk_id) -+{ -+ struct yaffs_dev *dev = obj->my_dev; -+ int i; -+ if (dev->param.n_caches > 0) { -+ for (i = 0; i < dev->param.n_caches; i++) { -+ if (dev->cache[i].object == obj && -+ dev->cache[i].chunk_id == chunk_id) { -+ dev->cache_hits++; -+ -+ return &dev->cache[i]; -+ } -+ } -+ } -+ return NULL; -+} -+ -+/* Mark the chunk for the least recently used algorithym */ -+static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache, -+ int is_write) -+{ -+ -+ if (dev->param.n_caches > 0) { -+ if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) { -+ /* Reset the cache usages */ -+ int i; -+ for (i = 1; i < dev->param.n_caches; i++) -+ dev->cache[i].last_use = 0; -+ -+ dev->cache_last_use = 0; -+ } -+ -+ dev->cache_last_use++; -+ -+ cache->last_use = dev->cache_last_use; -+ -+ if (is_write) -+ cache->dirty = 1; -+ } -+} -+ -+/* Invalidate a single cache page. -+ * Do this when a whole page gets written, -+ * ie the short cache for this page is no longer valid. -+ */ -+static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id) -+{ -+ if (object->my_dev->param.n_caches > 0) { -+ struct yaffs_cache *cache = -+ yaffs_find_chunk_cache(object, chunk_id); -+ -+ if (cache) -+ cache->object = NULL; -+ } -+} -+ -+/* Invalidate all the cache pages associated with this object -+ * Do this whenever ther file is deleted or resized. -+ */ -+static void yaffs_invalidate_whole_cache(struct yaffs_obj *in) -+{ -+ int i; -+ struct yaffs_dev *dev = in->my_dev; -+ -+ if (dev->param.n_caches > 0) { -+ /* Invalidate it. */ -+ for (i = 0; i < dev->param.n_caches; i++) { -+ if (dev->cache[i].object == in) -+ dev->cache[i].object = NULL; -+ } -+ } -+} -+ -+static void yaffs_unhash_obj(struct yaffs_obj *obj) -+{ -+ int bucket; -+ struct yaffs_dev *dev = obj->my_dev; -+ -+ /* If it is still linked into the bucket list, free from the list */ -+ if (!list_empty(&obj->hash_link)) { -+ list_del_init(&obj->hash_link); -+ bucket = yaffs_hash_fn(obj->obj_id); -+ dev->obj_bucket[bucket].count--; -+ } -+} -+ -+/* FreeObject frees up a Object and puts it back on the free list */ -+static void yaffs_free_obj(struct yaffs_obj *obj) -+{ -+ struct yaffs_dev *dev = obj->my_dev; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p", -+ obj, obj->my_inode); -+ -+ if (!obj) -+ YBUG(); -+ if (obj->parent) -+ YBUG(); -+ if (!list_empty(&obj->siblings)) -+ YBUG(); -+ -+ if (obj->my_inode) { -+ /* We're still hooked up to a cached inode. -+ * Don't delete now, but mark for later deletion -+ */ -+ obj->defered_free = 1; -+ return; -+ } -+ -+ yaffs_unhash_obj(obj); -+ -+ yaffs_free_raw_obj(dev, obj); -+ dev->n_obj--; -+ dev->checkpoint_blocks_required = 0; /* force recalculation */ -+} -+ -+void yaffs_handle_defered_free(struct yaffs_obj *obj) -+{ -+ if (obj->defered_free) -+ yaffs_free_obj(obj); -+} -+ -+static int yaffs_generic_obj_del(struct yaffs_obj *in) -+{ -+ -+ /* First off, invalidate the file's data in the cache, without flushing. */ -+ yaffs_invalidate_whole_cache(in); -+ -+ if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) { -+ /* Move to the unlinked directory so we have a record that it was deleted. */ -+ yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, -+ 0); -+ -+ } -+ -+ yaffs_remove_obj_from_dir(in); -+ yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__); -+ in->hdr_chunk = 0; -+ -+ yaffs_free_obj(in); -+ return YAFFS_OK; -+ -+} -+ -+static void yaffs_soft_del_file(struct yaffs_obj *obj) -+{ -+ if (obj->deleted && -+ obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) { -+ if (obj->n_data_chunks <= 0) { -+ /* Empty file with no duplicate object headers, -+ * just delete it immediately */ -+ yaffs_free_tnode(obj->my_dev, -+ obj->variant.file_variant.top); -+ obj->variant.file_variant.top = NULL; -+ yaffs_trace(YAFFS_TRACE_TRACING, -+ "yaffs: Deleting empty file %d", -+ obj->obj_id); -+ yaffs_generic_obj_del(obj); -+ } else { -+ yaffs_soft_del_worker(obj, -+ obj->variant.file_variant.top, -+ obj->variant. -+ file_variant.top_level, 0); -+ obj->soft_del = 1; -+ } -+ } -+} -+ -+/* Pruning removes any part of the file structure tree that is beyond the -+ * bounds of the file (ie that does not point to chunks). -+ * -+ * A file should only get pruned when its size is reduced. -+ * -+ * Before pruning, the chunks must be pulled from the tree and the -+ * level 0 tnode entries must be zeroed out. -+ * Could also use this for file deletion, but that's probably better handled -+ * by a special case. -+ * -+ * This function is recursive. For levels > 0 the function is called again on -+ * any sub-tree. For level == 0 we just check if the sub-tree has data. -+ * If there is no data in a subtree then it is pruned. -+ */ -+ -+static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev, -+ struct yaffs_tnode *tn, u32 level, -+ int del0) -+{ -+ int i; -+ int has_data; -+ -+ if (tn) { -+ has_data = 0; -+ -+ if (level > 0) { -+ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { -+ if (tn->internal[i]) { -+ tn->internal[i] = -+ yaffs_prune_worker(dev, -+ tn->internal[i], -+ level - 1, -+ (i == -+ 0) ? del0 : 1); -+ } -+ -+ if (tn->internal[i]) -+ has_data++; -+ } -+ } else { -+ int tnode_size_u32 = dev->tnode_size / sizeof(u32); -+ u32 *map = (u32 *) tn; -+ -+ for (i = 0; !has_data && i < tnode_size_u32; i++) { -+ if (map[i]) -+ has_data++; -+ } -+ } -+ -+ if (has_data == 0 && del0) { -+ /* Free and return NULL */ -+ -+ yaffs_free_tnode(dev, tn); -+ tn = NULL; -+ } -+ -+ } -+ -+ return tn; -+ -+} -+ -+static int yaffs_prune_tree(struct yaffs_dev *dev, -+ struct yaffs_file_var *file_struct) -+{ -+ int i; -+ int has_data; -+ int done = 0; -+ struct yaffs_tnode *tn; -+ -+ if (file_struct->top_level > 0) { -+ file_struct->top = -+ yaffs_prune_worker(dev, file_struct->top, -+ file_struct->top_level, 0); -+ -+ /* Now we have a tree with all the non-zero branches NULL but the height -+ * is the same as it was. -+ * Let's see if we can trim internal tnodes to shorten the tree. -+ * We can do this if only the 0th element in the tnode is in use -+ * (ie all the non-zero are NULL) -+ */ -+ -+ while (file_struct->top_level && !done) { -+ tn = file_struct->top; -+ -+ has_data = 0; -+ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { -+ if (tn->internal[i]) -+ has_data++; -+ } -+ -+ if (!has_data) { -+ file_struct->top = tn->internal[0]; -+ file_struct->top_level--; -+ yaffs_free_tnode(dev, tn); -+ } else { -+ done = 1; -+ } -+ } -+ } -+ -+ return YAFFS_OK; -+} -+ -+/*-------------------- End of File Structure functions.-------------------*/ -+ -+/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ -+static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev) -+{ -+ struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev); -+ -+ if (obj) { -+ dev->n_obj++; -+ -+ /* Now sweeten it up... */ -+ -+ memset(obj, 0, sizeof(struct yaffs_obj)); -+ obj->being_created = 1; -+ -+ obj->my_dev = dev; -+ obj->hdr_chunk = 0; -+ obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN; -+ INIT_LIST_HEAD(&(obj->hard_links)); -+ INIT_LIST_HEAD(&(obj->hash_link)); -+ INIT_LIST_HEAD(&obj->siblings); -+ -+ /* Now make the directory sane */ -+ if (dev->root_dir) { -+ obj->parent = dev->root_dir; -+ list_add(&(obj->siblings), -+ &dev->root_dir->variant.dir_variant.children); -+ } -+ -+ /* Add it to the lost and found directory. -+ * NB Can't put root or lost-n-found in lost-n-found so -+ * check if lost-n-found exists first -+ */ -+ if (dev->lost_n_found) -+ yaffs_add_obj_to_dir(dev->lost_n_found, obj); -+ -+ obj->being_created = 0; -+ } -+ -+ dev->checkpoint_blocks_required = 0; /* force recalculation */ -+ -+ return obj; -+} -+ -+static int yaffs_find_nice_bucket(struct yaffs_dev *dev) -+{ -+ int i; -+ int l = 999; -+ int lowest = 999999; -+ -+ /* Search for the shortest list or one that -+ * isn't too long. -+ */ -+ -+ for (i = 0; i < 10 && lowest > 4; i++) { -+ dev->bucket_finder++; -+ dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS; -+ if (dev->obj_bucket[dev->bucket_finder].count < lowest) { -+ lowest = dev->obj_bucket[dev->bucket_finder].count; -+ l = dev->bucket_finder; -+ } -+ -+ } -+ -+ return l; -+} -+ -+static int yaffs_new_obj_id(struct yaffs_dev *dev) -+{ -+ int bucket = yaffs_find_nice_bucket(dev); -+ -+ /* Now find an object value that has not already been taken -+ * by scanning the list. -+ */ -+ -+ int found = 0; -+ struct list_head *i; -+ -+ u32 n = (u32) bucket; -+ -+ /* yaffs_check_obj_hash_sane(); */ -+ -+ while (!found) { -+ found = 1; -+ n += YAFFS_NOBJECT_BUCKETS; -+ if (1 || dev->obj_bucket[bucket].count > 0) { -+ list_for_each(i, &dev->obj_bucket[bucket].list) { -+ /* If there is already one in the list */ -+ if (i && list_entry(i, struct yaffs_obj, -+ hash_link)->obj_id == n) { -+ found = 0; -+ } -+ } -+ } -+ } -+ -+ return n; -+} -+ -+static void yaffs_hash_obj(struct yaffs_obj *in) -+{ -+ int bucket = yaffs_hash_fn(in->obj_id); -+ struct yaffs_dev *dev = in->my_dev; -+ -+ list_add(&in->hash_link, &dev->obj_bucket[bucket].list); -+ dev->obj_bucket[bucket].count++; -+} -+ -+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number) -+{ -+ int bucket = yaffs_hash_fn(number); -+ struct list_head *i; -+ struct yaffs_obj *in; -+ -+ list_for_each(i, &dev->obj_bucket[bucket].list) { -+ /* Look if it is in the list */ -+ if (i) { -+ in = list_entry(i, struct yaffs_obj, hash_link); -+ if (in->obj_id == number) { -+ -+ /* Don't tell the VFS about this one if it is defered free */ -+ if (in->defered_free) -+ return NULL; -+ -+ return in; -+ } -+ } -+ } -+ -+ return NULL; -+} -+ -+struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number, -+ enum yaffs_obj_type type) -+{ -+ struct yaffs_obj *the_obj = NULL; -+ struct yaffs_tnode *tn = NULL; -+ -+ if (number < 0) -+ number = yaffs_new_obj_id(dev); -+ -+ if (type == YAFFS_OBJECT_TYPE_FILE) { -+ tn = yaffs_get_tnode(dev); -+ if (!tn) -+ return NULL; -+ } -+ -+ the_obj = yaffs_alloc_empty_obj(dev); -+ if (!the_obj) { -+ if (tn) -+ yaffs_free_tnode(dev, tn); -+ return NULL; -+ } -+ -+ if (the_obj) { -+ the_obj->fake = 0; -+ the_obj->rename_allowed = 1; -+ the_obj->unlink_allowed = 1; -+ the_obj->obj_id = number; -+ yaffs_hash_obj(the_obj); -+ the_obj->variant_type = type; -+ yaffs_load_current_time(the_obj, 1, 1); -+ -+ switch (type) { -+ case YAFFS_OBJECT_TYPE_FILE: -+ the_obj->variant.file_variant.file_size = 0; -+ the_obj->variant.file_variant.scanned_size = 0; -+ the_obj->variant.file_variant.shrink_size = ~0; /* max */ -+ the_obj->variant.file_variant.top_level = 0; -+ the_obj->variant.file_variant.top = tn; -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ INIT_LIST_HEAD(&the_obj->variant.dir_variant.children); -+ INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty); -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ /* No action required */ -+ break; -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ /* todo this should not happen */ -+ break; -+ } -+ } -+ -+ return the_obj; -+} -+ -+static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev, -+ int number, u32 mode) -+{ -+ -+ struct yaffs_obj *obj = -+ yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); -+ if (obj) { -+ obj->fake = 1; /* it is fake so it might have no NAND presence... */ -+ obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */ -+ obj->unlink_allowed = 0; /* ... or unlink it */ -+ obj->deleted = 0; -+ obj->unlinked = 0; -+ obj->yst_mode = mode; -+ obj->my_dev = dev; -+ obj->hdr_chunk = 0; /* Not a valid chunk. */ -+ } -+ -+ return obj; -+ -+} -+ -+ -+static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev) -+{ -+ int i; -+ -+ dev->n_obj = 0; -+ dev->n_tnodes = 0; -+ -+ yaffs_init_raw_tnodes_and_objs(dev); -+ -+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { -+ INIT_LIST_HEAD(&dev->obj_bucket[i].list); -+ dev->obj_bucket[i].count = 0; -+ } -+} -+ -+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, -+ int number, -+ enum yaffs_obj_type type) -+{ -+ struct yaffs_obj *the_obj = NULL; -+ -+ if (number > 0) -+ the_obj = yaffs_find_by_number(dev, number); -+ -+ if (!the_obj) -+ the_obj = yaffs_new_obj(dev, number, type); -+ -+ return the_obj; -+ -+} -+ -+YCHAR *yaffs_clone_str(const YCHAR * str) -+{ -+ YCHAR *new_str = NULL; -+ int len; -+ -+ if (!str) -+ str = _Y(""); -+ -+ len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH); -+ new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS); -+ if (new_str) { -+ strncpy(new_str, str, len); -+ new_str[len] = 0; -+ } -+ return new_str; -+ -+} -+/* -+ *yaffs_update_parent() handles fixing a directories mtime and ctime when a new -+ * link (ie. name) is created or deleted in the directory. -+ * -+ * ie. -+ * create dir/a : update dir's mtime/ctime -+ * rm dir/a: update dir's mtime/ctime -+ * modify dir/a: don't update dir's mtimme/ctime -+ * -+ * This can be handled immediately or defered. Defering helps reduce the number -+ * of updates when many files in a directory are changed within a brief period. -+ * -+ * If the directory updating is defered then yaffs_update_dirty_dirs must be -+ * called periodically. -+ */ -+ -+static void yaffs_update_parent(struct yaffs_obj *obj) -+{ -+ struct yaffs_dev *dev; -+ if (!obj) -+ return; -+ dev = obj->my_dev; -+ obj->dirty = 1; -+ yaffs_load_current_time(obj, 0, 1); -+ if (dev->param.defered_dir_update) { -+ struct list_head *link = &obj->variant.dir_variant.dirty; -+ -+ if (list_empty(link)) { -+ list_add(link, &dev->dirty_dirs); -+ yaffs_trace(YAFFS_TRACE_BACKGROUND, -+ "Added object %d to dirty directories", -+ obj->obj_id); -+ } -+ -+ } else { -+ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); -+ } -+} -+ -+void yaffs_update_dirty_dirs(struct yaffs_dev *dev) -+{ -+ struct list_head *link; -+ struct yaffs_obj *obj; -+ struct yaffs_dir_var *d_s; -+ union yaffs_obj_var *o_v; -+ -+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories"); -+ -+ while (!list_empty(&dev->dirty_dirs)) { -+ link = dev->dirty_dirs.next; -+ list_del_init(link); -+ -+ d_s = list_entry(link, struct yaffs_dir_var, dirty); -+ o_v = list_entry(d_s, union yaffs_obj_var, dir_variant); -+ obj = list_entry(o_v, struct yaffs_obj, variant); -+ -+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d", -+ obj->obj_id); -+ -+ if (obj->dirty) -+ yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); -+ } -+} -+ -+/* -+ * Mknod (create) a new object. -+ * equiv_obj only has meaning for a hard link; -+ * alias_str only has meaning for a symlink. -+ * rdev only has meaning for devices (a subset of special objects) -+ */ -+ -+static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type, -+ struct yaffs_obj *parent, -+ const YCHAR * name, -+ u32 mode, -+ u32 uid, -+ u32 gid, -+ struct yaffs_obj *equiv_obj, -+ const YCHAR * alias_str, u32 rdev) -+{ -+ struct yaffs_obj *in; -+ YCHAR *str = NULL; -+ -+ struct yaffs_dev *dev = parent->my_dev; -+ -+ /* Check if the entry exists. If it does then fail the call since we don't want a dup. */ -+ if (yaffs_find_by_name(parent, name)) -+ return NULL; -+ -+ if (type == YAFFS_OBJECT_TYPE_SYMLINK) { -+ str = yaffs_clone_str(alias_str); -+ if (!str) -+ return NULL; -+ } -+ -+ in = yaffs_new_obj(dev, -1, type); -+ -+ if (!in) { -+ if (str) -+ kfree(str); -+ return NULL; -+ } -+ -+ if (in) { -+ in->hdr_chunk = 0; -+ in->valid = 1; -+ in->variant_type = type; -+ -+ in->yst_mode = mode; -+ -+ yaffs_attribs_init(in, gid, uid, rdev); -+ -+ in->n_data_chunks = 0; -+ -+ yaffs_set_obj_name(in, name); -+ in->dirty = 1; -+ -+ yaffs_add_obj_to_dir(parent, in); -+ -+ in->my_dev = parent->my_dev; -+ -+ switch (type) { -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ in->variant.symlink_variant.alias = str; -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ in->variant.hardlink_variant.equiv_obj = equiv_obj; -+ in->variant.hardlink_variant.equiv_id = -+ equiv_obj->obj_id; -+ list_add(&in->hard_links, &equiv_obj->hard_links); -+ break; -+ case YAFFS_OBJECT_TYPE_FILE: -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ /* do nothing */ -+ break; -+ } -+ -+ if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) { -+ /* Could not create the object header, fail the creation */ -+ yaffs_del_obj(in); -+ in = NULL; -+ } -+ -+ yaffs_update_parent(parent); -+ } -+ -+ return in; -+} -+ -+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, -+ const YCHAR * name, u32 mode, u32 uid, -+ u32 gid) -+{ -+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, -+ uid, gid, NULL, NULL, 0); -+} -+ -+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR * name, -+ u32 mode, u32 uid, u32 gid) -+{ -+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, -+ mode, uid, gid, NULL, NULL, 0); -+} -+ -+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, -+ const YCHAR * name, u32 mode, u32 uid, -+ u32 gid, u32 rdev) -+{ -+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, -+ uid, gid, NULL, NULL, rdev); -+} -+ -+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, -+ const YCHAR * name, u32 mode, u32 uid, -+ u32 gid, const YCHAR * alias) -+{ -+ return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, -+ uid, gid, NULL, alias, 0); -+} -+ -+/* yaffs_link_obj returns the object id of the equivalent object.*/ -+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name, -+ struct yaffs_obj *equiv_obj) -+{ -+ /* Get the real object in case we were fed a hard link as an equivalent object */ -+ equiv_obj = yaffs_get_equivalent_obj(equiv_obj); -+ -+ if (yaffs_create_obj -+ (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, -+ equiv_obj, NULL, 0)) { -+ return equiv_obj; -+ } else { -+ return NULL; -+ } -+ -+} -+ -+ -+ -+/*------------------------- Block Management and Page Allocation ----------------*/ -+ -+static int yaffs_init_blocks(struct yaffs_dev *dev) -+{ -+ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; -+ -+ dev->block_info = NULL; -+ dev->chunk_bits = NULL; -+ -+ dev->alloc_block = -1; /* force it to get a new one */ -+ -+ /* If the first allocation strategy fails, thry the alternate one */ -+ dev->block_info = -+ kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS); -+ if (!dev->block_info) { -+ dev->block_info = -+ vmalloc(n_blocks * sizeof(struct yaffs_block_info)); -+ dev->block_info_alt = 1; -+ } else { -+ dev->block_info_alt = 0; -+ } -+ -+ if (dev->block_info) { -+ /* Set up dynamic blockinfo stuff. Round up bytes. */ -+ dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; -+ dev->chunk_bits = -+ kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS); -+ if (!dev->chunk_bits) { -+ dev->chunk_bits = -+ vmalloc(dev->chunk_bit_stride * n_blocks); -+ dev->chunk_bits_alt = 1; -+ } else { -+ dev->chunk_bits_alt = 0; -+ } -+ } -+ -+ if (dev->block_info && dev->chunk_bits) { -+ memset(dev->block_info, 0, -+ n_blocks * sizeof(struct yaffs_block_info)); -+ memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks); -+ return YAFFS_OK; -+ } -+ -+ return YAFFS_FAIL; -+} -+ -+static void yaffs_deinit_blocks(struct yaffs_dev *dev) -+{ -+ if (dev->block_info_alt && dev->block_info) -+ vfree(dev->block_info); -+ else if (dev->block_info) -+ kfree(dev->block_info); -+ -+ dev->block_info_alt = 0; -+ -+ dev->block_info = NULL; -+ -+ if (dev->chunk_bits_alt && dev->chunk_bits) -+ vfree(dev->chunk_bits); -+ else if (dev->chunk_bits) -+ kfree(dev->chunk_bits); -+ dev->chunk_bits_alt = 0; -+ dev->chunk_bits = NULL; -+} -+ -+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no) -+{ -+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no); -+ -+ int erased_ok = 0; -+ -+ /* If the block is still healthy erase it and mark as clean. -+ * If the block has had a data failure, then retire it. -+ */ -+ -+ yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, -+ "yaffs_block_became_dirty block %d state %d %s", -+ block_no, bi->block_state, -+ (bi->needs_retiring) ? "needs retiring" : ""); -+ -+ yaffs2_clear_oldest_dirty_seq(dev, bi); -+ -+ bi->block_state = YAFFS_BLOCK_STATE_DIRTY; -+ -+ /* If this is the block being garbage collected then stop gc'ing this block */ -+ if (block_no == dev->gc_block) -+ dev->gc_block = 0; -+ -+ /* If this block is currently the best candidate for gc then drop as a candidate */ -+ if (block_no == dev->gc_dirtiest) { -+ dev->gc_dirtiest = 0; -+ dev->gc_pages_in_use = 0; -+ } -+ -+ if (!bi->needs_retiring) { -+ yaffs2_checkpt_invalidate(dev); -+ erased_ok = yaffs_erase_block(dev, block_no); -+ if (!erased_ok) { -+ dev->n_erase_failures++; -+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, -+ "**>> Erasure failed %d", block_no); -+ } -+ } -+ -+ if (erased_ok && -+ ((yaffs_trace_mask & YAFFS_TRACE_ERASE) -+ || !yaffs_skip_verification(dev))) { -+ int i; -+ for (i = 0; i < dev->param.chunks_per_block; i++) { -+ if (!yaffs_check_chunk_erased -+ (dev, block_no * dev->param.chunks_per_block + i)) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ ">>Block %d erasure supposedly OK, but chunk %d not erased", -+ block_no, i); -+ } -+ } -+ } -+ -+ if (erased_ok) { -+ /* Clean it up... */ -+ bi->block_state = YAFFS_BLOCK_STATE_EMPTY; -+ bi->seq_number = 0; -+ dev->n_erased_blocks++; -+ bi->pages_in_use = 0; -+ bi->soft_del_pages = 0; -+ bi->has_shrink_hdr = 0; -+ bi->skip_erased_check = 1; /* Clean, so no need to check */ -+ bi->gc_prioritise = 0; -+ yaffs_clear_chunk_bits(dev, block_no); -+ -+ yaffs_trace(YAFFS_TRACE_ERASE, -+ "Erased block %d", block_no); -+ } else { -+ /* We lost a block of free space */ -+ dev->n_free_chunks -= dev->param.chunks_per_block; -+ yaffs_retire_block(dev, block_no); -+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, -+ "**>> Block %d retired", block_no); -+ } -+} -+ -+ -+ -+static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block) -+{ -+ int old_chunk; -+ int new_chunk; -+ int mark_flash; -+ int ret_val = YAFFS_OK; -+ int i; -+ int is_checkpt_block; -+ int matching_chunk; -+ int max_copies; -+ -+ int chunks_before = yaffs_get_erased_chunks(dev); -+ int chunks_after; -+ -+ struct yaffs_ext_tags tags; -+ -+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, block); -+ -+ struct yaffs_obj *object; -+ -+ is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT); -+ -+ yaffs_trace(YAFFS_TRACE_TRACING, -+ "Collecting block %d, in use %d, shrink %d, whole_block %d", -+ block, bi->pages_in_use, bi->has_shrink_hdr, -+ whole_block); -+ -+ /*yaffs_verify_free_chunks(dev); */ -+ -+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) -+ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING; -+ -+ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */ -+ -+ dev->gc_disable = 1; -+ -+ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) { -+ yaffs_trace(YAFFS_TRACE_TRACING, -+ "Collecting block %d that has no chunks in use", -+ block); -+ yaffs_block_became_dirty(dev, block); -+ } else { -+ -+ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ yaffs_verify_blk(dev, bi, block); -+ -+ max_copies = (whole_block) ? dev->param.chunks_per_block : 5; -+ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk; -+ -+ for ( /* init already done */ ; -+ ret_val == YAFFS_OK && -+ dev->gc_chunk < dev->param.chunks_per_block && -+ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) && -+ max_copies > 0; dev->gc_chunk++, old_chunk++) { -+ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) { -+ -+ /* This page is in use and might need to be copied off */ -+ -+ max_copies--; -+ -+ mark_flash = 1; -+ -+ yaffs_init_tags(&tags); -+ -+ yaffs_rd_chunk_tags_nand(dev, old_chunk, -+ buffer, &tags); -+ -+ object = yaffs_find_by_number(dev, tags.obj_id); -+ -+ yaffs_trace(YAFFS_TRACE_GC_DETAIL, -+ "Collecting chunk in block %d, %d %d %d ", -+ dev->gc_chunk, tags.obj_id, -+ tags.chunk_id, tags.n_bytes); -+ -+ if (object && !yaffs_skip_verification(dev)) { -+ if (tags.chunk_id == 0) -+ matching_chunk = -+ object->hdr_chunk; -+ else if (object->soft_del) -+ matching_chunk = old_chunk; /* Defeat the test */ -+ else -+ matching_chunk = -+ yaffs_find_chunk_in_file -+ (object, tags.chunk_id, -+ NULL); -+ -+ if (old_chunk != matching_chunk) -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "gc: page in gc mismatch: %d %d %d %d", -+ old_chunk, -+ matching_chunk, -+ tags.obj_id, -+ tags.chunk_id); -+ -+ } -+ -+ if (!object) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "page %d in gc has no object: %d %d %d ", -+ old_chunk, -+ tags.obj_id, tags.chunk_id, -+ tags.n_bytes); -+ } -+ -+ if (object && -+ object->deleted && -+ object->soft_del && tags.chunk_id != 0) { -+ /* Data chunk in a soft deleted file, throw it away -+ * It's a soft deleted data chunk, -+ * No need to copy this, just forget about it and -+ * fix up the object. -+ */ -+ -+ /* Free chunks already includes softdeleted chunks. -+ * How ever this chunk is going to soon be really deleted -+ * which will increment free chunks. -+ * We have to decrement free chunks so this works out properly. -+ */ -+ dev->n_free_chunks--; -+ bi->soft_del_pages--; -+ -+ object->n_data_chunks--; -+ -+ if (object->n_data_chunks <= 0) { -+ /* remeber to clean up the object */ -+ dev->gc_cleanup_list[dev-> -+ n_clean_ups] -+ = tags.obj_id; -+ dev->n_clean_ups++; -+ } -+ mark_flash = 0; -+ } else if (0) { -+ /* Todo object && object->deleted && object->n_data_chunks == 0 */ -+ /* Deleted object header with no data chunks. -+ * Can be discarded and the file deleted. -+ */ -+ object->hdr_chunk = 0; -+ yaffs_free_tnode(object->my_dev, -+ object-> -+ variant.file_variant. -+ top); -+ object->variant.file_variant.top = NULL; -+ yaffs_generic_obj_del(object); -+ -+ } else if (object) { -+ /* It's either a data chunk in a live file or -+ * an ObjectHeader, so we're interested in it. -+ * NB Need to keep the ObjectHeaders of deleted files -+ * until the whole file has been deleted off -+ */ -+ tags.serial_number++; -+ -+ dev->n_gc_copies++; -+ -+ if (tags.chunk_id == 0) { -+ /* It is an object Id, -+ * We need to nuke the shrinkheader flags first -+ * Also need to clean up shadowing. -+ * We no longer want the shrink_header flag since its work is done -+ * and if it is left in place it will mess up scanning. -+ */ -+ -+ struct yaffs_obj_hdr *oh; -+ oh = (struct yaffs_obj_hdr *) -+ buffer; -+ -+ oh->is_shrink = 0; -+ tags.extra_is_shrink = 0; -+ -+ oh->shadows_obj = 0; -+ oh->inband_shadowed_obj_id = 0; -+ tags.extra_shadows = 0; -+ -+ /* Update file size */ -+ if (object->variant_type == -+ YAFFS_OBJECT_TYPE_FILE) { -+ oh->file_size = -+ object->variant. -+ file_variant. -+ file_size; -+ tags.extra_length = -+ oh->file_size; -+ } -+ -+ yaffs_verify_oh(object, oh, -+ &tags, 1); -+ new_chunk = -+ yaffs_write_new_chunk(dev, -+ (u8 *) -+ oh, -+ &tags, -+ 1); -+ } else { -+ new_chunk = -+ yaffs_write_new_chunk(dev, -+ buffer, -+ &tags, -+ 1); -+ } -+ -+ if (new_chunk < 0) { -+ ret_val = YAFFS_FAIL; -+ } else { -+ -+ /* Ok, now fix up the Tnodes etc. */ -+ -+ if (tags.chunk_id == 0) { -+ /* It's a header */ -+ object->hdr_chunk = -+ new_chunk; -+ object->serial = -+ tags.serial_number; -+ } else { -+ /* It's a data chunk */ -+ int ok; -+ ok = yaffs_put_chunk_in_file(object, tags.chunk_id, new_chunk, 0); -+ } -+ } -+ } -+ -+ if (ret_val == YAFFS_OK) -+ yaffs_chunk_del(dev, old_chunk, -+ mark_flash, __LINE__); -+ -+ } -+ } -+ -+ yaffs_release_temp_buffer(dev, buffer, __LINE__); -+ -+ } -+ -+ yaffs_verify_collected_blk(dev, bi, block); -+ -+ if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { -+ /* -+ * The gc did not complete. Set block state back to FULL -+ * because checkpointing does not restore gc. -+ */ -+ bi->block_state = YAFFS_BLOCK_STATE_FULL; -+ } else { -+ /* The gc completed. */ -+ /* Do any required cleanups */ -+ for (i = 0; i < dev->n_clean_ups; i++) { -+ /* Time to delete the file too */ -+ object = -+ yaffs_find_by_number(dev, dev->gc_cleanup_list[i]); -+ if (object) { -+ yaffs_free_tnode(dev, -+ object->variant. -+ file_variant.top); -+ object->variant.file_variant.top = NULL; -+ yaffs_trace(YAFFS_TRACE_GC, -+ "yaffs: About to finally delete object %d", -+ object->obj_id); -+ yaffs_generic_obj_del(object); -+ object->my_dev->n_deleted_files--; -+ } -+ -+ } -+ -+ chunks_after = yaffs_get_erased_chunks(dev); -+ if (chunks_before >= chunks_after) -+ yaffs_trace(YAFFS_TRACE_GC, -+ "gc did not increase free chunks before %d after %d", -+ chunks_before, chunks_after); -+ dev->gc_block = 0; -+ dev->gc_chunk = 0; -+ dev->n_clean_ups = 0; -+ } -+ -+ dev->gc_disable = 0; -+ -+ return ret_val; -+} -+ -+/* -+ * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough) -+ * for garbage collection. -+ */ -+ -+static unsigned yaffs_find_gc_block(struct yaffs_dev *dev, -+ int aggressive, int background) -+{ -+ int i; -+ int iterations; -+ unsigned selected = 0; -+ int prioritised = 0; -+ int prioritised_exist = 0; -+ struct yaffs_block_info *bi; -+ int threshold; -+ -+ /* First let's see if we need to grab a prioritised block */ -+ if (dev->has_pending_prioritised_gc && !aggressive) { -+ dev->gc_dirtiest = 0; -+ bi = dev->block_info; -+ for (i = dev->internal_start_block; -+ i <= dev->internal_end_block && !selected; i++) { -+ -+ if (bi->gc_prioritise) { -+ prioritised_exist = 1; -+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL && -+ yaffs_block_ok_for_gc(dev, bi)) { -+ selected = i; -+ prioritised = 1; -+ } -+ } -+ bi++; -+ } -+ -+ /* -+ * If there is a prioritised block and none was selected then -+ * this happened because there is at least one old dirty block gumming -+ * up the works. Let's gc the oldest dirty block. -+ */ -+ -+ if (prioritised_exist && -+ !selected && dev->oldest_dirty_block > 0) -+ selected = dev->oldest_dirty_block; -+ -+ if (!prioritised_exist) /* None found, so we can clear this */ -+ dev->has_pending_prioritised_gc = 0; -+ } -+ -+ /* If we're doing aggressive GC then we are happy to take a less-dirty block, and -+ * search harder. -+ * else (we're doing a leasurely gc), then we only bother to do this if the -+ * block has only a few pages in use. -+ */ -+ -+ if (!selected) { -+ int pages_used; -+ int n_blocks = -+ dev->internal_end_block - dev->internal_start_block + 1; -+ if (aggressive) { -+ threshold = dev->param.chunks_per_block; -+ iterations = n_blocks; -+ } else { -+ int max_threshold; -+ -+ if (background) -+ max_threshold = dev->param.chunks_per_block / 2; -+ else -+ max_threshold = dev->param.chunks_per_block / 8; -+ -+ if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD) -+ max_threshold = YAFFS_GC_PASSIVE_THRESHOLD; -+ -+ threshold = background ? (dev->gc_not_done + 2) * 2 : 0; -+ if (threshold < YAFFS_GC_PASSIVE_THRESHOLD) -+ threshold = YAFFS_GC_PASSIVE_THRESHOLD; -+ if (threshold > max_threshold) -+ threshold = max_threshold; -+ -+ iterations = n_blocks / 16 + 1; -+ if (iterations > 100) -+ iterations = 100; -+ } -+ -+ for (i = 0; -+ i < iterations && -+ (dev->gc_dirtiest < 1 || -+ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); i++) { -+ dev->gc_block_finder++; -+ if (dev->gc_block_finder < dev->internal_start_block || -+ dev->gc_block_finder > dev->internal_end_block) -+ dev->gc_block_finder = -+ dev->internal_start_block; -+ -+ bi = yaffs_get_block_info(dev, dev->gc_block_finder); -+ -+ pages_used = bi->pages_in_use - bi->soft_del_pages; -+ -+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL && -+ pages_used < dev->param.chunks_per_block && -+ (dev->gc_dirtiest < 1 -+ || pages_used < dev->gc_pages_in_use) -+ && yaffs_block_ok_for_gc(dev, bi)) { -+ dev->gc_dirtiest = dev->gc_block_finder; -+ dev->gc_pages_in_use = pages_used; -+ } -+ } -+ -+ if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold) -+ selected = dev->gc_dirtiest; -+ } -+ -+ /* -+ * If nothing has been selected for a while, try selecting the oldest dirty -+ * because that's gumming up the works. -+ */ -+ -+ if (!selected && dev->param.is_yaffs2 && -+ dev->gc_not_done >= (background ? 10 : 20)) { -+ yaffs2_find_oldest_dirty_seq(dev); -+ if (dev->oldest_dirty_block > 0) { -+ selected = dev->oldest_dirty_block; -+ dev->gc_dirtiest = selected; -+ dev->oldest_dirty_gc_count++; -+ bi = yaffs_get_block_info(dev, selected); -+ dev->gc_pages_in_use = -+ bi->pages_in_use - bi->soft_del_pages; -+ } else { -+ dev->gc_not_done = 0; -+ } -+ } -+ -+ if (selected) { -+ yaffs_trace(YAFFS_TRACE_GC, -+ "GC Selected block %d with %d free, prioritised:%d", -+ selected, -+ dev->param.chunks_per_block - dev->gc_pages_in_use, -+ prioritised); -+ -+ dev->n_gc_blocks++; -+ if (background) -+ dev->bg_gcs++; -+ -+ dev->gc_dirtiest = 0; -+ dev->gc_pages_in_use = 0; -+ dev->gc_not_done = 0; -+ if (dev->refresh_skip > 0) -+ dev->refresh_skip--; -+ } else { -+ dev->gc_not_done++; -+ yaffs_trace(YAFFS_TRACE_GC, -+ "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s", -+ dev->gc_block_finder, dev->gc_not_done, threshold, -+ dev->gc_dirtiest, dev->gc_pages_in_use, -+ dev->oldest_dirty_block, background ? " bg" : ""); -+ } -+ -+ return selected; -+} -+ -+/* New garbage collector -+ * If we're very low on erased blocks then we do aggressive garbage collection -+ * otherwise we do "leasurely" garbage collection. -+ * Aggressive gc looks further (whole array) and will accept less dirty blocks. -+ * Passive gc only inspects smaller areas and will only accept more dirty blocks. -+ * -+ * The idea is to help clear out space in a more spread-out manner. -+ * Dunno if it really does anything useful. -+ */ -+static int yaffs_check_gc(struct yaffs_dev *dev, int background) -+{ -+ int aggressive = 0; -+ int gc_ok = YAFFS_OK; -+ int max_tries = 0; -+ int min_erased; -+ int erased_chunks; -+ int checkpt_block_adjust; -+ -+ if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0) -+ return YAFFS_OK; -+ -+ if (dev->gc_disable) { -+ /* Bail out so we don't get recursive gc */ -+ return YAFFS_OK; -+ } -+ -+ /* This loop should pass the first time. -+ * We'll only see looping here if the collection does not increase space. -+ */ -+ -+ do { -+ max_tries++; -+ -+ checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev); -+ -+ min_erased = -+ dev->param.n_reserved_blocks + checkpt_block_adjust + 1; -+ erased_chunks = -+ dev->n_erased_blocks * dev->param.chunks_per_block; -+ -+ /* If we need a block soon then do aggressive gc. */ -+ if (dev->n_erased_blocks < min_erased) -+ aggressive = 1; -+ else { -+ if (!background -+ && erased_chunks > (dev->n_free_chunks / 4)) -+ break; -+ -+ if (dev->gc_skip > 20) -+ dev->gc_skip = 20; -+ if (erased_chunks < dev->n_free_chunks / 2 || -+ dev->gc_skip < 1 || background) -+ aggressive = 0; -+ else { -+ dev->gc_skip--; -+ break; -+ } -+ } -+ -+ dev->gc_skip = 5; -+ -+ /* If we don't already have a block being gc'd then see if we should start another */ -+ -+ if (dev->gc_block < 1 && !aggressive) { -+ dev->gc_block = yaffs2_find_refresh_block(dev); -+ dev->gc_chunk = 0; -+ dev->n_clean_ups = 0; -+ } -+ if (dev->gc_block < 1) { -+ dev->gc_block = -+ yaffs_find_gc_block(dev, aggressive, background); -+ dev->gc_chunk = 0; -+ dev->n_clean_ups = 0; -+ } -+ -+ if (dev->gc_block > 0) { -+ dev->all_gcs++; -+ if (!aggressive) -+ dev->passive_gc_count++; -+ -+ yaffs_trace(YAFFS_TRACE_GC, -+ "yaffs: GC n_erased_blocks %d aggressive %d", -+ dev->n_erased_blocks, aggressive); -+ -+ gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive); -+ } -+ -+ if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) -+ && dev->gc_block > 0) { -+ yaffs_trace(YAFFS_TRACE_GC, -+ "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d", -+ dev->n_erased_blocks, max_tries, -+ dev->gc_block); -+ } -+ } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) && -+ (dev->gc_block > 0) && (max_tries < 2)); -+ -+ return aggressive ? gc_ok : YAFFS_OK; -+} -+ -+/* -+ * yaffs_bg_gc() -+ * Garbage collects. Intended to be called from a background thread. -+ * Returns non-zero if at least half the free chunks are erased. -+ */ -+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency) -+{ -+ int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block; -+ -+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency); -+ -+ yaffs_check_gc(dev, 1); -+ return erased_chunks > dev->n_free_chunks / 2; -+} -+ -+/*-------------------- Data file manipulation -----------------*/ -+ -+static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer) -+{ -+ int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL); -+ -+ if (nand_chunk >= 0) -+ return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk, -+ buffer, NULL); -+ else { -+ yaffs_trace(YAFFS_TRACE_NANDACCESS, -+ "Chunk %d not found zero instead", -+ nand_chunk); -+ /* get sane (zero) data if you read a hole */ -+ memset(buffer, 0, in->my_dev->data_bytes_per_chunk); -+ return 0; -+ } -+ -+} -+ -+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, -+ int lyn) -+{ -+ int block; -+ int page; -+ struct yaffs_ext_tags tags; -+ struct yaffs_block_info *bi; -+ -+ if (chunk_id <= 0) -+ return; -+ -+ dev->n_deletions++; -+ block = chunk_id / dev->param.chunks_per_block; -+ page = chunk_id % dev->param.chunks_per_block; -+ -+ if (!yaffs_check_chunk_bit(dev, block, page)) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Deleting invalid chunk %d", chunk_id); -+ -+ bi = yaffs_get_block_info(dev, block); -+ -+ yaffs2_update_oldest_dirty_seq(dev, block, bi); -+ -+ yaffs_trace(YAFFS_TRACE_DELETION, -+ "line %d delete of chunk %d", -+ lyn, chunk_id); -+ -+ if (!dev->param.is_yaffs2 && mark_flash && -+ bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) { -+ -+ yaffs_init_tags(&tags); -+ -+ tags.is_deleted = 1; -+ -+ yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags); -+ yaffs_handle_chunk_update(dev, chunk_id, &tags); -+ } else { -+ dev->n_unmarked_deletions++; -+ } -+ -+ /* Pull out of the management area. -+ * If the whole block became dirty, this will kick off an erasure. -+ */ -+ if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING || -+ bi->block_state == YAFFS_BLOCK_STATE_FULL || -+ bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || -+ bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { -+ dev->n_free_chunks++; -+ -+ yaffs_clear_chunk_bit(dev, block, page); -+ -+ bi->pages_in_use--; -+ -+ if (bi->pages_in_use == 0 && -+ !bi->has_shrink_hdr && -+ bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING && -+ bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { -+ yaffs_block_became_dirty(dev, block); -+ } -+ -+ } -+ -+} -+ -+static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, -+ const u8 * buffer, int n_bytes, int use_reserve) -+{ -+ /* Find old chunk Need to do this to get serial number -+ * Write new one and patch into tree. -+ * Invalidate old tags. -+ */ -+ -+ int prev_chunk_id; -+ struct yaffs_ext_tags prev_tags; -+ -+ int new_chunk_id; -+ struct yaffs_ext_tags new_tags; -+ -+ struct yaffs_dev *dev = in->my_dev; -+ -+ yaffs_check_gc(dev, 0); -+ -+ /* Get the previous chunk at this location in the file if it exists. -+ * If it does not exist then put a zero into the tree. This creates -+ * the tnode now, rather than later when it is harder to clean up. -+ */ -+ prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags); -+ if (prev_chunk_id < 1 && -+ !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0)) -+ return 0; -+ -+ /* Set up new tags */ -+ yaffs_init_tags(&new_tags); -+ -+ new_tags.chunk_id = inode_chunk; -+ new_tags.obj_id = in->obj_id; -+ new_tags.serial_number = -+ (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1; -+ new_tags.n_bytes = n_bytes; -+ -+ if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "Writing %d bytes to chunk!!!!!!!!!", -+ n_bytes); -+ YBUG(); -+ } -+ -+ new_chunk_id = -+ yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve); -+ -+ if (new_chunk_id > 0) { -+ yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0); -+ -+ if (prev_chunk_id > 0) -+ yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); -+ -+ yaffs_verify_file_sane(in); -+ } -+ return new_chunk_id; -+ -+} -+ -+ -+ -+static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set, -+ const YCHAR * name, const void *value, int size, -+ int flags) -+{ -+ struct yaffs_xattr_mod xmod; -+ -+ int result; -+ -+ xmod.set = set; -+ xmod.name = name; -+ xmod.data = value; -+ xmod.size = size; -+ xmod.flags = flags; -+ xmod.result = -ENOSPC; -+ -+ result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod); -+ -+ if (result > 0) -+ return xmod.result; -+ else -+ return -ENOSPC; -+} -+ -+static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, -+ struct yaffs_xattr_mod *xmod) -+{ -+ int retval = 0; -+ int x_offs = sizeof(struct yaffs_obj_hdr); -+ struct yaffs_dev *dev = obj->my_dev; -+ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); -+ -+ char *x_buffer = buffer + x_offs; -+ -+ if (xmod->set) -+ retval = -+ nval_set(x_buffer, x_size, xmod->name, xmod->data, -+ xmod->size, xmod->flags); -+ else -+ retval = nval_del(x_buffer, x_size, xmod->name); -+ -+ obj->has_xattr = nval_hasvalues(x_buffer, x_size); -+ obj->xattr_known = 1; -+ -+ xmod->result = retval; -+ -+ return retval; -+} -+ -+static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR * name, -+ void *value, int size) -+{ -+ char *buffer = NULL; -+ int result; -+ struct yaffs_ext_tags tags; -+ struct yaffs_dev *dev = obj->my_dev; -+ int x_offs = sizeof(struct yaffs_obj_hdr); -+ int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); -+ -+ char *x_buffer; -+ -+ int retval = 0; -+ -+ if (obj->hdr_chunk < 1) -+ return -ENODATA; -+ -+ /* If we know that the object has no xattribs then don't do all the -+ * reading and parsing. -+ */ -+ if (obj->xattr_known && !obj->has_xattr) { -+ if (name) -+ return -ENODATA; -+ else -+ return 0; -+ } -+ -+ buffer = (char *)yaffs_get_temp_buffer(dev, __LINE__); -+ if (!buffer) -+ return -ENOMEM; -+ -+ result = -+ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags); -+ -+ if (result != YAFFS_OK) -+ retval = -ENOENT; -+ else { -+ x_buffer = buffer + x_offs; -+ -+ if (!obj->xattr_known) { -+ obj->has_xattr = nval_hasvalues(x_buffer, x_size); -+ obj->xattr_known = 1; -+ } -+ -+ if (name) -+ retval = nval_get(x_buffer, x_size, name, value, size); -+ else -+ retval = nval_list(x_buffer, x_size, value, size); -+ } -+ yaffs_release_temp_buffer(dev, (u8 *) buffer, __LINE__); -+ return retval; -+} -+ -+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name, -+ const void *value, int size, int flags) -+{ -+ return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags); -+} -+ -+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name) -+{ -+ return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0); -+} -+ -+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value, -+ int size) -+{ -+ return yaffs_do_xattrib_fetch(obj, name, value, size); -+} -+ -+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size) -+{ -+ return yaffs_do_xattrib_fetch(obj, NULL, buffer, size); -+} -+ -+static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) -+{ -+ u8 *chunk_data; -+ struct yaffs_obj_hdr *oh; -+ struct yaffs_dev *dev; -+ struct yaffs_ext_tags tags; -+ int result; -+ int alloc_failed = 0; -+ -+ if (!in) -+ return; -+ -+ dev = in->my_dev; -+ -+ if (in->lazy_loaded && in->hdr_chunk > 0) { -+ in->lazy_loaded = 0; -+ chunk_data = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ result = -+ yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunk_data, -+ &tags); -+ oh = (struct yaffs_obj_hdr *)chunk_data; -+ -+ in->yst_mode = oh->yst_mode; -+ yaffs_load_attribs(in, oh); -+ yaffs_set_obj_name_from_oh(in, oh); -+ -+ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { -+ in->variant.symlink_variant.alias = -+ yaffs_clone_str(oh->alias); -+ if (!in->variant.symlink_variant.alias) -+ alloc_failed = 1; /* Not returned to caller */ -+ } -+ -+ yaffs_release_temp_buffer(dev, chunk_data, __LINE__); -+ } -+} -+ -+static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR * name, -+ const YCHAR * oh_name, int buff_size) -+{ -+#ifdef CONFIG_YAFFS_AUTO_UNICODE -+ if (dev->param.auto_unicode) { -+ if (*oh_name) { -+ /* It is an ASCII name, do an ASCII to -+ * unicode conversion */ -+ const char *ascii_oh_name = (const char *)oh_name; -+ int n = buff_size - 1; -+ while (n > 0 && *ascii_oh_name) { -+ *name = *ascii_oh_name; -+ name++; -+ ascii_oh_name++; -+ n--; -+ } -+ } else { -+ strncpy(name, oh_name + 1, buff_size - 1); -+ } -+ } else { -+#else -+ { -+#endif -+ strncpy(name, oh_name, buff_size - 1); -+ } -+} -+ -+static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR * oh_name, -+ const YCHAR * name) -+{ -+#ifdef CONFIG_YAFFS_AUTO_UNICODE -+ -+ int is_ascii; -+ YCHAR *w; -+ -+ if (dev->param.auto_unicode) { -+ -+ is_ascii = 1; -+ w = name; -+ -+ /* Figure out if the name will fit in ascii character set */ -+ while (is_ascii && *w) { -+ if ((*w) & 0xff00) -+ is_ascii = 0; -+ w++; -+ } -+ -+ if (is_ascii) { -+ /* It is an ASCII name, so do a unicode to ascii conversion */ -+ char *ascii_oh_name = (char *)oh_name; -+ int n = YAFFS_MAX_NAME_LENGTH - 1; -+ while (n > 0 && *name) { -+ *ascii_oh_name = *name; -+ name++; -+ ascii_oh_name++; -+ n--; -+ } -+ } else { -+ /* It is a unicode name, so save starting at the second YCHAR */ -+ *oh_name = 0; -+ strncpy(oh_name + 1, name, -+ YAFFS_MAX_NAME_LENGTH - 2); -+ } -+ } else { -+#else -+ { -+#endif -+ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1); -+ } -+ -+} -+ -+/* UpdateObjectHeader updates the header on NAND for an object. -+ * If name is not NULL, then that new name is used. -+ */ -+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR * name, int force, -+ int is_shrink, int shadows, struct yaffs_xattr_mod *xmod) -+{ -+ -+ struct yaffs_block_info *bi; -+ -+ struct yaffs_dev *dev = in->my_dev; -+ -+ int prev_chunk_id; -+ int ret_val = 0; -+ int result = 0; -+ -+ int new_chunk_id; -+ struct yaffs_ext_tags new_tags; -+ struct yaffs_ext_tags old_tags; -+ const YCHAR *alias = NULL; -+ -+ u8 *buffer = NULL; -+ YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ struct yaffs_obj_hdr *oh = NULL; -+ -+ strcpy(old_name, _Y("silly old name")); -+ -+ if (!in->fake || in == dev->root_dir || -+ force || xmod) { -+ -+ yaffs_check_gc(dev, 0); -+ yaffs_check_obj_details_loaded(in); -+ -+ buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__); -+ oh = (struct yaffs_obj_hdr *)buffer; -+ -+ prev_chunk_id = in->hdr_chunk; -+ -+ if (prev_chunk_id > 0) { -+ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id, -+ buffer, &old_tags); -+ -+ yaffs_verify_oh(in, oh, &old_tags, 0); -+ -+ memcpy(old_name, oh->name, sizeof(oh->name)); -+ memset(buffer, 0xFF, sizeof(struct yaffs_obj_hdr)); -+ } else { -+ memset(buffer, 0xFF, dev->data_bytes_per_chunk); -+ } -+ -+ oh->type = in->variant_type; -+ oh->yst_mode = in->yst_mode; -+ oh->shadows_obj = oh->inband_shadowed_obj_id = shadows; -+ -+ yaffs_load_attribs_oh(oh, in); -+ -+ if (in->parent) -+ oh->parent_obj_id = in->parent->obj_id; -+ else -+ oh->parent_obj_id = 0; -+ -+ if (name && *name) { -+ memset(oh->name, 0, sizeof(oh->name)); -+ yaffs_load_oh_from_name(dev, oh->name, name); -+ } else if (prev_chunk_id > 0) { -+ memcpy(oh->name, old_name, sizeof(oh->name)); -+ } else { -+ memset(oh->name, 0, sizeof(oh->name)); -+ } -+ -+ oh->is_shrink = is_shrink; -+ -+ switch (in->variant_type) { -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ /* Should not happen */ -+ break; -+ case YAFFS_OBJECT_TYPE_FILE: -+ oh->file_size = -+ (oh->parent_obj_id == YAFFS_OBJECTID_DELETED -+ || oh->parent_obj_id == -+ YAFFS_OBJECTID_UNLINKED) ? 0 : in-> -+ variant.file_variant.file_size; -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ oh->equiv_id = in->variant.hardlink_variant.equiv_id; -+ break; -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ /* Do nothing */ -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ /* Do nothing */ -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ alias = in->variant.symlink_variant.alias; -+ if (!alias) -+ alias = _Y("no alias"); -+ strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH); -+ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; -+ break; -+ } -+ -+ /* process any xattrib modifications */ -+ if (xmod) -+ yaffs_apply_xattrib_mod(in, (char *)buffer, xmod); -+ -+ /* Tags */ -+ yaffs_init_tags(&new_tags); -+ in->serial++; -+ new_tags.chunk_id = 0; -+ new_tags.obj_id = in->obj_id; -+ new_tags.serial_number = in->serial; -+ -+ /* Add extra info for file header */ -+ -+ new_tags.extra_available = 1; -+ new_tags.extra_parent_id = oh->parent_obj_id; -+ new_tags.extra_length = oh->file_size; -+ new_tags.extra_is_shrink = oh->is_shrink; -+ new_tags.extra_equiv_id = oh->equiv_id; -+ new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; -+ new_tags.extra_obj_type = in->variant_type; -+ -+ yaffs_verify_oh(in, oh, &new_tags, 1); -+ -+ /* Create new chunk in NAND */ -+ new_chunk_id = -+ yaffs_write_new_chunk(dev, buffer, &new_tags, -+ (prev_chunk_id > 0) ? 1 : 0); -+ -+ if (new_chunk_id >= 0) { -+ -+ in->hdr_chunk = new_chunk_id; -+ -+ if (prev_chunk_id > 0) { -+ yaffs_chunk_del(dev, prev_chunk_id, 1, -+ __LINE__); -+ } -+ -+ if (!yaffs_obj_cache_dirty(in)) -+ in->dirty = 0; -+ -+ /* If this was a shrink, then mark the block that the chunk lives on */ -+ if (is_shrink) { -+ bi = yaffs_get_block_info(in->my_dev, -+ new_chunk_id / -+ in->my_dev->param. -+ chunks_per_block); -+ bi->has_shrink_hdr = 1; -+ } -+ -+ } -+ -+ ret_val = new_chunk_id; -+ -+ } -+ -+ if (buffer) -+ yaffs_release_temp_buffer(dev, buffer, __LINE__); -+ -+ return ret_val; -+} -+ -+/*--------------------- File read/write ------------------------ -+ * Read and write have very similar structures. -+ * In general the read/write has three parts to it -+ * An incomplete chunk to start with (if the read/write is not chunk-aligned) -+ * Some complete chunks -+ * An incomplete chunk to end off with -+ * -+ * Curve-balls: the first chunk might also be the last chunk. -+ */ -+ -+int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes) -+{ -+ -+ int chunk; -+ u32 start; -+ int n_copy; -+ int n = n_bytes; -+ int n_done = 0; -+ struct yaffs_cache *cache; -+ -+ struct yaffs_dev *dev; -+ -+ dev = in->my_dev; -+ -+ while (n > 0) { -+ /* chunk = offset / dev->data_bytes_per_chunk + 1; */ -+ /* start = offset % dev->data_bytes_per_chunk; */ -+ yaffs_addr_to_chunk(dev, offset, &chunk, &start); -+ chunk++; -+ -+ /* OK now check for the curveball where the start and end are in -+ * the same chunk. -+ */ -+ if ((start + n) < dev->data_bytes_per_chunk) -+ n_copy = n; -+ else -+ n_copy = dev->data_bytes_per_chunk - start; -+ -+ cache = yaffs_find_chunk_cache(in, chunk); -+ -+ /* If the chunk is already in the cache or it is less than a whole chunk -+ * or we're using inband tags then use the cache (if there is caching) -+ * else bypass the cache. -+ */ -+ if (cache || n_copy != dev->data_bytes_per_chunk -+ || dev->param.inband_tags) { -+ if (dev->param.n_caches > 0) { -+ -+ /* If we can't find the data in the cache, then load it up. */ -+ -+ if (!cache) { -+ cache = -+ yaffs_grab_chunk_cache(in->my_dev); -+ cache->object = in; -+ cache->chunk_id = chunk; -+ cache->dirty = 0; -+ cache->locked = 0; -+ yaffs_rd_data_obj(in, chunk, -+ cache->data); -+ cache->n_bytes = 0; -+ } -+ -+ yaffs_use_cache(dev, cache, 0); -+ -+ cache->locked = 1; -+ -+ memcpy(buffer, &cache->data[start], n_copy); -+ -+ cache->locked = 0; -+ } else { -+ /* Read into the local buffer then copy.. */ -+ -+ u8 *local_buffer = -+ yaffs_get_temp_buffer(dev, __LINE__); -+ yaffs_rd_data_obj(in, chunk, local_buffer); -+ -+ memcpy(buffer, &local_buffer[start], n_copy); -+ -+ yaffs_release_temp_buffer(dev, local_buffer, -+ __LINE__); -+ } -+ -+ } else { -+ -+ /* A full chunk. Read directly into the supplied buffer. */ -+ yaffs_rd_data_obj(in, chunk, buffer); -+ -+ } -+ -+ n -= n_copy; -+ offset += n_copy; -+ buffer += n_copy; -+ n_done += n_copy; -+ -+ } -+ -+ return n_done; -+} -+ -+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 * buffer, loff_t offset, -+ int n_bytes, int write_trhrough) -+{ -+ -+ int chunk; -+ u32 start; -+ int n_copy; -+ int n = n_bytes; -+ int n_done = 0; -+ int n_writeback; -+ int start_write = offset; -+ int chunk_written = 0; -+ u32 n_bytes_read; -+ u32 chunk_start; -+ -+ struct yaffs_dev *dev; -+ -+ dev = in->my_dev; -+ -+ while (n > 0 && chunk_written >= 0) { -+ yaffs_addr_to_chunk(dev, offset, &chunk, &start); -+ -+ if (chunk * dev->data_bytes_per_chunk + start != offset || -+ start >= dev->data_bytes_per_chunk) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "AddrToChunk of offset %d gives chunk %d start %d", -+ (int)offset, chunk, start); -+ } -+ chunk++; /* File pos to chunk in file offset */ -+ -+ /* OK now check for the curveball where the start and end are in -+ * the same chunk. -+ */ -+ -+ if ((start + n) < dev->data_bytes_per_chunk) { -+ n_copy = n; -+ -+ /* Now folks, to calculate how many bytes to write back.... -+ * If we're overwriting and not writing to then end of file then -+ * we need to write back as much as was there before. -+ */ -+ -+ chunk_start = ((chunk - 1) * dev->data_bytes_per_chunk); -+ -+ if (chunk_start > in->variant.file_variant.file_size) -+ n_bytes_read = 0; /* Past end of file */ -+ else -+ n_bytes_read = -+ in->variant.file_variant.file_size - -+ chunk_start; -+ -+ if (n_bytes_read > dev->data_bytes_per_chunk) -+ n_bytes_read = dev->data_bytes_per_chunk; -+ -+ n_writeback = -+ (n_bytes_read > -+ (start + n)) ? n_bytes_read : (start + n); -+ -+ if (n_writeback < 0 -+ || n_writeback > dev->data_bytes_per_chunk) -+ YBUG(); -+ -+ } else { -+ n_copy = dev->data_bytes_per_chunk - start; -+ n_writeback = dev->data_bytes_per_chunk; -+ } -+ -+ if (n_copy != dev->data_bytes_per_chunk -+ || dev->param.inband_tags) { -+ /* An incomplete start or end chunk (or maybe both start and end chunk), -+ * or we're using inband tags, so we want to use the cache buffers. -+ */ -+ if (dev->param.n_caches > 0) { -+ struct yaffs_cache *cache; -+ /* If we can't find the data in the cache, then load the cache */ -+ cache = yaffs_find_chunk_cache(in, chunk); -+ -+ if (!cache -+ && yaffs_check_alloc_available(dev, 1)) { -+ cache = yaffs_grab_chunk_cache(dev); -+ cache->object = in; -+ cache->chunk_id = chunk; -+ cache->dirty = 0; -+ cache->locked = 0; -+ yaffs_rd_data_obj(in, chunk, -+ cache->data); -+ } else if (cache && -+ !cache->dirty && -+ !yaffs_check_alloc_available(dev, -+ 1)) { -+ /* Drop the cache if it was a read cache item and -+ * no space check has been made for it. -+ */ -+ cache = NULL; -+ } -+ -+ if (cache) { -+ yaffs_use_cache(dev, cache, 1); -+ cache->locked = 1; -+ -+ memcpy(&cache->data[start], buffer, -+ n_copy); -+ -+ cache->locked = 0; -+ cache->n_bytes = n_writeback; -+ -+ if (write_trhrough) { -+ chunk_written = -+ yaffs_wr_data_obj -+ (cache->object, -+ cache->chunk_id, -+ cache->data, -+ cache->n_bytes, 1); -+ cache->dirty = 0; -+ } -+ -+ } else { -+ chunk_written = -1; /* fail the write */ -+ } -+ } else { -+ /* An incomplete start or end chunk (or maybe both start and end chunk) -+ * Read into the local buffer then copy, then copy over and write back. -+ */ -+ -+ u8 *local_buffer = -+ yaffs_get_temp_buffer(dev, __LINE__); -+ -+ yaffs_rd_data_obj(in, chunk, local_buffer); -+ -+ memcpy(&local_buffer[start], buffer, n_copy); -+ -+ chunk_written = -+ yaffs_wr_data_obj(in, chunk, -+ local_buffer, -+ n_writeback, 0); -+ -+ yaffs_release_temp_buffer(dev, local_buffer, -+ __LINE__); -+ -+ } -+ -+ } else { -+ /* A full chunk. Write directly from the supplied buffer. */ -+ -+ chunk_written = -+ yaffs_wr_data_obj(in, chunk, buffer, -+ dev->data_bytes_per_chunk, 0); -+ -+ /* Since we've overwritten the cached data, we better invalidate it. */ -+ yaffs_invalidate_chunk_cache(in, chunk); -+ } -+ -+ if (chunk_written >= 0) { -+ n -= n_copy; -+ offset += n_copy; -+ buffer += n_copy; -+ n_done += n_copy; -+ } -+ -+ } -+ -+ /* Update file object */ -+ -+ if ((start_write + n_done) > in->variant.file_variant.file_size) -+ in->variant.file_variant.file_size = (start_write + n_done); -+ -+ in->dirty = 1; -+ -+ return n_done; -+} -+ -+int yaffs_wr_file(struct yaffs_obj *in, const u8 * buffer, loff_t offset, -+ int n_bytes, int write_trhrough) -+{ -+ yaffs2_handle_hole(in, offset); -+ return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_trhrough); -+} -+ -+/* ---------------------- File resizing stuff ------------------ */ -+ -+static void yaffs_prune_chunks(struct yaffs_obj *in, int new_size) -+{ -+ -+ struct yaffs_dev *dev = in->my_dev; -+ int old_size = in->variant.file_variant.file_size; -+ -+ int last_del = 1 + (old_size - 1) / dev->data_bytes_per_chunk; -+ -+ int start_del = 1 + (new_size + dev->data_bytes_per_chunk - 1) / -+ dev->data_bytes_per_chunk; -+ int i; -+ int chunk_id; -+ -+ /* Delete backwards so that we don't end up with holes if -+ * power is lost part-way through the operation. -+ */ -+ for (i = last_del; i >= start_del; i--) { -+ /* NB this could be optimised somewhat, -+ * eg. could retrieve the tags and write them without -+ * using yaffs_chunk_del -+ */ -+ -+ chunk_id = yaffs_find_del_file_chunk(in, i, NULL); -+ if (chunk_id > 0) { -+ if (chunk_id < -+ (dev->internal_start_block * -+ dev->param.chunks_per_block) -+ || chunk_id >= -+ ((dev->internal_end_block + -+ 1) * dev->param.chunks_per_block)) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "Found daft chunk_id %d for %d", -+ chunk_id, i); -+ } else { -+ in->n_data_chunks--; -+ yaffs_chunk_del(dev, chunk_id, 1, __LINE__); -+ } -+ } -+ } -+ -+} -+ -+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size) -+{ -+ int new_full; -+ u32 new_partial; -+ struct yaffs_dev *dev = obj->my_dev; -+ -+ yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial); -+ -+ yaffs_prune_chunks(obj, new_size); -+ -+ if (new_partial != 0) { -+ int last_chunk = 1 + new_full; -+ u8 *local_buffer = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ /* Rewrite the last chunk with its new size and zero pad */ -+ yaffs_rd_data_obj(obj, last_chunk, local_buffer); -+ memset(local_buffer + new_partial, 0, -+ dev->data_bytes_per_chunk - new_partial); -+ -+ yaffs_wr_data_obj(obj, last_chunk, local_buffer, -+ new_partial, 1); -+ -+ yaffs_release_temp_buffer(dev, local_buffer, __LINE__); -+ } -+ -+ obj->variant.file_variant.file_size = new_size; -+ -+ yaffs_prune_tree(dev, &obj->variant.file_variant); -+} -+ -+int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size) -+{ -+ struct yaffs_dev *dev = in->my_dev; -+ int old_size = in->variant.file_variant.file_size; -+ -+ yaffs_flush_file_cache(in); -+ yaffs_invalidate_whole_cache(in); -+ -+ yaffs_check_gc(dev, 0); -+ -+ if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) -+ return YAFFS_FAIL; -+ -+ if (new_size == old_size) -+ return YAFFS_OK; -+ -+ if (new_size > old_size) { -+ yaffs2_handle_hole(in, new_size); -+ in->variant.file_variant.file_size = new_size; -+ } else { -+ /* new_size < old_size */ -+ yaffs_resize_file_down(in, new_size); -+ } -+ -+ /* Write a new object header to reflect the resize. -+ * show we've shrunk the file, if need be -+ * Do this only if the file is not in the deleted directories -+ * and is not shadowed. -+ */ -+ if (in->parent && -+ !in->is_shadowed && -+ in->parent->obj_id != YAFFS_OBJECTID_UNLINKED && -+ in->parent->obj_id != YAFFS_OBJECTID_DELETED) -+ yaffs_update_oh(in, NULL, 0, 0, 0, NULL); -+ -+ return YAFFS_OK; -+} -+ -+int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync) -+{ -+ int ret_val; -+ if (in->dirty) { -+ yaffs_flush_file_cache(in); -+ if (data_sync) /* Only sync data */ -+ ret_val = YAFFS_OK; -+ else { -+ if (update_time) -+ yaffs_load_current_time(in, 0, 0); -+ -+ ret_val = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= -+ 0) ? YAFFS_OK : YAFFS_FAIL; -+ } -+ } else { -+ ret_val = YAFFS_OK; -+ } -+ -+ return ret_val; -+ -+} -+ -+ -+/* yaffs_del_file deletes the whole file data -+ * and the inode associated with the file. -+ * It does not delete the links associated with the file. -+ */ -+static int yaffs_unlink_file_if_needed(struct yaffs_obj *in) -+{ -+ -+ int ret_val; -+ int del_now = 0; -+ struct yaffs_dev *dev = in->my_dev; -+ -+ if (!in->my_inode) -+ del_now = 1; -+ -+ if (del_now) { -+ ret_val = -+ yaffs_change_obj_name(in, in->my_dev->del_dir, -+ _Y("deleted"), 0, 0); -+ yaffs_trace(YAFFS_TRACE_TRACING, -+ "yaffs: immediate deletion of file %d", -+ in->obj_id); -+ in->deleted = 1; -+ in->my_dev->n_deleted_files++; -+ if (dev->param.disable_soft_del || dev->param.is_yaffs2) -+ yaffs_resize_file(in, 0); -+ yaffs_soft_del_file(in); -+ } else { -+ ret_val = -+ yaffs_change_obj_name(in, in->my_dev->unlinked_dir, -+ _Y("unlinked"), 0, 0); -+ } -+ -+ return ret_val; -+} -+ -+int yaffs_del_file(struct yaffs_obj *in) -+{ -+ int ret_val = YAFFS_OK; -+ int deleted; /* Need to cache value on stack if in is freed */ -+ struct yaffs_dev *dev = in->my_dev; -+ -+ if (dev->param.disable_soft_del || dev->param.is_yaffs2) -+ yaffs_resize_file(in, 0); -+ -+ if (in->n_data_chunks > 0) { -+ /* Use soft deletion if there is data in the file. -+ * That won't be the case if it has been resized to zero. -+ */ -+ if (!in->unlinked) -+ ret_val = yaffs_unlink_file_if_needed(in); -+ -+ deleted = in->deleted; -+ -+ if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) { -+ in->deleted = 1; -+ deleted = 1; -+ in->my_dev->n_deleted_files++; -+ yaffs_soft_del_file(in); -+ } -+ return deleted ? YAFFS_OK : YAFFS_FAIL; -+ } else { -+ /* The file has no data chunks so we toss it immediately */ -+ yaffs_free_tnode(in->my_dev, in->variant.file_variant.top); -+ in->variant.file_variant.top = NULL; -+ yaffs_generic_obj_del(in); -+ -+ return YAFFS_OK; -+ } -+} -+ -+int yaffs_is_non_empty_dir(struct yaffs_obj *obj) -+{ -+ return (obj && -+ obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) && -+ !(list_empty(&obj->variant.dir_variant.children)); -+} -+ -+static int yaffs_del_dir(struct yaffs_obj *obj) -+{ -+ /* First check that the directory is empty. */ -+ if (yaffs_is_non_empty_dir(obj)) -+ return YAFFS_FAIL; -+ -+ return yaffs_generic_obj_del(obj); -+} -+ -+static int yaffs_del_symlink(struct yaffs_obj *in) -+{ -+ if (in->variant.symlink_variant.alias) -+ kfree(in->variant.symlink_variant.alias); -+ in->variant.symlink_variant.alias = NULL; -+ -+ return yaffs_generic_obj_del(in); -+} -+ -+static int yaffs_del_link(struct yaffs_obj *in) -+{ -+ /* remove this hardlink from the list assocaited with the equivalent -+ * object -+ */ -+ list_del_init(&in->hard_links); -+ return yaffs_generic_obj_del(in); -+} -+ -+int yaffs_del_obj(struct yaffs_obj *obj) -+{ -+ int ret_val = -1; -+ switch (obj->variant_type) { -+ case YAFFS_OBJECT_TYPE_FILE: -+ ret_val = yaffs_del_file(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ if (!list_empty(&obj->variant.dir_variant.dirty)) { -+ yaffs_trace(YAFFS_TRACE_BACKGROUND, -+ "Remove object %d from dirty directories", -+ obj->obj_id); -+ list_del_init(&obj->variant.dir_variant.dirty); -+ } -+ return yaffs_del_dir(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ ret_val = yaffs_del_symlink(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ ret_val = yaffs_del_link(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ ret_val = yaffs_generic_obj_del(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ ret_val = 0; -+ break; /* should not happen. */ -+ } -+ -+ return ret_val; -+} -+ -+static int yaffs_unlink_worker(struct yaffs_obj *obj) -+{ -+ -+ int del_now = 0; -+ -+ if (!obj->my_inode) -+ del_now = 1; -+ -+ if (obj) -+ yaffs_update_parent(obj->parent); -+ -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { -+ return yaffs_del_link(obj); -+ } else if (!list_empty(&obj->hard_links)) { -+ /* Curve ball: We're unlinking an object that has a hardlink. -+ * -+ * This problem arises because we are not strictly following -+ * The Linux link/inode model. -+ * -+ * We can't really delete the object. -+ * Instead, we do the following: -+ * - Select a hardlink. -+ * - Unhook it from the hard links -+ * - Move it from its parent directory (so that the rename can work) -+ * - Rename the object to the hardlink's name. -+ * - Delete the hardlink -+ */ -+ -+ struct yaffs_obj *hl; -+ struct yaffs_obj *parent; -+ int ret_val; -+ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ hl = list_entry(obj->hard_links.next, struct yaffs_obj, -+ hard_links); -+ -+ yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1); -+ parent = hl->parent; -+ -+ list_del_init(&hl->hard_links); -+ -+ yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl); -+ -+ ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0); -+ -+ if (ret_val == YAFFS_OK) -+ ret_val = yaffs_generic_obj_del(hl); -+ -+ return ret_val; -+ -+ } else if (del_now) { -+ switch (obj->variant_type) { -+ case YAFFS_OBJECT_TYPE_FILE: -+ return yaffs_del_file(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ list_del_init(&obj->variant.dir_variant.dirty); -+ return yaffs_del_dir(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ return yaffs_del_symlink(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ return yaffs_generic_obj_del(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ default: -+ return YAFFS_FAIL; -+ } -+ } else if (yaffs_is_non_empty_dir(obj)) { -+ return YAFFS_FAIL; -+ } else { -+ return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir, -+ _Y("unlinked"), 0, 0); -+ } -+} -+ -+static int yaffs_unlink_obj(struct yaffs_obj *obj) -+{ -+ -+ if (obj && obj->unlink_allowed) -+ return yaffs_unlink_worker(obj); -+ -+ return YAFFS_FAIL; -+ -+} -+ -+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name) -+{ -+ struct yaffs_obj *obj; -+ -+ obj = yaffs_find_by_name(dir, name); -+ return yaffs_unlink_obj(obj); -+} -+ -+/* Note: -+ * If old_name is NULL then we take old_dir as the object to be renamed. -+ */ -+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, -+ struct yaffs_obj *new_dir, const YCHAR * new_name) -+{ -+ struct yaffs_obj *obj = NULL; -+ struct yaffs_obj *existing_target = NULL; -+ int force = 0; -+ int result; -+ struct yaffs_dev *dev; -+ -+ if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) -+ YBUG(); -+ if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) -+ YBUG(); -+ -+ dev = old_dir->my_dev; -+ -+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE -+ /* Special case for case insemsitive systems. -+ * While look-up is case insensitive, the name isn't. -+ * Therefore we might want to change x.txt to X.txt -+ */ -+ if (old_dir == new_dir && -+ old_name && new_name && -+ strcmp(old_name, new_name) == 0) -+ force = 1; -+#endif -+ -+ if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) > -+ YAFFS_MAX_NAME_LENGTH) -+ /* ENAMETOOLONG */ -+ return YAFFS_FAIL; -+ -+ if(old_name) -+ obj = yaffs_find_by_name(old_dir, old_name); -+ else{ -+ obj = old_dir; -+ old_dir = obj->parent; -+ } -+ -+ -+ if (obj && obj->rename_allowed) { -+ -+ /* Now do the handling for an existing target, if there is one */ -+ -+ existing_target = yaffs_find_by_name(new_dir, new_name); -+ if (yaffs_is_non_empty_dir(existing_target)){ -+ return YAFFS_FAIL; /* ENOTEMPTY */ -+ } else if (existing_target && existing_target != obj) { -+ /* Nuke the target first, using shadowing, -+ * but only if it isn't the same object. -+ * -+ * Note we must disable gc otherwise it can mess up the shadowing. -+ * -+ */ -+ dev->gc_disable = 1; -+ yaffs_change_obj_name(obj, new_dir, new_name, force, -+ existing_target->obj_id); -+ existing_target->is_shadowed = 1; -+ yaffs_unlink_obj(existing_target); -+ dev->gc_disable = 0; -+ } -+ -+ result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0); -+ -+ yaffs_update_parent(old_dir); -+ if (new_dir != old_dir) -+ yaffs_update_parent(new_dir); -+ -+ return result; -+ } -+ return YAFFS_FAIL; -+} -+ -+/*----------------------- Initialisation Scanning ---------------------- */ -+ -+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, -+ int backward_scanning) -+{ -+ struct yaffs_obj *obj; -+ -+ if (!backward_scanning) { -+ /* Handle YAFFS1 forward scanning case -+ * For YAFFS1 we always do the deletion -+ */ -+ -+ } else { -+ /* Handle YAFFS2 case (backward scanning) -+ * If the shadowed object exists then ignore. -+ */ -+ obj = yaffs_find_by_number(dev, obj_id); -+ if (obj) -+ return; -+ } -+ -+ /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc. -+ * We put it in unlinked dir to be cleaned up after the scanning -+ */ -+ obj = -+ yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE); -+ if (!obj) -+ return; -+ obj->is_shadowed = 1; -+ yaffs_add_obj_to_dir(dev->unlinked_dir, obj); -+ obj->variant.file_variant.shrink_size = 0; -+ obj->valid = 1; /* So that we don't read any other info for this file */ -+ -+} -+ -+void yaffs_link_fixup(struct yaffs_dev *dev, struct yaffs_obj *hard_list) -+{ -+ struct yaffs_obj *hl; -+ struct yaffs_obj *in; -+ -+ while (hard_list) { -+ hl = hard_list; -+ hard_list = (struct yaffs_obj *)(hard_list->hard_links.next); -+ -+ in = yaffs_find_by_number(dev, -+ hl->variant. -+ hardlink_variant.equiv_id); -+ -+ if (in) { -+ /* Add the hardlink pointers */ -+ hl->variant.hardlink_variant.equiv_obj = in; -+ list_add(&hl->hard_links, &in->hard_links); -+ } else { -+ /* Todo Need to report/handle this better. -+ * Got a problem... hardlink to a non-existant object -+ */ -+ hl->variant.hardlink_variant.equiv_obj = NULL; -+ INIT_LIST_HEAD(&hl->hard_links); -+ -+ } -+ } -+} -+ -+static void yaffs_strip_deleted_objs(struct yaffs_dev *dev) -+{ -+ /* -+ * Sort out state of unlinked and deleted objects after scanning. -+ */ -+ struct list_head *i; -+ struct list_head *n; -+ struct yaffs_obj *l; -+ -+ if (dev->read_only) -+ return; -+ -+ /* Soft delete all the unlinked files */ -+ list_for_each_safe(i, n, -+ &dev->unlinked_dir->variant.dir_variant.children) { -+ if (i) { -+ l = list_entry(i, struct yaffs_obj, siblings); -+ yaffs_del_obj(l); -+ } -+ } -+ -+ list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) { -+ if (i) { -+ l = list_entry(i, struct yaffs_obj, siblings); -+ yaffs_del_obj(l); -+ } -+ } -+ -+} -+ -+/* -+ * This code iterates through all the objects making sure that they are rooted. -+ * Any unrooted objects are re-rooted in lost+found. -+ * An object needs to be in one of: -+ * - Directly under deleted, unlinked -+ * - Directly or indirectly under root. -+ * -+ * Note: -+ * This code assumes that we don't ever change the current relationships between -+ * directories: -+ * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL -+ * lost-n-found->parent == root_dir -+ * -+ * This fixes the problem where directories might have inadvertently been deleted -+ * leaving the object "hanging" without being rooted in the directory tree. -+ */ -+ -+static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj) -+{ -+ return (obj == dev->del_dir || -+ obj == dev->unlinked_dir || obj == dev->root_dir); -+} -+ -+static void yaffs_fix_hanging_objs(struct yaffs_dev *dev) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_obj *parent; -+ int i; -+ struct list_head *lh; -+ struct list_head *n; -+ int depth_limit; -+ int hanging; -+ -+ if (dev->read_only) -+ return; -+ -+ /* Iterate through the objects in each hash entry, -+ * looking at each object. -+ * Make sure it is rooted. -+ */ -+ -+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { -+ list_for_each_safe(lh, n, &dev->obj_bucket[i].list) { -+ if (lh) { -+ obj = -+ list_entry(lh, struct yaffs_obj, hash_link); -+ parent = obj->parent; -+ -+ if (yaffs_has_null_parent(dev, obj)) { -+ /* These directories are not hanging */ -+ hanging = 0; -+ } else if (!parent -+ || parent->variant_type != -+ YAFFS_OBJECT_TYPE_DIRECTORY) { -+ hanging = 1; -+ } else if (yaffs_has_null_parent(dev, parent)) { -+ hanging = 0; -+ } else { -+ /* -+ * Need to follow the parent chain to see if it is hanging. -+ */ -+ hanging = 0; -+ depth_limit = 100; -+ -+ while (parent != dev->root_dir && -+ parent->parent && -+ parent->parent->variant_type == -+ YAFFS_OBJECT_TYPE_DIRECTORY -+ && depth_limit > 0) { -+ parent = parent->parent; -+ depth_limit--; -+ } -+ if (parent != dev->root_dir) -+ hanging = 1; -+ } -+ if (hanging) { -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "Hanging object %d moved to lost and found", -+ obj->obj_id); -+ yaffs_add_obj_to_dir(dev->lost_n_found, -+ obj); -+ } -+ } -+ } -+ } -+} -+ -+/* -+ * Delete directory contents for cleaning up lost and found. -+ */ -+static void yaffs_del_dir_contents(struct yaffs_obj *dir) -+{ -+ struct yaffs_obj *obj; -+ struct list_head *lh; -+ struct list_head *n; -+ -+ if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) -+ YBUG(); -+ -+ list_for_each_safe(lh, n, &dir->variant.dir_variant.children) { -+ if (lh) { -+ obj = list_entry(lh, struct yaffs_obj, siblings); -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) -+ yaffs_del_dir_contents(obj); -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "Deleting lost_found object %d", -+ obj->obj_id); -+ -+ /* Need to use UnlinkObject since Delete would not handle -+ * hardlinked objects correctly. -+ */ -+ yaffs_unlink_obj(obj); -+ } -+ } -+ -+} -+ -+static void yaffs_empty_l_n_f(struct yaffs_dev *dev) -+{ -+ yaffs_del_dir_contents(dev->lost_n_found); -+} -+ -+ -+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory, -+ const YCHAR * name) -+{ -+ int sum; -+ -+ struct list_head *i; -+ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ struct yaffs_obj *l; -+ -+ if (!name) -+ return NULL; -+ -+ if (!directory) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "tragedy: yaffs_find_by_name: null pointer directory" -+ ); -+ YBUG(); -+ return NULL; -+ } -+ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "tragedy: yaffs_find_by_name: non-directory" -+ ); -+ YBUG(); -+ } -+ -+ sum = yaffs_calc_name_sum(name); -+ -+ list_for_each(i, &directory->variant.dir_variant.children) { -+ if (i) { -+ l = list_entry(i, struct yaffs_obj, siblings); -+ -+ if (l->parent != directory) -+ YBUG(); -+ -+ yaffs_check_obj_details_loaded(l); -+ -+ /* Special case for lost-n-found */ -+ if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { -+ if (!strcmp(name, YAFFS_LOSTNFOUND_NAME)) -+ return l; -+ } else if (l->sum == sum -+ || l->hdr_chunk <= 0) { -+ /* LostnFound chunk called Objxxx -+ * Do a real check -+ */ -+ yaffs_get_obj_name(l, buffer, -+ YAFFS_MAX_NAME_LENGTH + 1); -+ if (strncmp -+ (name, buffer, YAFFS_MAX_NAME_LENGTH) == 0) -+ return l; -+ } -+ } -+ } -+ -+ return NULL; -+} -+ -+/* GetEquivalentObject dereferences any hard links to get to the -+ * actual object. -+ */ -+ -+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj) -+{ -+ if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { -+ /* We want the object id of the equivalent object, not this one */ -+ obj = obj->variant.hardlink_variant.equiv_obj; -+ yaffs_check_obj_details_loaded(obj); -+ } -+ return obj; -+} -+ -+/* -+ * A note or two on object names. -+ * * If the object name is missing, we then make one up in the form objnnn -+ * -+ * * ASCII names are stored in the object header's name field from byte zero -+ * * Unicode names are historically stored starting from byte zero. -+ * -+ * Then there are automatic Unicode names... -+ * The purpose of these is to save names in a way that can be read as -+ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII -+ * system to share files. -+ * -+ * These automatic unicode are stored slightly differently... -+ * - If the name can fit in the ASCII character space then they are saved as -+ * ascii names as per above. -+ * - If the name needs Unicode then the name is saved in Unicode -+ * starting at oh->name[1]. -+ -+ */ -+static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR * name, -+ int buffer_size) -+{ -+ /* Create an object name if we could not find one. */ -+ if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) { -+ YCHAR local_name[20]; -+ YCHAR num_string[20]; -+ YCHAR *x = &num_string[19]; -+ unsigned v = obj->obj_id; -+ num_string[19] = 0; -+ while (v > 0) { -+ x--; -+ *x = '0' + (v % 10); -+ v /= 10; -+ } -+ /* make up a name */ -+ strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX); -+ strcat(local_name, x); -+ strncpy(name, local_name, buffer_size - 1); -+ } -+} -+ -+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size) -+{ -+ memset(name, 0, buffer_size * sizeof(YCHAR)); -+ -+ yaffs_check_obj_details_loaded(obj); -+ -+ if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { -+ strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1); -+ } -+#ifndef CONFIG_YAFFS_NO_SHORT_NAMES -+ else if (obj->short_name[0]) { -+ strcpy(name, obj->short_name); -+ } -+#endif -+ else if (obj->hdr_chunk > 0) { -+ int result; -+ u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__); -+ -+ struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer; -+ -+ memset(buffer, 0, obj->my_dev->data_bytes_per_chunk); -+ -+ if (obj->hdr_chunk > 0) { -+ result = yaffs_rd_chunk_tags_nand(obj->my_dev, -+ obj->hdr_chunk, -+ buffer, NULL); -+ } -+ yaffs_load_name_from_oh(obj->my_dev, name, oh->name, -+ buffer_size); -+ -+ yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__); -+ } -+ -+ yaffs_fix_null_name(obj, name, buffer_size); -+ -+ return strnlen(name, YAFFS_MAX_NAME_LENGTH); -+} -+ -+int yaffs_get_obj_length(struct yaffs_obj *obj) -+{ -+ /* Dereference any hard linking */ -+ obj = yaffs_get_equivalent_obj(obj); -+ -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) -+ return obj->variant.file_variant.file_size; -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { -+ if (!obj->variant.symlink_variant.alias) -+ return 0; -+ return strnlen(obj->variant.symlink_variant.alias, -+ YAFFS_MAX_ALIAS_LENGTH); -+ } else { -+ /* Only a directory should drop through to here */ -+ return obj->my_dev->data_bytes_per_chunk; -+ } -+} -+ -+int yaffs_get_obj_link_count(struct yaffs_obj *obj) -+{ -+ int count = 0; -+ struct list_head *i; -+ -+ if (!obj->unlinked) -+ count++; /* the object itself */ -+ -+ list_for_each(i, &obj->hard_links) -+ count++; /* add the hard links; */ -+ -+ return count; -+} -+ -+int yaffs_get_obj_inode(struct yaffs_obj *obj) -+{ -+ obj = yaffs_get_equivalent_obj(obj); -+ -+ return obj->obj_id; -+} -+ -+unsigned yaffs_get_obj_type(struct yaffs_obj *obj) -+{ -+ obj = yaffs_get_equivalent_obj(obj); -+ -+ switch (obj->variant_type) { -+ case YAFFS_OBJECT_TYPE_FILE: -+ return DT_REG; -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ return DT_DIR; -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ return DT_LNK; -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ return DT_REG; -+ break; -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ if (S_ISFIFO(obj->yst_mode)) -+ return DT_FIFO; -+ if (S_ISCHR(obj->yst_mode)) -+ return DT_CHR; -+ if (S_ISBLK(obj->yst_mode)) -+ return DT_BLK; -+ if (S_ISSOCK(obj->yst_mode)) -+ return DT_SOCK; -+ default: -+ return DT_REG; -+ break; -+ } -+} -+ -+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj) -+{ -+ obj = yaffs_get_equivalent_obj(obj); -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) -+ return yaffs_clone_str(obj->variant.symlink_variant.alias); -+ else -+ return yaffs_clone_str(_Y("")); -+} -+ -+/*--------------------------- Initialisation code -------------------------- */ -+ -+static int yaffs_check_dev_fns(const struct yaffs_dev *dev) -+{ -+ -+ /* Common functions, gotta have */ -+ if (!dev->param.erase_fn || !dev->param.initialise_flash_fn) -+ return 0; -+ -+#ifdef CONFIG_YAFFS_YAFFS2 -+ -+ /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ -+ if (dev->param.write_chunk_tags_fn && -+ dev->param.read_chunk_tags_fn && -+ !dev->param.write_chunk_fn && -+ !dev->param.read_chunk_fn && -+ dev->param.bad_block_fn && dev->param.query_block_fn) -+ return 1; -+#endif -+ -+ /* Can use the "spare" style interface for yaffs1 */ -+ if (!dev->param.is_yaffs2 && -+ !dev->param.write_chunk_tags_fn && -+ !dev->param.read_chunk_tags_fn && -+ dev->param.write_chunk_fn && -+ dev->param.read_chunk_fn && -+ !dev->param.bad_block_fn && !dev->param.query_block_fn) -+ return 1; -+ -+ return 0; /* bad */ -+} -+ -+static int yaffs_create_initial_dir(struct yaffs_dev *dev) -+{ -+ /* Initialise the unlinked, deleted, root and lost and found directories */ -+ -+ dev->lost_n_found = dev->root_dir = NULL; -+ dev->unlinked_dir = dev->del_dir = NULL; -+ -+ dev->unlinked_dir = -+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); -+ -+ dev->del_dir = -+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); -+ -+ dev->root_dir = -+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT, -+ YAFFS_ROOT_MODE | S_IFDIR); -+ dev->lost_n_found = -+ yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND, -+ YAFFS_LOSTNFOUND_MODE | S_IFDIR); -+ -+ if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir -+ && dev->del_dir) { -+ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found); -+ return YAFFS_OK; -+ } -+ -+ return YAFFS_FAIL; -+} -+ -+int yaffs_guts_initialise(struct yaffs_dev *dev) -+{ -+ int init_failed = 0; -+ unsigned x; -+ int bits; -+ -+ yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()" ); -+ -+ /* Check stuff that must be set */ -+ -+ if (!dev) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs: Need a device" -+ ); -+ return YAFFS_FAIL; -+ } -+ -+ dev->internal_start_block = dev->param.start_block; -+ dev->internal_end_block = dev->param.end_block; -+ dev->block_offset = 0; -+ dev->chunk_offset = 0; -+ dev->n_free_chunks = 0; -+ -+ dev->gc_block = 0; -+ -+ if (dev->param.start_block == 0) { -+ dev->internal_start_block = dev->param.start_block + 1; -+ dev->internal_end_block = dev->param.end_block + 1; -+ dev->block_offset = 1; -+ dev->chunk_offset = dev->param.chunks_per_block; -+ } -+ -+ /* Check geometry parameters. */ -+ -+ if ((!dev->param.inband_tags && dev->param.is_yaffs2 && -+ dev->param.total_bytes_per_chunk < 1024) || -+ (!dev->param.is_yaffs2 && -+ dev->param.total_bytes_per_chunk < 512) || -+ (dev->param.inband_tags && !dev->param.is_yaffs2) || -+ dev->param.chunks_per_block < 2 || -+ dev->param.n_reserved_blocks < 2 || -+ dev->internal_start_block <= 0 || -+ dev->internal_end_block <= 0 || -+ dev->internal_end_block <= -+ (dev->internal_start_block + dev->param.n_reserved_blocks + 2) -+ ) { -+ /* otherwise it is too small */ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ", -+ dev->param.total_bytes_per_chunk, -+ dev->param.is_yaffs2 ? "2" : "", -+ dev->param.inband_tags); -+ return YAFFS_FAIL; -+ } -+ -+ if (yaffs_init_nand(dev) != YAFFS_OK) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); -+ return YAFFS_FAIL; -+ } -+ -+ /* Sort out space for inband tags, if required */ -+ if (dev->param.inband_tags) -+ dev->data_bytes_per_chunk = -+ dev->param.total_bytes_per_chunk - -+ sizeof(struct yaffs_packed_tags2_tags_only); -+ else -+ dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk; -+ -+ /* Got the right mix of functions? */ -+ if (!yaffs_check_dev_fns(dev)) { -+ /* Function missing */ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "device function(s) missing or wrong"); -+ -+ return YAFFS_FAIL; -+ } -+ -+ if (dev->is_mounted) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); -+ return YAFFS_FAIL; -+ } -+ -+ /* Finished with most checks. One or two more checks happen later on too. */ -+ -+ dev->is_mounted = 1; -+ -+ /* OK now calculate a few things for the device */ -+ -+ /* -+ * Calculate all the chunk size manipulation numbers: -+ */ -+ x = dev->data_bytes_per_chunk; -+ /* We always use dev->chunk_shift and dev->chunk_div */ -+ dev->chunk_shift = calc_shifts(x); -+ x >>= dev->chunk_shift; -+ dev->chunk_div = x; -+ /* We only use chunk mask if chunk_div is 1 */ -+ dev->chunk_mask = (1 << dev->chunk_shift) - 1; -+ -+ /* -+ * Calculate chunk_grp_bits. -+ * We need to find the next power of 2 > than internal_end_block -+ */ -+ -+ x = dev->param.chunks_per_block * (dev->internal_end_block + 1); -+ -+ bits = calc_shifts_ceiling(x); -+ -+ /* Set up tnode width if wide tnodes are enabled. */ -+ if (!dev->param.wide_tnodes_disabled) { -+ /* bits must be even so that we end up with 32-bit words */ -+ if (bits & 1) -+ bits++; -+ if (bits < 16) -+ dev->tnode_width = 16; -+ else -+ dev->tnode_width = bits; -+ } else { -+ dev->tnode_width = 16; -+ } -+ -+ dev->tnode_mask = (1 << dev->tnode_width) - 1; -+ -+ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), -+ * so if the bitwidth of the -+ * chunk range we're using is greater than 16 we need -+ * to figure out chunk shift and chunk_grp_size -+ */ -+ -+ if (bits <= dev->tnode_width) -+ dev->chunk_grp_bits = 0; -+ else -+ dev->chunk_grp_bits = bits - dev->tnode_width; -+ -+ dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8; -+ if (dev->tnode_size < sizeof(struct yaffs_tnode)) -+ dev->tnode_size = sizeof(struct yaffs_tnode); -+ -+ dev->chunk_grp_size = 1 << dev->chunk_grp_bits; -+ -+ if (dev->param.chunks_per_block < dev->chunk_grp_size) { -+ /* We have a problem because the soft delete won't work if -+ * the chunk group size > chunks per block. -+ * This can be remedied by using larger "virtual blocks". -+ */ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large"); -+ -+ return YAFFS_FAIL; -+ } -+ -+ /* OK, we've finished verifying the device, lets continue with initialisation */ -+ -+ /* More device initialisation */ -+ dev->all_gcs = 0; -+ dev->passive_gc_count = 0; -+ dev->oldest_dirty_gc_count = 0; -+ dev->bg_gcs = 0; -+ dev->gc_block_finder = 0; -+ dev->buffered_block = -1; -+ dev->doing_buffered_block_rewrite = 0; -+ dev->n_deleted_files = 0; -+ dev->n_bg_deletions = 0; -+ dev->n_unlinked_files = 0; -+ dev->n_ecc_fixed = 0; -+ dev->n_ecc_unfixed = 0; -+ dev->n_tags_ecc_fixed = 0; -+ dev->n_tags_ecc_unfixed = 0; -+ dev->n_erase_failures = 0; -+ dev->n_erased_blocks = 0; -+ dev->gc_disable = 0; -+ dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */ -+ INIT_LIST_HEAD(&dev->dirty_dirs); -+ dev->oldest_dirty_seq = 0; -+ dev->oldest_dirty_block = 0; -+ -+ /* Initialise temporary buffers and caches. */ -+ if (!yaffs_init_tmp_buffers(dev)) -+ init_failed = 1; -+ -+ dev->cache = NULL; -+ dev->gc_cleanup_list = NULL; -+ -+ if (!init_failed && dev->param.n_caches > 0) { -+ int i; -+ void *buf; -+ int cache_bytes = -+ dev->param.n_caches * sizeof(struct yaffs_cache); -+ -+ if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES) -+ dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES; -+ -+ dev->cache = kmalloc(cache_bytes, GFP_NOFS); -+ -+ buf = (u8 *) dev->cache; -+ -+ if (dev->cache) -+ memset(dev->cache, 0, cache_bytes); -+ -+ for (i = 0; i < dev->param.n_caches && buf; i++) { -+ dev->cache[i].object = NULL; -+ dev->cache[i].last_use = 0; -+ dev->cache[i].dirty = 0; -+ dev->cache[i].data = buf = -+ kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); -+ } -+ if (!buf) -+ init_failed = 1; -+ -+ dev->cache_last_use = 0; -+ } -+ -+ dev->cache_hits = 0; -+ -+ if (!init_failed) { -+ dev->gc_cleanup_list = -+ kmalloc(dev->param.chunks_per_block * sizeof(u32), -+ GFP_NOFS); -+ if (!dev->gc_cleanup_list) -+ init_failed = 1; -+ } -+ -+ if (dev->param.is_yaffs2) -+ dev->param.use_header_file_size = 1; -+ -+ if (!init_failed && !yaffs_init_blocks(dev)) -+ init_failed = 1; -+ -+ yaffs_init_tnodes_and_objs(dev); -+ -+ if (!init_failed && !yaffs_create_initial_dir(dev)) -+ init_failed = 1; -+ -+ if (!init_failed) { -+ /* Now scan the flash. */ -+ if (dev->param.is_yaffs2) { -+ if (yaffs2_checkpt_restore(dev)) { -+ yaffs_check_obj_details_loaded(dev->root_dir); -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT, -+ "yaffs: restored from checkpoint" -+ ); -+ } else { -+ -+ /* Clean up the mess caused by an aborted checkpoint load -+ * and scan backwards. -+ */ -+ yaffs_deinit_blocks(dev); -+ -+ yaffs_deinit_tnodes_and_objs(dev); -+ -+ dev->n_erased_blocks = 0; -+ dev->n_free_chunks = 0; -+ dev->alloc_block = -1; -+ dev->alloc_page = -1; -+ dev->n_deleted_files = 0; -+ dev->n_unlinked_files = 0; -+ dev->n_bg_deletions = 0; -+ -+ if (!init_failed && !yaffs_init_blocks(dev)) -+ init_failed = 1; -+ -+ yaffs_init_tnodes_and_objs(dev); -+ -+ if (!init_failed -+ && !yaffs_create_initial_dir(dev)) -+ init_failed = 1; -+ -+ if (!init_failed && !yaffs2_scan_backwards(dev)) -+ init_failed = 1; -+ } -+ } else if (!yaffs1_scan(dev)) { -+ init_failed = 1; -+ } -+ -+ yaffs_strip_deleted_objs(dev); -+ yaffs_fix_hanging_objs(dev); -+ if (dev->param.empty_lost_n_found) -+ yaffs_empty_l_n_f(dev); -+ } -+ -+ if (init_failed) { -+ /* Clean up the mess */ -+ yaffs_trace(YAFFS_TRACE_TRACING, -+ "yaffs: yaffs_guts_initialise() aborted."); -+ -+ yaffs_deinitialise(dev); -+ return YAFFS_FAIL; -+ } -+ -+ /* Zero out stats */ -+ dev->n_page_reads = 0; -+ dev->n_page_writes = 0; -+ dev->n_erasures = 0; -+ dev->n_gc_copies = 0; -+ dev->n_retired_writes = 0; -+ -+ dev->n_retired_blocks = 0; -+ -+ yaffs_verify_free_chunks(dev); -+ yaffs_verify_blocks(dev); -+ -+ /* Clean up any aborted checkpoint data */ -+ if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0) -+ yaffs2_checkpt_invalidate(dev); -+ -+ yaffs_trace(YAFFS_TRACE_TRACING, -+ "yaffs: yaffs_guts_initialise() done."); -+ return YAFFS_OK; -+ -+} -+ -+void yaffs_deinitialise(struct yaffs_dev *dev) -+{ -+ if (dev->is_mounted) { -+ int i; -+ -+ yaffs_deinit_blocks(dev); -+ yaffs_deinit_tnodes_and_objs(dev); -+ if (dev->param.n_caches > 0 && dev->cache) { -+ -+ for (i = 0; i < dev->param.n_caches; i++) { -+ if (dev->cache[i].data) -+ kfree(dev->cache[i].data); -+ dev->cache[i].data = NULL; -+ } -+ -+ kfree(dev->cache); -+ dev->cache = NULL; -+ } -+ -+ kfree(dev->gc_cleanup_list); -+ -+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) -+ kfree(dev->temp_buffer[i].buffer); -+ -+ dev->is_mounted = 0; -+ -+ if (dev->param.deinitialise_flash_fn) -+ dev->param.deinitialise_flash_fn(dev); -+ } -+} -+ -+int yaffs_count_free_chunks(struct yaffs_dev *dev) -+{ -+ int n_free = 0; -+ int b; -+ -+ struct yaffs_block_info *blk; -+ -+ blk = dev->block_info; -+ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { -+ switch (blk->block_state) { -+ case YAFFS_BLOCK_STATE_EMPTY: -+ case YAFFS_BLOCK_STATE_ALLOCATING: -+ case YAFFS_BLOCK_STATE_COLLECTING: -+ case YAFFS_BLOCK_STATE_FULL: -+ n_free += -+ (dev->param.chunks_per_block - blk->pages_in_use + -+ blk->soft_del_pages); -+ break; -+ default: -+ break; -+ } -+ blk++; -+ } -+ -+ return n_free; -+} -+ -+int yaffs_get_n_free_chunks(struct yaffs_dev *dev) -+{ -+ /* This is what we report to the outside world */ -+ -+ int n_free; -+ int n_dirty_caches; -+ int blocks_for_checkpt; -+ int i; -+ -+ n_free = dev->n_free_chunks; -+ n_free += dev->n_deleted_files; -+ -+ /* Now count the number of dirty chunks in the cache and subtract those */ -+ -+ for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) { -+ if (dev->cache[i].dirty) -+ n_dirty_caches++; -+ } -+ -+ n_free -= n_dirty_caches; -+ -+ n_free -= -+ ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block); -+ -+ /* Now we figure out how much to reserve for the checkpoint and report that... */ -+ blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev); -+ -+ n_free -= (blocks_for_checkpt * dev->param.chunks_per_block); -+ -+ if (n_free < 0) -+ n_free = 0; -+ -+ return n_free; -+ -+} -diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h -new file mode 100644 -index 00000000..307eba28 ---- /dev/null -+++ b/fs/yaffs2/yaffs_guts.h -@@ -0,0 +1,915 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_GUTS_H__ -+#define __YAFFS_GUTS_H__ -+ -+#include "yportenv.h" -+ -+#define YAFFS_OK 1 -+#define YAFFS_FAIL 0 -+ -+/* Give us a Y=0x59, -+ * Give us an A=0x41, -+ * Give us an FF=0xFF -+ * Give us an S=0x53 -+ * And what have we got... -+ */ -+#define YAFFS_MAGIC 0x5941FF53 -+ -+#define YAFFS_NTNODES_LEVEL0 16 -+#define YAFFS_TNODES_LEVEL0_BITS 4 -+#define YAFFS_TNODES_LEVEL0_MASK 0xf -+ -+#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) -+#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) -+#define YAFFS_TNODES_INTERNAL_MASK 0x7 -+#define YAFFS_TNODES_MAX_LEVEL 6 -+ -+#ifndef CONFIG_YAFFS_NO_YAFFS1 -+#define YAFFS_BYTES_PER_SPARE 16 -+#define YAFFS_BYTES_PER_CHUNK 512 -+#define YAFFS_CHUNK_SIZE_SHIFT 9 -+#define YAFFS_CHUNKS_PER_BLOCK 32 -+#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) -+#endif -+ -+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 -+#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 -+ -+#define YAFFS_MAX_CHUNK_ID 0x000FFFFF -+ -+#define YAFFS_ALLOCATION_NOBJECTS 100 -+#define YAFFS_ALLOCATION_NTNODES 100 -+#define YAFFS_ALLOCATION_NLINKS 100 -+ -+#define YAFFS_NOBJECT_BUCKETS 256 -+ -+#define YAFFS_OBJECT_SPACE 0x40000 -+#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1) -+ -+#define YAFFS_CHECKPOINT_VERSION 4 -+ -+#ifdef CONFIG_YAFFS_UNICODE -+#define YAFFS_MAX_NAME_LENGTH 127 -+#define YAFFS_MAX_ALIAS_LENGTH 79 -+#else -+#define YAFFS_MAX_NAME_LENGTH 255 -+#define YAFFS_MAX_ALIAS_LENGTH 159 -+#endif -+ -+#define YAFFS_SHORT_NAME_LENGTH 15 -+ -+/* Some special object ids for pseudo objects */ -+#define YAFFS_OBJECTID_ROOT 1 -+#define YAFFS_OBJECTID_LOSTNFOUND 2 -+#define YAFFS_OBJECTID_UNLINKED 3 -+#define YAFFS_OBJECTID_DELETED 4 -+ -+/* Pseudo object ids for checkpointing */ -+#define YAFFS_OBJECTID_SB_HEADER 0x10 -+#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 -+#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 -+ -+#define YAFFS_MAX_SHORT_OP_CACHES 20 -+ -+#define YAFFS_N_TEMP_BUFFERS 6 -+ -+/* We limit the number attempts at sucessfully saving a chunk of data. -+ * Small-page devices have 32 pages per block; large-page devices have 64. -+ * Default to something in the order of 5 to 10 blocks worth of chunks. -+ */ -+#define YAFFS_WR_ATTEMPTS (5*64) -+ -+/* Sequence numbers are used in YAFFS2 to determine block allocation order. -+ * The range is limited slightly to help distinguish bad numbers from good. -+ * This also allows us to perhaps in the future use special numbers for -+ * special purposes. -+ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, -+ * and is a larger number than the lifetime of a 2GB device. -+ */ -+#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 -+#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00 -+ -+/* Special sequence number for bad block that failed to be marked bad */ -+#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000 -+ -+/* ChunkCache is used for short read/write operations.*/ -+struct yaffs_cache { -+ struct yaffs_obj *object; -+ int chunk_id; -+ int last_use; -+ int dirty; -+ int n_bytes; /* Only valid if the cache is dirty */ -+ int locked; /* Can't push out or flush while locked. */ -+ u8 *data; -+}; -+ -+/* Tags structures in RAM -+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise -+ * the structure size will get blown out. -+ */ -+ -+#ifndef CONFIG_YAFFS_NO_YAFFS1 -+struct yaffs_tags { -+ unsigned chunk_id:20; -+ unsigned serial_number:2; -+ unsigned n_bytes_lsb:10; -+ unsigned obj_id:18; -+ unsigned ecc:12; -+ unsigned n_bytes_msb:2; -+}; -+ -+union yaffs_tags_union { -+ struct yaffs_tags as_tags; -+ u8 as_bytes[8]; -+}; -+ -+#endif -+ -+/* Stuff used for extended tags in YAFFS2 */ -+ -+enum yaffs_ecc_result { -+ YAFFS_ECC_RESULT_UNKNOWN, -+ YAFFS_ECC_RESULT_NO_ERROR, -+ YAFFS_ECC_RESULT_FIXED, -+ YAFFS_ECC_RESULT_UNFIXED -+}; -+ -+enum yaffs_obj_type { -+ YAFFS_OBJECT_TYPE_UNKNOWN, -+ YAFFS_OBJECT_TYPE_FILE, -+ YAFFS_OBJECT_TYPE_SYMLINK, -+ YAFFS_OBJECT_TYPE_DIRECTORY, -+ YAFFS_OBJECT_TYPE_HARDLINK, -+ YAFFS_OBJECT_TYPE_SPECIAL -+}; -+ -+#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL -+ -+struct yaffs_ext_tags { -+ -+ unsigned validity0; -+ unsigned chunk_used; /* Status of the chunk: used or unused */ -+ unsigned obj_id; /* If 0 then this is not part of an object (unused) */ -+ unsigned chunk_id; /* If 0 then this is a header, else a data chunk */ -+ unsigned n_bytes; /* Only valid for data chunks */ -+ -+ /* The following stuff only has meaning when we read */ -+ enum yaffs_ecc_result ecc_result; -+ unsigned block_bad; -+ -+ /* YAFFS 1 stuff */ -+ unsigned is_deleted; /* The chunk is marked deleted */ -+ unsigned serial_number; /* Yaffs1 2-bit serial number */ -+ -+ /* YAFFS2 stuff */ -+ unsigned seq_number; /* The sequence number of this block */ -+ -+ /* Extra info if this is an object header (YAFFS2 only) */ -+ -+ unsigned extra_available; /* There is extra info available if this is not zero */ -+ unsigned extra_parent_id; /* The parent object */ -+ unsigned extra_is_shrink; /* Is it a shrink header? */ -+ unsigned extra_shadows; /* Does this shadow another object? */ -+ -+ enum yaffs_obj_type extra_obj_type; /* What object type? */ -+ -+ unsigned extra_length; /* Length if it is a file */ -+ unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */ -+ -+ unsigned validity1; -+ -+}; -+ -+/* Spare structure for YAFFS1 */ -+struct yaffs_spare { -+ u8 tb0; -+ u8 tb1; -+ u8 tb2; -+ u8 tb3; -+ u8 page_status; /* set to 0 to delete the chunk */ -+ u8 block_status; -+ u8 tb4; -+ u8 tb5; -+ u8 ecc1[3]; -+ u8 tb6; -+ u8 tb7; -+ u8 ecc2[3]; -+}; -+ -+/*Special structure for passing through to mtd */ -+struct yaffs_nand_spare { -+ struct yaffs_spare spare; -+ int eccres1; -+ int eccres2; -+}; -+ -+/* Block data in RAM */ -+ -+enum yaffs_block_state { -+ YAFFS_BLOCK_STATE_UNKNOWN = 0, -+ -+ YAFFS_BLOCK_STATE_SCANNING, -+ /* Being scanned */ -+ -+ YAFFS_BLOCK_STATE_NEEDS_SCANNING, -+ /* The block might have something on it (ie it is allocating or full, perhaps empty) -+ * but it needs to be scanned to determine its true state. -+ * This state is only valid during scanning. -+ * NB We tolerate empty because the pre-scanner might be incapable of deciding -+ * However, if this state is returned on a YAFFS2 device, then we expect a sequence number -+ */ -+ -+ YAFFS_BLOCK_STATE_EMPTY, -+ /* This block is empty */ -+ -+ YAFFS_BLOCK_STATE_ALLOCATING, -+ /* This block is partially allocated. -+ * At least one page holds valid data. -+ * This is the one currently being used for page -+ * allocation. Should never be more than one of these. -+ * If a block is only partially allocated at mount it is treated as full. -+ */ -+ -+ YAFFS_BLOCK_STATE_FULL, -+ /* All the pages in this block have been allocated. -+ * If a block was only partially allocated when mounted we treat -+ * it as fully allocated. -+ */ -+ -+ YAFFS_BLOCK_STATE_DIRTY, -+ /* The block was full and now all chunks have been deleted. -+ * Erase me, reuse me. -+ */ -+ -+ YAFFS_BLOCK_STATE_CHECKPOINT, -+ /* This block is assigned to holding checkpoint data. */ -+ -+ YAFFS_BLOCK_STATE_COLLECTING, -+ /* This block is being garbage collected */ -+ -+ YAFFS_BLOCK_STATE_DEAD -+ /* This block has failed and is not in use */ -+}; -+ -+#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) -+ -+struct yaffs_block_info { -+ -+ int soft_del_pages:10; /* number of soft deleted pages */ -+ int pages_in_use:10; /* number of pages in use */ -+ unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ -+ u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */ -+ /* and retire the block. */ -+ u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */ -+ u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block. -+ It should be prioritised for GC */ -+ u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ -+ -+#ifdef CONFIG_YAFFS_YAFFS2 -+ u32 has_shrink_hdr:1; /* This block has at least one shrink object header */ -+ u32 seq_number; /* block sequence number for yaffs2 */ -+#endif -+ -+}; -+ -+/* -------------------------- Object structure -------------------------------*/ -+/* This is the object structure as stored on NAND */ -+ -+struct yaffs_obj_hdr { -+ enum yaffs_obj_type type; -+ -+ /* Apply to everything */ -+ int parent_obj_id; -+ u16 sum_no_longer_used; /* checksum of name. No longer used */ -+ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ /* The following apply to directories, files, symlinks - not hard links */ -+ u32 yst_mode; /* protection */ -+ -+ u32 yst_uid; -+ u32 yst_gid; -+ u32 yst_atime; -+ u32 yst_mtime; -+ u32 yst_ctime; -+ -+ /* File size applies to files only */ -+ int file_size; -+ -+ /* Equivalent object id applies to hard links only. */ -+ int equiv_id; -+ -+ /* Alias is for symlinks only. */ -+ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; -+ -+ u32 yst_rdev; /* device stuff for block and char devices (major/min) */ -+ -+ u32 win_ctime[2]; -+ u32 win_atime[2]; -+ u32 win_mtime[2]; -+ -+ u32 inband_shadowed_obj_id; -+ u32 inband_is_shrink; -+ -+ u32 reserved[2]; -+ int shadows_obj; /* This object header shadows the specified object if > 0 */ -+ -+ /* is_shrink applies to object headers written when we shrink the file (ie resize) */ -+ u32 is_shrink; -+ -+}; -+ -+/*--------------------------- Tnode -------------------------- */ -+ -+struct yaffs_tnode { -+ struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL]; -+}; -+ -+/*------------------------ Object -----------------------------*/ -+/* An object can be one of: -+ * - a directory (no data, has children links -+ * - a regular file (data.... not prunes :->). -+ * - a symlink [symbolic link] (the alias). -+ * - a hard link -+ */ -+ -+struct yaffs_file_var { -+ u32 file_size; -+ u32 scanned_size; -+ u32 shrink_size; -+ int top_level; -+ struct yaffs_tnode *top; -+}; -+ -+struct yaffs_dir_var { -+ struct list_head children; /* list of child links */ -+ struct list_head dirty; /* Entry for list of dirty directories */ -+}; -+ -+struct yaffs_symlink_var { -+ YCHAR *alias; -+}; -+ -+struct yaffs_hardlink_var { -+ struct yaffs_obj *equiv_obj; -+ u32 equiv_id; -+}; -+ -+union yaffs_obj_var { -+ struct yaffs_file_var file_variant; -+ struct yaffs_dir_var dir_variant; -+ struct yaffs_symlink_var symlink_variant; -+ struct yaffs_hardlink_var hardlink_variant; -+}; -+ -+struct yaffs_obj { -+ u8 deleted:1; /* This should only apply to unlinked files. */ -+ u8 soft_del:1; /* it has also been soft deleted */ -+ u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory. */ -+ u8 fake:1; /* A fake object has no presence on NAND. */ -+ u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */ -+ u8 unlink_allowed:1; -+ u8 dirty:1; /* the object needs to be written to flash */ -+ u8 valid:1; /* When the file system is being loaded up, this -+ * object might be created before the data -+ * is available (ie. file data records appear before the header). -+ */ -+ u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */ -+ -+ u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is -+ * still in the inode cache. Free of object is defered. -+ * until the inode is released. -+ */ -+ u8 being_created:1; /* This object is still being created so skip some checks. */ -+ u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */ -+ -+ u8 xattr_known:1; /* We know if this has object has xattribs or not. */ -+ u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */ -+ -+ u8 serial; /* serial number of chunk in NAND. Cached here */ -+ u16 sum; /* sum of the name to speed searching */ -+ -+ struct yaffs_dev *my_dev; /* The device I'm on */ -+ -+ struct list_head hash_link; /* list of objects in this hash bucket */ -+ -+ struct list_head hard_links; /* all the equivalent hard linked objects */ -+ -+ /* directory structure stuff */ -+ /* also used for linking up the free list */ -+ struct yaffs_obj *parent; -+ struct list_head siblings; -+ -+ /* Where's my object header in NAND? */ -+ int hdr_chunk; -+ -+ int n_data_chunks; /* Number of data chunks attached to the file. */ -+ -+ u32 obj_id; /* the object id value */ -+ -+ u32 yst_mode; -+ -+#ifndef CONFIG_YAFFS_NO_SHORT_NAMES -+ YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; -+#endif -+ -+#ifdef CONFIG_YAFFS_WINCE -+ u32 win_ctime[2]; -+ u32 win_mtime[2]; -+ u32 win_atime[2]; -+#else -+ u32 yst_uid; -+ u32 yst_gid; -+ u32 yst_atime; -+ u32 yst_mtime; -+ u32 yst_ctime; -+#endif -+ -+ u32 yst_rdev; -+ -+ void *my_inode; -+ -+ enum yaffs_obj_type variant_type; -+ -+ union yaffs_obj_var variant; -+ -+}; -+ -+struct yaffs_obj_bucket { -+ struct list_head list; -+ int count; -+}; -+ -+/* yaffs_checkpt_obj holds the definition of an object as dumped -+ * by checkpointing. -+ */ -+ -+struct yaffs_checkpt_obj { -+ int struct_type; -+ u32 obj_id; -+ u32 parent_id; -+ int hdr_chunk; -+ enum yaffs_obj_type variant_type:3; -+ u8 deleted:1; -+ u8 soft_del:1; -+ u8 unlinked:1; -+ u8 fake:1; -+ u8 rename_allowed:1; -+ u8 unlink_allowed:1; -+ u8 serial; -+ int n_data_chunks; -+ u32 size_or_equiv_obj; -+}; -+ -+/*--------------------- Temporary buffers ---------------- -+ * -+ * These are chunk-sized working buffers. Each device has a few -+ */ -+ -+struct yaffs_buffer { -+ u8 *buffer; -+ int line; /* track from whence this buffer was allocated */ -+ int max_line; -+}; -+ -+/*----------------- Device ---------------------------------*/ -+ -+struct yaffs_param { -+ const YCHAR *name; -+ -+ /* -+ * Entry parameters set up way early. Yaffs sets up the rest. -+ * The structure should be zeroed out before use so that unused -+ * and defualt values are zero. -+ */ -+ -+ int inband_tags; /* Use unband tags */ -+ u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */ -+ int chunks_per_block; /* does not need to be a power of 2 */ -+ int spare_bytes_per_chunk; /* spare area size */ -+ int start_block; /* Start block we're allowed to use */ -+ int end_block; /* End block we're allowed to use */ -+ int n_reserved_blocks; /* We want this tuneable so that we can reduce */ -+ /* reserved blocks on NOR and RAM. */ -+ -+ int n_caches; /* If <= 0, then short op caching is disabled, else -+ * the number of short op caches (don't use too many). -+ * 10 to 20 is a good bet. -+ */ -+ int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */ -+ int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */ -+ -+ int is_yaffs2; /* Use yaffs2 mode on this device */ -+ -+ int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ -+ -+ int refresh_period; /* How often we should check to do a block refresh */ -+ -+ /* Checkpoint control. Can be set before or after initialisation */ -+ u8 skip_checkpt_rd; -+ u8 skip_checkpt_wr; -+ -+ int enable_xattr; /* Enable xattribs */ -+ -+ /* NAND access functions (Must be set before calling YAFFS) */ -+ -+ int (*write_chunk_fn) (struct yaffs_dev * dev, -+ int nand_chunk, const u8 * data, -+ const struct yaffs_spare * spare); -+ int (*read_chunk_fn) (struct yaffs_dev * dev, -+ int nand_chunk, u8 * data, -+ struct yaffs_spare * spare); -+ int (*erase_fn) (struct yaffs_dev * dev, int flash_block); -+ int (*initialise_flash_fn) (struct yaffs_dev * dev); -+ int (*deinitialise_flash_fn) (struct yaffs_dev * dev); -+ -+#ifdef CONFIG_YAFFS_YAFFS2 -+ int (*write_chunk_tags_fn) (struct yaffs_dev * dev, -+ int nand_chunk, const u8 * data, -+ const struct yaffs_ext_tags * tags); -+ int (*read_chunk_tags_fn) (struct yaffs_dev * dev, -+ int nand_chunk, u8 * data, -+ struct yaffs_ext_tags * tags); -+ int (*bad_block_fn) (struct yaffs_dev * dev, int block_no); -+ int (*query_block_fn) (struct yaffs_dev * dev, int block_no, -+ enum yaffs_block_state * state, -+ u32 * seq_number); -+#endif -+ -+ /* The remove_obj_fn function must be supplied by OS flavours that -+ * need it. -+ * yaffs direct uses it to implement the faster readdir. -+ * Linux uses it to protect the directory during unlocking. -+ */ -+ void (*remove_obj_fn) (struct yaffs_obj * obj); -+ -+ /* Callback to mark the superblock dirty */ -+ void (*sb_dirty_fn) (struct yaffs_dev * dev); -+ -+ /* Callback to control garbage collection. */ -+ unsigned (*gc_control) (struct yaffs_dev * dev); -+ -+ /* Debug control flags. Don't use unless you know what you're doing */ -+ int use_header_file_size; /* Flag to determine if we should use file sizes from the header */ -+ int disable_lazy_load; /* Disable lazy loading on this device */ -+ int wide_tnodes_disabled; /* Set to disable wide tnodes */ -+ int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */ -+ -+ int defered_dir_update; /* Set to defer directory updates */ -+ -+#ifdef CONFIG_YAFFS_AUTO_UNICODE -+ int auto_unicode; -+#endif -+ int always_check_erased; /* Force chunk erased check always on */ -+}; -+ -+struct yaffs_dev { -+ struct yaffs_param param; -+ -+ /* Context storage. Holds extra OS specific data for this device */ -+ -+ void *os_context; -+ void *driver_context; -+ -+ struct list_head dev_list; -+ -+ /* Runtime parameters. Set up by YAFFS. */ -+ int data_bytes_per_chunk; -+ -+ /* Non-wide tnode stuff */ -+ u16 chunk_grp_bits; /* Number of bits that need to be resolved if -+ * the tnodes are not wide enough. -+ */ -+ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ -+ -+ /* Stuff to support wide tnodes */ -+ u32 tnode_width; -+ u32 tnode_mask; -+ u32 tnode_size; -+ -+ /* Stuff for figuring out file offset to chunk conversions */ -+ u32 chunk_shift; /* Shift value */ -+ u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */ -+ u32 chunk_mask; /* Mask to use for power-of-2 case */ -+ -+ int is_mounted; -+ int read_only; -+ int is_checkpointed; -+ -+ /* Stuff to support block offsetting to support start block zero */ -+ int internal_start_block; -+ int internal_end_block; -+ int block_offset; -+ int chunk_offset; -+ -+ /* Runtime checkpointing stuff */ -+ int checkpt_page_seq; /* running sequence number of checkpoint pages */ -+ int checkpt_byte_count; -+ int checkpt_byte_offs; -+ u8 *checkpt_buffer; -+ int checkpt_open_write; -+ int blocks_in_checkpt; -+ int checkpt_cur_chunk; -+ int checkpt_cur_block; -+ int checkpt_next_block; -+ int *checkpt_block_list; -+ int checkpt_max_blocks; -+ u32 checkpt_sum; -+ u32 checkpt_xor; -+ -+ int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */ -+ -+ /* Block Info */ -+ struct yaffs_block_info *block_info; -+ u8 *chunk_bits; /* bitmap of chunks in use */ -+ unsigned block_info_alt:1; /* was allocated using alternative strategy */ -+ unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */ -+ int chunk_bit_stride; /* Number of bytes of chunk_bits per block. -+ * Must be consistent with chunks_per_block. -+ */ -+ -+ int n_erased_blocks; -+ int alloc_block; /* Current block being allocated off */ -+ u32 alloc_page; -+ int alloc_block_finder; /* Used to search for next allocation block */ -+ -+ /* Object and Tnode memory management */ -+ void *allocator; -+ int n_obj; -+ int n_tnodes; -+ -+ int n_hardlinks; -+ -+ struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; -+ u32 bucket_finder; -+ -+ int n_free_chunks; -+ -+ /* Garbage collection control */ -+ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ -+ u32 n_clean_ups; -+ -+ unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */ -+ unsigned gc_disable; -+ unsigned gc_block_finder; -+ unsigned gc_dirtiest; -+ unsigned gc_pages_in_use; -+ unsigned gc_not_done; -+ unsigned gc_block; -+ unsigned gc_chunk; -+ unsigned gc_skip; -+ -+ /* Special directories */ -+ struct yaffs_obj *root_dir; -+ struct yaffs_obj *lost_n_found; -+ -+ /* Buffer areas for storing data to recover from write failures TODO -+ * u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; -+ * struct yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK]; -+ */ -+ -+ int buffered_block; /* Which block is buffered here? */ -+ int doing_buffered_block_rewrite; -+ -+ struct yaffs_cache *cache; -+ int cache_last_use; -+ -+ /* Stuff for background deletion and unlinked files. */ -+ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted files live. */ -+ struct yaffs_obj *del_dir; /* Directory where deleted objects are sent to disappear. */ -+ struct yaffs_obj *unlinked_deletion; /* Current file being background deleted. */ -+ int n_deleted_files; /* Count of files awaiting deletion; */ -+ int n_unlinked_files; /* Count of unlinked files. */ -+ int n_bg_deletions; /* Count of background deletions. */ -+ -+ /* Temporary buffer management */ -+ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; -+ int max_temp; -+ int temp_in_use; -+ int unmanaged_buffer_allocs; -+ int unmanaged_buffer_deallocs; -+ -+ /* yaffs2 runtime stuff */ -+ unsigned seq_number; /* Sequence number of currently allocating block */ -+ unsigned oldest_dirty_seq; -+ unsigned oldest_dirty_block; -+ -+ /* Block refreshing */ -+ int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */ -+ -+ /* Dirty directory handling */ -+ struct list_head dirty_dirs; /* List of dirty directories */ -+ -+ /* Statistcs */ -+ u32 n_page_writes; -+ u32 n_page_reads; -+ u32 n_erasures; -+ u32 n_erase_failures; -+ u32 n_gc_copies; -+ u32 all_gcs; -+ u32 passive_gc_count; -+ u32 oldest_dirty_gc_count; -+ u32 n_gc_blocks; -+ u32 bg_gcs; -+ u32 n_retired_writes; -+ u32 n_retired_blocks; -+ u32 n_ecc_fixed; -+ u32 n_ecc_unfixed; -+ u32 n_tags_ecc_fixed; -+ u32 n_tags_ecc_unfixed; -+ u32 n_deletions; -+ u32 n_unmarked_deletions; -+ u32 refresh_count; -+ u32 cache_hits; -+ -+}; -+ -+/* The CheckpointDevice structure holds the device information that changes at runtime and -+ * must be preserved over unmount/mount cycles. -+ */ -+struct yaffs_checkpt_dev { -+ int struct_type; -+ int n_erased_blocks; -+ int alloc_block; /* Current block being allocated off */ -+ u32 alloc_page; -+ int n_free_chunks; -+ -+ int n_deleted_files; /* Count of files awaiting deletion; */ -+ int n_unlinked_files; /* Count of unlinked files. */ -+ int n_bg_deletions; /* Count of background deletions. */ -+ -+ /* yaffs2 runtime stuff */ -+ unsigned seq_number; /* Sequence number of currently allocating block */ -+ -+}; -+ -+struct yaffs_checkpt_validity { -+ int struct_type; -+ u32 magic; -+ u32 version; -+ u32 head; -+}; -+ -+struct yaffs_shadow_fixer { -+ int obj_id; -+ int shadowed_id; -+ struct yaffs_shadow_fixer *next; -+}; -+ -+/* Structure for doing xattr modifications */ -+struct yaffs_xattr_mod { -+ int set; /* If 0 then this is a deletion */ -+ const YCHAR *name; -+ const void *data; -+ int size; -+ int flags; -+ int result; -+}; -+ -+/*----------------------- YAFFS Functions -----------------------*/ -+ -+int yaffs_guts_initialise(struct yaffs_dev *dev); -+void yaffs_deinitialise(struct yaffs_dev *dev); -+ -+int yaffs_get_n_free_chunks(struct yaffs_dev *dev); -+ -+int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, -+ struct yaffs_obj *new_dir, const YCHAR * new_name); -+ -+int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name); -+int yaffs_del_obj(struct yaffs_obj *obj); -+ -+int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size); -+int yaffs_get_obj_length(struct yaffs_obj *obj); -+int yaffs_get_obj_inode(struct yaffs_obj *obj); -+unsigned yaffs_get_obj_type(struct yaffs_obj *obj); -+int yaffs_get_obj_link_count(struct yaffs_obj *obj); -+ -+/* File operations */ -+int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset, -+ int n_bytes); -+int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset, -+ int n_bytes, int write_trhrough); -+int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size); -+ -+struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, -+ const YCHAR * name, u32 mode, u32 uid, -+ u32 gid); -+ -+int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync); -+ -+/* Flushing and checkpointing */ -+void yaffs_flush_whole_cache(struct yaffs_dev *dev); -+ -+int yaffs_checkpoint_save(struct yaffs_dev *dev); -+int yaffs_checkpoint_restore(struct yaffs_dev *dev); -+ -+/* Directory operations */ -+struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR * name, -+ u32 mode, u32 uid, u32 gid); -+struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir, -+ const YCHAR * name); -+struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number); -+ -+/* Link operations */ -+struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name, -+ struct yaffs_obj *equiv_obj); -+ -+struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj); -+ -+/* Symlink operations */ -+struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, -+ const YCHAR * name, u32 mode, u32 uid, -+ u32 gid, const YCHAR * alias); -+YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj); -+ -+/* Special inodes (fifos, sockets and devices) */ -+struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, -+ const YCHAR * name, u32 mode, u32 uid, -+ u32 gid, u32 rdev); -+ -+int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name, -+ const void *value, int size, int flags); -+int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value, -+ int size); -+int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); -+int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name); -+ -+/* Special directories */ -+struct yaffs_obj *yaffs_root(struct yaffs_dev *dev); -+struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev); -+ -+void yaffs_handle_defered_free(struct yaffs_obj *obj); -+ -+void yaffs_update_dirty_dirs(struct yaffs_dev *dev); -+ -+int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency); -+ -+/* Debug dump */ -+int yaffs_dump_obj(struct yaffs_obj *obj); -+ -+void yaffs_guts_test(struct yaffs_dev *dev); -+ -+/* A few useful functions to be used within the core files*/ -+void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, -+ int lyn); -+int yaffs_check_ff(u8 * buffer, int n_bytes); -+void yaffs_handle_chunk_error(struct yaffs_dev *dev, -+ struct yaffs_block_info *bi); -+ -+u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev, int line_no); -+void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 * buffer, int line_no); -+ -+struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, -+ int number, -+ enum yaffs_obj_type type); -+int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, -+ int nand_chunk, int in_scan); -+void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name); -+void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, -+ const struct yaffs_obj_hdr *oh); -+void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj); -+YCHAR *yaffs_clone_str(const YCHAR * str); -+void yaffs_link_fixup(struct yaffs_dev *dev, struct yaffs_obj *hard_list); -+void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no); -+int yaffs_update_oh(struct yaffs_obj *in, const YCHAR * name, -+ int force, int is_shrink, int shadows, -+ struct yaffs_xattr_mod *xop); -+void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, -+ int backward_scanning); -+int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks); -+struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev); -+struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, -+ struct yaffs_file_var *file_struct, -+ u32 chunk_id, -+ struct yaffs_tnode *passed_tn); -+ -+int yaffs_do_file_wr(struct yaffs_obj *in, const u8 * buffer, loff_t offset, -+ int n_bytes, int write_trhrough); -+void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size); -+void yaffs_skip_rest_of_block(struct yaffs_dev *dev); -+ -+int yaffs_count_free_chunks(struct yaffs_dev *dev); -+ -+struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, -+ struct yaffs_file_var *file_struct, -+ u32 chunk_id); -+ -+u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, -+ unsigned pos); -+ -+int yaffs_is_non_empty_dir(struct yaffs_obj *obj); -+#endif -diff --git a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h -new file mode 100644 -index 00000000..3b508cbc ---- /dev/null -+++ b/fs/yaffs2/yaffs_linux.h -@@ -0,0 +1,41 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_LINUX_H__ -+#define __YAFFS_LINUX_H__ -+ -+#include "yportenv.h" -+ -+struct yaffs_linux_context { -+ struct list_head context_list; /* List of these we have mounted */ -+ struct yaffs_dev *dev; -+ struct super_block *super; -+ struct task_struct *bg_thread; /* Background thread for this device */ -+ int bg_running; -+ struct mutex gross_lock; /* Gross locking mutex*/ -+ u8 *spare_buffer; /* For mtdif2 use. Don't know the size of the buffer -+ * at compile time so we have to allocate it. -+ */ -+ struct list_head search_contexts; -+ void (*put_super_fn) (struct super_block * sb); -+ -+ struct task_struct *readdir_process; -+ unsigned mount_id; -+}; -+ -+#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context)) -+#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context)) -+ -+#endif -diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c -new file mode 100644 -index 00000000..7cf53b3d ---- /dev/null -+++ b/fs/yaffs2/yaffs_mtdif.c -@@ -0,0 +1,54 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yportenv.h" -+ -+#include "yaffs_mtdif.h" -+ -+#include "linux/mtd/mtd.h" -+#include "linux/types.h" -+#include "linux/time.h" -+#include "linux/mtd/nand.h" -+ -+#include "yaffs_linux.h" -+ -+int nandmtd_erase_block(struct yaffs_dev *dev, int block_no) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ u32 addr = -+ ((loff_t) block_no) * dev->param.total_bytes_per_chunk -+ * dev->param.chunks_per_block; -+ struct erase_info ei; -+ -+ int retval = 0; -+ -+ ei.mtd = mtd; -+ ei.addr = addr; -+ ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; -+ ei.time = 1000; -+ ei.retries = 2; -+ ei.callback = NULL; -+ ei.priv = (u_long) dev; -+ -+ retval = mtd->erase(mtd, &ei); -+ -+ if (retval == 0) -+ return YAFFS_OK; -+ else -+ return YAFFS_FAIL; -+} -+ -+int nandmtd_initialise(struct yaffs_dev *dev) -+{ -+ return YAFFS_OK; -+} -diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h -new file mode 100644 -index 00000000..66650741 ---- /dev/null -+++ b/fs/yaffs2/yaffs_mtdif.h -@@ -0,0 +1,23 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_MTDIF_H__ -+#define __YAFFS_MTDIF_H__ -+ -+#include "yaffs_guts.h" -+ -+int nandmtd_erase_block(struct yaffs_dev *dev, int block_no); -+int nandmtd_initialise(struct yaffs_dev *dev); -+#endif -diff --git a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c -new file mode 100644 -index 00000000..51083695 ---- /dev/null -+++ b/fs/yaffs2/yaffs_mtdif1.c -@@ -0,0 +1,330 @@ -+/* -+ * YAFFS: Yet another FFS. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+/* -+ * This module provides the interface between yaffs_nand.c and the -+ * MTD API. This version is used when the MTD interface supports the -+ * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, -+ * and we have small-page NAND device. -+ * -+ * These functions are invoked via function pointers in yaffs_nand.c. -+ * This replaces functionality provided by functions in yaffs_mtdif.c -+ * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are -+ * called in yaffs_mtdif.c when the function pointers are NULL. -+ * We assume the MTD layer is performing ECC (use_nand_ecc is true). -+ */ -+ -+#include "yportenv.h" -+#include "yaffs_trace.h" -+#include "yaffs_guts.h" -+#include "yaffs_packedtags1.h" -+#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */ -+#include "yaffs_linux.h" -+ -+#include "linux/kernel.h" -+#include "linux/version.h" -+#include "linux/types.h" -+#include "linux/mtd/mtd.h" -+ -+#ifndef CONFIG_YAFFS_9BYTE_TAGS -+# define YTAG1_SIZE 8 -+#else -+# define YTAG1_SIZE 9 -+#endif -+ -+/* Write a chunk (page) of data to NAND. -+ * -+ * Caller always provides ExtendedTags data which are converted to a more -+ * compact (packed) form for storage in NAND. A mini-ECC runs over the -+ * contents of the tags meta-data; used to valid the tags when read. -+ * -+ * - Pack ExtendedTags to packed_tags1 form -+ * - Compute mini-ECC for packed_tags1 -+ * - Write data and packed tags to NAND. -+ * -+ * Note: Due to the use of the packed_tags1 meta-data which does not include -+ * a full sequence number (as found in the larger packed_tags2 form) it is -+ * necessary for Yaffs to re-write a chunk/page (just once) to mark it as -+ * discarded and dirty. This is not ideal: newer NAND parts are supposed -+ * to be written just once. When Yaffs performs this operation, this -+ * function is called with a NULL data pointer -- calling MTD write_oob -+ * without data is valid usage (2.6.17). -+ * -+ * Any underlying MTD error results in YAFFS_FAIL. -+ * Returns YAFFS_OK or YAFFS_FAIL. -+ */ -+int nandmtd1_write_chunk_tags(struct yaffs_dev *dev, -+ int nand_chunk, const u8 * data, -+ const struct yaffs_ext_tags *etags) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ int chunk_bytes = dev->data_bytes_per_chunk; -+ loff_t addr = ((loff_t) nand_chunk) * chunk_bytes; -+ struct mtd_oob_ops ops; -+ struct yaffs_packed_tags1 pt1; -+ int retval; -+ -+ /* we assume that packed_tags1 and struct yaffs_tags are compatible */ -+ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); -+ compile_time_assertion(sizeof(struct yaffs_tags) == 8); -+ -+ yaffs_pack_tags1(&pt1, etags); -+ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); -+ -+ /* When deleting a chunk, the upper layer provides only skeletal -+ * etags, one with is_deleted set. However, we need to update the -+ * tags, not erase them completely. So we use the NAND write property -+ * that only zeroed-bits stick and set tag bytes to all-ones and -+ * zero just the (not) deleted bit. -+ */ -+#ifndef CONFIG_YAFFS_9BYTE_TAGS -+ if (etags->is_deleted) { -+ memset(&pt1, 0xff, 8); -+ /* clear delete status bit to indicate deleted */ -+ pt1.deleted = 0; -+ } -+#else -+ ((u8 *) & pt1)[8] = 0xff; -+ if (etags->is_deleted) { -+ memset(&pt1, 0xff, 8); -+ /* zero page_status byte to indicate deleted */ -+ ((u8 *) & pt1)[8] = 0; -+ } -+#endif -+ -+ memset(&ops, 0, sizeof(ops)); -+ ops.mode = MTD_OOB_AUTO; -+ ops.len = (data) ? chunk_bytes : 0; -+ ops.ooblen = YTAG1_SIZE; -+ ops.datbuf = (u8 *) data; -+ ops.oobbuf = (u8 *) & pt1; -+ -+ retval = mtd->write_oob(mtd, addr, &ops); -+ if (retval) { -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "write_oob failed, chunk %d, mtd error %d", -+ nand_chunk, retval); -+ } -+ return retval ? YAFFS_FAIL : YAFFS_OK; -+} -+ -+/* Return with empty ExtendedTags but add ecc_result. -+ */ -+static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval) -+{ -+ if (etags) { -+ memset(etags, 0, sizeof(*etags)); -+ etags->ecc_result = ecc_result; -+ } -+ return retval; -+} -+ -+/* Read a chunk (page) from NAND. -+ * -+ * Caller expects ExtendedTags data to be usable even on error; that is, -+ * all members except ecc_result and block_bad are zeroed. -+ * -+ * - Check ECC results for data (if applicable) -+ * - Check for blank/erased block (return empty ExtendedTags if blank) -+ * - Check the packed_tags1 mini-ECC (correct if necessary/possible) -+ * - Convert packed_tags1 to ExtendedTags -+ * - Update ecc_result and block_bad members to refect state. -+ * -+ * Returns YAFFS_OK or YAFFS_FAIL. -+ */ -+int nandmtd1_read_chunk_tags(struct yaffs_dev *dev, -+ int nand_chunk, u8 * data, -+ struct yaffs_ext_tags *etags) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ int chunk_bytes = dev->data_bytes_per_chunk; -+ loff_t addr = ((loff_t) nand_chunk) * chunk_bytes; -+ int eccres = YAFFS_ECC_RESULT_NO_ERROR; -+ struct mtd_oob_ops ops; -+ struct yaffs_packed_tags1 pt1; -+ int retval; -+ int deleted; -+ -+ memset(&ops, 0, sizeof(ops)); -+ ops.mode = MTD_OOB_AUTO; -+ ops.len = (data) ? chunk_bytes : 0; -+ ops.ooblen = YTAG1_SIZE; -+ ops.datbuf = data; -+ ops.oobbuf = (u8 *) & pt1; -+ -+ /* Read page and oob using MTD. -+ * Check status and determine ECC result. -+ */ -+ retval = mtd->read_oob(mtd, addr, &ops); -+ if (retval) { -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "read_oob failed, chunk %d, mtd error %d", -+ nand_chunk, retval); -+ } -+ -+ switch (retval) { -+ case 0: -+ /* no error */ -+ break; -+ -+ case -EUCLEAN: -+ /* MTD's ECC fixed the data */ -+ eccres = YAFFS_ECC_RESULT_FIXED; -+ dev->n_ecc_fixed++; -+ break; -+ -+ case -EBADMSG: -+ /* MTD's ECC could not fix the data */ -+ dev->n_ecc_unfixed++; -+ /* fall into... */ -+ default: -+ rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); -+ etags->block_bad = (mtd->block_isbad) (mtd, addr); -+ return YAFFS_FAIL; -+ } -+ -+ /* Check for a blank/erased chunk. -+ */ -+ if (yaffs_check_ff((u8 *) & pt1, 8)) { -+ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ -+ return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); -+ } -+#ifndef CONFIG_YAFFS_9BYTE_TAGS -+ /* Read deleted status (bit) then return it to it's non-deleted -+ * state before performing tags mini-ECC check. pt1.deleted is -+ * inverted. -+ */ -+ deleted = !pt1.deleted; -+ pt1.deleted = 1; -+#else -+ deleted = (yaffs_count_bits(((u8 *) & pt1)[8]) < 7); -+#endif -+ -+ /* Check the packed tags mini-ECC and correct if necessary/possible. -+ */ -+ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); -+ switch (retval) { -+ case 0: -+ /* no tags error, use MTD result */ -+ break; -+ case 1: -+ /* recovered tags-ECC error */ -+ dev->n_tags_ecc_fixed++; -+ if (eccres == YAFFS_ECC_RESULT_NO_ERROR) -+ eccres = YAFFS_ECC_RESULT_FIXED; -+ break; -+ default: -+ /* unrecovered tags-ECC error */ -+ dev->n_tags_ecc_unfixed++; -+ return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); -+ } -+ -+ /* Unpack the tags to extended form and set ECC result. -+ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] -+ */ -+ pt1.should_be_ff = 0xFFFFFFFF; -+ yaffs_unpack_tags1(etags, &pt1); -+ etags->ecc_result = eccres; -+ -+ /* Set deleted state */ -+ etags->is_deleted = deleted; -+ return YAFFS_OK; -+} -+ -+/* Mark a block bad. -+ * -+ * This is a persistant state. -+ * Use of this function should be rare. -+ * -+ * Returns YAFFS_OK or YAFFS_FAIL. -+ */ -+int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk; -+ int retval; -+ -+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, -+ "marking block %d bad", block_no); -+ -+ retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no); -+ return (retval) ? YAFFS_FAIL : YAFFS_OK; -+} -+ -+/* Check any MTD prerequists. -+ * -+ * Returns YAFFS_OK or YAFFS_FAIL. -+ */ -+static int nandmtd1_test_prerequists(struct mtd_info *mtd) -+{ -+ /* 2.6.18 has mtd->ecclayout->oobavail */ -+ /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ -+ int oobavail = mtd->ecclayout->oobavail; -+ -+ if (oobavail < YTAG1_SIZE) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "mtd device has only %d bytes for tags, need %d", -+ oobavail, YTAG1_SIZE); -+ return YAFFS_FAIL; -+ } -+ return YAFFS_OK; -+} -+ -+/* Query for the current state of a specific block. -+ * -+ * Examine the tags of the first chunk of the block and return the state: -+ * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad -+ * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use -+ * - YAFFS_BLOCK_STATE_EMPTY, the block is clean -+ * -+ * Always returns YAFFS_OK. -+ */ -+int nandmtd1_query_block(struct yaffs_dev *dev, int block_no, -+ enum yaffs_block_state *state_ptr, u32 * seq_ptr) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ int chunk_num = block_no * dev->param.chunks_per_block; -+ loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk; -+ struct yaffs_ext_tags etags; -+ int state = YAFFS_BLOCK_STATE_DEAD; -+ int seqnum = 0; -+ int retval; -+ -+ /* We don't yet have a good place to test for MTD config prerequists. -+ * Do it here as we are called during the initial scan. -+ */ -+ if (nandmtd1_test_prerequists(mtd) != YAFFS_OK) -+ return YAFFS_FAIL; -+ -+ retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags); -+ etags.block_bad = (mtd->block_isbad) (mtd, addr); -+ if (etags.block_bad) { -+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, -+ "block %d is marked bad", block_no); -+ state = YAFFS_BLOCK_STATE_DEAD; -+ } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { -+ /* bad tags, need to look more closely */ -+ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; -+ } else if (etags.chunk_used) { -+ state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; -+ seqnum = etags.seq_number; -+ } else { -+ state = YAFFS_BLOCK_STATE_EMPTY; -+ } -+ -+ *state_ptr = state; -+ *seq_ptr = seqnum; -+ -+ /* query always succeeds */ -+ return YAFFS_OK; -+} -diff --git a/fs/yaffs2/yaffs_mtdif1.h b/fs/yaffs2/yaffs_mtdif1.h -new file mode 100644 -index 00000000..07ce4524 ---- /dev/null -+++ b/fs/yaffs2/yaffs_mtdif1.h -@@ -0,0 +1,29 @@ -+/* -+ * YAFFS: Yet another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_MTDIF1_H__ -+#define __YAFFS_MTDIF1_H__ -+ -+int nandmtd1_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, -+ const u8 * data, -+ const struct yaffs_ext_tags *tags); -+ -+int nandmtd1_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, -+ u8 * data, struct yaffs_ext_tags *tags); -+ -+int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no); -+ -+int nandmtd1_query_block(struct yaffs_dev *dev, int block_no, -+ enum yaffs_block_state *state, u32 * seq_number); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c -new file mode 100644 -index 00000000..d1643df2 ---- /dev/null -+++ b/fs/yaffs2/yaffs_mtdif2.c -@@ -0,0 +1,225 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+/* mtd interface for YAFFS2 */ -+ -+#include "yportenv.h" -+#include "yaffs_trace.h" -+ -+#include "yaffs_mtdif2.h" -+ -+#include "linux/mtd/mtd.h" -+#include "linux/types.h" -+#include "linux/time.h" -+ -+#include "yaffs_packedtags2.h" -+ -+#include "yaffs_linux.h" -+ -+/* NB For use with inband tags.... -+ * We assume that the data buffer is of size total_bytes_per_chunk so that we can also -+ * use it to load the tags. -+ */ -+int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, -+ const u8 * data, -+ const struct yaffs_ext_tags *tags) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ struct mtd_oob_ops ops; -+ int retval = 0; -+ -+ loff_t addr; -+ -+ struct yaffs_packed_tags2 pt; -+ -+ int packed_tags_size = -+ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); -+ void *packed_tags_ptr = -+ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; -+ -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "nandmtd2_write_chunk_tags chunk %d data %p tags %p", -+ nand_chunk, data, tags); -+ -+ addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; -+ -+ /* For yaffs2 writing there must be both data and tags. -+ * If we're using inband tags, then the tags are stuffed into -+ * the end of the data buffer. -+ */ -+ if (!data || !tags) -+ BUG(); -+ else if (dev->param.inband_tags) { -+ struct yaffs_packed_tags2_tags_only *pt2tp; -+ pt2tp = -+ (struct yaffs_packed_tags2_tags_only *)(data + -+ dev-> -+ data_bytes_per_chunk); -+ yaffs_pack_tags2_tags_only(pt2tp, tags); -+ } else { -+ yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc); -+ } -+ -+ ops.mode = MTD_OOB_AUTO; -+ ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size; -+ ops.len = dev->param.total_bytes_per_chunk; -+ ops.ooboffs = 0; -+ ops.datbuf = (u8 *) data; -+ ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr; -+ retval = mtd->write_oob(mtd, addr, &ops); -+ -+ if (retval == 0) -+ return YAFFS_OK; -+ else -+ return YAFFS_FAIL; -+} -+ -+int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, -+ u8 * data, struct yaffs_ext_tags *tags) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ struct mtd_oob_ops ops; -+ -+ size_t dummy; -+ int retval = 0; -+ int local_data = 0; -+ -+ loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; -+ -+ struct yaffs_packed_tags2 pt; -+ -+ int packed_tags_size = -+ dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); -+ void *packed_tags_ptr = -+ dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; -+ -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "nandmtd2_read_chunk_tags chunk %d data %p tags %p", -+ nand_chunk, data, tags); -+ -+ if (dev->param.inband_tags) { -+ -+ if (!data) { -+ local_data = 1; -+ data = yaffs_get_temp_buffer(dev, __LINE__); -+ } -+ -+ } -+ -+ if (dev->param.inband_tags || (data && !tags)) -+ retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk, -+ &dummy, data); -+ else if (tags) { -+ ops.mode = MTD_OOB_AUTO; -+ ops.ooblen = packed_tags_size; -+ ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size; -+ ops.ooboffs = 0; -+ ops.datbuf = data; -+ ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer; -+ retval = mtd->read_oob(mtd, addr, &ops); -+ } -+ -+ if (dev->param.inband_tags) { -+ if (tags) { -+ struct yaffs_packed_tags2_tags_only *pt2tp; -+ pt2tp = -+ (struct yaffs_packed_tags2_tags_only *)&data[dev-> -+ data_bytes_per_chunk]; -+ yaffs_unpack_tags2_tags_only(tags, pt2tp); -+ } -+ } else { -+ if (tags) { -+ memcpy(packed_tags_ptr, -+ yaffs_dev_to_lc(dev)->spare_buffer, -+ packed_tags_size); -+ yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc); -+ } -+ } -+ -+ if (local_data) -+ yaffs_release_temp_buffer(dev, data, __LINE__); -+ -+ if (tags && retval == -EBADMSG -+ && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) { -+ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; -+ dev->n_ecc_unfixed++; -+ } -+ if (tags && retval == -EUCLEAN -+ && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) { -+ tags->ecc_result = YAFFS_ECC_RESULT_FIXED; -+ dev->n_ecc_fixed++; -+ } -+ if (retval == 0) -+ return YAFFS_OK; -+ else -+ return YAFFS_FAIL; -+} -+ -+int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ int retval; -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "nandmtd2_mark_block_bad %d", block_no); -+ -+ retval = -+ mtd->block_markbad(mtd, -+ block_no * dev->param.chunks_per_block * -+ dev->param.total_bytes_per_chunk); -+ -+ if (retval == 0) -+ return YAFFS_OK; -+ else -+ return YAFFS_FAIL; -+ -+} -+ -+int nandmtd2_query_block(struct yaffs_dev *dev, int block_no, -+ enum yaffs_block_state *state, u32 * seq_number) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev); -+ int retval; -+ -+ yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no); -+ retval = -+ mtd->block_isbad(mtd, -+ block_no * dev->param.chunks_per_block * -+ dev->param.total_bytes_per_chunk); -+ -+ if (retval) { -+ yaffs_trace(YAFFS_TRACE_MTD, "block is bad"); -+ -+ *state = YAFFS_BLOCK_STATE_DEAD; -+ *seq_number = 0; -+ } else { -+ struct yaffs_ext_tags t; -+ nandmtd2_read_chunk_tags(dev, block_no * -+ dev->param.chunks_per_block, NULL, &t); -+ -+ if (t.chunk_used) { -+ *seq_number = t.seq_number; -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; -+ } else { -+ *seq_number = 0; -+ *state = YAFFS_BLOCK_STATE_EMPTY; -+ } -+ } -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "block is bad seq %d state %d", *seq_number, *state); -+ -+ if (retval == 0) -+ return YAFFS_OK; -+ else -+ return YAFFS_FAIL; -+} -+ -diff --git a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h -new file mode 100644 -index 00000000..d8211261 ---- /dev/null -+++ b/fs/yaffs2/yaffs_mtdif2.h -@@ -0,0 +1,29 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_MTDIF2_H__ -+#define __YAFFS_MTDIF2_H__ -+ -+#include "yaffs_guts.h" -+int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, -+ const u8 * data, -+ const struct yaffs_ext_tags *tags); -+int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, -+ u8 * data, struct yaffs_ext_tags *tags); -+int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no); -+int nandmtd2_query_block(struct yaffs_dev *dev, int block_no, -+ enum yaffs_block_state *state, u32 * seq_number); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c -new file mode 100644 -index 00000000..daa36f98 ---- /dev/null -+++ b/fs/yaffs2/yaffs_nameval.c -@@ -0,0 +1,201 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+/* -+ * This simple implementation of a name-value store assumes a small number of values and fits -+ * into a small finite buffer. -+ * -+ * Each attribute is stored as a record: -+ * sizeof(int) bytes record size. -+ * strnlen+1 bytes name null terminated. -+ * nbytes value. -+ * ---------- -+ * total size stored in record size -+ * -+ * This code has not been tested with unicode yet. -+ */ -+ -+#include "yaffs_nameval.h" -+ -+#include "yportenv.h" -+ -+static int nval_find(const char *xb, int xb_size, const YCHAR * name, -+ int *exist_size) -+{ -+ int pos = 0; -+ int size; -+ -+ memcpy(&size, xb, sizeof(int)); -+ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { -+ if (strncmp -+ ((YCHAR *) (xb + pos + sizeof(int)), name, size) == 0) { -+ if (exist_size) -+ *exist_size = size; -+ return pos; -+ } -+ pos += size; -+ if (pos < xb_size - sizeof(int)) -+ memcpy(&size, xb + pos, sizeof(int)); -+ else -+ size = 0; -+ } -+ if (exist_size) -+ *exist_size = 0; -+ return -1; -+} -+ -+static int nval_used(const char *xb, int xb_size) -+{ -+ int pos = 0; -+ int size; -+ -+ memcpy(&size, xb + pos, sizeof(int)); -+ while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { -+ pos += size; -+ if (pos < xb_size - sizeof(int)) -+ memcpy(&size, xb + pos, sizeof(int)); -+ else -+ size = 0; -+ } -+ return pos; -+} -+ -+int nval_del(char *xb, int xb_size, const YCHAR * name) -+{ -+ int pos = nval_find(xb, xb_size, name, NULL); -+ int size; -+ -+ if (pos >= 0 && pos < xb_size) { -+ /* Find size, shift rest over this record, then zero out the rest of buffer */ -+ memcpy(&size, xb + pos, sizeof(int)); -+ memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); -+ memset(xb + (xb_size - size), 0, size); -+ return 0; -+ } else { -+ return -ENODATA; -+ } -+} -+ -+int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf, -+ int bsize, int flags) -+{ -+ int pos; -+ int namelen = strnlen(name, xb_size); -+ int reclen; -+ int size_exist = 0; -+ int space; -+ int start; -+ -+ pos = nval_find(xb, xb_size, name, &size_exist); -+ -+ if (flags & XATTR_CREATE && pos >= 0) -+ return -EEXIST; -+ if (flags & XATTR_REPLACE && pos < 0) -+ return -ENODATA; -+ -+ start = nval_used(xb, xb_size); -+ space = xb_size - start + size_exist; -+ -+ reclen = (sizeof(int) + namelen + 1 + bsize); -+ -+ if (reclen > space) -+ return -ENOSPC; -+ -+ if (pos >= 0) { -+ nval_del(xb, xb_size, name); -+ start = nval_used(xb, xb_size); -+ } -+ -+ pos = start; -+ -+ memcpy(xb + pos, &reclen, sizeof(int)); -+ pos += sizeof(int); -+ strncpy((YCHAR *) (xb + pos), name, reclen); -+ pos += (namelen + 1); -+ memcpy(xb + pos, buf, bsize); -+ return 0; -+} -+ -+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, -+ int bsize) -+{ -+ int pos = nval_find(xb, xb_size, name, NULL); -+ int size; -+ -+ if (pos >= 0 && pos < xb_size) { -+ -+ memcpy(&size, xb + pos, sizeof(int)); -+ pos += sizeof(int); /* advance past record length */ -+ size -= sizeof(int); -+ -+ /* Advance over name string */ -+ while (xb[pos] && size > 0 && pos < xb_size) { -+ pos++; -+ size--; -+ } -+ /*Advance over NUL */ -+ pos++; -+ size--; -+ -+ if (size <= bsize) { -+ memcpy(buf, xb + pos, size); -+ return size; -+ } -+ -+ } -+ if (pos >= 0) -+ return -ERANGE; -+ else -+ return -ENODATA; -+} -+ -+int nval_list(const char *xb, int xb_size, char *buf, int bsize) -+{ -+ int pos = 0; -+ int size; -+ int name_len; -+ int ncopied = 0; -+ int filled = 0; -+ -+ memcpy(&size, xb + pos, sizeof(int)); -+ while (size > sizeof(int) && size <= xb_size && (pos + size) < xb_size -+ && !filled) { -+ pos += sizeof(int); -+ size -= sizeof(int); -+ name_len = strnlen((YCHAR *) (xb + pos), size); -+ if (ncopied + name_len + 1 < bsize) { -+ memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); -+ buf += name_len; -+ *buf = '\0'; -+ buf++; -+ if (sizeof(YCHAR) > 1) { -+ *buf = '\0'; -+ buf++; -+ } -+ ncopied += (name_len + 1); -+ } else { -+ filled = 1; -+ } -+ pos += size; -+ if (pos < xb_size - sizeof(int)) -+ memcpy(&size, xb + pos, sizeof(int)); -+ else -+ size = 0; -+ } -+ return ncopied; -+} -+ -+int nval_hasvalues(const char *xb, int xb_size) -+{ -+ return nval_used(xb, xb_size) > 0; -+} -diff --git a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h -new file mode 100644 -index 00000000..2bb02b62 ---- /dev/null -+++ b/fs/yaffs2/yaffs_nameval.h -@@ -0,0 +1,28 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __NAMEVAL_H__ -+#define __NAMEVAL_H__ -+ -+#include "yportenv.h" -+ -+int nval_del(char *xb, int xb_size, const YCHAR * name); -+int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf, -+ int bsize, int flags); -+int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, -+ int bsize); -+int nval_list(const char *xb, int xb_size, char *buf, int bsize); -+int nval_hasvalues(const char *xb, int xb_size); -+#endif -diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c -new file mode 100644 -index 00000000..e816cabf ---- /dev/null -+++ b/fs/yaffs2/yaffs_nand.c -@@ -0,0 +1,127 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_nand.h" -+#include "yaffs_tagscompat.h" -+#include "yaffs_tagsvalidity.h" -+ -+#include "yaffs_getblockinfo.h" -+ -+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, -+ u8 * buffer, struct yaffs_ext_tags *tags) -+{ -+ int result; -+ struct yaffs_ext_tags local_tags; -+ -+ int realigned_chunk = nand_chunk - dev->chunk_offset; -+ -+ dev->n_page_reads++; -+ -+ /* If there are no tags provided, use local tags to get prioritised gc working */ -+ if (!tags) -+ tags = &local_tags; -+ -+ if (dev->param.read_chunk_tags_fn) -+ result = -+ dev->param.read_chunk_tags_fn(dev, realigned_chunk, buffer, -+ tags); -+ else -+ result = yaffs_tags_compat_rd(dev, -+ realigned_chunk, buffer, tags); -+ if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { -+ -+ struct yaffs_block_info *bi; -+ bi = yaffs_get_block_info(dev, -+ nand_chunk / -+ dev->param.chunks_per_block); -+ yaffs_handle_chunk_error(dev, bi); -+ } -+ -+ return result; -+} -+ -+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 * buffer, struct yaffs_ext_tags *tags) -+{ -+ -+ dev->n_page_writes++; -+ -+ nand_chunk -= dev->chunk_offset; -+ -+ if (tags) { -+ tags->seq_number = dev->seq_number; -+ tags->chunk_used = 1; -+ if (!yaffs_validate_tags(tags)) { -+ yaffs_trace(YAFFS_TRACE_ERROR, "Writing uninitialised tags"); -+ YBUG(); -+ } -+ yaffs_trace(YAFFS_TRACE_WRITE, -+ "Writing chunk %d tags %d %d", -+ nand_chunk, tags->obj_id, tags->chunk_id); -+ } else { -+ yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags"); -+ YBUG(); -+ } -+ -+ if (dev->param.write_chunk_tags_fn) -+ return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer, -+ tags); -+ else -+ return yaffs_tags_compat_wr(dev, nand_chunk, buffer, tags); -+} -+ -+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no) -+{ -+ block_no -= dev->block_offset; -+ -+ if (dev->param.bad_block_fn) -+ return dev->param.bad_block_fn(dev, block_no); -+ else -+ return yaffs_tags_compat_mark_bad(dev, block_no); -+} -+ -+int yaffs_query_init_block_state(struct yaffs_dev *dev, -+ int block_no, -+ enum yaffs_block_state *state, -+ u32 * seq_number) -+{ -+ block_no -= dev->block_offset; -+ -+ if (dev->param.query_block_fn) -+ return dev->param.query_block_fn(dev, block_no, state, -+ seq_number); -+ else -+ return yaffs_tags_compat_query_block(dev, block_no, -+ state, seq_number); -+} -+ -+int yaffs_erase_block(struct yaffs_dev *dev, int flash_block) -+{ -+ int result; -+ -+ flash_block -= dev->block_offset; -+ -+ dev->n_erasures++; -+ -+ result = dev->param.erase_fn(dev, flash_block); -+ -+ return result; -+} -+ -+int yaffs_init_nand(struct yaffs_dev *dev) -+{ -+ if (dev->param.initialise_flash_fn) -+ return dev->param.initialise_flash_fn(dev); -+ return YAFFS_OK; -+} -diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h -new file mode 100644 -index 00000000..543f1987 ---- /dev/null -+++ b/fs/yaffs2/yaffs_nand.h -@@ -0,0 +1,38 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_NAND_H__ -+#define __YAFFS_NAND_H__ -+#include "yaffs_guts.h" -+ -+int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, -+ u8 * buffer, struct yaffs_ext_tags *tags); -+ -+int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 * buffer, struct yaffs_ext_tags *tags); -+ -+int yaffs_mark_bad(struct yaffs_dev *dev, int block_no); -+ -+int yaffs_query_init_block_state(struct yaffs_dev *dev, -+ int block_no, -+ enum yaffs_block_state *state, -+ unsigned *seq_number); -+ -+int yaffs_erase_block(struct yaffs_dev *dev, int flash_block); -+ -+int yaffs_init_nand(struct yaffs_dev *dev); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c -new file mode 100644 -index 00000000..a77f0954 ---- /dev/null -+++ b/fs/yaffs2/yaffs_packedtags1.c -@@ -0,0 +1,53 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_packedtags1.h" -+#include "yportenv.h" -+ -+void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, -+ const struct yaffs_ext_tags *t) -+{ -+ pt->chunk_id = t->chunk_id; -+ pt->serial_number = t->serial_number; -+ pt->n_bytes = t->n_bytes; -+ pt->obj_id = t->obj_id; -+ pt->ecc = 0; -+ pt->deleted = (t->is_deleted) ? 0 : 1; -+ pt->unused_stuff = 0; -+ pt->should_be_ff = 0xFFFFFFFF; -+ -+} -+ -+void yaffs_unpack_tags1(struct yaffs_ext_tags *t, -+ const struct yaffs_packed_tags1 *pt) -+{ -+ static const u8 all_ff[] = -+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+ 0xff -+ }; -+ -+ if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) { -+ t->block_bad = 0; -+ if (pt->should_be_ff != 0xFFFFFFFF) -+ t->block_bad = 1; -+ t->chunk_used = 1; -+ t->obj_id = pt->obj_id; -+ t->chunk_id = pt->chunk_id; -+ t->n_bytes = pt->n_bytes; -+ t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR; -+ t->is_deleted = (pt->deleted) ? 0 : 1; -+ t->serial_number = pt->serial_number; -+ } else { -+ memset(t, 0, sizeof(struct yaffs_ext_tags)); -+ } -+} -diff --git a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h -new file mode 100644 -index 00000000..d6861ff5 ---- /dev/null -+++ b/fs/yaffs2/yaffs_packedtags1.h -@@ -0,0 +1,39 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ -+ -+#ifndef __YAFFS_PACKEDTAGS1_H__ -+#define __YAFFS_PACKEDTAGS1_H__ -+ -+#include "yaffs_guts.h" -+ -+struct yaffs_packed_tags1 { -+ unsigned chunk_id:20; -+ unsigned serial_number:2; -+ unsigned n_bytes:10; -+ unsigned obj_id:18; -+ unsigned ecc:12; -+ unsigned deleted:1; -+ unsigned unused_stuff:1; -+ unsigned should_be_ff; -+ -+}; -+ -+void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, -+ const struct yaffs_ext_tags *t); -+void yaffs_unpack_tags1(struct yaffs_ext_tags *t, -+ const struct yaffs_packed_tags1 *pt); -+#endif -diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c -new file mode 100644 -index 00000000..8e7fea3d ---- /dev/null -+++ b/fs/yaffs2/yaffs_packedtags2.c -@@ -0,0 +1,196 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_packedtags2.h" -+#include "yportenv.h" -+#include "yaffs_trace.h" -+#include "yaffs_tagsvalidity.h" -+ -+/* This code packs a set of extended tags into a binary structure for -+ * NAND storage -+ */ -+ -+/* Some of the information is "extra" struff which can be packed in to -+ * speed scanning -+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set. -+ */ -+ -+/* Extra flags applied to chunk_id */ -+ -+#define EXTRA_HEADER_INFO_FLAG 0x80000000 -+#define EXTRA_SHRINK_FLAG 0x40000000 -+#define EXTRA_SHADOWS_FLAG 0x20000000 -+#define EXTRA_SPARE_FLAGS 0x10000000 -+ -+#define ALL_EXTRA_FLAGS 0xF0000000 -+ -+/* Also, the top 4 bits of the object Id are set to the object type. */ -+#define EXTRA_OBJECT_TYPE_SHIFT (28) -+#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) -+ -+static void yaffs_dump_packed_tags2_tags_only(const struct -+ yaffs_packed_tags2_tags_only *ptt) -+{ -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "packed tags obj %d chunk %d byte %d seq %d", -+ ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number); -+} -+ -+static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt) -+{ -+ yaffs_dump_packed_tags2_tags_only(&pt->t); -+} -+ -+static void yaffs_dump_tags2(const struct yaffs_ext_tags *t) -+{ -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d", -+ t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, -+ t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, -+ t->seq_number); -+ -+} -+ -+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt, -+ const struct yaffs_ext_tags *t) -+{ -+ ptt->chunk_id = t->chunk_id; -+ ptt->seq_number = t->seq_number; -+ ptt->n_bytes = t->n_bytes; -+ ptt->obj_id = t->obj_id; -+ -+ if (t->chunk_id == 0 && t->extra_available) { -+ /* Store the extra header info instead */ -+ /* We save the parent object in the chunk_id */ -+ ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id; -+ if (t->extra_is_shrink) -+ ptt->chunk_id |= EXTRA_SHRINK_FLAG; -+ if (t->extra_shadows) -+ ptt->chunk_id |= EXTRA_SHADOWS_FLAG; -+ -+ ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; -+ ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); -+ -+ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) -+ ptt->n_bytes = t->extra_equiv_id; -+ else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) -+ ptt->n_bytes = t->extra_length; -+ else -+ ptt->n_bytes = 0; -+ } -+ -+ yaffs_dump_packed_tags2_tags_only(ptt); -+ yaffs_dump_tags2(t); -+} -+ -+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, -+ const struct yaffs_ext_tags *t, int tags_ecc) -+{ -+ yaffs_pack_tags2_tags_only(&pt->t, t); -+ -+ if (tags_ecc) -+ yaffs_ecc_calc_other((unsigned char *)&pt->t, -+ sizeof(struct -+ yaffs_packed_tags2_tags_only), -+ &pt->ecc); -+} -+ -+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, -+ struct yaffs_packed_tags2_tags_only *ptt) -+{ -+ -+ memset(t, 0, sizeof(struct yaffs_ext_tags)); -+ -+ yaffs_init_tags(t); -+ -+ if (ptt->seq_number != 0xFFFFFFFF) { -+ t->block_bad = 0; -+ t->chunk_used = 1; -+ t->obj_id = ptt->obj_id; -+ t->chunk_id = ptt->chunk_id; -+ t->n_bytes = ptt->n_bytes; -+ t->is_deleted = 0; -+ t->serial_number = 0; -+ t->seq_number = ptt->seq_number; -+ -+ /* Do extra header info stuff */ -+ -+ if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { -+ t->chunk_id = 0; -+ t->n_bytes = 0; -+ -+ t->extra_available = 1; -+ t->extra_parent_id = -+ ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); -+ t->extra_is_shrink = -+ (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0; -+ t->extra_shadows = -+ (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0; -+ t->extra_obj_type = -+ ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; -+ t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; -+ -+ if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) -+ t->extra_equiv_id = ptt->n_bytes; -+ else -+ t->extra_length = ptt->n_bytes; -+ } -+ } -+ -+ yaffs_dump_packed_tags2_tags_only(ptt); -+ yaffs_dump_tags2(t); -+ -+} -+ -+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, -+ int tags_ecc) -+{ -+ -+ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; -+ -+ if (pt->t.seq_number != 0xFFFFFFFF && tags_ecc) { -+ /* Chunk is in use and we need to do ECC */ -+ -+ struct yaffs_ecc_other ecc; -+ int result; -+ yaffs_ecc_calc_other((unsigned char *)&pt->t, -+ sizeof(struct -+ yaffs_packed_tags2_tags_only), -+ &ecc); -+ result = -+ yaffs_ecc_correct_other((unsigned char *)&pt->t, -+ sizeof(struct -+ yaffs_packed_tags2_tags_only), -+ &pt->ecc, &ecc); -+ switch (result) { -+ case 0: -+ ecc_result = YAFFS_ECC_RESULT_NO_ERROR; -+ break; -+ case 1: -+ ecc_result = YAFFS_ECC_RESULT_FIXED; -+ break; -+ case -1: -+ ecc_result = YAFFS_ECC_RESULT_UNFIXED; -+ break; -+ default: -+ ecc_result = YAFFS_ECC_RESULT_UNKNOWN; -+ } -+ } -+ -+ yaffs_unpack_tags2_tags_only(t, &pt->t); -+ -+ t->ecc_result = ecc_result; -+ -+ yaffs_dump_packed_tags2(pt); -+ yaffs_dump_tags2(t); -+} -diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h -new file mode 100644 -index 00000000..f3296697 ---- /dev/null -+++ b/fs/yaffs2/yaffs_packedtags2.h -@@ -0,0 +1,47 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ -+ -+#ifndef __YAFFS_PACKEDTAGS2_H__ -+#define __YAFFS_PACKEDTAGS2_H__ -+ -+#include "yaffs_guts.h" -+#include "yaffs_ecc.h" -+ -+struct yaffs_packed_tags2_tags_only { -+ unsigned seq_number; -+ unsigned obj_id; -+ unsigned chunk_id; -+ unsigned n_bytes; -+}; -+ -+struct yaffs_packed_tags2 { -+ struct yaffs_packed_tags2_tags_only t; -+ struct yaffs_ecc_other ecc; -+}; -+ -+/* Full packed tags with ECC, used for oob tags */ -+void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, -+ const struct yaffs_ext_tags *t, int tags_ecc); -+void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, -+ int tags_ecc); -+ -+/* Only the tags part (no ECC for use with inband tags */ -+void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt, -+ const struct yaffs_ext_tags *t); -+void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, -+ struct yaffs_packed_tags2_tags_only *pt); -+#endif -diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c -new file mode 100644 -index 00000000..7578075d ---- /dev/null -+++ b/fs/yaffs2/yaffs_tagscompat.c -@@ -0,0 +1,422 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_guts.h" -+#include "yaffs_tagscompat.h" -+#include "yaffs_ecc.h" -+#include "yaffs_getblockinfo.h" -+#include "yaffs_trace.h" -+ -+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); -+ -+ -+/********** Tags ECC calculations *********/ -+ -+void yaffs_calc_ecc(const u8 * data, struct yaffs_spare *spare) -+{ -+ yaffs_ecc_cacl(data, spare->ecc1); -+ yaffs_ecc_cacl(&data[256], spare->ecc2); -+} -+ -+void yaffs_calc_tags_ecc(struct yaffs_tags *tags) -+{ -+ /* Calculate an ecc */ -+ -+ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; -+ unsigned i, j; -+ unsigned ecc = 0; -+ unsigned bit = 0; -+ -+ tags->ecc = 0; -+ -+ for (i = 0; i < 8; i++) { -+ for (j = 1; j & 0xff; j <<= 1) { -+ bit++; -+ if (b[i] & j) -+ ecc ^= bit; -+ } -+ } -+ -+ tags->ecc = ecc; -+ -+} -+ -+int yaffs_check_tags_ecc(struct yaffs_tags *tags) -+{ -+ unsigned ecc = tags->ecc; -+ -+ yaffs_calc_tags_ecc(tags); -+ -+ ecc ^= tags->ecc; -+ -+ if (ecc && ecc <= 64) { -+ /* TODO: Handle the failure better. Retire? */ -+ unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; -+ -+ ecc--; -+ -+ b[ecc / 8] ^= (1 << (ecc & 7)); -+ -+ /* Now recvalc the ecc */ -+ yaffs_calc_tags_ecc(tags); -+ -+ return 1; /* recovered error */ -+ } else if (ecc) { -+ /* Wierd ecc failure value */ -+ /* TODO Need to do somethiong here */ -+ return -1; /* unrecovered error */ -+ } -+ -+ return 0; -+} -+ -+/********** Tags **********/ -+ -+static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, -+ struct yaffs_tags *tags_ptr) -+{ -+ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; -+ -+ yaffs_calc_tags_ecc(tags_ptr); -+ -+ spare_ptr->tb0 = tu->as_bytes[0]; -+ spare_ptr->tb1 = tu->as_bytes[1]; -+ spare_ptr->tb2 = tu->as_bytes[2]; -+ spare_ptr->tb3 = tu->as_bytes[3]; -+ spare_ptr->tb4 = tu->as_bytes[4]; -+ spare_ptr->tb5 = tu->as_bytes[5]; -+ spare_ptr->tb6 = tu->as_bytes[6]; -+ spare_ptr->tb7 = tu->as_bytes[7]; -+} -+ -+static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, -+ struct yaffs_spare *spare_ptr, -+ struct yaffs_tags *tags_ptr) -+{ -+ union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; -+ int result; -+ -+ tu->as_bytes[0] = spare_ptr->tb0; -+ tu->as_bytes[1] = spare_ptr->tb1; -+ tu->as_bytes[2] = spare_ptr->tb2; -+ tu->as_bytes[3] = spare_ptr->tb3; -+ tu->as_bytes[4] = spare_ptr->tb4; -+ tu->as_bytes[5] = spare_ptr->tb5; -+ tu->as_bytes[6] = spare_ptr->tb6; -+ tu->as_bytes[7] = spare_ptr->tb7; -+ -+ result = yaffs_check_tags_ecc(tags_ptr); -+ if (result > 0) -+ dev->n_tags_ecc_fixed++; -+ else if (result < 0) -+ dev->n_tags_ecc_unfixed++; -+} -+ -+static void yaffs_spare_init(struct yaffs_spare *spare) -+{ -+ memset(spare, 0xFF, sizeof(struct yaffs_spare)); -+} -+ -+static int yaffs_wr_nand(struct yaffs_dev *dev, -+ int nand_chunk, const u8 * data, -+ struct yaffs_spare *spare) -+{ -+ if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>> yaffs chunk %d is not valid", -+ nand_chunk); -+ return YAFFS_FAIL; -+ } -+ -+ return dev->param.write_chunk_fn(dev, nand_chunk, data, spare); -+} -+ -+static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, -+ int nand_chunk, -+ u8 * data, -+ struct yaffs_spare *spare, -+ enum yaffs_ecc_result *ecc_result, -+ int correct_errors) -+{ -+ int ret_val; -+ struct yaffs_spare local_spare; -+ -+ if (!spare && data) { -+ /* If we don't have a real spare, then we use a local one. */ -+ /* Need this for the calculation of the ecc */ -+ spare = &local_spare; -+ } -+ -+ if (!dev->param.use_nand_ecc) { -+ ret_val = -+ dev->param.read_chunk_fn(dev, nand_chunk, data, spare); -+ if (data && correct_errors) { -+ /* Do ECC correction */ -+ /* Todo handle any errors */ -+ int ecc_result1, ecc_result2; -+ u8 calc_ecc[3]; -+ -+ yaffs_ecc_cacl(data, calc_ecc); -+ ecc_result1 = -+ yaffs_ecc_correct(data, spare->ecc1, calc_ecc); -+ yaffs_ecc_cacl(&data[256], calc_ecc); -+ ecc_result2 = -+ yaffs_ecc_correct(&data[256], spare->ecc2, -+ calc_ecc); -+ -+ if (ecc_result1 > 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>yaffs ecc error fix performed on chunk %d:0", -+ nand_chunk); -+ dev->n_ecc_fixed++; -+ } else if (ecc_result1 < 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>yaffs ecc error unfixed on chunk %d:0", -+ nand_chunk); -+ dev->n_ecc_unfixed++; -+ } -+ -+ if (ecc_result2 > 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>yaffs ecc error fix performed on chunk %d:1", -+ nand_chunk); -+ dev->n_ecc_fixed++; -+ } else if (ecc_result2 < 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>yaffs ecc error unfixed on chunk %d:1", -+ nand_chunk); -+ dev->n_ecc_unfixed++; -+ } -+ -+ if (ecc_result1 || ecc_result2) { -+ /* We had a data problem on this page */ -+ yaffs_handle_rd_data_error(dev, nand_chunk); -+ } -+ -+ if (ecc_result1 < 0 || ecc_result2 < 0) -+ *ecc_result = YAFFS_ECC_RESULT_UNFIXED; -+ else if (ecc_result1 > 0 || ecc_result2 > 0) -+ *ecc_result = YAFFS_ECC_RESULT_FIXED; -+ else -+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; -+ } -+ } else { -+ /* Must allocate enough memory for spare+2*sizeof(int) */ -+ /* for ecc results from device. */ -+ struct yaffs_nand_spare nspare; -+ -+ memset(&nspare, 0, sizeof(nspare)); -+ -+ ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data, -+ (struct yaffs_spare *) -+ &nspare); -+ memcpy(spare, &nspare, sizeof(struct yaffs_spare)); -+ if (data && correct_errors) { -+ if (nspare.eccres1 > 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>mtd ecc error fix performed on chunk %d:0", -+ nand_chunk); -+ } else if (nspare.eccres1 < 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>mtd ecc error unfixed on chunk %d:0", -+ nand_chunk); -+ } -+ -+ if (nspare.eccres2 > 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>mtd ecc error fix performed on chunk %d:1", -+ nand_chunk); -+ } else if (nspare.eccres2 < 0) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "**>>mtd ecc error unfixed on chunk %d:1", -+ nand_chunk); -+ } -+ -+ if (nspare.eccres1 || nspare.eccres2) { -+ /* We had a data problem on this page */ -+ yaffs_handle_rd_data_error(dev, nand_chunk); -+ } -+ -+ if (nspare.eccres1 < 0 || nspare.eccres2 < 0) -+ *ecc_result = YAFFS_ECC_RESULT_UNFIXED; -+ else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) -+ *ecc_result = YAFFS_ECC_RESULT_FIXED; -+ else -+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; -+ -+ } -+ } -+ return ret_val; -+} -+ -+/* -+ * Functions for robustisizing -+ */ -+ -+static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) -+{ -+ int flash_block = nand_chunk / dev->param.chunks_per_block; -+ -+ /* Mark the block for retirement */ -+ yaffs_get_block_info(dev, -+ flash_block + dev->block_offset)->needs_retiring = -+ 1; -+ yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, -+ "**>>Block %d marked for retirement", -+ flash_block); -+ -+ /* TODO: -+ * Just do a garbage collection on the affected block -+ * then retire the block -+ * NB recursion -+ */ -+} -+ -+int yaffs_tags_compat_wr(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 * data, const struct yaffs_ext_tags *ext_tags) -+{ -+ struct yaffs_spare spare; -+ struct yaffs_tags tags; -+ -+ yaffs_spare_init(&spare); -+ -+ if (ext_tags->is_deleted) -+ spare.page_status = 0; -+ else { -+ tags.obj_id = ext_tags->obj_id; -+ tags.chunk_id = ext_tags->chunk_id; -+ -+ tags.n_bytes_lsb = ext_tags->n_bytes & 0x3ff; -+ -+ if (dev->data_bytes_per_chunk >= 1024) -+ tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; -+ else -+ tags.n_bytes_msb = 3; -+ -+ tags.serial_number = ext_tags->serial_number; -+ -+ if (!dev->param.use_nand_ecc && data) -+ yaffs_calc_ecc(data, &spare); -+ -+ yaffs_load_tags_to_spare(&spare, &tags); -+ -+ } -+ -+ return yaffs_wr_nand(dev, nand_chunk, data, &spare); -+} -+ -+int yaffs_tags_compat_rd(struct yaffs_dev *dev, -+ int nand_chunk, -+ u8 * data, struct yaffs_ext_tags *ext_tags) -+{ -+ -+ struct yaffs_spare spare; -+ struct yaffs_tags tags; -+ enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; -+ -+ static struct yaffs_spare spare_ff; -+ static int init; -+ -+ if (!init) { -+ memset(&spare_ff, 0xFF, sizeof(spare_ff)); -+ init = 1; -+ } -+ -+ if (yaffs_rd_chunk_nand(dev, nand_chunk, data, &spare, &ecc_result, 1)) { -+ /* ext_tags may be NULL */ -+ if (ext_tags) { -+ -+ int deleted = -+ (hweight8(spare.page_status) < 7) ? 1 : 0; -+ -+ ext_tags->is_deleted = deleted; -+ ext_tags->ecc_result = ecc_result; -+ ext_tags->block_bad = 0; /* We're reading it */ -+ /* therefore it is not a bad block */ -+ ext_tags->chunk_used = -+ (memcmp(&spare_ff, &spare, sizeof(spare_ff)) != -+ 0) ? 1 : 0; -+ -+ if (ext_tags->chunk_used) { -+ yaffs_get_tags_from_spare(dev, &spare, &tags); -+ -+ ext_tags->obj_id = tags.obj_id; -+ ext_tags->chunk_id = tags.chunk_id; -+ ext_tags->n_bytes = tags.n_bytes_lsb; -+ -+ if (dev->data_bytes_per_chunk >= 1024) -+ ext_tags->n_bytes |= -+ (((unsigned)tags. -+ n_bytes_msb) << 10); -+ -+ ext_tags->serial_number = tags.serial_number; -+ } -+ } -+ -+ return YAFFS_OK; -+ } else { -+ return YAFFS_FAIL; -+ } -+} -+ -+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) -+{ -+ -+ struct yaffs_spare spare; -+ -+ memset(&spare, 0xff, sizeof(struct yaffs_spare)); -+ -+ spare.block_status = 'Y'; -+ -+ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, -+ &spare); -+ yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, -+ NULL, &spare); -+ -+ return YAFFS_OK; -+ -+} -+ -+int yaffs_tags_compat_query_block(struct yaffs_dev *dev, -+ int block_no, -+ enum yaffs_block_state *state, -+ u32 * seq_number) -+{ -+ -+ struct yaffs_spare spare0, spare1; -+ static struct yaffs_spare spare_ff; -+ static int init; -+ enum yaffs_ecc_result dummy; -+ -+ if (!init) { -+ memset(&spare_ff, 0xFF, sizeof(spare_ff)); -+ init = 1; -+ } -+ -+ *seq_number = 0; -+ -+ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL, -+ &spare0, &dummy, 1); -+ yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, -+ NULL, &spare1, &dummy, 1); -+ -+ if (hweight8(spare0.block_status & spare1.block_status) < 7) -+ *state = YAFFS_BLOCK_STATE_DEAD; -+ else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0) -+ *state = YAFFS_BLOCK_STATE_EMPTY; -+ else -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; -+ -+ return YAFFS_OK; -+} -diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h -new file mode 100644 -index 00000000..8cd35dcd ---- /dev/null -+++ b/fs/yaffs2/yaffs_tagscompat.h -@@ -0,0 +1,36 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_TAGSCOMPAT_H__ -+#define __YAFFS_TAGSCOMPAT_H__ -+ -+#include "yaffs_guts.h" -+int yaffs_tags_compat_wr(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 * data, const struct yaffs_ext_tags *tags); -+int yaffs_tags_compat_rd(struct yaffs_dev *dev, -+ int nand_chunk, -+ u8 * data, struct yaffs_ext_tags *tags); -+int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no); -+int yaffs_tags_compat_query_block(struct yaffs_dev *dev, -+ int block_no, -+ enum yaffs_block_state *state, -+ u32 * seq_number); -+ -+void yaffs_calc_tags_ecc(struct yaffs_tags *tags); -+int yaffs_check_tags_ecc(struct yaffs_tags *tags); -+int yaffs_count_bits(u8 byte); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_tagsvalidity.c b/fs/yaffs2/yaffs_tagsvalidity.c -new file mode 100644 -index 00000000..4358d79d ---- /dev/null -+++ b/fs/yaffs2/yaffs_tagsvalidity.c -@@ -0,0 +1,27 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_tagsvalidity.h" -+ -+void yaffs_init_tags(struct yaffs_ext_tags *tags) -+{ -+ memset(tags, 0, sizeof(struct yaffs_ext_tags)); -+ tags->validity0 = 0xAAAAAAAA; -+ tags->validity1 = 0x55555555; -+} -+ -+int yaffs_validate_tags(struct yaffs_ext_tags *tags) -+{ -+ return (tags->validity0 == 0xAAAAAAAA && tags->validity1 == 0x55555555); -+ -+} -diff --git a/fs/yaffs2/yaffs_tagsvalidity.h b/fs/yaffs2/yaffs_tagsvalidity.h -new file mode 100644 -index 00000000..36a021fc ---- /dev/null -+++ b/fs/yaffs2/yaffs_tagsvalidity.h -@@ -0,0 +1,23 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_TAGS_VALIDITY_H__ -+#define __YAFFS_TAGS_VALIDITY_H__ -+ -+#include "yaffs_guts.h" -+ -+void yaffs_init_tags(struct yaffs_ext_tags *tags); -+int yaffs_validate_tags(struct yaffs_ext_tags *tags); -+#endif -diff --git a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h -new file mode 100644 -index 00000000..6273dbf9 ---- /dev/null -+++ b/fs/yaffs2/yaffs_trace.h -@@ -0,0 +1,57 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YTRACE_H__ -+#define __YTRACE_H__ -+ -+extern unsigned int yaffs_trace_mask; -+extern unsigned int yaffs_wr_attempts; -+ -+/* -+ * Tracing flags. -+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced. -+ */ -+ -+#define YAFFS_TRACE_OS 0x00000002 -+#define YAFFS_TRACE_ALLOCATE 0x00000004 -+#define YAFFS_TRACE_SCAN 0x00000008 -+#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 -+#define YAFFS_TRACE_ERASE 0x00000020 -+#define YAFFS_TRACE_GC 0x00000040 -+#define YAFFS_TRACE_WRITE 0x00000080 -+#define YAFFS_TRACE_TRACING 0x00000100 -+#define YAFFS_TRACE_DELETION 0x00000200 -+#define YAFFS_TRACE_BUFFERS 0x00000400 -+#define YAFFS_TRACE_NANDACCESS 0x00000800 -+#define YAFFS_TRACE_GC_DETAIL 0x00001000 -+#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 -+#define YAFFS_TRACE_MTD 0x00004000 -+#define YAFFS_TRACE_CHECKPOINT 0x00008000 -+ -+#define YAFFS_TRACE_VERIFY 0x00010000 -+#define YAFFS_TRACE_VERIFY_NAND 0x00020000 -+#define YAFFS_TRACE_VERIFY_FULL 0x00040000 -+#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 -+ -+#define YAFFS_TRACE_SYNC 0x00100000 -+#define YAFFS_TRACE_BACKGROUND 0x00200000 -+#define YAFFS_TRACE_LOCK 0x00400000 -+#define YAFFS_TRACE_MOUNT 0x00800000 -+ -+#define YAFFS_TRACE_ERROR 0x40000000 -+#define YAFFS_TRACE_BUG 0x80000000 -+#define YAFFS_TRACE_ALWAYS 0xF0000000 -+ -+#endif -diff --git a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c -new file mode 100644 -index 00000000..738c7f69 ---- /dev/null -+++ b/fs/yaffs2/yaffs_verify.c -@@ -0,0 +1,535 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_verify.h" -+#include "yaffs_trace.h" -+#include "yaffs_bitmap.h" -+#include "yaffs_getblockinfo.h" -+#include "yaffs_nand.h" -+ -+int yaffs_skip_verification(struct yaffs_dev *dev) -+{ -+ dev = dev; -+ return !(yaffs_trace_mask & -+ (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); -+} -+ -+static int yaffs_skip_full_verification(struct yaffs_dev *dev) -+{ -+ dev = dev; -+ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); -+} -+ -+static int yaffs_skip_nand_verification(struct yaffs_dev *dev) -+{ -+ dev = dev; -+ return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); -+} -+ -+static const char *block_state_name[] = { -+ "Unknown", -+ "Needs scanning", -+ "Scanning", -+ "Empty", -+ "Allocating", -+ "Full", -+ "Dirty", -+ "Checkpoint", -+ "Collecting", -+ "Dead" -+}; -+ -+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n) -+{ -+ int actually_used; -+ int in_use; -+ -+ if (yaffs_skip_verification(dev)) -+ return; -+ -+ /* Report illegal runtime states */ -+ if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Block %d has undefined state %d", -+ n, bi->block_state); -+ -+ switch (bi->block_state) { -+ case YAFFS_BLOCK_STATE_UNKNOWN: -+ case YAFFS_BLOCK_STATE_SCANNING: -+ case YAFFS_BLOCK_STATE_NEEDS_SCANNING: -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Block %d has bad run-state %s", -+ n, block_state_name[bi->block_state]); -+ } -+ -+ /* Check pages in use and soft deletions are legal */ -+ -+ actually_used = bi->pages_in_use - bi->soft_del_pages; -+ -+ if (bi->pages_in_use < 0 -+ || bi->pages_in_use > dev->param.chunks_per_block -+ || bi->soft_del_pages < 0 -+ || bi->soft_del_pages > dev->param.chunks_per_block -+ || actually_used < 0 || actually_used > dev->param.chunks_per_block) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Block %d has illegal values pages_in_used %d soft_del_pages %d", -+ n, bi->pages_in_use, bi->soft_del_pages); -+ -+ /* Check chunk bitmap legal */ -+ in_use = yaffs_count_chunk_bits(dev, n); -+ if (in_use != bi->pages_in_use) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Block %d has inconsistent values pages_in_use %d counted chunk bits %d", -+ n, bi->pages_in_use, in_use); -+ -+} -+ -+void yaffs_verify_collected_blk(struct yaffs_dev *dev, -+ struct yaffs_block_info *bi, int n) -+{ -+ yaffs_verify_blk(dev, bi, n); -+ -+ /* After collection the block should be in the erased state */ -+ -+ if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && -+ bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "Block %d is in state %d after gc, should be erased", -+ n, bi->block_state); -+ } -+} -+ -+void yaffs_verify_blocks(struct yaffs_dev *dev) -+{ -+ int i; -+ int state_count[YAFFS_NUMBER_OF_BLOCK_STATES]; -+ int illegal_states = 0; -+ -+ if (yaffs_skip_verification(dev)) -+ return; -+ -+ memset(state_count, 0, sizeof(state_count)); -+ -+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { -+ struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); -+ yaffs_verify_blk(dev, bi, i); -+ -+ if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) -+ state_count[bi->block_state]++; -+ else -+ illegal_states++; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary"); -+ -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "%d blocks have illegal states", -+ illegal_states); -+ if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Too many allocating blocks"); -+ -+ for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "%s %d blocks", -+ block_state_name[i], state_count[i]); -+ -+ if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT]) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Checkpoint block count wrong dev %d count %d", -+ dev->blocks_in_checkpt, -+ state_count[YAFFS_BLOCK_STATE_CHECKPOINT]); -+ -+ if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY]) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Erased block count wrong dev %d count %d", -+ dev->n_erased_blocks, -+ state_count[YAFFS_BLOCK_STATE_EMPTY]); -+ -+ if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Too many collecting blocks %d (max is 1)", -+ state_count[YAFFS_BLOCK_STATE_COLLECTING]); -+} -+ -+/* -+ * Verify the object header. oh must be valid, but obj and tags may be NULL in which -+ * case those tests will not be performed. -+ */ -+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, -+ struct yaffs_ext_tags *tags, int parent_check) -+{ -+ if (obj && yaffs_skip_verification(obj->my_dev)) -+ return; -+ -+ if (!(tags && obj && oh)) { -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Verifying object header tags %p obj %p oh %p", -+ tags, obj, oh); -+ return; -+ } -+ -+ if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || -+ oh->type > YAFFS_OBJECT_TYPE_MAX) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d header type is illegal value 0x%x", -+ tags->obj_id, oh->type); -+ -+ if (tags->obj_id != obj->obj_id) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d header mismatch obj_id %d", -+ tags->obj_id, obj->obj_id); -+ -+ /* -+ * Check that the object's parent ids match if parent_check requested. -+ * -+ * Tests do not apply to the root object. -+ */ -+ -+ if (parent_check && tags->obj_id > 1 && !obj->parent) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d header mismatch parent_id %d obj->parent is NULL", -+ tags->obj_id, oh->parent_obj_id); -+ -+ if (parent_check && obj->parent && -+ oh->parent_obj_id != obj->parent->obj_id && -+ (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || -+ obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d header mismatch parent_id %d parent_obj_id %d", -+ tags->obj_id, oh->parent_obj_id, -+ obj->parent->obj_id); -+ -+ if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d header name is NULL", -+ obj->obj_id); -+ -+ if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Trashed name */ -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d header name is 0xFF", -+ obj->obj_id); -+} -+ -+void yaffs_verify_file(struct yaffs_obj *obj) -+{ -+ int required_depth; -+ int actual_depth; -+ u32 last_chunk; -+ u32 x; -+ u32 i; -+ struct yaffs_dev *dev; -+ struct yaffs_ext_tags tags; -+ struct yaffs_tnode *tn; -+ u32 obj_id; -+ -+ if (!obj) -+ return; -+ -+ if (yaffs_skip_verification(obj->my_dev)) -+ return; -+ -+ dev = obj->my_dev; -+ obj_id = obj->obj_id; -+ -+ /* Check file size is consistent with tnode depth */ -+ last_chunk = -+ obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1; -+ x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS; -+ required_depth = 0; -+ while (x > 0) { -+ x >>= YAFFS_TNODES_INTERNAL_BITS; -+ required_depth++; -+ } -+ -+ actual_depth = obj->variant.file_variant.top_level; -+ -+ /* Check that the chunks in the tnode tree are all correct. -+ * We do this by scanning through the tnode tree and -+ * checking the tags for every chunk match. -+ */ -+ -+ if (yaffs_skip_nand_verification(dev)) -+ return; -+ -+ for (i = 1; i <= last_chunk; i++) { -+ tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); -+ -+ if (tn) { -+ u32 the_chunk = yaffs_get_group_base(dev, tn, i); -+ if (the_chunk > 0) { -+ yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, -+ &tags); -+ if (tags.obj_id != obj_id || tags.chunk_id != i) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)", -+ obj_id, i, the_chunk, -+ tags.obj_id, tags.chunk_id); -+ } -+ } -+ } -+} -+ -+void yaffs_verify_link(struct yaffs_obj *obj) -+{ -+ if (obj && yaffs_skip_verification(obj->my_dev)) -+ return; -+ -+ /* Verify sane equivalent object */ -+} -+ -+void yaffs_verify_symlink(struct yaffs_obj *obj) -+{ -+ if (obj && yaffs_skip_verification(obj->my_dev)) -+ return; -+ -+ /* Verify symlink string */ -+} -+ -+void yaffs_verify_special(struct yaffs_obj *obj) -+{ -+ if (obj && yaffs_skip_verification(obj->my_dev)) -+ return; -+} -+ -+void yaffs_verify_obj(struct yaffs_obj *obj) -+{ -+ struct yaffs_dev *dev; -+ -+ u32 chunk_min; -+ u32 chunk_max; -+ -+ u32 chunk_id_ok; -+ u32 chunk_in_range; -+ u32 chunk_wrongly_deleted; -+ u32 chunk_valid; -+ -+ if (!obj) -+ return; -+ -+ if (obj->being_created) -+ return; -+ -+ dev = obj->my_dev; -+ -+ if (yaffs_skip_verification(dev)) -+ return; -+ -+ /* Check sane object header chunk */ -+ -+ chunk_min = dev->internal_start_block * dev->param.chunks_per_block; -+ chunk_max = -+ (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1; -+ -+ chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min && -+ ((unsigned)(obj->hdr_chunk)) <= chunk_max); -+ chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0); -+ chunk_valid = chunk_in_range && -+ yaffs_check_chunk_bit(dev, -+ obj->hdr_chunk / dev->param.chunks_per_block, -+ obj->hdr_chunk % dev->param.chunks_per_block); -+ chunk_wrongly_deleted = chunk_in_range && !chunk_valid; -+ -+ if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d has chunk_id %d %s %s", -+ obj->obj_id, obj->hdr_chunk, -+ chunk_id_ok ? "" : ",out of range", -+ chunk_wrongly_deleted ? ",marked as deleted" : ""); -+ -+ if (chunk_valid && !yaffs_skip_nand_verification(dev)) { -+ struct yaffs_ext_tags tags; -+ struct yaffs_obj_hdr *oh; -+ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ oh = (struct yaffs_obj_hdr *)buffer; -+ -+ yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags); -+ -+ yaffs_verify_oh(obj, oh, &tags, 1); -+ -+ yaffs_release_temp_buffer(dev, buffer, __LINE__); -+ } -+ -+ /* Verify it has a parent */ -+ if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) { -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d has parent pointer %p which does not look like an object", -+ obj->obj_id, obj->parent); -+ } -+ -+ /* Verify parent is a directory */ -+ if (obj->parent -+ && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d's parent is not a directory (type %d)", -+ obj->obj_id, obj->parent->variant_type); -+ } -+ -+ switch (obj->variant_type) { -+ case YAFFS_OBJECT_TYPE_FILE: -+ yaffs_verify_file(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ yaffs_verify_symlink(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ yaffs_verify_dir(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ yaffs_verify_link(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ yaffs_verify_special(obj); -+ break; -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ default: -+ yaffs_trace(YAFFS_TRACE_VERIFY, -+ "Obj %d has illegaltype %d", -+ obj->obj_id, obj->variant_type); -+ break; -+ } -+} -+ -+void yaffs_verify_objects(struct yaffs_dev *dev) -+{ -+ struct yaffs_obj *obj; -+ int i; -+ struct list_head *lh; -+ -+ if (yaffs_skip_verification(dev)) -+ return; -+ -+ /* Iterate through the objects in each hash entry */ -+ -+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { -+ list_for_each(lh, &dev->obj_bucket[i].list) { -+ if (lh) { -+ obj = -+ list_entry(lh, struct yaffs_obj, hash_link); -+ yaffs_verify_obj(obj); -+ } -+ } -+ } -+} -+ -+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj) -+{ -+ struct list_head *lh; -+ struct yaffs_obj *list_obj; -+ -+ int count = 0; -+ -+ if (!obj) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify"); -+ YBUG(); -+ return; -+ } -+ -+ if (yaffs_skip_verification(obj->my_dev)) -+ return; -+ -+ if (!obj->parent) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent" ); -+ YBUG(); -+ return; -+ } -+ -+ if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory"); -+ YBUG(); -+ } -+ -+ /* Iterate through the objects in each hash entry */ -+ -+ list_for_each(lh, &obj->parent->variant.dir_variant.children) { -+ if (lh) { -+ list_obj = list_entry(lh, struct yaffs_obj, siblings); -+ yaffs_verify_obj(list_obj); -+ if (obj == list_obj) -+ count++; -+ } -+ } -+ -+ if (count != 1) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "Object in directory %d times", -+ count); -+ YBUG(); -+ } -+} -+ -+void yaffs_verify_dir(struct yaffs_obj *directory) -+{ -+ struct list_head *lh; -+ struct yaffs_obj *list_obj; -+ -+ if (!directory) { -+ YBUG(); -+ return; -+ } -+ -+ if (yaffs_skip_full_verification(directory->my_dev)) -+ return; -+ -+ if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "Directory has wrong type: %d", -+ directory->variant_type); -+ YBUG(); -+ } -+ -+ /* Iterate through the objects in each hash entry */ -+ -+ list_for_each(lh, &directory->variant.dir_variant.children) { -+ if (lh) { -+ list_obj = list_entry(lh, struct yaffs_obj, siblings); -+ if (list_obj->parent != directory) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "Object in directory list has wrong parent %p", -+ list_obj->parent); -+ YBUG(); -+ } -+ yaffs_verify_obj_in_dir(list_obj); -+ } -+ } -+} -+ -+static int yaffs_free_verification_failures; -+ -+void yaffs_verify_free_chunks(struct yaffs_dev *dev) -+{ -+ int counted; -+ int difference; -+ -+ if (yaffs_skip_verification(dev)) -+ return; -+ -+ counted = yaffs_count_free_chunks(dev); -+ -+ difference = dev->n_free_chunks - counted; -+ -+ if (difference) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "Freechunks verification failure %d %d %d", -+ dev->n_free_chunks, counted, difference); -+ yaffs_free_verification_failures++; -+ } -+} -+ -+int yaffs_verify_file_sane(struct yaffs_obj *in) -+{ -+ in = in; -+ return YAFFS_OK; -+} -+ -diff --git a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h -new file mode 100644 -index 00000000..cc6f8899 ---- /dev/null -+++ b/fs/yaffs2/yaffs_verify.h -@@ -0,0 +1,43 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_VERIFY_H__ -+#define __YAFFS_VERIFY_H__ -+ -+#include "yaffs_guts.h" -+ -+void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, -+ int n); -+void yaffs_verify_collected_blk(struct yaffs_dev *dev, -+ struct yaffs_block_info *bi, int n); -+void yaffs_verify_blocks(struct yaffs_dev *dev); -+ -+void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, -+ struct yaffs_ext_tags *tags, int parent_check); -+void yaffs_verify_file(struct yaffs_obj *obj); -+void yaffs_verify_link(struct yaffs_obj *obj); -+void yaffs_verify_symlink(struct yaffs_obj *obj); -+void yaffs_verify_special(struct yaffs_obj *obj); -+void yaffs_verify_obj(struct yaffs_obj *obj); -+void yaffs_verify_objects(struct yaffs_dev *dev); -+void yaffs_verify_obj_in_dir(struct yaffs_obj *obj); -+void yaffs_verify_dir(struct yaffs_obj *directory); -+void yaffs_verify_free_chunks(struct yaffs_dev *dev); -+ -+int yaffs_verify_file_sane(struct yaffs_obj *obj); -+ -+int yaffs_skip_verification(struct yaffs_dev *dev); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c -new file mode 100644 -index 00000000..d5b87531 ---- /dev/null -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -0,0 +1,2792 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * Acknowledgements: -+ * Luc van OostenRyck for numerous patches. -+ * Nick Bane for numerous patches. -+ * Nick Bane for 2.5/2.6 integration. -+ * Andras Toth for mknod rdev issue. -+ * Michael Fischer for finding the problem with inode inconsistency. -+ * Some code bodily lifted from JFFS -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+/* -+ * -+ * This is the file system front-end to YAFFS that hooks it up to -+ * the VFS. -+ * -+ * Special notes: -+ * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with -+ * this superblock -+ * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this -+ * superblock -+ * >> inode->u.generic_ip points to the associated struct yaffs_obj. -+ */ -+ -+/* -+ * NB There are two variants of Linux VFS glue code. This variant supports -+ * a single version and should not include any multi-version code. -+ */ -+#include <linux/version.h> -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/fs.h> -+#include <linux/proc_fs.h> -+#include <linux/smp_lock.h> -+#include <linux/pagemap.h> -+#include <linux/mtd/mtd.h> -+#include <linux/interrupt.h> -+#include <linux/string.h> -+#include <linux/ctype.h> -+#include <linux/namei.h> -+#include <linux/exportfs.h> -+#include <linux/kthread.h> -+#include <linux/delay.h> -+#include <linux/freezer.h> -+ -+#include <asm/div64.h> -+ -+#include <linux/statfs.h> -+ -+#define UnlockPage(p) unlock_page(p) -+#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) -+ -+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) -+ -+#define YPROC_ROOT NULL -+ -+#define Y_INIT_TIMER(a) init_timer_on_stack(a) -+ -+#define WRITE_SIZE_STR "writesize" -+#define WRITE_SIZE(mtd) ((mtd)->writesize) -+ -+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) -+{ -+ uint64_t result = partition_size; -+ do_div(result, block_size); -+ return (uint32_t) result; -+} -+ -+#include <linux/uaccess.h> -+#include <linux/mtd/mtd.h> -+ -+#include "yportenv.h" -+#include "yaffs_trace.h" -+#include "yaffs_guts.h" -+#include "yaffs_attribs.h" -+ -+#include "yaffs_linux.h" -+ -+#include "yaffs_mtdif.h" -+#include "yaffs_mtdif1.h" -+#include "yaffs_mtdif2.h" -+ -+unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; -+unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; -+unsigned int yaffs_auto_checkpoint = 1; -+unsigned int yaffs_gc_control = 1; -+unsigned int yaffs_bg_enable = 1; -+ -+/* Module Parameters */ -+module_param(yaffs_trace_mask, uint, 0644); -+module_param(yaffs_wr_attempts, uint, 0644); -+module_param(yaffs_auto_checkpoint, uint, 0644); -+module_param(yaffs_gc_control, uint, 0644); -+module_param(yaffs_bg_enable, uint, 0644); -+ -+ -+#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private) -+#define yaffs_inode_to_obj(iptr) ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr))) -+#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode) -+#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info) -+ -+#define update_dir_time(dir) do {\ -+ (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ -+ } while(0) -+ -+ -+static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev) -+{ -+ return yaffs_gc_control; -+} -+ -+static void yaffs_gross_lock(struct yaffs_dev *dev) -+{ -+ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current); -+ mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock)); -+ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current); -+} -+ -+static void yaffs_gross_unlock(struct yaffs_dev *dev) -+{ -+ yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current); -+ mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock)); -+} -+ -+static void yaffs_fill_inode_from_obj(struct inode *inode, -+ struct yaffs_obj *obj); -+ -+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) -+{ -+ struct inode *inode; -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev = yaffs_super_to_dev(sb); -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino); -+ -+ inode = iget_locked(sb, ino); -+ if (!inode) -+ return ERR_PTR(-ENOMEM); -+ if (!(inode->i_state & I_NEW)) -+ return inode; -+ -+ /* NB This is called as a side effect of other functions, but -+ * we had to release the lock to prevent deadlocks, so -+ * need to lock again. -+ */ -+ -+ yaffs_gross_lock(dev); -+ -+ obj = yaffs_find_by_number(dev, inode->i_ino); -+ -+ yaffs_fill_inode_from_obj(inode, obj); -+ -+ yaffs_gross_unlock(dev); -+ -+ unlock_new_inode(inode); -+ return inode; -+} -+ -+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, -+ struct yaffs_obj *obj) -+{ -+ struct inode *inode; -+ -+ if (!sb) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_get_inode for NULL super_block!!"); -+ return NULL; -+ -+ } -+ -+ if (!obj) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_get_inode for NULL object!!"); -+ return NULL; -+ -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_get_inode for object %d", -+ obj->obj_id); -+ -+ inode = yaffs_iget(sb, obj->obj_id); -+ if (IS_ERR(inode)) -+ return NULL; -+ -+ /* NB Side effect: iget calls back to yaffs_read_inode(). */ -+ /* iget also increments the inode's i_count */ -+ /* NB You can't be holding gross_lock or deadlock will happen! */ -+ -+ return inode; -+} -+ -+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, -+ dev_t rdev) -+{ -+ struct inode *inode; -+ -+ struct yaffs_obj *obj = NULL; -+ struct yaffs_dev *dev; -+ -+ struct yaffs_obj *parent = yaffs_inode_to_obj(dir); -+ -+ int error = -ENOSPC; -+ uid_t uid = current->cred->fsuid; -+ gid_t gid = -+ (dir->i_mode & S_ISGID) ? dir->i_gid : current->cred->fsgid; -+ -+ if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) -+ mode |= S_ISGID; -+ -+ if (parent) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_mknod: parent object %d type %d", -+ parent->obj_id, parent->variant_type); -+ } else { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_mknod: could not get parent object"); -+ return -EPERM; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_mknod: making oject for %s, mode %x dev %x", -+ dentry->d_name.name, mode, rdev); -+ -+ dev = parent->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ switch (mode & S_IFMT) { -+ default: -+ /* Special (socket, fifo, device...) */ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special"); -+ obj = -+ yaffs_create_special(parent, dentry->d_name.name, mode, uid, -+ gid, old_encode_dev(rdev)); -+ break; -+ case S_IFREG: /* file */ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file"); -+ obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid, -+ gid); -+ break; -+ case S_IFDIR: /* directory */ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory"); -+ obj = yaffs_create_dir(parent, dentry->d_name.name, mode, -+ uid, gid); -+ break; -+ case S_IFLNK: /* symlink */ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink"); -+ obj = NULL; /* Do we ever get here? */ -+ break; -+ } -+ -+ /* Can not call yaffs_get_inode() with gross lock held */ -+ yaffs_gross_unlock(dev); -+ -+ if (obj) { -+ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); -+ d_instantiate(dentry, inode); -+ update_dir_time(dir); -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_mknod created object %d count = %d", -+ obj->obj_id, atomic_read(&inode->i_count)); -+ error = 0; -+ yaffs_fill_inode_from_obj(dir, parent); -+ } else { -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object"); -+ error = -ENOMEM; -+ } -+ -+ return error; -+} -+ -+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -+{ -+ return yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); -+} -+ -+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, -+ struct nameidata *n) -+{ -+ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); -+} -+ -+static int yaffs_link(struct dentry *old_dentry, struct inode *dir, -+ struct dentry *dentry) -+{ -+ struct inode *inode = old_dentry->d_inode; -+ struct yaffs_obj *obj = NULL; -+ struct yaffs_obj *link = NULL; -+ struct yaffs_dev *dev; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_link"); -+ -+ obj = yaffs_inode_to_obj(inode); -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ -+ link = -+ yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name, -+ obj); -+ -+ if (link) { -+ old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj); -+ d_instantiate(dentry, old_dentry->d_inode); -+ atomic_inc(&old_dentry->d_inode->i_count); -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_link link count %d i_count %d", -+ old_dentry->d_inode->i_nlink, -+ atomic_read(&old_dentry->d_inode->i_count)); -+ } -+ -+ yaffs_gross_unlock(dev); -+ -+ if (link) { -+ update_dir_time(dir); -+ return 0; -+ } -+ -+ return -EPERM; -+} -+ -+static int yaffs_symlink(struct inode *dir, struct dentry *dentry, -+ const char *symname) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ uid_t uid = current->cred->fsuid; -+ gid_t gid = -+ (dir->i_mode & S_ISGID) ? dir->i_gid : current->cred->fsgid; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); -+ -+ dev = yaffs_inode_to_obj(dir)->my_dev; -+ yaffs_gross_lock(dev); -+ obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name, -+ S_IFLNK | S_IRWXUGO, uid, gid, symname); -+ yaffs_gross_unlock(dev); -+ -+ if (obj) { -+ struct inode *inode; -+ -+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); -+ d_instantiate(dentry, inode); -+ update_dir_time(dir); -+ yaffs_trace(YAFFS_TRACE_OS, "symlink created OK"); -+ return 0; -+ } else { -+ yaffs_trace(YAFFS_TRACE_OS, "symlink not created"); -+ } -+ -+ return -ENOMEM; -+} -+ -+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, -+ struct nameidata *n) -+{ -+ struct yaffs_obj *obj; -+ struct inode *inode = NULL; -+ -+ struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev; -+ -+ if (current != yaffs_dev_to_lc(dev)->readdir_process) -+ yaffs_gross_lock(dev); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_lookup for %d:%s", -+ yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name); -+ -+ obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name); -+ -+ obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */ -+ -+ /* Can't hold gross lock when calling yaffs_get_inode() */ -+ if (current != yaffs_dev_to_lc(dev)->readdir_process) -+ yaffs_gross_unlock(dev); -+ -+ if (obj) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_lookup found %d", obj->obj_id); -+ -+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); -+ -+ if (inode) { -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_loookup dentry"); -+ d_add(dentry, inode); -+ /* return dentry; */ -+ return NULL; -+ } -+ -+ } else { -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found"); -+ -+ } -+ -+ d_add(dentry, inode); -+ -+ return NULL; -+} -+ -+static int yaffs_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ int ret_val; -+ -+ struct yaffs_dev *dev; -+ struct yaffs_obj *obj; -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_unlink %d:%s", -+ (int)(dir->i_ino), dentry->d_name.name); -+ obj = yaffs_inode_to_obj(dir); -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ ret_val = yaffs_unlinker(obj, dentry->d_name.name); -+ -+ if (ret_val == YAFFS_OK) { -+ dentry->d_inode->i_nlink--; -+ dir->i_version++; -+ yaffs_gross_unlock(dev); -+ mark_inode_dirty(dentry->d_inode); -+ update_dir_time(dir); -+ return 0; -+ } -+ yaffs_gross_unlock(dev); -+ return -ENOTEMPTY; -+} -+ -+static int yaffs_sync_object(struct file *file, int datasync) -+{ -+ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ struct dentry *dentry = file->f_path.dentry; -+ -+ obj = yaffs_dentry_to_obj(dentry); -+ -+ dev = obj->my_dev; -+ -+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, "yaffs_sync_object"); -+ yaffs_gross_lock(dev); -+ yaffs_flush_file(obj, 1, datasync); -+ yaffs_gross_unlock(dev); -+ return 0; -+} -+/* -+ * The VFS layer already does all the dentry stuff for rename. -+ * -+ * NB: POSIX says you can rename an object over an old object of the same name -+ */ -+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, -+ struct inode *new_dir, struct dentry *new_dentry) -+{ -+ struct yaffs_dev *dev; -+ int ret_val = YAFFS_FAIL; -+ struct yaffs_obj *target; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename"); -+ dev = yaffs_inode_to_obj(old_dir)->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ /* Check if the target is an existing directory that is not empty. */ -+ target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir), -+ new_dentry->d_name.name); -+ -+ if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && -+ !list_empty(&target->variant.dir_variant.children)) { -+ -+ yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir"); -+ -+ ret_val = YAFFS_FAIL; -+ } else { -+ /* Now does unlinking internally using shadowing mechanism */ -+ yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj"); -+ -+ ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir), -+ old_dentry->d_name.name, -+ yaffs_inode_to_obj(new_dir), -+ new_dentry->d_name.name); -+ } -+ yaffs_gross_unlock(dev); -+ -+ if (ret_val == YAFFS_OK) { -+ if (target) { -+ new_dentry->d_inode->i_nlink--; -+ mark_inode_dirty(new_dentry->d_inode); -+ } -+ -+ update_dir_time(old_dir); -+ if (old_dir != new_dir) -+ update_dir_time(new_dir); -+ return 0; -+ } else { -+ return -ENOTEMPTY; -+ } -+} -+ -+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ struct inode *inode = dentry->d_inode; -+ int error = 0; -+ struct yaffs_dev *dev; -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_setattr of object %d", -+ yaffs_inode_to_obj(inode)->obj_id); -+ -+ /* Fail if a requested resize >= 2GB */ -+ if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31)) -+ error = -EINVAL; -+ -+ if (error == 0) -+ error = inode_change_ok(inode, attr); -+ if (error == 0) { -+ int result; -+ if (!error) { -+ setattr_copy(inode, attr); -+ yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called"); -+ if (attr->ia_valid & ATTR_SIZE) { -+ truncate_setsize(inode, attr->ia_size); -+ inode->i_blocks = (inode->i_size + 511) >> 9; -+ } -+ } -+ dev = yaffs_inode_to_obj(inode)->my_dev; -+ if (attr->ia_valid & ATTR_SIZE) { -+ yaffs_trace(YAFFS_TRACE_OS, "resize to %d(%x)", -+ (int)(attr->ia_size), -+ (int)(attr->ia_size)); -+ } -+ yaffs_gross_lock(dev); -+ result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr); -+ if (result == YAFFS_OK) { -+ error = 0; -+ } else { -+ error = -EPERM; -+ } -+ yaffs_gross_unlock(dev); -+ -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error); -+ -+ return error; -+} -+ -+#ifdef CONFIG_YAFFS_XATTR -+static int yaffs_setxattr(struct dentry *dentry, const char *name, -+ const void *value, size_t size, int flags) -+{ -+ struct inode *inode = dentry->d_inode; -+ int error = 0; -+ struct yaffs_dev *dev; -+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id); -+ -+ if (error == 0) { -+ int result; -+ dev = obj->my_dev; -+ yaffs_gross_lock(dev); -+ result = yaffs_set_xattrib(obj, name, value, size, flags); -+ if (result == YAFFS_OK) -+ error = 0; -+ else if (result < 0) -+ error = result; -+ yaffs_gross_unlock(dev); -+ -+ } -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error); -+ -+ return error; -+} -+ -+static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *buff, -+ size_t size) -+{ -+ struct inode *inode = dentry->d_inode; -+ int error = 0; -+ struct yaffs_dev *dev; -+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_getxattr \"%s\" from object %d", -+ name, obj->obj_id); -+ -+ if (error == 0) { -+ dev = obj->my_dev; -+ yaffs_gross_lock(dev); -+ error = yaffs_get_xattrib(obj, name, buff, size); -+ yaffs_gross_unlock(dev); -+ -+ } -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error); -+ -+ return error; -+} -+ -+static int yaffs_removexattr(struct dentry *dentry, const char *name) -+{ -+ struct inode *inode = dentry->d_inode; -+ int error = 0; -+ struct yaffs_dev *dev; -+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_removexattr of object %d", obj->obj_id); -+ -+ if (error == 0) { -+ int result; -+ dev = obj->my_dev; -+ yaffs_gross_lock(dev); -+ result = yaffs_remove_xattrib(obj, name); -+ if (result == YAFFS_OK) -+ error = 0; -+ else if (result < 0) -+ error = result; -+ yaffs_gross_unlock(dev); -+ -+ } -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_removexattr done returning %d", error); -+ -+ return error; -+} -+ -+static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size) -+{ -+ struct inode *inode = dentry->d_inode; -+ int error = 0; -+ struct yaffs_dev *dev; -+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_listxattr of object %d", obj->obj_id); -+ -+ if (error == 0) { -+ dev = obj->my_dev; -+ yaffs_gross_lock(dev); -+ error = yaffs_list_xattrib(obj, buff, size); -+ yaffs_gross_unlock(dev); -+ -+ } -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_listxattr done returning %d", error); -+ -+ return error; -+} -+ -+#endif -+ -+static const struct inode_operations yaffs_dir_inode_operations = { -+ .create = yaffs_create, -+ .lookup = yaffs_lookup, -+ .link = yaffs_link, -+ .unlink = yaffs_unlink, -+ .symlink = yaffs_symlink, -+ .mkdir = yaffs_mkdir, -+ .rmdir = yaffs_unlink, -+ .mknod = yaffs_mknod, -+ .rename = yaffs_rename, -+ .setattr = yaffs_setattr, -+#ifdef CONFIG_YAFFS_XATTR -+ .setxattr = yaffs_setxattr, -+ .getxattr = yaffs_getxattr, -+ .listxattr = yaffs_listxattr, -+ .removexattr = yaffs_removexattr, -+#endif -+}; -+/*-----------------------------------------------------------------*/ -+/* Directory search context allows us to unlock access to yaffs during -+ * filldir without causing problems with the directory being modified. -+ * This is similar to the tried and tested mechanism used in yaffs direct. -+ * -+ * A search context iterates along a doubly linked list of siblings in the -+ * directory. If the iterating object is deleted then this would corrupt -+ * the list iteration, likely causing a crash. The search context avoids -+ * this by using the remove_obj_fn to move the search context to the -+ * next object before the object is deleted. -+ * -+ * Many readdirs (and thus seach conexts) may be alive simulateously so -+ * each struct yaffs_dev has a list of these. -+ * -+ * A seach context lives for the duration of a readdir. -+ * -+ * All these functions must be called while yaffs is locked. -+ */ -+ -+struct yaffs_search_context { -+ struct yaffs_dev *dev; -+ struct yaffs_obj *dir_obj; -+ struct yaffs_obj *next_return; -+ struct list_head others; -+}; -+ -+/* -+ * yaffs_new_search() creates a new search context, initialises it and -+ * adds it to the device's search context list. -+ * -+ * Called at start of readdir. -+ */ -+static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir) -+{ -+ struct yaffs_dev *dev = dir->my_dev; -+ struct yaffs_search_context *sc = -+ kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS); -+ if (sc) { -+ sc->dir_obj = dir; -+ sc->dev = dev; -+ if (list_empty(&sc->dir_obj->variant.dir_variant.children)) -+ sc->next_return = NULL; -+ else -+ sc->next_return = -+ list_entry(dir->variant.dir_variant.children.next, -+ struct yaffs_obj, siblings); -+ INIT_LIST_HEAD(&sc->others); -+ list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts)); -+ } -+ return sc; -+} -+ -+/* -+ * yaffs_search_end() disposes of a search context and cleans up. -+ */ -+static void yaffs_search_end(struct yaffs_search_context *sc) -+{ -+ if (sc) { -+ list_del(&sc->others); -+ kfree(sc); -+ } -+} -+ -+/* -+ * yaffs_search_advance() moves a search context to the next object. -+ * Called when the search iterates or when an object removal causes -+ * the search context to be moved to the next object. -+ */ -+static void yaffs_search_advance(struct yaffs_search_context *sc) -+{ -+ if (!sc) -+ return; -+ -+ if (sc->next_return == NULL || -+ list_empty(&sc->dir_obj->variant.dir_variant.children)) -+ sc->next_return = NULL; -+ else { -+ struct list_head *next = sc->next_return->siblings.next; -+ -+ if (next == &sc->dir_obj->variant.dir_variant.children) -+ sc->next_return = NULL; /* end of list */ -+ else -+ sc->next_return = -+ list_entry(next, struct yaffs_obj, siblings); -+ } -+} -+ -+/* -+ * yaffs_remove_obj_callback() is called when an object is unlinked. -+ * We check open search contexts and advance any which are currently -+ * on the object being iterated. -+ */ -+static void yaffs_remove_obj_callback(struct yaffs_obj *obj) -+{ -+ -+ struct list_head *i; -+ struct yaffs_search_context *sc; -+ struct list_head *search_contexts = -+ &(yaffs_dev_to_lc(obj->my_dev)->search_contexts); -+ -+ /* Iterate through the directory search contexts. -+ * If any are currently on the object being removed, then advance -+ * the search context to the next object to prevent a hanging pointer. -+ */ -+ list_for_each(i, search_contexts) { -+ if (i) { -+ sc = list_entry(i, struct yaffs_search_context, others); -+ if (sc->next_return == obj) -+ yaffs_search_advance(sc); -+ } -+ } -+ -+} -+ -+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ struct yaffs_search_context *sc; -+ struct inode *inode = f->f_dentry->d_inode; -+ unsigned long offset, curoffs; -+ struct yaffs_obj *l; -+ int ret_val = 0; -+ -+ char name[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ obj = yaffs_dentry_to_obj(f->f_dentry); -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ yaffs_dev_to_lc(dev)->readdir_process = current; -+ -+ offset = f->f_pos; -+ -+ sc = yaffs_new_search(obj); -+ if (!sc) { -+ ret_val = -ENOMEM; -+ goto out; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: starting at %d", (int)offset); -+ -+ if (offset == 0) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry . ino %d", -+ (int)inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ f->f_pos++; -+ } -+ if (offset == 1) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry .. ino %d", -+ (int)f->f_dentry->d_parent->d_inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (filldir(dirent, "..", 2, offset, -+ f->f_dentry->d_parent->d_inode->i_ino, -+ DT_DIR) < 0) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ f->f_pos++; -+ } -+ -+ curoffs = 1; -+ -+ /* If the directory has changed since the open or last call to -+ readdir, rewind to after the 2 canned entries. */ -+ if (f->f_version != inode->i_version) { -+ offset = 2; -+ f->f_pos = offset; -+ f->f_version = inode->i_version; -+ } -+ -+ while (sc->next_return) { -+ curoffs++; -+ l = sc->next_return; -+ if (curoffs >= offset) { -+ int this_inode = yaffs_get_obj_inode(l); -+ int this_type = yaffs_get_obj_type(l); -+ -+ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: %s inode %d", -+ name, yaffs_get_obj_inode(l)); -+ -+ yaffs_gross_unlock(dev); -+ -+ if (filldir(dirent, -+ name, -+ strlen(name), -+ offset, this_inode, this_type) < 0) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ -+ yaffs_gross_lock(dev); -+ -+ offset++; -+ f->f_pos++; -+ } -+ yaffs_search_advance(sc); -+ } -+ -+out: -+ yaffs_search_end(sc); -+ yaffs_dev_to_lc(dev)->readdir_process = NULL; -+ yaffs_gross_unlock(dev); -+ -+ return ret_val; -+} -+ -+static const struct file_operations yaffs_dir_operations = { -+ .read = generic_read_dir, -+ .readdir = yaffs_readdir, -+ .fsync = yaffs_sync_object, -+ .llseek = generic_file_llseek, -+}; -+ -+ -+ -+static int yaffs_file_flush(struct file *file, fl_owner_t id) -+{ -+ struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry); -+ -+ struct yaffs_dev *dev = obj->my_dev; -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_file_flush object %d (%s)", -+ obj->obj_id, obj->dirty ? "dirty" : "clean"); -+ -+ yaffs_gross_lock(dev); -+ -+ yaffs_flush_file(obj, 1, 0); -+ -+ yaffs_gross_unlock(dev); -+ -+ return 0; -+} -+ -+static const struct file_operations yaffs_file_operations = { -+ .read = do_sync_read, -+ .write = do_sync_write, -+ .aio_read = generic_file_aio_read, -+ .aio_write = generic_file_aio_write, -+ .mmap = generic_file_mmap, -+ .flush = yaffs_file_flush, -+ .fsync = yaffs_sync_object, -+ .splice_read = generic_file_splice_read, -+ .splice_write = generic_file_splice_write, -+ .llseek = generic_file_llseek, -+}; -+ -+ -+/* ExportFS support */ -+static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, -+ uint32_t generation) -+{ -+ return yaffs_iget(sb, ino); -+} -+ -+static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb, -+ struct fid *fid, int fh_len, -+ int fh_type) -+{ -+ return generic_fh_to_dentry(sb, fid, fh_len, fh_type, -+ yaffs2_nfs_get_inode); -+} -+ -+static struct dentry *yaffs2_fh_to_parent(struct super_block *sb, -+ struct fid *fid, int fh_len, -+ int fh_type) -+{ -+ return generic_fh_to_parent(sb, fid, fh_len, fh_type, -+ yaffs2_nfs_get_inode); -+} -+ -+struct dentry *yaffs2_get_parent(struct dentry *dentry) -+{ -+ -+ struct super_block *sb = dentry->d_inode->i_sb; -+ struct dentry *parent = ERR_PTR(-ENOENT); -+ struct inode *inode; -+ unsigned long parent_ino; -+ struct yaffs_obj *d_obj; -+ struct yaffs_obj *parent_obj; -+ -+ d_obj = yaffs_inode_to_obj(dentry->d_inode); -+ -+ if (d_obj) { -+ parent_obj = d_obj->parent; -+ if (parent_obj) { -+ parent_ino = yaffs_get_obj_inode(parent_obj); -+ inode = yaffs_iget(sb, parent_ino); -+ -+ if (IS_ERR(inode)) { -+ parent = ERR_CAST(inode); -+ } else { -+ parent = d_obtain_alias(inode); -+ if (!IS_ERR(parent)) { -+ parent = ERR_PTR(-ENOMEM); -+ iput(inode); -+ } -+ } -+ } -+ } -+ -+ return parent; -+} -+ -+/* Just declare a zero structure as a NULL value implies -+ * using the default functions of exportfs. -+ */ -+ -+static struct export_operations yaffs_export_ops = { -+ .fh_to_dentry = yaffs2_fh_to_dentry, -+ .fh_to_parent = yaffs2_fh_to_parent, -+ .get_parent = yaffs2_get_parent, -+}; -+ -+ -+/*-----------------------------------------------------------------*/ -+ -+static int yaffs_readlink(struct dentry *dentry, char __user * buffer, -+ int buflen) -+{ -+ unsigned char *alias; -+ int ret; -+ -+ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); -+ -+ yaffs_gross_unlock(dev); -+ -+ if (!alias) -+ return -ENOMEM; -+ -+ ret = vfs_readlink(dentry, buffer, buflen, alias); -+ kfree(alias); -+ return ret; -+} -+ -+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) -+{ -+ unsigned char *alias; -+ void *ret; -+ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); -+ yaffs_gross_unlock(dev); -+ -+ if (!alias) { -+ ret = ERR_PTR(-ENOMEM); -+ goto out; -+ } -+ -+ nd_set_link(nd, alias); -+ ret = (void *)alias; -+out: -+ return ret; -+} -+ -+void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) -+{ -+ kfree(alias); -+} -+ -+ -+static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj) -+{ -+ /* Clear the association between the inode and -+ * the struct yaffs_obj. -+ */ -+ obj->my_inode = NULL; -+ yaffs_inode_to_obj_lv(inode) = NULL; -+ -+ /* If the object freeing was deferred, then the real -+ * free happens now. -+ * This should fix the inode inconsistency problem. -+ */ -+ yaffs_handle_defered_free(obj); -+} -+ -+/* yaffs_evict_inode combines into one operation what was previously done in -+ * yaffs_clear_inode() and yaffs_delete_inode() -+ * -+ */ -+static void yaffs_evict_inode(struct inode *inode) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ int deleteme = 0; -+ -+ obj = yaffs_inode_to_obj(inode); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_evict_inode: ino %d, count %d %s", -+ (int)inode->i_ino, -+ atomic_read(&inode->i_count), -+ obj ? "object exists" : "null object"); -+ -+ if (!inode->i_nlink && !is_bad_inode(inode)) -+ deleteme = 1; -+ truncate_inode_pages(&inode->i_data, 0); -+ end_writeback(inode); -+ -+ if (deleteme && obj) { -+ dev = obj->my_dev; -+ yaffs_gross_lock(dev); -+ yaffs_del_obj(obj); -+ yaffs_gross_unlock(dev); -+ } -+ if (obj) { -+ dev = obj->my_dev; -+ yaffs_gross_lock(dev); -+ yaffs_unstitch_obj(inode, obj); -+ yaffs_gross_unlock(dev); -+ } -+ -+} -+ -+static void yaffs_touch_super(struct yaffs_dev *dev) -+{ -+ struct super_block *sb = yaffs_dev_to_lc(dev)->super; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_touch_super() sb = %p", sb); -+ if (sb) -+ sb->s_dirt = 1; -+} -+ -+static int yaffs_readpage_nolock(struct file *f, struct page *pg) -+{ -+ /* Lifted from jffs2 */ -+ -+ struct yaffs_obj *obj; -+ unsigned char *pg_buf; -+ int ret; -+ -+ struct yaffs_dev *dev; -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readpage_nolock at %08x, size %08x", -+ (unsigned)(pg->index << PAGE_CACHE_SHIFT), -+ (unsigned)PAGE_CACHE_SIZE); -+ -+ obj = yaffs_dentry_to_obj(f->f_dentry); -+ -+ dev = obj->my_dev; -+ -+ BUG_ON(!PageLocked(pg)); -+ -+ pg_buf = kmap(pg); -+ /* FIXME: Can kmap fail? */ -+ -+ yaffs_gross_lock(dev); -+ -+ ret = yaffs_file_rd(obj, pg_buf, -+ pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE); -+ -+ yaffs_gross_unlock(dev); -+ -+ if (ret >= 0) -+ ret = 0; -+ -+ if (ret) { -+ ClearPageUptodate(pg); -+ SetPageError(pg); -+ } else { -+ SetPageUptodate(pg); -+ ClearPageError(pg); -+ } -+ -+ flush_dcache_page(pg); -+ kunmap(pg); -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done"); -+ return ret; -+} -+ -+static int yaffs_readpage_unlock(struct file *f, struct page *pg) -+{ -+ int ret = yaffs_readpage_nolock(f, pg); -+ UnlockPage(pg); -+ return ret; -+} -+ -+static int yaffs_readpage(struct file *f, struct page *pg) -+{ -+ int ret; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage"); -+ ret = yaffs_readpage_unlock(f, pg); -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done"); -+ return ret; -+} -+ -+/* writepage inspired by/stolen from smbfs */ -+ -+static int yaffs_writepage(struct page *page, struct writeback_control *wbc) -+{ -+ struct yaffs_dev *dev; -+ struct address_space *mapping = page->mapping; -+ struct inode *inode; -+ unsigned long end_index; -+ char *buffer; -+ struct yaffs_obj *obj; -+ int n_written = 0; -+ unsigned n_bytes; -+ loff_t i_size; -+ -+ if (!mapping) -+ BUG(); -+ inode = mapping->host; -+ if (!inode) -+ BUG(); -+ i_size = i_size_read(inode); -+ -+ end_index = i_size >> PAGE_CACHE_SHIFT; -+ -+ if (page->index < end_index) -+ n_bytes = PAGE_CACHE_SIZE; -+ else { -+ n_bytes = i_size & (PAGE_CACHE_SIZE - 1); -+ -+ if (page->index > end_index || !n_bytes) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_writepage at %08x, inode size = %08x!!!", -+ (unsigned)(page->index << PAGE_CACHE_SHIFT), -+ (unsigned)inode->i_size); -+ yaffs_trace(YAFFS_TRACE_OS, -+ " -> don't care!!"); -+ -+ zero_user_segment(page, 0, PAGE_CACHE_SIZE); -+ set_page_writeback(page); -+ unlock_page(page); -+ end_page_writeback(page); -+ return 0; -+ } -+ } -+ -+ if (n_bytes != PAGE_CACHE_SIZE) -+ zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE); -+ -+ get_page(page); -+ -+ buffer = kmap(page); -+ -+ obj = yaffs_inode_to_obj(inode); -+ dev = obj->my_dev; -+ yaffs_gross_lock(dev); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_writepage at %08x, size %08x", -+ (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes); -+ yaffs_trace(YAFFS_TRACE_OS, -+ "writepag0: obj = %05x, ino = %05x", -+ (int)obj->variant.file_variant.file_size, (int)inode->i_size); -+ -+ n_written = yaffs_wr_file(obj, buffer, -+ page->index << PAGE_CACHE_SHIFT, n_bytes, 0); -+ -+ yaffs_touch_super(dev); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "writepag1: obj = %05x, ino = %05x", -+ (int)obj->variant.file_variant.file_size, (int)inode->i_size); -+ -+ yaffs_gross_unlock(dev); -+ -+ kunmap(page); -+ set_page_writeback(page); -+ unlock_page(page); -+ end_page_writeback(page); -+ put_page(page); -+ -+ return (n_written == n_bytes) ? 0 : -ENOSPC; -+} -+ -+/* Space holding and freeing is done to ensure we have space available for -+ * write_begin/end. -+ * For now we just assume few parallel writes and check against a small -+ * number. -+ * Todo: need to do this with a counter to handle parallel reads better. -+ */ -+ -+static ssize_t yaffs_hold_space(struct file *f) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ -+ int n_free_chunks; -+ -+ obj = yaffs_dentry_to_obj(f->f_dentry); -+ -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ n_free_chunks = yaffs_get_n_free_chunks(dev); -+ -+ yaffs_gross_unlock(dev); -+ -+ return (n_free_chunks > 20) ? 1 : 0; -+} -+ -+static void yaffs_release_space(struct file *f) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ -+ obj = yaffs_dentry_to_obj(f->f_dentry); -+ -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ yaffs_gross_unlock(dev); -+} -+ -+static int yaffs_write_begin(struct file *filp, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned flags, -+ struct page **pagep, void **fsdata) -+{ -+ struct page *pg = NULL; -+ pgoff_t index = pos >> PAGE_CACHE_SHIFT; -+ -+ int ret = 0; -+ int space_held = 0; -+ -+ /* Get a page */ -+ pg = grab_cache_page_write_begin(mapping, index, flags); -+ -+ *pagep = pg; -+ if (!pg) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ yaffs_trace(YAFFS_TRACE_OS, -+ "start yaffs_write_begin index %d(%x) uptodate %d", -+ (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0); -+ -+ /* Get fs space */ -+ space_held = yaffs_hold_space(filp); -+ -+ if (!space_held) { -+ ret = -ENOSPC; -+ goto out; -+ } -+ -+ /* Update page if required */ -+ -+ if (!Page_Uptodate(pg)) -+ ret = yaffs_readpage_nolock(filp, pg); -+ -+ if (ret) -+ goto out; -+ -+ /* Happy path return */ -+ yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok"); -+ -+ return 0; -+ -+out: -+ yaffs_trace(YAFFS_TRACE_OS, -+ "end yaffs_write_begin fail returning %d", ret); -+ if (space_held) -+ yaffs_release_space(filp); -+ if (pg) { -+ unlock_page(pg); -+ page_cache_release(pg); -+ } -+ return ret; -+} -+ -+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, -+ loff_t * pos) -+{ -+ struct yaffs_obj *obj; -+ int n_written, ipos; -+ struct inode *inode; -+ struct yaffs_dev *dev; -+ -+ obj = yaffs_dentry_to_obj(f->f_dentry); -+ -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ inode = f->f_dentry->d_inode; -+ -+ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) -+ ipos = inode->i_size; -+ else -+ ipos = *pos; -+ -+ if (!obj) -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_file_write: hey obj is null!"); -+ else -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_file_write about to write writing %u(%x) bytes to object %d at %d(%x)", -+ (unsigned)n, (unsigned)n, obj->obj_id, ipos, ipos); -+ -+ n_written = yaffs_wr_file(obj, buf, ipos, n, 0); -+ -+ yaffs_touch_super(dev); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_file_write: %d(%x) bytes written", -+ (unsigned)n, (unsigned)n); -+ -+ if (n_written > 0) { -+ ipos += n_written; -+ *pos = ipos; -+ if (ipos > inode->i_size) { -+ inode->i_size = ipos; -+ inode->i_blocks = (ipos + 511) >> 9; -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_file_write size updated to %d bytes, %d blocks", -+ ipos, (int)(inode->i_blocks)); -+ } -+ -+ } -+ yaffs_gross_unlock(dev); -+ return (n_written == 0) && (n > 0) ? -ENOSPC : n_written; -+} -+ -+static int yaffs_write_end(struct file *filp, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned copied, -+ struct page *pg, void *fsdadata) -+{ -+ int ret = 0; -+ void *addr, *kva; -+ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); -+ -+ kva = kmap(pg); -+ addr = kva + offset_into_page; -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_write_end addr %p pos %x n_bytes %d", -+ addr, (unsigned)pos, copied); -+ -+ ret = yaffs_file_write(filp, addr, copied, &pos); -+ -+ if (ret != copied) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_write_end not same size ret %d copied %d", -+ ret, copied); -+ SetPageError(pg); -+ } -+ -+ kunmap(pg); -+ -+ yaffs_release_space(filp); -+ unlock_page(pg); -+ page_cache_release(pg); -+ return ret; -+} -+ -+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; -+ struct super_block *sb = dentry->d_sb; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs"); -+ -+ yaffs_gross_lock(dev); -+ -+ buf->f_type = YAFFS_MAGIC; -+ buf->f_bsize = sb->s_blocksize; -+ buf->f_namelen = 255; -+ -+ if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) { -+ /* Do this if chunk size is not a power of 2 */ -+ -+ uint64_t bytes_in_dev; -+ uint64_t bytes_free; -+ -+ bytes_in_dev = -+ ((uint64_t) -+ ((dev->param.end_block - dev->param.start_block + -+ 1))) * ((uint64_t) (dev->param.chunks_per_block * -+ dev->data_bytes_per_chunk)); -+ -+ do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */ -+ buf->f_blocks = bytes_in_dev; -+ -+ bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) * -+ ((uint64_t) (dev->data_bytes_per_chunk)); -+ -+ do_div(bytes_free, sb->s_blocksize); -+ -+ buf->f_bfree = bytes_free; -+ -+ } else if (sb->s_blocksize > dev->data_bytes_per_chunk) { -+ -+ buf->f_blocks = -+ (dev->param.end_block - dev->param.start_block + 1) * -+ dev->param.chunks_per_block / -+ (sb->s_blocksize / dev->data_bytes_per_chunk); -+ buf->f_bfree = -+ yaffs_get_n_free_chunks(dev) / -+ (sb->s_blocksize / dev->data_bytes_per_chunk); -+ } else { -+ buf->f_blocks = -+ (dev->param.end_block - dev->param.start_block + 1) * -+ dev->param.chunks_per_block * -+ (dev->data_bytes_per_chunk / sb->s_blocksize); -+ -+ buf->f_bfree = -+ yaffs_get_n_free_chunks(dev) * -+ (dev->data_bytes_per_chunk / sb->s_blocksize); -+ } -+ -+ buf->f_files = 0; -+ buf->f_ffree = 0; -+ buf->f_bavail = buf->f_bfree; -+ -+ yaffs_gross_unlock(dev); -+ return 0; -+} -+ -+static void yaffs_flush_inodes(struct super_block *sb) -+{ -+ struct inode *iptr; -+ struct yaffs_obj *obj; -+ -+ list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) { -+ obj = yaffs_inode_to_obj(iptr); -+ if (obj) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "flushing obj %d", obj->obj_id); -+ yaffs_flush_file(obj, 1, 0); -+ } -+ } -+} -+ -+static void yaffs_flush_super(struct super_block *sb, int do_checkpoint) -+{ -+ struct yaffs_dev *dev = yaffs_super_to_dev(sb); -+ if (!dev) -+ return; -+ -+ yaffs_flush_inodes(sb); -+ yaffs_update_dirty_dirs(dev); -+ yaffs_flush_whole_cache(dev); -+ if (do_checkpoint) -+ yaffs_checkpoint_save(dev); -+} -+ -+static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev) -+{ -+ unsigned erased_chunks = -+ dev->n_erased_blocks * dev->param.chunks_per_block; -+ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); -+ unsigned scattered = 0; /* Free chunks not in an erased block */ -+ -+ if (erased_chunks < dev->n_free_chunks) -+ scattered = (dev->n_free_chunks - erased_chunks); -+ -+ if (!context->bg_running) -+ return 0; -+ else if (scattered < (dev->param.chunks_per_block * 2)) -+ return 0; -+ else if (erased_chunks > dev->n_free_chunks / 2) -+ return 0; -+ else if (erased_chunks > dev->n_free_chunks / 4) -+ return 1; -+ else -+ return 2; -+} -+ -+static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint) -+{ -+ -+ struct yaffs_dev *dev = yaffs_super_to_dev(sb); -+ unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); -+ unsigned gc_urgent = yaffs_bg_gc_urgency(dev); -+ int do_checkpoint; -+ -+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, -+ "yaffs_do_sync_fs: gc-urgency %d %s %s%s", -+ gc_urgent, -+ sb->s_dirt ? "dirty" : "clean", -+ request_checkpoint ? "checkpoint requested" : "no checkpoint", -+ oneshot_checkpoint ? " one-shot" : ""); -+ -+ yaffs_gross_lock(dev); -+ do_checkpoint = ((request_checkpoint && !gc_urgent) || -+ oneshot_checkpoint) && !dev->is_checkpointed; -+ -+ if (sb->s_dirt || do_checkpoint) { -+ yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint); -+ sb->s_dirt = 0; -+ if (oneshot_checkpoint) -+ yaffs_auto_checkpoint &= ~4; -+ } -+ yaffs_gross_unlock(dev); -+ -+ return 0; -+} -+ -+/* -+ * yaffs background thread functions . -+ * yaffs_bg_thread_fn() the thread function -+ * yaffs_bg_start() launches the background thread. -+ * yaffs_bg_stop() cleans up the background thread. -+ * -+ * NB: -+ * The thread should only run after the yaffs is initialised -+ * The thread should be stopped before yaffs is unmounted. -+ * The thread should not do any writing while the fs is in read only. -+ */ -+ -+void yaffs_background_waker(unsigned long data) -+{ -+ wake_up_process((struct task_struct *)data); -+} -+ -+static int yaffs_bg_thread_fn(void *data) -+{ -+ struct yaffs_dev *dev = (struct yaffs_dev *)data; -+ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); -+ unsigned long now = jiffies; -+ unsigned long next_dir_update = now; -+ unsigned long next_gc = now; -+ unsigned long expires; -+ unsigned int urgency; -+ -+ int gc_result; -+ struct timer_list timer; -+ -+ yaffs_trace(YAFFS_TRACE_BACKGROUND, -+ "yaffs_background starting for dev %p", (void *)dev); -+ -+ set_freezable(); -+ while (context->bg_running) { -+ yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background"); -+ -+ if (kthread_should_stop()) -+ break; -+ -+ if (try_to_freeze()) -+ continue; -+ -+ yaffs_gross_lock(dev); -+ -+ now = jiffies; -+ -+ if (time_after(now, next_dir_update) && yaffs_bg_enable) { -+ yaffs_update_dirty_dirs(dev); -+ next_dir_update = now + HZ; -+ } -+ -+ if (time_after(now, next_gc) && yaffs_bg_enable) { -+ if (!dev->is_checkpointed) { -+ urgency = yaffs_bg_gc_urgency(dev); -+ gc_result = yaffs_bg_gc(dev, urgency); -+ if (urgency > 1) -+ next_gc = now + HZ / 20 + 1; -+ else if (urgency > 0) -+ next_gc = now + HZ / 10 + 1; -+ else -+ next_gc = now + HZ * 2; -+ } else { -+ /* -+ * gc not running so set to next_dir_update -+ * to cut down on wake ups -+ */ -+ next_gc = next_dir_update; -+ } -+ } -+ yaffs_gross_unlock(dev); -+ expires = next_dir_update; -+ if (time_before(next_gc, expires)) -+ expires = next_gc; -+ if (time_before(expires, now)) -+ expires = now + HZ; -+ -+ Y_INIT_TIMER(&timer); -+ timer.expires = expires + 1; -+ timer.data = (unsigned long)current; -+ timer.function = yaffs_background_waker; -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ add_timer(&timer); -+ schedule(); -+ del_timer_sync(&timer); -+ } -+ -+ return 0; -+} -+ -+static int yaffs_bg_start(struct yaffs_dev *dev) -+{ -+ int retval = 0; -+ struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); -+ -+ if (dev->read_only) -+ return -1; -+ -+ context->bg_running = 1; -+ -+ context->bg_thread = kthread_run(yaffs_bg_thread_fn, -+ (void *)dev, "yaffs-bg-%d", -+ context->mount_id); -+ -+ if (IS_ERR(context->bg_thread)) { -+ retval = PTR_ERR(context->bg_thread); -+ context->bg_thread = NULL; -+ context->bg_running = 0; -+ } -+ return retval; -+} -+ -+static void yaffs_bg_stop(struct yaffs_dev *dev) -+{ -+ struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev); -+ -+ ctxt->bg_running = 0; -+ -+ if (ctxt->bg_thread) { -+ kthread_stop(ctxt->bg_thread); -+ ctxt->bg_thread = NULL; -+ } -+} -+ -+static void yaffs_write_super(struct super_block *sb) -+{ -+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); -+ -+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, -+ "yaffs_write_super%s", -+ request_checkpoint ? " checkpt" : ""); -+ -+ yaffs_do_sync_fs(sb, request_checkpoint); -+ -+} -+ -+static int yaffs_sync_fs(struct super_block *sb, int wait) -+{ -+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); -+ -+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, -+ "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : ""); -+ -+ yaffs_do_sync_fs(sb, request_checkpoint); -+ -+ return 0; -+} -+ -+ -+static LIST_HEAD(yaffs_context_list); -+struct mutex yaffs_context_lock; -+ -+ -+ -+struct yaffs_options { -+ int inband_tags; -+ int skip_checkpoint_read; -+ int skip_checkpoint_write; -+ int no_cache; -+ int tags_ecc_on; -+ int tags_ecc_overridden; -+ int lazy_loading_enabled; -+ int lazy_loading_overridden; -+ int empty_lost_and_found; -+ int empty_lost_and_found_overridden; -+}; -+ -+#define MAX_OPT_LEN 30 -+static int yaffs_parse_options(struct yaffs_options *options, -+ const char *options_str) -+{ -+ char cur_opt[MAX_OPT_LEN + 1]; -+ int p; -+ int error = 0; -+ -+ /* Parse through the options which is a comma seperated list */ -+ -+ while (options_str && *options_str && !error) { -+ memset(cur_opt, 0, MAX_OPT_LEN + 1); -+ p = 0; -+ -+ while (*options_str == ',') -+ options_str++; -+ -+ while (*options_str && *options_str != ',') { -+ if (p < MAX_OPT_LEN) { -+ cur_opt[p] = *options_str; -+ p++; -+ } -+ options_str++; -+ } -+ -+ if (!strcmp(cur_opt, "inband-tags")) { -+ options->inband_tags = 1; -+ } else if (!strcmp(cur_opt, "tags-ecc-off")) { -+ options->tags_ecc_on = 0; -+ options->tags_ecc_overridden = 1; -+ } else if (!strcmp(cur_opt, "tags-ecc-on")) { -+ options->tags_ecc_on = 1; -+ options->tags_ecc_overridden = 1; -+ } else if (!strcmp(cur_opt, "lazy-loading-off")) { -+ options->lazy_loading_enabled = 0; -+ options->lazy_loading_overridden = 1; -+ } else if (!strcmp(cur_opt, "lazy-loading-on")) { -+ options->lazy_loading_enabled = 1; -+ options->lazy_loading_overridden = 1; -+ } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) { -+ options->empty_lost_and_found = 0; -+ options->empty_lost_and_found_overridden = 1; -+ } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) { -+ options->empty_lost_and_found = 1; -+ options->empty_lost_and_found_overridden = 1; -+ } else if (!strcmp(cur_opt, "no-cache")) { -+ options->no_cache = 1; -+ } else if (!strcmp(cur_opt, "no-checkpoint-read")) { -+ options->skip_checkpoint_read = 1; -+ } else if (!strcmp(cur_opt, "no-checkpoint-write")) { -+ options->skip_checkpoint_write = 1; -+ } else if (!strcmp(cur_opt, "no-checkpoint")) { -+ options->skip_checkpoint_read = 1; -+ options->skip_checkpoint_write = 1; -+ } else { -+ printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", -+ cur_opt); -+ error = 1; -+ } -+ } -+ -+ return error; -+} -+ -+static struct address_space_operations yaffs_file_address_operations = { -+ .readpage = yaffs_readpage, -+ .writepage = yaffs_writepage, -+ .write_begin = yaffs_write_begin, -+ .write_end = yaffs_write_end, -+}; -+ -+ -+ -+static const struct inode_operations yaffs_file_inode_operations = { -+ .setattr = yaffs_setattr, -+#ifdef CONFIG_YAFFS_XATTR -+ .setxattr = yaffs_setxattr, -+ .getxattr = yaffs_getxattr, -+ .listxattr = yaffs_listxattr, -+ .removexattr = yaffs_removexattr, -+#endif -+}; -+ -+static const struct inode_operations yaffs_symlink_inode_operations = { -+ .readlink = yaffs_readlink, -+ .follow_link = yaffs_follow_link, -+ .put_link = yaffs_put_link, -+ .setattr = yaffs_setattr, -+#ifdef CONFIG_YAFFS_XATTR -+ .setxattr = yaffs_setxattr, -+ .getxattr = yaffs_getxattr, -+ .listxattr = yaffs_listxattr, -+ .removexattr = yaffs_removexattr, -+#endif -+}; -+ -+static void yaffs_fill_inode_from_obj(struct inode *inode, -+ struct yaffs_obj *obj) -+{ -+ if (inode && obj) { -+ -+ /* Check mode against the variant type and attempt to repair if broken. */ -+ u32 mode = obj->yst_mode; -+ switch (obj->variant_type) { -+ case YAFFS_OBJECT_TYPE_FILE: -+ if (!S_ISREG(mode)) { -+ obj->yst_mode &= ~S_IFMT; -+ obj->yst_mode |= S_IFREG; -+ } -+ -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ if (!S_ISLNK(mode)) { -+ obj->yst_mode &= ~S_IFMT; -+ obj->yst_mode |= S_IFLNK; -+ } -+ -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ if (!S_ISDIR(mode)) { -+ obj->yst_mode &= ~S_IFMT; -+ obj->yst_mode |= S_IFDIR; -+ } -+ -+ break; -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ default: -+ /* TODO? */ -+ break; -+ } -+ -+ inode->i_flags |= S_NOATIME; -+ -+ inode->i_ino = obj->obj_id; -+ inode->i_mode = obj->yst_mode; -+ inode->i_uid = obj->yst_uid; -+ inode->i_gid = obj->yst_gid; -+ -+ inode->i_rdev = old_decode_dev(obj->yst_rdev); -+ -+ inode->i_atime.tv_sec = (time_t) (obj->yst_atime); -+ inode->i_atime.tv_nsec = 0; -+ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; -+ inode->i_mtime.tv_nsec = 0; -+ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; -+ inode->i_ctime.tv_nsec = 0; -+ inode->i_size = yaffs_get_obj_length(obj); -+ inode->i_blocks = (inode->i_size + 511) >> 9; -+ -+ inode->i_nlink = yaffs_get_obj_link_count(obj); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_fill_inode mode %x uid %d gid %d size %d count %d", -+ inode->i_mode, inode->i_uid, inode->i_gid, -+ (int)inode->i_size, atomic_read(&inode->i_count)); -+ -+ switch (obj->yst_mode & S_IFMT) { -+ default: /* fifo, device or socket */ -+ init_special_inode(inode, obj->yst_mode, -+ old_decode_dev(obj->yst_rdev)); -+ break; -+ case S_IFREG: /* file */ -+ inode->i_op = &yaffs_file_inode_operations; -+ inode->i_fop = &yaffs_file_operations; -+ inode->i_mapping->a_ops = -+ &yaffs_file_address_operations; -+ break; -+ case S_IFDIR: /* directory */ -+ inode->i_op = &yaffs_dir_inode_operations; -+ inode->i_fop = &yaffs_dir_operations; -+ break; -+ case S_IFLNK: /* symlink */ -+ inode->i_op = &yaffs_symlink_inode_operations; -+ break; -+ } -+ -+ yaffs_inode_to_obj_lv(inode) = obj; -+ -+ obj->my_inode = inode; -+ -+ } else { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_fill_inode invalid parameters"); -+ } -+} -+ -+static void yaffs_put_super(struct super_block *sb) -+{ -+ struct yaffs_dev *dev = yaffs_super_to_dev(sb); -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_put_super"); -+ -+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, -+ "Shutting down yaffs background thread"); -+ yaffs_bg_stop(dev); -+ yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, -+ "yaffs background thread shut down"); -+ -+ yaffs_gross_lock(dev); -+ -+ yaffs_flush_super(sb, 1); -+ -+ if (yaffs_dev_to_lc(dev)->put_super_fn) -+ yaffs_dev_to_lc(dev)->put_super_fn(sb); -+ -+ yaffs_deinitialise(dev); -+ -+ yaffs_gross_unlock(dev); -+ mutex_lock(&yaffs_context_lock); -+ list_del_init(&(yaffs_dev_to_lc(dev)->context_list)); -+ mutex_unlock(&yaffs_context_lock); -+ -+ if (yaffs_dev_to_lc(dev)->spare_buffer) { -+ kfree(yaffs_dev_to_lc(dev)->spare_buffer); -+ yaffs_dev_to_lc(dev)->spare_buffer = NULL; -+ } -+ -+ kfree(dev); -+} -+ -+static void yaffs_mtd_put_super(struct super_block *sb) -+{ -+ struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_super_to_dev(sb)); -+ -+ if (mtd->sync) -+ mtd->sync(mtd); -+ -+ put_mtd_device(mtd); -+} -+ -+static const struct super_operations yaffs_super_ops = { -+ .statfs = yaffs_statfs, -+ .put_super = yaffs_put_super, -+ .evict_inode = yaffs_evict_inode, -+ .sync_fs = yaffs_sync_fs, -+ .write_super = yaffs_write_super, -+}; -+ -+static struct super_block *yaffs_internal_read_super(int yaffs_version, -+ struct super_block *sb, -+ void *data, int silent) -+{ -+ int n_blocks; -+ struct inode *inode = NULL; -+ struct dentry *root; -+ struct yaffs_dev *dev = 0; -+ char devname_buf[BDEVNAME_SIZE + 1]; -+ struct mtd_info *mtd; -+ int err; -+ char *data_str = (char *)data; -+ struct yaffs_linux_context *context = NULL; -+ struct yaffs_param *param; -+ -+ int read_only = 0; -+ -+ struct yaffs_options options; -+ -+ unsigned mount_id; -+ int found; -+ struct yaffs_linux_context *context_iterator; -+ struct list_head *l; -+ -+ sb->s_magic = YAFFS_MAGIC; -+ sb->s_op = &yaffs_super_ops; -+ sb->s_flags |= MS_NOATIME; -+ -+ read_only = ((sb->s_flags & MS_RDONLY) != 0); -+ -+ sb->s_export_op = &yaffs_export_ops; -+ -+ if (!sb) -+ printk(KERN_INFO "yaffs: sb is NULL\n"); -+ else if (!sb->s_dev) -+ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); -+ else if (!yaffs_devname(sb, devname_buf)) -+ printk(KERN_INFO "yaffs: devname is NULL\n"); -+ else -+ printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", -+ sb->s_dev, -+ yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw"); -+ -+ if (!data_str) -+ data_str = ""; -+ -+ printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); -+ -+ memset(&options, 0, sizeof(options)); -+ -+ if (yaffs_parse_options(&options, data_str)) { -+ /* Option parsing failed */ -+ return NULL; -+ } -+ -+ sb->s_blocksize = PAGE_CACHE_SIZE; -+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_read_super: Using yaffs%d", yaffs_version); -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_read_super: block size %d", (int)(sb->s_blocksize)); -+ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "Attempting MTD mount of %u.%u,\"%s\"", -+ MAJOR(sb->s_dev), MINOR(sb->s_dev), -+ yaffs_devname(sb, devname_buf)); -+ -+ /* Check it's an mtd device..... */ -+ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) -+ return NULL; /* This isn't an mtd device */ -+ -+ /* Get the device */ -+ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); -+ if (!mtd) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "MTD device #%u doesn't appear to exist", -+ MINOR(sb->s_dev)); -+ return NULL; -+ } -+ /* Check it's NAND */ -+ if (mtd->type != MTD_NANDFLASH) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "MTD device is not NAND it's type %d", -+ mtd->type); -+ return NULL; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, " erase %p", mtd->erase); -+ yaffs_trace(YAFFS_TRACE_OS, " read %p", mtd->read); -+ yaffs_trace(YAFFS_TRACE_OS, " write %p", mtd->write); -+ yaffs_trace(YAFFS_TRACE_OS, " readoob %p", mtd->read_oob); -+ yaffs_trace(YAFFS_TRACE_OS, " writeoob %p", mtd->write_oob); -+ yaffs_trace(YAFFS_TRACE_OS, " block_isbad %p", mtd->block_isbad); -+ yaffs_trace(YAFFS_TRACE_OS, " block_markbad %p", mtd->block_markbad); -+ yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd)); -+ yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize); -+ yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize); -+ yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size); -+ -+#ifdef CONFIG_YAFFS_AUTO_YAFFS2 -+ -+ if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2"); -+ yaffs_version = 2; -+ } -+ -+ /* Added NCB 26/5/2006 for completeness */ -+ if (yaffs_version == 2 && !options.inband_tags -+ && WRITE_SIZE(mtd) == 512) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); -+ yaffs_version = 1; -+ } -+#endif -+ -+ if (yaffs_version == 2) { -+ /* Check for version 2 style functions */ -+ if (!mtd->erase || -+ !mtd->block_isbad || -+ !mtd->block_markbad || -+ !mtd->read || -+ !mtd->write || !mtd->read_oob || !mtd->write_oob) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "MTD device does not support required functions"); -+ return NULL; -+ } -+ -+ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || -+ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && -+ !options.inband_tags) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "MTD device does not have the right page sizes"); -+ return NULL; -+ } -+ } else { -+ /* Check for V1 style functions */ -+ if (!mtd->erase || -+ !mtd->read || -+ !mtd->write || !mtd->read_oob || !mtd->write_oob) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "MTD device does not support required functions"); -+ return NULL; -+ } -+ -+ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || -+ mtd->oobsize != YAFFS_BYTES_PER_SPARE) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "MTD device does not support have the right page sizes"); -+ return NULL; -+ } -+ } -+ -+ /* OK, so if we got here, we have an MTD that's NAND and looks -+ * like it has the right capabilities -+ * Set the struct yaffs_dev up for mtd -+ */ -+ -+ if (!read_only && !(mtd->flags & MTD_WRITEABLE)) { -+ read_only = 1; -+ printk(KERN_INFO -+ "yaffs: mtd is read only, setting superblock read only"); -+ sb->s_flags |= MS_RDONLY; -+ } -+ -+ dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL); -+ context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL); -+ -+ if (!dev || !context) { -+ if (dev) -+ kfree(dev); -+ if (context) -+ kfree(context); -+ dev = NULL; -+ context = NULL; -+ } -+ -+ if (!dev) { -+ /* Deep shit could not allocate device structure */ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs_read_super failed trying to allocate yaffs_dev"); -+ return NULL; -+ } -+ memset(dev, 0, sizeof(struct yaffs_dev)); -+ param = &(dev->param); -+ -+ memset(context, 0, sizeof(struct yaffs_linux_context)); -+ dev->os_context = context; -+ INIT_LIST_HEAD(&(context->context_list)); -+ context->dev = dev; -+ context->super = sb; -+ -+ dev->read_only = read_only; -+ -+ sb->s_fs_info = dev; -+ -+ dev->driver_context = mtd; -+ param->name = mtd->name; -+ -+ /* Set up the memory size parameters.... */ -+ -+ n_blocks = -+ YCALCBLOCKS(mtd->size, -+ (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); -+ -+ param->start_block = 0; -+ param->end_block = n_blocks - 1; -+ param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK; -+ param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK; -+ param->n_reserved_blocks = 5; -+ param->n_caches = (options.no_cache) ? 0 : 10; -+ param->inband_tags = options.inband_tags; -+ -+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD -+ param->disable_lazy_load = 1; -+#endif -+#ifdef CONFIG_YAFFS_XATTR -+ param->enable_xattr = 1; -+#endif -+ if (options.lazy_loading_overridden) -+ param->disable_lazy_load = !options.lazy_loading_enabled; -+ -+#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC -+ param->no_tags_ecc = 1; -+#endif -+ -+#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND -+#else -+ param->defered_dir_update = 1; -+#endif -+ -+ if (options.tags_ecc_overridden) -+ param->no_tags_ecc = !options.tags_ecc_on; -+ -+#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND -+ param->empty_lost_n_found = 1; -+#endif -+ -+#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING -+ param->refresh_period = 0; -+#else -+ param->refresh_period = 500; -+#endif -+ -+#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED -+ param->always_check_erased = 1; -+#endif -+ -+ if (options.empty_lost_and_found_overridden) -+ param->empty_lost_n_found = options.empty_lost_and_found; -+ -+ /* ... and the functions. */ -+ if (yaffs_version == 2) { -+ param->write_chunk_tags_fn = nandmtd2_write_chunk_tags; -+ param->read_chunk_tags_fn = nandmtd2_read_chunk_tags; -+ param->bad_block_fn = nandmtd2_mark_block_bad; -+ param->query_block_fn = nandmtd2_query_block; -+ yaffs_dev_to_lc(dev)->spare_buffer = -+ kmalloc(mtd->oobsize, GFP_NOFS); -+ param->is_yaffs2 = 1; -+ param->total_bytes_per_chunk = mtd->writesize; -+ param->chunks_per_block = mtd->erasesize / mtd->writesize; -+ n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize); -+ -+ param->start_block = 0; -+ param->end_block = n_blocks - 1; -+ } else { -+ /* use the MTD interface in yaffs_mtdif1.c */ -+ param->write_chunk_tags_fn = nandmtd1_write_chunk_tags; -+ param->read_chunk_tags_fn = nandmtd1_read_chunk_tags; -+ param->bad_block_fn = nandmtd1_mark_block_bad; -+ param->query_block_fn = nandmtd1_query_block; -+ param->is_yaffs2 = 0; -+ } -+ /* ... and common functions */ -+ param->erase_fn = nandmtd_erase_block; -+ param->initialise_flash_fn = nandmtd_initialise; -+ -+ yaffs_dev_to_lc(dev)->put_super_fn = yaffs_mtd_put_super; -+ -+ param->sb_dirty_fn = yaffs_touch_super; -+ param->gc_control = yaffs_gc_control_callback; -+ -+ yaffs_dev_to_lc(dev)->super = sb; -+ -+#ifndef CONFIG_YAFFS_DOES_ECC -+ param->use_nand_ecc = 1; -+#endif -+ -+ param->skip_checkpt_rd = options.skip_checkpoint_read; -+ param->skip_checkpt_wr = options.skip_checkpoint_write; -+ -+ mutex_lock(&yaffs_context_lock); -+ /* Get a mount id */ -+ found = 0; -+ for (mount_id = 0; !found; mount_id++) { -+ found = 1; -+ list_for_each(l, &yaffs_context_list) { -+ context_iterator = -+ list_entry(l, struct yaffs_linux_context, -+ context_list); -+ if (context_iterator->mount_id == mount_id) -+ found = 0; -+ } -+ } -+ context->mount_id = mount_id; -+ -+ list_add_tail(&(yaffs_dev_to_lc(dev)->context_list), -+ &yaffs_context_list); -+ mutex_unlock(&yaffs_context_lock); -+ -+ /* Directory search handling... */ -+ INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts)); -+ param->remove_obj_fn = yaffs_remove_obj_callback; -+ -+ mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock)); -+ -+ yaffs_gross_lock(dev); -+ -+ err = yaffs_guts_initialise(dev); -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_read_super: guts initialised %s", -+ (err == YAFFS_OK) ? "OK" : "FAILED"); -+ -+ if (err == YAFFS_OK) -+ yaffs_bg_start(dev); -+ -+ if (!context->bg_thread) -+ param->defered_dir_update = 0; -+ -+ /* Release lock before yaffs_get_inode() */ -+ yaffs_gross_unlock(dev); -+ -+ /* Create root inode */ -+ if (err == YAFFS_OK) -+ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev)); -+ -+ if (!inode) -+ return NULL; -+ -+ inode->i_op = &yaffs_dir_inode_operations; -+ inode->i_fop = &yaffs_dir_operations; -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode"); -+ -+ root = d_alloc_root(inode); -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: d_alloc_root done"); -+ -+ if (!root) { -+ iput(inode); -+ return NULL; -+ } -+ sb->s_root = root; -+ sb->s_dirt = !dev->is_checkpointed; -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs_read_super: is_checkpointed %d", -+ dev->is_checkpointed); -+ -+ yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done"); -+ return sb; -+} -+ -+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, -+ int silent) -+{ -+ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; -+} -+ -+static int yaffs_read_super(struct file_system_type *fs, -+ int flags, const char *dev_name, -+ void *data, struct vfsmount *mnt) -+{ -+ -+ return get_sb_bdev(fs, flags, dev_name, data, -+ yaffs_internal_read_super_mtd, mnt); -+} -+ -+static struct file_system_type yaffs_fs_type = { -+ .owner = THIS_MODULE, -+ .name = "yaffs", -+ .get_sb = yaffs_read_super, -+ .kill_sb = kill_block_super, -+ .fs_flags = FS_REQUIRES_DEV, -+}; -+ -+#ifdef CONFIG_YAFFS_YAFFS2 -+ -+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, -+ int silent) -+{ -+ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; -+} -+ -+static int yaffs2_read_super(struct file_system_type *fs, -+ int flags, const char *dev_name, void *data, -+ struct vfsmount *mnt) -+{ -+ return get_sb_bdev(fs, flags, dev_name, data, -+ yaffs2_internal_read_super_mtd, mnt); -+} -+ -+static struct file_system_type yaffs2_fs_type = { -+ .owner = THIS_MODULE, -+ .name = "yaffs2", -+ .get_sb = yaffs2_read_super, -+ .kill_sb = kill_block_super, -+ .fs_flags = FS_REQUIRES_DEV, -+}; -+#endif /* CONFIG_YAFFS_YAFFS2 */ -+ -+static struct proc_dir_entry *my_proc_entry; -+ -+static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) -+{ -+ struct yaffs_param *param = &dev->param; -+ buf += sprintf(buf, "start_block........... %d\n", param->start_block); -+ buf += sprintf(buf, "end_block............. %d\n", param->end_block); -+ buf += sprintf(buf, "total_bytes_per_chunk. %d\n", -+ param->total_bytes_per_chunk); -+ buf += sprintf(buf, "use_nand_ecc.......... %d\n", -+ param->use_nand_ecc); -+ buf += sprintf(buf, "no_tags_ecc........... %d\n", param->no_tags_ecc); -+ buf += sprintf(buf, "is_yaffs2............. %d\n", param->is_yaffs2); -+ buf += sprintf(buf, "inband_tags........... %d\n", param->inband_tags); -+ buf += sprintf(buf, "empty_lost_n_found.... %d\n", -+ param->empty_lost_n_found); -+ buf += sprintf(buf, "disable_lazy_load..... %d\n", -+ param->disable_lazy_load); -+ buf += sprintf(buf, "refresh_period........ %d\n", -+ param->refresh_period); -+ buf += sprintf(buf, "n_caches.............. %d\n", param->n_caches); -+ buf += sprintf(buf, "n_reserved_blocks..... %d\n", -+ param->n_reserved_blocks); -+ buf += sprintf(buf, "always_check_erased... %d\n", -+ param->always_check_erased); -+ -+ return buf; -+} -+ -+static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev) -+{ -+ buf += -+ sprintf(buf, "data_bytes_per_chunk.. %d\n", -+ dev->data_bytes_per_chunk); -+ buf += sprintf(buf, "chunk_grp_bits........ %d\n", dev->chunk_grp_bits); -+ buf += sprintf(buf, "chunk_grp_size........ %d\n", dev->chunk_grp_size); -+ buf += -+ sprintf(buf, "n_erased_blocks....... %d\n", dev->n_erased_blocks); -+ buf += -+ sprintf(buf, "blocks_in_checkpt..... %d\n", dev->blocks_in_checkpt); -+ buf += sprintf(buf, "\n"); -+ buf += sprintf(buf, "n_tnodes.............. %d\n", dev->n_tnodes); -+ buf += sprintf(buf, "n_obj................. %d\n", dev->n_obj); -+ buf += sprintf(buf, "n_free_chunks......... %d\n", dev->n_free_chunks); -+ buf += sprintf(buf, "\n"); -+ buf += sprintf(buf, "n_page_writes......... %u\n", dev->n_page_writes); -+ buf += sprintf(buf, "n_page_reads.......... %u\n", dev->n_page_reads); -+ buf += sprintf(buf, "n_erasures............ %u\n", dev->n_erasures); -+ buf += sprintf(buf, "n_gc_copies........... %u\n", dev->n_gc_copies); -+ buf += sprintf(buf, "all_gcs............... %u\n", dev->all_gcs); -+ buf += -+ sprintf(buf, "passive_gc_count...... %u\n", dev->passive_gc_count); -+ buf += -+ sprintf(buf, "oldest_dirty_gc_count. %u\n", -+ dev->oldest_dirty_gc_count); -+ buf += sprintf(buf, "n_gc_blocks........... %u\n", dev->n_gc_blocks); -+ buf += sprintf(buf, "bg_gcs................ %u\n", dev->bg_gcs); -+ buf += -+ sprintf(buf, "n_retired_writes...... %u\n", dev->n_retired_writes); -+ buf += -+ sprintf(buf, "n_retired_blocks...... %u\n", dev->n_retired_blocks); -+ buf += sprintf(buf, "n_ecc_fixed........... %u\n", dev->n_ecc_fixed); -+ buf += sprintf(buf, "n_ecc_unfixed......... %u\n", dev->n_ecc_unfixed); -+ buf += -+ sprintf(buf, "n_tags_ecc_fixed...... %u\n", dev->n_tags_ecc_fixed); -+ buf += -+ sprintf(buf, "n_tags_ecc_unfixed.... %u\n", -+ dev->n_tags_ecc_unfixed); -+ buf += sprintf(buf, "cache_hits............ %u\n", dev->cache_hits); -+ buf += -+ sprintf(buf, "n_deleted_files....... %u\n", dev->n_deleted_files); -+ buf += -+ sprintf(buf, "n_unlinked_files...... %u\n", dev->n_unlinked_files); -+ buf += sprintf(buf, "refresh_count......... %u\n", dev->refresh_count); -+ buf += sprintf(buf, "n_bg_deletions........ %u\n", dev->n_bg_deletions); -+ -+ return buf; -+} -+ -+static int yaffs_proc_read(char *page, -+ char **start, -+ off_t offset, int count, int *eof, void *data) -+{ -+ struct list_head *item; -+ char *buf = page; -+ int step = offset; -+ int n = 0; -+ -+ /* Get proc_file_read() to step 'offset' by one on each sucessive call. -+ * We use 'offset' (*ppos) to indicate where we are in dev_list. -+ * This also assumes the user has posted a read buffer large -+ * enough to hold the complete output; but that's life in /proc. -+ */ -+ -+ *(int *)start = 1; -+ -+ /* Print header first */ -+ if (step == 0) -+ buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ "\n"); -+ else if (step == 1) -+ buf += sprintf(buf, "\n"); -+ else { -+ step -= 2; -+ -+ mutex_lock(&yaffs_context_lock); -+ -+ /* Locate and print the Nth entry. Order N-squared but N is small. */ -+ list_for_each(item, &yaffs_context_list) { -+ struct yaffs_linux_context *dc = -+ list_entry(item, struct yaffs_linux_context, -+ context_list); -+ struct yaffs_dev *dev = dc->dev; -+ -+ if (n < (step & ~1)) { -+ n += 2; -+ continue; -+ } -+ if ((step & 1) == 0) { -+ buf += -+ sprintf(buf, "\nDevice %d \"%s\"\n", n, -+ dev->param.name); -+ buf = yaffs_dump_dev_part0(buf, dev); -+ } else { -+ buf = yaffs_dump_dev_part1(buf, dev); -+ } -+ -+ break; -+ } -+ mutex_unlock(&yaffs_context_lock); -+ } -+ -+ return buf - page < count ? buf - page : count; -+} -+ -+ -+/** -+ * Set the verbosity of the warnings and error messages. -+ * -+ * Note that the names can only be a..z or _ with the current code. -+ */ -+ -+static struct { -+ char *mask_name; -+ unsigned mask_bitfield; -+} mask_flags[] = { -+ {"allocate", YAFFS_TRACE_ALLOCATE}, -+ {"always", YAFFS_TRACE_ALWAYS}, -+ {"background", YAFFS_TRACE_BACKGROUND}, -+ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, -+ {"buffers", YAFFS_TRACE_BUFFERS}, -+ {"bug", YAFFS_TRACE_BUG}, -+ {"checkpt", YAFFS_TRACE_CHECKPOINT}, -+ {"deletion", YAFFS_TRACE_DELETION}, -+ {"erase", YAFFS_TRACE_ERASE}, -+ {"error", YAFFS_TRACE_ERROR}, -+ {"gc_detail", YAFFS_TRACE_GC_DETAIL}, -+ {"gc", YAFFS_TRACE_GC}, -+ {"lock", YAFFS_TRACE_LOCK}, -+ {"mtd", YAFFS_TRACE_MTD}, -+ {"nandaccess", YAFFS_TRACE_NANDACCESS}, -+ {"os", YAFFS_TRACE_OS}, -+ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, -+ {"scan", YAFFS_TRACE_SCAN}, -+ {"mount", YAFFS_TRACE_MOUNT}, -+ {"tracing", YAFFS_TRACE_TRACING}, -+ {"sync", YAFFS_TRACE_SYNC}, -+ {"write", YAFFS_TRACE_WRITE}, -+ {"verify", YAFFS_TRACE_VERIFY}, -+ {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, -+ {"verify_full", YAFFS_TRACE_VERIFY_FULL}, -+ {"verify_all", YAFFS_TRACE_VERIFY_ALL}, -+ {"all", 0xffffffff}, -+ {"none", 0}, -+ {NULL, 0}, -+}; -+ -+#define MAX_MASK_NAME_LENGTH 40 -+static int yaffs_proc_write_trace_options(struct file *file, const char *buf, -+ unsigned long count, void *data) -+{ -+ unsigned rg = 0, mask_bitfield; -+ char *end; -+ char *mask_name; -+ const char *x; -+ char substring[MAX_MASK_NAME_LENGTH + 1]; -+ int i; -+ int done = 0; -+ int add, len = 0; -+ int pos = 0; -+ -+ rg = yaffs_trace_mask; -+ -+ while (!done && (pos < count)) { -+ done = 1; -+ while ((pos < count) && isspace(buf[pos])) -+ pos++; -+ -+ switch (buf[pos]) { -+ case '+': -+ case '-': -+ case '=': -+ add = buf[pos]; -+ pos++; -+ break; -+ -+ default: -+ add = ' '; -+ break; -+ } -+ mask_name = NULL; -+ -+ mask_bitfield = simple_strtoul(buf + pos, &end, 0); -+ -+ if (end > buf + pos) { -+ mask_name = "numeral"; -+ len = end - (buf + pos); -+ pos += len; -+ done = 0; -+ } else { -+ for (x = buf + pos, i = 0; -+ (*x == '_' || (*x >= 'a' && *x <= 'z')) && -+ i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) -+ substring[i] = *x; -+ substring[i] = '\0'; -+ -+ for (i = 0; mask_flags[i].mask_name != NULL; i++) { -+ if (strcmp(substring, mask_flags[i].mask_name) -+ == 0) { -+ mask_name = mask_flags[i].mask_name; -+ mask_bitfield = -+ mask_flags[i].mask_bitfield; -+ done = 0; -+ break; -+ } -+ } -+ } -+ -+ if (mask_name != NULL) { -+ done = 0; -+ switch (add) { -+ case '-': -+ rg &= ~mask_bitfield; -+ break; -+ case '+': -+ rg |= mask_bitfield; -+ break; -+ case '=': -+ rg = mask_bitfield; -+ break; -+ default: -+ rg |= mask_bitfield; -+ break; -+ } -+ } -+ } -+ -+ yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS; -+ -+ printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask); -+ -+ if (rg & YAFFS_TRACE_ALWAYS) { -+ for (i = 0; mask_flags[i].mask_name != NULL; i++) { -+ char flag; -+ flag = ((rg & mask_flags[i].mask_bitfield) == -+ mask_flags[i].mask_bitfield) ? '+' : '-'; -+ printk(KERN_DEBUG "%c%s\n", flag, -+ mask_flags[i].mask_name); -+ } -+ } -+ -+ return count; -+} -+ -+static int yaffs_proc_write(struct file *file, const char *buf, -+ unsigned long count, void *data) -+{ -+ return yaffs_proc_write_trace_options(file, buf, count, data); -+} -+ -+/* Stuff to handle installation of file systems */ -+struct file_system_to_install { -+ struct file_system_type *fst; -+ int installed; -+}; -+ -+static struct file_system_to_install fs_to_install[] = { -+ {&yaffs_fs_type, 0}, -+ {&yaffs2_fs_type, 0}, -+ {NULL, 0} -+}; -+ -+static int __init init_yaffs_fs(void) -+{ -+ int error = 0; -+ struct file_system_to_install *fsinst; -+ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs built " __DATE__ " " __TIME__ " Installing."); -+ -+#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n"); -+#endif -+ -+ mutex_init(&yaffs_context_lock); -+ -+ /* Install the proc_fs entries */ -+ my_proc_entry = create_proc_entry("yaffs", -+ S_IRUGO | S_IFREG, YPROC_ROOT); -+ -+ if (my_proc_entry) { -+ my_proc_entry->write_proc = yaffs_proc_write; -+ my_proc_entry->read_proc = yaffs_proc_read; -+ my_proc_entry->data = NULL; -+ } else { -+ return -ENOMEM; -+ } -+ -+ -+ /* Now add the file system entries */ -+ -+ fsinst = fs_to_install; -+ -+ while (fsinst->fst && !error) { -+ error = register_filesystem(fsinst->fst); -+ if (!error) -+ fsinst->installed = 1; -+ fsinst++; -+ } -+ -+ /* Any errors? uninstall */ -+ if (error) { -+ fsinst = fs_to_install; -+ -+ while (fsinst->fst) { -+ if (fsinst->installed) { -+ unregister_filesystem(fsinst->fst); -+ fsinst->installed = 0; -+ } -+ fsinst++; -+ } -+ } -+ -+ return error; -+} -+ -+static void __exit exit_yaffs_fs(void) -+{ -+ -+ struct file_system_to_install *fsinst; -+ -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "yaffs built " __DATE__ " " __TIME__ " removing."); -+ -+ remove_proc_entry("yaffs", YPROC_ROOT); -+ -+ fsinst = fs_to_install; -+ -+ while (fsinst->fst) { -+ if (fsinst->installed) { -+ unregister_filesystem(fsinst->fst); -+ fsinst->installed = 0; -+ } -+ fsinst++; -+ } -+} -+ -+module_init(init_yaffs_fs) -+ module_exit(exit_yaffs_fs) -+ -+ MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); -+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010"); -+MODULE_LICENSE("GPL"); -diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c -new file mode 100644 -index 00000000..9eb60308 ---- /dev/null -+++ b/fs/yaffs2/yaffs_yaffs1.c -@@ -0,0 +1,433 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_yaffs1.h" -+#include "yportenv.h" -+#include "yaffs_trace.h" -+#include "yaffs_bitmap.h" -+#include "yaffs_getblockinfo.h" -+#include "yaffs_nand.h" -+#include "yaffs_attribs.h" -+ -+int yaffs1_scan(struct yaffs_dev *dev) -+{ -+ struct yaffs_ext_tags tags; -+ int blk; -+ int result; -+ -+ int chunk; -+ int c; -+ int deleted; -+ enum yaffs_block_state state; -+ struct yaffs_obj *hard_list = NULL; -+ struct yaffs_block_info *bi; -+ u32 seq_number; -+ struct yaffs_obj_hdr *oh; -+ struct yaffs_obj *in; -+ struct yaffs_obj *parent; -+ -+ int alloc_failed = 0; -+ -+ struct yaffs_shadow_fixer *shadow_fixers = NULL; -+ -+ u8 *chunk_data; -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "yaffs1_scan starts intstartblk %d intendblk %d...", -+ dev->internal_start_block, dev->internal_end_block); -+ -+ chunk_data = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; -+ -+ /* Scan all the blocks to determine their state */ -+ bi = dev->block_info; -+ for (blk = dev->internal_start_block; blk <= dev->internal_end_block; -+ blk++) { -+ yaffs_clear_chunk_bits(dev, blk); -+ bi->pages_in_use = 0; -+ bi->soft_del_pages = 0; -+ -+ yaffs_query_init_block_state(dev, blk, &state, &seq_number); -+ -+ bi->block_state = state; -+ bi->seq_number = seq_number; -+ -+ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) -+ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; -+ -+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, -+ "Block scanning block %d state %d seq %d", -+ blk, state, seq_number); -+ -+ if (state == YAFFS_BLOCK_STATE_DEAD) { -+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, -+ "block %d is bad", blk); -+ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { -+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); -+ dev->n_erased_blocks++; -+ dev->n_free_chunks += dev->param.chunks_per_block; -+ } -+ bi++; -+ } -+ -+ /* For each block.... */ -+ for (blk = dev->internal_start_block; -+ !alloc_failed && blk <= dev->internal_end_block; blk++) { -+ -+ cond_resched(); -+ -+ bi = yaffs_get_block_info(dev, blk); -+ state = bi->block_state; -+ -+ deleted = 0; -+ -+ /* For each chunk in each block that needs scanning.... */ -+ for (c = 0; !alloc_failed && c < dev->param.chunks_per_block && -+ state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { -+ /* Read the tags and decide what to do */ -+ chunk = blk * dev->param.chunks_per_block + c; -+ -+ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, -+ &tags); -+ -+ /* Let's have a good look at this chunk... */ -+ -+ if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED -+ || tags.is_deleted) { -+ /* YAFFS1 only... -+ * A deleted chunk -+ */ -+ deleted++; -+ dev->n_free_chunks++; -+ /*T((" %d %d deleted\n",blk,c)); */ -+ } else if (!tags.chunk_used) { -+ /* An unassigned chunk in the block -+ * This means that either the block is empty or -+ * this is the one being allocated from -+ */ -+ -+ if (c == 0) { -+ /* We're looking at the first chunk in the block so the block is unused */ -+ state = YAFFS_BLOCK_STATE_EMPTY; -+ dev->n_erased_blocks++; -+ } else { -+ /* this is the block being allocated from */ -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ " Allocating from %d %d", -+ blk, c); -+ state = YAFFS_BLOCK_STATE_ALLOCATING; -+ dev->alloc_block = blk; -+ dev->alloc_page = c; -+ dev->alloc_block_finder = blk; -+ /* Set block finder here to encourage the allocator to go forth from here. */ -+ -+ } -+ -+ dev->n_free_chunks += -+ (dev->param.chunks_per_block - c); -+ } else if (tags.chunk_id > 0) { -+ /* chunk_id > 0 so it is a data chunk... */ -+ unsigned int endpos; -+ -+ yaffs_set_chunk_bit(dev, blk, c); -+ bi->pages_in_use++; -+ -+ in = yaffs_find_or_create_by_number(dev, -+ tags.obj_id, -+ YAFFS_OBJECT_TYPE_FILE); -+ /* PutChunkIntoFile checks for a clash (two data chunks with -+ * the same chunk_id). -+ */ -+ -+ if (!in) -+ alloc_failed = 1; -+ -+ if (in) { -+ if (!yaffs_put_chunk_in_file -+ (in, tags.chunk_id, chunk, 1)) -+ alloc_failed = 1; -+ } -+ -+ endpos = -+ (tags.chunk_id - -+ 1) * dev->data_bytes_per_chunk + -+ tags.n_bytes; -+ if (in -+ && in->variant_type == -+ YAFFS_OBJECT_TYPE_FILE -+ && in->variant.file_variant.scanned_size < -+ endpos) { -+ in->variant.file_variant.scanned_size = -+ endpos; -+ if (!dev->param.use_header_file_size) { -+ in->variant. -+ file_variant.file_size = -+ in->variant. -+ file_variant.scanned_size; -+ } -+ -+ } -+ /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */ -+ } else { -+ /* chunk_id == 0, so it is an ObjectHeader. -+ * Thus, we read in the object header and make the object -+ */ -+ yaffs_set_chunk_bit(dev, blk, c); -+ bi->pages_in_use++; -+ -+ result = yaffs_rd_chunk_tags_nand(dev, chunk, -+ chunk_data, -+ NULL); -+ -+ oh = (struct yaffs_obj_hdr *)chunk_data; -+ -+ in = yaffs_find_by_number(dev, tags.obj_id); -+ if (in && in->variant_type != oh->type) { -+ /* This should not happen, but somehow -+ * Wev'e ended up with an obj_id that has been reused but not yet -+ * deleted, and worse still it has changed type. Delete the old object. -+ */ -+ -+ yaffs_del_obj(in); -+ -+ in = 0; -+ } -+ -+ in = yaffs_find_or_create_by_number(dev, -+ tags.obj_id, -+ oh->type); -+ -+ if (!in) -+ alloc_failed = 1; -+ -+ if (in && oh->shadows_obj > 0) { -+ -+ struct yaffs_shadow_fixer *fixer; -+ fixer = -+ kmalloc(sizeof -+ (struct yaffs_shadow_fixer), -+ GFP_NOFS); -+ if (fixer) { -+ fixer->next = shadow_fixers; -+ shadow_fixers = fixer; -+ fixer->obj_id = tags.obj_id; -+ fixer->shadowed_id = -+ oh->shadows_obj; -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ " Shadow fixer: %d shadows %d", -+ fixer->obj_id, -+ fixer->shadowed_id); -+ -+ } -+ -+ } -+ -+ if (in && in->valid) { -+ /* We have already filled this one. We have a duplicate and need to resolve it. */ -+ -+ unsigned existing_serial = in->serial; -+ unsigned new_serial = -+ tags.serial_number; -+ -+ if (((existing_serial + 1) & 3) == -+ new_serial) { -+ /* Use new one - destroy the exisiting one */ -+ yaffs_chunk_del(dev, -+ in->hdr_chunk, -+ 1, __LINE__); -+ in->valid = 0; -+ } else { -+ /* Use existing - destroy this one. */ -+ yaffs_chunk_del(dev, chunk, 1, -+ __LINE__); -+ } -+ } -+ -+ if (in && !in->valid && -+ (tags.obj_id == YAFFS_OBJECTID_ROOT || -+ tags.obj_id == -+ YAFFS_OBJECTID_LOSTNFOUND)) { -+ /* We only load some info, don't fiddle with directory structure */ -+ in->valid = 1; -+ in->variant_type = oh->type; -+ -+ in->yst_mode = oh->yst_mode; -+ yaffs_load_attribs(in, oh); -+ in->hdr_chunk = chunk; -+ in->serial = tags.serial_number; -+ -+ } else if (in && !in->valid) { -+ /* we need to load this info */ -+ -+ in->valid = 1; -+ in->variant_type = oh->type; -+ -+ in->yst_mode = oh->yst_mode; -+ yaffs_load_attribs(in, oh); -+ in->hdr_chunk = chunk; -+ in->serial = tags.serial_number; -+ -+ yaffs_set_obj_name_from_oh(in, oh); -+ in->dirty = 0; -+ -+ /* directory stuff... -+ * hook up to parent -+ */ -+ -+ parent = -+ yaffs_find_or_create_by_number -+ (dev, oh->parent_obj_id, -+ YAFFS_OBJECT_TYPE_DIRECTORY); -+ if (!parent) -+ alloc_failed = 1; -+ if (parent && parent->variant_type == -+ YAFFS_OBJECT_TYPE_UNKNOWN) { -+ /* Set up as a directory */ -+ parent->variant_type = -+ YAFFS_OBJECT_TYPE_DIRECTORY; -+ INIT_LIST_HEAD(&parent-> -+ variant.dir_variant.children); -+ } else if (!parent -+ || parent->variant_type != -+ YAFFS_OBJECT_TYPE_DIRECTORY) { -+ /* Hoosterman, another problem.... -+ * We're trying to use a non-directory as a directory -+ */ -+ -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." -+ ); -+ parent = dev->lost_n_found; -+ } -+ -+ yaffs_add_obj_to_dir(parent, in); -+ -+ if (0 && (parent == dev->del_dir || -+ parent == -+ dev->unlinked_dir)) { -+ in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ -+ dev->n_deleted_files++; -+ } -+ /* Note re hardlinks. -+ * Since we might scan a hardlink before its equivalent object is scanned -+ * we put them all in a list. -+ * After scanning is complete, we should have all the objects, so we run through this -+ * list and fix up all the chains. -+ */ -+ -+ switch (in->variant_type) { -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ /* Todo got a problem */ -+ break; -+ case YAFFS_OBJECT_TYPE_FILE: -+ if (dev->param. -+ use_header_file_size) -+ -+ in->variant. -+ file_variant.file_size -+ = oh->file_size; -+ -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ in->variant. -+ hardlink_variant.equiv_id = -+ oh->equiv_id; -+ in->hard_links.next = -+ (struct list_head *) -+ hard_list; -+ hard_list = in; -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ /* Do nothing */ -+ break; -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ /* Do nothing */ -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ in->variant.symlink_variant. -+ alias = -+ yaffs_clone_str(oh->alias); -+ if (!in->variant. -+ symlink_variant.alias) -+ alloc_failed = 1; -+ break; -+ } -+ -+ } -+ } -+ } -+ -+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { -+ /* If we got this far while scanning, then the block is fully allocated. */ -+ state = YAFFS_BLOCK_STATE_FULL; -+ } -+ -+ if (state == YAFFS_BLOCK_STATE_ALLOCATING) { -+ /* If the block was partially allocated then treat it as fully allocated. */ -+ state = YAFFS_BLOCK_STATE_FULL; -+ dev->alloc_block = -1; -+ } -+ -+ bi->block_state = state; -+ -+ /* Now let's see if it was dirty */ -+ if (bi->pages_in_use == 0 && -+ !bi->has_shrink_hdr && -+ bi->block_state == YAFFS_BLOCK_STATE_FULL) { -+ yaffs_block_became_dirty(dev, blk); -+ } -+ -+ } -+ -+ /* Ok, we've done all the scanning. -+ * Fix up the hard link chains. -+ * We should now have scanned all the objects, now it's time to add these -+ * hardlinks. -+ */ -+ -+ yaffs_link_fixup(dev, hard_list); -+ -+ /* Fix up any shadowed objects */ -+ { -+ struct yaffs_shadow_fixer *fixer; -+ struct yaffs_obj *obj; -+ -+ while (shadow_fixers) { -+ fixer = shadow_fixers; -+ shadow_fixers = fixer->next; -+ /* Complete the rename transaction by deleting the shadowed object -+ * then setting the object header to unshadowed. -+ */ -+ obj = yaffs_find_by_number(dev, fixer->shadowed_id); -+ if (obj) -+ yaffs_del_obj(obj); -+ -+ obj = yaffs_find_by_number(dev, fixer->obj_id); -+ -+ if (obj) -+ yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); -+ -+ kfree(fixer); -+ } -+ } -+ -+ yaffs_release_temp_buffer(dev, chunk_data, __LINE__); -+ -+ if (alloc_failed) -+ return YAFFS_FAIL; -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends"); -+ -+ return YAFFS_OK; -+} -diff --git a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h -new file mode 100644 -index 00000000..db23e049 ---- /dev/null -+++ b/fs/yaffs2/yaffs_yaffs1.h -@@ -0,0 +1,22 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_YAFFS1_H__ -+#define __YAFFS_YAFFS1_H__ -+ -+#include "yaffs_guts.h" -+int yaffs1_scan(struct yaffs_dev *dev); -+ -+#endif -diff --git a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c -new file mode 100644 -index 00000000..33397af7 ---- /dev/null -+++ b/fs/yaffs2/yaffs_yaffs2.c -@@ -0,0 +1,1598 @@ -+/* -+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "yaffs_guts.h" -+#include "yaffs_trace.h" -+#include "yaffs_yaffs2.h" -+#include "yaffs_checkptrw.h" -+#include "yaffs_bitmap.h" -+#include "yaffs_nand.h" -+#include "yaffs_getblockinfo.h" -+#include "yaffs_verify.h" -+#include "yaffs_attribs.h" -+ -+/* -+ * Checkpoints are really no benefit on very small partitions. -+ * -+ * To save space on small partitions don't bother with checkpoints unless -+ * the partition is at least this big. -+ */ -+#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 -+ -+#define YAFFS_SMALL_HOLE_THRESHOLD 4 -+ -+/* -+ * Oldest Dirty Sequence Number handling. -+ */ -+ -+/* yaffs_calc_oldest_dirty_seq() -+ * yaffs2_find_oldest_dirty_seq() -+ * Calculate the oldest dirty sequence number if we don't know it. -+ */ -+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) -+{ -+ int i; -+ unsigned seq; -+ unsigned block_no = 0; -+ struct yaffs_block_info *b; -+ -+ if (!dev->param.is_yaffs2) -+ return; -+ -+ /* Find the oldest dirty sequence number. */ -+ seq = dev->seq_number + 1; -+ b = dev->block_info; -+ for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { -+ if (b->block_state == YAFFS_BLOCK_STATE_FULL && -+ (b->pages_in_use - b->soft_del_pages) < -+ dev->param.chunks_per_block && b->seq_number < seq) { -+ seq = b->seq_number; -+ block_no = i; -+ } -+ b++; -+ } -+ -+ if (block_no) { -+ dev->oldest_dirty_seq = seq; -+ dev->oldest_dirty_block = block_no; -+ } -+ -+} -+ -+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev) -+{ -+ if (!dev->param.is_yaffs2) -+ return; -+ -+ if (!dev->oldest_dirty_seq) -+ yaffs_calc_oldest_dirty_seq(dev); -+} -+ -+/* -+ * yaffs_clear_oldest_dirty_seq() -+ * Called when a block is erased or marked bad. (ie. when its seq_number -+ * becomes invalid). If the value matches the oldest then we clear -+ * dev->oldest_dirty_seq to force its recomputation. -+ */ -+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, -+ struct yaffs_block_info *bi) -+{ -+ -+ if (!dev->param.is_yaffs2) -+ return; -+ -+ if (!bi || bi->seq_number == dev->oldest_dirty_seq) { -+ dev->oldest_dirty_seq = 0; -+ dev->oldest_dirty_block = 0; -+ } -+} -+ -+/* -+ * yaffs2_update_oldest_dirty_seq() -+ * Update the oldest dirty sequence number whenever we dirty a block. -+ * Only do this if the oldest_dirty_seq is actually being tracked. -+ */ -+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, -+ struct yaffs_block_info *bi) -+{ -+ if (!dev->param.is_yaffs2) -+ return; -+ -+ if (dev->oldest_dirty_seq) { -+ if (dev->oldest_dirty_seq > bi->seq_number) { -+ dev->oldest_dirty_seq = bi->seq_number; -+ dev->oldest_dirty_block = block_no; -+ } -+ } -+} -+ -+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi) -+{ -+ -+ if (!dev->param.is_yaffs2) -+ return 1; /* disqualification only applies to yaffs2. */ -+ -+ if (!bi->has_shrink_hdr) -+ return 1; /* can gc */ -+ -+ yaffs2_find_oldest_dirty_seq(dev); -+ -+ /* Can't do gc of this block if there are any blocks older than this one that have -+ * discarded pages. -+ */ -+ return (bi->seq_number <= dev->oldest_dirty_seq); -+} -+ -+/* -+ * yaffs2_find_refresh_block() -+ * periodically finds the oldest full block by sequence number for refreshing. -+ * Only for yaffs2. -+ */ -+u32 yaffs2_find_refresh_block(struct yaffs_dev * dev) -+{ -+ u32 b; -+ -+ u32 oldest = 0; -+ u32 oldest_seq = 0; -+ -+ struct yaffs_block_info *bi; -+ -+ if (!dev->param.is_yaffs2) -+ return oldest; -+ -+ /* -+ * If refresh period < 10 then refreshing is disabled. -+ */ -+ if (dev->param.refresh_period < 10) -+ return oldest; -+ -+ /* -+ * Fix broken values. -+ */ -+ if (dev->refresh_skip > dev->param.refresh_period) -+ dev->refresh_skip = dev->param.refresh_period; -+ -+ if (dev->refresh_skip > 0) -+ return oldest; -+ -+ /* -+ * Refresh skip is now zero. -+ * We'll do a refresh this time around.... -+ * Update the refresh skip and find the oldest block. -+ */ -+ dev->refresh_skip = dev->param.refresh_period; -+ dev->refresh_count++; -+ bi = dev->block_info; -+ for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { -+ -+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL) { -+ -+ if (oldest < 1 || bi->seq_number < oldest_seq) { -+ oldest = b; -+ oldest_seq = bi->seq_number; -+ } -+ } -+ bi++; -+ } -+ -+ if (oldest > 0) { -+ yaffs_trace(YAFFS_TRACE_GC, -+ "GC refresh count %d selected block %d with seq_number %d", -+ dev->refresh_count, oldest, oldest_seq); -+ } -+ -+ return oldest; -+} -+ -+int yaffs2_checkpt_required(struct yaffs_dev *dev) -+{ -+ int nblocks; -+ -+ if (!dev->param.is_yaffs2) -+ return 0; -+ -+ nblocks = dev->internal_end_block - dev->internal_start_block + 1; -+ -+ return !dev->param.skip_checkpt_wr && -+ !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); -+} -+ -+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev) -+{ -+ int retval; -+ -+ if (!dev->param.is_yaffs2) -+ return 0; -+ -+ if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) { -+ /* Not a valid value so recalculate */ -+ int n_bytes = 0; -+ int n_blocks; -+ int dev_blocks = -+ (dev->param.end_block - dev->param.start_block + 1); -+ -+ n_bytes += sizeof(struct yaffs_checkpt_validity); -+ n_bytes += sizeof(struct yaffs_checkpt_dev); -+ n_bytes += dev_blocks * sizeof(struct yaffs_block_info); -+ n_bytes += dev_blocks * dev->chunk_bit_stride; -+ n_bytes += -+ (sizeof(struct yaffs_checkpt_obj) + -+ sizeof(u32)) * (dev->n_obj); -+ n_bytes += (dev->tnode_size + sizeof(u32)) * (dev->n_tnodes); -+ n_bytes += sizeof(struct yaffs_checkpt_validity); -+ n_bytes += sizeof(u32); /* checksum */ -+ -+ /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */ -+ -+ n_blocks = -+ (n_bytes / -+ (dev->data_bytes_per_chunk * -+ dev->param.chunks_per_block)) + 3; -+ -+ dev->checkpoint_blocks_required = n_blocks; -+ } -+ -+ retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; -+ if (retval < 0) -+ retval = 0; -+ return retval; -+} -+ -+/*--------------------- Checkpointing --------------------*/ -+ -+static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) -+{ -+ struct yaffs_checkpt_validity cp; -+ -+ memset(&cp, 0, sizeof(cp)); -+ -+ cp.struct_type = sizeof(cp); -+ cp.magic = YAFFS_MAGIC; -+ cp.version = YAFFS_CHECKPOINT_VERSION; -+ cp.head = (head) ? 1 : 0; -+ -+ return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0; -+} -+ -+static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) -+{ -+ struct yaffs_checkpt_validity cp; -+ int ok; -+ -+ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); -+ -+ if (ok) -+ ok = (cp.struct_type == sizeof(cp)) && -+ (cp.magic == YAFFS_MAGIC) && -+ (cp.version == YAFFS_CHECKPOINT_VERSION) && -+ (cp.head == ((head) ? 1 : 0)); -+ return ok ? 1 : 0; -+} -+ -+static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp, -+ struct yaffs_dev *dev) -+{ -+ cp->n_erased_blocks = dev->n_erased_blocks; -+ cp->alloc_block = dev->alloc_block; -+ cp->alloc_page = dev->alloc_page; -+ cp->n_free_chunks = dev->n_free_chunks; -+ -+ cp->n_deleted_files = dev->n_deleted_files; -+ cp->n_unlinked_files = dev->n_unlinked_files; -+ cp->n_bg_deletions = dev->n_bg_deletions; -+ cp->seq_number = dev->seq_number; -+ -+} -+ -+static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev, -+ struct yaffs_checkpt_dev *cp) -+{ -+ dev->n_erased_blocks = cp->n_erased_blocks; -+ dev->alloc_block = cp->alloc_block; -+ dev->alloc_page = cp->alloc_page; -+ dev->n_free_chunks = cp->n_free_chunks; -+ -+ dev->n_deleted_files = cp->n_deleted_files; -+ dev->n_unlinked_files = cp->n_unlinked_files; -+ dev->n_bg_deletions = cp->n_bg_deletions; -+ dev->seq_number = cp->seq_number; -+} -+ -+static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev) -+{ -+ struct yaffs_checkpt_dev cp; -+ u32 n_bytes; -+ u32 n_blocks = -+ (dev->internal_end_block - dev->internal_start_block + 1); -+ -+ int ok; -+ -+ /* Write device runtime values */ -+ yaffs2_dev_to_checkpt_dev(&cp, dev); -+ cp.struct_type = sizeof(cp); -+ -+ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); -+ -+ /* Write block info */ -+ if (ok) { -+ n_bytes = n_blocks * sizeof(struct yaffs_block_info); -+ ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == -+ n_bytes); -+ } -+ -+ /* Write chunk bits */ -+ if (ok) { -+ n_bytes = n_blocks * dev->chunk_bit_stride; -+ ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == -+ n_bytes); -+ } -+ return ok ? 1 : 0; -+ -+} -+ -+static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) -+{ -+ struct yaffs_checkpt_dev cp; -+ u32 n_bytes; -+ u32 n_blocks = -+ (dev->internal_end_block - dev->internal_start_block + 1); -+ -+ int ok; -+ -+ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); -+ if (!ok) -+ return 0; -+ -+ if (cp.struct_type != sizeof(cp)) -+ return 0; -+ -+ yaffs_checkpt_dev_to_dev(dev, &cp); -+ -+ n_bytes = n_blocks * sizeof(struct yaffs_block_info); -+ -+ ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); -+ -+ if (!ok) -+ return 0; -+ n_bytes = n_blocks * dev->chunk_bit_stride; -+ -+ ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); -+ -+ return ok ? 1 : 0; -+} -+ -+static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp, -+ struct yaffs_obj *obj) -+{ -+ -+ cp->obj_id = obj->obj_id; -+ cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; -+ cp->hdr_chunk = obj->hdr_chunk; -+ cp->variant_type = obj->variant_type; -+ cp->deleted = obj->deleted; -+ cp->soft_del = obj->soft_del; -+ cp->unlinked = obj->unlinked; -+ cp->fake = obj->fake; -+ cp->rename_allowed = obj->rename_allowed; -+ cp->unlink_allowed = obj->unlink_allowed; -+ cp->serial = obj->serial; -+ cp->n_data_chunks = obj->n_data_chunks; -+ -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) -+ cp->size_or_equiv_obj = obj->variant.file_variant.file_size; -+ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) -+ cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; -+} -+ -+static int taffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, -+ struct yaffs_checkpt_obj *cp) -+{ -+ -+ struct yaffs_obj *parent; -+ -+ if (obj->variant_type != cp->variant_type) { -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "Checkpoint read object %d type %d chunk %d does not match existing object type %d", -+ cp->obj_id, cp->variant_type, cp->hdr_chunk, -+ obj->variant_type); -+ return 0; -+ } -+ -+ obj->obj_id = cp->obj_id; -+ -+ if (cp->parent_id) -+ parent = yaffs_find_or_create_by_number(obj->my_dev, -+ cp->parent_id, -+ YAFFS_OBJECT_TYPE_DIRECTORY); -+ else -+ parent = NULL; -+ -+ if (parent) { -+ if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { -+ yaffs_trace(YAFFS_TRACE_ALWAYS, -+ "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory", -+ cp->obj_id, cp->parent_id, -+ cp->variant_type, cp->hdr_chunk, -+ parent->variant_type); -+ return 0; -+ } -+ yaffs_add_obj_to_dir(parent, obj); -+ } -+ -+ obj->hdr_chunk = cp->hdr_chunk; -+ obj->variant_type = cp->variant_type; -+ obj->deleted = cp->deleted; -+ obj->soft_del = cp->soft_del; -+ obj->unlinked = cp->unlinked; -+ obj->fake = cp->fake; -+ obj->rename_allowed = cp->rename_allowed; -+ obj->unlink_allowed = cp->unlink_allowed; -+ obj->serial = cp->serial; -+ obj->n_data_chunks = cp->n_data_chunks; -+ -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) -+ obj->variant.file_variant.file_size = cp->size_or_equiv_obj; -+ else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) -+ obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; -+ -+ if (obj->hdr_chunk > 0) -+ obj->lazy_loaded = 1; -+ return 1; -+} -+ -+static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, -+ struct yaffs_tnode *tn, u32 level, -+ int chunk_offset) -+{ -+ int i; -+ struct yaffs_dev *dev = in->my_dev; -+ int ok = 1; -+ -+ if (tn) { -+ if (level > 0) { -+ -+ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { -+ if (tn->internal[i]) { -+ ok = yaffs2_checkpt_tnode_worker(in, -+ tn-> -+ internal -+ [i], -+ level - -+ 1, -+ (chunk_offset -+ << -+ YAFFS_TNODES_INTERNAL_BITS) -+ + i); -+ } -+ } -+ } else if (level == 0) { -+ u32 base_offset = -+ chunk_offset << YAFFS_TNODES_LEVEL0_BITS; -+ ok = (yaffs2_checkpt_wr -+ (dev, &base_offset, -+ sizeof(base_offset)) == sizeof(base_offset)); -+ if (ok) -+ ok = (yaffs2_checkpt_wr -+ (dev, tn, -+ dev->tnode_size) == dev->tnode_size); -+ } -+ } -+ -+ return ok; -+ -+} -+ -+static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj) -+{ -+ u32 end_marker = ~0; -+ int ok = 1; -+ -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { -+ ok = yaffs2_checkpt_tnode_worker(obj, -+ obj->variant.file_variant.top, -+ obj->variant.file_variant. -+ top_level, 0); -+ if (ok) -+ ok = (yaffs2_checkpt_wr -+ (obj->my_dev, &end_marker, -+ sizeof(end_marker)) == sizeof(end_marker)); -+ } -+ -+ return ok ? 1 : 0; -+} -+ -+static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) -+{ -+ u32 base_chunk; -+ int ok = 1; -+ struct yaffs_dev *dev = obj->my_dev; -+ struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant; -+ struct yaffs_tnode *tn; -+ int nread = 0; -+ -+ ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) == -+ sizeof(base_chunk)); -+ -+ while (ok && (~base_chunk)) { -+ nread++; -+ /* Read level 0 tnode */ -+ -+ tn = yaffs_get_tnode(dev); -+ if (tn) { -+ ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == -+ dev->tnode_size); -+ } else { -+ ok = 0; -+ } -+ -+ if (tn && ok) -+ ok = yaffs_add_find_tnode_0(dev, -+ file_stuct_ptr, -+ base_chunk, tn) ? 1 : 0; -+ -+ if (ok) -+ ok = (yaffs2_checkpt_rd -+ (dev, &base_chunk, -+ sizeof(base_chunk)) == sizeof(base_chunk)); -+ -+ } -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "Checkpoint read tnodes %d records, last %d. ok %d", -+ nread, base_chunk, ok); -+ -+ return ok ? 1 : 0; -+} -+ -+static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_checkpt_obj cp; -+ int i; -+ int ok = 1; -+ struct list_head *lh; -+ -+ /* Iterate through the objects in each hash entry, -+ * dumping them to the checkpointing stream. -+ */ -+ -+ for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { -+ list_for_each(lh, &dev->obj_bucket[i].list) { -+ if (lh) { -+ obj = -+ list_entry(lh, struct yaffs_obj, hash_link); -+ if (!obj->defered_free) { -+ yaffs2_obj_checkpt_obj(&cp, obj); -+ cp.struct_type = sizeof(cp); -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "Checkpoint write object %d parent %d type %d chunk %d obj addr %p", -+ cp.obj_id, cp.parent_id, -+ cp.variant_type, cp.hdr_chunk, obj); -+ -+ ok = (yaffs2_checkpt_wr -+ (dev, &cp, -+ sizeof(cp)) == sizeof(cp)); -+ -+ if (ok -+ && obj->variant_type == -+ YAFFS_OBJECT_TYPE_FILE) -+ ok = yaffs2_wr_checkpt_tnodes -+ (obj); -+ } -+ } -+ } -+ } -+ -+ /* Dump end of list */ -+ memset(&cp, 0xFF, sizeof(struct yaffs_checkpt_obj)); -+ cp.struct_type = sizeof(cp); -+ -+ if (ok) -+ ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); -+ -+ return ok ? 1 : 0; -+} -+ -+static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_checkpt_obj cp; -+ int ok = 1; -+ int done = 0; -+ struct yaffs_obj *hard_list = NULL; -+ -+ while (ok && !done) { -+ ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); -+ if (cp.struct_type != sizeof(cp)) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "struct size %d instead of %d ok %d", -+ cp.struct_type, (int)sizeof(cp), ok); -+ ok = 0; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "Checkpoint read object %d parent %d type %d chunk %d ", -+ cp.obj_id, cp.parent_id, cp.variant_type, -+ cp.hdr_chunk); -+ -+ if (ok && cp.obj_id == ~0) { -+ done = 1; -+ } else if (ok) { -+ obj = -+ yaffs_find_or_create_by_number(dev, cp.obj_id, -+ cp.variant_type); -+ if (obj) { -+ ok = taffs2_checkpt_obj_to_obj(obj, &cp); -+ if (!ok) -+ break; -+ if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { -+ ok = yaffs2_rd_checkpt_tnodes(obj); -+ } else if (obj->variant_type == -+ YAFFS_OBJECT_TYPE_HARDLINK) { -+ obj->hard_links.next = -+ (struct list_head *)hard_list; -+ hard_list = obj; -+ } -+ } else { -+ ok = 0; -+ } -+ } -+ } -+ -+ if (ok) -+ yaffs_link_fixup(dev, hard_list); -+ -+ return ok ? 1 : 0; -+} -+ -+static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev) -+{ -+ u32 checkpt_sum; -+ int ok; -+ -+ yaffs2_get_checkpt_sum(dev, &checkpt_sum); -+ -+ ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == -+ sizeof(checkpt_sum)); -+ -+ if (!ok) -+ return 0; -+ -+ return 1; -+} -+ -+static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev) -+{ -+ u32 checkpt_sum0; -+ u32 checkpt_sum1; -+ int ok; -+ -+ yaffs2_get_checkpt_sum(dev, &checkpt_sum0); -+ -+ ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == -+ sizeof(checkpt_sum1)); -+ -+ if (!ok) -+ return 0; -+ -+ if (checkpt_sum0 != checkpt_sum1) -+ return 0; -+ -+ return 1; -+} -+ -+static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev) -+{ -+ int ok = 1; -+ -+ if (!yaffs2_checkpt_required(dev)) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "skipping checkpoint write"); -+ ok = 0; -+ } -+ -+ if (ok) -+ ok = yaffs2_checkpt_open(dev, 1); -+ -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "write checkpoint validity"); -+ ok = yaffs2_wr_checkpt_validity_marker(dev, 1); -+ } -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "write checkpoint device"); -+ ok = yaffs2_wr_checkpt_dev(dev); -+ } -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "write checkpoint objects"); -+ ok = yaffs2_wr_checkpt_objs(dev); -+ } -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "write checkpoint validity"); -+ ok = yaffs2_wr_checkpt_validity_marker(dev, 0); -+ } -+ -+ if (ok) -+ ok = yaffs2_wr_checkpt_sum(dev); -+ -+ if (!yaffs_checkpt_close(dev)) -+ ok = 0; -+ -+ if (ok) -+ dev->is_checkpointed = 1; -+ else -+ dev->is_checkpointed = 0; -+ -+ return dev->is_checkpointed; -+} -+ -+static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev) -+{ -+ int ok = 1; -+ -+ if (!dev->param.is_yaffs2) -+ ok = 0; -+ -+ if (ok && dev->param.skip_checkpt_rd) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "skipping checkpoint read"); -+ ok = 0; -+ } -+ -+ if (ok) -+ ok = yaffs2_checkpt_open(dev, 0); /* open for read */ -+ -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "read checkpoint validity"); -+ ok = yaffs2_rd_checkpt_validity_marker(dev, 1); -+ } -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "read checkpoint device"); -+ ok = yaffs2_rd_checkpt_dev(dev); -+ } -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "read checkpoint objects"); -+ ok = yaffs2_rd_checkpt_objs(dev); -+ } -+ if (ok) { -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "read checkpoint validity"); -+ ok = yaffs2_rd_checkpt_validity_marker(dev, 0); -+ } -+ -+ if (ok) { -+ ok = yaffs2_rd_checkpt_sum(dev); -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "read checkpoint checksum %d", ok); -+ } -+ -+ if (!yaffs_checkpt_close(dev)) -+ ok = 0; -+ -+ if (ok) -+ dev->is_checkpointed = 1; -+ else -+ dev->is_checkpointed = 0; -+ -+ return ok ? 1 : 0; -+ -+} -+ -+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev) -+{ -+ if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) { -+ dev->is_checkpointed = 0; -+ yaffs2_checkpt_invalidate_stream(dev); -+ } -+ if (dev->param.sb_dirty_fn) -+ dev->param.sb_dirty_fn(dev); -+} -+ -+int yaffs_checkpoint_save(struct yaffs_dev *dev) -+{ -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "save entry: is_checkpointed %d", -+ dev->is_checkpointed); -+ -+ yaffs_verify_objects(dev); -+ yaffs_verify_blocks(dev); -+ yaffs_verify_free_chunks(dev); -+ -+ if (!dev->is_checkpointed) { -+ yaffs2_checkpt_invalidate(dev); -+ yaffs2_wr_checkpt_data(dev); -+ } -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT, -+ "save exit: is_checkpointed %d", -+ dev->is_checkpointed); -+ -+ return dev->is_checkpointed; -+} -+ -+int yaffs2_checkpt_restore(struct yaffs_dev *dev) -+{ -+ int retval; -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "restore entry: is_checkpointed %d", -+ dev->is_checkpointed); -+ -+ retval = yaffs2_rd_checkpt_data(dev); -+ -+ if (dev->is_checkpointed) { -+ yaffs_verify_objects(dev); -+ yaffs_verify_blocks(dev); -+ yaffs_verify_free_chunks(dev); -+ } -+ -+ yaffs_trace(YAFFS_TRACE_CHECKPOINT, -+ "restore exit: is_checkpointed %d", -+ dev->is_checkpointed); -+ -+ return retval; -+} -+ -+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) -+{ -+ /* if new_size > old_file_size. -+ * We're going to be writing a hole. -+ * If the hole is small then write zeros otherwise write a start of hole marker. -+ */ -+ -+ loff_t old_file_size; -+ int increase; -+ int small_hole; -+ int result = YAFFS_OK; -+ struct yaffs_dev *dev = NULL; -+ -+ u8 *local_buffer = NULL; -+ -+ int small_increase_ok = 0; -+ -+ if (!obj) -+ return YAFFS_FAIL; -+ -+ if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) -+ return YAFFS_FAIL; -+ -+ dev = obj->my_dev; -+ -+ /* Bail out if not yaffs2 mode */ -+ if (!dev->param.is_yaffs2) -+ return YAFFS_OK; -+ -+ old_file_size = obj->variant.file_variant.file_size; -+ -+ if (new_size <= old_file_size) -+ return YAFFS_OK; -+ -+ increase = new_size - old_file_size; -+ -+ if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && -+ yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) -+ small_hole = 1; -+ else -+ small_hole = 0; -+ -+ if (small_hole) -+ local_buffer = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ if (local_buffer) { -+ /* fill hole with zero bytes */ -+ int pos = old_file_size; -+ int this_write; -+ int written; -+ memset(local_buffer, 0, dev->data_bytes_per_chunk); -+ small_increase_ok = 1; -+ -+ while (increase > 0 && small_increase_ok) { -+ this_write = increase; -+ if (this_write > dev->data_bytes_per_chunk) -+ this_write = dev->data_bytes_per_chunk; -+ written = -+ yaffs_do_file_wr(obj, local_buffer, pos, this_write, -+ 0); -+ if (written == this_write) { -+ pos += this_write; -+ increase -= this_write; -+ } else { -+ small_increase_ok = 0; -+ } -+ } -+ -+ yaffs_release_temp_buffer(dev, local_buffer, __LINE__); -+ -+ /* If we were out of space then reverse any chunks we've added */ -+ if (!small_increase_ok) -+ yaffs_resize_file_down(obj, old_file_size); -+ } -+ -+ if (!small_increase_ok && -+ obj->parent && -+ obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && -+ obj->parent->obj_id != YAFFS_OBJECTID_DELETED) { -+ /* Write a hole start header with the old file size */ -+ yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); -+ } -+ -+ return result; -+ -+} -+ -+struct yaffs_block_index { -+ int seq; -+ int block; -+}; -+ -+static int yaffs2_ybicmp(const void *a, const void *b) -+{ -+ int aseq = ((struct yaffs_block_index *)a)->seq; -+ int bseq = ((struct yaffs_block_index *)b)->seq; -+ int ablock = ((struct yaffs_block_index *)a)->block; -+ int bblock = ((struct yaffs_block_index *)b)->block; -+ if (aseq == bseq) -+ return ablock - bblock; -+ else -+ return aseq - bseq; -+} -+ -+int yaffs2_scan_backwards(struct yaffs_dev *dev) -+{ -+ struct yaffs_ext_tags tags; -+ int blk; -+ int block_iter; -+ int start_iter; -+ int end_iter; -+ int n_to_scan = 0; -+ -+ int chunk; -+ int result; -+ int c; -+ int deleted; -+ enum yaffs_block_state state; -+ struct yaffs_obj *hard_list = NULL; -+ struct yaffs_block_info *bi; -+ u32 seq_number; -+ struct yaffs_obj_hdr *oh; -+ struct yaffs_obj *in; -+ struct yaffs_obj *parent; -+ int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; -+ int is_unlinked; -+ u8 *chunk_data; -+ -+ int file_size; -+ int is_shrink; -+ int found_chunks; -+ int equiv_id; -+ int alloc_failed = 0; -+ -+ struct yaffs_block_index *block_index = NULL; -+ int alt_block_index = 0; -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "yaffs2_scan_backwards starts intstartblk %d intendblk %d...", -+ dev->internal_start_block, dev->internal_end_block); -+ -+ dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; -+ -+ block_index = kmalloc(n_blocks * sizeof(struct yaffs_block_index), -+ GFP_NOFS); -+ -+ if (!block_index) { -+ block_index = -+ vmalloc(n_blocks * sizeof(struct yaffs_block_index)); -+ alt_block_index = 1; -+ } -+ -+ if (!block_index) { -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "yaffs2_scan_backwards() could not allocate block index!" -+ ); -+ return YAFFS_FAIL; -+ } -+ -+ dev->blocks_in_checkpt = 0; -+ -+ chunk_data = yaffs_get_temp_buffer(dev, __LINE__); -+ -+ /* Scan all the blocks to determine their state */ -+ bi = dev->block_info; -+ for (blk = dev->internal_start_block; blk <= dev->internal_end_block; -+ blk++) { -+ yaffs_clear_chunk_bits(dev, blk); -+ bi->pages_in_use = 0; -+ bi->soft_del_pages = 0; -+ -+ yaffs_query_init_block_state(dev, blk, &state, &seq_number); -+ -+ bi->block_state = state; -+ bi->seq_number = seq_number; -+ -+ if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) -+ bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT; -+ if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) -+ bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; -+ -+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, -+ "Block scanning block %d state %d seq %d", -+ blk, state, seq_number); -+ -+ if (state == YAFFS_BLOCK_STATE_CHECKPOINT) { -+ dev->blocks_in_checkpt++; -+ -+ } else if (state == YAFFS_BLOCK_STATE_DEAD) { -+ yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, -+ "block %d is bad", blk); -+ } else if (state == YAFFS_BLOCK_STATE_EMPTY) { -+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); -+ dev->n_erased_blocks++; -+ dev->n_free_chunks += dev->param.chunks_per_block; -+ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { -+ -+ /* Determine the highest sequence number */ -+ if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && -+ seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { -+ -+ block_index[n_to_scan].seq = seq_number; -+ block_index[n_to_scan].block = blk; -+ -+ n_to_scan++; -+ -+ if (seq_number >= dev->seq_number) -+ dev->seq_number = seq_number; -+ } else { -+ /* TODO: Nasty sequence number! */ -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "Block scanning block %d has bad sequence number %d", -+ blk, seq_number); -+ -+ } -+ } -+ bi++; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan); -+ -+ cond_resched(); -+ -+ /* Sort the blocks by sequence number */ -+ sort(block_index, n_to_scan, sizeof(struct yaffs_block_index), -+ yaffs2_ybicmp, NULL); -+ -+ cond_resched(); -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, "...done"); -+ -+ /* Now scan the blocks looking at the data. */ -+ start_iter = 0; -+ end_iter = n_to_scan - 1; -+ yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan); -+ -+ /* For each block.... backwards */ -+ for (block_iter = end_iter; !alloc_failed && block_iter >= start_iter; -+ block_iter--) { -+ /* Cooperative multitasking! This loop can run for so -+ long that watchdog timers expire. */ -+ cond_resched(); -+ -+ /* get the block to scan in the correct order */ -+ blk = block_index[block_iter].block; -+ -+ bi = yaffs_get_block_info(dev, blk); -+ -+ state = bi->block_state; -+ -+ deleted = 0; -+ -+ /* For each chunk in each block that needs scanning.... */ -+ found_chunks = 0; -+ for (c = dev->param.chunks_per_block - 1; -+ !alloc_failed && c >= 0 && -+ (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || -+ state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { -+ /* Scan backwards... -+ * Read the tags and decide what to do -+ */ -+ -+ chunk = blk * dev->param.chunks_per_block + c; -+ -+ result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, -+ &tags); -+ -+ /* Let's have a good look at this chunk... */ -+ -+ if (!tags.chunk_used) { -+ /* An unassigned chunk in the block. -+ * If there are used chunks after this one, then -+ * it is a chunk that was skipped due to failing the erased -+ * check. Just skip it so that it can be deleted. -+ * But, more typically, We get here when this is an unallocated -+ * chunk and his means that either the block is empty or -+ * this is the one being allocated from -+ */ -+ -+ if (found_chunks) { -+ /* This is a chunk that was skipped due to failing the erased check */ -+ } else if (c == 0) { -+ /* We're looking at the first chunk in the block so the block is unused */ -+ state = YAFFS_BLOCK_STATE_EMPTY; -+ dev->n_erased_blocks++; -+ } else { -+ if (state == -+ YAFFS_BLOCK_STATE_NEEDS_SCANNING -+ || state == -+ YAFFS_BLOCK_STATE_ALLOCATING) { -+ if (dev->seq_number == -+ bi->seq_number) { -+ /* this is the block being allocated from */ -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ " Allocating from %d %d", -+ blk, c); -+ -+ state = -+ YAFFS_BLOCK_STATE_ALLOCATING; -+ dev->alloc_block = blk; -+ dev->alloc_page = c; -+ dev-> -+ alloc_block_finder = -+ blk; -+ } else { -+ /* This is a partially written block that is not -+ * the current allocation block. -+ */ -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "Partially written block %d detected", -+ blk); -+ } -+ } -+ } -+ -+ dev->n_free_chunks++; -+ -+ } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) { -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ " Unfixed ECC in chunk(%d:%d), chunk ignored", -+ blk, c); -+ -+ dev->n_free_chunks++; -+ -+ } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || -+ tags.chunk_id > YAFFS_MAX_CHUNK_ID || -+ (tags.chunk_id > 0 -+ && tags.n_bytes > dev->data_bytes_per_chunk) -+ || tags.seq_number != bi->seq_number) { -+ yaffs_trace(YAFFS_TRACE_SCAN, -+ "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored", -+ blk, c, tags.obj_id, -+ tags.chunk_id, tags.n_bytes); -+ -+ dev->n_free_chunks++; -+ -+ } else if (tags.chunk_id > 0) { -+ /* chunk_id > 0 so it is a data chunk... */ -+ unsigned int endpos; -+ u32 chunk_base = -+ (tags.chunk_id - -+ 1) * dev->data_bytes_per_chunk; -+ -+ found_chunks = 1; -+ -+ yaffs_set_chunk_bit(dev, blk, c); -+ bi->pages_in_use++; -+ -+ in = yaffs_find_or_create_by_number(dev, -+ tags.obj_id, -+ YAFFS_OBJECT_TYPE_FILE); -+ if (!in) { -+ /* Out of memory */ -+ alloc_failed = 1; -+ } -+ -+ if (in && -+ in->variant_type == YAFFS_OBJECT_TYPE_FILE -+ && chunk_base < -+ in->variant.file_variant.shrink_size) { -+ /* This has not been invalidated by a resize */ -+ if (!yaffs_put_chunk_in_file -+ (in, tags.chunk_id, chunk, -1)) { -+ alloc_failed = 1; -+ } -+ -+ /* File size is calculated by looking at the data chunks if we have not -+ * seen an object header yet. Stop this practice once we find an object header. -+ */ -+ endpos = chunk_base + tags.n_bytes; -+ -+ if (!in->valid && /* have not got an object header yet */ -+ in->variant.file_variant. -+ scanned_size < endpos) { -+ in->variant.file_variant. -+ scanned_size = endpos; -+ in->variant.file_variant. -+ file_size = endpos; -+ } -+ -+ } else if (in) { -+ /* This chunk has been invalidated by a resize, or a past file deletion -+ * so delete the chunk*/ -+ yaffs_chunk_del(dev, chunk, 1, -+ __LINE__); -+ -+ } -+ } else { -+ /* chunk_id == 0, so it is an ObjectHeader. -+ * Thus, we read in the object header and make the object -+ */ -+ found_chunks = 1; -+ -+ yaffs_set_chunk_bit(dev, blk, c); -+ bi->pages_in_use++; -+ -+ oh = NULL; -+ in = NULL; -+ -+ if (tags.extra_available) { -+ in = yaffs_find_or_create_by_number(dev, -+ tags. -+ obj_id, -+ tags. -+ extra_obj_type); -+ if (!in) -+ alloc_failed = 1; -+ } -+ -+ if (!in || -+ (!in->valid && dev->param.disable_lazy_load) -+ || tags.extra_shadows || (!in->valid -+ && (tags.obj_id == -+ YAFFS_OBJECTID_ROOT -+ || tags. -+ obj_id == -+ YAFFS_OBJECTID_LOSTNFOUND))) -+ { -+ -+ /* If we don't have valid info then we need to read the chunk -+ * TODO In future we can probably defer reading the chunk and -+ * living with invalid data until needed. -+ */ -+ -+ result = yaffs_rd_chunk_tags_nand(dev, -+ chunk, -+ chunk_data, -+ NULL); -+ -+ oh = (struct yaffs_obj_hdr *)chunk_data; -+ -+ if (dev->param.inband_tags) { -+ /* Fix up the header if they got corrupted by inband tags */ -+ oh->shadows_obj = -+ oh->inband_shadowed_obj_id; -+ oh->is_shrink = -+ oh->inband_is_shrink; -+ } -+ -+ if (!in) { -+ in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type); -+ if (!in) -+ alloc_failed = 1; -+ } -+ -+ } -+ -+ if (!in) { -+ /* TODO Hoosterman we have a problem! */ -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy: Could not make object for object %d at chunk %d during scan", -+ tags.obj_id, chunk); -+ continue; -+ } -+ -+ if (in->valid) { -+ /* We have already filled this one. -+ * We have a duplicate that will be discarded, but -+ * we first have to suck out resize info if it is a file. -+ */ -+ -+ if ((in->variant_type == -+ YAFFS_OBJECT_TYPE_FILE) && ((oh -+ && -+ oh-> -+ type -+ == -+ YAFFS_OBJECT_TYPE_FILE) -+ || -+ (tags. -+ extra_available -+ && -+ tags. -+ extra_obj_type -+ == -+ YAFFS_OBJECT_TYPE_FILE))) -+ { -+ u32 this_size = -+ (oh) ? oh-> -+ file_size : -+ tags.extra_length; -+ u32 parent_obj_id = -+ (oh) ? oh->parent_obj_id : -+ tags.extra_parent_id; -+ -+ is_shrink = -+ (oh) ? oh-> -+ is_shrink : -+ tags.extra_is_shrink; -+ -+ /* If it is deleted (unlinked at start also means deleted) -+ * we treat the file size as being zeroed at this point. -+ */ -+ if (parent_obj_id == -+ YAFFS_OBJECTID_DELETED -+ || parent_obj_id == -+ YAFFS_OBJECTID_UNLINKED) { -+ this_size = 0; -+ is_shrink = 1; -+ } -+ -+ if (is_shrink -+ && in->variant.file_variant. -+ shrink_size > this_size) -+ in->variant. -+ file_variant. -+ shrink_size = -+ this_size; -+ -+ if (is_shrink) -+ bi->has_shrink_hdr = 1; -+ -+ } -+ /* Use existing - destroy this one. */ -+ yaffs_chunk_del(dev, chunk, 1, -+ __LINE__); -+ -+ } -+ -+ if (!in->valid && in->variant_type != -+ (oh ? oh->type : tags.extra_obj_type)) -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan", -+ oh ? -+ oh->type : tags.extra_obj_type, -+ in->variant_type, tags.obj_id, -+ chunk); -+ -+ if (!in->valid && -+ (tags.obj_id == YAFFS_OBJECTID_ROOT || -+ tags.obj_id == -+ YAFFS_OBJECTID_LOSTNFOUND)) { -+ /* We only load some info, don't fiddle with directory structure */ -+ in->valid = 1; -+ -+ if (oh) { -+ -+ in->yst_mode = oh->yst_mode; -+ yaffs_load_attribs(in, oh); -+ in->lazy_loaded = 0; -+ } else { -+ in->lazy_loaded = 1; -+ } -+ in->hdr_chunk = chunk; -+ -+ } else if (!in->valid) { -+ /* we need to load this info */ -+ -+ in->valid = 1; -+ in->hdr_chunk = chunk; -+ -+ if (oh) { -+ in->variant_type = oh->type; -+ -+ in->yst_mode = oh->yst_mode; -+ yaffs_load_attribs(in, oh); -+ -+ if (oh->shadows_obj > 0) -+ yaffs_handle_shadowed_obj -+ (dev, -+ oh->shadows_obj, -+ 1); -+ -+ yaffs_set_obj_name_from_oh(in, -+ oh); -+ parent = -+ yaffs_find_or_create_by_number -+ (dev, oh->parent_obj_id, -+ YAFFS_OBJECT_TYPE_DIRECTORY); -+ -+ file_size = oh->file_size; -+ is_shrink = oh->is_shrink; -+ equiv_id = oh->equiv_id; -+ -+ } else { -+ in->variant_type = -+ tags.extra_obj_type; -+ parent = -+ yaffs_find_or_create_by_number -+ (dev, tags.extra_parent_id, -+ YAFFS_OBJECT_TYPE_DIRECTORY); -+ file_size = tags.extra_length; -+ is_shrink = -+ tags.extra_is_shrink; -+ equiv_id = tags.extra_equiv_id; -+ in->lazy_loaded = 1; -+ -+ } -+ in->dirty = 0; -+ -+ if (!parent) -+ alloc_failed = 1; -+ -+ /* directory stuff... -+ * hook up to parent -+ */ -+ -+ if (parent && parent->variant_type == -+ YAFFS_OBJECT_TYPE_UNKNOWN) { -+ /* Set up as a directory */ -+ parent->variant_type = -+ YAFFS_OBJECT_TYPE_DIRECTORY; -+ INIT_LIST_HEAD(&parent-> -+ variant.dir_variant.children); -+ } else if (!parent -+ || parent->variant_type != -+ YAFFS_OBJECT_TYPE_DIRECTORY) { -+ /* Hoosterman, another problem.... -+ * We're trying to use a non-directory as a directory -+ */ -+ -+ yaffs_trace(YAFFS_TRACE_ERROR, -+ "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." -+ ); -+ parent = dev->lost_n_found; -+ } -+ -+ yaffs_add_obj_to_dir(parent, in); -+ -+ is_unlinked = (parent == dev->del_dir) -+ || (parent == dev->unlinked_dir); -+ -+ if (is_shrink) { -+ /* Mark the block as having a shrink header */ -+ bi->has_shrink_hdr = 1; -+ } -+ -+ /* Note re hardlinks. -+ * Since we might scan a hardlink before its equivalent object is scanned -+ * we put them all in a list. -+ * After scanning is complete, we should have all the objects, so we run -+ * through this list and fix up all the chains. -+ */ -+ -+ switch (in->variant_type) { -+ case YAFFS_OBJECT_TYPE_UNKNOWN: -+ /* Todo got a problem */ -+ break; -+ case YAFFS_OBJECT_TYPE_FILE: -+ -+ if (in->variant. -+ file_variant.scanned_size < -+ file_size) { -+ /* This covers the case where the file size is greater -+ * than where the data is -+ * This will happen if the file is resized to be larger -+ * than its current data extents. -+ */ -+ in->variant. -+ file_variant. -+ file_size = -+ file_size; -+ in->variant. -+ file_variant. -+ scanned_size = -+ file_size; -+ } -+ -+ if (in->variant.file_variant. -+ shrink_size > file_size) -+ in->variant. -+ file_variant. -+ shrink_size = -+ file_size; -+ -+ break; -+ case YAFFS_OBJECT_TYPE_HARDLINK: -+ if (!is_unlinked) { -+ in->variant. -+ hardlink_variant. -+ equiv_id = equiv_id; -+ in->hard_links.next = -+ (struct list_head *) -+ hard_list; -+ hard_list = in; -+ } -+ break; -+ case YAFFS_OBJECT_TYPE_DIRECTORY: -+ /* Do nothing */ -+ break; -+ case YAFFS_OBJECT_TYPE_SPECIAL: -+ /* Do nothing */ -+ break; -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ if (oh) { -+ in->variant. -+ symlink_variant. -+ alias = -+ yaffs_clone_str(oh-> -+ alias); -+ if (!in->variant. -+ symlink_variant. -+ alias) -+ alloc_failed = -+ 1; -+ } -+ break; -+ } -+ -+ } -+ -+ } -+ -+ } /* End of scanning for each chunk */ -+ -+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { -+ /* If we got this far while scanning, then the block is fully allocated. */ -+ state = YAFFS_BLOCK_STATE_FULL; -+ } -+ -+ bi->block_state = state; -+ -+ /* Now let's see if it was dirty */ -+ if (bi->pages_in_use == 0 && -+ !bi->has_shrink_hdr && -+ bi->block_state == YAFFS_BLOCK_STATE_FULL) { -+ yaffs_block_became_dirty(dev, blk); -+ } -+ -+ } -+ -+ yaffs_skip_rest_of_block(dev); -+ -+ if (alt_block_index) -+ vfree(block_index); -+ else -+ kfree(block_index); -+ -+ /* Ok, we've done all the scanning. -+ * Fix up the hard link chains. -+ * We should now have scanned all the objects, now it's time to add these -+ * hardlinks. -+ */ -+ yaffs_link_fixup(dev, hard_list); -+ -+ yaffs_release_temp_buffer(dev, chunk_data, __LINE__); -+ -+ if (alloc_failed) -+ return YAFFS_FAIL; -+ -+ yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends"); -+ -+ return YAFFS_OK; -+} -diff --git a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h -new file mode 100644 -index 00000000..e1a9287f ---- /dev/null -+++ b/fs/yaffs2/yaffs_yaffs2.h -@@ -0,0 +1,39 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YAFFS_YAFFS2_H__ -+#define __YAFFS_YAFFS2_H__ -+ -+#include "yaffs_guts.h" -+ -+void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev); -+void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev); -+void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, -+ struct yaffs_block_info *bi); -+void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, -+ struct yaffs_block_info *bi); -+int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi); -+u32 yaffs2_find_refresh_block(struct yaffs_dev *dev); -+int yaffs2_checkpt_required(struct yaffs_dev *dev); -+int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev); -+ -+void yaffs2_checkpt_invalidate(struct yaffs_dev *dev); -+int yaffs2_checkpt_save(struct yaffs_dev *dev); -+int yaffs2_checkpt_restore(struct yaffs_dev *dev); -+ -+int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size); -+int yaffs2_scan_backwards(struct yaffs_dev *dev); -+ -+#endif -diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h -new file mode 100644 -index 00000000..81834254 ---- /dev/null -+++ b/fs/yaffs2/yportenv.h -@@ -0,0 +1,70 @@ -+/* -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * -+ * Copyright (C) 2002-2010 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning <charles@aleph1.co.uk> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU Lesser General Public License version 2.1 as -+ * published by the Free Software Foundation. -+ * -+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -+ */ -+ -+#ifndef __YPORTENV_LINUX_H__ -+#define __YPORTENV_LINUX_H__ -+ -+#include <linux/version.h> -+#include <linux/kernel.h> -+#include <linux/mm.h> -+#include <linux/sched.h> -+#include <linux/string.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <linux/xattr.h> -+#include <linux/list.h> -+#include <linux/types.h> -+#include <linux/fs.h> -+#include <linux/stat.h> -+#include <linux/sort.h> -+#include <linux/bitops.h> -+ -+#define YCHAR char -+#define YUCHAR unsigned char -+#define _Y(x) x -+ -+#define YAFFS_LOSTNFOUND_NAME "lost+found" -+#define YAFFS_LOSTNFOUND_PREFIX "obj" -+ -+ -+#define YAFFS_ROOT_MODE 0755 -+#define YAFFS_LOSTNFOUND_MODE 0700 -+ -+#define Y_CURRENT_TIME CURRENT_TIME.tv_sec -+#define Y_TIME_CONVERT(x) (x).tv_sec -+ -+#define compile_time_assertion(assertion) \ -+ ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) -+ -+ -+#ifndef Y_DUMP_STACK -+#define Y_DUMP_STACK() dump_stack() -+#endif -+ -+#define yaffs_trace(msk, fmt, ...) do { \ -+ if(yaffs_trace_mask & (msk)) \ -+ printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \ -+} while(0) -+ -+#ifndef YBUG -+#define YBUG() do {\ -+ yaffs_trace(YAFFS_TRACE_BUG,\ -+ "bug " __FILE__ " %d",\ -+ __LINE__);\ -+ Y_DUMP_STACK();\ -+} while (0) -+#endif -+ -+#endif -diff --git a/include/linux/Kbuild b/include/linux/Kbuild -index f2f73f9b..4bf41009 100644 ---- a/include/linux/Kbuild -+++ b/include/linux/Kbuild -@@ -183,6 +183,8 @@ header-y += if_plip.h - header-y += if_ppp.h - header-y += if_pppol2tp.h - header-y += if_pppox.h -+header-y += if_pppolac.h -+header-y += if_pppopns.h - header-y += if_slip.h - header-y += if_strip.h - header-y += if_team.h -@@ -375,6 +377,7 @@ header-y += tty.h - header-y += types.h - header-y += udf_fs_i.h - header-y += udp.h -+header-y += uhid.h - header-y += uinput.h - header-y += uio.h - header-y += ultrasound.h -diff --git a/include/linux/akm8975.h b/include/linux/akm8975.h -new file mode 100644 -index 00000000..6a7c4326 ---- /dev/null -+++ b/include/linux/akm8975.h -@@ -0,0 +1,87 @@ -+/* -+ * Definitions for akm8975 compass chip. -+ */ -+#ifndef AKM8975_H -+#define AKM8975_H -+ -+#include <linux/ioctl.h> -+ -+/*! \name AK8975 operation mode -+ \anchor AK8975_Mode -+ Defines an operation mode of the AK8975.*/ -+/*! @{*/ -+#define AK8975_MODE_SNG_MEASURE 0x01 -+#define AK8975_MODE_SELF_TEST 0x08 -+#define AK8975_MODE_FUSE_ACCESS 0x0F -+#define AK8975_MODE_POWER_DOWN 0x00 -+/*! @}*/ -+ -+#define RBUFF_SIZE 8 /* Rx buffer size */ -+ -+/*! \name AK8975 register address -+\anchor AK8975_REG -+Defines a register address of the AK8975.*/ -+/*! @{*/ -+#define AK8975_REG_WIA 0x00 -+#define AK8975_REG_INFO 0x01 -+#define AK8975_REG_ST1 0x02 -+#define AK8975_REG_HXL 0x03 -+#define AK8975_REG_HXH 0x04 -+#define AK8975_REG_HYL 0x05 -+#define AK8975_REG_HYH 0x06 -+#define AK8975_REG_HZL 0x07 -+#define AK8975_REG_HZH 0x08 -+#define AK8975_REG_ST2 0x09 -+#define AK8975_REG_CNTL 0x0A -+#define AK8975_REG_RSV 0x0B -+#define AK8975_REG_ASTC 0x0C -+#define AK8975_REG_TS1 0x0D -+#define AK8975_REG_TS2 0x0E -+#define AK8975_REG_I2CDIS 0x0F -+/*! @}*/ -+ -+/*! \name AK8975 fuse-rom address -+\anchor AK8975_FUSE -+Defines a read-only address of the fuse ROM of the AK8975.*/ -+/*! @{*/ -+#define AK8975_FUSE_ASAX 0x10 -+#define AK8975_FUSE_ASAY 0x11 -+#define AK8975_FUSE_ASAZ 0x12 -+/*! @}*/ -+ -+#define AKMIO 0xA1 -+ -+/* IOCTLs for AKM library */ -+#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x02, char[5]) -+#define ECS_IOCTL_READ _IOWR(AKMIO, 0x03, char[5]) -+#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE]) -+#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12]) -+#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int) -+#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int) -+#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short) -+ -+/* IOCTLs for APPs */ -+#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short) -+#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short) -+#define ECS_IOCTL_APP_SET_AFLAG _IOW(AKMIO, 0x13, short) -+#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short) -+#define ECS_IOCTL_APP_SET_DELAY _IOW(AKMIO, 0x18, short) -+#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY -+/* Set raw magnetic vector flag */ -+#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) -+/* Get raw magnetic vector flag */ -+#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) -+#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short) -+ -+ -+struct akm8975_platform_data { -+ int intr; -+ -+ int (*init)(void); -+ void (*exit)(void); -+ int (*power_on)(void); -+ int (*power_off)(void); -+}; -+ -+#endif -+ -diff --git a/include/linux/akuio_driver.h b/include/linux/akuio_driver.h -new file mode 100644 -index 00000000..19ee327e ---- /dev/null -+++ b/include/linux/akuio_driver.h -@@ -0,0 +1,37 @@ -+/** -+ * @filename include/linux/akuio_driver.h -+ * @brief This file provide the ioctl definitions of akuio driver for hw codec. -+ * Copyright (C) 2011 Anyka(Guangzhou) Microelectronics Technology CO.,LTD. -+ * @author Jacky Lau -+ * @date 2011-07-05 -+ * @version 0.1 -+ * @ref Please refer to uio_ak98_vcodec.c -+ */ -+ -+#ifndef _AKUIO_DRIVER_H -+#define _AKUIO_DRIVER_H -+ -+/* struct used by AKUIO_SYSREG_WRITE */ -+struct akuio_sysreg_write_t -+{ -+ unsigned int paddr; -+ unsigned int val; -+ unsigned int mask; -+}; -+ -+#define DBG(fmt...) //printk(fmt) -+ -+/* write system register */ -+#define AKUIO_SYSREG_WRITE _IOW('U', 100, struct akuio_sysreg_write_t) -+ -+/* wait for a interrupt occur */ -+#define AKUIO_WAIT_IRQ _IOR('U', 101, int) -+ -+/* invalidate the l2 cache in ak98 */ -+#define AKUIO_INVALIDATE_L2CACHE _IOR('U', 102, int) -+ -+/* incalidate the l1 cache in ak98 */ -+#define AKUIO_INVALIDATE_L1CACHE _IOR('U', 103, int) -+ -+ -+#endif -diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h -index 975009e1..96c5c249 100644 ---- a/include/linux/alarmtimer.h -+++ b/include/linux/alarmtimer.h -@@ -76,4 +76,7 @@ static inline int alarmtimer_callback_running(struct alarm *timer) - } - - -+/* Provide way to access the rtc device being used by alarmtimers */ -+struct rtc_device *alarmtimer_get_rtcdev(void); -+ - #endif -diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h -index 32a89cf5..9d1d9caf 100644 ---- a/include/linux/amba/mmci.h -+++ b/include/linux/amba/mmci.h -@@ -5,6 +5,15 @@ - #define AMBA_MMCI_H - - #include <linux/mmc/host.h> -+#include <linux/mmc/card.h> -+#include <linux/mmc/sdio_func.h> -+ -+struct embedded_sdio_data { -+ struct sdio_cis cis; -+ struct sdio_cccr cccr; -+ struct sdio_embedded_func *funcs; -+ int num_funcs; -+}; - - - /* -@@ -73,6 +82,9 @@ struct mmci_platform_data { - bool (*dma_filter)(struct dma_chan *chan, void *filter_param); - void *dma_rx_param; - void *dma_tx_param; -+ unsigned int status_irq; -+ struct embedded_sdio_data *embedded_sdio; -+ int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); - }; - - #endif -diff --git a/include/linux/android_aid.h b/include/linux/android_aid.h -new file mode 100644 -index 00000000..06264b8b ---- /dev/null -+++ b/include/linux/android_aid.h -@@ -0,0 +1,28 @@ -+/* include/linux/android_aid.h -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_ANDROID_AID_H -+#define _LINUX_ANDROID_AID_H -+ -+/* AIDs that the kernel treats differently */ -+#define AID_OBSOLETE_000 3001 /* was NET_BT_ADMIN */ -+#define AID_OBSOLETE_001 3002 /* was NET_BT */ -+#define AID_INET 3003 -+#define AID_NET_RAW 3004 -+#define AID_NET_ADMIN 3005 -+#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */ -+#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */ -+ -+#endif -diff --git a/include/linux/capability.h b/include/linux/capability.h -index 12d52ded..c398cff3 100644 ---- a/include/linux/capability.h -+++ b/include/linux/capability.h -@@ -360,8 +360,11 @@ struct cpu_vfs_cap_data { - - #define CAP_WAKE_ALARM 35 - -+/* Allow preventing system suspends while epoll events are pending */ - --#define CAP_LAST_CAP CAP_WAKE_ALARM -+#define CAP_EPOLLWAKEUP 36 -+ -+#define CAP_LAST_CAP CAP_EPOLLWAKEUP - - #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) - -diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h -index 5a85b341..b2a37357 100644 ---- a/include/linux/cgroup.h -+++ b/include/linux/cgroup.h -@@ -84,12 +84,6 @@ enum { - CSS_REMOVED, /* This CSS is dead */ - }; - --/* Caller must verify that the css is not for root cgroup */ --static inline void __css_get(struct cgroup_subsys_state *css, int count) --{ -- atomic_add(count, &css->refcnt); --} -- - /* - * Call css_get() to hold a reference on the css; it can be used - * for a reference obtained via: -@@ -97,6 +91,7 @@ static inline void __css_get(struct cgroup_subsys_state *css, int count) - * - task->cgroups for a locked task - */ - -+extern void __css_get(struct cgroup_subsys_state *css, int count); - static inline void css_get(struct cgroup_subsys_state *css) - { - /* We don't need to reference count the root state */ -@@ -143,10 +138,7 @@ static inline void css_put(struct cgroup_subsys_state *css) - enum { - /* Control Group is dead */ - CGRP_REMOVED, -- /* -- * Control Group has previously had a child cgroup or a task, -- * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set) -- */ -+ /* Control Group has ever had a child cgroup or a task */ - CGRP_RELEASABLE, - /* Control Group requires release notifications to userspace */ - CGRP_NOTIFY_ON_RELEASE, -@@ -255,6 +247,7 @@ struct css_set { - - /* For RCU-protected deletion */ - struct rcu_head rcu_head; -+ struct work_struct work; - }; - - /* -@@ -455,6 +448,7 @@ struct cgroup_subsys { - struct cgroup_subsys_state *(*create)(struct cgroup *cgrp); - int (*pre_destroy)(struct cgroup *cgrp); - void (*destroy)(struct cgroup *cgrp); -+ int (*allow_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset); - int (*can_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset); - void (*cancel_attach)(struct cgroup *cgrp, struct cgroup_taskset *tset); - void (*attach)(struct cgroup *cgrp, struct cgroup_taskset *tset); -diff --git a/include/linux/cpu.h b/include/linux/cpu.h -index 78ed62f3..caec85be 100644 ---- a/include/linux/cpu.h -+++ b/include/linux/cpu.h -@@ -213,4 +213,11 @@ static inline int disable_nonboot_cpus(void) { return 0; } - static inline void enable_nonboot_cpus(void) {} - #endif /* !CONFIG_PM_SLEEP_SMP */ - -+#define IDLE_START 1 -+#define IDLE_END 2 -+ -+void idle_notifier_register(struct notifier_block *n); -+void idle_notifier_unregister(struct notifier_block *n); -+void idle_notifier_call_chain(unsigned long val); -+ - #endif /* _LINUX_CPU_H_ */ -diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h -index b60f6ba0..d1c3bb0e 100644 ---- a/include/linux/cpufreq.h -+++ b/include/linux/cpufreq.h -@@ -364,6 +364,9 @@ extern struct cpufreq_governor cpufreq_gov_ondemand; - #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE) - extern struct cpufreq_governor cpufreq_gov_conservative; - #define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative) -+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE) -+extern struct cpufreq_governor cpufreq_gov_interactive; -+#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_interactive) - #endif - - -diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h -index 6c26a3da..5ab71833 100644 ---- a/include/linux/cpuidle.h -+++ b/include/linux/cpuidle.h -@@ -57,6 +57,7 @@ struct cpuidle_state { - - /* Idle State Flags */ - #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ -+#define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ - - #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) - -@@ -100,6 +101,12 @@ struct cpuidle_device { - struct list_head device_list; - struct kobject kobj; - struct completion kobj_unregister; -+ -+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED -+ int safe_state_index; -+ cpumask_t coupled_cpus; -+ struct cpuidle_coupled *coupled; -+#endif - }; - - DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); -@@ -176,6 +183,10 @@ static inline int cpuidle_play_dead(void) {return -ENODEV; } - - #endif - -+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED -+void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a); -+#endif -+ - /****************************** - * CPUIDLE GOVERNOR INTERFACE * - ******************************/ -diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h -index 3efbfc21..1f78d159 100644 ---- a/include/linux/dma-buf.h -+++ b/include/linux/dma-buf.h -@@ -61,6 +61,10 @@ struct dma_buf_attachment; - * This Callback must not sleep. - * @kmap: maps a page from the buffer into kernel address space. - * @kunmap: [optional] unmaps a page from the buffer. -+ * @mmap: used to expose the backing storage to userspace. Note that the -+ * mapping needs to be coherent - if the exporter doesn't directly -+ * support this, it needs to fake coherency by shooting down any ptes -+ * when transitioning away from the cpu domain. - */ - struct dma_buf_ops { - int (*attach)(struct dma_buf *, struct device *, -@@ -92,6 +96,8 @@ struct dma_buf_ops { - void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *); - void *(*kmap)(struct dma_buf *, unsigned long); - void (*kunmap)(struct dma_buf *, unsigned long, void *); -+ -+ int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); - }; - - /** -@@ -167,6 +173,9 @@ void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long); - void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *); - void *dma_buf_kmap(struct dma_buf *, unsigned long); - void dma_buf_kunmap(struct dma_buf *, unsigned long, void *); -+ -+int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, -+ unsigned long); - #else - - static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, -@@ -248,6 +257,13 @@ static inline void dma_buf_kunmap(struct dma_buf *dmabuf, - unsigned long pnum, void *vaddr) - { - } -+ -+static inline int dma_buf_mmap(struct dma_buf *dmabuf, -+ struct vm_area_struct *vma, -+ unsigned long pgoff) -+{ -+ return -ENODEV; -+} - #endif /* CONFIG_DMA_SHARED_BUFFER */ - - #endif /* __DMA_BUF_H__ */ -diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h -index 657ab55b..6f8be328 100644 ---- a/include/linux/eventpoll.h -+++ b/include/linux/eventpoll.h -@@ -26,6 +26,18 @@ - #define EPOLL_CTL_DEL 2 - #define EPOLL_CTL_MOD 3 - -+/* -+ * Request the handling of system wakeup events so as to prevent system suspends -+ * from happening while those events are being processed. -+ * -+ * Assuming neither EPOLLET nor EPOLLONESHOT is set, system suspends will not be -+ * re-allowed until epoll_wait is called again after consuming the wakeup -+ * event(s). -+ * -+ * Requires CAP_EPOLLWAKEUP -+ */ -+#define EPOLLWAKEUP (1 << 29) -+ - /* Set the One Shot behaviour for the target file descriptor */ - #define EPOLLONESHOT (1 << 30) - -diff --git a/include/linux/freezer.h b/include/linux/freezer.h -index ee899329..b79e4d87 100644 ---- a/include/linux/freezer.h -+++ b/include/linux/freezer.h -@@ -41,6 +41,17 @@ extern int freeze_kernel_threads(void); - extern void thaw_processes(void); - extern void thaw_kernel_threads(void); - -+/* -+ * HACK: prevent sleeping while atomic warnings due to ARM signal handling -+ * disabling irqs -+ */ -+static inline bool try_to_freeze_nowarn(void) -+{ -+ if (likely(!freezing(current))) -+ return false; -+ return __refrigerator(false); -+} -+ - static inline bool try_to_freeze(void) - { - might_sleep(); -diff --git a/include/linux/gpio_event.h b/include/linux/gpio_event.h -new file mode 100644 -index 00000000..2613fc5e ---- /dev/null -+++ b/include/linux/gpio_event.h -@@ -0,0 +1,170 @@ -+/* include/linux/gpio_event.h -+ * -+ * Copyright (C) 2007 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_GPIO_EVENT_H -+#define _LINUX_GPIO_EVENT_H -+ -+#include <linux/input.h> -+ -+struct gpio_event_input_devs { -+ int count; -+ struct input_dev *dev[]; -+}; -+enum { -+ GPIO_EVENT_FUNC_UNINIT = 0x0, -+ GPIO_EVENT_FUNC_INIT = 0x1, -+ GPIO_EVENT_FUNC_SUSPEND = 0x2, -+ GPIO_EVENT_FUNC_RESUME = 0x3, -+}; -+struct gpio_event_info { -+ int (*func)(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, -+ void **data, int func); -+ int (*event)(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, -+ void **data, unsigned int dev, unsigned int type, -+ unsigned int code, int value); /* out events */ -+ bool no_suspend; -+}; -+ -+struct gpio_event_platform_data { -+ const char *name; -+ struct gpio_event_info **info; -+ size_t info_count; -+ int (*power)(const struct gpio_event_platform_data *pdata, bool on); -+ const char *names[]; /* If name is NULL, names contain a NULL */ -+ /* terminated list of input devices to create */ -+}; -+ -+#define GPIO_EVENT_DEV_NAME "gpio-event" -+ -+/* Key matrix */ -+ -+enum gpio_event_matrix_flags { -+ /* unset: drive active output low, set: drive active output high */ -+ GPIOKPF_ACTIVE_HIGH = 1U << 0, -+ GPIOKPF_DEBOUNCE = 1U << 1, -+ GPIOKPF_REMOVE_SOME_PHANTOM_KEYS = 1U << 2, -+ GPIOKPF_REMOVE_PHANTOM_KEYS = GPIOKPF_REMOVE_SOME_PHANTOM_KEYS | -+ GPIOKPF_DEBOUNCE, -+ GPIOKPF_DRIVE_INACTIVE = 1U << 3, -+ GPIOKPF_LEVEL_TRIGGERED_IRQ = 1U << 4, -+ GPIOKPF_PRINT_UNMAPPED_KEYS = 1U << 16, -+ GPIOKPF_PRINT_MAPPED_KEYS = 1U << 17, -+ GPIOKPF_PRINT_PHANTOM_KEYS = 1U << 18, -+}; -+ -+#define MATRIX_CODE_BITS (10) -+#define MATRIX_KEY_MASK ((1U << MATRIX_CODE_BITS) - 1) -+#define MATRIX_KEY(dev, code) \ -+ (((dev) << MATRIX_CODE_BITS) | (code & MATRIX_KEY_MASK)) -+ -+extern int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, int func); -+struct gpio_event_matrix_info { -+ /* initialize to gpio_event_matrix_func */ -+ struct gpio_event_info info; -+ /* size must be ninputs * noutputs */ -+ const unsigned short *keymap; -+ unsigned int *input_gpios; -+ unsigned int *output_gpios; -+ unsigned int ninputs; -+ unsigned int noutputs; -+ /* time to wait before reading inputs after driving each output */ -+ ktime_t settle_time; -+ /* time to wait before scanning the keypad a second time */ -+ ktime_t debounce_delay; -+ ktime_t poll_time; -+ unsigned flags; -+}; -+ -+/* Directly connected inputs and outputs */ -+ -+enum gpio_event_direct_flags { -+ GPIOEDF_ACTIVE_HIGH = 1U << 0, -+/* GPIOEDF_USE_DOWN_IRQ = 1U << 1, */ -+/* GPIOEDF_USE_IRQ = (1U << 2) | GPIOIDF_USE_DOWN_IRQ, */ -+ GPIOEDF_PRINT_KEYS = 1U << 8, -+ GPIOEDF_PRINT_KEY_DEBOUNCE = 1U << 9, -+ GPIOEDF_PRINT_KEY_UNSTABLE = 1U << 10, -+}; -+ -+struct gpio_event_direct_entry { -+ uint32_t gpio:16; -+ uint32_t code:10; -+ uint32_t dev:6; -+}; -+ -+/* inputs */ -+extern int gpio_event_input_func(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, int func); -+struct gpio_event_input_info { -+ /* initialize to gpio_event_input_func */ -+ struct gpio_event_info info; -+ ktime_t debounce_time; -+ ktime_t poll_time; -+ uint16_t flags; -+ uint16_t type; -+ const struct gpio_event_direct_entry *keymap; -+ size_t keymap_size; -+}; -+ -+/* outputs */ -+extern int gpio_event_output_func(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, int func); -+extern int gpio_event_output_event(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, -+ unsigned int dev, unsigned int type, -+ unsigned int code, int value); -+struct gpio_event_output_info { -+ /* initialize to gpio_event_output_func and gpio_event_output_event */ -+ struct gpio_event_info info; -+ uint16_t flags; -+ uint16_t type; -+ const struct gpio_event_direct_entry *keymap; -+ size_t keymap_size; -+}; -+ -+ -+/* axes */ -+ -+enum gpio_event_axis_flags { -+ GPIOEAF_PRINT_UNKNOWN_DIRECTION = 1U << 16, -+ GPIOEAF_PRINT_RAW = 1U << 17, -+ GPIOEAF_PRINT_EVENT = 1U << 18, -+}; -+ -+extern int gpio_event_axis_func(struct gpio_event_input_devs *input_devs, -+ struct gpio_event_info *info, void **data, int func); -+struct gpio_event_axis_info { -+ /* initialize to gpio_event_axis_func */ -+ struct gpio_event_info info; -+ uint8_t count; /* number of gpios for this axis */ -+ uint8_t dev; /* device index when using multiple input devices */ -+ uint8_t type; /* EV_REL or EV_ABS */ -+ uint16_t code; -+ uint16_t decoded_size; -+ uint16_t (*map)(struct gpio_event_axis_info *info, uint16_t in); -+ uint32_t *gpio; -+ uint32_t flags; -+}; -+#define gpio_axis_2bit_gray_map gpio_axis_4bit_gray_map -+#define gpio_axis_3bit_gray_map gpio_axis_4bit_gray_map -+uint16_t gpio_axis_4bit_gray_map( -+ struct gpio_event_axis_info *info, uint16_t in); -+uint16_t gpio_axis_5bit_singletrack_map( -+ struct gpio_event_axis_info *info, uint16_t in); -+ -+#endif -diff --git a/include/linux/hid.h b/include/linux/hid.h -index 3a95da60..773b4acf 100644 ---- a/include/linux/hid.h -+++ b/include/linux/hid.h -@@ -618,6 +618,8 @@ struct hid_usage_id { - * @input_mapping: invoked on input registering before mapping an usage - * @input_mapped: invoked on input registering after mapping an usage - * @feature_mapping: invoked on feature registering -+ * @input_register: called just before input device is registered after reports -+ * are parsed. - * @suspend: invoked on suspend (NULL means nop) - * @resume: invoked on resume if device was not reset (NULL means nop) - * @reset_resume: invoked on resume if device was reset (NULL means nop) -@@ -664,6 +666,8 @@ struct hid_driver { - void (*feature_mapping)(struct hid_device *hdev, - struct hid_field *field, - struct hid_usage *usage); -+ int (*input_register)(struct hid_device *hdev, struct hid_input -+ *hidinput); - #ifdef CONFIG_PM - int (*suspend)(struct hid_device *hdev, pm_message_t message); - int (*resume)(struct hid_device *hdev); -diff --git a/include/linux/if_pppolac.h b/include/linux/if_pppolac.h -new file mode 100644 -index 00000000..c06bd6c8 ---- /dev/null -+++ b/include/linux/if_pppolac.h -@@ -0,0 +1,33 @@ -+/* include/linux/if_pppolac.h -+ * -+ * Header for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661) -+ * -+ * Copyright (C) 2009 Google, Inc. -+ * Author: Chia-chi Yeh <chiachi@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#ifndef __LINUX_IF_PPPOLAC_H -+#define __LINUX_IF_PPPOLAC_H -+ -+#include <linux/socket.h> -+#include <linux/types.h> -+ -+struct sockaddr_pppolac { -+ sa_family_t sa_family; /* AF_PPPOX */ -+ unsigned int sa_protocol; /* PX_PROTO_OLAC */ -+ int udp_socket; -+ struct __attribute__((packed)) { -+ __u16 tunnel, session; -+ } local, remote; -+} __attribute__((packed)); -+ -+#endif /* __LINUX_IF_PPPOLAC_H */ -diff --git a/include/linux/if_pppopns.h b/include/linux/if_pppopns.h -new file mode 100644 -index 00000000..0cf34b4d ---- /dev/null -+++ b/include/linux/if_pppopns.h -@@ -0,0 +1,32 @@ -+/* include/linux/if_pppopns.h -+ * -+ * Header for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637) -+ * -+ * Copyright (C) 2009 Google, Inc. -+ * Author: Chia-chi Yeh <chiachi@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#ifndef __LINUX_IF_PPPOPNS_H -+#define __LINUX_IF_PPPOPNS_H -+ -+#include <linux/socket.h> -+#include <linux/types.h> -+ -+struct sockaddr_pppopns { -+ sa_family_t sa_family; /* AF_PPPOX */ -+ unsigned int sa_protocol; /* PX_PROTO_OPNS */ -+ int tcp_socket; -+ __u16 local; -+ __u16 remote; -+} __attribute__((packed)); -+ -+#endif /* __LINUX_IF_PPPOPNS_H */ -diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h -index b5f927f5..1597b8bc 100644 ---- a/include/linux/if_pppox.h -+++ b/include/linux/if_pppox.h -@@ -28,6 +28,8 @@ - #include <linux/ppp_channel.h> - #endif /* __KERNEL__ */ - #include <linux/if_pppol2tp.h> -+#include <linux/if_pppolac.h> -+#include <linux/if_pppopns.h> - - /* For user-space programs to pick up these definitions - * which they wouldn't get otherwise without defining __KERNEL__ -@@ -61,7 +63,9 @@ struct pptp_addr { - #define PX_PROTO_OE 0 /* Currently just PPPoE */ - #define PX_PROTO_OL2TP 1 /* Now L2TP also */ - #define PX_PROTO_PPTP 2 --#define PX_MAX_PROTO 3 -+#define PX_PROTO_OLAC 3 -+#define PX_PROTO_OPNS 4 -+#define PX_MAX_PROTO 5 - - struct sockaddr_pppox { - __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */ -@@ -168,6 +172,25 @@ struct pptp_opt { - u32 seq_sent, seq_recv; - int ppp_flags; - }; -+ -+struct pppolac_opt { -+ __u32 local; -+ __u32 remote; -+ __u32 recv_sequence; -+ __u32 xmit_sequence; -+ atomic_t sequencing; -+ int (*backlog_rcv)(struct sock *sk_udp, struct sk_buff *skb); -+}; -+ -+struct pppopns_opt { -+ __u16 local; -+ __u16 remote; -+ __u32 recv_sequence; -+ __u32 xmit_sequence; -+ void (*data_ready)(struct sock *sk_raw, int length); -+ int (*backlog_rcv)(struct sock *sk_raw, struct sk_buff *skb); -+}; -+ - #include <net/sock.h> - - struct pppox_sock { -@@ -178,6 +201,8 @@ struct pppox_sock { - union { - struct pppoe_opt pppoe; - struct pptp_opt pptp; -+ struct pppolac_opt lac; -+ struct pppopns_opt pns; - } proto; - __be16 num; - }; -diff --git a/include/linux/input.h b/include/linux/input.h -index a8167145..49fb20e3 100644 ---- a/include/linux/input.h -+++ b/include/linux/input.h -@@ -154,6 +154,9 @@ struct input_keymap_entry { - - #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ - -+#define EVIOCGSUSPENDBLOCK _IOR('E', 0x91, int) /* get suspend block enable */ -+#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) /* set suspend block enable */ -+ - #define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ - - /* -diff --git a/include/linux/input/akmatrix_keypad.h b/include/linux/input/akmatrix_keypad.h -new file mode 100755 -index 00000000..49dae8d3 ---- /dev/null -+++ b/include/linux/input/akmatrix_keypad.h -@@ -0,0 +1,105 @@ -+#ifndef _MATRIX_KEYPAD_H -+#define _MATRIX_KEYPAD_H -+ -+#include <linux/types.h> -+#include <linux/input.h> -+#include <mach/gpio.h> -+ -+#define MATRIX_MAX_ROWS 16 -+#define MATRIX_MAX_COLS 16 -+ -+#define KEY(row, col, val) ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\ -+ (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\ -+ (val & 0xffff)) -+ -+#define KEY_ROW(k) (((k) >> 24) & 0xff) -+#define KEY_COL(k) (((k) >> 16) & 0xff) -+#define KEY_VAL(k) ((k) & 0xffff) -+ -+#define MATRIX_SCAN_CODE(row, col, row_shift) (((row) << (row_shift)) + (col)) -+ -+/** -+ * struct matrix_keymap_data - keymap for matrix keyboards -+ * @keymap: pointer to array of uint32 values encoded with KEY() macro -+ * representing keymap -+ * @keymap_size: number of entries (initialized) in this keymap -+ * -+ * This structure is supposed to be used by platform code to supply -+ * keymaps to drivers that implement matrix-like keypads/keyboards. -+ */ -+struct matrix_keymap_data { -+ const uint32_t *keymap; -+ unsigned int keymap_size; -+}; -+ -+/** -+ * struct matrix_keypad_platform_data - platform-dependent keypad data -+ * @keymap_data: pointer to &matrix_keymap_data -+ * @row_gpios: pointer to array of gpio numbers representing rows -+ * @col_gpios: pointer to array of gpio numbers reporesenting colums -+ * @num_row_gpios: actual number of row gpios used by device -+ * @num_col_gpios: actual number of col gpios used by device -+ * @col_scan_delay_us: delay, measured in microseconds, that is -+ * needed before we can keypad after activating column gpio -+ * @debounce_ms: debounce interval in milliseconds -+ * -+ * This structure represents platform-specific data that use used by -+ * matrix_keypad driver to perform proper initialization. -+ */ -+struct matrix_keypad_platform_data { -+ const struct matrix_keymap_data *keymap_data; -+ -+ const unsigned int *row_gpios; -+ const unsigned int *col_gpios; -+ -+ unsigned int num_row_gpios; -+ unsigned int num_col_gpios; -+ -+ unsigned int col_scan_delay_us; -+ -+ /* key debounce interval in milli-second */ -+ unsigned int debounce_ms; -+ -+ bool active_low; -+ bool wakeup; -+ -+ /* add for anyka */ -+ struct gpio_info row_gpios_cfginfo; -+ struct gpio_info col_gpios_cfginfo; -+ /* true: one column selecting line is grounded */ -+ bool grounding; -+}; -+ -+/** -+ * matrix_keypad_build_keymap - convert platform keymap into matrix keymap -+ * @keymap_data: keymap supplied by the platform code -+ * @row_shift: number of bits to shift row value by to advance to the next -+ * line in the keymap -+ * @keymap: expanded version of keymap that is suitable for use by -+ * matrix keyboad driver -+ * @keybit: pointer to bitmap of keys supported by input device -+ * -+ * This function converts platform keymap (encoded with KEY() macro) into -+ * an array of keycodes that is suitable for using in a standard matrix -+ * keyboard driver that uses row and col as indices. -+ */ -+static inline void -+matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, -+ unsigned int row_shift, -+ unsigned short *keymap, unsigned long *keybit) -+{ -+ int i; -+ -+ for (i = 0; i < keymap_data->keymap_size; i++) { -+ unsigned int key = keymap_data->keymap[i]; -+ unsigned int row = KEY_ROW(key); -+ unsigned int col = KEY_COL(key); -+ unsigned short code = KEY_VAL(key); -+ -+ keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code; -+ __set_bit(code, keybit); -+ } -+ __clear_bit(KEY_RESERVED, keybit); -+} -+ -+#endif /* _MATRIX_KEYPAD_H */ -diff --git a/include/linux/ion.h b/include/linux/ion.h -new file mode 100644 -index 00000000..8414a6d9 ---- /dev/null -+++ b/include/linux/ion.h -@@ -0,0 +1,373 @@ -+/* -+ * include/linux/ion.h -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_ION_H -+#define _LINUX_ION_H -+ -+#include <linux/types.h> -+ -+struct ion_handle; -+/** -+ * enum ion_heap_types - list of all possible types of heaps -+ * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc -+ * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc -+ * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved -+ * carveout heap, allocations are physically -+ * contiguous -+ * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask -+ * is used to identify the heaps, so only 32 -+ * total heap types are supported -+ */ -+enum ion_heap_type { -+ ION_HEAP_TYPE_SYSTEM, -+ ION_HEAP_TYPE_SYSTEM_CONTIG, -+ ION_HEAP_TYPE_CARVEOUT, -+ ION_HEAP_TYPE_CHUNK, -+ ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always -+ are at the end of this enum */ -+ ION_NUM_HEAPS = 16, -+}; -+ -+#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) -+#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) -+#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) -+ -+#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 -+ -+/** -+ * allocation flags - the lower 16 bits are used by core ion, the upper 16 -+ * bits are reserved for use by the heaps themselves. -+ */ -+#define ION_FLAG_CACHED 1 /* mappings of this buffer should be -+ cached, ion will do cache -+ maintenance when the buffer is -+ mapped for dma */ -+#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created -+ at mmap time, if this is set -+ caches must be managed manually */ -+ -+#ifdef __KERNEL__ -+struct ion_device; -+struct ion_heap; -+struct ion_mapper; -+struct ion_client; -+struct ion_buffer; -+ -+/* This should be removed some day when phys_addr_t's are fully -+ plumbed in the kernel, and all instances of ion_phys_addr_t should -+ be converted to phys_addr_t. For the time being many kernel interfaces -+ do not accept phys_addr_t's that would have to */ -+#define ion_phys_addr_t unsigned long -+ -+/** -+ * struct ion_platform_heap - defines a heap in the given platform -+ * @type: type of the heap from ion_heap_type enum -+ * @id: unique identifier for heap. When allocating higher numbers -+ * will be allocated from first. At allocation these are passed -+ * as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS. -+ * @name: used for debug purposes -+ * @base: base address of heap in physical memory if applicable -+ * @size: size of the heap in bytes if applicable -+ * @align: required alignment in physical memory if applicable -+ * @priv: private info passed from the board file -+ * -+ * Provided by the board file. -+ */ -+struct ion_platform_heap { -+ enum ion_heap_type type; -+ unsigned int id; -+ const char *name; -+ ion_phys_addr_t base; -+ size_t size; -+ ion_phys_addr_t align; -+ void *priv; -+}; -+ -+/** -+ * struct ion_platform_data - array of platform heaps passed from board file -+ * @nr: number of structures in the array -+ * @heaps: array of platform_heap structions -+ * -+ * Provided by the board file in the form of platform data to a platform device. -+ */ -+struct ion_platform_data { -+ int nr; -+ struct ion_platform_heap heaps[]; -+}; -+ -+/** -+ * ion_reserve() - reserve memory for ion heaps if applicable -+ * @data: platform data specifying starting physical address and -+ * size -+ * -+ * Calls memblock reserve to set aside memory for heaps that are -+ * located at specific memory addresses or of specfic sizes not -+ * managed by the kernel -+ */ -+void ion_reserve(struct ion_platform_data *data); -+ -+/** -+ * ion_client_create() - allocate a client and returns it -+ * @dev: the global ion device -+ * @heap_type_mask: mask of heaps this client can allocate from -+ * @name: used for debugging -+ */ -+struct ion_client *ion_client_create(struct ion_device *dev, -+ const char *name); -+ -+/** -+ * ion_client_destroy() - free's a client and all it's handles -+ * @client: the client -+ * -+ * Free the provided client and all it's resources including -+ * any handles it is holding. -+ */ -+void ion_client_destroy(struct ion_client *client); -+ -+/** -+ * ion_alloc - allocate ion memory -+ * @client: the client -+ * @len: size of the allocation -+ * @align: requested allocation alignment, lots of hardware blocks -+ * have alignment requirements of some kind -+ * @heap_id_mask: mask of heaps to allocate from, if multiple bits are set -+ * heaps will be tried in order from highest to lowest -+ * id -+ * @flags: heap flags, the low 16 bits are consumed by ion, the -+ * high 16 bits are passed on to the respective heap and -+ * can be heap custom -+ * -+ * Allocate memory in one of the heaps provided in heap mask and return -+ * an opaque handle to it. -+ */ -+struct ion_handle *ion_alloc(struct ion_client *client, size_t len, -+ size_t align, unsigned int heap_id_mask, -+ unsigned int flags); -+ -+/** -+ * ion_free - free a handle -+ * @client: the client -+ * @handle: the handle to free -+ * -+ * Free the provided handle. -+ */ -+void ion_free(struct ion_client *client, struct ion_handle *handle); -+ -+/** -+ * ion_phys - returns the physical address and len of a handle -+ * @client: the client -+ * @handle: the handle -+ * @addr: a pointer to put the address in -+ * @len: a pointer to put the length in -+ * -+ * This function queries the heap for a particular handle to get the -+ * handle's physical address. It't output is only correct if -+ * a heap returns physically contiguous memory -- in other cases -+ * this api should not be implemented -- ion_sg_table should be used -+ * instead. Returns -EINVAL if the handle is invalid. This has -+ * no implications on the reference counting of the handle -- -+ * the returned value may not be valid if the caller is not -+ * holding a reference. -+ */ -+int ion_phys(struct ion_client *client, struct ion_handle *handle, -+ ion_phys_addr_t *addr, size_t *len); -+ -+/** -+ * ion_map_dma - return an sg_table describing a handle -+ * @client: the client -+ * @handle: the handle -+ * -+ * This function returns the sg_table describing -+ * a particular ion handle. -+ */ -+struct sg_table *ion_sg_table(struct ion_client *client, -+ struct ion_handle *handle); -+ -+/** -+ * ion_map_kernel - create mapping for the given handle -+ * @client: the client -+ * @handle: handle to map -+ * -+ * Map the given handle into the kernel and return a kernel address that -+ * can be used to access this address. -+ */ -+void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle); -+ -+/** -+ * ion_unmap_kernel() - destroy a kernel mapping for a handle -+ * @client: the client -+ * @handle: handle to unmap -+ */ -+void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle); -+ -+/** -+ * ion_share_dma_buf() - share buffer as dma-buf -+ * @client: the client -+ * @handle: the handle -+ */ -+struct dma_buf *ion_share_dma_buf(struct ion_client *client, -+ struct ion_handle *handle); -+ -+/** -+ * ion_share_dma_buf_fd() - given an ion client, create a dma-buf fd -+ * @client: the client -+ * @handle: the handle -+ */ -+int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle); -+ -+/** -+ * ion_import_dma_buf() - given an dma-buf fd from the ion exporter get handle -+ * @client: the client -+ * @fd: the dma-buf fd -+ * -+ * Given an dma-buf fd that was allocated through ion via ion_share_dma_buf, -+ * import that fd and return a handle representing it. If a dma-buf from -+ * another exporter is passed in this function will return ERR_PTR(-EINVAL) -+ */ -+struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd); -+ -+#endif /* __KERNEL__ */ -+ -+/** -+ * DOC: Ion Userspace API -+ * -+ * create a client by opening /dev/ion -+ * most operations handled via following ioctls -+ * -+ */ -+ -+/** -+ * struct ion_allocation_data - metadata passed from userspace for allocations -+ * @len: size of the allocation -+ * @align: required alignment of the allocation -+ * @heap_id_mask: mask of heap ids to allocate from -+ * @flags: flags passed to heap -+ * @handle: pointer that will be populated with a cookie to use to -+ * refer to this allocation -+ * -+ * Provided by userspace as an argument to the ioctl -+ */ -+struct ion_allocation_data { -+ size_t len; -+ size_t align; -+ unsigned int heap_id_mask; -+ unsigned int flags; -+ struct ion_handle *handle; -+}; -+ -+/** -+ * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair -+ * @handle: a handle -+ * @fd: a file descriptor representing that handle -+ * -+ * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with -+ * the handle returned from ion alloc, and the kernel returns the file -+ * descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace -+ * provides the file descriptor and the kernel returns the handle. -+ */ -+struct ion_fd_data { -+ struct ion_handle *handle; -+ int fd; -+}; -+ -+/** -+ * struct ion_handle_data - a handle passed to/from the kernel -+ * @handle: a handle -+ */ -+struct ion_handle_data { -+ struct ion_handle *handle; -+}; -+ -+/** -+ * struct ion_custom_data - metadata passed to/from userspace for a custom ioctl -+ * @cmd: the custom ioctl function to call -+ * @arg: additional data to pass to the custom ioctl, typically a user -+ * pointer to a predefined structure -+ * -+ * This works just like the regular cmd and arg fields of an ioctl. -+ */ -+struct ion_custom_data { -+ unsigned int cmd; -+ unsigned long arg; -+}; -+ -+#define ION_IOC_MAGIC 'I' -+ -+/** -+ * DOC: ION_IOC_ALLOC - allocate memory -+ * -+ * Takes an ion_allocation_data struct and returns it with the handle field -+ * populated with the opaque handle for the allocation. -+ */ -+#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ -+ struct ion_allocation_data) -+ -+/** -+ * DOC: ION_IOC_FREE - free memory -+ * -+ * Takes an ion_handle_data struct and frees the handle. -+ */ -+#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) -+ -+/** -+ * DOC: ION_IOC_MAP - get a file descriptor to mmap -+ * -+ * Takes an ion_fd_data struct with the handle field populated with a valid -+ * opaque handle. Returns the struct with the fd field set to a file -+ * descriptor open in the current address space. This file descriptor -+ * can then be used as an argument to mmap. -+ */ -+#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation -+ * -+ * Takes an ion_fd_data struct with the handle field populated with a valid -+ * opaque handle. Returns the struct with the fd field set to a file -+ * descriptor open in the current address space. This file descriptor -+ * can then be passed to another process. The corresponding opaque handle can -+ * be retrieved via ION_IOC_IMPORT. -+ */ -+#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_IMPORT - imports a shared file descriptor -+ * -+ * Takes an ion_fd_data struct with the fd field populated with a valid file -+ * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle -+ * filed set to the corresponding opaque handle. -+ */ -+#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_SYNC - syncs a shared file descriptors to memory -+ * -+ * Deprecated in favor of using the dma_buf api's correctly (syncing -+ * will happend automatically when the buffer is mapped to a device). -+ * If necessary should be used after touching a cached buffer from the cpu, -+ * this will make the buffer in memory coherent. -+ */ -+#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) -+ -+/** -+ * DOC: ION_IOC_CUSTOM - call architecture specific ion ioctl -+ * -+ * Takes the argument of the architecture specific ioctl to call and -+ * passes appropriate userdata for that ioctl -+ */ -+#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) -+ -+#endif /* _LINUX_ION_H */ -diff --git a/include/linux/kernel.h b/include/linux/kernel.h -index 645231c3..747404ab 100644 ---- a/include/linux/kernel.h -+++ b/include/linux/kernel.h -@@ -705,6 +705,9 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } - - extern int do_sysinfo(struct sysinfo *info); - -+/* To identify board information in panic logs, set this */ -+extern char *mach_panic_string; -+ - #endif /* __KERNEL__ */ - - #endif -diff --git a/include/linux/keychord.h b/include/linux/keychord.h -new file mode 100644 -index 00000000..856a5850 ---- /dev/null -+++ b/include/linux/keychord.h -@@ -0,0 +1,52 @@ -+/* -+ * Key chord input driver -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+*/ -+ -+#ifndef __LINUX_KEYCHORD_H_ -+#define __LINUX_KEYCHORD_H_ -+ -+#include <linux/input.h> -+ -+#define KEYCHORD_VERSION 1 -+ -+/* -+ * One or more input_keychord structs are written to /dev/keychord -+ * at once to specify the list of keychords to monitor. -+ * Reading /dev/keychord returns the id of a keychord when the -+ * keychord combination is pressed. A keychord is signalled when -+ * all of the keys in the keycode list are in the pressed state. -+ * The order in which the keys are pressed does not matter. -+ * The keychord will not be signalled if keys not in the keycode -+ * list are pressed. -+ * Keychords will not be signalled on key release events. -+ */ -+struct input_keychord { -+ /* should be KEYCHORD_VERSION */ -+ __u16 version; -+ /* -+ * client specified ID, returned from read() -+ * when this keychord is pressed. -+ */ -+ __u16 id; -+ -+ /* number of keycodes in this keychord */ -+ __u16 count; -+ -+ /* variable length array of keycodes */ -+ __u16 keycodes[]; -+}; -+ -+#endif /* __LINUX_KEYCHORD_H_ */ -diff --git a/include/linux/keyreset.h b/include/linux/keyreset.h -new file mode 100644 -index 00000000..a2ac49e5 ---- /dev/null -+++ b/include/linux/keyreset.h -@@ -0,0 +1,28 @@ -+/* -+ * include/linux/keyreset.h - platform data structure for resetkeys driver -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_KEYRESET_H -+#define _LINUX_KEYRESET_H -+ -+#define KEYRESET_NAME "keyreset" -+ -+struct keyreset_platform_data { -+ int (*reset_fn)(void); -+ int *keys_up; -+ int keys_down[]; /* 0 terminated */ -+}; -+ -+#endif /* _LINUX_KEYRESET_H */ -diff --git a/include/linux/mm.h b/include/linux/mm.h -index 441a5641..01ebcc59 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -873,6 +873,7 @@ extern bool skip_free_areas_node(unsigned int flags, int nid); - - int shmem_lock(struct file *file, int lock, struct user_struct *user); - struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags); -+void shmem_set_file(struct vm_area_struct *vma, struct file *file); - int shmem_zero_setup(struct vm_area_struct *); - - extern int can_do_mlock(void); -diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h -index 1b431c72..884c08bb 100644 ---- a/include/linux/mmc/core.h -+++ b/include/linux/mmc/core.h -@@ -103,6 +103,7 @@ struct mmc_data { - unsigned int timeout_clks; /* data timeout (in clocks) */ - unsigned int blksz; /* data block size */ - unsigned int blocks; /* number of blocks */ -+ unsigned int retries; /* max number of retries */ - unsigned int error; /* data error */ - unsigned int flags; - -diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h -index 0707d228..5674504e 100644 ---- a/include/linux/mmc/host.h -+++ b/include/linux/mmc/host.h -@@ -14,6 +14,7 @@ - #include <linux/sched.h> - #include <linux/device.h> - #include <linux/fault-inject.h> -+#include <linux/wakelock.h> - - #include <linux/mmc/core.h> - #include <linux/mmc/pm.h> -@@ -289,12 +290,17 @@ struct mmc_host { - int claim_cnt; /* "claim" nesting count */ - - struct delayed_work detect; -+ struct wake_lock detect_wake_lock; - int detect_change; /* card detect flag */ - struct mmc_hotplug hotplug; - - const struct mmc_bus_ops *bus_ops; /* current bus driver */ - unsigned int bus_refs; /* reference counter */ - -+ unsigned int bus_resume_flags; -+#define MMC_BUSRESUME_MANUAL_RESUME (1 << 0) -+#define MMC_BUSRESUME_NEEDS_RESUME (1 << 1) -+ - unsigned int sdio_irqs; - struct task_struct *sdio_irq_thread; - bool sdio_irq_pending; -@@ -320,6 +326,15 @@ struct mmc_host { - - unsigned int actual_clock; /* Actual HC clock rate */ - -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+ struct { -+ struct sdio_cis *cis; -+ struct sdio_cccr *cccr; -+ struct sdio_embedded_func *funcs; -+ int num_funcs; -+ } embedded_sdio_data; -+#endif -+ - unsigned long private[0] ____cacheline_aligned; - }; - -@@ -328,6 +343,14 @@ extern int mmc_add_host(struct mmc_host *); - extern void mmc_remove_host(struct mmc_host *); - extern void mmc_free_host(struct mmc_host *); - -+#ifdef CONFIG_MMC_EMBEDDED_SDIO -+extern void mmc_set_embedded_sdio_data(struct mmc_host *host, -+ struct sdio_cis *cis, -+ struct sdio_cccr *cccr, -+ struct sdio_embedded_func *funcs, -+ int num_funcs); -+#endif -+ - static inline void *mmc_priv(struct mmc_host *host) - { - return (void *)host->private; -@@ -338,6 +361,18 @@ static inline void *mmc_priv(struct mmc_host *host) - #define mmc_dev(x) ((x)->parent) - #define mmc_classdev(x) (&(x)->class_dev) - #define mmc_hostname(x) (dev_name(&(x)->class_dev)) -+#define mmc_bus_needs_resume(host) ((host)->bus_resume_flags & MMC_BUSRESUME_NEEDS_RESUME) -+#define mmc_bus_manual_resume(host) ((host)->bus_resume_flags & MMC_BUSRESUME_MANUAL_RESUME) -+ -+static inline void mmc_set_bus_resume_policy(struct mmc_host *host, int manual) -+{ -+ if (manual) -+ host->bus_resume_flags |= MMC_BUSRESUME_MANUAL_RESUME; -+ else -+ host->bus_resume_flags &= ~MMC_BUSRESUME_MANUAL_RESUME; -+} -+ -+extern int mmc_resume_bus(struct mmc_host *host); - - extern int mmc_suspend_host(struct mmc_host *); - extern int mmc_resume_host(struct mmc_host *); -diff --git a/include/linux/mmc/pm.h b/include/linux/mmc/pm.h -index 4a139204..6e2d6a13 100644 ---- a/include/linux/mmc/pm.h -+++ b/include/linux/mmc/pm.h -@@ -26,5 +26,6 @@ typedef unsigned int mmc_pm_flag_t; - - #define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */ - #define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */ -+#define MMC_PM_IGNORE_PM_NOTIFY (1 << 2) /* ignore mmc pm notify */ - - #endif /* LINUX_MMC_PM_H */ -diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h -old mode 100644 -new mode 100755 -index 50f0bc95..dc680c4b ---- a/include/linux/mmc/sdio_func.h -+++ b/include/linux/mmc/sdio_func.h -@@ -22,6 +22,14 @@ struct sdio_func; - - typedef void (sdio_irq_handler_t)(struct sdio_func *); - -+/* -+ * Structure used to hold embedded SDIO device data from platform layer -+ */ -+struct sdio_embedded_func { -+ uint8_t f_class; -+ uint32_t f_maxblksize; -+}; -+ - /* - * SDIO function CIS tuple (unknown to the core) - */ -@@ -130,6 +138,8 @@ extern int sdio_release_irq(struct sdio_func *func); - extern unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz); - - extern u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret); -+extern u8 sdio_readb_ext(struct sdio_func *func, unsigned int addr, int *err_ret, -+ unsigned in); - extern u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret); - extern u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret); - -diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h -index 34066e65..f38d4f0a 100644 ---- a/include/linux/msdos_fs.h -+++ b/include/linux/msdos_fs.h -@@ -101,6 +101,7 @@ struct __fat_dirent { - /* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */ - #define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32) - #define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32) -+#define VFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) - - struct fat_boot_sector { - __u8 ignored[3]; /* Boot strap short or near jump */ -@@ -138,6 +139,17 @@ struct fat_boot_fsinfo { - __le32 reserved2[4]; - }; - -+struct fat_boot_bsx { -+ __u8 drive; /* drive number */ -+ __u8 reserved1; -+ __u8 signature; /* extended boot signature */ -+ __u8 vol_id[4]; /* volume ID */ -+ __u8 vol_label[11]; /* volume label */ -+ __u8 type[8]; /* file system type */ -+}; -+#define FAT16_BSX_OFFSET 36 /* offset of fat_boot_bsx in FAT12 and FAT16 */ -+#define FAT32_BSX_OFFSET 64 /* offset of fat_boot_bsx in FAT32 */ -+ - struct msdos_dir_entry { - __u8 name[MSDOS_NAME];/* name and extension */ - __u8 attr; /* attribute bits */ -diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h -index cf5ea8cd..76e77810 100644 ---- a/include/linux/mtd/mtd.h -+++ b/include/linux/mtd/mtd.h -@@ -224,6 +224,9 @@ struct mtd_info { - int (*_get_device) (struct mtd_info *mtd); - void (*_put_device) (struct mtd_info *mtd); - -+ /*Get device chip ID.*/ -+ int (*get_device_id) (struct mtd_info *mtd); -+ - /* Backing device capabilities for this device - * - provides mmap capabilities - */ -diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h -index 208ae938..faaa28b3 100644 ---- a/include/linux/netfilter/xt_IDLETIMER.h -+++ b/include/linux/netfilter/xt_IDLETIMER.h -@@ -4,6 +4,7 @@ - * Header file for Xtables timer target module. - * - * Copyright (C) 2004, 2010 Nokia Corporation -+ * - * Written by Timo Teras <ext-timo.teras@nokia.com> - * - * Converted to x_tables and forward-ported to 2.6.34 -@@ -32,12 +33,19 @@ - #include <linux/types.h> - - #define MAX_IDLETIMER_LABEL_SIZE 28 -+#define NLMSG_MAX_SIZE 64 -+ -+#define NL_EVENT_TYPE_INACTIVE 0 -+#define NL_EVENT_TYPE_ACTIVE 1 - - struct idletimer_tg_info { - __u32 timeout; - - char label[MAX_IDLETIMER_LABEL_SIZE]; - -+ /* Use netlink messages for notification in addition to sysfs */ -+ __u8 send_nl_msg; -+ - /* for kernel module internal use only */ - struct idletimer_tg *timer __attribute__((aligned(8))); - }; -diff --git a/include/linux/netfilter/xt_qtaguid.h b/include/linux/netfilter/xt_qtaguid.h -new file mode 100644 -index 00000000..ca60fbde ---- /dev/null -+++ b/include/linux/netfilter/xt_qtaguid.h -@@ -0,0 +1,13 @@ -+#ifndef _XT_QTAGUID_MATCH_H -+#define _XT_QTAGUID_MATCH_H -+ -+/* For now we just replace the xt_owner. -+ * FIXME: make iptables aware of qtaguid. */ -+#include <linux/netfilter/xt_owner.h> -+ -+#define XT_QTAGUID_UID XT_OWNER_UID -+#define XT_QTAGUID_GID XT_OWNER_GID -+#define XT_QTAGUID_SOCKET XT_OWNER_SOCKET -+#define xt_qtaguid_match_info xt_owner_match_info -+ -+#endif /* _XT_QTAGUID_MATCH_H */ -diff --git a/include/linux/netfilter/xt_quota2.h b/include/linux/netfilter/xt_quota2.h -new file mode 100644 -index 00000000..eadc6903 ---- /dev/null -+++ b/include/linux/netfilter/xt_quota2.h -@@ -0,0 +1,25 @@ -+#ifndef _XT_QUOTA_H -+#define _XT_QUOTA_H -+ -+enum xt_quota_flags { -+ XT_QUOTA_INVERT = 1 << 0, -+ XT_QUOTA_GROW = 1 << 1, -+ XT_QUOTA_PACKET = 1 << 2, -+ XT_QUOTA_NO_CHANGE = 1 << 3, -+ XT_QUOTA_MASK = 0x0F, -+}; -+ -+struct xt_quota_counter; -+ -+struct xt_quota_mtinfo2 { -+ char name[15]; -+ u_int8_t flags; -+ -+ /* Comparison-invariant */ -+ aligned_u64 quota; -+ -+ /* Used internally by the kernel */ -+ struct xt_quota_counter *master __attribute__((aligned(8))); -+}; -+ -+#endif /* _XT_QUOTA_H */ -diff --git a/include/linux/netfilter/xt_socket.h b/include/linux/netfilter/xt_socket.h -index 26d7217b..63594564 100644 ---- a/include/linux/netfilter/xt_socket.h -+++ b/include/linux/netfilter/xt_socket.h -@@ -11,4 +11,10 @@ struct xt_socket_mtinfo1 { - __u8 flags; - }; - -+void xt_socket_put_sk(struct sock *sk); -+struct sock *xt_socket_get4_sk(const struct sk_buff *skb, -+ struct xt_action_param *par); -+struct sock *xt_socket_get6_sk(const struct sk_buff *skb, -+ struct xt_action_param *par); -+ - #endif /* _XT_SOCKET_H */ -diff --git a/include/linux/nmi.h b/include/linux/nmi.h -index db50840e..c8f8aa03 100644 ---- a/include/linux/nmi.h -+++ b/include/linux/nmi.h -@@ -14,8 +14,11 @@ - * may be used to reset the timeout - for code which intentionally - * disables interrupts for a long time. This call is stateless. - */ --#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR) -+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR_NMI) - #include <asm/nmi.h> -+#endif -+ -+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR) - extern void touch_nmi_watchdog(void); - #else - static inline void touch_nmi_watchdog(void) -diff --git a/drivers/staging/android/persistent_ram.h b/include/linux/persistent_ram.h -similarity index 96% -rename from drivers/staging/android/persistent_ram.h -rename to include/linux/persistent_ram.h -index f41e2086..22422171 100644 ---- a/drivers/staging/android/persistent_ram.h -+++ b/include/linux/persistent_ram.h -@@ -31,6 +31,11 @@ struct persistent_ram { - phys_addr_t start; - phys_addr_t size; - -+ int ecc_block_size; -+ int ecc_size; -+ int ecc_symsize; -+ int ecc_poly; -+ - int num_descs; - struct persistent_ram_descriptor *descs; - -diff --git a/include/linux/platform_data/android_battery.h b/include/linux/platform_data/android_battery.h -new file mode 100644 -index 00000000..f6c8298f ---- /dev/null -+++ b/include/linux/platform_data/android_battery.h -@@ -0,0 +1,47 @@ -+/* -+ * android_battery.h -+ * -+ * Copyright (C) 2012 Samsung Electronics -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef _LINUX_ANDROID_BATTERY_H -+#define _LINUX_ANDROID_BATTERY_H -+ -+enum { -+ CHARGE_SOURCE_NONE = 0, -+ CHARGE_SOURCE_AC, -+ CHARGE_SOURCE_USB, -+}; -+ -+struct android_bat_callbacks { -+ void (*charge_source_changed) -+ (struct android_bat_callbacks *, int); -+ void (*battery_set_full)(struct android_bat_callbacks *); -+}; -+ -+struct android_bat_platform_data { -+ void (*register_callbacks)(struct android_bat_callbacks *); -+ void (*unregister_callbacks)(void); -+ void (*set_charging_current) (int); -+ void (*set_charging_enable) (int); -+ int (*poll_charge_source) (void); -+ int (*get_capacity) (void); -+ int (*get_temperature) (int *); -+ int (*get_voltage_now)(void); -+ int (*get_current_now)(int *); -+ -+ int temp_high_threshold; -+ int temp_high_recovery; -+ int temp_low_recovery; -+ int temp_low_threshold; -+ -+ unsigned long full_charging_time; -+ unsigned long recharging_time; -+ unsigned int recharging_voltage; -+}; -+ -+#endif -diff --git a/include/linux/platform_data/ds2482.h b/include/linux/platform_data/ds2482.h -new file mode 100644 -index 00000000..5a6879e2 ---- /dev/null -+++ b/include/linux/platform_data/ds2482.h -@@ -0,0 +1,21 @@ -+/* -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#ifndef __PLATFORM_DATA_DS2482__ -+#define __PLATFORM_DATA_DS2482__ -+ -+struct ds2482_platform_data { -+ int slpz_gpio; -+}; -+ -+#endif /* __PLATFORM_DATA_DS2482__ */ -diff --git a/include/linux/pm.h b/include/linux/pm.h -index 715305e0..f067e60a 100644 ---- a/include/linux/pm.h -+++ b/include/linux/pm.h -@@ -544,8 +544,6 @@ struct dev_pm_info { - unsigned long active_jiffies; - unsigned long suspended_jiffies; - unsigned long accounting_timestamp; -- ktime_t suspend_time; -- s64 max_time_suspended_ns; - struct dev_pm_qos_request *pq_req; - #endif - struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ -diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h -index 91f82861..30f794eb 100644 ---- a/include/linux/pm_domain.h -+++ b/include/linux/pm_domain.h -@@ -14,6 +14,7 @@ - #include <linux/pm.h> - #include <linux/err.h> - #include <linux/of.h> -+#include <linux/notifier.h> - - enum gpd_status { - GPD_STATE_ACTIVE = 0, /* PM domain is active */ -@@ -70,9 +71,9 @@ struct generic_pm_domain { - int (*power_on)(struct generic_pm_domain *domain); - s64 power_on_latency_ns; - struct gpd_dev_ops dev_ops; -- s64 break_even_ns; /* Power break even for the entire domain. */ - s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ -- ktime_t power_off_time; -+ bool max_off_time_changed; -+ bool cached_power_down_ok; - struct device_node *of_node; /* Node in device tree */ - }; - -@@ -93,13 +94,17 @@ struct gpd_timing_data { - s64 start_latency_ns; - s64 save_state_latency_ns; - s64 restore_state_latency_ns; -- s64 break_even_ns; -+ s64 effective_constraint_ns; -+ bool constraint_changed; -+ bool cached_stop_ok; - }; - - struct generic_pm_domain_data { - struct pm_domain_data base; - struct gpd_dev_ops ops; - struct gpd_timing_data td; -+ struct notifier_block nb; -+ struct mutex lock; - bool need_restore; - bool always_on; - }; -@@ -141,6 +146,7 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node, - extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, - struct device *dev); - extern void pm_genpd_dev_always_on(struct device *dev, bool val); -+extern void pm_genpd_dev_need_restore(struct device *dev, bool val); - extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *new_subdomain); - extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, -@@ -184,6 +190,7 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, - return -ENOSYS; - } - static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {} -+static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {} - static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *new_sd) - { -diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h -index 609daae7..f271860c 100644 ---- a/include/linux/pm_runtime.h -+++ b/include/linux/pm_runtime.h -@@ -150,9 +150,6 @@ static inline void pm_runtime_set_autosuspend_delay(struct device *dev, - static inline unsigned long pm_runtime_autosuspend_expiration( - struct device *dev) { return 0; } - --static inline void pm_runtime_update_max_time_suspended(struct device *dev, -- s64 delta_ns) {} -- - #endif /* !CONFIG_PM_RUNTIME */ - - static inline int pm_runtime_idle(struct device *dev) -diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h -index d9f05113..569781fa 100644 ---- a/include/linux/pm_wakeup.h -+++ b/include/linux/pm_wakeup.h -@@ -33,12 +33,15 @@ - * - * @total_time: Total time this wakeup source has been active. - * @max_time: Maximum time this wakeup source has been continuously active. -- * @last_time: Monotonic clock when the wakeup source's was activated last time. -+ * @last_time: Monotonic clock when the wakeup source's was touched last time. -+ * @prevent_sleep_time: Total time this source has been preventing autosleep. - * @event_count: Number of signaled wakeup events. - * @active_count: Number of times the wakeup sorce was activated. - * @relax_count: Number of times the wakeup sorce was deactivated. -- * @hit_count: Number of times the wakeup sorce might abort system suspend. -+ * @expire_count: Number of times the wakeup source's timeout has expired. -+ * @wakeup_count: Number of times the wakeup source might abort suspend. - * @active: Status of the wakeup source. -+ * @has_timeout: The wakeup source has been activated with a timeout. - */ - struct wakeup_source { - const char *name; -@@ -49,11 +52,15 @@ struct wakeup_source { - ktime_t total_time; - ktime_t max_time; - ktime_t last_time; -+ ktime_t start_prevent_time; -+ ktime_t prevent_sleep_time; - unsigned long event_count; - unsigned long active_count; - unsigned long relax_count; -- unsigned long hit_count; -- unsigned int active:1; -+ unsigned long expire_count; -+ unsigned long wakeup_count; -+ bool active:1; -+ bool autosleep_enabled:1; - }; - - #ifdef CONFIG_PM_SLEEP -diff --git a/include/linux/power/smb347-charger.h b/include/linux/power/smb347-charger.h -index b3cb20da..e9aab944 100644 ---- a/include/linux/power/smb347-charger.h -+++ b/include/linux/power/smb347-charger.h -@@ -110,8 +110,14 @@ struct smb347_charger_platform_data { - bool use_mains; - bool use_usb; - bool use_usb_otg; -+ bool disable_automatic_recharge; - int irq_gpio; -+ bool disable_stat_interrupts; - enum smb347_chg_enable enable_control; -+ bool usb_mode_pin_ctrl; -+ char **supplied_to; -+ size_t num_supplicants; -+ int en_gpio; - }; - - #endif /* SMB347_CHARGER_H */ -diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h -index c38c13db..e1f54479 100644 ---- a/include/linux/power_supply.h -+++ b/include/linux/power_supply.h -@@ -124,6 +124,10 @@ enum power_supply_property { - POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, - POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */ - POWER_SUPPLY_PROP_SCOPE, -+ /* Local extensions */ -+ POWER_SUPPLY_PROP_USB_HC, -+ POWER_SUPPLY_PROP_USB_OTG, -+ POWER_SUPPLY_PROP_CHARGE_ENABLED, - /* Properties of type `const char *' */ - POWER_SUPPLY_PROP_MODEL_NAME, - POWER_SUPPLY_PROP_MANUFACTURER, -@@ -172,6 +176,8 @@ struct power_supply { - /* private */ - struct device *dev; - struct work_struct changed_work; -+ spinlock_t changed_lock; -+ bool changed; - - #ifdef CONFIG_LEDS_TRIGGERS - struct led_trigger *charging_full_trig; -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 3dd0efbb..937ab61f 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1804,6 +1804,9 @@ static inline void put_task_struct(struct task_struct *t) - extern void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st); - extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st); - -+extern int task_free_register(struct notifier_block *n); -+extern int task_free_unregister(struct notifier_block *n); -+ - /* - * Per process flags - */ -diff --git a/include/linux/security.h b/include/linux/security.h -index 673afbb8..b62f3969 100644 ---- a/include/linux/security.h -+++ b/include/linux/security.h -@@ -1381,6 +1381,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) - struct security_operations { - char name[SECURITY_NAME_MAX + 1]; - -+ int (*binder_set_context_mgr) (struct task_struct *mgr); -+ int (*binder_transaction) (struct task_struct *from, struct task_struct *to); -+ int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to); -+ int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file); -+ - int (*ptrace_access_check) (struct task_struct *child, unsigned int mode); - int (*ptrace_traceme) (struct task_struct *parent); - int (*capget) (struct task_struct *target, -@@ -1664,6 +1669,10 @@ extern void __init security_fixup_ops(struct security_operations *ops); - - - /* Security operations */ -+int security_binder_set_context_mgr(struct task_struct *mgr); -+int security_binder_transaction(struct task_struct *from, struct task_struct *to); -+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to); -+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file); - int security_ptrace_access_check(struct task_struct *child, unsigned int mode); - int security_ptrace_traceme(struct task_struct *parent); - int security_capget(struct task_struct *target, -@@ -1842,6 +1851,26 @@ static inline int security_init(void) - return 0; - } - -+static inline int security_binder_set_context_mgr(struct task_struct *mgr) -+{ -+ return 0; -+} -+ -+static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to) -+{ -+ return 0; -+} -+ -+static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to) -+{ -+ return 0; -+} -+ -+static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) -+{ -+ return 0; -+} -+ - static inline int security_ptrace_access_check(struct task_struct *child, - unsigned int mode) - { -diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h -index 2db407a4..c1df3fe2 100644 ---- a/include/linux/serial_core.h -+++ b/include/linux/serial_core.h -@@ -213,6 +213,12 @@ - /* Energy Micro efm32 SoC */ - #define PORT_EFMUART 100 - -+/* Anyka AK39xx UART */ -+#define PORT_AK39 101 -+ -+/* Anyka GPIO UART */ -+#define PORT_GPIO 102 -+ - #ifdef __KERNEL__ - - #include <linux/compiler.h> -@@ -252,6 +258,7 @@ struct uart_ops { - void (*pm)(struct uart_port *, unsigned int state, - unsigned int oldstate); - int (*set_wake)(struct uart_port *, unsigned int state); -+ void (*wake_peer)(struct uart_port *); - - /* - * Return a string describing the type of the port -diff --git a/include/linux/sockios.h b/include/linux/sockios.h -index 7997a506..f7ffe36d 100644 ---- a/include/linux/sockios.h -+++ b/include/linux/sockios.h -@@ -65,6 +65,7 @@ - #define SIOCDIFADDR 0x8936 /* delete PA address */ - #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ - #define SIOCGIFCOUNT 0x8938 /* get number of devices */ -+#define SIOCKILLADDR 0x8939 /* kill sockets with this local addr */ - - #define SIOCGIFBR 0x8940 /* Bridging support */ - #define SIOCSIFBR 0x8941 /* Set bridging options */ -diff --git a/include/linux/spi/flash.h b/include/linux/spi/flash.h -index 3f22932e..7a76e33d 100644 ---- a/include/linux/spi/flash.h -+++ b/include/linux/spi/flash.h -@@ -3,6 +3,14 @@ - - struct mtd_partition; - -+ -+ -+#define FLASH_BUS_WIDTH_1WIRE (1<<0) -+#define FLASH_BUS_WIDTH_2WIRE (1<<1) -+#define FLASH_BUS_WIDTH_4WIRE (1<<2) -+ -+ -+ - /** - * struct flash_platform_data: board-specific flash data - * @name: optional flash device name (eg, as used with mtdparts=) -@@ -25,6 +33,7 @@ struct flash_platform_data { - - char *type; - -+ u8 bus_width; - /* we'll likely add more ... use JEDEC IDs, etc */ - }; - -diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h -index fa702aeb..10fedb05 100644 ---- a/include/linux/spi/spi.h -+++ b/include/linux/spi/spi.h -@@ -72,7 +72,7 @@ struct spi_device { - struct spi_master *master; - u32 max_speed_hz; - u8 chip_select; -- u8 mode; -+ u16 mode; - #define SPI_CPHA 0x01 /* clock phase */ - #define SPI_CPOL 0x02 /* clock polarity */ - #define SPI_MODE_0 (0|0) /* (original MicroWire) */ -@@ -85,6 +85,7 @@ struct spi_device { - #define SPI_LOOP 0x20 /* loopback mode */ - #define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */ - #define SPI_READY 0x80 /* slave pulls low to pause */ -+ - u8 bits_per_word; - int irq; - void *controller_state; -@@ -507,9 +508,15 @@ struct spi_transfer { - u16 delay_usecs; - u32 speed_hz; - -+ u8 xfer_mode; -+#define XFER_1DATAWIRE 0x00 -+#define XFER_2DATAWIRE 0x01 -+#define XFER_4DATAWIRE 0x02 -+ - struct list_head transfer_list; - }; - -+ - /** - * struct spi_message - one multi-segment SPI transaction - * @transfers: list of transfer segments in this transaction -@@ -806,7 +813,7 @@ struct spi_board_info { - /* mode becomes spi_device.mode, and is essential for chips - * where the default of SPI_CS_HIGH = 0 is wrong. - */ -- u8 mode; -+ u16 mode; - - /* ... may need additional spi_device chip config data here. - * avoid stuff protocol drivers can set; but include stuff -diff --git a/include/linux/suspend.h b/include/linux/suspend.h -index ac1c114c..cd83059f 100644 ---- a/include/linux/suspend.h -+++ b/include/linux/suspend.h -@@ -356,8 +356,9 @@ extern int unregister_pm_notifier(struct notifier_block *nb); - extern bool events_check_enabled; - - extern bool pm_wakeup_pending(void); --extern bool pm_get_wakeup_count(unsigned int *count); -+extern bool pm_get_wakeup_count(unsigned int *count, bool block); - extern bool pm_save_wakeup_count(unsigned int count); -+extern void pm_wakep_autosleep_enabled(bool set); - - static inline void lock_system_sleep(void) - { -@@ -407,6 +408,17 @@ static inline void unlock_system_sleep(void) {} - - #endif /* !CONFIG_PM_SLEEP */ - -+#ifdef CONFIG_PM_AUTOSLEEP -+ -+/* kernel/power/autosleep.c */ -+void queue_up_suspend_work(void); -+ -+#else /* !CONFIG_PM_AUTOSLEEP */ -+ -+static inline void queue_up_suspend_work(void) {} -+ -+#endif /* !CONFIG_PM_AUTOSLEEP */ -+ - #ifdef CONFIG_ARCH_SAVE_PAGE_KEYS - /* - * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture -diff --git a/include/linux/sw_sync.h b/include/linux/sw_sync.h -new file mode 100644 -index 00000000..bd6f2089 ---- /dev/null -+++ b/include/linux/sw_sync.h -@@ -0,0 +1,58 @@ -+/* -+ * include/linux/sw_sync.h -+ * -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_SW_SYNC_H -+#define _LINUX_SW_SYNC_H -+ -+#include <linux/types.h> -+ -+#ifdef __KERNEL__ -+ -+#include <linux/sync.h> -+ -+struct sw_sync_timeline { -+ struct sync_timeline obj; -+ -+ u32 value; -+}; -+ -+struct sw_sync_pt { -+ struct sync_pt pt; -+ -+ u32 value; -+}; -+ -+struct sw_sync_timeline *sw_sync_timeline_create(const char *name); -+void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc); -+ -+struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value); -+ -+#endif /* __KERNEL __ */ -+ -+struct sw_sync_create_fence_data { -+ __u32 value; -+ char name[32]; -+ __s32 fence; /* fd of new fence */ -+}; -+ -+#define SW_SYNC_IOC_MAGIC 'W' -+ -+#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ -+ struct sw_sync_create_fence_data) -+#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) -+ -+ -+#endif /* _LINUX_SW_SYNC_H */ -diff --git a/include/linux/switch.h b/include/linux/switch.h -new file mode 100644 -index 00000000..3e4c748e ---- /dev/null -+++ b/include/linux/switch.h -@@ -0,0 +1,53 @@ -+/* -+ * Switch class driver -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+*/ -+ -+#ifndef __LINUX_SWITCH_H__ -+#define __LINUX_SWITCH_H__ -+ -+struct switch_dev { -+ const char *name; -+ struct device *dev; -+ int index; -+ int state; -+ -+ ssize_t (*print_name)(struct switch_dev *sdev, char *buf); -+ ssize_t (*print_state)(struct switch_dev *sdev, char *buf); -+}; -+ -+struct gpio_switch_platform_data { -+ const char *name; -+ unsigned gpio; -+ -+ /* if NULL, switch_dev.name will be printed */ -+ const char *name_on; -+ const char *name_off; -+ /* if NULL, "0" or "1" will be printed */ -+ const char *state_on; -+ const char *state_off; -+}; -+ -+extern int switch_dev_register(struct switch_dev *sdev); -+extern void switch_dev_unregister(struct switch_dev *sdev); -+ -+static inline int switch_get_state(struct switch_dev *sdev) -+{ -+ return sdev->state; -+} -+ -+extern void switch_set_state(struct switch_dev *sdev, int state); -+ -+#endif /* __LINUX_SWITCH_H__ */ -diff --git a/include/linux/synaptics_i2c_rmi.h b/include/linux/synaptics_i2c_rmi.h -new file mode 100644 -index 00000000..5539cc52 ---- /dev/null -+++ b/include/linux/synaptics_i2c_rmi.h -@@ -0,0 +1,55 @@ -+/* -+ * include/linux/synaptics_i2c_rmi.h - platform data structure for f75375s sensor -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_SYNAPTICS_I2C_RMI_H -+#define _LINUX_SYNAPTICS_I2C_RMI_H -+ -+#define SYNAPTICS_I2C_RMI_NAME "synaptics-rmi-ts" -+ -+enum { -+ SYNAPTICS_FLIP_X = 1UL << 0, -+ SYNAPTICS_FLIP_Y = 1UL << 1, -+ SYNAPTICS_SWAP_XY = 1UL << 2, -+ SYNAPTICS_SNAP_TO_INACTIVE_EDGE = 1UL << 3, -+}; -+ -+struct synaptics_i2c_rmi_platform_data { -+ uint32_t version; /* Use this entry for panels with */ -+ /* (major << 8 | minor) version or above. */ -+ /* If non-zero another array entry follows */ -+ int (*power)(int on); /* Only valid in first array entry */ -+ uint32_t flags; -+ unsigned long irqflags; -+ uint32_t inactive_left; /* 0x10000 = screen width */ -+ uint32_t inactive_right; /* 0x10000 = screen width */ -+ uint32_t inactive_top; /* 0x10000 = screen height */ -+ uint32_t inactive_bottom; /* 0x10000 = screen height */ -+ uint32_t snap_left_on; /* 0x10000 = screen width */ -+ uint32_t snap_left_off; /* 0x10000 = screen width */ -+ uint32_t snap_right_on; /* 0x10000 = screen width */ -+ uint32_t snap_right_off; /* 0x10000 = screen width */ -+ uint32_t snap_top_on; /* 0x10000 = screen height */ -+ uint32_t snap_top_off; /* 0x10000 = screen height */ -+ uint32_t snap_bottom_on; /* 0x10000 = screen height */ -+ uint32_t snap_bottom_off; /* 0x10000 = screen height */ -+ uint32_t fuzz_x; /* 0x10000 = screen width */ -+ uint32_t fuzz_y; /* 0x10000 = screen height */ -+ int fuzz_p; -+ int fuzz_w; -+ int8_t sensitivity_adjust; -+}; -+ -+#endif /* _LINUX_SYNAPTICS_I2C_RMI_H */ -diff --git a/include/linux/sync.h b/include/linux/sync.h -new file mode 100644 -index 00000000..5f493638 ---- /dev/null -+++ b/include/linux/sync.h -@@ -0,0 +1,427 @@ -+/* -+ * include/linux/sync.h -+ * -+ * Copyright (C) 2012 Google, Inc. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_SYNC_H -+#define _LINUX_SYNC_H -+ -+#include <linux/types.h> -+#ifdef __KERNEL__ -+ -+#include <linux/kref.h> -+#include <linux/ktime.h> -+#include <linux/list.h> -+#include <linux/seq_file.h> -+#include <linux/spinlock.h> -+#include <linux/wait.h> -+ -+struct sync_timeline; -+struct sync_pt; -+struct sync_fence; -+ -+/** -+ * struct sync_timeline_ops - sync object implementation ops -+ * @driver_name: name of the implentation -+ * @dup: duplicate a sync_pt -+ * @has_signaled: returns: -+ * 1 if pt has signaled -+ * 0 if pt has not signaled -+ * <0 on error -+ * @compare: returns: -+ * 1 if b will signal before a -+ * 0 if a and b will signal at the same time -+ * -1 if a will signabl before b -+ * @free_pt: called before sync_pt is freed -+ * @release_obj: called before sync_timeline is freed -+ * @print_obj: deprecated -+ * @print_pt: deprecated -+ * @fill_driver_data: write implmentation specific driver data to data. -+ * should return an error if there is not enough room -+ * as specified by size. This information is returned -+ * to userspace by SYNC_IOC_FENCE_INFO. -+ * @timeline_value_str: fill str with the value of the sync_timeline's counter -+ * @pt_value_str: fill str with the value of the sync_pt -+ */ -+struct sync_timeline_ops { -+ const char *driver_name; -+ -+ /* required */ -+ struct sync_pt *(*dup)(struct sync_pt *pt); -+ -+ /* required */ -+ int (*has_signaled)(struct sync_pt *pt); -+ -+ /* required */ -+ int (*compare)(struct sync_pt *a, struct sync_pt *b); -+ -+ /* optional */ -+ void (*free_pt)(struct sync_pt *sync_pt); -+ -+ /* optional */ -+ void (*release_obj)(struct sync_timeline *sync_timeline); -+ -+ /* deprecated */ -+ void (*print_obj)(struct seq_file *s, -+ struct sync_timeline *sync_timeline); -+ -+ /* deprecated */ -+ void (*print_pt)(struct seq_file *s, struct sync_pt *sync_pt); -+ -+ /* optional */ -+ int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size); -+ -+ /* optional */ -+ void (*timeline_value_str)(struct sync_timeline *timeline, char *str, -+ int size); -+ -+ /* optional */ -+ void (*pt_value_str)(struct sync_pt *pt, char *str, int size); -+}; -+ -+/** -+ * struct sync_timeline - sync object -+ * @kref: reference count on fence. -+ * @ops: ops that define the implementaiton of the sync_timeline -+ * @name: name of the sync_timeline. Useful for debugging -+ * @destoryed: set when sync_timeline is destroyed -+ * @child_list_head: list of children sync_pts for this sync_timeline -+ * @child_list_lock: lock protecting @child_list_head, destroyed, and -+ * sync_pt.status -+ * @active_list_head: list of active (unsignaled/errored) sync_pts -+ * @sync_timeline_list: membership in global sync_timeline_list -+ */ -+struct sync_timeline { -+ struct kref kref; -+ const struct sync_timeline_ops *ops; -+ char name[32]; -+ -+ /* protected by child_list_lock */ -+ bool destroyed; -+ -+ struct list_head child_list_head; -+ spinlock_t child_list_lock; -+ -+ struct list_head active_list_head; -+ spinlock_t active_list_lock; -+ -+ struct list_head sync_timeline_list; -+}; -+ -+/** -+ * struct sync_pt - sync point -+ * @parent: sync_timeline to which this sync_pt belongs -+ * @child_list: membership in sync_timeline.child_list_head -+ * @active_list: membership in sync_timeline.active_list_head -+ * @signaled_list: membership in temorary signaled_list on stack -+ * @fence: sync_fence to which the sync_pt belongs -+ * @pt_list: membership in sync_fence.pt_list_head -+ * @status: 1: signaled, 0:active, <0: error -+ * @timestamp: time which sync_pt status transitioned from active to -+ * singaled or error. -+ */ -+struct sync_pt { -+ struct sync_timeline *parent; -+ struct list_head child_list; -+ -+ struct list_head active_list; -+ struct list_head signaled_list; -+ -+ struct sync_fence *fence; -+ struct list_head pt_list; -+ -+ /* protected by parent->active_list_lock */ -+ int status; -+ -+ ktime_t timestamp; -+}; -+ -+/** -+ * struct sync_fence - sync fence -+ * @file: file representing this fence -+ * @kref: referenace count on fence. -+ * @name: name of sync_fence. Useful for debugging -+ * @pt_list_head: list of sync_pts in ths fence. immutable once fence -+ * is created -+ * @waiter_list_head: list of asynchronous waiters on this fence -+ * @waiter_list_lock: lock protecting @waiter_list_head and @status -+ * @status: 1: signaled, 0:active, <0: error -+ * -+ * @wq: wait queue for fence signaling -+ * @sync_fence_list: membership in global fence list -+ */ -+struct sync_fence { -+ struct file *file; -+ struct kref kref; -+ char name[32]; -+ -+ /* this list is immutable once the fence is created */ -+ struct list_head pt_list_head; -+ -+ struct list_head waiter_list_head; -+ spinlock_t waiter_list_lock; /* also protects status */ -+ int status; -+ -+ wait_queue_head_t wq; -+ -+ struct list_head sync_fence_list; -+}; -+ -+struct sync_fence_waiter; -+typedef void (*sync_callback_t)(struct sync_fence *fence, -+ struct sync_fence_waiter *waiter); -+ -+/** -+ * struct sync_fence_waiter - metadata for asynchronous waiter on a fence -+ * @waiter_list: membership in sync_fence.waiter_list_head -+ * @callback: function pointer to call when fence signals -+ * @callback_data: pointer to pass to @callback -+ */ -+struct sync_fence_waiter { -+ struct list_head waiter_list; -+ -+ sync_callback_t callback; -+}; -+ -+static inline void sync_fence_waiter_init(struct sync_fence_waiter *waiter, -+ sync_callback_t callback) -+{ -+ waiter->callback = callback; -+} -+ -+/* -+ * API for sync_timeline implementers -+ */ -+ -+/** -+ * sync_timeline_create() - creates a sync object -+ * @ops: specifies the implemention ops for the object -+ * @size: size to allocate for this obj -+ * @name: sync_timeline name -+ * -+ * Creates a new sync_timeline which will use the implemetation specified by -+ * @ops. @size bytes will be allocated allowing for implemntation specific -+ * data to be kept after the generic sync_timeline stuct. -+ */ -+struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, -+ int size, const char *name); -+ -+/** -+ * sync_timeline_destory() - destorys a sync object -+ * @obj: sync_timeline to destroy -+ * -+ * A sync implemntation should call this when the @obj is going away -+ * (i.e. module unload.) @obj won't actually be freed until all its childern -+ * sync_pts are freed. -+ */ -+void sync_timeline_destroy(struct sync_timeline *obj); -+ -+/** -+ * sync_timeline_signal() - signal a status change on a sync_timeline -+ * @obj: sync_timeline to signal -+ * -+ * A sync implemntation should call this any time one of it's sync_pts -+ * has signaled or has an error condition. -+ */ -+void sync_timeline_signal(struct sync_timeline *obj); -+ -+/** -+ * sync_pt_create() - creates a sync pt -+ * @parent: sync_pt's parent sync_timeline -+ * @size: size to allocate for this pt -+ * -+ * Creates a new sync_pt as a chiled of @parent. @size bytes will be -+ * allocated allowing for implemntation specific data to be kept after -+ * the generic sync_timeline struct. -+ */ -+struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size); -+ -+/** -+ * sync_pt_free() - frees a sync pt -+ * @pt: sync_pt to free -+ * -+ * This should only be called on sync_pts which have been created but -+ * not added to a fence. -+ */ -+void sync_pt_free(struct sync_pt *pt); -+ -+/** -+ * sync_fence_create() - creates a sync fence -+ * @name: name of fence to create -+ * @pt: sync_pt to add to the fence -+ * -+ * Creates a fence containg @pt. Once this is called, the fence takes -+ * ownership of @pt. -+ */ -+struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt); -+ -+/* -+ * API for sync_fence consumers -+ */ -+ -+/** -+ * sync_fence_merge() - merge two fences -+ * @name: name of new fence -+ * @a: fence a -+ * @b: fence b -+ * -+ * Creates a new fence which contains copies of all the sync_pts in both -+ * @a and @b. @a and @b remain valid, independent fences. -+ */ -+struct sync_fence *sync_fence_merge(const char *name, -+ struct sync_fence *a, struct sync_fence *b); -+ -+/** -+ * sync_fence_fdget() - get a fence from an fd -+ * @fd: fd referencing a fence -+ * -+ * Ensures @fd references a valid fence, increments the refcount of the backing -+ * file, and returns the fence. -+ */ -+struct sync_fence *sync_fence_fdget(int fd); -+ -+/** -+ * sync_fence_put() - puts a refernnce of a sync fence -+ * @fence: fence to put -+ * -+ * Puts a reference on @fence. If this is the last reference, the fence and -+ * all it's sync_pts will be freed -+ */ -+void sync_fence_put(struct sync_fence *fence); -+ -+/** -+ * sync_fence_install() - installs a fence into a file descriptor -+ * @fence: fence to instal -+ * @fd: file descriptor in which to install the fence -+ * -+ * Installs @fence into @fd. @fd's should be acquired through get_unused_fd(). -+ */ -+void sync_fence_install(struct sync_fence *fence, int fd); -+ -+/** -+ * sync_fence_wait_async() - registers and async wait on the fence -+ * @fence: fence to wait on -+ * @waiter: waiter callback struck -+ * -+ * Returns 1 if @fence has already signaled. -+ * -+ * Registers a callback to be called when @fence signals or has an error. -+ * @waiter should be initialized with sync_fence_waiter_init(). -+ */ -+int sync_fence_wait_async(struct sync_fence *fence, -+ struct sync_fence_waiter *waiter); -+ -+/** -+ * sync_fence_cancel_async() - cancels an async wait -+ * @fence: fence to wait on -+ * @waiter: waiter callback struck -+ * -+ * returns 0 if waiter was removed from fence's async waiter list. -+ * returns -ENOENT if waiter was not found on fence's async waiter list. -+ * -+ * Cancels a previously registered async wait. Will fail gracefully if -+ * @waiter was never registered or if @fence has already signaled @waiter. -+ */ -+int sync_fence_cancel_async(struct sync_fence *fence, -+ struct sync_fence_waiter *waiter); -+ -+/** -+ * sync_fence_wait() - wait on fence -+ * @fence: fence to wait on -+ * @tiemout: timeout in ms -+ * -+ * Wait for @fence to be signaled or have an error. Waits indefinitely -+ * if @timeout < 0 -+ */ -+int sync_fence_wait(struct sync_fence *fence, long timeout); -+ -+#endif /* __KERNEL__ */ -+ -+/** -+ * struct sync_merge_data - data passed to merge ioctl -+ * @fd2: file descriptor of second fence -+ * @name: name of new fence -+ * @fence: returns the fd of the new fence to userspace -+ */ -+struct sync_merge_data { -+ __s32 fd2; /* fd of second fence */ -+ char name[32]; /* name of new fence */ -+ __s32 fence; /* fd on newly created fence */ -+}; -+ -+/** -+ * struct sync_pt_info - detailed sync_pt information -+ * @len: length of sync_pt_info including any driver_data -+ * @obj_name: name of parent sync_timeline -+ * @driver_name: name of driver implmenting the parent -+ * @status: status of the sync_pt 0:active 1:signaled <0:error -+ * @timestamp_ns: timestamp of status change in nanoseconds -+ * @driver_data: any driver dependant data -+ */ -+struct sync_pt_info { -+ __u32 len; -+ char obj_name[32]; -+ char driver_name[32]; -+ __s32 status; -+ __u64 timestamp_ns; -+ -+ __u8 driver_data[0]; -+}; -+ -+/** -+ * struct sync_fence_info_data - data returned from fence info ioctl -+ * @len: ioctl caller writes the size of the buffer its passing in. -+ * ioctl returns length of sync_fence_data reutnred to userspace -+ * including pt_info. -+ * @name: name of fence -+ * @status: status of fence. 1: signaled 0:active <0:error -+ * @pt_info: a sync_pt_info struct for every sync_pt in the fence -+ */ -+struct sync_fence_info_data { -+ __u32 len; -+ char name[32]; -+ __s32 status; -+ -+ __u8 pt_info[0]; -+}; -+ -+#define SYNC_IOC_MAGIC '>' -+ -+/** -+ * DOC: SYNC_IOC_WAIT - wait for a fence to signal -+ * -+ * pass timeout in milliseconds. Waits indefinitely timeout < 0. -+ */ -+#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32) -+ -+/** -+ * DOC: SYNC_IOC_MERGE - merge two fences -+ * -+ * Takes a struct sync_merge_data. Creates a new fence containing copies of -+ * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the -+ * new fence's fd in sync_merge_data.fence -+ */ -+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data) -+ -+/** -+ * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence -+ * -+ * Takes a struct sync_fence_info_data with extra space allocated for pt_info. -+ * Caller should write the size of the buffer into len. On return, len is -+ * updated to reflect the total size of the sync_fence_info_data including -+ * pt_info. -+ * -+ * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence. -+ * To itterate over the sync_pt_infos, use the sync_pt_info.len field. -+ */ -+#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\ -+ struct sync_fence_info_data) -+ -+#endif /* _LINUX_SYNC_H */ -diff --git a/include/linux/uhid.h b/include/linux/uhid.h -new file mode 100644 -index 00000000..9c6974f1 ---- /dev/null -+++ b/include/linux/uhid.h -@@ -0,0 +1,104 @@ -+#ifndef __UHID_H_ -+#define __UHID_H_ -+ -+/* -+ * User-space I/O driver support for HID subsystem -+ * Copyright (c) 2012 David Herrmann -+ */ -+ -+/* -+ * 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. -+ */ -+ -+/* -+ * Public header for user-space communication. We try to keep every structure -+ * aligned but to be safe we also use __attribute__((__packed__)). Therefore, -+ * the communication should be ABI compatible even between architectures. -+ */ -+ -+#include <linux/input.h> -+#include <linux/types.h> -+ -+enum uhid_event_type { -+ UHID_CREATE, -+ UHID_DESTROY, -+ UHID_START, -+ UHID_STOP, -+ UHID_OPEN, -+ UHID_CLOSE, -+ UHID_OUTPUT, -+ UHID_OUTPUT_EV, -+ UHID_INPUT, -+ UHID_FEATURE, -+ UHID_FEATURE_ANSWER, -+}; -+ -+struct uhid_create_req { -+ __u8 name[128]; -+ __u8 phys[64]; -+ __u8 uniq[64]; -+ __u8 __user *rd_data; -+ __u16 rd_size; -+ -+ __u16 bus; -+ __u32 vendor; -+ __u32 product; -+ __u32 version; -+ __u32 country; -+} __attribute__((__packed__)); -+ -+#define UHID_DATA_MAX 4096 -+ -+enum uhid_report_type { -+ UHID_FEATURE_REPORT, -+ UHID_OUTPUT_REPORT, -+ UHID_INPUT_REPORT, -+}; -+ -+struct uhid_input_req { -+ __u8 data[UHID_DATA_MAX]; -+ __u16 size; -+} __attribute__((__packed__)); -+ -+struct uhid_output_req { -+ __u8 data[UHID_DATA_MAX]; -+ __u16 size; -+ __u8 rtype; -+} __attribute__((__packed__)); -+ -+struct uhid_output_ev_req { -+ __u16 type; -+ __u16 code; -+ __s32 value; -+} __attribute__((__packed__)); -+ -+struct uhid_feature_req { -+ __u32 id; -+ __u8 rnum; -+ __u8 rtype; -+} __attribute__((__packed__)); -+ -+struct uhid_feature_answer_req { -+ __u32 id; -+ __u16 err; -+ __u16 size; -+ __u8 data[UHID_DATA_MAX]; -+}; -+ -+struct uhid_event { -+ __u32 type; -+ -+ union { -+ struct uhid_create_req create; -+ struct uhid_input_req input; -+ struct uhid_output_req output; -+ struct uhid_output_ev_req output_ev; -+ struct uhid_feature_req feature; -+ struct uhid_feature_answer_req feature_answer; -+ } u; -+} __attribute__((__packed__)); -+ -+#endif /* __UHID_H_ */ -diff --git a/include/linux/uid_stat.h b/include/linux/uid_stat.h -new file mode 100644 -index 00000000..6bd6c4e5 ---- /dev/null -+++ b/include/linux/uid_stat.h -@@ -0,0 +1,29 @@ -+/* include/linux/uid_stat.h -+ * -+ * Copyright (C) 2008-2009 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef __uid_stat_h -+#define __uid_stat_h -+ -+/* Contains definitions for resource tracking per uid. */ -+ -+#ifdef CONFIG_UID_STAT -+int uid_stat_tcp_snd(uid_t uid, int size); -+int uid_stat_tcp_rcv(uid_t uid, int size); -+#else -+#define uid_stat_tcp_snd(uid, size) do {} while (0); -+#define uid_stat_tcp_rcv(uid, size) do {} while (0); -+#endif -+ -+#endif /* _LINUX_UID_STAT_H */ -diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h -index 1ad47244..f72d1ad5 100644 ---- a/include/linux/uio_driver.h -+++ b/include/linux/uio_driver.h -@@ -14,6 +14,7 @@ - #ifndef _UIO_DRIVER_H_ - #define _UIO_DRIVER_H_ - -+#include <linux/module.h> - #include <linux/fs.h> - #include <linux/interrupt.h> - -@@ -41,7 +42,7 @@ struct uio_mem { - struct uio_map *map; - }; - --#define MAX_UIO_MAPS 5 -+#define MAX_UIO_MAPS 16 - - struct uio_portio; - -@@ -95,6 +96,7 @@ struct uio_info { - int (*open)(struct uio_info *info, struct inode *inode); - int (*release)(struct uio_info *info, struct inode *inode); - int (*irqcontrol)(struct uio_info *info, s32 irq_on); -+ int (*ioctl)(struct uio_info *info, unsigned int cmd, unsigned long arg); - }; - - extern int __must_check -diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h -index a316fba7..6938a860 100644 ---- a/include/linux/usb/composite.h -+++ b/include/linux/usb/composite.h -@@ -242,6 +242,9 @@ int usb_add_config(struct usb_composite_dev *, - struct usb_configuration *, - int (*)(struct usb_configuration *)); - -+int usb_remove_config(struct usb_composite_dev *, -+ struct usb_configuration *); -+ - /** - * struct usb_composite_driver - groups configurations into a gadget - * @name: For diagnostics, identifies the driver. -diff --git a/include/linux/usb/f_accessory.h b/include/linux/usb/f_accessory.h -new file mode 100644 -index 00000000..61ebe0aa ---- /dev/null -+++ b/include/linux/usb/f_accessory.h -@@ -0,0 +1,146 @@ -+/* -+ * Gadget Function Driver for Android USB accessories -+ * -+ * Copyright (C) 2011 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef __LINUX_USB_F_ACCESSORY_H -+#define __LINUX_USB_F_ACCESSORY_H -+ -+/* Use Google Vendor ID when in accessory mode */ -+#define USB_ACCESSORY_VENDOR_ID 0x18D1 -+ -+ -+/* Product ID to use when in accessory mode */ -+#define USB_ACCESSORY_PRODUCT_ID 0x2D00 -+ -+/* Product ID to use when in accessory mode and adb is enabled */ -+#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01 -+ -+/* Indexes for strings sent by the host via ACCESSORY_SEND_STRING */ -+#define ACCESSORY_STRING_MANUFACTURER 0 -+#define ACCESSORY_STRING_MODEL 1 -+#define ACCESSORY_STRING_DESCRIPTION 2 -+#define ACCESSORY_STRING_VERSION 3 -+#define ACCESSORY_STRING_URI 4 -+#define ACCESSORY_STRING_SERIAL 5 -+ -+/* Control request for retrieving device's protocol version -+ * -+ * requestType: USB_DIR_IN | USB_TYPE_VENDOR -+ * request: ACCESSORY_GET_PROTOCOL -+ * value: 0 -+ * index: 0 -+ * data version number (16 bits little endian) -+ * 1 for original accessory support -+ * 2 adds HID and device to host audio support -+ */ -+#define ACCESSORY_GET_PROTOCOL 51 -+ -+/* Control request for host to send a string to the device -+ * -+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR -+ * request: ACCESSORY_SEND_STRING -+ * value: 0 -+ * index: string ID -+ * data zero terminated UTF8 string -+ * -+ * The device can later retrieve these strings via the -+ * ACCESSORY_GET_STRING_* ioctls -+ */ -+#define ACCESSORY_SEND_STRING 52 -+ -+/* Control request for starting device in accessory mode. -+ * The host sends this after setting all its strings to the device. -+ * -+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR -+ * request: ACCESSORY_START -+ * value: 0 -+ * index: 0 -+ * data none -+ */ -+#define ACCESSORY_START 53 -+ -+/* Control request for registering a HID device. -+ * Upon registering, a unique ID is sent by the accessory in the -+ * value parameter. This ID will be used for future commands for -+ * the device -+ * -+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR -+ * request: ACCESSORY_REGISTER_HID_DEVICE -+ * value: Accessory assigned ID for the HID device -+ * index: total length of the HID report descriptor -+ * data none -+ */ -+#define ACCESSORY_REGISTER_HID 54 -+ -+/* Control request for unregistering a HID device. -+ * -+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR -+ * request: ACCESSORY_REGISTER_HID -+ * value: Accessory assigned ID for the HID device -+ * index: 0 -+ * data none -+ */ -+#define ACCESSORY_UNREGISTER_HID 55 -+ -+/* Control request for sending the HID report descriptor. -+ * If the HID descriptor is longer than the endpoint zero max packet size, -+ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC -+ * commands. The data for the descriptor must be sent sequentially -+ * if multiple packets are needed. -+ * -+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR -+ * request: ACCESSORY_SET_HID_REPORT_DESC -+ * value: Accessory assigned ID for the HID device -+ * index: offset of data in descriptor -+ * (needed when HID descriptor is too big for one packet) -+ * data the HID report descriptor -+ */ -+#define ACCESSORY_SET_HID_REPORT_DESC 56 -+ -+/* Control request for sending HID events. -+ * -+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR -+ * request: ACCESSORY_SEND_HID_EVENT -+ * value: Accessory assigned ID for the HID device -+ * index: 0 -+ * data the HID report for the event -+ */ -+#define ACCESSORY_SEND_HID_EVENT 57 -+ -+/* Control request for setting the audio mode. -+ * -+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR -+ * request: ACCESSORY_SET_AUDIO_MODE -+ * value: 0 - no audio -+ * 1 - device to host, 44100 16-bit stereo PCM -+ * index: 0 -+ * data none -+ */ -+#define ACCESSORY_SET_AUDIO_MODE 58 -+ -+/* ioctls for retrieving strings set by the host */ -+#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256]) -+#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256]) -+#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[256]) -+#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256]) -+#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256]) -+#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256]) -+/* returns 1 if there is a start request pending */ -+#define ACCESSORY_IS_START_REQUESTED _IO('M', 7) -+/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */ -+#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8) -+ -+#endif /* __LINUX_USB_F_ACCESSORY_H */ -diff --git a/include/linux/usb/f_mtp.h b/include/linux/usb/f_mtp.h -new file mode 100644 -index 00000000..72a432e2 ---- /dev/null -+++ b/include/linux/usb/f_mtp.h -@@ -0,0 +1,75 @@ -+/* -+ * Gadget Function Driver for MTP -+ * -+ * Copyright (C) 2010 Google, Inc. -+ * Author: Mike Lockwood <lockwood@android.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef __LINUX_USB_F_MTP_H -+#define __LINUX_USB_F_MTP_H -+ -+#include <linux/ioctl.h> -+ -+#ifdef __KERNEL__ -+ -+struct mtp_data_header { -+ /* length of packet, including this header */ -+ uint32_t length; -+ /* container type (2 for data packet) */ -+ uint16_t type; -+ /* MTP command code */ -+ uint16_t command; -+ /* MTP transaction ID */ -+ uint32_t transaction_id; -+}; -+ -+#endif /* __KERNEL__ */ -+ -+struct mtp_file_range { -+ /* file descriptor for file to transfer */ -+ int fd; -+ /* offset in file for start of transfer */ -+ loff_t offset; -+ /* number of bytes to transfer */ -+ int64_t length; -+ /* MTP command ID for data header, -+ * used only for MTP_SEND_FILE_WITH_HEADER -+ */ -+ uint16_t command; -+ /* MTP transaction ID for data header, -+ * used only for MTP_SEND_FILE_WITH_HEADER -+ */ -+ uint32_t transaction_id; -+}; -+ -+struct mtp_event { -+ /* size of the event */ -+ size_t length; -+ /* event data to send */ -+ void *data; -+}; -+ -+/* Sends the specified file range to the host */ -+#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range) -+/* Receives data from the host and writes it to a file. -+ * The file is created if it does not exist. -+ */ -+#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range) -+/* Sends an event to the host via the interrupt endpoint */ -+#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event) -+/* Sends the specified file range to the host, -+ * with a 12 byte MTP data packet header at the beginning. -+ */ -+#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range) -+ -+#endif /* __LINUX_USB_F_MTP_H */ -diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h -index c9c9a468..38ea5643 100644 ---- a/include/linux/videodev2.h -+++ b/include/linux/videodev2.h -@@ -1191,6 +1191,13 @@ struct v4l2_querymenu { - #define V4L2_CID_MAX_CTRLS 1024 - #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) - #define V4L2_CID_USER_BASE V4L2_CID_BASE -+#define V4L2_CID_SCENE (V4L2_CID_USER_BASE + 0) -+#define V4L2_CID_FOCUS (V4L2_CID_USER_BASE + 1) -+#define V4L2_CID_FLASH (V4L2_CID_USER_BASE + 2) -+#define V4L2_CID_PREVIEW (V4L2_CID_USER_BASE + 3) -+#define V4L2_CID_PICTURE (V4L2_CID_USER_BASE + 4) -+#define V4L2_CID_FRAME (V4L2_CID_USER_BASE + 5) //use to report how many frames are abandoned before ecoding -+#define V4L2_CID_NIGHTMODE (V4L2_CID_USER_BASE + 6) - /* IDs reserved for driver specific controls */ - #define V4L2_CID_PRIVATE_BASE 0x08000000 - -diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h -new file mode 100644 -index 00000000..f4a698a2 ---- /dev/null -+++ b/include/linux/wakelock.h -@@ -0,0 +1,67 @@ -+/* include/linux/wakelock.h -+ * -+ * Copyright (C) 2007-2012 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LINUX_WAKELOCK_H -+#define _LINUX_WAKELOCK_H -+ -+#include <linux/ktime.h> -+#include <linux/device.h> -+ -+/* A wake_lock prevents the system from entering suspend or other low power -+ * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock -+ * prevents a full system suspend. -+ */ -+ -+enum { -+ WAKE_LOCK_SUSPEND, /* Prevent suspend */ -+ WAKE_LOCK_TYPE_COUNT -+}; -+ -+struct wake_lock { -+ struct wakeup_source ws; -+}; -+ -+static inline void wake_lock_init(struct wake_lock *lock, int type, -+ const char *name) -+{ -+ wakeup_source_init(&lock->ws, name); -+} -+ -+static inline void wake_lock_destroy(struct wake_lock *lock) -+{ -+ wakeup_source_trash(&lock->ws); -+} -+ -+static inline void wake_lock(struct wake_lock *lock) -+{ -+ __pm_stay_awake(&lock->ws); -+} -+ -+static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) -+{ -+ __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); -+} -+ -+static inline void wake_unlock(struct wake_lock *lock) -+{ -+ __pm_relax(&lock->ws); -+} -+ -+static inline int wake_lock_active(struct wake_lock *lock) -+{ -+ return lock->ws.active; -+} -+ -+#endif -diff --git a/include/linux/wifi_tiwlan.h b/include/linux/wifi_tiwlan.h -new file mode 100644 -index 00000000..f07e0679 ---- /dev/null -+++ b/include/linux/wifi_tiwlan.h -@@ -0,0 +1,27 @@ -+/* include/linux/wifi_tiwlan.h -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+#ifndef _LINUX_WIFI_TIWLAN_H_ -+#define _LINUX_WIFI_TIWLAN_H_ -+ -+#include <linux/wlan_plat.h> -+ -+#define WMPA_NUMBER_OF_SECTIONS 3 -+#define WMPA_NUMBER_OF_BUFFERS 160 -+#define WMPA_SECTION_HEADER 24 -+#define WMPA_SECTION_SIZE_0 (WMPA_NUMBER_OF_BUFFERS * 64) -+#define WMPA_SECTION_SIZE_1 (WMPA_NUMBER_OF_BUFFERS * 256) -+#define WMPA_SECTION_SIZE_2 (WMPA_NUMBER_OF_BUFFERS * 2048) -+ -+#endif -diff --git a/include/linux/wl127x-rfkill.h b/include/linux/wl127x-rfkill.h -new file mode 100644 -index 00000000..9057ec63 ---- /dev/null -+++ b/include/linux/wl127x-rfkill.h -@@ -0,0 +1,35 @@ -+/* -+ * Bluetooth TI wl127x rfkill power control via GPIO -+ * -+ * Copyright (C) 2009 Motorola, Inc. -+ * Copyright (C) 2008 Texas Instruments -+ * Initial code: Pavan Savoy <pavan.savoy@gmail.com> (wl127x_power.c) -+ * -+ * 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_WL127X_RFKILL_H -+#define _LINUX_WL127X_RFKILL_H -+ -+#include <linux/rfkill.h> -+ -+struct wl127x_rfkill_platform_data { -+ int nshutdown_gpio; -+ -+ struct rfkill *rfkill; /* for driver only */ -+}; -+ -+#endif -diff --git a/include/linux/wlan_plat.h b/include/linux/wlan_plat.h -new file mode 100644 -index 00000000..40ec3482 ---- /dev/null -+++ b/include/linux/wlan_plat.h -@@ -0,0 +1,27 @@ -+/* include/linux/wlan_plat.h -+ * -+ * Copyright (C) 2010 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+#ifndef _LINUX_WLAN_PLAT_H_ -+#define _LINUX_WLAN_PLAT_H_ -+ -+struct wifi_platform_data { -+ int (*set_power)(int val); -+ int (*set_reset)(int val); -+ int (*set_carddetect)(int val); -+ void *(*mem_prealloc)(int section, unsigned long size); -+ int (*get_mac_addr)(unsigned char *buf); -+ void *(*get_country_code)(char *ccode); -+}; -+ -+#endif -diff --git a/include/mach-anyka/Kbuild b/include/mach-anyka/Kbuild -new file mode 100644 -index 00000000..486cf616 ---- /dev/null -+++ b/include/mach-anyka/Kbuild -@@ -0,0 +1,4 @@ -+header-y += fha.h -+header-y += anyka_types.h -+header-y += nand_list.h -+ -diff --git a/include/mach-anyka/aec_interface.h b/include/mach-anyka/aec_interface.h -new file mode 100644 -index 00000000..e5aed96d ---- /dev/null -+++ b/include/mach-anyka/aec_interface.h -@@ -0,0 +1,193 @@ -+ -+/** -+* @file aec_interface.h -+* @brief Anyka AEC Module interfaces header file. -+* -+* This file declare Anyka AEC Module interfaces. -+* Copyright (C) 2011 Anyka (Guangzhou) Microelectronics Technology Co., Ltd. -+* @author Tang Xuechai -+* @date 2013-07-15 -+* @version V1.0.0 -+* @ref -+*/ -+ -+#ifndef _AEC_INTERFACE_H_ -+#define _AEC_INTERFACE_H_ -+ -+#include "anyka_types.h" -+ -+#define AECS_VERSION_STRING (T_U8 *)"EchoS Version V1.0.04_svn95" -+ -+ -+typedef T_pVOID (*AEC_CALLBACK_FUN_MALLOC)(T_U32 size); -+typedef T_VOID (*AEC_CALLBACK_FUN_FREE)(T_pVOID mem); -+typedef T_VOID (*AEC_CALLBACK_FUN_PRINTF)(T_pCSTR format, ...); -+typedef T_VOID (*AEC_CALLBACK_FUN_RTC_DELAY) (T_U32 ulTicks); -+typedef T_VOID (*AEC_CALLBACK_FUN_NOTIFY) (T_U32 event); -+ -+typedef enum -+{ -+ AEC_TYPE_UNKNOWN, -+ AEC_TYPE_1, -+ AEC_TYPE_2 -+}T_AEC_TYPE; -+ -+typedef struct -+{ -+ AEC_CALLBACK_FUN_MALLOC Malloc; -+ AEC_CALLBACK_FUN_FREE Free; -+ AEC_CALLBACK_FUN_PRINTF printf; -+ AEC_CALLBACK_FUN_RTC_DELAY delay; -+ AEC_CALLBACK_FUN_NOTIFY notify; -+}T_AEC_CB_FUNS; -+ -+typedef struct -+{ -+ T_U32 m_Type; //��չ�ã�����AEC�㷨�����T_AEC_TYPE��ö��֮һ -+ T_U32 m_SampleRate; //sample rate, sample per second -+ T_U16 m_Channels; //channel number -+ T_U16 m_BitsPerSample; //bits per sample -+ -+ union -+ { -+ struct -+ { -+ T_U32 m_aecBypass; -+ T_U32 m_framelen; //NN -+ T_U32 m_tail; //TAIL -+ -+ /* ADC���ڲ��� */ -+ /* adc������ֵ�� Ĭ��ֵ�� 512����mic�������ȹ�ϵ�Ƚϴ�*/ -+ T_U32 AdcMinSpeechPow; -+ /* adc�������������Ĺ���ʱ�䣬����(ms)Ϊ��λ��Ĭ��ֵ�� 920�����������������Լ��Ƿ�ɱ���ϡ�*/ -+ T_U32 AdcSpeechHoldTime; -+ /* adc���ڻ�������ϵ����Ĭ���� (T_U32)(1.8*(1<<14))�� -+ ����Խ�����ֵҪԽС����Ȼ���ܻ���Ҫ�ʵ����AdcMinSpeechPow */ -+ T_U32 AdcSpeechMultiple; -+ /* adc�����ı�ʱ������ʱ�䣬����(ms)Ϊ��λ��Ĭ��ֵ�� 5000 */ -+ T_S32 AdcConvergTime; -+ /* adc��ʼһ��ʱ������ݶ������������ö�����ʱ�䳤�ȣ�����(ms)Ϊ��λ��Ĭ��ֵ�� 100 */ -+ T_U32 AdcCutTime; -+ -+ /* DAC���ڲ��� */ -+ /* �Է��ֻ��˴�������������ֵ�� Ĭ��ֵ�� 512 */ -+ T_U32 DacMinSpeechPow; -+ /* �Է��ֻ��˴��������������������������Ĺ���ʱ�䣬����(ms)Ϊ��λ��Ĭ��ֵ�� 920 */ -+ T_U32 DacSpeechHoldTime; -+ /* �Է��ֻ������ڻ�������ϵ����Ĭ����(T_U32)(1.8*(1<<14))�� -+ ����Խ�����ֵҪԽС����Ȼ���ܻ���Ҫ�ʵ����DacMinSpeechPow */ -+ T_U32 DacSpeechMultiple; -+ //�Է��ֻ������ı�ʱ������ʱ�䣬����(ms)Ϊ��λ��Ĭ��ֵ��5000 -+ T_U32 DacConvergTime; -+ -+ //dac��������������ֵ��Ĭ����0 -+ T_U16 DacFadeOutThreshold; -+ //DAC ����������á�����1024ʱ���Ŵ���=1��>1024ʱ���Ŵ���>1; <1024ʱ���Ŵ���<1 -+ T_U16 DacVolume; -+ -+ // for agc -+ T_U8 m_PreprocessEna; -+ T_U16 AGClevel; -+ T_U16 maxGain; // ���Ŵ��� -+ T_U16 minGain; // ��С�Ŵ��� -+ }m_aec; -+ }m_Private; -+}T_AEC_IN_INFO; -+ -+typedef struct -+{ -+ T_AEC_CB_FUNS cb_fun; -+ T_AEC_IN_INFO m_info; -+}T_AEC_INPUT; -+ -+typedef struct -+{ -+ T_VOID *buf_near; //near, mic -+ T_U32 len_near; -+ T_VOID *buf_far; //far, speaker -+ T_U32 len_far; -+ T_VOID *buf_out; // output of aec -+ T_U32 len_out; -+}T_AEC_BUF; -+ -+ -+/** -+* @brief open the AEC's device. -+* @author Tang Xuechai -+* @date 2013-07-15 -+* @param [in] info: input information. Please refer "T_AEC_INPUT" for detail -+* @return T_VOID * -+* @retval the pointer to AEC's memory -+*/ -+T_VOID *AECLib_Open(T_AEC_INPUT *info); -+ -+/** -+* @brief close the AEC's device. -+* @author Tang Xuechai -+* @date 2013-07-15 -+* @param [in] p_aec: the pointer to AEC's memory, get from AECLib_Open -+* @return T_S32 -+* @retval AK_TRUE : close success -+* @retval AK_FLASE : close fail -+*/ -+T_S32 AECLib_Close(T_VOID *p_aec); -+ -+/** -+* @brief process ADC's data. Should be called in ADC's interrupt -+* @author Tang Xuechai -+* @date 2013-07-15 -+* @param [in] p_aec: the pointer to AEC's memory, get from AECLib_Open -+* @param [in] in: ADC's pcm data -+* @param [in] len: ADC's pcm data length -+* @return T_VOID -+*/ -+T_VOID AECLib_DacInt(T_VOID *p_aec, T_U8 *in, T_S32 len); -+ -+/** -+* @brief process DAC's data. Should be called in DAC's interrupt -+* @author Tang Xuechai -+* @date 2013-07-15 -+* @param [in] p_aec: the pointer to AEC's memory, get from AECLib_Open -+* @param [in] in: DAC's pcm data -+* @param [in] len: DAC's pcm data length -+* @return T_VOID -+*/ -+T_VOID AECLib_AdcInt(T_VOID *p_aec, T_U8 *in, T_S32 len); -+ -+/** -+* @brief main process of AEC. Should be called before transmit data to far end -+* @author Tang Xuechai -+* @date 2013-07-15 -+* @param [in] p_aec: the pointer to AEC's memory, get from AECLib_Open -+* @param [in] p_aec_buf: buffer structure for saving output pcm data. -+* @return T_S32 -+* @retval <0: error -+* @retval >=0: output pcm data length (bytes count) -+*/ -+T_S32 AECLib_Control(T_VOID *p_aec, T_AEC_BUF *p_aec_buf); -+ -+/** -+* @brief pre process DAC/ADC data. Should be called while received fardata's packet -+* @author Tang Xuechai -+* @date 2013-08-13 -+* @param [in] p_aec: the pointer to AEC's memory, get from AECLib_Open -+* @param [in] p_aec_buf: buffer structure for saving output pcm data. -+* @return T_S32 -+* @retval <0: error -+* @retval >=0: output pcm data length (bytes count) -+*/ -+T_S32 AECLib_FarPreprocess(T_VOID *p_aec, T_AEC_BUF *p_aec_buf); -+ -+/** -+* @brief set DAC's volume -+* @author Tang Xuechai -+* @date 2013-07-15 -+* @param [in] p_aec: the pointer to AEC's memory, get from AECLib_Open -+* @param [in] volume: the object volume. -+* @return T_S32 -+* @retval AK_TRUE : success -+* @retval AK_FLASE : fail -+*/ -+T_S32 AECLib_SetDaVolume(T_VOID *p_aec, T_U16 volume); -+ -+#endif -\ No newline at end of file -diff --git a/include/mach-anyka/anyka_types.h b/include/mach-anyka/anyka_types.h -new file mode 100644 -index 00000000..e2d3d1fb ---- /dev/null -+++ b/include/mach-anyka/anyka_types.h -@@ -0,0 +1,70 @@ -+/** @file -+ * @brief Define the register operator for system -+ * -+ * Copyright (C) 2006 Anyka (GuangZhou) Software Technology Co., Ltd. -+ * @author -+ * @date 2006-01-16 -+ * @version 1.0 -+ */ -+ -+#ifndef _ANYKA_TYPES_H_ -+#define _ANYKA_TYPES_H_ -+ -+/** @defgroup ANYKA_CPU -+ * @ingroup M3PLATFORM -+ */ -+/*@{*/ -+ -+/* preliminary type definition for global area */ -+typedef unsigned char T_U8; /* unsigned 8 bit integer */ -+typedef unsigned short T_U16; /* unsigned 16 bit integer */ -+typedef unsigned long T_U32; /* unsigned 32 bit integer */ -+typedef signed char T_S8; /* signed 8 bit integer */ -+typedef signed short T_S16; /* signed 16 bit integer */ -+typedef signed long T_S32; /* signed 32 bit integer */ -+typedef void T_VOID; /* void */ -+ -+#define T_U8_MAX ((T_U8)0xff) // maximum T_U8 value -+#define T_U16_MAX ((T_U16)0xffff) // maximum T_U16 value -+#define T_U32_MAX ((T_U32)0xffffffff) // maximum T_U32 value -+#define T_S8_MIN ((T_S8)(-127-1)) // minimum T_S8 value -+#define T_S8_MAX ((T_S8)127) // maximum T_S8 value -+#define T_S16_MIN ((T_S16)(-32767L-1L)) // minimum T_S16 value -+#define T_S16_MAX ((T_S16)(32767L)) // maximum T_S16 value -+#define T_S32_MIN ((T_S32)(-2147483647L-1L)) // minimum T_S32 value -+#define T_S32_MAX ((T_S32)(2147483647L)) // maximum T_S32 value -+ -+/* basal type definition for global area */ -+typedef T_S8 T_CHR; /* char */ -+typedef T_U8 T_BOOL; /* BOOL type */ -+ -+typedef T_VOID * T_pVOID; /* pointer of void data */ -+typedef const T_VOID * T_pCVOID; /* const pointer of void data */ -+ -+typedef T_S8 * T_pSTR; /* pointer of string */ -+typedef const T_S8 * T_pCSTR; /* const pointer of string */ -+ -+ -+typedef T_U16 T_WCHR; /**< unicode char */ -+typedef T_U16 * T_pWSTR; /* pointer of unicode string */ -+typedef const T_U16 * T_pCWSTR; /* const pointer of unicode string */ -+ -+ -+typedef T_U8 * T_pDATA; /* pointer of data */ -+typedef const T_U8 * T_pCDATA; /* const pointer of data */ -+ -+typedef T_U32 T_COLOR; /* color value */ -+ -+typedef T_U32 T_HANDLE; /* a handle */ -+ -+#define AK_FALSE 0 -+#define AK_TRUE 1 -+#undef AK_NULL -+#define AK_NULL ((T_pVOID)(0)) -+ -+#define AK_EMPTY -+/*@}*/ -+ -+ -+#endif // _ANYKA_TYPES_H_ -+ -diff --git a/include/mach-anyka/fha.h b/include/mach-anyka/fha.h -new file mode 100644 -index 00000000..a7667333 ---- /dev/null -+++ b/include/mach-anyka/fha.h -@@ -0,0 +1,387 @@ -+#ifndef _FHA_H_ -+#define _FHA_H_ -+ -+#include "anyka_types.h" -+#include "nand_list.h" -+ -+#define FHA_SUCCESS 1 -+#define FHA_FAIL 0 -+ -+#define VER_NAME_FHA "FHA" -+#define VER_NAME_FS "FS" -+#define VER_NAME_MTD "MTD" -+#define VER_NAME_DRV "DRV" -+#define VER_NAME_MOUNT "MOUNT" -+#define VER_NAME_FSA "FSA" -+ -+typedef enum -+{ -+ FHA_CHIP_880X, //aspen3 -+ FHA_CHIP_10XX, //snowbirds -+ FHA_CHIP_980X, //aspen3s -+ FHA_CHIP_37XX, //Sundance3 -+ FHA_CHIP_11XX, //snowbird2 -+ FHA_CHIP_39XX, //tmp!!!!!! -+}E_FHA_CHIP_TYPE; -+ -+#if defined (CONFIG_ARCH_AK98) -+#define FHA_CHIP_SET_TYPE FHA_CHIP_980X -+#elif defined (CONFIG_ARCH_AK37) -+#define FHA_CHIP_SET_TYPE FHA_CHIP_37XX -+#elif defined (CONFIG_ARCH_AK39) -+#define FHA_CHIP_SET_TYPE FHA_CHIP_39XX -+#endif -+ -+typedef enum -+{ -+ PLAT_SPOT, //spot system -+ PLAT_SPR, //spring system -+ PLAT_SWORD, //sword system -+ PLAT_LINUX //linux system -+}E_FHA_PLATFORM_TYPE; -+ -+typedef enum -+{ -+ MEDIUM_NAND, //nand -+ MEDIUM_SPIFLASH, //spiflash -+ MEDIUM_EMMC, //sd, emmc, inand -+ MEDIUM_SPI_EMMC, //data is stored in spiflash and sd -+ MEDIUM_EMMC_SPIBOOT, //data is stored in sd and boot from spiflash -+}E_FHA_MEDIUM_TYPE; -+ -+typedef enum -+{ -+ MODE_NEWBURN = 1, //new burn -+ MODE_UPDATE, //update mode -+ MODE_UPDATE_SELF, //update mode self -+}E_BURN_MODE; -+ -+typedef enum -+{ -+ FHA_DATA_BOOT, -+ FHA_DATA_ASA, -+ FHA_DATA_BIN, -+ FHA_DATA_FS, -+ FHA_GET_NAND_PARAM -+}E_FHA_DATA_TYPE; -+ -+typedef struct -+{ -+ T_U8 lib_name[10]; -+ T_U8 lib_version[40]; -+}T_LIB_VER_INFO; -+ -+ -+/************************************************************************ -+ * NAME: FHA_Erase -+ * FUNCTION callback function, medium erase -+ * PARAM: [in] nChip--meidum chip -+ * [in] nPage--medium page -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+typedef T_U32 (*FHA_Erase)(T_U32 nChip, T_U32 nPage); -+ -+/************************************************************************ -+ * NAME: FHA_Write -+ * FUNCTION callback function, medium write -+ * PARAM: [in] nChip-----meidum chip -+ * [in] nPage-----medium page -+ * [in] pData-----need to write data pointer addr -+ * [in] nDataLen--need to write data length -+ * nand(unit byte) -+ * SD(unit sector count(1sec = 512byte)) -+ * SPI(unit page count, page size in platform define, generally is 256bytes) -+ * [in] pOob------Spare area��Out Of Band, only nand use -+ * [in] nOobLen---Spare area length -+ * [in] eDataType-burn medium data type -+ * nand -- E_FHA_DATA_TYPE -+ * SD----- MEDIUM_EMMC -+ * SPI---- MEDIUM_SPIFLASH -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+typedef T_U32 (*FHA_Write)(T_U32 nChip, T_U32 nPage, const T_U8 *pData, T_U32 nDataLen, T_U8 *pOob, T_U32 nOobLen, T_U32 eDataType); -+ -+/************************************************************************ -+ * NAME: FHA_Read -+ * FUNCTION callback function, medium read -+ * PARAM: [in] nChip-----meidum chip -+ * [in] nPage-----medium page -+ * [out]pData-----need to read data pointer addr -+ * [in] nDataLen--need to ren data length -+ * nand(unit byte) -+ * SD(unit sector count(1sec = 512byte)) -+ * SPI(unit page count, page size in platform define, generally is 256bytes) -+ * [out]pOob------Spare area��Out Of Band, only nand use -+ * [in] nOobLen---Spare area length -+ * [in] eDataType-burn medium data type -+ * nand -- E_FHA_DATA_TYPE -+ * SD----- MEDIUM_EMMC -+ * SPI---- MEDIUM_SPIFLASH -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+typedef T_U32 (*FHA_Read)(T_U32 nChip, T_U32 nPage, T_U8 *pData, T_U32 nDataLen, T_U8 *pOob, T_U32 nOobLen , T_U32 eDataType); -+ -+/************************************************************************ -+ * NAME: FHA_ReadNandBytes -+ * FUNCTION callback function, nand read no ECC -+ * PARAM: [in] nChip-------meidum chip -+ * [in] rowAddr-----nand physical row addr -+ * [in] columnAddr--nand physical cloumn addr -+ * [out] pData------need to read data pointer addr -+ * [in] nDataLen----need to ren data length -+ * nand(unit byte) -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+typedef T_U32 (*FHA_ReadNandBytes)(T_U32 nChip, T_U32 rowAddr, T_U32 columnAddr, T_U8 *pData, T_U32 nDataLen); -+ -+typedef T_pVOID (*FHA_RamAlloc)(T_U32 size); -+typedef T_pVOID (*FHA_RamFree)(T_pVOID var); -+typedef T_pVOID (*FHA_MemSet)(T_pVOID pBuf, T_S32 value, T_U32 count); -+typedef T_pVOID (*FHA_MemCpy)(T_pVOID dst, T_pCVOID src, T_U32 count); -+typedef T_S32 (*FHA_MemCmp)(T_pCVOID pbuf1, T_pCVOID pbuf2, T_U32 count); -+typedef T_pVOID (*FHA_MemMov)(T_pVOID dst, const T_pCVOID src, T_U32 count); -+typedef T_S32 (*FHA_Printf)(T_pCSTR s, ...); -+ -+typedef struct tag_FHA_LibCallback -+{ -+ FHA_Erase Erase; -+ FHA_Write Write; -+ FHA_Read Read; -+ FHA_ReadNandBytes ReadNandBytes; -+ FHA_RamAlloc RamAlloc; -+ FHA_RamFree RamFree; -+ FHA_MemSet MemSet; -+ FHA_MemCpy MemCpy; -+ FHA_MemCmp MemCmp; -+ FHA_MemMov MemMov; -+ FHA_Printf Printf; -+}T_FHA_LIB_CALLBACK, *T_PFHA_LIB_CALLBACK; -+ -+typedef struct tag_FHA_Init_Info -+{ -+ T_U32 nChipCnt; //Ƭѡ�� -+ T_U32 nBlockStep; //nand block stepֵ -+ E_FHA_CHIP_TYPE eAKChip; //AKоƬ���� -+ E_FHA_PLATFORM_TYPE ePlatform; //ϵͳ���� -+ E_FHA_MEDIUM_TYPE eMedium; //�洢�������� -+ E_BURN_MODE eMode; //��¼ģʽ -+}T_FHA_INIT_INFO, *T_PFHA_INIT_INFO; -+ -+typedef struct tag_FHABinParam -+{ -+ T_U32 data_length; //���ݳ��� -+ T_U32 ld_addr; //���е�ַ -+ T_U8 file_name[16]; //�ļ����� -+ T_BOOL bBackup; //�Ƿ� -+ T_BOOL bCheck; //�Ƿ�У�� -+ T_BOOL bUpdateSelf; //spotlight�������ã����ÿ��BINԤ��ͬ����Ŀռ� -+}T_FHA_BIN_PARAM, *T_PFHA_BIN_PARAM; -+ -+typedef struct -+{ -+ T_U32 BinPageStart; /*bin data start addr*/ -+ T_U32 PageSize; /*spi page size*/ -+ T_U32 PagesPerBlock;/*page per block*/ -+}T_SPI_INIT_INFO, *T_PSPI_INIT_INFO; -+ -+/************************************************************************ -+ * NAME: FHA_burn_init -+ * FUNCTION Initial FHA callback function, init fha init info para -+ * PARAM: [in] pInit----burn platform init struct pointer -+ * [in] pCB------callback function struct pointer -+ * [in] pPhyInfo-input medium struct pointer -+ * NAND-------T_NAND_PHY_INFO* -+ * SPIFLASH---T_PSPI_INIT_INFO -+ * EMMC-------AK_NULL -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_burn_init(T_PFHA_INIT_INFO pInit, T_PFHA_LIB_CALLBACK pCB, T_pVOID pPhyInfo); -+ -+/************************************************************************ -+ * NAME: FHA_set_resv_zone_info -+ * FUNCTION set reserve area -+ * PARAM: [in] nSize--set reserve area size(unit Mbyte) -+ * [in] bErase-if == 1 ,erase reserve area, or else not erase -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_set_resv_zone_info(T_U32 nSize, T_BOOL bErase); -+ -+/************************************************************************ -+ * NAME: FHA_set_bin_resv_size -+ * FUNCTION set write bin reserve size(unit byte) -+ * PARAM: [in] bin_size--reserve bin size -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_set_bin_resv_size(T_U32 bin_size); -+ -+/************************************************************************ -+ * NAME: FHA_write_bin_begin -+ * FUNCTION set write bin start init para -+ * PARAM: [in] bin_param--Bin file info struct -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_write_bin_begin(T_PFHA_BIN_PARAM bin_param); -+ -+/************************************************************************ -+ * NAME: FHA_write_bin -+ * FUNCTION write bin to medium -+ * PARAM: [in] pData-----need to write bin data pointer addr -+ * [in] data_len--need to write bin data length -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_write_bin(const T_U8 * pData, T_U32 data_len); -+ -+/************************************************************************ -+ * NAME: FHA_write_boot_begin -+ * FUNCTION set write boot start init para -+ * PARAM: [in] bin_len--boot length -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_write_boot_begin(T_U32 bin_len); -+ -+/************************************************************************ -+ * NAME: FHA_write_boot -+ * FUNCTION write boot to medium -+ * PARAM: [in] pData-----need to write boot data pointer addr -+ * [in] data_len--need to write boot data length -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_write_boot(const T_U8 *pData, T_U32 data_len); -+ -+/************************************************************************ -+ * NAME: FHA_get_last_pos -+ * FUNCTION get fs start position -+ * PARAM: NULL -+ * RETURN: success return fs start block, fail retuen 0 -+**************************************************************************/ -+T_U32 FHA_get_last_pos(void); -+ -+/************************************************************************ -+ * NAME: FHA_set_fs_part -+ * FUNCTION set fs partition info to medium -+ * PARAM: [in] pInfoBuf-----need to write fs info data pointer addr -+ * [in] data_len--need to write fs info data length -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_set_fs_part(const T_U8 *pInfoBuf, T_U32 buf_len); -+ -+/************************************************************************ -+ * NAME: FHA_close -+ * FUNCTION flush all need to save data to medium, and free all fha malloc ram -+ * PARAM: NULL -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_close(T_VOID); -+ -+/************************************************************************ -+ * NAME: FHA_mount -+ * FUNCTION Initial FHA mount callback function, init fha mount init info para -+ * PARAM: [in] pInit----burn platform init struct pointer -+ * [in] pCB------callback function struct pointer -+ * [in] pPhyInfo-input medium struct pointer -+ * NAND-------T_NAND_PHY_INFO*, linux platform == AK_NULL -+ * SPIFLASH---T_PSPI_INIT_INFO -+ * EMMC-------AK_NULL -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_mount(T_PFHA_INIT_INFO pInit, T_PFHA_LIB_CALLBACK pCB, T_pVOID pPhyInfo); -+ -+/************************************************************************ -+ * NAME: FHA_read_bin_begin -+ * FUNCTION set read bin start init para -+ * PARAM: [in] bin_param--Bin file info struct -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_read_bin_begin(T_PFHA_BIN_PARAM bin_param); -+ -+/************************************************************************ -+ * NAME: FHA_read_bin -+ * FUNCTION read bin to buf from medium -+ * PARAM: [out]pData-----need to read bin data buf pointer addr -+ * [in] data_len--need to read bin data length -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_read_bin(T_U8 *pData, T_U32 data_len); -+ -+/************************************************************************ -+ * NAME: FHA_get_maplist -+ * FUNCTION get block address map of bin. (only nand) -+ * PARAM: [in] file_name---need to get bin's file name -+ * [out]map_data----need to get bin's block map buf pointer addr -+ * [out]file_len----need to get bin's file length -+ * [in] bBackup-----if AK_TRUE == bBackup, get backup block map, or else get origin block map -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_maplist(T_U8 file_name[], T_U16 *map_data, T_U32 *file_len, T_BOOL bBackup); -+ -+/************************************************************************ -+ * NAME: FHA_get_nand_para -+ * FUNCTION get nand para -+ * PARAM: [out] pNandPhyInfo--nand info struct pointer -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_nand_para(T_NAND_PHY_INFO *pNandPhyInfo); -+ -+/************************************************************************ -+ * NAME: FHA_get_fs_part -+ * FUNCTION get fs partition info -+ * PARAM: [out]pInfoBuf---need to get fs info data pointer addr -+ * [in] data_len---need to get fs info data length -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_fs_part(T_U8 *pInfoBuf , T_U32 buf_len); -+ -+/************************************************************************ -+ * NAME: FHA_get_resv_zone_info -+ * FUNCTION get reserve area -+ * PARAM: [out] start_block--get reserve area start block -+ * [out] block_cnt----get reserve area block count -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_resv_zone_info(T_U16 *start_block, T_U16 *block_cnt); -+ -+/************************************************************************ -+ * NAME: FHA_get_bin_num -+ * FUNCTION get bin file number -+ * [out] cnt----bin file count in medium -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_bin_num(T_U32 *cnt); -+ -+/************************************************************************ -+ * NAME: FHA_set_lib_version -+ * FUNCTION set burn all lib version -+ * PARAM: [in] lib_info--all lib version struct pointer addr -+ * [in] lib_cnt---lib count -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_set_lib_version(T_LIB_VER_INFO *lib_info, T_U32 lib_cnt); -+ -+/************************************************************************ -+ * NAME: FHA_get_lib_verison -+ * FUNCTION get burn lib version by input lib_info->lib_name -+ * PARAM: [in-out] lib_info--input lib_info->lib_name, output lib_info->lib_version -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_lib_verison(T_LIB_VER_INFO *lib_info); -+ -+/************************************************************************ -+ * NAME: FHA_get_version -+ * FUNCTION get fha version -+ * PARAM: NULL -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U8 *FHA_get_version(void); -+ -+/************************************************************************ -+ * NAME: FHA_check_lib_version -+ * FUNCTION check burn lib version -+ * PARAM: [in] lib_info lib name and verison -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_check_lib_version(T_LIB_VER_INFO *lib_info); -+ -+ -+#endif //_FHA_BINBURN_H_ -+ -+ -diff --git a/include/mach-anyka/fha_asa.h b/include/mach-anyka/fha_asa.h -new file mode 100644 -index 00000000..5a30deaa ---- /dev/null -+++ b/include/mach-anyka/fha_asa.h -@@ -0,0 +1,81 @@ -+#ifndef _FHA_ASA_H_ -+#define _FHA_ASA_H_ -+ -+#define ASA_FILE_FAIL 0 -+#define ASA_FILE_SUCCESS 1 -+#define ASA_FILE_EXIST 2 -+#define ASA_MODE_OPEN 0 -+#define ASA_MODE_CREATE 1 -+ -+#define ASA_FORMAT_NORMAL 0 -+#define ASA_FORMAT_EWR 1 -+#define ASA_FORMAT_RESTORE 2 -+ -+/************************************************************************ -+ * NAME: FHA_asa_scan -+ * FUNCTION scan nand flash security area -+ * PARAM: [in] bMount -- if buffer is enough, set AK_TURE, scan speedup -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_asa_scan(T_BOOL bMount); -+ -+/************************************************************************ -+ * NAME: FHA_asa_format -+ * FUNCTION nand flash format security area -+ * PARAM: [in] type -- ASA_FORMAT_NORMAL: only scan initial bad blocks -+ * ASA_FORMAT_EWR: Erase-wirte-read test -+ * ASA_FORMAT_RESTORE: do nothing -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_asa_format(T_U32 type); -+ -+/************************************************************************ -+ * NAME: FHA_set_bad_block -+ * FUNCTION set nand flash bad block -+ * PARAM: [in] block -- the bad block item -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_set_bad_block(T_U32 block); -+ -+/************************************************************************ -+ * NAME: FHA_check_bad_block -+ * FUNCTION check nand flash bad block -+ * PARAM: [in] block -- need to check block item -+ * RETURN: is bad block return FHA_SUCCESS, or else retuen FHA_ FAIL -+**************************************************************************/ -+T_BOOL FHA_check_bad_block(T_U32 block); -+ -+/************************************************************************ -+ * NAME: FHA_get_bad_block -+ * FUNCTION get bad block information of one or more blocks -+ * PARAM: [in] start_block -- start block -+ * [out]pData -------- buffer used to store bad blocks information data -+ * [in] blk_cnt ------ how many blocks you want to know -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_bad_block(T_U32 start_block, T_U8 *pData, T_U32 blk_cnt); -+ -+/************************************************************************ -+ * NAME: FHA_asa_write_file -+ * FUNCTION write important infomation to security area, data_len can't too large -+ * PARAM: [in] file_name -- asa file name -+ * [in] pData ------ buffer used to store information data -+ * [in] data_len --- need to store data length -+ * [in] mode-------- operation mode -+ * ASA_MODE_OPEN------open -+ * ASA_MODE_CREATE----create -+ * RETURN: success return ASA_FILE_SUCCESS, fail retuen ASA_FILE_FAIL -+**************************************************************************/ -+T_U32 FHA_asa_write_file(T_U8 file_name[], const T_U8 *pData, T_U32 data_len, T_U8 mode); -+ -+/************************************************************************ -+ * NAME: FHA_asa_read_file -+ * FUNCTION get infomation from security area by input file name -+ * PARAM: [in] file_name -- asa file name -+ * [out]pData ------ buffer used to store information data -+ * [in] data_len --- need to get data length -+ * RETURN: success return ASA_FILE_SUCCESS, fail retuen ASA_FILE_FAIL -+**************************************************************************/ -+T_U32 FHA_asa_read_file(T_U8 file_name[], T_U8 *pData, T_U32 data_len); -+#endif // -+ -diff --git a/include/mach-anyka/mac.h b/include/mach-anyka/mac.h -new file mode 100755 -index 00000000..e5c585c7 ---- /dev/null -+++ b/include/mach-anyka/mac.h -@@ -0,0 +1,20 @@ -+#ifndef __AK_MAC_H -+#define __AK_MAC_H -+ -+/* platfrom data for platfrom device structure's platfrom_data field */ -+ -+#define MAC_ADDR_LEN 6 -+#define MAC_ADDR_STRING_LEN (MAC_ADDR_LEN * 3 - 1) -+ -+ -+struct ak_mac_data { -+ unsigned int flags; -+ unsigned char dev_addr[MAC_ADDR_LEN]; -+ void (* gpio_init) (const struct gpio_info *); -+ struct gpio_info pwr_gpio; // power up -+ struct gpio_info phy_rst_gpio; // PHY RESET gpio -+}; -+ -+ -+#endif /* __AK_MAC_H */ -+ -diff --git a/include/mach-anyka/nand_list.h b/include/mach-anyka/nand_list.h -new file mode 100644 -index 00000000..6f2f609d ---- /dev/null -+++ b/include/mach-anyka/nand_list.h -@@ -0,0 +1,85 @@ -+/** -+ * @filename nand_list.h -+ * @brief: AK3223M interrupt -+ * -+ * This file describe what is in the table of nand list -+ * Copyright (C) 2006 Anyka (GuangZhou) Software Technology Co., Ltd. -+ * @author zhaojiahuan -+ * @modify chenyanyan -+ * @date 2007-1-10 -+ * @version 1.0 -+ * @ref -+ */ -+ -+#ifndef __CHIP_NFC_3224__ -+#define __CHIP_NFC_3224__ -+ -+#include "anyka_types.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** @defgroup NandFlash Architecture NandFlash Interface -+ * @ingroup Architecture -+ */ -+/*@{*/ -+ -+/** -+* @BRIEF Nandflash info define -+* @AUTHOR zhaojiahuan -+* @DATE 2006-7-17 -+*/ -+ -+typedef struct -+Nand_phy_info{ -+ T_U32 chip_id;//chip id -+ T_U16 page_size; //page size -+ T_U16 page_per_blk; //page of one blok -+ T_U16 blk_num;//total block number -+ T_U16 group_blk_num;//the same concept as die, according to nand's struture -+ T_U16 plane_blk_num; -+ T_U8 spare_size;//spare�����С�ĵ�λ��������255 Byte -+ T_U8 col_cycle;//column address cycle -+ T_U8 lst_col_mask;//last column addrress cycle mask bit -+ T_U8 row_cycle;//row address cycle -+ T_U8 delay_cnt;//Rb delay, unit is 1024 asic clock, default value corresponds to 84MHz -+ T_U8 custom_nd;//nand type flag, used to detect the original invilid block -+ //currently there are 7 types, more types might be added when new nand come out -+ //˵����������ǰһ����page��,��һ����page�е�λ��, �����Щλ�ò�Ϊ0xFF���block�dz������� -+ //NAND_TYPE_SAMSUNG: 0x1 СҳSLC([0,1],[517]), ��ҳSLC([0,1],[2048]), MLC([127], [2048/4096]) -+ //NAND_TYPE_HYNIX: 0x2 СҳSLC([0,1],[517]), ��ҳSLC([0,1],[2048]), MLC([125,127], [2048/4096]) -+ //NAND_TYPE_TOSHIBA: 0x3 СҳSLC([0,1],[0,512]), ��ҳSLC([0,1],[0,2048]), MLC([127], [0,2048/4096]) -+ //NAND_TYPE_TOSHIBA_EXT: 0x4 СҳSLC(), ��ҳSLC(), MLC([0,127/255], [0,2048/4096/8192]) -+ //NAND_TYPE_MICRON: 0x5 СҳSLC([0,1],[512]), ��ҳSLC([0,1],[2048]), MLC([0,1], [2048/4096]) -+ //NAND_TYPE_ST: 0x6 СҳSLC([0,1],[517]), ��ҳSLC([0],[2048,2053]), MLC([127], [0]) -+ //NAND_TYPE_MICRON_4K 0x7 СҳSLC(), ��ҳSLC(), MLC([0], [4096 ~ 4096+218]) -+ T_U32 flag;//character bits, ���4λ��ʾplane���ԣ����λ��ʾ�Ƿ���Ҫblock��˳��дpage -+ //bit31��ʾ�Ƿ���copyback��1��ʾ��copyback -+ //bit30��ʾ�Ƿ�ֻ��һ��plane��1��ʾֻ��һ��plane -+ //bit29��ʾ�Ƿ�ǰ��plane��1��ʾ��ǰ��plane -+ //bit28��ʾ�Ƿ���żplane��1��ʾ����żplane -+ -+ //����bit��Ϊ�˽��page��block��ַ�����������ӵĿ���bit: -+ //bit11��ʾblock number per die�Ƿ���Ҫ���Ϲ�������Toshiba TH58NVG6D2ETA20��2048 block/die(ʵ����2084 block/die) -+ //Ϊ�˶�����һ��die��block����Ҫ����Ϊ4096 block/die���ײ����� -+ //bit10��ʾpage number�Ƿ���Ҫ���Ϲ�������TLC��192page/block��Ϊ�˶�����һ��block����Ҫ����Ϊ256page/block������ -+ -+ //bit8~9��ʾspare�����С�ĸ�λ����λ��256 Bytes����spare_size��ΪT_U8�������Ա�ʾ����nand��400����ֽڵ�spare��С -+ //bit4-7��ʾECC���ͣ�0Ϊ4 bit/512B��1Ϊ8 bit/512B��2Ϊ12 bit/512B��3Ϊ16 bit/512B��4Ϊ24 bit/1024B��5Ϊ32 bit/1024B -+ //bit0��ʾ��ͬһ��block���Ƿ���Ҫ˳��дpage��1��ʾ��Ҫ��˳��д������nandΪMLC -+ //ע��: ���(bit29��bit28)Ϊ'11'�����ʾ��chip����4��plane��������żҲ��ǰ��plane -+ -+ T_U32 cmd_len;//nandflash command length -+ T_U32 data_len;//nandflash data length -+ T_U8 des_str[32];//descriptor string -+}T_NAND_PHY_INFO; -+ -+#define ERROR_CHIP_ID 0xFFFFFFFF -+ -+/*@}*/ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/include/net/activity_stats.h b/include/net/activity_stats.h -new file mode 100644 -index 00000000..10e4c150 ---- /dev/null -+++ b/include/net/activity_stats.h -@@ -0,0 +1,25 @@ -+/* -+ * Copyright (C) 2010 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ * Author: Mike Chan (mike@android.com) -+ */ -+ -+#ifndef __activity_stats_h -+#define __activity_stats_h -+ -+#ifdef CONFIG_NET_ACTIVITY_STATS -+void activity_stats_update(void); -+#else -+#define activity_stats_update(void) {} -+#endif -+ -+#endif /* _NET_ACTIVITY_STATS_H */ -diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h -index d47e523c..78132a8a 100644 ---- a/include/net/bluetooth/hci.h -+++ b/include/net/bluetooth/hci.h -@@ -174,8 +174,10 @@ enum { - #define ESCO_2EV5 0x0100 - #define ESCO_3EV5 0x0200 - --#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) --#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) -+#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) -+#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) -+#define ALL_ESCO_MASK (SCO_ESCO_MASK | ESCO_EV3 | ESCO_EV4 | ESCO_EV5 | \ -+ EDR_ESCO_MASK) - - /* ACL flags */ - #define ACL_START_NO_FLUSH 0x00 -@@ -1392,6 +1394,9 @@ struct hci_conn_info { - __u8 out; - __u16 state; - __u32 link_mode; -+ __u32 mtu; -+ __u32 cnt; -+ __u32 pkts; - }; - - struct hci_dev_req { -diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h -index db1c5df4..392b2cab 100644 ---- a/include/net/bluetooth/hci_core.h -+++ b/include/net/bluetooth/hci_core.h -@@ -561,7 +561,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle); - void hci_setup_sync(struct hci_conn *conn, __u16 handle); - void hci_sco_setup(struct hci_conn *conn, __u8 status); - --struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); -+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, -+ __u16 pkt_type, bdaddr_t *dst); - int hci_conn_del(struct hci_conn *conn); - void hci_conn_hash_flush(struct hci_dev *hdev); - void hci_conn_check_pending(struct hci_dev *hdev); -@@ -570,8 +571,9 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn); - int hci_chan_del(struct hci_chan *chan); - void hci_chan_list_flush(struct hci_conn *conn); - --struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, -- __u8 sec_level, __u8 auth_type); -+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, -+ __u16 pkt_type, bdaddr_t *dst, -+ __u8 sec_level, __u8 auth_type); - int hci_conn_check_link_mode(struct hci_conn *conn); - int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); - int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); -@@ -598,7 +600,7 @@ static inline void hci_conn_put(struct hci_conn *conn) - if (conn->state == BT_CONNECTED) { - timeo = msecs_to_jiffies(conn->disc_timeout); - if (!conn->out) -- timeo *= 2; -+ timeo *= 20; - } else { - timeo = msecs_to_jiffies(10); - } -diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h -index 1e35c436..6d1857ab 100644 ---- a/include/net/bluetooth/sco.h -+++ b/include/net/bluetooth/sco.h -@@ -37,6 +37,7 @@ - struct sockaddr_sco { - sa_family_t sco_family; - bdaddr_t sco_bdaddr; -+ __u16 sco_pkt_type; - }; - - /* SCO socket options */ -@@ -72,7 +73,8 @@ struct sco_conn { - - struct sco_pinfo { - struct bt_sock bt; -- __u32 flags; -+ __u16 pkt_type; -+ - struct sco_conn *conn; - }; - -diff --git a/include/net/tcp.h b/include/net/tcp.h -index 2757a115..ed5b0c70 100644 ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1456,6 +1456,8 @@ extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head, - extern int tcp_gro_complete(struct sk_buff *skb); - extern int tcp4_gro_complete(struct sk_buff *skb); - -+extern int tcp_nuke_addr(struct net *net, struct sockaddr *addr); -+ - #ifdef CONFIG_PROC_FS - extern int tcp4_proc_init(void); - extern void tcp4_proc_exit(void); -diff --git a/include/plat-anyka/adkey.h b/include/plat-anyka/adkey.h -new file mode 100755 -index 00000000..0e98c1a9 ---- /dev/null -+++ b/include/plat-anyka/adkey.h -@@ -0,0 +1,78 @@ -+/* -+ * include/plat-anyka/adkey.h -+ */ -+ -+#ifndef __ADKEY_H -+#define __ADKEY_H -+ -+#include <mach/gpio.h> -+#include "notify.h" -+ -+typedef enum { -+ PLUGIN_NODEV = 0x0, -+ PLUGIN_DEV1 = 0x1, //dev1 -+ PLUGIN_DEV2 = 0x2, //dev2 -+ PLUGIN_DEV3 = 0x4, //dev3 -+ PLUGIN_DEV4 = 0x8, //dev4 -+ PLUGIN_DEV12 = PLUGIN_DEV1|PLUGIN_DEV2, //dev12 -+ PLUGIN_DEV13 = PLUGIN_DEV1|PLUGIN_DEV3, //dev13 -+ PLUGIN_DEV23 = PLUGIN_DEV2|PLUGIN_DEV3, //dev23 -+ PLUGIN_DEV123 = PLUGIN_DEV1|PLUGIN_DEV2|PLUGIN_DEV3, //dev123 -+ -+ PLUGIN_INVALID, -+} T_ad_check; -+ -+ -+#define PLUGIN_MMC PLUGIN_DEV1 //sd card -+#define PLUGIN_SDIO PLUGIN_DEV2 //sdio dev -+#define PLUGIN_AC PLUGIN_DEV3 //ac -+#define PLUGIN_MMC_SDIO PLUGIN_DEV12 //mmc+ac -+#define PLUGIN_MMC_AC PLUGIN_DEV13 //hp+mmc -+#define PLUGIN_SDIO_AC PLUGIN_DEV23 //sdio+ac -+#define PLUGIN_MMC_SDIO_AC PLUGIN_DEV123 //mmc+sdio+ac -+ -+#define ADDETECT_MMC_PLUGIN ADDEDECT_DEV1_PLUGIN -+#define ADDETECT_MMC_PLUGOUT ADDEDECT_DEV1_PLUGOUT -+#define ADDETECT_SDIO_PLUGIN ADDEDECT_DEV2_PLUGIN -+#define ADDETECT_SDIO_PLUGOUT ADDEDECT_DEV2_PLUGOUT -+#define ADDETECT_AC_PLUGIN ADDEDECT_DEV3_PLUGIN -+#define ADDETECT_AC_PLUGOUT ADDEDECT_DEV3_PLUGOUT -+ -+struct adgpio_key { -+ int code; /* Key code */ -+ int min; /* min voltage */ -+ int max; /* max voltage */ -+}; -+ -+struct multi_addetect { -+ int unpress_min; -+ int unpress_max; -+ struct adgpio_key *fixkeys; -+ T_ad_check plugdev; -+}; -+ -+struct analog_gpio_key { -+ char *desc; /* key description */ -+ int interval; /* the value is poll adkey */ -+ int debounce_interval; /* press key delay */ -+ -+ struct multi_addetect *addet; -+ int naddet; -+ int nkey; /* key number */ -+ -+ int chanel; /* AD channel */ -+ int wakeup; /* enable ad-key wakeup from standby */ -+}; -+ -+#if defined(CONFIG_ARCH_AK39) -+static inline void adkey_wakeup_enable(int en) -+{ -+} -+#else -+static inline void adkey_wakeup_enable(int en) -+{ -+} -+#endif -+ -+#endif /* end __ADKEY_H */ -+ -diff --git a/include/plat-anyka/ak_camera.h b/include/plat-anyka/ak_camera.h -new file mode 100755 -index 00000000..cca9f0ce ---- /dev/null -+++ b/include/plat-anyka/ak_camera.h -@@ -0,0 +1,119 @@ -+/* -+ * ak_camera.h - AK camera driver header file -+ * -+ * Copyright (c) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt> -+ * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com> -+ * -+ * Based on PXA camera.h file: -+ * Copyright (C) 2003, Intel Corporation -+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_ARCH_CAMERA_H_ -+#define __ASM_ARCH_CAMERA_H_ -+ -+#include <mach/map.h> -+ -+#define AK_CAM_DRV_NAME "ak_camera" -+#define MAX_VIDEO_MEM 16 -+ -+#if 0 -+#define CSI_BUS_FLAGS (SOCAM_MASTER | SOCAM_HSYNC_ACTIVE_HIGH | \ -+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | \ -+ SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ -+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW | \ -+ SOCAM_DATAWIDTH_8) -+#endif -+ -+#define CSI_BUS_FLAGS (V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ -+ V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ -+ V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ -+ V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW) -+ -+#define AK_CAMERA_MASTER 1 -+#define AK_CAMERA_DATAWIDTH_4 2 -+#define AK_CAMERA_DATAWIDTH_5 4 -+#define AK_CAMERA_DATAWIDTH_8 8 -+#define AK_CAMERA_DATAWIDTH_9 0x10 -+#define AK_CAMERA_DATAWIDTH_10 0x20 -+ -+#define AK_CAMERA_VSYNC_HIGH 0x100 -+#define AK_CAMERA_PCLK_RISING 0x200 -+#define AK_CAMERA_DATA_HIGH 0x400 -+ -+/* Image Sensor Command Register */ -+#define CICR_DATA_FMT (0x3 << 0) -+#define CICR_HSCAL_EN (1 << 2) -+#define CICR_VSCAL_EN (1 << 3) -+#define CICR_MODE (1 << 4) -+#define CICR_FULL_RANGE_YUV (1 << 5) -+#define CICR_DATA_FMT_VAL(x) (((x) << 0) & CICR_DATA_FMT) -+ -+ -+/* Personal */ -+ -+ -+/** @{@name IMAGE sensor module register and bit map define -+ */ -+/* image capturing command */ -+#define IMG_CMD 0x0000 -+/* Source/Destination image horizontal length */ -+#define IMG_HINFO1 0x0004 -+/* Horizontal scalling information */ -+#define IMG_HINFO2 0x0008 -+/* Source/Destination image vertical length */ -+#define IMG_VINFO1 0x000C -+/* Horizontal scalling information */ -+#define IMG_VINFO2 0x0010 -+ -+/* DMA starting address of external RAM for Y component of odd frame */ -+#define IMG_YODD 0x0018 -+#define IMG_UODD 0x001c -+#define IMG_VODD 0x0020 -+#define IMG_RGBODD 0x0024 -+#define IMG_YEVE 0x0028 -+#define IMG_UEVE 0x002c -+#define IMG_VEVE 0x0030 -+#define IMG_RGBEVE 0x0034 -+/* Image sensor configuration */ -+#define IMG_CONFIG 0x0040 -+/* Status of the current frame */ -+#define IMG_STATUS 0x0060 -+/* The line number of a frame when JPEG-compressed format */ -+#define IMG_NUM 0x0080 -+/** @} */ -+ -+ -+/** @{@name IMAGE sensor module register and bit map define -+ */ -+/* Multiple function control register */ -+#define MUL_FUN_CTL_REG (AK_VA_SYSCTRL + 0x0058) -+/* Multiple function control register2 */ -+#define MUL_FUN_CTL_REG2 (AK_VA_SYSCTRL + 0x0014) -+/** @} */ -+#define MUL_RESET_CTRL_REG (AK_VA_SYSCTRL + 0x0010) -+ -+struct captureSync{ -+ unsigned long long adcCapture_bytes; -+ struct timeval tv; -+ unsigned int rate; -+ unsigned int frame_bits; -+}; -+ -+ -+/** -+ * struct ak_camera_pdata - AK camera platform data -+ * @mclk: master clock frequency in MHz units -+ * @flags: AK camera platform flags -+ */ -+struct ak_camera_pdata { -+ unsigned long mclk; -+ unsigned long flags; -+}; -+ -+#endif /* __ASM_ARCH_CAMERA_H_ */ -+ -diff --git a/include/plat-anyka/ak_motor.h b/include/plat-anyka/ak_motor.h -new file mode 100644 -index 00000000..b8df1643 ---- /dev/null -+++ b/include/plat-anyka/ak_motor.h -@@ -0,0 +1,55 @@ -+#ifndef __AK_MOTOR_H__ -+#define __AK_MOTOR_H__ -+ -+#ifdef __KERNEL__ -+enum ak_motor_phase { -+ AK_MOTOR_PHASE_A = 0, -+ AK_MOTOR_PHASE_B, -+ AK_MOTOR_PHASE_C, -+ AK_MOTOR_PHASE_D, -+ AK_MOTOR_PHASE_NUM, -+}; -+ -+enum ak_motor_hit { -+ AK_MOTOR_HIT_LEFT = 0, -+ AK_MOTOR_HIT_RIGHT, -+ AK_MOTOR_HIT_NUM, -+}; -+ -+ -+struct ak_motor_plat_data -+{ -+ struct gpio_info gpio_phase[AK_MOTOR_PHASE_NUM]; -+ struct gpio_info gpio_hit[AK_MOTOR_HIT_NUM]; -+ unsigned int irq_hit_type[AK_MOTOR_HIT_NUM]; -+ void (* gpio_init) (const struct gpio_info *); -+ -+ unsigned int angular_speed; -+}; -+#endif -+ -+#define AK_MOTOR_IOC_MAGIC 'm' -+#define AK_MOTOR_SET_ANG_SPEED _IOW(AK_MOTOR_IOC_MAGIC, 11, int) -+#define AK_MOTOR_GET_ANG_SPEED _IOR(AK_MOTOR_IOC_MAGIC, 12, int) -+#define AK_MOTOR_TURN_CLKWISE _IOW(AK_MOTOR_IOC_MAGIC, 13, int) -+#define AK_MOTOR_TURN_ANTICLKWISE _IOW(AK_MOTOR_IOC_MAGIC, 14, int) -+#define AK_MOTOR_GET_HIT_STATUS _IOW(AK_MOTOR_IOC_MAGIC, 15, int) -+#define AK_MOTOR_TURN_STOP _IOW(AK_MOTOR_IOC_MAGIC, 16, int) -+ -+#define AK_MOTOR_EVENT_HIT (1) -+#define AK_MOTOR_EVENT_UNHIT (2) -+#define AK_MOTOR_EVENT_STOP (3) -+ -+#define AK_MOTOR_HITTING_LEFT (1<<0) -+#define AK_MOTOR_HITTING_RIGHT (1<<1) -+ -+#define AK_MOTOR_MIN_SPEED (1) -+#define AK_MOTOR_MAX_SPEED (16) -+struct notify_data -+{ -+ int hit_num; -+ int event; -+ int remain_angle; -+}; -+ -+#endif -diff --git a/include/plat-anyka/akgpios.h b/include/plat-anyka/akgpios.h -new file mode 100755 -index 00000000..ab08cd83 ---- /dev/null -+++ b/include/plat-anyka/akgpios.h -@@ -0,0 +1,40 @@ -+#ifndef __AKAPPLY_GPIO_H -+#define __AKAPPLY_GPIO_H -+ -+ -+#define APPLY_IOC_MAGIC 'f' -+ -+/* -+ Command definitions which are supported by this dirver -+*/ -+#define GET_GPIO_NUM _IOR(APPLY_IOC_MAGIC, 40, __u8) -+#define GET_AVAILABLE_GPIO _IOR(APPLY_IOC_MAGIC, 41, __u8) -+#define SET_GPIO_FUNC _IOW(APPLY_IOC_MAGIC, 42, __u8) -+#define GET_GPIO_VALUE _IOWR(APPLY_IOC_MAGIC, 43, __u8) -+#define SET_GPIO_IRQ _IOW(APPLY_IOC_MAGIC, 44, __u8) -+#define LISTEN_GPIO_IRQ _IOW(APPLY_IOC_MAGIC, 45, __u8) -+#define DELETE_GPIO_IRQ _IOW(APPLY_IOC_MAGIC, 46, __u8) -+#define SET_GPIO_LEVEL _IOW(APPLY_IOC_MAGIC, 47, __u8) -+#define SET_GROUP_GPIO_LEVEL _IOW(APPLY_IOC_MAGIC, 48, __u8) -+ -+ -+#ifdef __KERNEL__ -+ -+struct custom_gpio_data { -+ unsigned int *gpiopin; -+ unsigned int ngpiopin; -+}; -+ -+struct gpio_ginfo { -+ int pin; -+ int value; -+}; -+ -+struct gpio_group_info { -+ struct gpio_ginfo *gpio; -+ int gpio_num; -+}; -+ -+#endif /* end __KERNEL__ */ -+ -+#endif /* end AKAPPLY_GPIO_H */ -diff --git a/include/plat-anyka/akmci.h b/include/plat-anyka/akmci.h -new file mode 100644 -index 00000000..a35ebea5 ---- /dev/null -+++ b/include/plat-anyka/akmci.h -@@ -0,0 +1,225 @@ -+/* -+ * include/plat-anyka/akmci.h - Anyka MMC/SD driver -+ * -+ * Copyright (C) 2010 Anyka, Ltd, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef __AK_MCI_H__ -+#define __AK_MCI_H__ -+ -+#define MCI_CLK_REG 0x004 -+#define MMC_CLK_DIVL(x) ((x) & 0xff) -+#define MMC_CLK_DIVH(x) (((x) & 0xff) << 8) -+#define MCI_CLK_ENABLE (1 << 16) -+#define MCI_CLK_PWRSAVE (1 << 17) -+#define MCI_FAIL_TRIGGER (1 << 19) -+#define MCI_ENABLE (1 << 20) -+ -+#define MCI_ARGUMENT_REG 0x008 -+#define MCI_COMMAND_REG 0x00c -+#define MCI_CPSM_ENABLE (1 << 0) -+#define MCI_CPSM_CMD(x) (((x) & 0x3f) << 1) -+#define MCI_CPSM_RESPONSE (1 << 7) -+#define MCI_CPSM_LONGRSP (1 << 8) -+#define MCI_CPSM_PENDING (1 << 9) -+#define MCI_CPSM_RSPCRC_NOCHK (1 << 10) -+#define MCI_CPSM_WITHDATA (1 << 11) -+ -+#define MCI_RESPCMD_REG 0x010 -+#define MCI_RESPONSE0_REG 0x014 -+#define MCI_RESPONSE1_REG 0x018 -+#define MCI_RESPONSE2_REG 0x01c -+#define MCI_RESPONSE3_REG 0x020 -+#define MCI_DATATIMER_REG 0x024 -+#define MCI_DATALENGTH_REG 0x028 -+#define MCI_DATACTRL_REG 0x02c -+#define MCI_DPSM_ENABLE (1 << 0) -+#define MCI_DPSM_DIRECTION (1 << 1) -+#define MCI_DPSM_STREAM (1 << 2) -+#define MCI_DPSM_BUSMODE(x) (((x) & 0x3) << 3) -+#define MCI_DPSM_BLOCKSIZE(x) (((x) & 0xfff) << 16) -+ -+#define MCI_DATACNT_REG 0x030 -+#define MCI_STATUS_REG 0x034 -+#define MCI_RESPCRCFAIL (1 << 0) -+#define MCI_DATACRCFAIL (1 << 1) -+#define MCI_RESPTIMEOUT (1 << 2) -+#define MCI_DATATIMEOUT (1 << 3) -+#define MCI_RESPEND (1 << 4) -+#define MCI_CMDSENT (1 << 5) -+#define MCI_DATAEND (1 << 6) -+#define MCI_DATABLOCKEND (1 << 7) -+#define MCI_STARTBIT_ERR (1 << 8) -+#define MCI_CMDACTIVE (1 << 9) -+#define MCI_TXACTIVE (1 << 10) -+#define MCI_RXACTIVE (1 << 11) -+#define MCI_FIFOFULL (1 << 12) -+#define MCI_FIFOEMPTY (1 << 13) -+#define MCI_FIFOHALFFULL (1 << 14) -+#define MCI_FIFOHALFEMPTY (1 << 15) -+#define MCI_DATATRANS_FINISH (1 << 16) -+#define MCI_SDIOINT (1 << 17) -+ -+#define MCI_MASK_REG 0x038 -+#define MCI_RESPCRCFAILMASK (1 << 0) -+#define MCI_DATACRCFAILMASK (1 << 1) -+#define MCI_RESPTIMEOUTMASK (1 << 2) -+#define MCI_DATATIMEOUTMASK (1 << 3) -+#define MCI_RESPENDMASK (1 << 4) -+#define MCI_CMDSENTMASK (1 << 5) -+#define MCI_DATAENDMASK (1 << 6) -+#define MCI_DATABLOCKENDMASK (1 << 7) -+#define MCI_STARTBIT_ERRMASK (1 << 8) -+#define MCI_CMDACTIVEMASK (1 << 9) -+#define MCI_TXACTIVEMASK (1 << 10) -+#define MCI_RXACTIVEMASK (1 << 11) -+#define MCI_FIFOFULLMASK (1 << 12) -+#define MCI_FIFOEMPTYMASK (1 << 13) -+#define MCI_FIFOHALFFULLMASK (1 << 14) -+#define MCI_FIFOHALFEMPTYMASK (1 << 15) -+#define MCI_DATATRANS_FINISHMASK (1 << 16) -+#define MCI_SDIOINTMASK (1 << 17) -+ -+#define MCI_DMACTRL_REG 0x03c -+#define MCI_DMA_BUFEN (1 << 0) -+#define MCI_DMA_ADDR(x) (((x) & 0x7fff) << 1) -+#define MCI_DMA_EN (1 << 16) -+#define MCI_DMA_SIZE(x) (((x) & 0x7fff) << 17) -+ -+#define MCI_FIFO_REG 0x040 -+ -+#define SDIO_INTRCTR_REG 0x000 -+#define SDIO_INTR_CTR_ENABLE (1 << 8) -+#define SDIO_INTR_ENABLE (1 << 17) -+ -+ -+#define MCI_CMDIRQMASKS \ -+ (MCI_CMDSENTMASK|MCI_RESPENDMASK| \ -+ MCI_RESPCRCFAILMASK|MCI_RESPTIMEOUTMASK) -+ -+#define MCI_DATAIRQMASKS \ -+ (MCI_DATAEND|MCI_DATABLOCKENDMASK| \ -+ MCI_DATACRCFAILMASK|MCI_DATATIMEOUTMASK) -+ -+/*| \ -+ MCI_STARTBIT_ERRMASK) -+*/ -+ -+/* -+ * The size of the FIFO in bytes. -+ */ -+#define MCI_FIFOSIZE 4 -+#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) -+ -+#define NR_SG 16 -+ -+#define L2BASE 0x2002c000 -+#define L2FIFO_DMACONF 0x80 -+#define L2FIFO_CONF1 0x88 -+#define L2FIFO_ASSIGN1 0x90 -+#define L2FIFO_INTEN 0x9c -+ -+#define L2FIFOBASE 0x48000000 -+#define L2ADDR(n) (L2FIFOBASE + 512 * (n)) -+#define MCI_L2FIFO_NUM 2 /* #6 l2fifo */ -+#define MCI_L2FIFO_SIZE 512 -+ -+#define L2DMA_MAX_SIZE (64*255) -+ -+#define L2_DMA_ALIGN (512) -+ -+enum akmci_detect_mode { -+ AKMCI_PLUGIN_ALWAY, -+ AKMCI_DETECT_MODE_GPIO, -+ AKMCI_DETECT_MODE_AD, -+}; -+ -+enum akmci_xfer_mode { -+ AKMCI_XFER_UNKNOWN, -+ AKMCI_XFER_L2DMA, -+ AKMCI_XFER_L2PIO, -+ AKMCI_XFER_INNERPIO, -+ -+}; -+ -+struct ak_mci_platform_data { -+ int irq_cd_type; -+ int cap_highspeed; -+ int detect_mode; -+ int xfer_mode; -+ int mci_mode; -+ u32 max_speed_hz; -+ void (* gpio_init) (const struct gpio_info *); -+ struct gpio_info gpio_cd; /* card detect pin */ -+ struct gpio_info gpio_wp; /* write protect pin */ -+}; -+ -+struct clk; -+ -+#define MAX_STATUS_COUNT (1<<10) -+#define MAX_STATUS_MASK (MAX_STATUS_COUNT - 1) -+ -+ -+#define MCI_MODE_MMC_SD 0 -+#define MCI_MODE_SDIO 1 -+ -+ -+/* the 0x800000 value is reference RTOS platform, -+ * timeout is 419ms */ -+#define TRANS_DATA_TIMEOUT 0x800000 -+ -+#define MAX_MCI_REQ_SIZE (65536) -+/* as l2 fifo limit to 512 bytes */ -+#define MAX_MCI_BLOCK_SIZE (512) -+ -+struct akmci_host { -+ struct platform_device *pdev; -+ struct ak_mci_platform_data *plat; -+ struct mmc_request *mrq; -+ struct mmc_host *mmc; -+ struct mmc_data *data; -+ struct mmc_command *cmd; -+ void __iomem *base; -+ struct resource *mem; -+ struct clk *clk; -+ unsigned long asic_clk; -+ unsigned char bus_mode; -+ unsigned char bus_width; -+ unsigned long bus_clock; -+ unsigned long clkreg; -+ -+ int mci_mode; -+ int irq_mci; -+ int irq_cd; -+ int irq_cd_type; -+ int gpio_cd; -+ int gpio_wp; -+ int detect_mode; -+ int xfer_mode; -+ int data_err_flag; -+ u8 l2buf_id; -+ spinlock_t lock; -+ -+ unsigned int data_xfered; -+ unsigned int sg_len; -+ struct scatterlist *sg_ptr; -+ unsigned int sg_off; -+ unsigned int size; -+ -+ struct timer_list detect_timer; -+ struct notifier_block detect_nb; -+ int plugin_flag; -+ -+#ifdef CONFIG_CPU_FREQ -+ struct notifier_block freq_transition; -+ struct semaphore freq_lock; -+#endif -+}; -+ -+ -+ -+#endif /* end __AK_MCI_H__ */ -+ -diff --git a/include/plat-anyka/aksensor.h b/include/plat-anyka/aksensor.h -new file mode 100755 -index 00000000..c8be7c08 ---- /dev/null -+++ b/include/plat-anyka/aksensor.h -@@ -0,0 +1,92 @@ -+/* gc0308 Camera -+ * -+ * Copyright (C) 2008 Renesas Solutions Corp. -+ * Kuninori Morimoto <morimoto.kuninori@renesas.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. -+ */ -+ -+#ifndef __AKSENSOR_H__ -+#define __AKSENSOR_H__ -+ -+#include <media/soc_camera.h> -+#include <plat-anyka/wrap_sensor.h> -+ -+s32 aksensor_i2c_write_byte_data(u8 daddr, u8 raddr, u8 *data, u32 size); -+s32 aksensor_i2c_read_byte_data(u8 daddr, u8 raddr); -+ -+s32 aksensor_i2c_write_byte_short(u8 daddr, u16 raddr, u8 *data, u32 size); -+s32 aksensor_i2c_read_byte_short(u8 daddr, u16 raddr); -+ -+s32 aksensor_i2c_write_word_data(u8 daddr, u16 raddr, u16 *data, u32 size); -+s32 aksensor_i2c_read_word_data(u8 daddr, u16 raddr); -+ -+void aksensor_set_param(u32 cmd, u32 data); -+ -+ -+/* -+ * for Edge ctrl -+ * -+ * strength also control Auto or Manual Edge Control Mode -+ */ -+struct aksensor_edge_ctrl { -+ unsigned char strength; -+ unsigned char threshold; -+ unsigned char upper; -+ unsigned char lower; -+}; -+ -+/* -+ * aksensor camera info -+ */ -+struct aksensor_camera_info { -+ unsigned long buswidth; -+ unsigned long flags; -+ unsigned long pin_avdd; -+ unsigned long pin_power; -+ unsigned long pin_reset; -+ struct soc_camera_link link; -+ struct aksensor_edge_ctrl edgectrl; -+}; -+ -+struct aksensor_color_format { -+ enum v4l2_mbus_pixelcode code; -+ enum v4l2_colorspace colorspace; -+}; -+ -+ -+struct aksensor_win_size { -+ char *name; -+ __u32 width; -+ __u32 height; -+}; -+ -+struct sensor_info -+{ -+ const char *sensor_name; -+ int sensor_id; -+ const struct v4l2_ctrl_config *ctrls; -+ int nr_ctrls; -+ const struct aksensor_color_format *formats; -+ int num_formats; -+ const struct aksensor_win_size *resolution; -+ int num_resolution; -+ T_CAMERA_FUNCTION_HANDLER *handler; -+}; -+ -+#define SENSOR_MAX_SUPPORT 20 -+ -+/** -+ * @brief register a camera device, which will be probed at camera open -+ * @author dengzhou/wudaochao -+ * @date 2012-11-06 -+ * @param[in] struct sensor_info -+ * @param[in] handler camera interface -+ * @retval 0 register successfully -+ * @retval -1 register unsuccessfully -+ */ -+int register_sensor(struct sensor_info *si); -+#endif /* END __AKSENSOR_H__ */ -+ -diff --git a/include/plat-anyka/anyka_types.h b/include/plat-anyka/anyka_types.h -new file mode 100644 -index 00000000..e2d3d1fb ---- /dev/null -+++ b/include/plat-anyka/anyka_types.h -@@ -0,0 +1,70 @@ -+/** @file -+ * @brief Define the register operator for system -+ * -+ * Copyright (C) 2006 Anyka (GuangZhou) Software Technology Co., Ltd. -+ * @author -+ * @date 2006-01-16 -+ * @version 1.0 -+ */ -+ -+#ifndef _ANYKA_TYPES_H_ -+#define _ANYKA_TYPES_H_ -+ -+/** @defgroup ANYKA_CPU -+ * @ingroup M3PLATFORM -+ */ -+/*@{*/ -+ -+/* preliminary type definition for global area */ -+typedef unsigned char T_U8; /* unsigned 8 bit integer */ -+typedef unsigned short T_U16; /* unsigned 16 bit integer */ -+typedef unsigned long T_U32; /* unsigned 32 bit integer */ -+typedef signed char T_S8; /* signed 8 bit integer */ -+typedef signed short T_S16; /* signed 16 bit integer */ -+typedef signed long T_S32; /* signed 32 bit integer */ -+typedef void T_VOID; /* void */ -+ -+#define T_U8_MAX ((T_U8)0xff) // maximum T_U8 value -+#define T_U16_MAX ((T_U16)0xffff) // maximum T_U16 value -+#define T_U32_MAX ((T_U32)0xffffffff) // maximum T_U32 value -+#define T_S8_MIN ((T_S8)(-127-1)) // minimum T_S8 value -+#define T_S8_MAX ((T_S8)127) // maximum T_S8 value -+#define T_S16_MIN ((T_S16)(-32767L-1L)) // minimum T_S16 value -+#define T_S16_MAX ((T_S16)(32767L)) // maximum T_S16 value -+#define T_S32_MIN ((T_S32)(-2147483647L-1L)) // minimum T_S32 value -+#define T_S32_MAX ((T_S32)(2147483647L)) // maximum T_S32 value -+ -+/* basal type definition for global area */ -+typedef T_S8 T_CHR; /* char */ -+typedef T_U8 T_BOOL; /* BOOL type */ -+ -+typedef T_VOID * T_pVOID; /* pointer of void data */ -+typedef const T_VOID * T_pCVOID; /* const pointer of void data */ -+ -+typedef T_S8 * T_pSTR; /* pointer of string */ -+typedef const T_S8 * T_pCSTR; /* const pointer of string */ -+ -+ -+typedef T_U16 T_WCHR; /**< unicode char */ -+typedef T_U16 * T_pWSTR; /* pointer of unicode string */ -+typedef const T_U16 * T_pCWSTR; /* const pointer of unicode string */ -+ -+ -+typedef T_U8 * T_pDATA; /* pointer of data */ -+typedef const T_U8 * T_pCDATA; /* const pointer of data */ -+ -+typedef T_U32 T_COLOR; /* color value */ -+ -+typedef T_U32 T_HANDLE; /* a handle */ -+ -+#define AK_FALSE 0 -+#define AK_TRUE 1 -+#undef AK_NULL -+#define AK_NULL ((T_pVOID)(0)) -+ -+#define AK_EMPTY -+/*@}*/ -+ -+ -+#endif // _ANYKA_TYPES_H_ -+ -diff --git a/include/plat-anyka/bat.h b/include/plat-anyka/bat.h -new file mode 100644 -index 00000000..3fbdb6de ---- /dev/null -+++ b/include/plat-anyka/bat.h -@@ -0,0 +1,85 @@ -+#ifndef __AK_BAT_H_ -+#define __AK_BAT_H_ __FILE__ -+ -+#include <mach/gpio.h> -+#include <linux/delay.h> -+#include <linux/spinlock.h> -+#include <plat/gpio_keys.h> -+ -+#define poweroff_enable 1 -+#define poweroff_disable 0 -+ -+#define BAT_CHARGE_ADC_DETECT 0 -+#define BAT_CHARGE_GPIO_DETECT 1 -+ -+struct bat_gpio{ -+ int is_detect_mode; /* ac detect mode: ADC or GPIO */ -+ int active; /* active value */ -+ int irq; /* use for ac in or out irq */ -+ int delay; /* delay irq handler */ -+ struct gpio_info pindata; /* battery gpios info */ -+ -+}; -+ -+struct bat_info{ -+ int charge_full_pin; /* use for juge if battery charge full */ -+ int power_on_voltage; /* if (voltage<=power_on_voltage), disable power on */ -+ int power_on_correct; /* correct power on voltage */ -+ int charge_min_voltage; /* charge minute voltage */ -+ int max_voltage; /* max battery voltage */ -+ int min_voltage; /* min battery voltage */ -+ int power_off; /* enable or disable machine power off in battery driver */ -+ int full_capacity; -+ int voltage_sample; -+ int poweroff_cap; -+ int low_cap; -+ int recover_cap; -+ int cpower_on_voltage; /* if (voltage<=cpower_on_voltage in charge), disable power on */ -+ unsigned int full_delay;/* time to up to full capacity, unit: minute */ -+ int full_voltage; /* if voltage > full_voltage in full capacity, when in discharge,display full */ -+}; -+ -+struct read_voltage_sample{ -+ int index; // voltage[6] index -+ int max; // sample max voltage -+ int min; // sample min voltage -+ int sum; // sum of read voltage -+ int sample; /* read how many voltge sample */ -+ int design_max; -+}; -+ -+ -+struct bat_ad4{ -+ int up_resistance; /* read ad4 voltage resistance */ -+ int dw_resistance; -+ int voltage_correct; /* correct voltage from adc1-4*/ -+ int adc_avdd; /* adc avdd */ -+}; -+ -+struct ak_bat_mach_info { -+ -+ void (* gpio_init) (const struct gpio_info *); -+ struct bat_gpio usb_gpio; -+ struct bat_gpio ac_gpio; -+ struct bat_gpio full_gpio; -+ struct bat_info bat_mach_info; -+ struct bat_ad4 bat_adc; -+}; -+ -+ -+int ak_bat_read_voltage(struct ak_bat_mach_info *info); -+ -+#ifdef CONFIG_STARTUP_CHECK_VOLTAGE -+void ak_mach_check_bat_vol(struct ak_bat_mach_info *batinfo, -+ struct ak_gpio_keys_button *pwr_gpio, int len); -+#else -+static inline void ak_mach_check_bat_vol(struct ak_bat_mach_info *batinfo, -+ struct ak_gpio_keys_button *pwr_gpio, int len) -+{ -+} -+#endif -+ -+ -+#endif /* __AK_BAT_H_ */ -+ -+ -diff --git a/include/plat-anyka/cam_com_sensor.h b/include/plat-anyka/cam_com_sensor.h -new file mode 100755 -index 00000000..2e2c8d69 ---- /dev/null -+++ b/include/plat-anyka/cam_com_sensor.h -@@ -0,0 +1,259 @@ -+#ifndef __CAM_COM_SENSOR__ -+#define __CAM_COM_SENSOR__ -+ -+#ifdef CONFIG_LINUX_AKSENSOR -+#include <mach-anyka/anyka_types.h> -+#endif -+ -+#define M_DRVSYS "DRVLIB" /* module name */ -+ -+#define C1 1 /*Fatal error message*/ -+#define C2 2 /*Error message*/ -+#define C3 3 /*Common message*/ -+ -+typedef enum { -+ CAMERA_WMODE_PREV = 0, //Ԥ��ģʽ -+ CAMERA_WMODE_CAP, // ����ģʽ -+ CAMERA_WMODE_REC // ¼��ģʽ -+} T_CAMERA_WORKMODE; -+ -+typedef enum { -+ PIN_AVDD = 0, //��ȡAVDD GPIO ֵ -+ PIN_POWER, //��ȡPOWER GPIO ֵ -+ PIN_RESET //��ȡRESET GPIO ֵ -+} T_CAMERA_PINTYPE; -+ -+/** @brief Camera type definition -+ * -+ * This structure define the type of camera -+ */ -+typedef enum -+{ -+ CAMERA_P3M = 0x00000001, -+ CAMERA_1P3M = 0x00000002, -+ CAMERA_2M = 0x00000004, -+ CAMERA_3M = 0x00000008, -+ CAMERA_4M = 0x00000010, -+ CAMERA_5M = 0x00000020, -+ CAMERA_ZOOM = 0x00000040 -+}T_CAMERA_TYPE; -+ -+/** @brief Camera Parameter Night Mode definition -+ * -+ * This structure define the value of parameter Night Mode -+ */ -+typedef enum -+{ -+ CAMERA_DAY_MODE, -+ CAMERA_NIGHT_MODE, -+ CAMERA_NIGHT_NUM -+}T_NIGHT_MODE; -+ -+typedef enum { -+ CAMERA_MODE_QXGA = 0, // 2048 X 1536 -+ CAMERA_MODE_UXGA, // 1600 X 1200 -+ CAMERA_MODE_SXGA, // 1280 X 1024 -+ CAMERA_MODE_XGA, // 1024 X 768 -+ CAMERA_MODE_SVGA, // 800 X 600 -+ CAMERA_MODE_VGA, // 640 X 480 -+ CAMERA_MODE_QSVGA, // 400 X 300 -+ CAMERA_MODE_CIF, // 352 X 288 -+ CAMERA_MODE_QVGA, // 320 X 240 -+ CAMERA_MODE_QCIF, // 176 X 144 -+ CAMERA_MODE_QQVGA, // 160 X 120 -+ CAMERA_MODE_PREV, // 640 X 480 -+ CAMERA_MODE_REC, // 352 X 288 -+ CAMERA_MODE_720P, // 1280 X 720 -+ CAMERA_MODE_800P, // 1280 X 800 -+ CAMERA_MODE_960P, // 1280 X 960 -+ CAMERA_MODE_D1, // 720 X 480 -+ CAMERA_MODE_QSXGA, //2592X1944 -+ CAMERA_MODE_QXGA_JPEG, //2048X1536 jpeg -+ CAMERA_MODE_QSXGA_JPEG, //2592X1944 jpeg -+ CAMERA_MODE_VGA_JPEG, // 640 X 480 jpeg -+ CAMERA_MODE_NUM -+} T_CAMERA_MODE; -+ -+/** @brief Camera Parameter Exposure definition -+ * -+ * This structure define the value of parameter Exposure -+ */ -+typedef enum -+{ -+ EXPOSURE_WHOLE = 0, -+ EXPOSURE_CENTER, -+ EXPOSURE_MIDDLE, -+ CAMERA_EXPOSURE_NUM -+}T_CAMERA_EXPOSURE; -+ -+/** @brief Camera Parameter Brightness definition -+ * -+ * This structure define the value of parameter Brightness -+ */ -+typedef enum -+{ -+ CAMERA_BRIGHTNESS_0 = 0, -+ CAMERA_BRIGHTNESS_1, -+ CAMERA_BRIGHTNESS_2, -+ CAMERA_BRIGHTNESS_3, -+ CAMERA_BRIGHTNESS_4, -+ CAMERA_BRIGHTNESS_5, -+ CAMERA_BRIGHTNESS_6, -+ CAMERA_BRIGHTNESS_NUM -+}T_CAMERA_BRIGHTNESS; -+ -+/** @brief Camera Parameter Contrast definition -+ * -+ * This structure define the value of parameter Contrast -+ */ -+typedef enum -+{ -+ CAMERA_CONTRAST_1 = 0, -+ CAMERA_CONTRAST_2, -+ CAMERA_CONTRAST_3, -+ CAMERA_CONTRAST_4, -+ CAMERA_CONTRAST_5, -+ CAMERA_CONTRAST_6, -+ CAMERA_CONTRAST_7, -+ CAMERA_CONTRAST_NUM -+}T_CAMERA_CONTRAST; -+ -+/** @brief Camera Parameter Saturation definition -+ * -+ * This structure define the value of parameter Saturation -+ */ -+typedef enum -+{ -+ CAMERA_SATURATION_0 = 0, -+ CAMERA_SATURATION_1, -+ CAMERA_SATURATION_2, -+ CAMERA_SATURATION_3, -+ CAMERA_SATURATION_4, -+ CAMERA_SATURATION_5, -+ CAMERA_SATURATION_6, -+ CAMERA_SATURATION_NUM -+}T_CAMERA_SATURATION; -+ -+/** @brief Camera Parameter Sharpness definition -+ * -+ * This structure define the value of parameter Sharpness -+ */ -+typedef enum -+{ -+ CAMERA_SHARPNESS_0 = 0, -+ CAMERA_SHARPNESS_1, -+ CAMERA_SHARPNESS_2, -+ CAMERA_SHARPNESS_3, -+ CAMERA_SHARPNESS_4, -+ CAMERA_SHARPNESS_5, -+ CAMERA_SHARPNESS_6, -+ CAMERA_SHARPNESS_NUM -+}T_CAMERA_SHARPNESS; -+ -+/** @brief Camera Parameter AWB definition -+ * -+ * This structure define the value of parameter AWB -+ */ -+typedef enum -+{ -+ AWB_AUTO = 0, -+ AWB_SUNNY, -+ AWB_CLOUDY, -+ AWB_OFFICE, -+ AWB_HOME, -+ AWB_NIGHT, -+ AWB_NUM -+}T_CAMERA_AWB; -+ -+/** @brief Camera Parameter Mirror definition -+ * -+ * This structure define the value of parameter Mirror -+ */ -+typedef enum -+{ -+ CAMERA_MIRROR_V = 0, -+ CAMERA_MIRROR_H, -+ CAMERA_MIRROR_NORMAL, -+ CAMERA_MIRROR_FLIP, -+ CAMERA_MIRROR_NUM -+}T_CAMERA_MIRROR; -+ -+/** @brief Camera Parameter Effect definition -+ * -+ * This structure define the value of parameter Effect -+ */ -+typedef enum -+{ -+ CAMERA_EFFECT_NORMAL = 0, -+ CAMERA_EFFECT_SEPIA, -+ CAMERA_EFFECT_ANTIQUE, -+ CAMERA_EFFECT_BLUE, -+ CAMERA_EFFECT_GREEN, -+ CAMERA_EFFECT_RED, -+ CAMERA_EFFECT_NEGATIVE, -+ CAMERA_EFFECT_BW, -+ CAMERA_EFFECT_BWN, -+ CAMERA_EFFECT_AQUA, // PO1200 additional mode add by Liub 20060918 -+ CAMERA_EFFECT_COOL, -+ CAMERA_EFFECT_WARM, -+ CAMERA_EFFECT_NUM -+}T_CAMERA_EFFECT; -+ -+ -+/** @brief Camera Parameter CCIR601/656 protocol -+ * -+ * This structure define the CMOS sensor compatible with CCIR601 or CCIR656 protocol -+ */ -+typedef enum -+{ -+ CAMERA_CCIR_601, -+ CAMERA_CCIR_656, -+ CAMERA_CCIR_NUM -+}T_CAMERA_INTERFACE; -+ -+/** @brief Camera feature definition -+ * -+ * This structure define the feature list of camera -+ */ -+typedef enum { -+ CAM_FEATURE_NIGHT_MODE = 0, -+ CAM_FEATURE_EXPOSURE, -+ CAM_FEATURE_AWB, -+ CAM_FEATURE_BRIGHTNESS, -+ CAM_FEATURE_CONTRAST, -+ CAM_FEATURE_SATURATION, -+ CAM_FEATURE_SHARPNESS, -+ CAM_FEATURE_MIRROR, -+ CAM_FEATURE_EFFECT, -+ CAM_FEATURE_NUM -+}T_CAMERA_FEATURE; -+ -+ -+typedef struct -+{ -+ T_U32 cam_mclk; -+ T_VOID (*cam_open_func)(T_VOID); -+ T_BOOL (*cam_close_func)(T_VOID); -+ T_U32 (*cam_read_id_func)(T_VOID); -+ T_BOOL (*cam_init_func)(T_VOID); -+ T_VOID (*cam_set_mode_func)(T_CAMERA_MODE mode); -+ T_VOID (*cam_set_exposure_func)(T_CAMERA_EXPOSURE exposure); -+ T_VOID (*cam_set_brightness_func)(T_CAMERA_BRIGHTNESS brightness); -+ T_VOID (*cam_set_contrast_func)(T_CAMERA_CONTRAST contrast); -+ T_VOID (*cam_set_saturation_func)(T_CAMERA_SATURATION saturation); -+ T_VOID (*cam_set_sharpness_func)(T_CAMERA_SHARPNESS sharpness); -+ T_VOID (*cam_set_AWB_func)(T_CAMERA_AWB awb); -+ T_VOID (*cam_set_mirror_func)(T_CAMERA_MIRROR mirror); -+ T_VOID (*cam_set_effect_func)(T_CAMERA_EFFECT effect); -+ T_S32 (*cam_set_window_func)(T_U32 srcWidth, T_U32 srcHeight); -+ T_VOID (*cam_set_night_mode_func)(T_NIGHT_MODE mode); -+ T_U32 (*cam_set_framerate_func)(float framerate); -+ T_VOID (*cam_set_anti_flicker_func)(T_U32 value); -+ T_BOOL (*cam_set_to_cap_func)(T_U32 srcWidth, T_U32 srcHeight); -+ T_BOOL (*cam_set_to_prev_func)(T_U32 srcWidth, T_U32 srcHeight); -+ T_BOOL (*cam_set_to_record_func)(T_U32 srcWidth, T_U32 srcHeight); -+ T_CAMERA_TYPE (*cam_get_type)(T_VOID); -+ T_VOID (*cam_set_sensor_param_func)(T_U32 cmd, T_U32 data); -+}T_CAMERA_FUNCTION_HANDLER; -+#endif -+ -diff --git a/include/plat-anyka/drv_module_lock.h b/include/plat-anyka/drv_module_lock.h -new file mode 100755 -index 00000000..9f83886c ---- /dev/null -+++ b/include/plat-anyka/drv_module_lock.h -@@ -0,0 +1,143 @@ -+#ifndef __DRV_MODULE_LOCK__ -+#define __DRV_MODULE_LOCK__ -+ -+#include <mach/gpio.h> -+ -+/** -+ * @brief driver module define. -+ * define all the moudle -+ */ -+typedef enum -+{ -+ DRV_MODULE_AD = 0, -+ DRV_MODULE_DA, -+ DRV_MODULE_I2S, -+ DRV_MODULE_UART, -+ DRV_MODULE_CAMERA, -+ DRV_MODULE_DETECT, -+ DRV_MODULE_RTC, -+ DRV_MODULE_KEYPAD, -+ DRV_MODULE_VTIMER, -+ DRV_MODULE_TOUCH_SCREEN, -+ -+ DRV_MODULE_UVC, -+ DRV_MODULE_USB_DISK, -+ DRV_MODULE_USB_CDC, -+ DRV_MODULE_USB_CAMERA, -+ DRV_MODULE_USB_ANYKA, -+ DRV_MODULE_USB_CMMB, -+ -+ DRV_MODULE_UDISK_HOST, -+ DRV_MODULE_UVC_HOST, -+ -+ DRV_MODULE_USB_BUS, -+ -+ DRV_MODULE_FREQ, -+ DRV_MODULE_HTIMER, -+ DRV_MODULE_LCD_RGB, -+ DRV_MODULE_LCD_MPU, -+ DRV_MODULE_NAND, -+ DRV_MODULE_SDMMC, -+ DRV_MODULE_SPI, -+ DRV_MODULE_SDIO, -+ DRV_MODULE_I2C, -+ -+ DRV_MODULE_GPIO_EDGE, -+ -+ DRV_MODULE_JPEG_CODEC -+} E_DRV_MODULE; -+ -+typedef enum { -+ AK_MODULE_LOCK_1, -+ AK_MODULE_LOCK_2, -+ AK_MODULE_LOCK_3, -+ AK_MODULE_LOCK_4, -+ AK_MODULE_LOCK_5, -+ AK_MODULE_LOCK_6, -+ AK_MODULE_LOCK_7, -+ AK_MODULE_LOCK_8, -+ AK_MODULE_LOCK_9, -+ AK_MODULE_LOCK_10, -+ AK_MODULE_COUNT, -+} E_LOCK_NAME; -+ -+typedef enum { -+ TYPE_LOCK_SEMAPHORE, -+ TYPE_LOCK_MUTEX, -+ TYPE_LOCK_SPINLOCK, -+ TYPE_LOCK_SPINLOCK_IRQ -+} E_LOCK_TYPE; -+ -+struct ak_drv_module_lock { -+ E_DRV_MODULE drv_mod_name; -+ E_LOCK_NAME lock_name; -+ E_LOCK_TYPE lock_type; -+ unsigned long flags; -+ T_GPIO_SHAREPIN_CFG sharepin_cfg; -+}; -+ -+struct ak_drv_sharepin_lock { -+ E_DRV_MODULE drv_mod_name; -+ E_LOCK_NAME lock_name; -+ E_LOCK_TYPE lock_type; -+ unsigned long flags; -+ void (*config_share_pin)(void); -+}; -+ -+ -+/** -+ * function: acquire lock. protect driver module to do normally. -+ * as GPIOs are part of drivers module. -+ * param: [in]driver module name -+ * ret: void -+ */ -+int ak_drv_module_lock(E_DRV_MODULE drv_mod_name); -+ -+/** -+ * function: release lock. protect driver module to do normally. -+ * as GPIOs are part of drivers module. -+ * param: [in]driver module name -+ * ret: void -+ */ -+void ak_drv_module_unlock(E_DRV_MODULE drv_mod_name); -+ -+/** -+ * function: acquire lock. protect driver module to do normally. -+ * as the GPIO is defined only at board(name is product also). -+ * param: [in]driver module name -+ * ret: -+ * 0: if acquire lock successed; -+ * <0: indicate the driver is not need lock -+ */ -+int ak_drv_sharepin_lock(E_DRV_MODULE drv_mod_name); -+ -+/** -+ * function: release lock. protect driver module to do normally. -+ * as the GPIO is defined only at board(name is product also). -+ * param: [in]driver module name -+ * ret: -+ * 0: if acquire lock successed; -+ * <0: indicate the driver is not need lock -+ */ -+void ak_drv_sharepin_unlock(E_DRV_MODULE drv_mod_name); -+ -+/** -+ * function: acquire lock. protect driver module to do normally. -+ * param: [in]driver module name -+ * ret: void -+ */ -+void ak_drv_module_protect(E_DRV_MODULE drv_mod_name); -+ -+/** -+ * function: release lock. protect driver module to do normally. -+ * param: [in]driver module name -+ * ret: void -+ */ -+void ak_drv_module_unprotect(E_DRV_MODULE drv_mod_name); -+ -+void ak_set_sharepin_lock_table( -+ struct ak_drv_sharepin_lock *shpin_lock_table, int count, void **lock_array); -+ -+ -+#endif /* __DRV_MODULE_LOCK__ */ -+ -diff --git a/include/plat-anyka/fha_asa.h b/include/plat-anyka/fha_asa.h -new file mode 100644 -index 00000000..5a30deaa ---- /dev/null -+++ b/include/plat-anyka/fha_asa.h -@@ -0,0 +1,81 @@ -+#ifndef _FHA_ASA_H_ -+#define _FHA_ASA_H_ -+ -+#define ASA_FILE_FAIL 0 -+#define ASA_FILE_SUCCESS 1 -+#define ASA_FILE_EXIST 2 -+#define ASA_MODE_OPEN 0 -+#define ASA_MODE_CREATE 1 -+ -+#define ASA_FORMAT_NORMAL 0 -+#define ASA_FORMAT_EWR 1 -+#define ASA_FORMAT_RESTORE 2 -+ -+/************************************************************************ -+ * NAME: FHA_asa_scan -+ * FUNCTION scan nand flash security area -+ * PARAM: [in] bMount -- if buffer is enough, set AK_TURE, scan speedup -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_asa_scan(T_BOOL bMount); -+ -+/************************************************************************ -+ * NAME: FHA_asa_format -+ * FUNCTION nand flash format security area -+ * PARAM: [in] type -- ASA_FORMAT_NORMAL: only scan initial bad blocks -+ * ASA_FORMAT_EWR: Erase-wirte-read test -+ * ASA_FORMAT_RESTORE: do nothing -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_asa_format(T_U32 type); -+ -+/************************************************************************ -+ * NAME: FHA_set_bad_block -+ * FUNCTION set nand flash bad block -+ * PARAM: [in] block -- the bad block item -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_set_bad_block(T_U32 block); -+ -+/************************************************************************ -+ * NAME: FHA_check_bad_block -+ * FUNCTION check nand flash bad block -+ * PARAM: [in] block -- need to check block item -+ * RETURN: is bad block return FHA_SUCCESS, or else retuen FHA_ FAIL -+**************************************************************************/ -+T_BOOL FHA_check_bad_block(T_U32 block); -+ -+/************************************************************************ -+ * NAME: FHA_get_bad_block -+ * FUNCTION get bad block information of one or more blocks -+ * PARAM: [in] start_block -- start block -+ * [out]pData -------- buffer used to store bad blocks information data -+ * [in] blk_cnt ------ how many blocks you want to know -+ * RETURN: success return FHA_SUCCESS, fail retuen FHA_ FAIL -+**************************************************************************/ -+T_U32 FHA_get_bad_block(T_U32 start_block, T_U8 *pData, T_U32 blk_cnt); -+ -+/************************************************************************ -+ * NAME: FHA_asa_write_file -+ * FUNCTION write important infomation to security area, data_len can't too large -+ * PARAM: [in] file_name -- asa file name -+ * [in] pData ------ buffer used to store information data -+ * [in] data_len --- need to store data length -+ * [in] mode-------- operation mode -+ * ASA_MODE_OPEN------open -+ * ASA_MODE_CREATE----create -+ * RETURN: success return ASA_FILE_SUCCESS, fail retuen ASA_FILE_FAIL -+**************************************************************************/ -+T_U32 FHA_asa_write_file(T_U8 file_name[], const T_U8 *pData, T_U32 data_len, T_U8 mode); -+ -+/************************************************************************ -+ * NAME: FHA_asa_read_file -+ * FUNCTION get infomation from security area by input file name -+ * PARAM: [in] file_name -- asa file name -+ * [out]pData ------ buffer used to store information data -+ * [in] data_len --- need to get data length -+ * RETURN: success return ASA_FILE_SUCCESS, fail retuen ASA_FILE_FAIL -+**************************************************************************/ -+T_U32 FHA_asa_read_file(T_U8 file_name[], T_U8 *pData, T_U32 data_len); -+#endif // -+ -diff --git a/include/plat-anyka/gpio_keys.h b/include/plat-anyka/gpio_keys.h -new file mode 100755 -index 00000000..0da5c6e2 ---- /dev/null -+++ b/include/plat-anyka/gpio_keys.h -@@ -0,0 +1,36 @@ -+#ifndef _GPIO_KEYS_H -+#define _GPIO_KEYS_H -+ -+struct device; -+ -+struct gpio_keys_button { -+ /* Configuration parameters */ -+ unsigned int code; /* input event code (KEY_*, SW_*) */ -+ int gpio; /* -1 if this key does not support gpio */ -+ int active_low; -+ const char *desc; -+ unsigned int type; /* input event type (EV_KEY, EV_SW, EV_ABS) */ -+ int wakeup; /* configure the button as a wake-up source */ -+ int debounce_interval; /* debounce ticks interval in msecs */ -+ bool can_disable; -+ int value; /* axis value for EV_ABS */ -+ unsigned int irq; /* Irq number in case of interrupt keys */ -+ -+ char pulldown; //pulldown function flag -+ char pullup; //pullup function flag -+ char dir; //direction input/output -+ char int_pol; //interrupt polarity -+}; -+ -+struct akgpio_keys_platform_data { -+ struct gpio_keys_button *buttons; -+ int nbuttons; -+ unsigned int poll_interval; /* polling interval in msecs - -+ for polling driver only */ -+ unsigned int rep:1; /* enable input subsystem auto repeat */ -+ int (*enable)(struct device *dev); -+ void (*disable)(struct device *dev); -+ const char *name; /* input device name */ -+}; -+ -+#endif -diff --git a/include/plat-anyka/isp_interface.h b/include/plat-anyka/isp_interface.h -new file mode 100755 -index 00000000..52fadbb1 ---- /dev/null -+++ b/include/plat-anyka/isp_interface.h -@@ -0,0 +1,246 @@ -+#ifndef _ISP_INTERFACE_H -+#define _ISP_INTERFACE_H -+ -+#define ISP_PARM_MODE 0x01 -+#define ISP_PARM_CHANNEL2 0x02 -+#define ISP_PARM_OSD 0x04 -+#define ISP_PARM_OCCLUSION 0x08 -+#define ISP_PARM_OCCLUSION_COLOR 0x10 -+#define ISP_PARM_ZOOM 0x20 -+ -+enum isp_working_mode { -+ ISP_JPEG_MODE, // JPEG compression frame mode -+ ISP_JPEG_VIDEO, // JPEG video frame mode -+ ISP_YUV_OUT, // YUV single frame mode. is not support minor channel -+ ISP_YUV_BYPASS, // YUV single frame mode and bypass -+ ISP_YUV_MERGER_OUT, -+ ISP_YUV_BIG, // YUV single frame and big image mode -+ ISP_YUV_VIDEO_OUT, // YUV video frame mode -+ ISP_YUV_VIDEO_BYPASS, // YUV video frame mode and bypass -+ ISP_YUV_VIDEO_MERGER_OUT, -+ ISP_RGB_OUT, // RGB single frame mode -+ ISP_RGB_VIDEO_OUT, // RGB video frame mode -+ ISP_RGB_BIG, // RGB single frame and big image mode -+}; -+ -+enum isp_mode_class { -+ ISP_RGB_CLASS, -+ ISP_YUV_CLASS, -+ ISP_JPEG_CLASS, -+}; -+ -+struct isp_channel2_info { -+ int type; -+ int width; -+ int height; -+ int enable; -+}; -+ -+struct isp_mode_info { -+ int type; -+ enum isp_working_mode mode; -+}; -+ -+struct isp_osd_info { -+ int type; -+ int channel; -+ int color_depth; -+ int color_transparency; -+ int start_xpos; -+ int end_xpos; -+ int start_ypos; -+ int end_ypos; -+ int enable; -+ unsigned long phys_addr; -+ unsigned long virt_addr; -+}; -+ -+struct isp_occlusion_info { -+ int type; -+ int channel; -+ int number; -+ int start_xpos; -+ int end_xpos; -+ int start_ypos; -+ int end_ypos; -+ int enable; -+}; -+ -+struct isp_occlusion_color { -+ int type; -+ int color_type; -+ int transparency; -+ int y_component; -+ int u_component; -+ int v_component; -+}; -+ -+struct isp_zoom_info { -+ int type; -+ int channel; // value: 1 indicate isp master channel, 2 indicate the second channel -+ int cut_xpos; -+ int cut_ypos; -+ int cut_width; -+ int cut_height; -+ int out_width; -+ int out_height; -+}; -+ -+ -+/* response pc tool control command */ -+#define ISP_CID_BLACK_BALANCE 0x60 //black balance -+#define ISP_CID_LENS 0x61 //lens correct -+#define ISP_CID_DEMOSAIC 0x62 //demosaic -+#define ISP_CID_RGB_FILTER 0x63 //RGB filter, noise reduce -+#define ISP_CID_UV_FILTER 0x64 //uv filter -+#define ISP_CID_DEFECT_PIXEL 0x65 //bad color correct -+#define ISP_CID_WHITE_BALANCE 0x66 //white balance -+#define ISP_CID_AUTO_WHITE_BALANCE 0x67 //auto white balance -+#define ISP_CID_COLOR 0x68 //color correct -+#define ISP_CID_GAMMA 0x69 //gamma calculate -+#define ISP_CID_BRIGHTNESS_ENHANCE 0x70 //brightness edge enhancement -+#define ISP_CID_SATURATION 0x72 //saturation -+#define ISP_CID_HISTOGRAM 0x73 //histogram -+#define ISP_CID_SPECIAL_EFFECT 0x74 //special effect -+#define ISP_CID_SET_SENSOR_PARAM 0x75 //set sensor parameter -+ -+/* response pc tool control command structure define */ -+struct isp_black_balance { -+ int type; -+ int enable; -+ unsigned int r_offset; //register table 0x20: offset register 13 [31:22] -+ unsigned int g_offset; //register table 0x20: offset register 14 [31:22] -+ unsigned int b_offset; //register table 0x20: offset register 15 [31:22] -+}; -+ -+struct isp_lens_correct { -+ int type; -+ int enable; //register table 0x20: offset register 24 [31] -+ int lens_coefa[10]; //register table 0x20: start offset register 13 [21:0] -+ int lens_coefb[10]; -+ int lens_coefc[10]; -+ unsigned int lens_range[10]; -+ unsigned int lens_xref; //register table 0x20: offset register 23 [31:22] -+ unsigned int lens_yref; //register table 0x20: offset register 23 [31:22] -+}; -+ -+//demosaic -+struct isp_demosaic { -+ int type; -+ int enable; //register table 0x20: offset register 2 [12] -+ unsigned int threshold; //register table 0x20: offset register 2 [11:0] -+}; -+ -+// noise reduce -+struct isp_rgb_filter { -+ int type; -+ int enable; //register table 0x24: offset register 1 [31] -+ unsigned int threshold; //register table 0x24: offset register 1 [21:12] -+}; -+ -+//uv iso filter -+struct isp_uv_filter { -+ int type; -+ int enable; //register table 0x24: offset register 13 [30] -+}; -+ -+// defect pixel -+struct isp_defect_pixel { -+ int type; -+ int enable; //register table 0x24: offset register 1 [30] -+ unsigned int threshold; //register table 0x24: offset register 1 [29:28] -+}; -+ -+struct isp_white_balance { -+ int type; -+ int enable; -+ unsigned int co_r; //register table 0x24: offset register 0 [11:0] -+ unsigned int co_g; //register table 0x24: offset register 0 [23:12] -+ unsigned int co_b; //register table 0x24: offset register 1 [11:0] -+}; -+ -+struct isp_auto_white_balance { -+ int type; -+ int enable; //register table 0x20: offset register 25 [31] -+ unsigned int gr_low; // 0.8125 -+ unsigned int gr_high; // 1.555 -+ unsigned int gb_low; // 0.863 -+ unsigned int gb_high; // 1.820 -+ unsigned int grb_low; // 0.461 -+ unsigned int grb_high; // 1.559 -+ //range of pixel -+ unsigned int r_low; -+ unsigned int r_high; -+ unsigned int g_low; -+ unsigned int g_high; -+ unsigned int b_low; -+ unsigned int b_high; -+ -+ unsigned int co_r; //register table 0x24: offset register 0 [11:0] -+ unsigned int co_g; //register table 0x24: offset register 0 [23:12] -+ unsigned int co_b; //register table 0x24: offset register 1 [11:0] -+}; -+ -+struct isp_color_correct { -+ int type; -+ int enable; //register table 0x24: offset register 11 [31] -+ unsigned int cc_thrs_low; -+ unsigned int cc_thrs_high; -+ int ccMtrx[3][3]; -+}; -+ -+struct isp_gamma_calculate { -+ int type; -+ int enable; //register table 0x24: offset register 11 [30] -+ int is_sync; //count: 0: 1 -+ unsigned int gamma[32]; //register table 0x28: 64 register -+}; -+ -+//brightness edge enhancement -+struct isp_brightness_enhance { -+ int type; -+ int enable; //register table 0x24: offset register 11 [29] -+ int ygain; //register table 0x24: offset register 12 [31:24] -+ unsigned int y_thrs; //register table 0x24: offset register 12 [22:12] -+ unsigned int y_edgek; //register table 0x24: offset register 12 [10:0] -+}; -+ -+struct isp_saturation { -+ int type; -+ int enable; //register table 0x24: offset register 13 [31] -+ int Khigh; //register table 0x24: offset register 13 [29:20], (0.1~3) *256 _8_8 -+ int Klow; //register table 0x24: offset register 13 [19:10], register value (0.1~3) -+ int Kslope; //register table 0x24: offset register 13 [9:0], (ih-il)*256/(ch-cl) -+ unsigned int Chigh; //register table 0x24: offset register 14 [31:24],0~255 -+ unsigned int Clow; //register table 0x24: offset register 14 [23:16], 0~255 -+}; -+ -+struct isp_histogram { -+ int type; -+ int enable; // -+ int sync; //sync: 0: 1 -+ unsigned int hist[32]; // -+}; -+ -+struct isp_special_effect { -+ int type; -+ int enable; //register table 0x24: offset register 11 [28] -+ int solar_enable; //register table 0x24: offset register 11 [27] -+ unsigned int solar_thrs; //register table 0x24: offset register 0 [31:24] -+ int y_eff_coefa; //register table 0x24: offset register 14 [15:8] -+ unsigned int y_eff_coefb; //register table 0x24: offset register 14 [7:0] -+ int u_eff_coefa; //register table 0x24: offset register 15 [31:24] -+ unsigned int u_eff_coefb; //register table 0x24: offset register 15 [23:16] -+ int v_eff_coefa; //register table 0x24: offset register 15 [15:8] -+ unsigned int v_eff_coefb; //register table 0x24: offset register 15 [7:0] -+}; -+ -+struct isp_config_sensor_reg { -+ int type; -+ int enable; -+ unsigned int cmd; -+ unsigned int data; -+}; -+ -+#endif -+ -diff --git a/include/plat-anyka/notify.h b/include/plat-anyka/notify.h -new file mode 100755 -index 00000000..b230fd4e ---- /dev/null -+++ b/include/plat-anyka/notify.h -@@ -0,0 +1,36 @@ -+/* -+ * include/plat-anyka/notify.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef __NOTIFY_H_ -+#define __NOTIFY_H_ -+ -+#define POWER_EVENT_AC_PLUGIN 0x01 -+#define POWER_EVENT_AC_PLUGOUT 0x02 -+#define POWER_EVENT_USB_PLUGIN 0x03 -+#define POWER_EVENT_USB_PLUGOUT 0x04 -+ -+#define ADDEDECT_DEV1_PLUGIN 0x10 -+#define ADDEDECT_DEV1_PLUGOUT 0x11 -+#define ADDEDECT_DEV2_PLUGIN 0x12 -+#define ADDEDECT_DEV2_PLUGOUT 0x13 -+#define ADDEDECT_DEV3_PLUGIN 0x14 -+#define ADDEDECT_DEV3_PLUGOUT 0x15 -+#define ADDEDECT_DEV4_PLUGIN 0x16 -+#define ADDEDECT_DEV4_PLUGOUT 0x17 -+ -+int power_register_client(struct notifier_block *nb); -+int power_unregister_client(struct notifier_block *nb); -+int power_notifier_call_chain(unsigned long val, void *v); -+ -+int addetect_register_client(struct notifier_block *nb); -+int addetect_unregister_client(struct notifier_block *nb); -+int addetect_notifier_call_chain(unsigned long val, void *v); -+ -+#endif /* __NOTIFY_H_ */ -+ -diff --git a/include/plat-anyka/otg-hshcd.h b/include/plat-anyka/otg-hshcd.h -new file mode 100755 -index 00000000..495927ba ---- /dev/null -+++ b/include/plat-anyka/otg-hshcd.h -@@ -0,0 +1,29 @@ -+/* -+ * AKOTG HS register declarations and HCD data structures -+ */ -+ -+#ifndef __ANYKA_OTG_HS_H_ -+#define __ANYKA_OTG_HS_H_ -+ -+ -+#include <linux/delay.h> -+#include <asm/gpio.h> -+ -+#define AKOTG_HC_HCD -+ -+#define USB_OP_MOD_REG (AK_VA_SYSCTRL + 0x58) -+#define USB_MODULE_RESET_REG (AK_VA_SYSCTRL + 0x20) -+ -+ -+#define USB_HC_BASE_ADDR (AK_VA_USB) -+#define H_MAXPACKET 512 /* bytes in fifo */ -+ -+struct akotghc_usb_platform_data { -+ void (* gpio_init)(const struct gpio_info *info); -+ struct gpio_info gpio_pwr_on; -+ struct gpio_info gpio_pwr_off; -+ struct gpio_info switch_onboard; -+ struct gpio_info switch_extport; -+}; -+ -+#endif /* __ANYKA_OTG_HS_H_ */ -diff --git a/include/plat-anyka/spi-anyka-slave.h b/include/plat-anyka/spi-anyka-slave.h -new file mode 100755 -index 00000000..02f6aee7 ---- /dev/null -+++ b/include/plat-anyka/spi-anyka-slave.h -@@ -0,0 +1,38 @@ -+/* -+ * Copyright (C) anyka 2012 -+ * Wangsheng Gao <gao_wangsheng@anyka.oa> -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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 SPI_ANYKA_SLAVE_H_ -+#define SPI_ANYKA_SLAVE_H_ -+ -+ -+/* -+ * Spi command definitions -+ * Support 4294967295 commands -+ */ -+ -+ #define OPEN_WIFI 0x00000001 -+ #define CLOSE_WIFI 0x00000002 -+ -+ #define MAX_COMMAND 0xffffffff -+ -+#endif /*SPI_ANYKA_SLAVE_H_*/ -diff --git a/include/plat-anyka/tscp2007.h b/include/plat-anyka/tscp2007.h -new file mode 100755 -index 00000000..9c59df7d ---- /dev/null -+++ b/include/plat-anyka/tscp2007.h -@@ -0,0 +1,46 @@ -+#ifndef __LINUX_I2C_TSC2007_H -+#define __LINUX_I2C_TSC2007_H -+ -+enum { -+ ORIGIN_TOPLEFT = 1, -+ ORIGIN_BOTTOMLEFT, -+ ORIGIN_TOPRIGHT, -+ ORIGIN_BOTTOMRIGHT, -+}; -+ -+struct cp2007_intpin_info { -+ unsigned int pin; -+ char pulldown; //pulldown function flag -+ char pullup; //pullup function flag -+ char dir; //direction input/output -+ char int_pol; //interrupt polarity -+ unsigned int rst_pin; -+ int rst_time; -+ char rst_dir; -+ char rst_pol; -+ char rst_not; -+}; -+ -+ -+struct tscp2007_platform_data { -+ u16 model; /* 2007. */ -+ u16 x_plate_ohms; /* must be non-zero value */ -+ u16 max_rt; /* max. resistance above which samples are ignored */ -+ unsigned long poll_delay; /* delay (in ms) after pen-down event -+ before polling starts */ -+ unsigned long poll_period; /* time (in ms) between samples */ -+ int fuzzx; /* fuzz factor for X, Y and pressure axes */ -+ int fuzzy; -+ int fuzzz; -+ -+ struct cp2007_intpin_info intpin_info; -+ -+ int (*get_pendown_state)(unsigned int pin); -+ void (*clear_penirq)(void); /* If needed, clear 2nd level interrupt source */ -+ int (*init_platform_hw)(const struct cp2007_intpin_info *intpin_info); -+ void (*exit_platform_hw)(void); -+ -+ void (*reset_platform_hw)(const struct cp2007_intpin_info *intpin_info); -+}; -+ -+#endif /* __LINUX_I2C_TSC2007_H */ -\ No newline at end of file -diff --git a/include/plat-anyka/udc.h b/include/plat-anyka/udc.h -new file mode 100755 -index 00000000..aeef52af ---- /dev/null -+++ b/include/plat-anyka/udc.h -@@ -0,0 +1,240 @@ -+#ifndef __UDC_H__ -+#define __UDC_H__ -+ -+#include <asm/gpio.h> -+ -+#define USB_OP_MOD_REG (AK_VA_SYSCTRL + 0x58) -+#define USB_MODULE_RESET_REG (AK_VA_SYSCTRL + 0x20) -+ -+/* Anyka usb register */ -+#define USB_FUNCTION_ADDR 0x0 -+#define USB_POWER_CTRL 0x1 -+#define USB_INTERRUPT_1 0x2 -+#define USB_INTERRUPT_2 0x4 -+#define USB_INTERRUPT_TX 0x6 -+#define USB_INTERRUPT_RX 0x8 -+#define USB_INTERRUPT_COMM 0xA -+#define USB_INTERRUPT_USB 0xB -+#define USB_FRAME_NUM 0xC -+#define USB_EP_INDEX 0xE -+#define USB_TEST_MODE 0xF -+#define USB_TX_MAX 0x10 -+#define USB_CTRL_1 0x12 -+#define USB_CTRL_1_2 0x13 -+#define USB_RX_MAX 0x14 -+#define USB_CTRL_2 0x16 -+#define USB_CTRL_2_2 0x17 -+#define USB_EP_COUNT 0x18 -+#define USB_CFG_INFO 0x1F -+#define USB_EP0_FIFO 0x20 -+#define USB_EP1_FIFO 0x24 -+#define USB_EP2_FIFO 0x28 -+#define USB_EP3_FIFO 0x2C -+#define USB_EP4_FIFO 0x30 -+#define USB_EP5_FIFO 0x34 -+#define USB_DEVICE_CTRL 0x60 -+#define USB_DMA_INTR 0x200 -+#define USB_DMA_CTRL1 0x204 -+#define USB_DMA_CTRL2 0x214 -+#define USB_DMA_CTRL3 0x224 -+#define USB_DMA_CTRL4 0x234 -+#define USB_DMA_ADDR1 0x208 -+#define USB_DMA_ADDR2 0x218 -+#define USB_DMA_ADDR3 0x228 -+#define USB_DMA_ADDR4 0x238 -+#define USB_DMA_COUNT1 0x20C -+#define USB_DMA_COUNT2 0x21C -+#define USB_DMA_COUNT3 0x22C -+#define USB_DMA_COUNT4 0x23C -+#define USB_EP0_NUM 0x330 -+#define USB_EP2_NUM 0x334 -+#define USB_MODE_STATUS 0x344 -+ -+#define USB_LINESTATE_WP (3 << 15) -+#define USB_DP_PU_EN (1 << 14) -+#define USB_ID_CFG (3 << 12) -+#define USB_PHY_CFG (0x3f << 6) -+#define USB_SUSPEND_EN (1 << 2) -+#define USB_ID_CLIENT (3) -+#define USB_ID_HOST (1) -+#define USB_PHY_CLIENT (23) -+#define USB_PHY_HOST (31) -+#define USB_ISO_UPDATE (1 << 7) -+#define USB_HSPEED_EN (1 << 5) -+#define USB_HSPEED_MODE (1 << 4) -+#define USB_RESUME_EN (1 << 2) -+#define USB_SUSPEND_MODE (1 << 1) -+#define USB_SUSPENDM_EN (1 << 0) -+ -+#define USB_ENABLE_DMA (1) -+#define USB_DIRECTION_RX (0<<1) -+#define USB_DIRECTION_TX (1<<1) -+#define USB_DMA_MODE1 (1<<2) -+#define USB_DMA_MODE0 (0<<2) -+#define USB_DMA_INT_ENABLE (1<<3) -+#define USB_DMA_INT_DISABLE (0<<3) -+#define USB_DMA_BUS_ERROR (1<<8) -+#define USB_DMA_BUS_MODE0 (0<<9) -+#define USB_DMA_BUS_MODE1 (1<<9) -+#define USB_DMA_BUS_MODE2 (2<<9) -+#define USB_DMA_BUS_MODE3 (3<<9) -+#define DMA_CHANNEL1_INT (1) -+#define DMA_CHANNEL2_INT (2) -+#define DMA_CHANNEL3_INT (4) -+#define DMA_CHANNEL4_INT (8) -+#define USB_EP0_INDEX (0) -+#define USB_EP1_INDEX (1 << 0) -+#define USB_EP2_INDEX (1 << 1) -+#define USB_EP3_INDEX ((1 << 1)|(1 << 0)) -+#define USB_EP4_INDEX (1 << 2) -+#define USB_EP5_INDEX ((1 << 2)|(1 << 0)) -+ -+// #define USB_11 [> usb1.1 <] -+ -+#define EP0_FIFO_SIZE 64 /* control, not 64byte? */ -+#define EP1_FIFO_SIZE 64 /* interrupt */ -+#define EP2_FIFO_SIZE 512 /* ep2 in bulk */ -+#define EP3_FIFO_SIZE 512 /* ep3 out bulk */ -+#define EP4_FIFO_SIZE 512 /* ep4 in bulk */ -+#define EP5_FIFO_SIZE 512 /* ep5 out bulk */ -+ -+#define USB_TXCSR_AUTOSET (0x80) -+#define USB_TXCSR_ISO (0x40) -+#define USB_TXCSR_MODE1 (0x20) -+#define USB_TXCSR_DMAREQENABLE (0x10) -+#define USB_TXCSR_FRCDATATOG (0x8) -+#define USB_TXCSR_DMAREQMODE1 (0x4) -+#define USB_TXCSR_DMAREQMODE0 (0x0) -+ -+struct akudc_request; -+ -+/* the struct of endpoint for Anyka udc */ -+struct akudc_ep { -+ struct usb_ep ep; /* the basic endpoint */ -+ struct usb_gadget *gadget; /* the gadget for udc */ -+ struct usb_endpoint_descriptor *desc; /* the descriptor for this endpoint */ -+ -+ struct list_head queue; /* the queue head for request of this endpoint */ -+ -+ struct work_struct work; -+ struct akudc_request *req; /* req be about to handle */ -+ -+ struct akudc_udc *udc; /* the udc struct */ -+ int maxpacket; -+ volatile int done; /* whether the current request is complete */ -+ unsigned int bufaddr; -+ dma_addr_t bufphys; -+ -+ unsigned irq_enable; /* whether the endpoint cpu irq is enable */ -+ volatile unsigned stopped; /*whether the endpoint is stopped */ -+ // unsigned stopped:1; -+ unsigned is_in:1; /* whether the endpoint is in */ -+ unsigned is_iso:1; -+ // unsigned fifo_bank:1; -+ u8 l2_buf_id; /* the l2 buffer id for this endpoint */ -+}; -+ -+struct akudc_request { -+ struct list_head queue; /* ep's requests */ -+ struct usb_request req; -+ int status; -+}; -+ -+/* the status flag for ep0 Control SETUP Transaction */ -+enum ep0_status { -+ EP0_IDLE, -+ EP0_IN_DATA_PHASE, -+ EP0_OUT_DATA_PHASE, -+ EP0_END_XFER, -+ EP0_STALL, -+}; -+#if 0 -+static const char *ep0states[]= { -+ "EP0_IDLE", -+ "EP0_IN_DATA_PHASE", -+ "EP0_OUT_DATA_PHASE", -+ "EP0_END_XFER", -+ "EP0_STALL", -+}; -+#endif -+struct usb_l2 { -+ void *buf; -+ dma_addr_t phys; -+}; -+ -+static const char * const ep_name[] = { -+ "ep0", -+ "ep1-int", -+ "ep2in-bulk", -+ "ep3out-bulk", -+ "ep4in-bulk", -+ "ep5out-bulk", -+}; -+ -+#define ENDPOINTS_NUM ARRAY_SIZE(ep_name) -+ -+struct akudc_udc { -+ struct usb_gadget gadget; /* the core struct for anyka udc */ -+ struct usb_gadget_driver *driver; /* the core struct for function drivers */ -+ -+ struct akudc_ep ep[ENDPOINTS_NUM]; /* the endpoints for udc */ -+ enum ep0_status ep0_status; -+ -+ void __iomem *baseaddr; -+ -+ unsigned int mcu_irq; /* the irq for cpu irq */ -+ unsigned int dma_irq; /* the irq for l2 dma irq */ -+ struct clk *clk; /* the clk for udc */ -+ char addr; /* assigned device address */ -+ u16 devstatus; -+ int ep0state; /* the status flag for ep0 Control SETUP Transaction */ -+ unsigned req_std : 1; -+ unsigned req_config : 1; -+ unsigned req_pending : 1; -+ unsigned high_speed: 1; -+ struct proc_dir_entry *pde; -+}; -+ -+ -+/* usb dosen't have vbus and id pin,so these bit must be set */ -+static inline void set_usb_as_slave(void) -+{ -+ unsigned long con; -+ -+ con = __raw_readl(USB_OP_MOD_REG); -+ con &= ~(0xff << 6); -+ con |= ((0x3 << 12)|(0x17 << 6)); -+ __raw_writel(con, USB_OP_MOD_REG); -+} -+ -+static inline void usb_vbus_wakeup(int enable) -+{ -+#if defined (CONFIG_ARCH_AK37) -+ /* open usb detect */ -+ if(enable) { -+ REG32(AK_VA_SYSCTRL + 0xd8) &= ~(1 << 0); //falling-trig -+ -+ REG32(AK_VA_SYSCTRL + 0xd8) |= (1 << 2); //clear usb det -+ REG32(AK_VA_SYSCTRL + 0xd8) &= ~(1 << 2); -+ -+ REG32(AK_VA_SYSCTRL + 0xd8) |= (1 << 4); //enable usb detect -+ } else { -+ REG32(AK_VA_SYSCTRL + 0xd8) |= (1 << 2); //clear usb det -+ REG32(AK_VA_SYSCTRL + 0xd8) &= ~(1 << 2); -+ -+ REG32(AK_VA_SYSCTRL + 0xd8) &= ~(1 << 4); //disable usb detect -+ } -+#endif -+} -+ -+static void udc_reg_writel(unsigned long __iomem *__reg, -+ unsigned long value, int bits, int index); -+//static unsigned long udc_reg_readl(unsigned long __iomem *__reg, -+// int bits, int index); -+ -+static void udc_reinit(struct akudc_udc *udc); -+static void akudc_enable(struct akudc_udc *udc); -+static void akudc_disable(struct akudc_udc *udc); -+static void done(struct akudc_ep *ep, struct akudc_request *req, int status); -+ -+#endif /* __UDC_H__ */ -diff --git a/include/plat-anyka/usb-hc.h b/include/plat-anyka/usb-hc.h -new file mode 100755 -index 00000000..5294651c ---- /dev/null -+++ b/include/plat-anyka/usb-hc.h -@@ -0,0 +1,900 @@ -+#ifndef _ANYKA_USB_HC_H_ -+#define _ANYKA_USB_HC_H_ -+ -+ -+#include <linux/usb.h> -+#include <linux/platform_device.h> -+#include <asm/io.h> -+#include <plat/l2.h> -+ -+#include <mach/map.h> -+#include <mach/gpio.h> -+#include "usb-reg-define.h" -+ -+#include "otg-hshcd.h" -+ -+#define DYNAMIC_EPFIFO -+#define MAX_EP_NUM (5) -+#define USBDMA_CHANNEL_NUM (4) -+ -+#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */ -+#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE) -+ -+ /* usb 1.1 says max 90% of a frame is available for periodic transfers. -+ * this driver doesn't promise that much since it's got to handle an -+ * IRQ per packet; irq handling latencies also use up that time. -+ * -+ * NOTE: the periodic schedule is a sparse tree, with the load for -+ * each branch minimized. see fig 3.5 in the OHCI spec for example. -+ */ -+#define MAX_PERIODIC_LOAD 500 /* out of 1000 usec */ -+ -+ /*-------------------------------------------------------------------------*/ -+ -+ /*Common Registers Access - Just use base address plus offset */ -+ -+ static DEFINE_SPINLOCK(USB_HC_REG_LOCK); -+ -+#define hc_readb(reg) __raw_readb(USB_HC_BASE_ADDR + (reg)) -+#define hc_writeb(val, reg) __raw_writeb(val, USB_HC_BASE_ADDR + (reg)) -+ -+#define hc_readw(reg) __raw_readw(USB_HC_BASE_ADDR + (reg)) -+#define hc_writew(val, reg) __raw_writew(val, USB_HC_BASE_ADDR + (reg)) -+ -+#define hc_readl(reg) __raw_readl(USB_HC_BASE_ADDR + (reg)) -+#define hc_writel(val, reg) __raw_writel(val, USB_HC_BASE_ADDR + (reg)) -+ -+ struct akotghc_ep { -+ struct usb_host_endpoint *hep; -+ struct usb_device *udev; -+ -+ u16 maxpacket; -+ u8 epnum; -+ u8 epfifo; -+ u8 nextpid; -+ -+ u16 error_count; -+ u16 nak_count; -+ u16 length; /* of current packet */ -+ -+ bool bdma; -+ -+ /* periodic schedule */ -+ u16 period; -+ u16 branch; -+ u16 load; -+ struct akotghc_ep *next; -+ -+ /* async schedule */ -+ struct list_head schedule; -+ }; -+ -+/** -+ struct for usb dma channel -+ */ -+ struct akotg_dma -+ { -+ u8 channel; //channel num -+ u8 status; //channel status -+ u8 dir; //transfer direction, -+ u8 epfifo; //dma is bind to which usb ep fifo -+ u8 l2buffer; //l2 buffer which is bind to ep fifo -+ u32 addr; //inner addr for dma, start with 0x70000000 -+ u32 count; //dma count -+ u32 phyaddr; //phycical address for dma -+ }; -+ -+ struct akotg_usbhc { -+ spinlock_t lock; -+ -+ struct clk *clk; -+ -+ /* sw model */ -+ struct timer_list timer; -+ struct akotghc_ep *next_periodic; -+ struct akotghc_ep *next_async_ep0; -+ struct akotghc_ep *next_async_epx[MAX_EP_NUM]; -+ -+ struct akotghc_ep *active_ep0; -+ struct akotghc_ep *active_epx[MAX_EP_NUM]; -+ unsigned long jiffies_ep0; -+ unsigned long jiffies_epx[MAX_EP_NUM]; -+ -+ int mcu_irq; -+ -+ //dma -+ int dma_irq; //irq alloced for dma -+ struct akotg_dma dma_channel[USBDMA_CHANNEL_NUM]; -+ -+ u32 port_status; -+ u16 frame; -+ -+ /* async schedule: control, bulk */ -+ struct list_head async_ep0; -+ struct list_head async_epx[MAX_EP_NUM]; -+ -+ /* periodic schedule: interrupt, iso */ -+ u16 load[PERIODIC_SIZE]; -+ struct akotghc_ep *periodic[PERIODIC_SIZE]; -+ unsigned periodic_count; -+ }; -+ -+ -+ struct epfifo_mapping { -+ int epfifo; /* AKOTG HC EP FIFO number: 1 ~ 6 */ -+ int used; /* 0 - Unused, 1 - used */ -+ int epnum; /* USB Device endpoint number: 1 ~ 16 */ -+ int direction; /* 0 - In, 1 - Out */ -+}; -+ -+struct akotghc_epfifo_mapping { -+ spinlock_t lock; -+ struct epfifo_mapping mapping[MAX_EP_NUM]; -+}; -+ -+/** -+ enum for DMA channel status -+ */ -+enum -+{ -+ USB_DMA_CHANNEL_IDLE, //idle -+ USB_DMA_CHANNEL_ALLOC, //alloced for a specific ep fifo but not under tranfering -+ USB_DMA_CHANNEL_TRANS //there is a dma tranfering in this channel -+}; -+ -+irqreturn_t akotg_usbhc_irq(struct usb_hcd *hcd); -+irqreturn_t akotg_dma_irq(int irqnum, void *__hcd); -+ -+int akotg_usbhc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); -+int akotg_usbhc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); -+void akotg_usbhc_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *hep); -+void akotg_usbhc_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep); -+int akotg_usbhc_get_frame(struct usb_hcd *hcd); -+int akotg_usbhc_hub_status_data(struct usb_hcd *hcd, char *buf); -+void akotg_usbhc_hub_descriptor (struct akotg_usbhc *akotghc, struct usb_hub_descriptor *desc); -+void akotg_usbhc_timer(unsigned long _akotghs); -+int akotg_usbhc_hub_control( -+ struct usb_hcd *hcd, -+ u16 typeReq, -+ u16 wValue, -+ u16 wIndex, -+ char *buf, -+ u16 wLength -+); -+ -+int akotg_usbhc_bus_suspend(struct usb_hcd *hcd); -+int akotg_usbhc_bus_resume(struct usb_hcd *hcd); -+void akotg_usbhc_stop(struct usb_hcd *hcd); -+int akotg_usbhc_start(struct usb_hcd *hcd); -+ -+void port_power(struct akotg_usbhc *akotghc, int is_on); -+ -+static inline struct akotg_usbhc *hcd_to_akotg_usbhc(struct usb_hcd *hcd) -+{ -+ return (struct akotg_usbhc *) (hcd->hcd_priv); -+} -+ -+static inline struct usb_hcd *akotg_usbhc_to_hcd(struct akotg_usbhc *akotghc) -+{ -+ return container_of((void *) akotghc, struct usb_hcd, hcd_priv); -+} -+ -+ -+/* -+ * Part II: Index Registers Access - Spinlock+IRQ protection -+ */ -+//static DEFINE_SPINLOCK(fsh_reg_lock); -+ -+static inline unsigned char hc_index_readb(int epindex, int reg) -+{ -+ unsigned long flags; -+ unsigned char val; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(epindex, USB_REG_INDEX); -+ val = hc_readb(reg); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+ -+ return val; -+} -+ -+static inline void hc_index_writeb(int epindex, unsigned char val, int reg) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(epindex, USB_REG_INDEX); -+ hc_writeb(val, reg); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+} -+ -+static inline unsigned short hc_index_readw(int epindex, int reg) -+{ -+ unsigned long flags; -+ unsigned short val; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(epindex, USB_REG_INDEX); -+ val = hc_readw(reg); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+ -+ return val; -+ -+} -+ -+static inline void hc_index_writew(int epindex, unsigned short val, int reg) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(epindex, USB_REG_INDEX); -+ hc_writew(val, reg); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+} -+ -+static inline unsigned long hc_index_readl(int epindex, int reg) -+{ -+ unsigned long flags; -+ unsigned long val; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(epindex, USB_REG_INDEX); -+ val = hc_readl(reg); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+ -+ return val; -+} -+ -+static inline void hc_index_writel(int epindex, unsigned long val, int reg) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(epindex, USB_REG_INDEX); -+ hc_writel(val, reg); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+ -+} -+static inline void flush_ep0_fifo(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(0, USB_REG_INDEX); -+ if (hc_readb(USB_REG_TXCSR1) & (USB_CSR01_RXPKTRDY | USB_CSR01_TXPKTRDY)) -+ hc_writeb(USB_CSR02_FLUSHFIFO, USB_REG_TXCSR2); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+} -+ -+static inline void flush_epx_tx_fifo(int i) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(i, USB_REG_INDEX); -+ if (hc_readb(USB_REG_TXCSR1) & (USB_CSR01_RXPKTRDY)) -+ hc_writeb(USB_TXCSR1_FLUSHFIFO, USB_REG_TXCSR1); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+ -+} -+ -+static inline void flush_epx_rx_fifo(int i) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(i, USB_REG_INDEX); -+ if (hc_readb(USB_REG_RXCSR1) & (USB_RXCSR1_RXPKTRDY)) -+ hc_writeb(USB_RXCSR1_FLUSHFIFO, USB_REG_RXCSR1); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+} -+ -+static inline void flush_epx_fifo(int i) -+{ -+ flush_epx_tx_fifo(i); -+ flush_epx_rx_fifo(i); -+} -+ -+static inline void flush_ep_fifo(int i) -+{ -+ if (i == 0) -+ flush_ep0_fifo(); -+ else -+ flush_epx_fifo(i); -+} -+ -+static inline void set_epx_rx_mode(int i) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(i, USB_REG_INDEX); -+ regval = hc_readb(USB_REG_TXCSR2); -+ regval &= ~USB_TXCSR2_MODE; -+ hc_writeb(regval, USB_REG_TXCSR2); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+} -+ -+static inline void set_epx_tx_mode(int i) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&USB_HC_REG_LOCK, flags); -+ -+ hc_writeb(i, USB_REG_INDEX); -+ regval = hc_readb(USB_REG_TXCSR2); -+ regval |= USB_TXCSR2_MODE; -+ hc_writeb(regval, USB_REG_TXCSR2); -+ -+ spin_unlock_irqrestore(&USB_HC_REG_LOCK, flags); -+} -+ -+static inline void clear_epx_tx_data_toggle(int i) -+{ -+ hc_index_writeb(i, USB_TXCSR1_CLRDATATOG, USB_REG_TXCSR1); -+ //hc_index_writeb(i, USB_RXCSR2_DMAREQENAB, USB_REG_TXCSR2); //??? -+} -+ -+static inline void clear_epx_rx_data_toggle(int i) -+{ -+ hc_index_writeb(i, USB_RXCSR1_CLRDATATOG, USB_REG_RXCSR1); -+} -+ -+/* -+ * Valid types: -+ * 1 - Isochronous -+ * 2 - Bulk -+ * 3 - Interrupt -+ * Invalid type: -+ * 0 - Illegal -+ */ -+static inline void set_epx_tx_type(int i, int epnum, int type) -+{ -+ BUG_ON(i < 0 || i > MAX_EP_NUM); -+ BUG_ON(type < 0 || type > 3); -+ -+ hc_index_writeb(i, type << 4 | epnum, USB_REG_TXTYPE); -+} -+ -+static inline void set_epx_rx_type(int i, int epnum, int type) -+{ -+ BUG_ON(i < 0 || i > MAX_EP_NUM); -+ BUG_ON(type < 0 || type > 3); -+ -+ hc_index_writeb(i, type << 4 | epnum, USB_REG_RXTYPE); -+} -+ -+static inline void enable_ep0_interrupt(void) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = hc_readb(USB_REG_INTRTXE); -+ regval |= USB_INTR_EP0; -+ hc_writeb(regval, USB_REG_INTRTXE); -+ -+ local_irq_restore(flags); -+} -+ -+static inline void enable_epx_tx_interrupt(int i) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = hc_readb(USB_REG_INTRTXE); -+ regval |= (1 << i); -+ hc_writeb(regval, USB_REG_INTRTXE); -+ -+ local_irq_restore(flags); -+} -+ -+static inline void enable_epx_rx_interrupt(int i) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = hc_readb(USB_REG_INTRRXE); -+ regval |= (1 << i); -+ hc_writeb(regval, USB_REG_INTRRXE); -+ -+ local_irq_restore(flags); -+} -+ -+static inline void disable_ep0_interrupt(void) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = hc_readb(USB_REG_INTRTXE); -+ regval &= ~USB_INTR_EP0; -+ hc_writeb(regval, USB_REG_INTRTXE); -+ -+ local_irq_restore(flags); -+} -+ -+static inline void disable_epx_tx_interrupt(int i) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = hc_readb(USB_REG_INTRTXE); -+ regval &= ~(1 << i); -+ hc_writeb(regval, USB_REG_INTRTXE); -+ -+ local_irq_restore(flags); -+} -+ -+static inline void disable_epx_rx_interrupt(int i) -+{ -+ u8 regval; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ regval = hc_readb(USB_REG_INTRRXE); -+ regval &= ~(1 << i); -+ hc_writeb(regval, USB_REG_INTRRXE); -+ -+ local_irq_restore(flags); -+} -+ -+static inline void disable_epx_interrupt(int i) -+{ -+ disable_epx_tx_interrupt(i); -+ disable_epx_rx_interrupt(i); -+} -+ -+static inline void disable_ep_interrupt(int i) -+{ -+ BUG_ON(i < 0 || i > MAX_EP_NUM); -+ -+ if (i == 0) { -+ disable_ep0_interrupt(); -+ } else { -+ disable_epx_interrupt(i); -+ } -+} -+ -+static inline void clear_all_interrupts(void) -+{ -+ hc_writeb(0x0, USB_REG_INTRUSBE); -+ hc_writew(0x0, USB_REG_INTRTXE); -+ hc_writew(0x0, USB_REG_INTRRXE); -+ -+ hc_readb(USB_REG_INTRUSB); -+ hc_readw(USB_REG_INTRTX); -+ hc_readw(USB_REG_INTRRX); -+} -+ -+static inline void reset_endpoint(int i) -+{ -+ BUG_ON(i < 0 || i > MAX_EP_NUM); -+ -+ disable_ep_interrupt(i); -+ if (i == 0) { -+ flush_ep0_fifo(); -+ } else { -+ flush_epx_fifo(i); -+ set_epx_rx_type(i, 0, 0); -+ set_epx_tx_type(i, 0, 0); -+ } -+} -+ -+static inline void reset_endpoints(void) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_EP_NUM + 1; i++) { -+ reset_endpoint(i); -+ } -+} -+ -+ -+static inline u8 akotg_alloc_l2_buffer(int epfifo) -+{ -+ l2_device_t l2addr[] = {ADDR_USB_EP2, ADDR_USB_EP3, ADDR_USB_EP4, ADDR_USB_EP5}; -+ -+ //check param -+ if((epfifo < 2) || (epfifo > MAX_EP_NUM)) -+ return BUF_NULL; -+ -+ //alloc l2 buffer -+ return l2_alloc_nowait(l2addr[epfifo-2]); -+} -+ -+static inline void akotg_free_l2_buffer(int epfifo) -+{ -+ l2_device_t l2addr[] = {ADDR_USB_EP2, ADDR_USB_EP3, ADDR_USB_EP4, ADDR_USB_EP5}; -+ -+ //check param -+ if((epfifo < 2) || (epfifo > MAX_EP_NUM)) -+ return; -+ -+ //alloc l2 buffer -+ l2_free(l2addr[epfifo-2]); -+} -+ -+ -+ -+static inline void akotg_dma_init(struct akotg_usbhc *otg) -+{ -+ int i; -+ -+ memset(otg->dma_channel, 0, sizeof(otg->dma_channel)); -+ -+ for(i = 0; i < USBDMA_CHANNEL_NUM; i++) -+ { -+ otg->dma_channel[i].channel = i; -+ otg->dma_channel[i].status = USB_DMA_CHANNEL_IDLE; -+ otg->dma_channel[i].l2buffer = BUF_NULL; -+ } -+} -+ -+ -+/** -+ config dma register -+*/ -+static inline bool akotg_dma_config(struct akotg_dma *dma) -+{ -+ u8 channel = dma->channel; -+ u8 dir = dma->dir; -+ u8 epfifo = dma->epfifo; -+ -+ u32 dmactrl; -+ -+ -+ //config dma address and count -+ hc_writel(dma->addr, USB_DMA_ADDR(channel)); -+ hc_writel(dma->count, USB_DMA_COUNT(channel)); -+ -+ //config dma control -+ dmactrl = (USB_ENABLE_DMA|dir|USB_DMA_MODE1|USB_DMA_INT_ENABLE|(epfifo <<4)|USB_DMA_BUS_MODE3); -+ hc_writel(dmactrl, USB_DMA_CTRL(channel)); -+ -+ dma->status = USB_DMA_CHANNEL_TRANS; -+ -+ return true; -+} -+ -+ -+/** -+ config dma struct -+*/ -+static inline bool akotg_dma_set_struct(struct akotg_dma *dma, u8 dir, u8 epfifo, u8 l2buffer, u32 count, dma_addr_t phyaddr) -+{ -+ if((epfifo < 2) || (epfifo > MAX_EP_NUM)) -+ return false; -+ -+ dma->dir = dir; -+ dma->count = count; -+ dma->epfifo = epfifo; -+ dma->l2buffer = l2buffer; -+ -+ //config dma addr -+ dma->addr = 0x70000000 + 0x1000000*(epfifo-2); -+ dma->phyaddr = phyaddr; -+ -+ return true; -+} -+ -+ -+ -+/** -+ alloc dma channel for epfifo -+*/ -+static inline struct akotg_dma * akotg_dma_alloc(struct akotg_usbhc *otg, u8 epfifo) -+{ -+ struct akotg_dma *dma; -+ u8 l2buffer; -+ -+ if((epfifo < 2) || (epfifo > MAX_EP_NUM)) -+ return NULL; -+ -+ //alloc dma channel, do simple now, -+ //we'll complete it later -+ dma = &otg->dma_channel[epfifo-2]; -+ if(dma->status != USB_DMA_CHANNEL_IDLE){ -+ return NULL; -+ } -+ -+ //alloc l2 buffer -+ l2buffer = akotg_alloc_l2_buffer(epfifo); -+ if(BUF_NULL == l2buffer){ -+ return NULL; -+ } -+ -+ //printk("<%d:%d>\n", epfifo, l2buffer); -+ -+ dma->status = USB_DMA_CHANNEL_ALLOC; -+ dma->l2buffer = l2buffer; -+ -+ return dma; -+} -+ -+/** -+ get dma struct for channel i -+*/ -+static inline struct akotg_dma *akotg_dma_get_struct(struct akotg_usbhc *otg, u8 channel) -+{ -+ if(channel > USBDMA_CHANNEL_NUM) -+ return NULL; -+ -+ return &otg->dma_channel[channel]; -+} -+ -+/** -+ the usb dma trans will be stopped if a short packet is received, -+ we can use this func to check the real number of data been received -+*/ -+static inline u32 akotg_dma_get_trans_length(struct akotg_usbhc *otg, u8 epfifo) -+{ -+ int i; -+ struct akotg_dma *dma; -+ u32 addr; -+ -+ for(i = 0; i < USBDMA_CHANNEL_NUM; i++) -+ { -+ dma = &otg->dma_channel[i]; -+ -+ if((dma->epfifo == epfifo) && (dma->status == USB_DMA_CHANNEL_TRANS)) -+ { -+ addr = hc_readl(USB_DMA_ADDR(dma->channel)); -+ return (addr - dma->addr); -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+ clear dma, -+ epfifo: 0-clear all, >0 clear dma for epfifo -+*/ -+static inline void akotg_dma_clear(struct akotg_usbhc *otg, u8 epfifo) -+{ -+ int i; -+ struct akotg_dma *dma; -+ -+ for(i = 0; i < USBDMA_CHANNEL_NUM; i++) -+ { -+ dma = &otg->dma_channel[i]; -+ -+ if((epfifo != 0) && (dma->epfifo != epfifo)){ -+ continue; -+ } -+ -+ if(dma->l2buffer != BUF_NULL) -+ { -+ //l2 free -+ akotg_free_l2_buffer(dma->epfifo); -+ } -+ -+ hc_writel(0, USB_DMA_CTRL(i)); -+ -+ dma->status = USB_DMA_CHANNEL_IDLE; -+ dma->l2buffer = BUF_NULL; -+ } -+ -+ -+} -+ -+static inline void init_epfifo_mapping(struct akotghc_epfifo_mapping *akotg_mapping) -+{ -+ int i; -+ struct epfifo_mapping *mapping; -+ -+ spin_lock_init(&akotg_mapping->lock); -+ -+ for (i = 0; i < MAX_EP_NUM; i++) { -+ mapping = &akotg_mapping->mapping[i]; -+ mapping->epfifo = i + 1; /* EPFIFO 1~MAX_EP_NUM is used by AKOTG HS HCD */ -+ mapping->used = 0; -+ mapping->epnum = 0; -+ mapping->direction = 0; -+ } -+} -+ -+static inline bool __is_epnum_mapped( -+ struct akotghc_epfifo_mapping *akotg_mapping, int epnum, int direction) -+{ -+ int i; -+ struct epfifo_mapping *mapping; -+ -+ if(epnum == 0) -+ return true; -+ -+ for (i = 0; i < MAX_EP_NUM; i++) { -+ mapping = &akotg_mapping->mapping[i]; -+ if (mapping->used -+ && (mapping->epnum == epnum) -+ && (mapping->direction == direction)) { -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static inline bool is_epnum_mapped(struct akotghc_epfifo_mapping *akotg_mapping, -+ int epnum, int direction) -+{ -+ bool ret; -+ unsigned long flags; -+ -+ BUG_ON(akotg_mapping == NULL); -+ -+ if(epnum == 0) -+ return true; -+ -+ spin_lock_irqsave(&akotg_mapping->lock, flags); -+ -+ ret = __is_epnum_mapped(akotg_mapping, epnum, direction); -+ -+ spin_unlock_irqrestore(&akotg_mapping->lock, flags); -+ -+ return ret; -+ -+} -+ -+static inline bool __map_epnum_to_epfifo( -+ struct akotghc_epfifo_mapping *akotg_mapping, -+ int epnum, int direction, int *epfifo) -+{ -+ int i; -+ struct epfifo_mapping *mapping; -+ -+ if (__is_epnum_mapped(akotg_mapping, epnum, direction)) -+ return false; -+ -+ //allocate 512 byte size of filo to epnum -+ for (i = 1; i < MAX_EP_NUM; i++) { -+ mapping = &akotg_mapping->mapping[i]; -+ if (!mapping->used) { -+ mapping->used = 1; -+ mapping->epnum = epnum; -+ mapping->direction = direction; -+ *epfifo = mapping->epfifo; -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static inline bool map_epnum_to_epfifo(struct akotghc_epfifo_mapping *akotg_mapping, -+ int epnum, int direction, int *epfifo) -+{ -+ bool ret; -+ unsigned long flags; -+ -+ BUG_ON(akotg_mapping == NULL); -+ -+ if (is_epnum_mapped(akotg_mapping, epnum, direction)) -+ return false; -+ -+ spin_lock_irqsave(&akotg_mapping->lock, flags); -+ -+ ret = __map_epnum_to_epfifo(akotg_mapping, epnum, direction, epfifo); -+ -+ spin_unlock_irqrestore(&akotg_mapping->lock, flags); -+ -+ return ret; -+} -+ -+static inline bool epfifo_to_epnum(struct akotghc_epfifo_mapping *akotg_mapping, int epfifo, int *epnum, int *direction) -+{ -+ int ret; -+ unsigned long flags; -+ struct epfifo_mapping *mapping; -+ -+ ret = false; -+ -+ spin_lock_irqsave(&akotg_mapping->lock, flags); -+ -+ mapping = &akotg_mapping->mapping[epfifo]; -+ if (mapping->used) { -+ *epnum = mapping->epnum; -+ *direction = mapping->direction; -+ ret = true; -+ } else { -+ *epnum = 0; -+ *direction = 0; -+ ret = false; -+ } -+ -+ spin_unlock_irqrestore(&akotg_mapping->lock, flags); -+ -+ return ret; -+} -+ -+static inline bool epnum_to_epfifo(struct akotghc_epfifo_mapping *akotg_mapping, int epnum, int direction, int *epfifo) -+{ -+ int i; -+ unsigned long flags; -+ struct epfifo_mapping *mapping; -+ -+ if (epnum == 0) { -+ *epfifo = 0; -+ return true; -+ } -+ -+ spin_lock_irqsave(&akotg_mapping->lock, flags); -+ -+ for (i = 0; i < MAX_EP_NUM; i++) { -+ mapping = &akotg_mapping->mapping[i]; -+ if (mapping->used && (mapping->epnum == epnum) && (mapping->direction == direction)) { -+ *epfifo = mapping->epfifo; -+ spin_unlock_irqrestore(&akotg_mapping->lock, flags); -+ return true; -+ } -+ } -+ -+ spin_unlock_irqrestore(&akotg_mapping->lock, flags); -+ -+ return false; -+} -+ -+static inline void set_usb_as_host(void) -+{ -+ unsigned long con; -+ -+ con = __raw_readl(USB_OP_MOD_REG); -+ con &= ~(0xff << 6); -+ con |= (0x1 << 12)|(0x1f << 6); -+ __raw_writel(con, USB_OP_MOD_REG); -+} -+ -+static inline void usb_reset_phy(struct akotg_usbhc *otghc) -+{ -+ unsigned long con; -+ -+ con = __raw_readl(USB_OP_MOD_REG); -+ con &= ~(0x7 << 0); -+ con |= (1 << 0); -+ __raw_writel(con, USB_OP_MOD_REG); -+} -+ -+/* power up and set usb suspend */ -+static inline void usb_power_up(struct akotg_usbhc *otghc) -+{ -+ unsigned long con; -+ -+ con = __raw_readl(USB_OP_MOD_REG); -+ con &= ~(0x7 << 0); -+ con |= (3 << 1); -+ __raw_writel(con, USB_OP_MOD_REG); -+} -+ -+#endif -diff --git a/include/plat-anyka/usb-reg-define.h b/include/plat-anyka/usb-reg-define.h -new file mode 100755 -index 00000000..3b8779ad ---- /dev/null -+++ b/include/plat-anyka/usb-reg-define.h -@@ -0,0 +1,262 @@ -+#ifndef _ANYKA_USB_REG_DEFINE_H_ -+#define _ANYKA_USB_REG_DEFINE_H_ -+ -+ /** Control Registers*/ -+#define USB_REG_FADDR (0x0000) // 8-bit -+#define USB_REG_POWER (0x0001) // 8-bit -+#define USB_REG_INTRTX (0x0002) // 16-bit, read clear -+#define USB_REG_INTRRX (0x0004) // 16-bit, read clear -+#define USB_REG_INTRTXE (0x0006) // 16-bit -+#define USB_REG_INTRRXE (0x0008) // 16-bit -+#define USB_REG_INTRUSB (0x000A) // 8-bit, read clear -+#define USB_REG_INTRUSBE (0x000B) // 8-bit -+#define USB_REG_FRAME (0x000C) // 16-bit -+#define USB_REG_INDEX (0x000E) // 8-bit -+#define USB_REG_TESEMODE (0x000F) // 8-bit -+#define USB_REG_DEVCTL (0x0060) // 8-bit -+ -+/** Endpoint Control/Status Registers */ -+#define USB_REG_TXMAXP (0x0010) // 16-bit, when index == 1~4 -+#define USB_REG_TXCSR1 (0x0012) // 8-bit, when index == 1~4 -+#define USB_REG_TXCSR2 (0x0013) // 8-bit, when index == 1~4 -+#define USB_REG_RXMAXP (0x0014) // 16-bit, when index == 1~4 -+#define USB_REG_RXCSR1 (0x0016) // 8-bit, when index == 1~4 -+#define USB_REG_RXCSR2 (0x0017) // 8-bit, when index == 1~4 -+#define USB_REG_COUNT0 (0x0018) // 16-bit, when index == 0 -+#define USB_REG_RXCOUNT (0x0018) // 16-bit, when index == 1~4 -+#define USB_REG_TXTYPE (0x001A) // 8-bit, when index == 1~4, host only -+#define USB_REG_NAKLIMIT0 (0x001B) // 8-bit, when index == 0, host only -+#define USB_REG_TXINTERVAL (0x001B) // 8-bit, when index == 1~4, host only -+#define USB_REG_RXTYPE (0x001C) // 8-bit, when index == 1~4, host only -+#define USB_REG_RXINTERVAL (0x001D) // 8-bit, when index == 1~4, host only -+#define USB_REG_CONFIGDATA (0x001F) // 8-bit, when index == 0 -+#define USB_REG_FIFOSIZE (0x001F) // 8-bit, when index == 1~4 -+ -+/** USB DMA */ -+#define USB_DMA_INTR (0x0200) -+#define USB_DMA_CTRL_BASE (0x0204) -+#define USB_DMA_ADDR_BASE (0x0208) -+#define USB_DMA_COUNT_BASE (0x020c) -+#define USB_DMA_CTRL(n) (USB_DMA_CTRL_BASE+(n)*0x10) -+#define USB_DMA_ADDR(n) (USB_DMA_ADDR_BASE+(n)*0x10) -+#define USB_DMA_COUNT(n) (USB_DMA_COUNT_BASE+(n)*0x10) -+ -+#define USB_REG_REQPKTCNT_BASE (0x0304) -+#define USB_REG_REQPKTCNT(ep) (USB_REG_REQPKTCNT_BASE + (ep-1)*0x4) -+ -+/** FIFOs Entry */ -+#define USB_FIFO_EP0 (0x0020) // 8- / 16- / 32-bit -+#define USB_FIFO_EP1 (0x0024) // 8- / 16- / 32-bit -+#define USB_FIFO_EP2 (0x0028) // 8- / 16- / 32-bit -+#define USB_FIFO_EP3 (0x002C) // 8- / 16- / 32-bit -+#define USB_FIFO_EP4 (0x0030) // 8- / 16- / 32-bit -+#define USB_FIFO_EP5 (0x0034) // 8- / 16- / 32-bit -+ -+/*DMA controler registers.*/ -+#define DMA_INTR_STAT 0x0 /*DMA interrupt status.*/ -+ -+#define DMA_CTRL_REG1 0x04 /*DMA channel 1 control.*/ -+#define DMA_CTRL_REG2 0x14 /*DMA channel 2 control.*/ -+#define DMA_CTRL_REG3 0x24 /*DMA channel 3 control.*/ -+#define DMA_CTRL_REG4 0x34 /*DMA channel 4 control.*/ -+ -+#define DMA_ADDR_REG1 0x08 /*DMA channel 1 AHB memory address.*/ -+#define DMA_ADDR_REG2 0x18 /*DMA channel 2 AHB memory address.*/ -+#define DMA_ADDR_REG3 0x28 /*DMA channel 3 AHB memory address.*/ -+#define DMA_ADDR_REG4 0x38 /*DMA channel 4 AHB memory address.*/ -+ -+#define DMA_CUNT_REG1 0x0c /*DMA channel 1 byte count.*/ -+#define DMA_CUNT_REG2 0x1c /*DMA channel 2 byte count.*/ -+#define DMA_CUNT_REG3 0x2c /*DMA channel 3 byte count.*/ -+#define DMA_CUNT_REG4 0x3c /*DMA channel 4 byte count.*/ -+ -+ -+//********************** bit fields defs*********************** -+ -+#define USB_ENABLE_DMA (1) -+#define USB_DIRECTION_RX (0<<1) -+#define USB_DIRECTION_TX (1<<1) -+#define USB_DMA_MODE1 (1<<2) -+#define USB_DMA_MODE0 (0<<2) -+#define USB_DMA_INT_ENABLE (1<<3) -+#define USB_DMA_INT_DISABLE (0<<3) -+#define USB_DMA_BUS_ERROR (1<<8) -+#define USB_DMA_BUS_MODE0 (0<<9) -+#define USB_DMA_BUS_MODE1 (1<<9) -+#define USB_DMA_BUS_MODE2 (2<<9) -+#define USB_DMA_BUS_MODE3 (3<<9) -+ -+// RTC_USB_CONFIG_REG -+#define SESSEND (1 << 31) // 0:above/1:below Session End threshold -+#define AVALID (1 << 30) -+#define VBUSVALID (1 << 29) -+#define SESSEND_SEL (1 << 28) -+#define AVALID_SEL (1 << 27) -+#define VBUSVALID_SEL (1 << 26) -+ -+ -+/** POWER Control register */ -+#define USB_POWER_ENSUSPEND (1 << 0) -+#define USB_POWER_SUSPENDM (1 << 1) // host/client -+#define USB_POWER_RESUME (1 << 2) // host/client -+#define USB_POWER_RESET (1 << 3) -+#define USB_HOSG_HIGH_SPEED (1 << 5) -+ -+ /** CSR01 register */ -+ // mode-agnostic -+#define USB_CSR01_RXPKTRDY (1 << 0) // r / clear -+#define USB_CSR01_TXPKTRDY (1 << 1) // r / set -+ // Client mode -+#define USB_CSR01_P_SENTSTALL (1 << 2) -+#define USB_CSR01_P_DATAEND (1 << 3) -+#define USB_CSR01_P_SETUPEND (1 << 4) -+#define USB_CSR01_P_SENDSTALL (1 << 5) -+#define USB_CSR01_P_SVDRXPKTRDY (1 << 6) -+#define USB_CSR01_P_SVDSETUPEND (1 << 7) -+ // Host mode -+#define USB_CSR01_H_RXSTALL (1 << 2) // r / clear -+#define USB_CSR01_H_SETUPPKT (1 << 3) // r / w -+#define USB_CSR01_H_ERROR (1 << 4) // r / clear -+#define USB_CSR01_H_REQPKT (1 << 5) // r / w -+#define USB_CSR01_H_STATUSPKT (1 << 6) // r / w -+#define USB_CSR01_H_NAKTIMEOUT (1 << 7) // r / clear -+ -+ /** CSR02 register */ -+ // mode-agnostic -+#define USB_CSR02_FLUSHFIFO (1 << 0) // set -+ // Client mode (none) -+ // Host mode -+#define USB_CSR02_H_DISPING (1 << 3) // r / w -+ -+ -+ /** TXCSR1 register */ -+ // mode-agnostic -+#define USB_TXCSR1_TXPKTRDY (1 << 0) -+#define USB_TXCSR1_FIFONOTEMPTY (1 << 1) -+#define USB_TXCSR1_FLUSHFIFO (1 << 3) -+#define USB_TXCSR1_CLRDATATOG (1 << 6) -+ // Client mode -+#define USB_TXCSR1_P_UNDERRUN (1 << 2) -+#define USB_TXCSR1_P_SENDSTALL (1 << 4) -+#define USB_TXCSR1_P_SENTSTALL (1 << 5) -+#define USB_TXCSR1_P_INCOMPTX (1 << 7) -+ // Host MODE -+#define USB_TXCSR1_H_ERROR (1 << 2) -+#define USB_TXCSR1_H_RXSTALL (1 << 5) -+#define USB_TXCSR1_H_NAKTIMEOUT (1 << 7) // for Bulk Endpoint -+#define USB_TXCSR1_H_INCOMPTX (1 << 7) // for Interrupt Endpoint -+ -+ /** TXCSR2 register */ -+ // mode-agnostic -+#define USB_TXCSR2_DMAMODE1 (1 << 2) -+#define USB_TXCSR2_FRCDATATOG (1 << 3) -+#define USB_TXCSR2_DMAENAB (1 << 4) -+#define USB_TXCSR2_MODE (1 << 5) -+ // Host mode -+#define USB_TXCSR2_MODE_TX (1 << 5) -+#define USB_TXCSR2_AUTOSET (1 << 7) -+ // Client mode -+#define USB_TXCSR2_P_ISO (1 << 6) -+ -+ /** RXCSR1 register */ -+ // mode-agnostic -+#define USB_RXCSR1_RXPKTRDY (1 << 0) // r / clear -+#define USB_RXCSR1_FIFOFULL (1 << 1) // r -+#define USB_RXCSR1_DATAERR (1 << 3) // r / clear(host), for ISO only -+#define USB_RXCSR1_FLUSHFIFO (1 << 4) // set -+#define USB_RXCSR1_CLRDATATOG (1 << 7) // set -+ // Client mode -+#define USB_RXCSR1_P_OVERRUN (1 << 2) // r / clear, for ISO only -+#define USB_RXCSR1_P_SENDSTALL (1 << 5) // r / w -+#define USB_RXCSR1_P_SENTSTALL (1 << 6) // r / clear -+ // Host MODE -+#define USB_RXCSR1_H_ERROR (1 << 2) // r / clear -+#define USB_RXCSR1_H_NAKTIMEOUT (1 << 3) // r / clear, for BULK -+#define USB_RXCSR1_H_REQPKT (1 << 5) // r / w -+#define USB_RXCSR1_H_RXSTALL (1 << 6) // r / clear -+ -+ /** RXCSR2 register */ -+ // mode-agnostic -+#define USB_RXCSR2_INCOMPRX (1 << 0) // r -+#define USB_RXCSR2_DMAMODE0 (0 << 3) -+#define USB_RXCSR2_DMAMODE1 (1 << 3) // r / w -+#define USB_RXCSR2_DMAREQENAB (1 << 5) // r / w -+#define USB_RXCSR2_AUTOCLEAR (1 << 7) // r / w -+ -+#define USB_RXCSR2_AUTOREQ (1 << 6) -+#define USB_RXCSR2_DMAENAB (1 << 5) -+#define USB_RXCSR2_DISNYET (1 << 4) -+#define USB_RXCSR2_DMAMODE (1 << 3) -+ -+ // Client mode -+#define USB_RXCSR2_P_DISNYET (1 << 4) // for Bulk/Interrupt transaction -+#define USB_RXCSR2_P_PIDERROR (1 << 4) // for ISO transaction -+#define USB_RXCSR2_P_ISO (1 << 6) -+ // Host Mode -+#define USB_RXCSR2_H_PIDERROR (1 << 4) // r / w, for ISO only -+#define USB_RXCSR2_H_AUTOREQ (1 << 6) // r / w -+ -+ -+ /** IntrUSB/IntrUSBE register */ -+#define USB_INTR_SUSPEND (1 << 0) // client -+#define USB_INTR_RESUME (1 << 1) -+#define USB_INTR_RESET (1 << 2) // client -+#define USB_INTR_BABBLE (1 << 2) // host -+#define USB_INTR_SOF (1 << 3) -+#define USB_INTR_CONNECT (1 << 4) // host -+#define USB_INTR_DISCONNECT (1 << 5) // host/client -+#define USB_INTR_SESSREQ (1 << 6) // A device -+#define USB_INTR_VBUSERROR (1 << 7) // A device -+ -+ -+ /** IntrTX register */ -+ /** IntrRX register */ -+ /** IntrTXE register */ -+ /** IntrRXE register */ -+#define USB_INTR_EP0 (1 << 0) -+#define USB_INTR_EP1 (1 << 1) -+#define USB_INTR_EP2 (1 << 2) -+#define USB_INTR_EP3 (1 << 3) -+#define USB_INTR_EP4 (1 << 4) -+#define USB_INTR_EP5 (1 << 5) -+#define USB_INTR_EPX_MASK (USB_INTR_EP1|USB_INTR_EP2|USB_INTR_EP3|USB_INTR_EP4|USB_INTR_EP5) -+ -+ /** IntrUSB/IntrUSBE register */ -+#define USB_INTR_SUSPEND (1 << 0) // client -+#define USB_INTR_RESUME (1 << 1) -+#define USB_INTR_RESET (1 << 2) // client -+#define USB_INTR_BABBLE (1 << 2) // host -+#define USB_INTR_SOF (1 << 3) -+#define USB_INTR_CONNECT (1 << 4) // host -+#define USB_INTR_DISCONNECT (1 << 5) // host/client -+#define USB_INTR_SESSREQ (1 << 6) // A device -+#define USB_INTR_VBUSERROR (1 << 7) // A device -+ -+ /** RXMAXP register */ -+#define USB_RXMAXP_MASK (0x07FF) -+#define USB_RXMAXP(cnt) ((cnt) & 0x07FF) -+ -+ /** TXTYPE register */ -+#define USB_TXTYPE_EPNUM_MASK (0xf << 0) -+#define USB_TXTYPE_EPNUM(ep) (((ep)&0xf) << 0) -+#define USB_TXTYPE_PROTOCOL_ILLEGAL (0 << 4) -+#define USB_TXTYPE_PROTOCOL_ISO (1 << 4) -+#define USB_TXTYPE_PROTOCOL_BULK (2 << 4) -+#define USB_TXTYPE_PROTOCOL_INTR (3 << 4) -+ -+ /** DevCtl register */ -+#define USB_DEVCTL_SESSION (1 << 0) // host/client -+#define USB_DEVCTL_HOSTREQ (1 << 1) // B device -+#define USB_DEVCTL_HOSTMODE_MASK (1 << 2) -+ -+#define USB_DEVCTL_HOSTMODE_HOST (1 << 2) -+#define USB_DEVCTL_VBUS_MASK (3 << 3) -+ -+#define USB_DEVCTL_LSDEV (1 << 5) -+#define USB_DEVCTL_FSDEV (1 << 6) // host -+#define USB_DEVCTL_BDEVICE_MASK (1 << 7) -+ -+#define USB_DEVCTL_BDEVICE_B (1 << 7) -+ -+#endif /* _ANYKA_USB_REG_DEFINE_H_ */ -+ -diff --git a/include/plat-anyka/usbburn.h b/include/plat-anyka/usbburn.h -new file mode 100644 -index 00000000..08f2917d ---- /dev/null -+++ b/include/plat-anyka/usbburn.h -@@ -0,0 +1,16 @@ -+#ifndef __USB_BURN__ -+#define __USB_BURN__ -+ -+extern int sense_data; // the CSW status -+ -+extern struct semaphore sense_data_lock; // synchronization sense_data -+ -+/* the write function for the usb file_storage */ -+extern int usbburn_write(void *buf, size_t count); -+ -+/* the read function for the usb file_storage */ -+extern int usbburn_read(void *buf, size_t count); -+ -+extern void usbburn_ioctl(void); -+ -+#endif /* __USB_BURN__ */ -diff --git a/include/plat-anyka/wifi.h b/include/plat-anyka/wifi.h -new file mode 100755 -index 00000000..a3058815 ---- /dev/null -+++ b/include/plat-anyka/wifi.h -@@ -0,0 +1,25 @@ -+/* -+ * include/plat-anyka/wifi.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef __WIFI_H__ -+#define __WIFI_H__ -+ -+#include <mach/gpio.h> -+ -+struct akwifi_platform_data { -+ struct gpio_info gpio_on; -+ struct gpio_info gpio_off; -+ int power_on_delay; -+ int power_off_delay; -+ int total_usb_ep_num; -+ void (* gpio_init) (const struct gpio_info *); -+}; -+ -+#endif /* __WIFI_H__ */ -+ -diff --git a/include/plat-anyka/wrap_sensor.h b/include/plat-anyka/wrap_sensor.h -new file mode 100755 -index 00000000..e161d49e ---- /dev/null -+++ b/include/plat-anyka/wrap_sensor.h -@@ -0,0 +1,114 @@ -+#ifndef __WRAP_SENSOR__ -+#define __WRAP_SENSOR__ -+ -+#include <mach-anyka/anyka_types.h> -+#include <linux/i2c.h> -+#include <mach/gpio.h> -+#include <plat-anyka/cam_com_sensor.h> -+ -+#define GPIO_I2C_SCL INVALID_GPIO -+#define GPIO_I2C_SDA INVALID_GPIO -+ -+/** -+ * @brief millisecond delay -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] minisecond minisecond delay number -+ * @return T_VOID -+ */ -+T_VOID mini_delay(T_U32 minisecond); -+ -+/** -+ * @brief anyka specific printf -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] level forbidden level -+ * @param[in] mStr module string -+ * @param[in] s format string -+ * @return T_S32 -+ * @retval 0 is print ok, -1 is forbidden to print -+ */ -+T_S32 akprintf(T_U8 level, T_pCSTR mStr, T_pCSTR s, ...); -+ -+/** -+ * @brief write data to SCCB device -+ * -+ * write size length data to daddr's raddr register -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] daddr SCCB device address -+ * @param[in] raddr register address -+ * @param[in] data write data's point -+ * @param[in] size write data's length -+ * @return T_BOOL return write success or failed -+ * @retval AK_FALSE operate failed -+ * @retval AK_TRUE operate success -+ */ -+T_BOOL sccb_write_data(T_U8 daddr, T_U8 raddr, T_U8 *data, T_U32 size); -+T_BOOL sccb_write_short(T_U8 daddr, T_U16 raddr, T_U8 *data, T_U32 size); -+T_BOOL sccb_write_word(T_U8 daddr, T_U16 raddr, T_U16 *data, T_U32 size); -+ -+/** -+ * @brief read data from SCCB device function -+ * -+ * read data from daddr's raddr register -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] daddr SCCB device address -+ * @param[in] raddr register address -+ * @return T_U8 -+ * @retval read-back data -+ */ -+T_U8 sccb_read_data(T_U8 daddr, T_U8 raddr); -+T_U8 sccb_read_short(T_U8 daddr, T_U16 raddr); -+T_U16 sccb_read_word(T_U8 daddr, T_U16 raddr); -+ -+/*@{*/ -+/** -+ * @brief SCCB interface initialize function -+ * -+ * setup SCCB interface -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param[in] pin_scl the pin assigned to SCL -+ * @param[in] pin_sda the pin assigned to SDA -+ * @return T_VOID -+ */ -+T_VOID sccb_init(T_U32 pin_scl, T_U32 pin_sda); -+ -+ -+/** -+ * @brief set client handle -+ * @author dengzhou -+ * @date 2012-03-19 -+ * @param[in] client handle of I2C open -+ * @return T_VOID -+ */ -+void sensor_set_handle(struct i2c_client *client); -+ -+/** -+ * @brief get GPIO pin value -+ * @author dengzhou -+ * @date 2012-03-16 -+ * @param GPIO pin type -+ * @return GPIO pin value -+ * @retval -+ */ -+T_U32 cam_getpin(T_CAMERA_PINTYPE pin_type); -+ -+#define GPIO_CAMERA_AVDD cam_getpin(PIN_AVDD) -+#define GPIO_CAMERA_CHIP_ENABLE cam_getpin(PIN_POWER) -+#define GPIO_CAMERA_RESET cam_getpin(PIN_RESET) -+ -+#define GPIO_DIR_INPUT AK_GPIO_DIR_INPUT -+#define GPIO_DIR_OUTPUT AK_GPIO_DIR_OUTPUT -+#define GPIO_LEVEL_LOW AK_GPIO_OUT_LOW -+#define GPIO_LEVEL_HIGH AK_GPIO_OUT_HIGH -+ -+#define gpio_set_pin_dir(pin,dir) ak_gpio_cfgpin(pin,dir) -+#define gpio_set_pin_level(pin,level) ak_gpio_setpin(pin,level) -+#define gpio_set_pin_as_gpio(pin) ak_setpin_as_gpio(pin) -+#define gpio_pin_get_ActiveLevel(pin) ak_gpio_getpin(pin) -+ -+#endif -+ -diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h -index f34a5a87..11a4fd05 100644 ---- a/include/scsi/scsi.h -+++ b/include/scsi/scsi.h -@@ -146,6 +146,13 @@ struct scsi_cmnd; - #define SYNCHRONIZE_CACHE_16 0x91 - #define WRITE_SAME_16 0x93 - #define SERVICE_ACTION_IN 0x9e -+ -+#ifdef CONFIG_USB_AKUDC_PRODUCER -+//modified by anyka Zhang Jingyuan -+#define SCSI_ANYKA_UBOOT 0xf1 -+//end of modified by anyka Zhang Jingyuan -+#endif -+ - /* values for service action in */ - #define SAI_READ_CAPACITY_16 0x10 - #define SAI_GET_LBA_STATUS 0x12 -diff --git a/include/sound/ak_pcm.h b/include/sound/ak_pcm.h -new file mode 100644 -index 00000000..559dd858 ---- /dev/null -+++ b/include/sound/ak_pcm.h -@@ -0,0 +1,51 @@ -+#ifndef _AK_PCM_H -+#define _AK_PCM_H -+ -+#include <sound/core.h> -+#include <sound/pcm.h> -+ -+ -+struct ak_codec_dai; -+ -+struct ak_codec_ops { -+ void (*dac_init) (struct ak_codec_dai *dai); -+ void (*dac_exit) (struct ak_codec_dai *dai); -+ -+ void (*adc_init) (struct ak_codec_dai *dai); -+ void (*adc_exit) (struct ak_codec_dai *dai); -+ -+ void (*set_dac_samplerate)(struct ak_codec_dai *dai, unsigned int rate); -+ unsigned long (*set_adc_samplerate)(struct ak_codec_dai *dai, unsigned int rate); -+ -+ void (*set_dac_channels)(struct ak_codec_dai *dai, unsigned int channels); -+ void (*set_adc_channels)(struct ak_codec_dai *dai, unsigned int channels); -+ -+ void (*playback_start)(struct ak_codec_dai *dai); -+ void (*playback_end)(struct ak_codec_dai *dai); -+ -+ void (*capture_start)(struct ak_codec_dai *dai); -+ void (*capture_end)(struct ak_codec_dai *dai); -+ -+ void (*start_to_play) (struct ak_codec_dai *dai, unsigned int channels, unsigned int rate); -+}; -+ -+struct ak_proc_entry { -+ const char *name; -+ void (*cb)(struct snd_info_entry *, struct snd_info_buffer *); -+}; -+ -+struct ak_codec_dai { -+ int num_kcontrols; -+ struct snd_kcontrol_new *kcontrols; -+ int num_pentries; -+ void *entries_private; -+ struct ak_proc_entry *pentries; -+ struct ak_codec_ops *ops; -+ int aec_flag; -+ -+}; -+ -+int ak_codec_register(struct ak_codec_dai *dai); -+void ak_codec_ctl_event(unsigned int iface, unsigned int event, const char* ctl_name); -+ -+#endif -diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h -index 8da3c240..055242e6 100644 ---- a/include/sound/soc-dapm.h -+++ b/include/sound/soc-dapm.h -@@ -432,6 +432,11 @@ enum snd_soc_dapm_type { - snd_soc_dapm_dai, /* link to DAI structure */ - }; - -+enum snd_soc_dapm_subclass { -+ SND_SOC_DAPM_CLASS_INIT = 0, -+ SND_SOC_DAPM_CLASS_PCM = 1, -+}; -+ - /* - * DAPM audio route definition. - * -diff --git a/include/sound/soc.h b/include/sound/soc.h -index 2ebf7877..66fd9bc9 100644 ---- a/include/sound/soc.h -+++ b/include/sound/soc.h -@@ -288,6 +288,11 @@ enum snd_soc_pcm_subclass { - SND_SOC_PCM_CLASS_BE = 1, - }; - -+enum snd_soc_card_subclass { -+ SND_SOC_CARD_CLASS_INIT = 0, -+ SND_SOC_CARD_CLASS_PCM = 1, -+}; -+ - int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, - int source, unsigned int freq, int dir); - int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, -@@ -800,6 +805,7 @@ struct snd_soc_card { - - struct list_head list; - struct mutex mutex; -+ struct mutex dapm_mutex; - - bool instantiated; - -diff --git a/include/trace/events/cpufreq_interactive.h b/include/trace/events/cpufreq_interactive.h -new file mode 100644 -index 00000000..951e6ca1 ---- /dev/null -+++ b/include/trace/events/cpufreq_interactive.h -@@ -0,0 +1,112 @@ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM cpufreq_interactive -+ -+#if !defined(_TRACE_CPUFREQ_INTERACTIVE_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _TRACE_CPUFREQ_INTERACTIVE_H -+ -+#include <linux/tracepoint.h> -+ -+DECLARE_EVENT_CLASS(set, -+ TP_PROTO(u32 cpu_id, unsigned long targfreq, -+ unsigned long actualfreq), -+ TP_ARGS(cpu_id, targfreq, actualfreq), -+ -+ TP_STRUCT__entry( -+ __field( u32, cpu_id ) -+ __field(unsigned long, targfreq ) -+ __field(unsigned long, actualfreq ) -+ ), -+ -+ TP_fast_assign( -+ __entry->cpu_id = (u32) cpu_id; -+ __entry->targfreq = targfreq; -+ __entry->actualfreq = actualfreq; -+ ), -+ -+ TP_printk("cpu=%u targ=%lu actual=%lu", -+ __entry->cpu_id, __entry->targfreq, -+ __entry->actualfreq) -+); -+ -+DEFINE_EVENT(set, cpufreq_interactive_setspeed, -+ TP_PROTO(u32 cpu_id, unsigned long targfreq, -+ unsigned long actualfreq), -+ TP_ARGS(cpu_id, targfreq, actualfreq) -+); -+ -+DECLARE_EVENT_CLASS(loadeval, -+ TP_PROTO(unsigned long cpu_id, unsigned long load, -+ unsigned long curtarg, unsigned long curactual, -+ unsigned long newtarg), -+ TP_ARGS(cpu_id, load, curtarg, curactual, newtarg), -+ -+ TP_STRUCT__entry( -+ __field(unsigned long, cpu_id ) -+ __field(unsigned long, load ) -+ __field(unsigned long, curtarg ) -+ __field(unsigned long, curactual ) -+ __field(unsigned long, newtarg ) -+ ), -+ -+ TP_fast_assign( -+ __entry->cpu_id = cpu_id; -+ __entry->load = load; -+ __entry->curtarg = curtarg; -+ __entry->curactual = curactual; -+ __entry->newtarg = newtarg; -+ ), -+ -+ TP_printk("cpu=%lu load=%lu cur=%lu actual=%lu targ=%lu", -+ __entry->cpu_id, __entry->load, __entry->curtarg, -+ __entry->curactual, __entry->newtarg) -+); -+ -+DEFINE_EVENT(loadeval, cpufreq_interactive_target, -+ TP_PROTO(unsigned long cpu_id, unsigned long load, -+ unsigned long curtarg, unsigned long curactual, -+ unsigned long newtarg), -+ TP_ARGS(cpu_id, load, curtarg, curactual, newtarg) -+); -+ -+DEFINE_EVENT(loadeval, cpufreq_interactive_already, -+ TP_PROTO(unsigned long cpu_id, unsigned long load, -+ unsigned long curtarg, unsigned long curactual, -+ unsigned long newtarg), -+ TP_ARGS(cpu_id, load, curtarg, curactual, newtarg) -+); -+ -+DEFINE_EVENT(loadeval, cpufreq_interactive_notyet, -+ TP_PROTO(unsigned long cpu_id, unsigned long load, -+ unsigned long curtarg, unsigned long curactual, -+ unsigned long newtarg), -+ TP_ARGS(cpu_id, load, curtarg, curactual, newtarg) -+); -+ -+TRACE_EVENT(cpufreq_interactive_boost, -+ TP_PROTO(const char *s), -+ TP_ARGS(s), -+ TP_STRUCT__entry( -+ __string(s, s) -+ ), -+ TP_fast_assign( -+ __assign_str(s, s); -+ ), -+ TP_printk("%s", __get_str(s)) -+); -+ -+TRACE_EVENT(cpufreq_interactive_unboost, -+ TP_PROTO(const char *s), -+ TP_ARGS(s), -+ TP_STRUCT__entry( -+ __string(s, s) -+ ), -+ TP_fast_assign( -+ __assign_str(s, s); -+ ), -+ TP_printk("%s", __get_str(s)) -+); -+ -+#endif /* _TRACE_CPUFREQ_INTERACTIVE_H */ -+ -+/* This part must be outside protection */ -+#include <trace/define_trace.h> -diff --git a/include/trace/events/gpu.h b/include/trace/events/gpu.h -new file mode 100644 -index 00000000..09efa71d ---- /dev/null -+++ b/include/trace/events/gpu.h -@@ -0,0 +1,142 @@ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM gpu -+ -+#if !defined(_TRACE_GPU_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _TRACE_GPU_H -+ -+#include <linux/tracepoint.h> -+#include <linux/time.h> -+ -+#define show_secs_from_ns(ns) \ -+ ({ \ -+ u64 t = ns + (NSEC_PER_USEC / 2); \ -+ do_div(t, NSEC_PER_SEC); \ -+ }) -+ -+#define show_usecs_from_ns(ns) \ -+ ({ \ -+ u64 t = ns + (NSEC_PER_USEC / 2) ; \ -+ u32 rem; \ -+ do_div(t, NSEC_PER_USEC); \ -+ rem = do_div(t, USEC_PER_SEC); \ -+ }) -+ -+/* -+ * The gpu_sched_switch event indicates that a switch from one GPU context to -+ * another occurred on one of the GPU hardware blocks. -+ * -+ * The gpu_name argument identifies the GPU hardware block. Each independently -+ * scheduled GPU hardware block should have a different name. This may be used -+ * in different ways for different GPUs. For example, if a GPU includes -+ * multiple processing cores it may use names "GPU 0", "GPU 1", etc. If a GPU -+ * includes a separately scheduled 2D and 3D hardware block, it might use the -+ * names "2D" and "3D". -+ * -+ * The timestamp argument is the timestamp at which the switch occurred on the -+ * GPU. These timestamps are in units of nanoseconds and must use -+ * approximately the same time as sched_clock, though they need not come from -+ * any CPU clock. The timestamps for a single hardware block must be -+ * monotonically nondecreasing. This means that if a variable compensation -+ * offset is used to translate from some other clock to the sched_clock, then -+ * care must be taken when increasing that offset, and doing so may result in -+ * multiple events with the same timestamp. -+ * -+ * The next_ctx_id argument identifies the next context that was running on -+ * the GPU hardware block. A value of 0 indicates that the hardware block -+ * will be idle. -+ * -+ * The next_prio argument indicates the priority of the next context at the -+ * time of the event. The exact numeric values may mean different things for -+ * different GPUs, but they should follow the rule that lower values indicate a -+ * higher priority. -+ * -+ * The next_job_id argument identifies the batch of work that the GPU will be -+ * working on. This should correspond to a job_id that was previously traced -+ * as a gpu_job_enqueue event when the batch of work was created. -+ */ -+TRACE_EVENT(gpu_sched_switch, -+ -+ TP_PROTO(const char *gpu_name, u64 timestamp, -+ u32 next_ctx_id, s32 next_prio, u32 next_job_id), -+ -+ TP_ARGS(gpu_name, timestamp, next_ctx_id, next_prio, next_job_id), -+ -+ TP_STRUCT__entry( -+ __string( gpu_name, gpu_name ) -+ __field( u64, timestamp ) -+ __field( u32, next_ctx_id ) -+ __field( s32, next_prio ) -+ __field( u32, next_job_id ) -+ ), -+ -+ TP_fast_assign( -+ __assign_str(gpu_name, gpu_name); -+ __entry->timestamp = timestamp; -+ __entry->next_ctx_id = next_ctx_id; -+ __entry->next_prio = next_prio; -+ __entry->next_job_id = next_job_id; -+ ), -+ -+ TP_printk("gpu_name=%s ts=%5llu.%06lu next_ctx_id=%lu next_prio=%ld " -+ "next_job_id=%lu", -+ __get_str(gpu_name), -+ (unsigned long long)show_secs_from_ns(__entry->timestamp), -+ (unsigned long)show_usecs_from_ns(__entry->timestamp), -+ (unsigned long)__entry->next_ctx_id, -+ (long)__entry->next_prio, -+ (unsigned long)__entry->next_job_id) -+); -+ -+/* -+ * The gpu_job_enqueue event indicates that a batch of work has been queued up -+ * to be processed by the GPU. This event is not intended to indicate that -+ * the batch of work has been submitted to the GPU hardware, but rather that -+ * it has been submitted to the GPU kernel driver. -+ * -+ * This event should be traced on the thread that initiated the work being -+ * queued. For example, if a batch of work is submitted to the kernel by a -+ * userland thread, the event should be traced on that thread. -+ * -+ * The ctx_id field identifies the GPU context in which the batch of work -+ * being queued is to be run. -+ * -+ * The job_id field identifies the batch of work being queued within the given -+ * GPU context. The first batch of work submitted for a given GPU context -+ * should have a job_id of 0, and each subsequent batch of work should -+ * increment the job_id by 1. -+ * -+ * The type field identifies the type of the job being enqueued. The job -+ * types may be different for different GPU hardware. For example, a GPU may -+ * differentiate between "2D", "3D", and "compute" jobs. -+ */ -+TRACE_EVENT(gpu_job_enqueue, -+ -+ TP_PROTO(u32 ctx_id, u32 job_id, const char *type), -+ -+ TP_ARGS(ctx_id, job_id, type), -+ -+ TP_STRUCT__entry( -+ __field( u32, ctx_id ) -+ __field( u32, job_id ) -+ __string( type, type ) -+ ), -+ -+ TP_fast_assign( -+ __entry->ctx_id = ctx_id; -+ __entry->job_id = job_id; -+ __assign_str(type, type); -+ ), -+ -+ TP_printk("ctx_id=%lu job_id=%lu type=%s", -+ (unsigned long)__entry->ctx_id, -+ (unsigned long)__entry->job_id, -+ __get_str(type)) -+); -+ -+#undef show_secs_from_ns -+#undef show_usecs_from_ns -+ -+#endif /* _TRACE_GPU_H */ -+ -+/* This part must be outside protection */ -+#include <trace/define_trace.h> -diff --git a/include/trace/events/power.h b/include/trace/events/power.h -index cae9a94f..243c677c 100644 ---- a/include/trace/events/power.h -+++ b/include/trace/events/power.h -@@ -65,6 +65,40 @@ TRACE_EVENT(machine_suspend, - TP_printk("state=%lu", (unsigned long)__entry->state) - ); - -+DECLARE_EVENT_CLASS(wakeup_source, -+ -+ TP_PROTO(const char *name, unsigned int state), -+ -+ TP_ARGS(name, state), -+ -+ TP_STRUCT__entry( -+ __string( name, name ) -+ __field( u64, state ) -+ ), -+ -+ TP_fast_assign( -+ __assign_str(name, name); -+ __entry->state = state; -+ ), -+ -+ TP_printk("%s state=0x%lx", __get_str(name), -+ (unsigned long)__entry->state) -+); -+ -+DEFINE_EVENT(wakeup_source, wakeup_source_activate, -+ -+ TP_PROTO(const char *name, unsigned int state), -+ -+ TP_ARGS(name, state) -+); -+ -+DEFINE_EVENT(wakeup_source, wakeup_source_deactivate, -+ -+ TP_PROTO(const char *name, unsigned int state), -+ -+ TP_ARGS(name, state) -+); -+ - #ifdef CONFIG_EVENT_POWER_TRACING_DEPRECATED - - /* -@@ -204,6 +238,25 @@ DEFINE_EVENT(clock, clock_set_rate, - TP_ARGS(name, state, cpu_id) - ); - -+TRACE_EVENT(clock_set_parent, -+ -+ TP_PROTO(const char *name, const char *parent_name), -+ -+ TP_ARGS(name, parent_name), -+ -+ TP_STRUCT__entry( -+ __string( name, name ) -+ __string( parent_name, parent_name ) -+ ), -+ -+ TP_fast_assign( -+ __assign_str(name, name); -+ __assign_str(parent_name, parent_name); -+ ), -+ -+ TP_printk("%s parent=%s", __get_str(name), __get_str(parent_name)) -+); -+ - /* - * The power domain events are used for power domains transitions - */ -diff --git a/include/trace/events/sync.h b/include/trace/events/sync.h -new file mode 100644 -index 00000000..f31bc63c ---- /dev/null -+++ b/include/trace/events/sync.h -@@ -0,0 +1,82 @@ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM sync -+ -+#if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _TRACE_SYNC_H -+ -+#include <linux/sync.h> -+#include <linux/tracepoint.h> -+ -+TRACE_EVENT(sync_timeline, -+ TP_PROTO(struct sync_timeline *timeline), -+ -+ TP_ARGS(timeline), -+ -+ TP_STRUCT__entry( -+ __string(name, timeline->name) -+ __array(char, value, 32) -+ ), -+ -+ TP_fast_assign( -+ __assign_str(name, timeline->name); -+ if (timeline->ops->timeline_value_str) { -+ timeline->ops->timeline_value_str(timeline, -+ __entry->value, -+ sizeof(__entry->value)); -+ } else { -+ __entry->value[0] = '\0'; -+ } -+ ), -+ -+ TP_printk("name=%s value=%s", __get_str(name), __entry->value) -+); -+ -+TRACE_EVENT(sync_wait, -+ TP_PROTO(struct sync_fence *fence, int begin), -+ -+ TP_ARGS(fence, begin), -+ -+ TP_STRUCT__entry( -+ __string(name, fence->name) -+ __field(s32, status) -+ __field(u32, begin) -+ ), -+ -+ TP_fast_assign( -+ __assign_str(name, fence->name); -+ __entry->status = fence->status; -+ __entry->begin = begin; -+ ), -+ -+ TP_printk("%s name=%s state=%d", __entry->begin ? "begin" : "end", -+ __get_str(name), __entry->status) -+); -+ -+TRACE_EVENT(sync_pt, -+ TP_PROTO(struct sync_pt *pt), -+ -+ TP_ARGS(pt), -+ -+ TP_STRUCT__entry( -+ __string(timeline, pt->parent->name) -+ __array(char, value, 32) -+ ), -+ -+ TP_fast_assign( -+ __assign_str(timeline, pt->parent->name); -+ if (pt->parent->ops->pt_value_str) { -+ pt->parent->ops->pt_value_str(pt, -+ __entry->value, -+ sizeof(__entry->value)); -+ } else { -+ __entry->value[0] = '\0'; -+ } -+ ), -+ -+ TP_printk("name=%s value=%s", __get_str(timeline), __entry->value) -+ ); -+ -+#endif /* if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) */ -+ -+/* This part must be outside protection */ -+#include <trace/define_trace.h> -diff --git a/init/Kconfig b/init/Kconfig -index 6cfd71d0..a7cffc83 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -953,6 +953,12 @@ config SYSCTL - config ANON_INODES - bool - -+config PANIC_TIMEOUT -+ int "Default panic timeout" -+ default 0 -+ help -+ Set default panic timeout. -+ - menuconfig EXPERT - bool "Configure standard kernel features (expert users)" - # Unhide debug options, to make the on-by-default options visible -diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index a4c47d1b..c5d69222 100644 ---- a/kernel/cgroup.c -+++ b/kernel/cgroup.c -@@ -287,6 +287,33 @@ static void cgroup_release_agent(struct work_struct *work); - static DECLARE_WORK(release_agent_work, cgroup_release_agent); - static void check_for_release(struct cgroup *cgrp); - -+/* -+ * A queue for waiters to do rmdir() cgroup. A tasks will sleep when -+ * cgroup->count == 0 && list_empty(&cgroup->children) && subsys has some -+ * reference to css->refcnt. In general, this refcnt is expected to goes down -+ * to zero, soon. -+ * -+ * CGRP_WAIT_ON_RMDIR flag is set under cgroup's inode->i_mutex; -+ */ -+static DECLARE_WAIT_QUEUE_HEAD(cgroup_rmdir_waitq); -+ -+static void cgroup_wakeup_rmdir_waiter(struct cgroup *cgrp) -+{ -+ if (unlikely(test_and_clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags))) -+ wake_up_all(&cgroup_rmdir_waitq); -+} -+ -+void cgroup_exclude_rmdir(struct cgroup_subsys_state *css) -+{ -+ css_get(css); -+} -+ -+void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css) -+{ -+ cgroup_wakeup_rmdir_waiter(css->cgroup); -+ css_put(css); -+} -+ - /* Link structure for associating css_set objects with cgroups */ - struct cg_cgroup_link { - /* -@@ -346,60 +373,51 @@ static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[]) - return &css_set_table[index]; - } - --/* We don't maintain the lists running through each css_set to its -- * task until after the first call to cgroup_iter_start(). This -- * reduces the fork()/exit() overhead for people who have cgroups -- * compiled into their kernel but not actually in use */ --static int use_task_css_set_links __read_mostly; -- --static void __put_css_set(struct css_set *cg, int taskexit) -+static void free_css_set_work(struct work_struct *work) - { -+ struct css_set *cg = container_of(work, struct css_set, work); - struct cg_cgroup_link *link; - struct cg_cgroup_link *saved_link; -- /* -- * Ensure that the refcount doesn't hit zero while any readers -- * can see it. Similar to atomic_dec_and_lock(), but for an -- * rwlock -- */ -- if (atomic_add_unless(&cg->refcount, -1, 1)) -- return; -- write_lock(&css_set_lock); -- if (!atomic_dec_and_test(&cg->refcount)) { -- write_unlock(&css_set_lock); -- return; -- } -- -- /* This css_set is dead. unlink it and release cgroup refcounts */ -- hlist_del(&cg->hlist); -- css_set_count--; - -+ write_lock(&css_set_lock); - list_for_each_entry_safe(link, saved_link, &cg->cg_links, - cg_link_list) { - struct cgroup *cgrp = link->cgrp; - list_del(&link->cg_link_list); - list_del(&link->cgrp_link_list); -- - /* - * We may not be holding cgroup_mutex, and if cgrp->count is - * dropped to 0 the cgroup can be destroyed at any time, hence - * rcu_read_lock is used to keep it alive. - */ - rcu_read_lock(); -- if (atomic_dec_and_test(&cgrp->count) && -- notify_on_release(cgrp)) { -- if (taskexit) -- set_bit(CGRP_RELEASABLE, &cgrp->flags); -+ if (atomic_dec_and_test(&cgrp->count)) { - check_for_release(cgrp); -+ cgroup_wakeup_rmdir_waiter(cgrp); - } - rcu_read_unlock(); - - kfree(link); - } -- - write_unlock(&css_set_lock); -- kfree_rcu(cg, rcu_head); -+ -+ kfree(cg); - } - -+static void free_css_set_rcu(struct rcu_head *obj) -+{ -+ struct css_set *cg = container_of(obj, struct css_set, rcu_head); -+ -+ INIT_WORK(&cg->work, free_css_set_work); -+ schedule_work(&cg->work); -+} -+ -+/* We don't maintain the lists running through each css_set to its -+ * task until after the first call to cgroup_iter_start(). This -+ * reduces the fork()/exit() overhead for people who have cgroups -+ * compiled into their kernel but not actually in use */ -+static int use_task_css_set_links __read_mostly; -+ - /* - * refcounted get/put for css_set objects - */ -@@ -408,14 +426,26 @@ static inline void get_css_set(struct css_set *cg) - atomic_inc(&cg->refcount); - } - --static inline void put_css_set(struct css_set *cg) -+static void put_css_set(struct css_set *cg) - { -- __put_css_set(cg, 0); --} -+ /* -+ * Ensure that the refcount doesn't hit zero while any readers -+ * can see it. Similar to atomic_dec_and_lock(), but for an -+ * rwlock -+ */ -+ if (atomic_add_unless(&cg->refcount, -1, 1)) -+ return; -+ write_lock(&css_set_lock); -+ if (!atomic_dec_and_test(&cg->refcount)) { -+ write_unlock(&css_set_lock); -+ return; -+ } - --static inline void put_css_set_taskexit(struct css_set *cg) --{ -- __put_css_set(cg, 1); -+ hlist_del(&cg->hlist); -+ css_set_count--; -+ -+ write_unlock(&css_set_lock); -+ call_rcu(&cg->rcu_head, free_css_set_rcu); - } - - /* -@@ -747,9 +777,9 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task, - * cgroup_attach_task(), which overwrites one tasks cgroup pointer with - * another. It does so using cgroup_mutex, however there are - * several performance critical places that need to reference -- * task->cgroup without the expense of grabbing a system global -+ * task->cgroups without the expense of grabbing a system global - * mutex. Therefore except as noted below, when dereferencing or, as -- * in cgroup_attach_task(), modifying a task'ss cgroup pointer we use -+ * in cgroup_attach_task(), modifying a task's cgroups pointer we use - * task_lock(), which acts on a spinlock (task->alloc_lock) already in - * the task_struct routinely used for such matters. - * -@@ -938,33 +968,6 @@ static void cgroup_d_remove_dir(struct dentry *dentry) - remove_dir(dentry); - } - --/* -- * A queue for waiters to do rmdir() cgroup. A tasks will sleep when -- * cgroup->count == 0 && list_empty(&cgroup->children) && subsys has some -- * reference to css->refcnt. In general, this refcnt is expected to goes down -- * to zero, soon. -- * -- * CGRP_WAIT_ON_RMDIR flag is set under cgroup's inode->i_mutex; -- */ --static DECLARE_WAIT_QUEUE_HEAD(cgroup_rmdir_waitq); -- --static void cgroup_wakeup_rmdir_waiter(struct cgroup *cgrp) --{ -- if (unlikely(test_and_clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags))) -- wake_up_all(&cgroup_rmdir_waitq); --} -- --void cgroup_exclude_rmdir(struct cgroup_subsys_state *css) --{ -- css_get(css); --} -- --void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css) --{ -- cgroup_wakeup_rmdir_waiter(css->cgroup); -- css_put(css); --} -- - /* - * Call with cgroup_mutex held. Drops reference counts on modules, including - * any duplicate ones that parse_cgroupfs_options took. If this function -@@ -1896,6 +1899,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) - struct cgroupfs_root *root = cgrp->root; - struct cgroup_taskset tset = { }; - struct css_set *newcg; -+ struct css_set *cg; - - /* @tsk either already exited or can't exit until the end */ - if (tsk->flags & PF_EXITING) -@@ -1931,14 +1935,20 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) - goto out; - } - -+ task_lock(tsk); -+ cg = tsk->cgroups; -+ get_css_set(cg); -+ task_unlock(tsk); -+ - cgroup_task_migrate(cgrp, oldcgrp, tsk, newcg); - - for_each_subsys(root, ss) { - if (ss->attach) - ss->attach(cgrp, &tset); - } -- -- synchronize_rcu(); -+ set_bit(CGRP_RELEASABLE, &cgrp->flags); -+ /* put_css_set will not destroy cg until after an RCU grace period */ -+ put_css_set(cg); - - /* - * wake up rmdir() waiter. the rmdir should fail since the cgroup -@@ -2139,6 +2149,24 @@ out_free_group_list: - return retval; - } - -+static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) -+{ -+ struct cgroup_subsys *ss; -+ int ret; -+ -+ for_each_subsys(cgrp->root, ss) { -+ if (ss->allow_attach) { -+ ret = ss->allow_attach(cgrp, tset); -+ if (ret) -+ return ret; -+ } else { -+ return -EACCES; -+ } -+ } -+ -+ return 0; -+} -+ - /* - * Find the task_struct of the task to attach by vpid and pass it along to the - * function to attach either it or all tasks in its threadgroup. Will lock -@@ -2170,9 +2198,18 @@ retry_find_task: - if (cred->euid && - cred->euid != tcred->uid && - cred->euid != tcred->suid) { -- rcu_read_unlock(); -- ret = -EACCES; -- goto out_unlock_cgroup; -+ /* -+ * if the default permission check fails, give each -+ * cgroup a chance to extend the permission check -+ */ -+ struct cgroup_taskset tset = { }; -+ tset.single.task = tsk; -+ tset.single.cgrp = cgrp; -+ ret = cgroup_allow_attach(cgrp, &tset); -+ if (ret) { -+ rcu_read_unlock(); -+ goto out_unlock_cgroup; -+ } - } - } else - tsk = current; -@@ -3789,6 +3826,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, - if (err < 0) - goto err_remove; - -+ set_bit(CGRP_RELEASABLE, &parent->flags); -+ - /* The cgroup directory was pre-locked for us */ - BUG_ON(!mutex_is_locked(&cgrp->dentry->d_inode->i_mutex)); - -@@ -3920,6 +3959,21 @@ static int cgroup_clear_css_refs(struct cgroup *cgrp) - return !failed; - } - -+/* checks if all of the css_sets attached to a cgroup have a refcount of 0. -+ * Must be called with css_set_lock held */ -+static int cgroup_css_sets_empty(struct cgroup *cgrp) -+{ -+ struct cg_cgroup_link *link; -+ -+ list_for_each_entry(link, &cgrp->css_sets, cgrp_link_list) { -+ struct css_set *cg = link->cg; -+ if (atomic_read(&cg->refcount) > 0) -+ return 0; -+ } -+ -+ return 1; -+} -+ - static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) - { - struct cgroup *cgrp = dentry->d_fsdata; -@@ -3932,7 +3986,7 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) - /* the vfs holds both inode->i_mutex already */ - again: - mutex_lock(&cgroup_mutex); -- if (atomic_read(&cgrp->count) != 0) { -+ if (!cgroup_css_sets_empty(cgrp)) { - mutex_unlock(&cgroup_mutex); - return -EBUSY; - } -@@ -3965,7 +4019,7 @@ again: - - mutex_lock(&cgroup_mutex); - parent = cgrp->parent; -- if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children)) { -+ if (!cgroup_css_sets_empty(cgrp) || !list_empty(&cgrp->children)) { - clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags); - mutex_unlock(&cgroup_mutex); - return -EBUSY; -@@ -4005,7 +4059,6 @@ again: - cgroup_d_remove_dir(d); - dput(d); - -- set_bit(CGRP_RELEASABLE, &parent->flags); - check_for_release(parent); - - /* -@@ -4616,7 +4669,7 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks) - task_unlock(tsk); - - if (cg) -- put_css_set_taskexit(cg); -+ put_css_set(cg); - } - - /** -@@ -4669,6 +4722,14 @@ static void check_for_release(struct cgroup *cgrp) - } - } - -+/* Caller must verify that the css is not for root cgroup */ -+void __css_get(struct cgroup_subsys_state *css, int count) -+{ -+ atomic_add(count, &css->refcnt); -+ set_bit(CGRP_RELEASABLE, &css->cgroup->flags); -+} -+EXPORT_SYMBOL_GPL(__css_get); -+ - /* Caller must verify that the css is not for root cgroup */ - void __css_put(struct cgroup_subsys_state *css, int count) - { -@@ -4677,10 +4738,7 @@ void __css_put(struct cgroup_subsys_state *css, int count) - rcu_read_lock(); - val = atomic_sub_return(count, &css->refcnt); - if (val == 1) { -- if (notify_on_release(cgrp)) { -- set_bit(CGRP_RELEASABLE, &cgrp->flags); -- check_for_release(cgrp); -- } -+ check_for_release(cgrp); - cgroup_wakeup_rmdir_waiter(cgrp); - } - rcu_read_unlock(); -diff --git a/kernel/cpu.c b/kernel/cpu.c -index 2060c6e5..fb4a5acc 100644 ---- a/kernel/cpu.c -+++ b/kernel/cpu.c -@@ -668,3 +668,23 @@ void init_cpu_online(const struct cpumask *src) - { - cpumask_copy(to_cpumask(cpu_online_bits), src); - } -+ -+static ATOMIC_NOTIFIER_HEAD(idle_notifier); -+ -+void idle_notifier_register(struct notifier_block *n) -+{ -+ atomic_notifier_chain_register(&idle_notifier, n); -+} -+EXPORT_SYMBOL_GPL(idle_notifier_register); -+ -+void idle_notifier_unregister(struct notifier_block *n) -+{ -+ atomic_notifier_chain_unregister(&idle_notifier, n); -+} -+EXPORT_SYMBOL_GPL(idle_notifier_unregister); -+ -+void idle_notifier_call_chain(unsigned long val) -+{ -+ atomic_notifier_call_chain(&idle_notifier, val, NULL); -+} -+EXPORT_SYMBOL_GPL(idle_notifier_call_chain); -diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c -index 0557f24c..35b94ace 100644 ---- a/kernel/debug/debug_core.c -+++ b/kernel/debug/debug_core.c -@@ -85,6 +85,10 @@ static int kgdb_use_con; - bool dbg_is_early = true; - /* Next cpu to become the master debug core */ - int dbg_switch_cpu; -+/* Flag for entering kdb when a panic occurs */ -+static bool break_on_panic = true; -+/* Flag for entering kdb when an exception occurs */ -+static bool break_on_exception = true; - - /* Use kdb or gdbserver mode */ - int dbg_kdb_mode = 1; -@@ -99,6 +103,8 @@ early_param("kgdbcon", opt_kgdb_con); - - module_param(kgdb_use_con, int, 0644); - module_param(kgdbreboot, int, 0644); -+module_param(break_on_panic, bool, 0644); -+module_param(break_on_exception, bool, 0644); - - /* - * Holds information about breakpoints in a kernel. These breakpoints are -@@ -673,6 +679,9 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) - struct kgdb_state kgdb_var; - struct kgdb_state *ks = &kgdb_var; - -+ if (unlikely(signo != SIGTRAP && !break_on_exception)) -+ return 1; -+ - ks->cpu = raw_smp_processor_id(); - ks->ex_vector = evector; - ks->signo = signo; -@@ -759,6 +768,9 @@ static int kgdb_panic_event(struct notifier_block *self, - unsigned long val, - void *data) - { -+ if (!break_on_panic) -+ return NOTIFY_DONE; -+ - if (dbg_kdb_mode) - kdb_printf("PANIC: %s\n", (char *)data); - kgdb_breakpoint(); -diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c -index 572e604c..81b31bba 100644 ---- a/kernel/debug/kdb/kdb_io.c -+++ b/kernel/debug/kdb/kdb_io.c -@@ -216,7 +216,7 @@ static char *kdb_read(char *buffer, size_t bufsize) - int i; - int diag, dtab_count; - int key; -- -+ static int last_crlf; - - diag = kdbgetintenv("DTABCOUNT", &dtab_count); - if (diag) -@@ -237,6 +237,9 @@ poll_again: - return buffer; - if (key != 9) - tab = 0; -+ if (key != 10 && key != 13) -+ last_crlf = 0; -+ - switch (key) { - case 8: /* backspace */ - if (cp > buffer) { -@@ -254,7 +257,12 @@ poll_again: - *cp = tmp; - } - break; -- case 13: /* enter */ -+ case 10: /* new line */ -+ case 13: /* carriage return */ -+ /* handle \n after \r */ -+ if (last_crlf && last_crlf != key) -+ break; -+ last_crlf = key; - *lastchar++ = '\n'; - *lastchar++ = '\0'; - if (!KDB_STATE(KGDB_TRANS)) { -diff --git a/kernel/fork.c b/kernel/fork.c -index 81633337..bc3398ee 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -158,6 +158,9 @@ struct kmem_cache *vm_area_cachep; - /* SLAB cache for mm_struct structures (tsk->mm) */ - static struct kmem_cache *mm_cachep; - -+/* Notifier list called when a task struct is freed */ -+static ATOMIC_NOTIFIER_HEAD(task_free_notifier); -+ - static void account_kernel_stack(struct thread_info *ti, int account) - { - struct zone *zone = page_zone(virt_to_page(ti)); -@@ -188,6 +191,18 @@ static inline void put_signal_struct(struct signal_struct *sig) - free_signal_struct(sig); - } - -+int task_free_register(struct notifier_block *n) -+{ -+ return atomic_notifier_chain_register(&task_free_notifier, n); -+} -+EXPORT_SYMBOL(task_free_register); -+ -+int task_free_unregister(struct notifier_block *n) -+{ -+ return atomic_notifier_chain_unregister(&task_free_notifier, n); -+} -+EXPORT_SYMBOL(task_free_unregister); -+ - void __put_task_struct(struct task_struct *tsk) - { - WARN_ON(!tsk->exit_state); -@@ -199,6 +214,7 @@ void __put_task_struct(struct task_struct *tsk) - delayacct_tsk_free(tsk); - put_signal_struct(tsk->signal); - -+ atomic_notifier_call_chain(&task_free_notifier, 0, tsk); - if (!profile_handoff_task(tsk)) - free_task(tsk); - } -@@ -677,7 +693,8 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) - - mm = get_task_mm(task); - if (mm && mm != current->mm && -- !ptrace_may_access(task, mode)) { -+ !ptrace_may_access(task, mode) && -+ !capable(CAP_SYS_RESOURCE)) { - mmput(mm); - mm = ERR_PTR(-EACCES); - } -diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c -index 15e53b17..fe4b09cf 100644 ---- a/kernel/irq/pm.c -+++ b/kernel/irq/pm.c -@@ -104,8 +104,13 @@ int check_wakeup_irqs(void) - - for_each_irq_desc(irq, desc) { - if (irqd_is_wakeup_set(&desc->irq_data)) { -- if (desc->istate & IRQS_PENDING) -+ if (desc->istate & IRQS_PENDING) { -+ pr_info("Wakeup IRQ %d %s pending, suspend aborted\n", -+ irq, -+ desc->action && desc->action->name ? -+ desc->action->name : ""); - return -EBUSY; -+ } - continue; - } - /* -diff --git a/kernel/panic.c b/kernel/panic.c -index 9ed023b8..90fd4431 100644 ---- a/kernel/panic.c -+++ b/kernel/panic.c -@@ -27,13 +27,19 @@ - #define PANIC_TIMER_STEP 100 - #define PANIC_BLINK_SPD 18 - -+/* Machine specific panic information string */ -+char *mach_panic_string; -+ - int panic_on_oops; - static unsigned long tainted_mask; - static int pause_on_oops; - static int pause_on_oops_flag; - static DEFINE_SPINLOCK(pause_on_oops_lock); - --int panic_timeout; -+#ifndef CONFIG_PANIC_TIMEOUT -+#define CONFIG_PANIC_TIMEOUT 0 -+#endif -+int panic_timeout = CONFIG_PANIC_TIMEOUT; - EXPORT_SYMBOL_GPL(panic_timeout); - - ATOMIC_NOTIFIER_HEAD(panic_notifier_list); -@@ -375,6 +381,11 @@ late_initcall(init_oops_id); - void print_oops_end_marker(void) - { - init_oops_id(); -+ -+ if (mach_panic_string) -+ printk(KERN_WARNING "Board Information: %s\n", -+ mach_panic_string); -+ - printk(KERN_WARNING "---[ end trace %016llx ]---\n", - (unsigned long long)oops_id); - } -diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig -index deb5461e..904fc660 100644 ---- a/kernel/power/Kconfig -+++ b/kernel/power/Kconfig -@@ -18,6 +18,14 @@ config SUSPEND_FREEZER - - Turning OFF this setting is NOT recommended! If in doubt, say Y. - -+config HAS_WAKELOCK -+ bool -+ default y -+ -+config WAKELOCK -+ bool -+ default y -+ - config HIBERNATE_CALLBACKS - bool - -@@ -103,6 +111,33 @@ config PM_SLEEP_SMP - select HOTPLUG - select HOTPLUG_CPU - -+config PM_AUTOSLEEP -+ bool "Opportunistic sleep" -+ depends on PM_SLEEP -+ default n -+ ---help--- -+ Allow the kernel to trigger a system transition into a global sleep -+ state automatically whenever there are no active wakeup sources. -+ -+config PM_WAKELOCKS -+ bool "User space wakeup sources interface" -+ depends on PM_SLEEP -+ default n -+ ---help--- -+ Allow user space to create, activate and deactivate wakeup source -+ objects with the help of a sysfs-based interface. -+ -+config PM_WAKELOCKS_LIMIT -+ int "Maximum number of user space wakeup sources (0 = no limit)" -+ range 0 100000 -+ default 100 -+ depends on PM_WAKELOCKS -+ -+config PM_WAKELOCKS_GC -+ bool "Garbage collector for user space wakeup sources" -+ depends on PM_WAKELOCKS -+ default y -+ - config PM_RUNTIME - bool "Run-time PM core functionality" - depends on !IA64_HP_SIM -@@ -243,3 +278,10 @@ config PM_GENERIC_DOMAINS_RUNTIME - config CPU_PM - bool - depends on SUSPEND || CPU_IDLE -+ -+config SUSPEND_TIME -+ bool "Log time spent in suspend" -+ ---help--- -+ Prints the time spent in suspend in the kernel log, and -+ keeps statistics on the time spent in suspend in -+ /sys/kernel/debug/suspend_time -diff --git a/kernel/power/Makefile b/kernel/power/Makefile -index 66d808ec..8450b85d 100644 ---- a/kernel/power/Makefile -+++ b/kernel/power/Makefile -@@ -9,5 +9,8 @@ obj-$(CONFIG_SUSPEND) += suspend.o - obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o - obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \ - block_io.o -+obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o -+obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o -+obj-$(CONFIG_SUSPEND_TIME) += suspend_time.o - - obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o -diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c -new file mode 100644 -index 00000000..ca304046 ---- /dev/null -+++ b/kernel/power/autosleep.c -@@ -0,0 +1,127 @@ -+/* -+ * kernel/power/autosleep.c -+ * -+ * Opportunistic sleep support. -+ * -+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl> -+ */ -+ -+#include <linux/device.h> -+#include <linux/mutex.h> -+#include <linux/pm_wakeup.h> -+ -+#include "power.h" -+ -+static suspend_state_t autosleep_state; -+static struct workqueue_struct *autosleep_wq; -+/* -+ * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source -+ * is active, otherwise a deadlock with try_to_suspend() is possible. -+ * Alternatively mutex_lock_interruptible() can be used. This will then fail -+ * if an auto_sleep cycle tries to freeze processes. -+ */ -+static DEFINE_MUTEX(autosleep_lock); -+static struct wakeup_source *autosleep_ws; -+ -+static void try_to_suspend(struct work_struct *work) -+{ -+ unsigned int initial_count, final_count; -+ -+ if (!pm_get_wakeup_count(&initial_count, true)) -+ goto out; -+ -+ mutex_lock(&autosleep_lock); -+ -+ if (!pm_save_wakeup_count(initial_count)) { -+ mutex_unlock(&autosleep_lock); -+ goto out; -+ } -+ -+ if (autosleep_state == PM_SUSPEND_ON) { -+ mutex_unlock(&autosleep_lock); -+ return; -+ } -+ if (autosleep_state >= PM_SUSPEND_MAX) -+ hibernate(); -+ else -+ pm_suspend(autosleep_state); -+ -+ mutex_unlock(&autosleep_lock); -+ -+ if (!pm_get_wakeup_count(&final_count, false)) -+ goto out; -+ -+ /* -+ * If the wakeup occured for an unknown reason, wait to prevent the -+ * system from trying to suspend and waking up in a tight loop. -+ */ -+ if (final_count == initial_count) -+ schedule_timeout_uninterruptible(HZ / 2); -+ -+ out: -+ queue_up_suspend_work(); -+} -+ -+static DECLARE_WORK(suspend_work, try_to_suspend); -+ -+void queue_up_suspend_work(void) -+{ -+ if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON) -+ queue_work(autosleep_wq, &suspend_work); -+} -+ -+suspend_state_t pm_autosleep_state(void) -+{ -+ return autosleep_state; -+} -+ -+int pm_autosleep_lock(void) -+{ -+ return mutex_lock_interruptible(&autosleep_lock); -+} -+ -+void pm_autosleep_unlock(void) -+{ -+ mutex_unlock(&autosleep_lock); -+} -+ -+int pm_autosleep_set_state(suspend_state_t state) -+{ -+ -+#ifndef CONFIG_HIBERNATION -+ if (state >= PM_SUSPEND_MAX) -+ return -EINVAL; -+#endif -+ -+ __pm_stay_awake(autosleep_ws); -+ -+ mutex_lock(&autosleep_lock); -+ -+ autosleep_state = state; -+ -+ __pm_relax(autosleep_ws); -+ -+ if (state > PM_SUSPEND_ON) { -+ pm_wakep_autosleep_enabled(true); -+ queue_up_suspend_work(); -+ } else { -+ pm_wakep_autosleep_enabled(false); -+ } -+ -+ mutex_unlock(&autosleep_lock); -+ return 0; -+} -+ -+int __init pm_autosleep_init(void) -+{ -+ autosleep_ws = wakeup_source_register("autosleep"); -+ if (!autosleep_ws) -+ return -ENOMEM; -+ -+ autosleep_wq = alloc_ordered_workqueue("autosleep", 0); -+ if (autosleep_wq) -+ return 0; -+ -+ wakeup_source_unregister(autosleep_ws); -+ return -ENOMEM; -+} -diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c -index 52a18173..586521aa 100644 ---- a/kernel/power/hibernate.c -+++ b/kernel/power/hibernate.c -@@ -25,6 +25,8 @@ - #include <linux/freezer.h> - #include <linux/gfp.h> - #include <linux/syscore_ops.h> -+#include <linux/ctype.h> -+#include <linux/genhd.h> - #include <scsi/scsi_scan.h> - - #include "power.h" -@@ -728,6 +730,17 @@ static int software_resume(void) - - /* Check if the device is there */ - swsusp_resume_device = name_to_dev_t(resume_file); -+ -+ /* -+ * name_to_dev_t is ineffective to verify parition if resume_file is in -+ * integer format. (e.g. major:minor) -+ */ -+ if (isdigit(resume_file[0]) && resume_wait) { -+ int partno; -+ while (!get_gendisk(swsusp_resume_device, &partno)) -+ msleep(10); -+ } -+ - if (!swsusp_resume_device) { - /* - * Some device discovery might still be in progress; we need -diff --git a/kernel/power/main.c b/kernel/power/main.c -index 1c12581f..428f8a03 100644 ---- a/kernel/power/main.c -+++ b/kernel/power/main.c -@@ -269,8 +269,7 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, - return (s - buf); - } - --static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, -- const char *buf, size_t n) -+static suspend_state_t decode_state(const char *buf, size_t n) - { - #ifdef CONFIG_SUSPEND - suspend_state_t state = PM_SUSPEND_STANDBY; -@@ -278,27 +277,48 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, - #endif - char *p; - int len; -- int error = -EINVAL; - - p = memchr(buf, '\n', n); - len = p ? p - buf : n; - -- /* First, check if we are requested to hibernate */ -- if (len == 4 && !strncmp(buf, "disk", len)) { -- error = hibernate(); -- goto Exit; -- } -+ /* Check hibernation first. */ -+ if (len == 4 && !strncmp(buf, "disk", len)) -+ return PM_SUSPEND_MAX; - - #ifdef CONFIG_SUSPEND -- for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { -- if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { -- error = pm_suspend(state); -- break; -- } -- } -+ for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) -+ if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) -+ return state; - #endif - -- Exit: -+ return PM_SUSPEND_ON; -+} -+ -+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ suspend_state_t state; -+ int error; -+ -+ error = pm_autosleep_lock(); -+ if (error) -+ return error; -+ -+ if (pm_autosleep_state() > PM_SUSPEND_ON) { -+ error = -EBUSY; -+ goto out; -+ } -+ -+ state = decode_state(buf, n); -+ if (state < PM_SUSPEND_MAX) -+ error = pm_suspend(state); -+ else if (state == PM_SUSPEND_MAX) -+ error = hibernate(); -+ else -+ error = -EINVAL; -+ -+ out: -+ pm_autosleep_unlock(); - return error ? error : n; - } - -@@ -339,7 +359,8 @@ static ssize_t wakeup_count_show(struct kobject *kobj, - { - unsigned int val; - -- return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR; -+ return pm_get_wakeup_count(&val, true) ? -+ sprintf(buf, "%u\n", val) : -EINTR; - } - - static ssize_t wakeup_count_store(struct kobject *kobj, -@@ -347,15 +368,106 @@ static ssize_t wakeup_count_store(struct kobject *kobj, - const char *buf, size_t n) - { - unsigned int val; -+ int error; -+ -+ error = pm_autosleep_lock(); -+ if (error) -+ return error; -+ -+ if (pm_autosleep_state() > PM_SUSPEND_ON) { -+ error = -EBUSY; -+ goto out; -+ } - -+ error = -EINVAL; - if (sscanf(buf, "%u", &val) == 1) { - if (pm_save_wakeup_count(val)) -- return n; -+ error = n; - } -- return -EINVAL; -+ -+ out: -+ pm_autosleep_unlock(); -+ return error; - } - - power_attr(wakeup_count); -+ -+#ifdef CONFIG_PM_AUTOSLEEP -+static ssize_t autosleep_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ suspend_state_t state = pm_autosleep_state(); -+ -+ if (state == PM_SUSPEND_ON) -+ return sprintf(buf, "off\n"); -+ -+#ifdef CONFIG_SUSPEND -+ if (state < PM_SUSPEND_MAX) -+ return sprintf(buf, "%s\n", valid_state(state) ? -+ pm_states[state] : "error"); -+#endif -+#ifdef CONFIG_HIBERNATION -+ return sprintf(buf, "disk\n"); -+#else -+ return sprintf(buf, "error"); -+#endif -+} -+ -+static ssize_t autosleep_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ suspend_state_t state = decode_state(buf, n); -+ int error; -+ -+ if (state == PM_SUSPEND_ON -+ && strcmp(buf, "off") && strcmp(buf, "off\n")) -+ return -EINVAL; -+ -+ error = pm_autosleep_set_state(state); -+ return error ? error : n; -+} -+ -+power_attr(autosleep); -+#endif /* CONFIG_PM_AUTOSLEEP */ -+ -+#ifdef CONFIG_PM_WAKELOCKS -+static ssize_t wake_lock_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ return pm_show_wakelocks(buf, true); -+} -+ -+static ssize_t wake_lock_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ int error = pm_wake_lock(buf); -+ return error ? error : n; -+} -+ -+power_attr(wake_lock); -+ -+static ssize_t wake_unlock_show(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf) -+{ -+ return pm_show_wakelocks(buf, false); -+} -+ -+static ssize_t wake_unlock_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t n) -+{ -+ int error = pm_wake_unlock(buf); -+ return error ? error : n; -+} -+ -+power_attr(wake_unlock); -+ -+#endif /* CONFIG_PM_WAKELOCKS */ - #endif /* CONFIG_PM_SLEEP */ - - #ifdef CONFIG_PM_TRACE -@@ -409,6 +521,13 @@ static struct attribute * g[] = { - #ifdef CONFIG_PM_SLEEP - &pm_async_attr.attr, - &wakeup_count_attr.attr, -+#ifdef CONFIG_PM_AUTOSLEEP -+ &autosleep_attr.attr, -+#endif -+#ifdef CONFIG_PM_WAKELOCKS -+ &wake_lock_attr.attr, -+ &wake_unlock_attr.attr, -+#endif - #ifdef CONFIG_PM_DEBUG - &pm_test_attr.attr, - #endif -@@ -444,7 +563,10 @@ static int __init pm_init(void) - power_kobj = kobject_create_and_add("power", NULL); - if (!power_kobj) - return -ENOMEM; -- return sysfs_create_group(power_kobj, &attr_group); -+ error = sysfs_create_group(power_kobj, &attr_group); -+ if (error) -+ return error; -+ return pm_autosleep_init(); - } - - core_initcall(pm_init); -diff --git a/kernel/power/power.h b/kernel/power/power.h -index 98f3622d..b0bd4bea 100644 ---- a/kernel/power/power.h -+++ b/kernel/power/power.h -@@ -264,3 +264,30 @@ static inline void suspend_thaw_processes(void) - { - } - #endif -+ -+#ifdef CONFIG_PM_AUTOSLEEP -+ -+/* kernel/power/autosleep.c */ -+extern int pm_autosleep_init(void); -+extern int pm_autosleep_lock(void); -+extern void pm_autosleep_unlock(void); -+extern suspend_state_t pm_autosleep_state(void); -+extern int pm_autosleep_set_state(suspend_state_t state); -+ -+#else /* !CONFIG_PM_AUTOSLEEP */ -+ -+static inline int pm_autosleep_init(void) { return 0; } -+static inline int pm_autosleep_lock(void) { return 0; } -+static inline void pm_autosleep_unlock(void) {} -+static inline suspend_state_t pm_autosleep_state(void) { return PM_SUSPEND_ON; } -+ -+#endif /* !CONFIG_PM_AUTOSLEEP */ -+ -+#ifdef CONFIG_PM_WAKELOCKS -+ -+/* kernel/power/wakelock.c */ -+extern ssize_t pm_show_wakelocks(char *buf, bool show_active); -+extern int pm_wake_lock(const char *buf); -+extern int pm_wake_unlock(const char *buf); -+ -+#endif /* !CONFIG_PM_WAKELOCKS */ -diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c -index c8b7446b..e97a689f 100644 ---- a/kernel/power/suspend.c -+++ b/kernel/power/suspend.c -@@ -25,6 +25,7 @@ - #include <linux/suspend.h> - #include <linux/syscore_ops.h> - #include <linux/ftrace.h> -+#include <linux/rtc.h> - #include <trace/events/power.h> - - #include "power.h" -@@ -303,6 +304,18 @@ static int enter_state(suspend_state_t state) - return error; - } - -+static void pm_suspend_marker(char *annotation) -+{ -+ struct timespec ts; -+ struct rtc_time tm; -+ -+ getnstimeofday(&ts); -+ rtc_time_to_tm(ts.tv_sec, &tm); -+ pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n", -+ annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, -+ tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); -+} -+ - /** - * pm_suspend - Externally visible function for suspending the system. - * @state: System sleep state to enter. -@@ -317,6 +330,7 @@ int pm_suspend(suspend_state_t state) - if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) - return -EINVAL; - -+ pm_suspend_marker("entry"); - error = enter_state(state); - if (error) { - suspend_stats.fail++; -@@ -324,6 +338,7 @@ int pm_suspend(suspend_state_t state) - } else { - suspend_stats.success++; - } -+ pm_suspend_marker("exit"); - return error; - } - EXPORT_SYMBOL(pm_suspend); -diff --git a/kernel/power/suspend_time.c b/kernel/power/suspend_time.c -new file mode 100644 -index 00000000..d2a65da9 ---- /dev/null -+++ b/kernel/power/suspend_time.c -@@ -0,0 +1,111 @@ -+/* -+ * debugfs file to track time spent in suspend -+ * -+ * Copyright (c) 2011, Google, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ */ -+ -+#include <linux/debugfs.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/seq_file.h> -+#include <linux/syscore_ops.h> -+#include <linux/time.h> -+ -+static struct timespec suspend_time_before; -+static unsigned int time_in_suspend_bins[32]; -+ -+#ifdef CONFIG_DEBUG_FS -+static int suspend_time_debug_show(struct seq_file *s, void *data) -+{ -+ int bin; -+ seq_printf(s, "time (secs) count\n"); -+ seq_printf(s, "------------------\n"); -+ for (bin = 0; bin < 32; bin++) { -+ if (time_in_suspend_bins[bin] == 0) -+ continue; -+ seq_printf(s, "%4d - %4d %4u\n", -+ bin ? 1 << (bin - 1) : 0, 1 << bin, -+ time_in_suspend_bins[bin]); -+ } -+ return 0; -+} -+ -+static int suspend_time_debug_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, suspend_time_debug_show, NULL); -+} -+ -+static const struct file_operations suspend_time_debug_fops = { -+ .open = suspend_time_debug_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static int __init suspend_time_debug_init(void) -+{ -+ struct dentry *d; -+ -+ d = debugfs_create_file("suspend_time", 0755, NULL, NULL, -+ &suspend_time_debug_fops); -+ if (!d) { -+ pr_err("Failed to create suspend_time debug file\n"); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+late_initcall(suspend_time_debug_init); -+#endif -+ -+static int suspend_time_syscore_suspend(void) -+{ -+ read_persistent_clock(&suspend_time_before); -+ -+ return 0; -+} -+ -+static void suspend_time_syscore_resume(void) -+{ -+ struct timespec after; -+ -+ read_persistent_clock(&after); -+ -+ after = timespec_sub(after, suspend_time_before); -+ -+ time_in_suspend_bins[fls(after.tv_sec)]++; -+ -+ pr_info("Suspended for %lu.%03lu seconds\n", after.tv_sec, -+ after.tv_nsec / NSEC_PER_MSEC); -+} -+ -+static struct syscore_ops suspend_time_syscore_ops = { -+ .suspend = suspend_time_syscore_suspend, -+ .resume = suspend_time_syscore_resume, -+}; -+ -+static int suspend_time_syscore_init(void) -+{ -+ register_syscore_ops(&suspend_time_syscore_ops); -+ -+ return 0; -+} -+ -+static void suspend_time_syscore_exit(void) -+{ -+ unregister_syscore_ops(&suspend_time_syscore_ops); -+} -+module_init(suspend_time_syscore_init); -+module_exit(suspend_time_syscore_exit); -diff --git a/kernel/power/swap.c b/kernel/power/swap.c -index eef311a5..11e22c06 100644 ---- a/kernel/power/swap.c -+++ b/kernel/power/swap.c -@@ -6,7 +6,7 @@ - * - * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> - * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> -- * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com> -+ * Copyright (C) 2010-2012 Bojan Smojver <bojan@rexursive.com> - * - * This file is released under the GPLv2. - * -@@ -282,14 +282,17 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain) - return -ENOSPC; - - if (bio_chain) { -- src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); -+ src = (void *)__get_free_page(__GFP_WAIT | __GFP_NOWARN | -+ __GFP_NORETRY); - if (src) { - copy_page(src, buf); - } else { - ret = hib_wait_on_bio_chain(bio_chain); /* Free pages */ - if (ret) - return ret; -- src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); -+ src = (void *)__get_free_page(__GFP_WAIT | -+ __GFP_NOWARN | -+ __GFP_NORETRY); - if (src) { - copy_page(src, buf); - } else { -@@ -367,12 +370,17 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, - clear_page(handle->cur); - handle->cur_swap = offset; - handle->k = 0; -- } -- if (bio_chain && low_free_pages() <= handle->reqd_free_pages) { -- error = hib_wait_on_bio_chain(bio_chain); -- if (error) -- goto out; -- handle->reqd_free_pages = reqd_free_pages(); -+ -+ if (bio_chain && low_free_pages() <= handle->reqd_free_pages) { -+ error = hib_wait_on_bio_chain(bio_chain); -+ if (error) -+ goto out; -+ /* -+ * Recalculate the number of required free pages, to -+ * make sure we never take more than half. -+ */ -+ handle->reqd_free_pages = reqd_free_pages(); -+ } - } - out: - return error; -@@ -419,8 +427,9 @@ static int swap_writer_finish(struct swap_map_handle *handle, - /* Maximum number of threads for compression/decompression. */ - #define LZO_THREADS 3 - --/* Maximum number of pages for read buffering. */ --#define LZO_READ_PAGES (MAP_PAGE_ENTRIES * 8) -+/* Minimum/maximum number of pages for read buffering. */ -+#define LZO_MIN_RD_PAGES 1024 -+#define LZO_MAX_RD_PAGES 8192 - - - /** -@@ -630,12 +639,6 @@ static int save_image_lzo(struct swap_map_handle *handle, - } - } - -- /* -- * Adjust number of free pages after all allocations have been done. -- * We don't want to run out of pages when writing. -- */ -- handle->reqd_free_pages = reqd_free_pages(); -- - /* - * Start the CRC32 thread. - */ -@@ -657,6 +660,12 @@ static int save_image_lzo(struct swap_map_handle *handle, - goto out_clean; - } - -+ /* -+ * Adjust the number of required free pages after all allocations have -+ * been done. We don't want to run out of pages when writing. -+ */ -+ handle->reqd_free_pages = reqd_free_pages(); -+ - printk(KERN_INFO - "PM: Using %u thread(s) for compression.\n" - "PM: Compressing and saving image data (%u pages) ... ", -@@ -1067,7 +1076,7 @@ static int load_image_lzo(struct swap_map_handle *handle, - unsigned i, thr, run_threads, nr_threads; - unsigned ring = 0, pg = 0, ring_size = 0, - have = 0, want, need, asked = 0; -- unsigned long read_pages; -+ unsigned long read_pages = 0; - unsigned char **page = NULL; - struct dec_data *data = NULL; - struct crc_data *crc = NULL; -@@ -1079,7 +1088,7 @@ static int load_image_lzo(struct swap_map_handle *handle, - nr_threads = num_online_cpus() - 1; - nr_threads = clamp_val(nr_threads, 1, LZO_THREADS); - -- page = vmalloc(sizeof(*page) * LZO_READ_PAGES); -+ page = vmalloc(sizeof(*page) * LZO_MAX_RD_PAGES); - if (!page) { - printk(KERN_ERR "PM: Failed to allocate LZO page\n"); - ret = -ENOMEM; -@@ -1144,15 +1153,22 @@ static int load_image_lzo(struct swap_map_handle *handle, - } - - /* -- * Adjust number of pages for read buffering, in case we are short. -+ * Set the number of pages for read buffering. -+ * This is complete guesswork, because we'll only know the real -+ * picture once prepare_image() is called, which is much later on -+ * during the image load phase. We'll assume the worst case and -+ * say that none of the image pages are from high memory. - */ -- read_pages = (nr_free_pages() - snapshot_get_image_size()) >> 1; -- read_pages = clamp_val(read_pages, LZO_CMP_PAGES, LZO_READ_PAGES); -+ if (low_free_pages() > snapshot_get_image_size()) -+ read_pages = (low_free_pages() - snapshot_get_image_size()) / 2; -+ read_pages = clamp_val(read_pages, LZO_MIN_RD_PAGES, LZO_MAX_RD_PAGES); - - for (i = 0; i < read_pages; i++) { - page[i] = (void *)__get_free_page(i < LZO_CMP_PAGES ? - __GFP_WAIT | __GFP_HIGH : -- __GFP_WAIT); -+ __GFP_WAIT | __GFP_NOWARN | -+ __GFP_NORETRY); -+ - if (!page[i]) { - if (i < LZO_CMP_PAGES) { - ring_size = i; -diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c -new file mode 100644 -index 00000000..c8fba338 ---- /dev/null -+++ b/kernel/power/wakelock.c -@@ -0,0 +1,259 @@ -+/* -+ * kernel/power/wakelock.c -+ * -+ * User space wakeup sources support. -+ * -+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl> -+ * -+ * This code is based on the analogous interface allowing user space to -+ * manipulate wakelocks on Android. -+ */ -+ -+#include <linux/ctype.h> -+#include <linux/device.h> -+#include <linux/err.h> -+#include <linux/hrtimer.h> -+#include <linux/list.h> -+#include <linux/rbtree.h> -+#include <linux/slab.h> -+ -+static DEFINE_MUTEX(wakelocks_lock); -+ -+struct wakelock { -+ char *name; -+ struct rb_node node; -+ struct wakeup_source ws; -+#ifdef CONFIG_PM_WAKELOCKS_GC -+ struct list_head lru; -+#endif -+}; -+ -+static struct rb_root wakelocks_tree = RB_ROOT; -+ -+ssize_t pm_show_wakelocks(char *buf, bool show_active) -+{ -+ struct rb_node *node; -+ struct wakelock *wl; -+ char *str = buf; -+ char *end = buf + PAGE_SIZE; -+ -+ mutex_lock(&wakelocks_lock); -+ -+ for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) { -+ wl = rb_entry(node, struct wakelock, node); -+ if (wl->ws.active == show_active) -+ str += scnprintf(str, end - str, "%s ", wl->name); -+ } -+ if (str > buf) -+ str--; -+ -+ str += scnprintf(str, end - str, "\n"); -+ -+ mutex_unlock(&wakelocks_lock); -+ return (str - buf); -+} -+ -+#if CONFIG_PM_WAKELOCKS_LIMIT > 0 -+static unsigned int number_of_wakelocks; -+ -+static inline bool wakelocks_limit_exceeded(void) -+{ -+ return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT; -+} -+ -+static inline void increment_wakelocks_number(void) -+{ -+ number_of_wakelocks++; -+} -+ -+static inline void decrement_wakelocks_number(void) -+{ -+ number_of_wakelocks--; -+} -+#else /* CONFIG_PM_WAKELOCKS_LIMIT = 0 */ -+static inline bool wakelocks_limit_exceeded(void) { return false; } -+static inline void increment_wakelocks_number(void) {} -+static inline void decrement_wakelocks_number(void) {} -+#endif /* CONFIG_PM_WAKELOCKS_LIMIT */ -+ -+#ifdef CONFIG_PM_WAKELOCKS_GC -+#define WL_GC_COUNT_MAX 100 -+#define WL_GC_TIME_SEC 300 -+ -+static LIST_HEAD(wakelocks_lru_list); -+static unsigned int wakelocks_gc_count; -+ -+static inline void wakelocks_lru_add(struct wakelock *wl) -+{ -+ list_add(&wl->lru, &wakelocks_lru_list); -+} -+ -+static inline void wakelocks_lru_most_recent(struct wakelock *wl) -+{ -+ list_move(&wl->lru, &wakelocks_lru_list); -+} -+ -+static void wakelocks_gc(void) -+{ -+ struct wakelock *wl, *aux; -+ ktime_t now; -+ -+ if (++wakelocks_gc_count <= WL_GC_COUNT_MAX) -+ return; -+ -+ now = ktime_get(); -+ list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) { -+ u64 idle_time_ns; -+ bool active; -+ -+ spin_lock_irq(&wl->ws.lock); -+ idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time)); -+ active = wl->ws.active; -+ spin_unlock_irq(&wl->ws.lock); -+ -+ if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC)) -+ break; -+ -+ if (!active) { -+ wakeup_source_remove(&wl->ws); -+ rb_erase(&wl->node, &wakelocks_tree); -+ list_del(&wl->lru); -+ kfree(wl->name); -+ kfree(wl); -+ decrement_wakelocks_number(); -+ } -+ } -+ wakelocks_gc_count = 0; -+} -+#else /* !CONFIG_PM_WAKELOCKS_GC */ -+static inline void wakelocks_lru_add(struct wakelock *wl) {} -+static inline void wakelocks_lru_most_recent(struct wakelock *wl) {} -+static inline void wakelocks_gc(void) {} -+#endif /* !CONFIG_PM_WAKELOCKS_GC */ -+ -+static struct wakelock *wakelock_lookup_add(const char *name, size_t len, -+ bool add_if_not_found) -+{ -+ struct rb_node **node = &wakelocks_tree.rb_node; -+ struct rb_node *parent = *node; -+ struct wakelock *wl; -+ -+ while (*node) { -+ int diff; -+ -+ parent = *node; -+ wl = rb_entry(*node, struct wakelock, node); -+ diff = strncmp(name, wl->name, len); -+ if (diff == 0) { -+ if (wl->name[len]) -+ diff = -1; -+ else -+ return wl; -+ } -+ if (diff < 0) -+ node = &(*node)->rb_left; -+ else -+ node = &(*node)->rb_right; -+ } -+ if (!add_if_not_found) -+ return ERR_PTR(-EINVAL); -+ -+ if (wakelocks_limit_exceeded()) -+ return ERR_PTR(-ENOSPC); -+ -+ /* Not found, we have to add a new one. */ -+ wl = kzalloc(sizeof(*wl), GFP_KERNEL); -+ if (!wl) -+ return ERR_PTR(-ENOMEM); -+ -+ wl->name = kstrndup(name, len, GFP_KERNEL); -+ if (!wl->name) { -+ kfree(wl); -+ return ERR_PTR(-ENOMEM); -+ } -+ wl->ws.name = wl->name; -+ wakeup_source_add(&wl->ws); -+ rb_link_node(&wl->node, parent, node); -+ rb_insert_color(&wl->node, &wakelocks_tree); -+ wakelocks_lru_add(wl); -+ increment_wakelocks_number(); -+ return wl; -+} -+ -+int pm_wake_lock(const char *buf) -+{ -+ const char *str = buf; -+ struct wakelock *wl; -+ u64 timeout_ns = 0; -+ size_t len; -+ int ret = 0; -+ -+ while (*str && !isspace(*str)) -+ str++; -+ -+ len = str - buf; -+ if (!len) -+ return -EINVAL; -+ -+ if (*str && *str != '\n') { -+ /* Find out if there's a valid timeout string appended. */ -+ ret = kstrtou64(skip_spaces(str), 10, &timeout_ns); -+ if (ret) -+ return -EINVAL; -+ } -+ -+ mutex_lock(&wakelocks_lock); -+ -+ wl = wakelock_lookup_add(buf, len, true); -+ if (IS_ERR(wl)) { -+ ret = PTR_ERR(wl); -+ goto out; -+ } -+ if (timeout_ns) { -+ u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1; -+ -+ do_div(timeout_ms, NSEC_PER_MSEC); -+ __pm_wakeup_event(&wl->ws, timeout_ms); -+ } else { -+ __pm_stay_awake(&wl->ws); -+ } -+ -+ wakelocks_lru_most_recent(wl); -+ -+ out: -+ mutex_unlock(&wakelocks_lock); -+ return ret; -+} -+ -+int pm_wake_unlock(const char *buf) -+{ -+ struct wakelock *wl; -+ size_t len; -+ int ret = 0; -+ -+ len = strlen(buf); -+ if (!len) -+ return -EINVAL; -+ -+ if (buf[len-1] == '\n') -+ len--; -+ -+ if (!len) -+ return -EINVAL; -+ -+ mutex_lock(&wakelocks_lock); -+ -+ wl = wakelock_lookup_add(buf, len, false); -+ if (IS_ERR(wl)) { -+ ret = PTR_ERR(wl); -+ goto out; -+ } -+ __pm_relax(&wl->ws); -+ -+ wakelocks_lru_most_recent(wl); -+ wakelocks_gc(); -+ -+ out: -+ mutex_unlock(&wakelocks_lock); -+ return ret; -+} -diff --git a/kernel/printk.c b/kernel/printk.c -index e95c6622..ffe4b65a 100644 ---- a/kernel/printk.c -+++ b/kernel/printk.c -@@ -56,6 +56,10 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) - - #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) - -+#ifdef CONFIG_DEBUG_LL -+extern void printascii(char *); -+#endif -+ - /* printk's without a loglevel use this.. */ - #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL - -@@ -293,6 +297,53 @@ static inline void boot_delay_msec(void) - } - #endif - -+/* -+ * Return the number of unread characters in the log buffer. -+ */ -+static int log_buf_get_len(void) -+{ -+ return logged_chars; -+} -+ -+/* -+ * Clears the ring-buffer -+ */ -+void log_buf_clear(void) -+{ -+ logged_chars = 0; -+} -+ -+/* -+ * Copy a range of characters from the log buffer. -+ */ -+int log_buf_copy(char *dest, int idx, int len) -+{ -+ int ret, max; -+ bool took_lock = false; -+ -+ if (!oops_in_progress) { -+ raw_spin_lock_irq(&logbuf_lock); -+ took_lock = true; -+ } -+ -+ max = log_buf_get_len(); -+ if (idx < 0 || idx >= max) { -+ ret = -1; -+ } else { -+ if (len > max - idx) -+ len = max - idx; -+ ret = len; -+ idx += (log_end - max); -+ while (len-- > 0) -+ dest[len] = LOG_BUF(idx + len); -+ } -+ -+ if (took_lock) -+ raw_spin_unlock_irq(&logbuf_lock); -+ -+ return ret; -+} -+ - #ifdef CONFIG_SECURITY_DMESG_RESTRICT - int dmesg_restrict = 1; - #else -@@ -895,6 +946,10 @@ asmlinkage int vprintk(const char *fmt, va_list args) - printed_len += vscnprintf(printk_buf + printed_len, - sizeof(printk_buf) - printed_len, fmt, args); - -+#ifdef CONFIG_DEBUG_LL -+ printascii(printk_buf); -+#endif -+ - p = printk_buf; - - /* Read log level and handle special printk prefix */ -@@ -1172,7 +1227,6 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self, - switch (action) { - case CPU_ONLINE: - case CPU_DEAD: -- case CPU_DYING: - case CPU_DOWN_FAILED: - case CPU_UP_CANCELED: - console_lock(); -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index e1718bc3..d10a575b 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -7243,13 +7243,24 @@ static inline int preempt_count_equals(int preempt_offset) - return (nested == preempt_offset); - } - -+static int __might_sleep_init_called; -+int __init __might_sleep_init(void) -+{ -+ __might_sleep_init_called = 1; -+ return 0; -+} -+early_initcall(__might_sleep_init); -+ - void __might_sleep(const char *file, int line, int preempt_offset) - { - static unsigned long prev_jiffy; /* ratelimiting */ - - rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */ - if ((preempt_count_equals(preempt_offset) && !irqs_disabled()) || -- system_state != SYSTEM_RUNNING || oops_in_progress) -+ oops_in_progress) -+ return; -+ if (system_state != SYSTEM_RUNNING && -+ (!__might_sleep_init_called || system_state != SYSTEM_BOOTING)) - return; - if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) - return; -@@ -7809,6 +7820,23 @@ static void cpu_cgroup_destroy(struct cgroup *cgrp) - sched_destroy_group(tg); - } - -+static int -+cpu_cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) -+{ -+ const struct cred *cred = current_cred(), *tcred; -+ struct task_struct *task; -+ -+ cgroup_taskset_for_each(task, cgrp, tset) { -+ tcred = __task_cred(task); -+ -+ if ((current != task) && !capable(CAP_SYS_NICE) && -+ cred->euid != tcred->uid && cred->euid != tcred->suid) -+ return -EACCES; -+ } -+ -+ return 0; -+} -+ - static int cpu_cgroup_can_attach(struct cgroup *cgrp, - struct cgroup_taskset *tset) - { -@@ -8170,6 +8198,7 @@ struct cgroup_subsys cpu_cgroup_subsys = { - .destroy = cpu_cgroup_destroy, - .can_attach = cpu_cgroup_can_attach, - .attach = cpu_cgroup_attach, -+ .allow_attach = cpu_cgroup_allow_attach, - .exit = cpu_cgroup_exit, - .populate = cpu_cgroup_populate, - .subsys_id = cpu_cgroup_subsys_id, -diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c -index ead03360..e8a7a2c0 100644 ---- a/kernel/sched/rt.c -+++ b/kernel/sched/rt.c -@@ -1983,6 +1983,8 @@ static void watchdog(struct rq *rq, struct task_struct *p) - - static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) - { -+ struct sched_rt_entity *rt_se = &p->rt; -+ - update_curr_rt(rq); - - watchdog(rq, p); -@@ -2000,12 +2002,15 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) - p->rt.time_slice = RR_TIMESLICE; - - /* -- * Requeue to the end of queue if we are not the only element -- * on the queue: -+ * Requeue to the end of queue if we (and all of our ancestors) are the -+ * only element on the queue - */ -- if (p->rt.run_list.prev != p->rt.run_list.next) { -- requeue_task_rt(rq, p, 0); -- set_tsk_need_resched(p); -+ for_each_sched_rt_entity(rt_se) { -+ if (rt_se->run_list.prev != rt_se->run_list.next) { -+ requeue_task_rt(rq, p, 0); -+ set_tsk_need_resched(p); -+ return; -+ } - } - } - -diff --git a/kernel/signal.c b/kernel/signal.c -index a4363a98..563b7711 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -2208,7 +2208,7 @@ relock: - * Now that we woke up, it's crucial if we're supposed to be - * frozen that we freeze now before running anything substantial. - */ -- try_to_freeze(); -+ try_to_freeze_nowarn(); - - spin_lock_irq(&sighand->siglock); - /* -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 4ab11879..49f47258 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -102,6 +102,7 @@ extern char core_pattern[]; - extern unsigned int core_pipe_limit; - extern int pid_max; - extern int min_free_kbytes; -+extern int min_free_order_shift; - extern int pid_max_min, pid_max_max; - extern int sysctl_drop_caches; - extern int percpu_pagelist_fraction; -@@ -1198,6 +1199,13 @@ static struct ctl_table vm_table[] = { - .proc_handler = min_free_kbytes_sysctl_handler, - .extra1 = &zero, - }, -+ { -+ .procname = "min_free_order_shift", -+ .data = &min_free_order_shift, -+ .maxlen = sizeof(min_free_order_shift), -+ .mode = 0644, -+ .proc_handler = &proc_dointvec -+ }, - { - .procname = "percpu_pagelist_fraction", - .data = &percpu_pagelist_fraction, -diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c -index 8a538c55..f979d852 100644 ---- a/kernel/time/alarmtimer.c -+++ b/kernel/time/alarmtimer.c -@@ -46,6 +46,8 @@ static struct alarm_base { - static ktime_t freezer_delta; - static DEFINE_SPINLOCK(freezer_delta_lock); - -+static struct wakeup_source *ws; -+ - #ifdef CONFIG_RTC_CLASS - /* rtc timer and device for setting alarm wakeups at suspend */ - static struct rtc_timer rtctimer; -@@ -59,7 +61,7 @@ static DEFINE_SPINLOCK(rtcdev_lock); - * If one has not already been chosen, it checks to see if a - * functional rtc device is available. - */ --static struct rtc_device *alarmtimer_get_rtcdev(void) -+struct rtc_device *alarmtimer_get_rtcdev(void) - { - unsigned long flags; - struct rtc_device *ret; -@@ -115,7 +117,7 @@ static void alarmtimer_rtc_interface_remove(void) - class_interface_unregister(&alarmtimer_rtc_interface); - } - #else --static inline struct rtc_device *alarmtimer_get_rtcdev(void) -+struct rtc_device *alarmtimer_get_rtcdev(void) - { - return NULL; - } -@@ -250,6 +252,7 @@ static int alarmtimer_suspend(struct device *dev) - unsigned long flags; - struct rtc_device *rtc; - int i; -+ int ret; - - spin_lock_irqsave(&freezer_delta_lock, flags); - min = freezer_delta; -@@ -279,8 +282,10 @@ static int alarmtimer_suspend(struct device *dev) - if (min.tv64 == 0) - return 0; - -- /* XXX - Should we enforce a minimum sleep time? */ -- WARN_ON(min.tv64 < NSEC_PER_SEC); -+ if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) { -+ __pm_wakeup_event(ws, 2 * MSEC_PER_SEC); -+ return -EBUSY; -+ } - - /* Setup an rtc timer to fire that far in the future */ - rtc_timer_cancel(rtc, &rtctimer); -@@ -288,9 +293,11 @@ static int alarmtimer_suspend(struct device *dev) - now = rtc_tm_to_ktime(tm); - now = ktime_add(now, min); - -- rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); -- -- return 0; -+ /* Set alarm, if in the past reject suspend briefly to handle */ -+ ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); -+ if (ret < 0) -+ __pm_wakeup_event(ws, 1 * MSEC_PER_SEC); -+ return ret; - } - #else - static int alarmtimer_suspend(struct device *dev) -@@ -821,6 +828,7 @@ static int __init alarmtimer_init(void) - error = PTR_ERR(pdev); - goto out_drv; - } -+ ws = wakeup_source_register("alarmtimer"); - return 0; - - out_drv: -diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c -index eff0b1e9..0a462de7 100644 ---- a/kernel/time/timekeeping.c -+++ b/kernel/time/timekeeping.c -@@ -1193,7 +1193,7 @@ void get_monotonic_boottime(struct timespec *ts) - } while (read_seqretry(&timekeeper.lock, seq)); - - set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec, -- ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs); -+ (s64)ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs); - } - EXPORT_SYMBOL_GPL(get_monotonic_boottime); - -diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig -index a1d2849f..59a80f8a 100644 ---- a/kernel/trace/Kconfig -+++ b/kernel/trace/Kconfig -@@ -69,6 +69,9 @@ config EVENT_TRACING - select CONTEXT_SWITCH_TRACER - bool - -+config GPU_TRACEPOINTS -+ bool -+ - config EVENT_POWER_TRACING_DEPRECATED - depends on EVENT_TRACING - bool "Deprecated power event trace API, to be removed" -diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile -index 5f39a07f..fedcd61d 100644 ---- a/kernel/trace/Makefile -+++ b/kernel/trace/Makefile -@@ -61,5 +61,6 @@ endif - ifeq ($(CONFIG_TRACING),y) - obj-$(CONFIG_KGDB_KDB) += trace_kdb.o - endif -+obj-$(CONFIG_GPU_TRACEPOINTS) += gpu-traces.o - - libftrace-y := ftrace.o -diff --git a/kernel/trace/gpu-traces.c b/kernel/trace/gpu-traces.c -new file mode 100644 -index 00000000..a4b3f00f ---- /dev/null -+++ b/kernel/trace/gpu-traces.c -@@ -0,0 +1,23 @@ -+/* -+ * GPU tracepoints -+ * -+ * Copyright (C) 2013 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/module.h> -+ -+#define CREATE_TRACE_POINTS -+#include <trace/events/gpu.h> -+ -+EXPORT_TRACEPOINT_SYMBOL(gpu_sched_switch); -+EXPORT_TRACEPOINT_SYMBOL(gpu_job_enqueue); -diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c -index 55e4d4c5..418c79b0 100644 ---- a/kernel/trace/trace.c -+++ b/kernel/trace/trace.c -@@ -482,6 +482,7 @@ static const char *trace_options[] = { - "overwrite", - "disable_on_free", - "irq-info", -+ "print-tgid", - NULL - }; - -@@ -970,6 +971,7 @@ void tracing_reset_current_online_cpus(void) - static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; - static unsigned map_cmdline_to_pid[SAVED_CMDLINES]; - static char saved_cmdlines[SAVED_CMDLINES][TASK_COMM_LEN]; -+static unsigned saved_tgids[SAVED_CMDLINES]; - static int cmdline_idx; - static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; - -@@ -1117,6 +1119,7 @@ static void trace_save_cmdline(struct task_struct *tsk) - } - - memcpy(&saved_cmdlines[idx], tsk->comm, TASK_COMM_LEN); -+ saved_tgids[idx] = tsk->tgid; - - arch_spin_unlock(&trace_cmdline_lock); - } -@@ -1152,6 +1155,25 @@ void trace_find_cmdline(int pid, char comm[]) - preempt_enable(); - } - -+int trace_find_tgid(int pid) -+{ -+ unsigned map; -+ int tgid; -+ -+ preempt_disable(); -+ arch_spin_lock(&trace_cmdline_lock); -+ map = map_pid_to_cmdline[pid]; -+ if (map != NO_CMDLINE_MAP) -+ tgid = saved_tgids[map]; -+ else -+ tgid = -1; -+ -+ arch_spin_unlock(&trace_cmdline_lock); -+ preempt_enable(); -+ -+ return tgid; -+} -+ - void tracing_record_cmdline(struct task_struct *tsk) - { - if (atomic_read(&trace_record_cmdline_disabled) || !tracer_enabled || -@@ -1960,6 +1982,13 @@ static void print_func_help_header(struct trace_array *tr, struct seq_file *m) - seq_puts(m, "# | | | | |\n"); - } - -+static void print_func_help_header_tgid(struct trace_array *tr, struct seq_file *m) -+{ -+ print_event_info(tr, m); -+ seq_puts(m, "# TASK-PID TGID CPU# TIMESTAMP FUNCTION\n"); -+ seq_puts(m, "# | | | | | |\n"); -+} -+ - static void print_func_help_header_irq(struct trace_array *tr, struct seq_file *m) - { - print_event_info(tr, m); -@@ -1972,6 +2001,18 @@ static void print_func_help_header_irq(struct trace_array *tr, struct seq_file * - seq_puts(m, "# | | | |||| | |\n"); - } - -+static void print_func_help_header_irq_tgid(struct trace_array *tr, struct seq_file *m) -+{ -+ print_event_info(tr, m); -+ seq_puts(m, "# _-----=> irqs-off\n"); -+ seq_puts(m, "# / _----=> need-resched\n"); -+ seq_puts(m, "# | / _---=> hardirq/softirq\n"); -+ seq_puts(m, "# || / _--=> preempt-depth\n"); -+ seq_puts(m, "# ||| / delay\n"); -+ seq_puts(m, "# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION\n"); -+ seq_puts(m, "# | | | | |||| | |\n"); -+} -+ - void - print_trace_header(struct seq_file *m, struct trace_iterator *iter) - { -@@ -2264,9 +2305,15 @@ void trace_default_header(struct seq_file *m) - } else { - if (!(trace_flags & TRACE_ITER_VERBOSE)) { - if (trace_flags & TRACE_ITER_IRQ_INFO) -- print_func_help_header_irq(iter->tr, m); -+ if (trace_flags & TRACE_ITER_TGID) -+ print_func_help_header_irq_tgid(iter->tr, m); -+ else -+ print_func_help_header_irq(iter->tr, m); - else -- print_func_help_header(iter->tr, m); -+ if (trace_flags & TRACE_ITER_TGID) -+ print_func_help_header_tgid(iter->tr, m); -+ else -+ print_func_help_header(iter->tr, m); - } - } - } -@@ -2898,9 +2945,53 @@ tracing_saved_cmdlines_read(struct file *file, char __user *ubuf, - } - - static const struct file_operations tracing_saved_cmdlines_fops = { -- .open = tracing_open_generic, -- .read = tracing_saved_cmdlines_read, -- .llseek = generic_file_llseek, -+ .open = tracing_open_generic, -+ .read = tracing_saved_cmdlines_read, -+ .llseek = generic_file_llseek, -+}; -+ -+static ssize_t -+tracing_saved_tgids_read(struct file *file, char __user *ubuf, -+ size_t cnt, loff_t *ppos) -+{ -+ char *file_buf; -+ char *buf; -+ int len = 0; -+ int pid; -+ int i; -+ -+ file_buf = kmalloc(SAVED_CMDLINES*(16+1+16), GFP_KERNEL); -+ if (!file_buf) -+ return -ENOMEM; -+ -+ buf = file_buf; -+ -+ for (i = 0; i < SAVED_CMDLINES; i++) { -+ int tgid; -+ int r; -+ -+ pid = map_cmdline_to_pid[i]; -+ if (pid == -1 || pid == NO_CMDLINE_MAP) -+ continue; -+ -+ tgid = trace_find_tgid(pid); -+ r = sprintf(buf, "%d %d\n", pid, tgid); -+ buf += r; -+ len += r; -+ } -+ -+ len = simple_read_from_buffer(ubuf, cnt, ppos, -+ file_buf, len); -+ -+ kfree(file_buf); -+ -+ return len; -+} -+ -+static const struct file_operations tracing_saved_tgids_fops = { -+ .open = tracing_open_generic, -+ .read = tracing_saved_tgids_read, -+ .llseek = generic_file_llseek, - }; - - static ssize_t -@@ -4736,6 +4827,9 @@ static __init int tracer_init_debugfs(void) - trace_create_file("saved_cmdlines", 0444, d_tracer, - NULL, &tracing_saved_cmdlines_fops); - -+ trace_create_file("saved_tgids", 0444, d_tracer, -+ NULL, &tracing_saved_tgids_fops); -+ - trace_create_file("trace_clock", 0644, d_tracer, NULL, - &trace_clock_fops); - -diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h -index f95d65da..6d83991c 100644 ---- a/kernel/trace/trace.h -+++ b/kernel/trace/trace.h -@@ -456,6 +456,7 @@ static inline void __trace_stack(struct trace_array *tr, unsigned long flags, - extern cycle_t ftrace_now(int cpu); - - extern void trace_find_cmdline(int pid, char comm[]); -+extern int trace_find_tgid(int pid); - - #ifdef CONFIG_DYNAMIC_FTRACE - extern unsigned long ftrace_update_tot_cnt; -@@ -667,6 +668,7 @@ enum trace_iterator_flags { - TRACE_ITER_OVERWRITE = 0x200000, - TRACE_ITER_STOP_ON_FREE = 0x400000, - TRACE_ITER_IRQ_INFO = 0x800000, -+ TRACE_ITER_TGID = 0x1000000, - }; - - /* -diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c -index a7d2a4c6..f7f1f37a 100644 ---- a/kernel/trace/trace_functions_graph.c -+++ b/kernel/trace/trace_functions_graph.c -@@ -46,6 +46,8 @@ struct fgraph_data { - #define TRACE_GRAPH_PRINT_DURATION 0x10 - #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 - #define TRACE_GRAPH_PRINT_IRQS 0x40 -+#define TRACE_GRAPH_PRINT_FLAT 0x80 -+ - - static struct tracer_opt trace_opts[] = { - /* Display overruns? (for self-debug purpose) */ -@@ -62,6 +64,8 @@ static struct tracer_opt trace_opts[] = { - { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, - /* Display interrupts */ - { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) }, -+ /* Use standard trace formatting rather than hierarchical */ -+ { TRACER_OPT(funcgraph-flat, TRACE_GRAPH_PRINT_FLAT) }, - { } /* Empty entry */ - }; - -@@ -1222,6 +1226,9 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags) - int cpu = iter->cpu; - int ret; - -+ if (flags & TRACE_GRAPH_PRINT_FLAT) -+ return TRACE_TYPE_UNHANDLED; -+ - if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) { - per_cpu_ptr(data->cpu_data, cpu)->ignore = 0; - return TRACE_TYPE_HANDLED; -@@ -1279,13 +1286,6 @@ print_graph_function(struct trace_iterator *iter) - return print_graph_function_flags(iter, tracer_flags.val); - } - --static enum print_line_t --print_graph_function_event(struct trace_iterator *iter, int flags, -- struct trace_event *event) --{ -- return print_graph_function(iter); --} -- - static void print_lat_header(struct seq_file *s, u32 flags) - { - static const char spaces[] = " " /* 16 spaces */ -@@ -1352,6 +1352,11 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags) - { - struct trace_iterator *iter = s->private; - -+ if (flags & TRACE_GRAPH_PRINT_FLAT) { -+ trace_default_header(s); -+ return; -+ } -+ - if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) - return; - -@@ -1422,20 +1427,6 @@ static int func_graph_set_flag(u32 old_flags, u32 bit, int set) - return 0; - } - --static struct trace_event_functions graph_functions = { -- .trace = print_graph_function_event, --}; -- --static struct trace_event graph_trace_entry_event = { -- .type = TRACE_GRAPH_ENT, -- .funcs = &graph_functions, --}; -- --static struct trace_event graph_trace_ret_event = { -- .type = TRACE_GRAPH_RET, -- .funcs = &graph_functions --}; -- - static struct tracer graph_trace __read_mostly = { - .name = "function_graph", - .open = graph_trace_open, -@@ -1458,16 +1449,6 @@ static __init int init_graph_trace(void) - { - max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); - -- if (!register_ftrace_event(&graph_trace_entry_event)) { -- pr_warning("Warning: could not register graph trace events\n"); -- return 1; -- } -- -- if (!register_ftrace_event(&graph_trace_ret_event)) { -- pr_warning("Warning: could not register graph trace events\n"); -- return 1; -- } -- - return register_tracer(&graph_trace); - } - -diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c -index df611a0e..cb29ce20 100644 ---- a/kernel/trace/trace_output.c -+++ b/kernel/trace/trace_output.c -@@ -630,11 +630,25 @@ int trace_print_context(struct trace_iterator *iter) - unsigned long secs = (unsigned long)t; - char comm[TASK_COMM_LEN]; - int ret; -+ int tgid; - - trace_find_cmdline(entry->pid, comm); - -- ret = trace_seq_printf(s, "%16s-%-5d [%03d] ", -- comm, entry->pid, iter->cpu); -+ ret = trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid); -+ if (!ret) -+ return 0; -+ -+ if (trace_flags & TRACE_ITER_TGID) { -+ tgid = trace_find_tgid(entry->pid); -+ if (tgid < 0) -+ ret = trace_seq_puts(s, "(-----) "); -+ else -+ ret = trace_seq_printf(s, "(%5d) ", tgid); -+ if (!ret) -+ return 0; -+ } -+ -+ ret = trace_seq_printf(s, "[%03d] ", iter->cpu); - if (!ret) - return 0; - -@@ -966,6 +980,168 @@ static struct trace_event trace_fn_event = { - .funcs = &trace_fn_funcs, - }; - -+/* TRACE_GRAPH_ENT */ -+static enum print_line_t trace_graph_ent_trace(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct trace_seq *s = &iter->seq; -+ struct ftrace_graph_ent_entry *field; -+ -+ trace_assign_type(field, iter->ent); -+ -+ if (!trace_seq_puts(s, "graph_ent: func=")) -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ if (!seq_print_ip_sym(s, field->graph_ent.func, flags)) -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ if (!trace_seq_puts(s, "\n")) -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static enum print_line_t trace_graph_ent_raw(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct ftrace_graph_ent_entry *field; -+ -+ trace_assign_type(field, iter->ent); -+ -+ if (!trace_seq_printf(&iter->seq, "%lx %d\n", -+ field->graph_ent.func, -+ field->graph_ent.depth)) -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static enum print_line_t trace_graph_ent_hex(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct ftrace_graph_ent_entry *field; -+ struct trace_seq *s = &iter->seq; -+ -+ trace_assign_type(field, iter->ent); -+ -+ SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.func); -+ SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.depth); -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static enum print_line_t trace_graph_ent_bin(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct ftrace_graph_ent_entry *field; -+ struct trace_seq *s = &iter->seq; -+ -+ trace_assign_type(field, iter->ent); -+ -+ SEQ_PUT_FIELD_RET(s, field->graph_ent.func); -+ SEQ_PUT_FIELD_RET(s, field->graph_ent.depth); -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static struct trace_event_functions trace_graph_ent_funcs = { -+ .trace = trace_graph_ent_trace, -+ .raw = trace_graph_ent_raw, -+ .hex = trace_graph_ent_hex, -+ .binary = trace_graph_ent_bin, -+}; -+ -+static struct trace_event trace_graph_ent_event = { -+ .type = TRACE_GRAPH_ENT, -+ .funcs = &trace_graph_ent_funcs, -+}; -+ -+/* TRACE_GRAPH_RET */ -+static enum print_line_t trace_graph_ret_trace(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct trace_seq *s = &iter->seq; -+ struct trace_entry *entry = iter->ent; -+ struct ftrace_graph_ret_entry *field; -+ -+ trace_assign_type(field, entry); -+ -+ if (!trace_seq_puts(s, "graph_ret: func=")) -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ if (!seq_print_ip_sym(s, field->ret.func, flags)) -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ if (!trace_seq_puts(s, "\n")) -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static enum print_line_t trace_graph_ret_raw(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct ftrace_graph_ret_entry *field; -+ -+ trace_assign_type(field, iter->ent); -+ -+ if (!trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n", -+ field->ret.func, -+ field->ret.calltime, -+ field->ret.rettime, -+ field->ret.overrun, -+ field->ret.depth)); -+ return TRACE_TYPE_PARTIAL_LINE; -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static enum print_line_t trace_graph_ret_hex(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct ftrace_graph_ret_entry *field; -+ struct trace_seq *s = &iter->seq; -+ -+ trace_assign_type(field, iter->ent); -+ -+ SEQ_PUT_HEX_FIELD_RET(s, field->ret.func); -+ SEQ_PUT_HEX_FIELD_RET(s, field->ret.calltime); -+ SEQ_PUT_HEX_FIELD_RET(s, field->ret.rettime); -+ SEQ_PUT_HEX_FIELD_RET(s, field->ret.overrun); -+ SEQ_PUT_HEX_FIELD_RET(s, field->ret.depth); -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static enum print_line_t trace_graph_ret_bin(struct trace_iterator *iter, int flags, -+ struct trace_event *event) -+{ -+ struct ftrace_graph_ret_entry *field; -+ struct trace_seq *s = &iter->seq; -+ -+ trace_assign_type(field, iter->ent); -+ -+ SEQ_PUT_FIELD_RET(s, field->ret.func); -+ SEQ_PUT_FIELD_RET(s, field->ret.calltime); -+ SEQ_PUT_FIELD_RET(s, field->ret.rettime); -+ SEQ_PUT_FIELD_RET(s, field->ret.overrun); -+ SEQ_PUT_FIELD_RET(s, field->ret.depth); -+ -+ return TRACE_TYPE_HANDLED; -+} -+ -+static struct trace_event_functions trace_graph_ret_funcs = { -+ .trace = trace_graph_ret_trace, -+ .raw = trace_graph_ret_raw, -+ .hex = trace_graph_ret_hex, -+ .binary = trace_graph_ret_bin, -+}; -+ -+static struct trace_event trace_graph_ret_event = { -+ .type = TRACE_GRAPH_RET, -+ .funcs = &trace_graph_ret_funcs, -+}; -+ - /* TRACE_CTX an TRACE_WAKE */ - static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter, - char *delim) -@@ -1298,6 +1474,8 @@ static struct trace_event trace_print_event = { - - static struct trace_event *events[] __initdata = { - &trace_fn_event, -+ &trace_graph_ent_event, -+ &trace_graph_ret_event, - &trace_ctx_event, - &trace_wake_event, - &trace_stack_event, -diff --git a/kernel/watchdog.c b/kernel/watchdog.c -index 991aa938..19c81d8e 100644 ---- a/kernel/watchdog.c -+++ b/kernel/watchdog.c -@@ -39,6 +39,8 @@ static DEFINE_PER_CPU(bool, hard_watchdog_warn); - static DEFINE_PER_CPU(bool, watchdog_nmi_touch); - static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts); - static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved); -+#endif -+#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI - static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); - #endif - -@@ -174,7 +176,7 @@ void touch_softlockup_watchdog_sync(void) - __raw_get_cpu_var(watchdog_touch_ts) = 0; - } - --#ifdef CONFIG_HARDLOCKUP_DETECTOR -+#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI - /* watchdog detector functions */ - static int is_hardlockup(void) - { -@@ -188,6 +190,61 @@ static int is_hardlockup(void) - } - #endif - -+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU -+static int is_hardlockup_other_cpu(int cpu) -+{ -+ unsigned long hrint = per_cpu(hrtimer_interrupts, cpu); -+ -+ if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint) -+ return 1; -+ -+ per_cpu(hrtimer_interrupts_saved, cpu) = hrint; -+ return 0; -+} -+ -+static void watchdog_check_hardlockup_other_cpu(void) -+{ -+ int cpu; -+ -+ /* -+ * Test for hardlockups every 3 samples. The sample period is -+ * watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over -+ * watchdog_thresh (over by 20%). -+ */ -+ if (__this_cpu_read(hrtimer_interrupts) % 3 != 0) -+ return; -+ -+ /* check for a hardlockup on the next cpu */ -+ cpu = cpumask_next(smp_processor_id(), cpu_online_mask); -+ if (cpu >= nr_cpu_ids) -+ cpu = cpumask_first(cpu_online_mask); -+ if (cpu == smp_processor_id()) -+ return; -+ -+ if (per_cpu(watchdog_nmi_touch, cpu) == true) { -+ per_cpu(watchdog_nmi_touch, cpu) = false; -+ return; -+ } -+ -+ if (is_hardlockup_other_cpu(cpu)) { -+ /* only warn once */ -+ if (per_cpu(hard_watchdog_warn, cpu) == true) -+ return; -+ -+ if (hardlockup_panic) -+ panic("Watchdog detected hard LOCKUP on cpu %d", cpu); -+ else -+ WARN(1, "Watchdog detected hard LOCKUP on cpu %d", cpu); -+ -+ per_cpu(hard_watchdog_warn, cpu) = true; -+ } else { -+ per_cpu(hard_watchdog_warn, cpu) = false; -+ } -+} -+#else -+static inline void watchdog_check_hardlockup_other_cpu(void) { return; } -+#endif -+ - static int is_softlockup(unsigned long touch_ts) - { - unsigned long now = get_timestamp(smp_processor_id()); -@@ -199,7 +256,7 @@ static int is_softlockup(unsigned long touch_ts) - return 0; - } - --#ifdef CONFIG_HARDLOCKUP_DETECTOR -+#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI - - static struct perf_event_attr wd_hw_attr = { - .type = PERF_TYPE_HARDWARE, -@@ -247,6 +304,9 @@ static void watchdog_overflow_callback(struct perf_event *event, - __this_cpu_write(hard_watchdog_warn, false); - return; - } -+#endif -+ -+#ifdef CONFIG_HARDLOCKUP_DETECTOR - static void watchdog_interrupt_count(void) - { - __this_cpu_inc(hrtimer_interrupts); -@@ -265,6 +325,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) - /* kick the hardlockup detector */ - watchdog_interrupt_count(); - -+ /* test for hardlockups on the next cpu */ -+ watchdog_check_hardlockup_other_cpu(); -+ - /* kick the softlockup detector */ - wake_up_process(__this_cpu_read(softlockup_watchdog)); - -@@ -359,7 +422,7 @@ static int watchdog(void *unused) - } - - --#ifdef CONFIG_HARDLOCKUP_DETECTOR -+#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI - static int watchdog_nmi_enable(int cpu) - { - struct perf_event_attr *wd_attr; -@@ -430,6 +493,18 @@ static void watchdog_prepare_cpu(int cpu) - WARN_ON(per_cpu(softlockup_watchdog, cpu)); - hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrtimer->function = watchdog_timer_fn; -+ -+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU -+ /* -+ * The new cpu will be marked online before the first hrtimer interrupt -+ * runs on it. If another cpu tests for a hardlockup on the new cpu -+ * before it has run its first hrtimer, it will get a false positive. -+ * Touch the watchdog on the new cpu to delay the first check for at -+ * least 3 sampling periods to guarantee one hrtimer has run on the new -+ * cpu. -+ */ -+ per_cpu(watchdog_nmi_touch, cpu) = true; -+#endif - } - - static int watchdog_enable(int cpu) -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 6777153f..bbdea1d8 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -178,14 +178,24 @@ config LOCKUP_DETECTOR - The overhead should be minimal. A periodic hrtimer runs to - generate interrupts and kick the watchdog task every 4 seconds. - An NMI is generated every 10 seconds or so to check for hardlockups. -+ If NMIs are not available on the platform, every 12 seconds the -+ hrtimer interrupt on one cpu will be used to check for hardlockups -+ on the next cpu. - - The frequency of hrtimer and NMI events and the soft and hard lockup - thresholds can be controlled through the sysctl watchdog_thresh. - --config HARDLOCKUP_DETECTOR -+config HARDLOCKUP_DETECTOR_NMI - def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI && \ - !HAVE_NMI_WATCHDOG - -+config HARDLOCKUP_DETECTOR_OTHER_CPU -+ def_bool LOCKUP_DETECTOR && SMP && !HARDLOCKUP_DETECTOR_NMI && \ -+ !HAVE_NMI_WATCHDOG -+ -+config HARDLOCKUP_DETECTOR -+ def_bool HARDLOCKUP_DETECTOR_NMI || HARDLOCKUP_DETECTOR_OTHER_CPU -+ - config BOOTPARAM_HARDLOCKUP_PANIC - bool "Panic (Reboot) On Hard Lockups" - depends on LOCKUP_DETECTOR -@@ -676,8 +686,9 @@ config DEBUG_LOCKING_API_SELFTESTS - mutexes and rwsems. - - config STACKTRACE -- bool -+ bool "Stacktrace" - depends on STACKTRACE_SUPPORT -+ default y - - config DEBUG_STACK_USAGE - bool "Stack utilization instrumentation" -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 533ea80f..035fbe94 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -192,6 +192,7 @@ static char * const zone_names[MAX_NR_ZONES] = { - }; - - int min_free_kbytes = 1024; -+int min_free_order_shift = 1; - - static unsigned long __meminitdata nr_kernel_pages; - static unsigned long __meminitdata nr_all_pages; -@@ -1565,7 +1566,7 @@ static bool __zone_watermark_ok(struct zone *z, int order, unsigned long mark, - free_pages -= z->free_area[o].nr_free << o; - - /* Require fewer higher order pages to be free */ -- min >>= 1; -+ min >>= min_free_order_shift; - - if (free_pages <= min) - return false; -diff --git a/mm/shmem.c b/mm/shmem.c -index 58c4a477..44895669 100644 ---- a/mm/shmem.c -+++ b/mm/shmem.c -@@ -2621,6 +2621,15 @@ put_memory: - } - EXPORT_SYMBOL_GPL(shmem_file_setup); - -+void shmem_set_file(struct vm_area_struct *vma, struct file *file) -+{ -+ if (vma->vm_file) -+ fput(vma->vm_file); -+ vma->vm_file = file; -+ vma->vm_ops = &shmem_vm_ops; -+ vma->vm_flags |= VM_CAN_NONLINEAR; -+} -+ - /** - * shmem_zero_setup - setup a shared anonymous mapping - * @vma: the vma to be mmapped is prepared by do_mmap_pgoff -@@ -2634,11 +2643,7 @@ int shmem_zero_setup(struct vm_area_struct *vma) - if (IS_ERR(file)) - return PTR_ERR(file); - -- if (vma->vm_file) -- fput(vma->vm_file); -- vma->vm_file = file; -- vma->vm_ops = &shmem_vm_ops; -- vma->vm_flags |= VM_CAN_NONLINEAR; -+ shmem_set_file(vma, file); - return 0; - } - -diff --git a/mm/vmscan.c b/mm/vmscan.c -index e6ca5051..7fa5fc87 100644 ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -42,6 +42,7 @@ - #include <linux/sysctl.h> - #include <linux/oom.h> - #include <linux/prefetch.h> -+#include <linux/debugfs.h> - - #include <asm/tlbflush.h> - #include <asm/div64.h> -@@ -201,6 +202,39 @@ static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz, - return zone_page_state(mz->zone, NR_LRU_BASE + lru); - } - -+struct dentry *debug_file; -+ -+static int debug_shrinker_show(struct seq_file *s, void *unused) -+{ -+ struct shrinker *shrinker; -+ struct shrink_control sc; -+ -+ sc.gfp_mask = -1; -+ sc.nr_to_scan = 0; -+ -+ down_read(&shrinker_rwsem); -+ list_for_each_entry(shrinker, &shrinker_list, list) { -+ char name[64]; -+ int num_objs; -+ -+ num_objs = shrinker->shrink(shrinker, &sc); -+ seq_printf(s, "%pf %d\n", shrinker->shrink, num_objs); -+ } -+ up_read(&shrinker_rwsem); -+ return 0; -+} -+ -+static int debug_shrinker_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, debug_shrinker_show, inode->i_private); -+} -+ -+static const struct file_operations debug_shrinker_fops = { -+ .open = debug_shrinker_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; - - /* - * Add a shrinker callback to be called from the vm -@@ -214,6 +248,15 @@ void register_shrinker(struct shrinker *shrinker) - } - EXPORT_SYMBOL(register_shrinker); - -+static int __init add_shrinker_debug(void) -+{ -+ debugfs_create_file("shrinker", 0644, NULL, NULL, -+ &debug_shrinker_fops); -+ return 0; -+} -+ -+late_initcall(add_shrinker_debug); -+ - /* - * Remove one - */ -diff --git a/net/Kconfig b/net/Kconfig -index e07272d0..c8ee300c 100644 ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -79,6 +79,20 @@ source "net/netlabel/Kconfig" - - endif # if INET - -+config ANDROID_PARANOID_NETWORK -+ bool "Only allow certain groups to create sockets" -+ default y -+ help -+ none -+ -+config NET_ACTIVITY_STATS -+ bool "Network activity statistics tracking" -+ default y -+ help -+ Network activity statistics are useful for tracking wireless -+ modem activity on 2G, 3G, 4G wireless networks. Counts number of -+ transmissions and groups them in specified time buckets. -+ - config NETWORK_SECMARK - bool "Security Marking" - help -@@ -218,7 +232,7 @@ source "net/batman-adv/Kconfig" - source "net/openvswitch/Kconfig" - - config RPS -- boolean -+ boolean "RPS" - depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS - default y - -diff --git a/net/Makefile b/net/Makefile -index ad432fa4..6865dab6 100644 ---- a/net/Makefile -+++ b/net/Makefile -@@ -70,3 +70,4 @@ obj-$(CONFIG_CEPH_LIB) += ceph/ - obj-$(CONFIG_BATMAN_ADV) += batman-adv/ - obj-$(CONFIG_NFC) += nfc/ - obj-$(CONFIG_OPENVSWITCH) += openvswitch/ -+obj-$(CONFIG_NET_ACTIVITY_STATS) += activity_stats.o -diff --git a/net/activity_stats.c b/net/activity_stats.c -new file mode 100644 -index 00000000..8a3e9347 ---- /dev/null -+++ b/net/activity_stats.c -@@ -0,0 +1,115 @@ -+/* net/activity_stats.c -+ * -+ * Copyright (C) 2010 Google, Inc. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ * -+ * Author: Mike Chan (mike@android.com) -+ */ -+ -+#include <linux/proc_fs.h> -+#include <linux/suspend.h> -+#include <net/net_namespace.h> -+ -+/* -+ * Track transmission rates in buckets (power of 2). -+ * 1,2,4,8...512 seconds. -+ * -+ * Buckets represent the count of network transmissions at least -+ * N seconds apart, where N is 1 << bucket index. -+ */ -+#define BUCKET_MAX 10 -+ -+/* Track network activity frequency */ -+static unsigned long activity_stats[BUCKET_MAX]; -+static ktime_t last_transmit; -+static ktime_t suspend_time; -+static DEFINE_SPINLOCK(activity_lock); -+ -+void activity_stats_update(void) -+{ -+ int i; -+ unsigned long flags; -+ ktime_t now; -+ s64 delta; -+ -+ spin_lock_irqsave(&activity_lock, flags); -+ now = ktime_get(); -+ delta = ktime_to_ns(ktime_sub(now, last_transmit)); -+ -+ for (i = BUCKET_MAX - 1; i >= 0; i--) { -+ /* -+ * Check if the time delta between network activity is within the -+ * minimum bucket range. -+ */ -+ if (delta < (1000000000ULL << i)) -+ continue; -+ -+ activity_stats[i]++; -+ last_transmit = now; -+ break; -+ } -+ spin_unlock_irqrestore(&activity_lock, flags); -+} -+ -+static int activity_stats_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int i; -+ int len; -+ char *p = page; -+ -+ /* Only print if offset is 0, or we have enough buffer space */ -+ if (off || count < (30 * BUCKET_MAX + 22)) -+ return -ENOMEM; -+ -+ len = snprintf(p, count, "Min Bucket(sec) Count\n"); -+ count -= len; -+ p += len; -+ -+ for (i = 0; i < BUCKET_MAX; i++) { -+ len = snprintf(p, count, "%15d %lu\n", 1 << i, activity_stats[i]); -+ count -= len; -+ p += len; -+ } -+ *eof = 1; -+ -+ return p - page; -+} -+ -+static int activity_stats_notifier(struct notifier_block *nb, -+ unsigned long event, void *dummy) -+{ -+ switch (event) { -+ case PM_SUSPEND_PREPARE: -+ suspend_time = ktime_get_real(); -+ break; -+ -+ case PM_POST_SUSPEND: -+ suspend_time = ktime_sub(ktime_get_real(), suspend_time); -+ last_transmit = ktime_sub(last_transmit, suspend_time); -+ } -+ -+ return 0; -+} -+ -+static struct notifier_block activity_stats_notifier_block = { -+ .notifier_call = activity_stats_notifier, -+}; -+ -+static int __init activity_stats_init(void) -+{ -+ create_proc_read_entry("activity", S_IRUGO, -+ init_net.proc_net_stat, activity_stats_read_proc, NULL); -+ return register_pm_notifier(&activity_stats_notifier_block); -+} -+ -+subsys_initcall(activity_stats_init); -+ -diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c -index 6fb68a97..f7fa8087 100644 ---- a/net/bluetooth/af_bluetooth.c -+++ b/net/bluetooth/af_bluetooth.c -@@ -40,6 +40,11 @@ - - #include <net/bluetooth/bluetooth.h> - -+#ifndef CONFIG_BT_SOCK_DEBUG -+#undef BT_DBG -+#define BT_DBG(D...) -+#endif -+ - #define VERSION "2.16" - - /* Bluetooth sockets */ -@@ -122,11 +127,40 @@ int bt_sock_unregister(int proto) - } - EXPORT_SYMBOL(bt_sock_unregister); - -+#ifdef CONFIG_PARANOID_NETWORK -+static inline int current_has_bt_admin(void) -+{ -+ return !current_euid(); -+} -+ -+static inline int current_has_bt(void) -+{ -+ return current_has_bt_admin(); -+} -+# else -+static inline int current_has_bt_admin(void) -+{ -+ return 1; -+} -+ -+static inline int current_has_bt(void) -+{ -+ return 1; -+} -+#endif -+ - static int bt_sock_create(struct net *net, struct socket *sock, int proto, - int kern) - { - int err; - -+ if (proto == BTPROTO_RFCOMM || proto == BTPROTO_SCO || -+ proto == BTPROTO_L2CAP) { -+ if (!current_has_bt()) -+ return -EPERM; -+ } else if (!current_has_bt_admin()) -+ return -EPERM; -+ - if (net != &init_net) - return -EAFNOSUPPORT; - -diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c -index 39b2baf6..0e8f89f9 100644 ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -361,7 +361,8 @@ static void hci_conn_auto_accept(unsigned long arg) - &conn->dst); - } - --struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) -+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, -+ __u16 pkt_type, bdaddr_t *dst) - { - struct hci_conn *conn; - -@@ -389,14 +390,22 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) - conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; - break; - case SCO_LINK: -- if (lmp_esco_capable(hdev)) -- conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | -- (hdev->esco_type & EDR_ESCO_MASK); -- else -- conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; -- break; -+ if (!pkt_type) -+ pkt_type = SCO_ESCO_MASK; - case ESCO_LINK: -- conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK; -+ if (!pkt_type) -+ pkt_type = ALL_ESCO_MASK; -+ if (lmp_esco_capable(hdev)) { -+ /* HCI Setup Synchronous Connection Command uses -+ reverse logic on the EDR_ESCO_MASK bits */ -+ conn->pkt_type = (pkt_type ^ EDR_ESCO_MASK) & -+ hdev->esco_type; -+ } else { -+ /* Legacy HCI Add Sco Connection Command uses a -+ shifted bitmask */ -+ conn->pkt_type = (pkt_type << 5) & hdev->pkt_type & -+ SCO_PTYPE_MASK; -+ } - break; - } - -@@ -514,7 +523,9 @@ EXPORT_SYMBOL(hci_get_route); - - /* Create SCO, ACL or LE connection. - * Device _must_ be locked */ --struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) -+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, -+ __u16 pkt_type, bdaddr_t *dst, -+ __u8 sec_level, __u8 auth_type) - { - struct hci_conn *acl; - struct hci_conn *sco; -@@ -533,7 +544,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 - if (!entry) - return ERR_PTR(-EHOSTUNREACH); - -- le = hci_conn_add(hdev, LE_LINK, dst); -+ le = hci_conn_add(hdev, LE_LINK, 0, dst); - if (!le) - return ERR_PTR(-ENOMEM); - -@@ -548,7 +559,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 - - acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); - if (!acl) { -- acl = hci_conn_add(hdev, ACL_LINK, dst); -+ acl = hci_conn_add(hdev, ACL_LINK, 0, dst); - if (!acl) - return ERR_PTR(-ENOMEM); - } -@@ -567,7 +578,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 - - sco = hci_conn_hash_lookup_ba(hdev, type, dst); - if (!sco) { -- sco = hci_conn_add(hdev, type, dst); -+ sco = hci_conn_add(hdev, type, pkt_type, dst); - if (!sco) { - hci_conn_put(acl); - return ERR_PTR(-ENOMEM); -@@ -874,6 +885,15 @@ int hci_get_conn_list(void __user *arg) - (ci + n)->out = c->out; - (ci + n)->state = c->state; - (ci + n)->link_mode = c->link_mode; -+ if (c->type == SCO_LINK) { -+ (ci + n)->mtu = hdev->sco_mtu; -+ (ci + n)->cnt = hdev->sco_cnt; -+ (ci + n)->pkts = hdev->sco_pkts; -+ } else { -+ (ci + n)->mtu = hdev->acl_mtu; -+ (ci + n)->cnt = hdev->acl_cnt; -+ (ci + n)->pkts = hdev->acl_pkts; -+ } - if (++n >= req.conn_num) - break; - } -@@ -910,6 +930,15 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) - ci.out = conn->out; - ci.state = conn->state; - ci.link_mode = conn->link_mode; -+ if (req.type == SCO_LINK) { -+ ci.mtu = hdev->sco_mtu; -+ ci.cnt = hdev->sco_cnt; -+ ci.pkts = hdev->sco_pkts; -+ } else { -+ ci.mtu = hdev->acl_mtu; -+ ci.cnt = hdev->acl_cnt; -+ ci.pkts = hdev->acl_pkts; -+ } - } - hci_dev_unlock(hdev); - -diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c -old mode 100644 -new mode 100755 -index ef45e10c..aba4fccd ---- a/net/bluetooth/hci_event.c -+++ b/net/bluetooth/hci_event.c -@@ -1213,7 +1213,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) - } - } else { - if (!conn) { -- conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); -+ conn = hci_conn_add(hdev, ACL_LINK, 0, &cp->bdaddr); - if (conn) { - conn->out = true; - conn->link_mode |= HCI_LM_MASTER; -@@ -1641,7 +1641,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) - } - } else { - if (!conn) { -- conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr); -+ conn = hci_conn_add(hdev, LE_LINK, 0, &cp->peer_addr); - if (conn) { - conn->dst_type = cp->peer_addr_type; - conn->out = true; -@@ -1816,6 +1816,15 @@ unlock: - hci_conn_check_pending(hdev); - } - -+static inline bool is_sco_active(struct hci_dev *hdev) -+{ -+ if (hci_conn_hash_lookup_state(hdev, SCO_LINK, BT_CONNECTED) || -+ (hci_conn_hash_lookup_state(hdev, ESCO_LINK, -+ BT_CONNECTED))) -+ return true; -+ return false; -+} -+ - static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) - { - struct hci_ev_conn_request *ev = (void *) skb->data; -@@ -1840,7 +1849,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk - - conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); - if (!conn) { -- conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); -+ /* pkt_type not yet used for incoming connections */ -+ conn = hci_conn_add(hdev, ev->link_type, 0, &ev->bdaddr); - if (!conn) { - BT_ERR("No memory for new connection"); - hci_dev_unlock(hdev); -@@ -1858,7 +1868,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk - - bacpy(&cp.bdaddr, &ev->bdaddr); - -- if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) -+ if (lmp_rswitch_capable(hdev) && ((mask & HCI_LM_MASTER) -+ || is_sco_active(hdev))) - cp.role = 0x00; /* Become master */ - else - cp.role = 0x01; /* Remain slave */ -@@ -2945,6 +2956,7 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu - hci_conn_add_sysfs(conn); - break; - -+ case 0x10: /* Connection Accept Timeout */ - case 0x11: /* Unsupported Feature or Parameter Value */ - case 0x1c: /* SCO interval rejected */ - case 0x1a: /* Unsupported Remote Feature */ -@@ -3290,7 +3302,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff - - conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr); - if (!conn) { -- conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); -+ conn = hci_conn_add(hdev, LE_LINK, 0, &ev->bdaddr); - if (!conn) { - BT_ERR("No memory for new connection"); - hci_dev_unlock(hdev); -diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c -index fa07aed3..e49f200c 100644 ---- a/net/bluetooth/l2cap_core.c -+++ b/net/bluetooth/l2cap_core.c -@@ -1220,10 +1220,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d - auth_type = l2cap_get_auth_type(chan); - - if (chan->dcid == L2CAP_CID_LE_DATA) -- hcon = hci_connect(hdev, LE_LINK, dst, -+ hcon = hci_connect(hdev, LE_LINK, 0, dst, - chan->sec_level, auth_type); - else -- hcon = hci_connect(hdev, ACL_LINK, dst, -+ hcon = hci_connect(hdev, ACL_LINK, 0, dst, - chan->sec_level, auth_type); - - if (IS_ERR(hcon)) { -diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c -index 8f3d9dc7..00879b82 100644 ---- a/net/bluetooth/mgmt.c -+++ b/net/bluetooth/mgmt.c -@@ -1891,11 +1891,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, - auth_type = HCI_AT_DEDICATED_BONDING_MITM; - - if (cp->addr.type == MGMT_ADDR_BREDR) -- conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, -- auth_type); -+ conn = hci_connect(hdev, ACL_LINK, 0, &cp->addr.bdaddr, -+ sec_level, auth_type); - else -- conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level, -- auth_type); -+ conn = hci_connect(hdev, LE_LINK, 0, &cp->addr.bdaddr, -+ sec_level, auth_type); - - memset(&rp, 0, sizeof(rp)); - bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); -diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c -index 8a602388..9652707b 100644 ---- a/net/bluetooth/rfcomm/core.c -+++ b/net/bluetooth/rfcomm/core.c -@@ -462,7 +462,6 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) - - switch (d->state) { - case BT_CONNECT: -- case BT_CONFIG: - if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { - set_bit(RFCOMM_AUTH_REJECT, &d->flags); - rfcomm_schedule(); -diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c -index f6ab1290..458cec07 100644 ---- a/net/bluetooth/sco.c -+++ b/net/bluetooth/sco.c -@@ -177,6 +177,7 @@ static int sco_connect(struct sock *sk) - { - bdaddr_t *src = &bt_sk(sk)->src; - bdaddr_t *dst = &bt_sk(sk)->dst; -+ __u16 pkt_type = sco_pi(sk)->pkt_type; - struct sco_conn *conn; - struct hci_conn *hcon; - struct hci_dev *hdev; -@@ -192,10 +193,12 @@ static int sco_connect(struct sock *sk) - - if (lmp_esco_capable(hdev) && !disable_esco) - type = ESCO_LINK; -- else -+ else { - type = SCO_LINK; -+ pkt_type &= SCO_ESCO_MASK; -+ } - -- hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); -+ hcon = hci_connect(hdev, type, pkt_type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); - if (IS_ERR(hcon)) { - err = PTR_ERR(hcon); - goto done; -@@ -462,18 +465,22 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol, - return 0; - } - --static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) -+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) - { -- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; -+ struct sockaddr_sco sa; - struct sock *sk = sock->sk; -- bdaddr_t *src = &sa->sco_bdaddr; -- int err = 0; -+ bdaddr_t *src = &sa.sco_bdaddr; -+ int len, err = 0; - -- BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); -+ BT_DBG("sk %p %s", sk, batostr(&sa.sco_bdaddr)); - - if (!addr || addr->sa_family != AF_BLUETOOTH) - return -EINVAL; - -+ memset(&sa, 0, sizeof(sa)); -+ len = min_t(unsigned int, sizeof(sa), alen); -+ memcpy(&sa, addr, len); -+ - lock_sock(sk); - - if (sk->sk_state != BT_OPEN) { -@@ -487,7 +494,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le - err = -EADDRINUSE; - } else { - /* Save source address */ -- bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); -+ bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr); -+ sco_pi(sk)->pkt_type = sa.sco_pkt_type; - sk->sk_state = BT_BOUND; - } - -@@ -500,27 +508,34 @@ done: - - static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) - { -- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; - struct sock *sk = sock->sk; -- int err = 0; -- -+ struct sockaddr_sco sa; -+ int len, err = 0; - - BT_DBG("sk %p", sk); - -- if (alen < sizeof(struct sockaddr_sco) || -- addr->sa_family != AF_BLUETOOTH) -+ if (!addr || addr->sa_family != AF_BLUETOOTH) - return -EINVAL; - -- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) -- return -EBADFD; -- -- if (sk->sk_type != SOCK_SEQPACKET) -- return -EINVAL; -+ memset(&sa, 0, sizeof(sa)); -+ len = min_t(unsigned int, sizeof(sa), alen); -+ memcpy(&sa, addr, len); - - lock_sock(sk); - -+ if (sk->sk_type != SOCK_SEQPACKET) { -+ err = -EINVAL; -+ goto done; -+ } -+ -+ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { -+ err = -EBADFD; -+ goto done; -+ } -+ - /* Set destination address and psm */ -- bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); -+ bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr); -+ sco_pi(sk)->pkt_type = sa.sco_pkt_type; - - err = sco_connect(sk); - if (err) -@@ -627,6 +642,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len - bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst); - else - bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src); -+ sa->sco_pkt_type = sco_pi(sk)->pkt_type; - - return 0; - } -diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c -index ba829de8..9ec0822f 100644 ---- a/net/bridge/br_device.c -+++ b/net/bridge/br_device.c -@@ -38,16 +38,17 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) - } - #endif - -- u64_stats_update_begin(&brstats->syncp); -- brstats->tx_packets++; -- brstats->tx_bytes += skb->len; -- u64_stats_update_end(&brstats->syncp); -- - BR_INPUT_SKB_CB(skb)->brdev = dev; - - skb_reset_mac_header(skb); - skb_pull(skb, ETH_HLEN); - -+ u64_stats_update_begin(&brstats->syncp); -+ brstats->tx_packets++; -+ /* Exclude ETH_HLEN from byte stats for consistency with Rx chain */ -+ brstats->tx_bytes += skb->len; -+ u64_stats_update_end(&brstats->syncp); -+ - rcu_read_lock(); - if (is_broadcast_ether_addr(dest)) - br_flood_deliver(br, skb); -diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile -index ff75d3bb..c6f177cf 100644 ---- a/net/ipv4/Makefile -+++ b/net/ipv4/Makefile -@@ -14,6 +14,7 @@ obj-y := route.o inetpeer.o protocol.o \ - inet_fragment.o ping.o - - obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o -+obj-$(CONFIG_SYSFS) += sysfs_net_ipv4.o - obj-$(CONFIG_PROC_FS) += proc.o - obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o - obj-$(CONFIG_IP_MROUTE) += ipmr.o -diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c -index 78ec2980..de5ec030 100644 ---- a/net/ipv4/af_inet.c -+++ b/net/ipv4/af_inet.c -@@ -119,6 +119,19 @@ - #include <linux/mroute.h> - #endif - -+#ifdef CONFIG_ANDROID_PARANOID_NETWORK -+#include <linux/android_aid.h> -+ -+static inline int current_has_network(void) -+{ -+ return in_egroup_p(AID_INET) || capable(CAP_NET_RAW); -+} -+#else -+static inline int current_has_network(void) -+{ -+ return 1; -+} -+#endif - - /* The inetsw table contains everything that inet_create needs to - * build a new socket. -@@ -264,6 +277,7 @@ static inline int inet_netns_ok(struct net *net, int protocol) - return ipprot->netns_ok; - } - -+ - /* - * Create an inet socket. - */ -@@ -280,6 +294,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol, - int try_loading_module = 0; - int err; - -+ if (!current_has_network()) -+ return -EACCES; -+ - if (unlikely(!inet_ehash_secret)) - if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) - build_ehash_secret(); -@@ -886,6 +903,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) - case SIOCSIFPFLAGS: - case SIOCGIFPFLAGS: - case SIOCSIFFLAGS: -+ case SIOCKILLADDR: - err = devinet_ioctl(net, cmd, (void __user *)arg); - break; - default: -diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c -index 6e447ff9..8a9aab37 100644 ---- a/net/ipv4/devinet.c -+++ b/net/ipv4/devinet.c -@@ -58,6 +58,7 @@ - - #include <net/arp.h> - #include <net/ip.h> -+#include <net/tcp.h> - #include <net/route.h> - #include <net/ip_fib.h> - #include <net/rtnetlink.h> -@@ -734,6 +735,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) - case SIOCSIFBRDADDR: /* Set the broadcast address */ - case SIOCSIFDSTADDR: /* Set the destination address */ - case SIOCSIFNETMASK: /* Set the netmask for the interface */ -+ case SIOCKILLADDR: /* Nuke all sockets on this address */ - ret = -EACCES; - if (!capable(CAP_NET_ADMIN)) - goto out; -@@ -785,7 +787,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) - } - - ret = -EADDRNOTAVAIL; -- if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) -+ if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS -+ && cmd != SIOCKILLADDR) - goto done; - - switch (cmd) { -@@ -911,6 +914,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) - inet_insert_ifa(ifa); - } - break; -+ case SIOCKILLADDR: /* Nuke all connections on this address */ -+ ret = tcp_nuke_addr(net, (struct sockaddr *) sin); -+ break; - } - done: - rtnl_unlock(); -diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig -index fcc543cd..a1dce8a2 100644 ---- a/net/ipv4/netfilter/Kconfig -+++ b/net/ipv4/netfilter/Kconfig -@@ -123,6 +123,18 @@ config IP_NF_TARGET_REJECT - - To compile it as a module, choose M here. If unsure, say N. - -+config IP_NF_TARGET_REJECT_SKERR -+ bool "Force socket error when rejecting with icmp*" -+ depends on IP_NF_TARGET_REJECT -+ default n -+ help -+ This option enables turning a "--reject-with icmp*" into a matching -+ socket error also. -+ The REJECT target normally allows sending an ICMP message. But it -+ leaves the local socket unaware of any ingress rejects. -+ -+ If unsure, say N. -+ - config IP_NF_TARGET_ULOG - tristate "ULOG target support" - default m if NETFILTER_ADVANCED=n -diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c -index 51f13f8e..9dd754c7 100644 ---- a/net/ipv4/netfilter/ipt_REJECT.c -+++ b/net/ipv4/netfilter/ipt_REJECT.c -@@ -128,6 +128,14 @@ static void send_reset(struct sk_buff *oldskb, int hook) - static inline void send_unreach(struct sk_buff *skb_in, int code) - { - icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); -+#ifdef CONFIG_IP_NF_TARGET_REJECT_SKERR -+ if (skb_in->sk) { -+ skb_in->sk->sk_err = icmp_err_convert[code].errno; -+ skb_in->sk->sk_error_report(skb_in->sk); -+ pr_debug("ipt_REJECT: sk_err=%d for skb=%p sk=%p\n", -+ skb_in->sk->sk_err, skb_in, skb_in->sk); -+ } -+#endif - } - - static unsigned int -diff --git a/net/ipv4/sysfs_net_ipv4.c b/net/ipv4/sysfs_net_ipv4.c -new file mode 100644 -index 00000000..0cbbf100 ---- /dev/null -+++ b/net/ipv4/sysfs_net_ipv4.c -@@ -0,0 +1,88 @@ -+/* -+ * net/ipv4/sysfs_net_ipv4.c -+ * -+ * sysfs-based networking knobs (so we can, unlike with sysctl, control perms) -+ * -+ * Copyright (C) 2008 Google, Inc. -+ * -+ * Robert Love <rlove@google.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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. -+ */ -+ -+#include <linux/kobject.h> -+#include <linux/string.h> -+#include <linux/sysfs.h> -+#include <linux/init.h> -+#include <net/tcp.h> -+ -+#define CREATE_IPV4_FILE(_name, _var) \ -+static ssize_t _name##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+{ \ -+ return sprintf(buf, "%d\n", _var); \ -+} \ -+static ssize_t _name##_store(struct kobject *kobj, \ -+ struct kobj_attribute *attr, \ -+ const char *buf, size_t count) \ -+{ \ -+ int val, ret; \ -+ ret = sscanf(buf, "%d", &val); \ -+ if (ret != 1) \ -+ return -EINVAL; \ -+ if (val < 0) \ -+ return -EINVAL; \ -+ _var = val; \ -+ return count; \ -+} \ -+static struct kobj_attribute _name##_attr = \ -+ __ATTR(_name, 0644, _name##_show, _name##_store) -+ -+CREATE_IPV4_FILE(tcp_wmem_min, sysctl_tcp_wmem[0]); -+CREATE_IPV4_FILE(tcp_wmem_def, sysctl_tcp_wmem[1]); -+CREATE_IPV4_FILE(tcp_wmem_max, sysctl_tcp_wmem[2]); -+ -+CREATE_IPV4_FILE(tcp_rmem_min, sysctl_tcp_rmem[0]); -+CREATE_IPV4_FILE(tcp_rmem_def, sysctl_tcp_rmem[1]); -+CREATE_IPV4_FILE(tcp_rmem_max, sysctl_tcp_rmem[2]); -+ -+static struct attribute *ipv4_attrs[] = { -+ &tcp_wmem_min_attr.attr, -+ &tcp_wmem_def_attr.attr, -+ &tcp_wmem_max_attr.attr, -+ &tcp_rmem_min_attr.attr, -+ &tcp_rmem_def_attr.attr, -+ &tcp_rmem_max_attr.attr, -+ NULL -+}; -+ -+static struct attribute_group ipv4_attr_group = { -+ .attrs = ipv4_attrs, -+}; -+ -+static __init int sysfs_ipv4_init(void) -+{ -+ struct kobject *ipv4_kobject; -+ int ret; -+ -+ ipv4_kobject = kobject_create_and_add("ipv4", kernel_kobj); -+ if (!ipv4_kobject) -+ return -ENOMEM; -+ -+ ret = sysfs_create_group(ipv4_kobject, &ipv4_attr_group); -+ if (ret) { -+ kobject_put(ipv4_kobject); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+subsys_initcall(sysfs_ipv4_init); -diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c -index 01870bd2..8429ac5e 100644 ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -268,11 +268,15 @@ - #include <linux/crypto.h> - #include <linux/time.h> - #include <linux/slab.h> -+#include <linux/uid_stat.h> - - #include <net/icmp.h> - #include <net/tcp.h> - #include <net/xfrm.h> - #include <net/ip.h> -+#include <net/ip6_route.h> -+#include <net/ipv6.h> -+#include <net/transp_v6.h> - #include <net/netdma.h> - #include <net/sock.h> - -@@ -1115,6 +1119,9 @@ out: - if (copied) - tcp_push(sk, flags, mss_now, tp->nonagle); - release_sock(sk); -+ -+ if (copied > 0) -+ uid_stat_tcp_snd(current_uid(), copied); - return copied; - - do_fault: -@@ -1389,8 +1396,11 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, - tcp_rcv_space_adjust(sk); - - /* Clean up data we have read: This will do ACK frames. */ -- if (copied > 0) -+ if (copied > 0) { - tcp_cleanup_rbuf(sk, copied); -+ uid_stat_tcp_rcv(current_uid(), copied); -+ } -+ - return copied; - } - EXPORT_SYMBOL(tcp_read_sock); -@@ -1779,6 +1789,9 @@ skip_copy: - tcp_cleanup_rbuf(sk, copied); - - release_sock(sk); -+ -+ if (copied > 0) -+ uid_stat_tcp_rcv(current_uid(), copied); - return copied; - - out: -@@ -1787,6 +1800,8 @@ out: - - recv_urg: - err = tcp_recv_urg(sk, msg, len, flags); -+ if (err > 0) -+ uid_stat_tcp_rcv(current_uid(), err); - goto out; - } - EXPORT_SYMBOL(tcp_recvmsg); -@@ -3336,3 +3351,107 @@ void __init tcp_init(void) - tcp_secret_retiring = &tcp_secret_two; - tcp_secret_secondary = &tcp_secret_two; - } -+ -+static int tcp_is_local(struct net *net, __be32 addr) { -+ struct rtable *rt; -+ struct flowi4 fl4 = { .daddr = addr }; -+ rt = ip_route_output_key(net, &fl4); -+ if (IS_ERR_OR_NULL(rt)) -+ return 0; -+ return rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK); -+} -+ -+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -+static int tcp_is_local6(struct net *net, struct in6_addr *addr) { -+ struct rt6_info *rt6 = rt6_lookup(net, addr, addr, 0, 0); -+ return rt6 && rt6->dst.dev && (rt6->dst.dev->flags & IFF_LOOPBACK); -+} -+#endif -+ -+/* -+ * tcp_nuke_addr - destroy all sockets on the given local address -+ * if local address is the unspecified address (0.0.0.0 or ::), destroy all -+ * sockets with local addresses that are not configured. -+ */ -+int tcp_nuke_addr(struct net *net, struct sockaddr *addr) -+{ -+ int family = addr->sa_family; -+ unsigned int bucket; -+ -+ struct in_addr *in; -+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -+ struct in6_addr *in6; -+#endif -+ if (family == AF_INET) { -+ in = &((struct sockaddr_in *)addr)->sin_addr; -+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -+ } else if (family == AF_INET6) { -+ in6 = &((struct sockaddr_in6 *)addr)->sin6_addr; -+#endif -+ } else { -+ return -EAFNOSUPPORT; -+ } -+ -+ for (bucket = 0; bucket < tcp_hashinfo.ehash_mask; bucket++) { -+ struct hlist_nulls_node *node; -+ struct sock *sk; -+ spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket); -+ -+restart: -+ spin_lock_bh(lock); -+ sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) { -+ struct inet_sock *inet = inet_sk(sk); -+ -+ if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT) -+ continue; -+ if (sock_flag(sk, SOCK_DEAD)) -+ continue; -+ -+ if (family == AF_INET) { -+ __be32 s4 = inet->inet_rcv_saddr; -+ if (s4 == LOOPBACK4_IPV6) -+ continue; -+ -+ if (in->s_addr != s4 && -+ !(in->s_addr == INADDR_ANY && -+ !tcp_is_local(net, s4))) -+ continue; -+ } -+ -+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -+ if (family == AF_INET6) { -+ struct in6_addr *s6; -+ if (!inet->pinet6) -+ continue; -+ -+ s6 = &inet->pinet6->rcv_saddr; -+ if (ipv6_addr_type(s6) == IPV6_ADDR_MAPPED) -+ continue; -+ -+ if (!ipv6_addr_equal(in6, s6) && -+ !(ipv6_addr_equal(in6, &in6addr_any) && -+ !tcp_is_local6(net, s6))) -+ continue; -+ } -+#endif -+ -+ sock_hold(sk); -+ spin_unlock_bh(lock); -+ -+ local_bh_disable(); -+ bh_lock_sock(sk); -+ sk->sk_err = ETIMEDOUT; -+ sk->sk_error_report(sk); -+ -+ tcp_done(sk); -+ bh_unlock_sock(sk); -+ local_bh_enable(); -+ sock_put(sk); -+ -+ goto restart; -+ } -+ spin_unlock_bh(lock); -+ } -+ -+ return 0; -+} -diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c -index 8ed1b930..29625e9a 100644 ---- a/net/ipv6/af_inet6.c -+++ b/net/ipv6/af_inet6.c -@@ -62,6 +62,20 @@ - #include <asm/uaccess.h> - #include <linux/mroute6.h> - -+#ifdef CONFIG_ANDROID_PARANOID_NETWORK -+#include <linux/android_aid.h> -+ -+static inline int current_has_network(void) -+{ -+ return in_egroup_p(AID_INET) || capable(CAP_NET_RAW); -+} -+#else -+static inline int current_has_network(void) -+{ -+ return 1; -+} -+#endif -+ - MODULE_AUTHOR("Cast of dozens"); - MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); - MODULE_LICENSE("GPL"); -@@ -108,6 +122,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, - int try_loading_module = 0; - int err; - -+ if (!current_has_network()) -+ return -EACCES; -+ - if (sock->type != SOCK_RAW && - sock->type != SOCK_DGRAM && - !inet_ehash_secret) -@@ -477,6 +494,21 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, - - EXPORT_SYMBOL(inet6_getname); - -+int inet6_killaddr_ioctl(struct net *net, void __user *arg) { -+ struct in6_ifreq ireq; -+ struct sockaddr_in6 sin6; -+ -+ if (!capable(CAP_NET_ADMIN)) -+ return -EACCES; -+ -+ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) -+ return -EFAULT; -+ -+ sin6.sin6_family = AF_INET6; -+ sin6.sin6_addr = ireq.ifr6_addr; -+ return tcp_nuke_addr(net, (struct sockaddr *) &sin6); -+} -+ - int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) - { - struct sock *sk = sock->sk; -@@ -501,6 +533,8 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) - return addrconf_del_ifaddr(net, (void __user *) arg); - case SIOCSIFDSTADDR: - return addrconf_set_dstaddr(net, (void __user *) arg); -+ case SIOCKILLADDR: -+ return inet6_killaddr_ioctl(net, (void __user *) arg); - default: - if (!sk->sk_prot->ioctl) - return -ENOIOCTLCMD; -diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig -index d33cddd1..acd7c9e1 100644 ---- a/net/ipv6/netfilter/Kconfig -+++ b/net/ipv6/netfilter/Kconfig -@@ -175,6 +175,18 @@ config IP6_NF_TARGET_REJECT - - To compile it as a module, choose M here. If unsure, say N. - -+config IP6_NF_TARGET_REJECT_SKERR -+ bool "Force socket error when rejecting with icmp*" -+ depends on IP6_NF_TARGET_REJECT -+ default n -+ help -+ This option enables turning a "--reject-with icmp*" into a matching -+ socket error also. -+ The REJECT target normally allows sending an ICMP message. But it -+ leaves the local socket unaware of any ingress rejects. -+ -+ If unsure, say N. -+ - config IP6_NF_MANGLE - tristate "Packet mangling" - default m if NETFILTER_ADVANCED=n -diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c -index 9d4e1555..e641f8fa 100644 ---- a/net/ipv6/netfilter/ip6_tables.c -+++ b/net/ipv6/netfilter/ip6_tables.c -@@ -2279,16 +2279,15 @@ static void __exit ip6_tables_fini(void) - * "No next header". - * - * If target header is found, its offset is set in *offset and return protocol -- * number. Otherwise, return -1. -+ * number. Otherwise, return -ENOENT or -EBADMSG. - * - * If the first fragment doesn't contain the final protocol header or - * NEXTHDR_NONE it is considered invalid. - * - * Note that non-1st fragment is special case that "the protocol number - * of last header" is "next header" field in Fragment header. In this case, -- * *offset is meaningless and fragment offset is stored in *fragoff if fragoff -- * isn't NULL. -- * -+ * *offset is meaningless. If fragoff is not NULL, the fragment offset is -+ * stored in *fragoff; if it is NULL, return -EINVAL. - */ - int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, - int target, unsigned short *fragoff) -@@ -2329,9 +2328,12 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, - if (target < 0 && - ((!ipv6_ext_hdr(hp->nexthdr)) || - hp->nexthdr == NEXTHDR_NONE)) { -- if (fragoff) -+ if (fragoff) { - *fragoff = _frag_off; -- return hp->nexthdr; -+ return hp->nexthdr; -+ } else { -+ return -EINVAL; -+ } - } - return -ENOENT; - } -diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c -index aad2fa41..09155e34 100644 ---- a/net/ipv6/netfilter/ip6t_REJECT.c -+++ b/net/ipv6/netfilter/ip6t_REJECT.c -@@ -178,6 +178,15 @@ send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code, - skb_in->dev = net->loopback_dev; - - icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); -+#ifdef CONFIG_IP6_NF_TARGET_REJECT_SKERR -+ if (skb_in->sk) { -+ icmpv6_err_convert(ICMPV6_DEST_UNREACH, code, -+ &skb_in->sk->sk_err); -+ skb_in->sk->sk_error_report(skb_in->sk); -+ pr_debug("ip6t_REJECT: sk_err=%d for skb=%p sk=%p\n", -+ skb_in->sk->sk_err, skb_in, skb_in->sk); -+ } -+#endif - } - - static unsigned int -diff --git a/net/ipv6/route.c b/net/ipv6/route.c -index 493490f0..5a272c65 100644 ---- a/net/ipv6/route.c -+++ b/net/ipv6/route.c -@@ -1973,7 +1973,8 @@ void rt6_purge_dflt_routers(struct net *net) - restart: - read_lock_bh(&table->tb6_lock); - for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { -- if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { -+ if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) && -+ (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) { - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - ip6_del_rt(rt); -diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig -index 0c6f67e8..ce2976c0 100644 ---- a/net/netfilter/Kconfig -+++ b/net/netfilter/Kconfig -@@ -967,6 +967,8 @@ config NETFILTER_XT_MATCH_OWNER - based on who created the socket: the user or group. It is also - possible to check whether a socket actually exists. - -+ Conflicts with '"quota, tag, uid" match' -+ - config NETFILTER_XT_MATCH_POLICY - tristate 'IPsec "policy" match support' - depends on XFRM -@@ -1000,6 +1002,22 @@ config NETFILTER_XT_MATCH_PKTTYPE - - To compile it as a module, choose M here. If unsure, say N. - -+config NETFILTER_XT_MATCH_QTAGUID -+ bool '"quota, tag, owner" match and stats support' -+ depends on NETFILTER_XT_MATCH_SOCKET -+ depends on NETFILTER_XT_MATCH_OWNER=n -+ help -+ This option replaces the `owner' match. In addition to matching -+ on uid, it keeps stats based on a tag assigned to a socket. -+ The full tag is comprised of a UID and an accounting tag. -+ The tags are assignable to sockets from user space (e.g. a download -+ manager can assign the socket to another UID for accounting). -+ Stats and control are done via /proc/net/xt_qtaguid/. -+ It replaces owner as it takes the same arguments, but should -+ really be recognized by the iptables tool. -+ -+ If unsure, say `N'. -+ - config NETFILTER_XT_MATCH_QUOTA - tristate '"quota" match support' - depends on NETFILTER_ADVANCED -@@ -1010,6 +1028,30 @@ config NETFILTER_XT_MATCH_QUOTA - If you want to compile it as a module, say M here and read - <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. - -+config NETFILTER_XT_MATCH_QUOTA2 -+ tristate '"quota2" match support' -+ depends on NETFILTER_ADVANCED -+ help -+ This option adds a `quota2' match, which allows to match on a -+ byte counter correctly and not per CPU. -+ It allows naming the quotas. -+ This is based on http://xtables-addons.git.sourceforge.net -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. -+ -+config NETFILTER_XT_MATCH_QUOTA2_LOG -+ bool '"quota2" Netfilter LOG support' -+ depends on NETFILTER_XT_MATCH_QUOTA2 -+ depends on IP_NF_TARGET_ULOG=n # not yes, not module, just no -+ default n -+ help -+ This option allows `quota2' to log ONCE when a quota limit -+ is passed. It logs via NETLINK using the NETLINK_NFLOG family. -+ It logs similarly to how ipt_ULOG would without data. -+ -+ If unsure, say `N'. -+ - config NETFILTER_XT_MATCH_RATEEST - tristate '"rateest" match support' - depends on NETFILTER_ADVANCED -diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile -index ca367658..452e84de 100644 ---- a/net/netfilter/Makefile -+++ b/net/netfilter/Makefile -@@ -101,7 +101,9 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o - obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o - obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o - obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o -+obj-$(CONFIG_NETFILTER_XT_MATCH_QTAGUID) += xt_qtaguid_print.o xt_qtaguid.o - obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o -+obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA2) += xt_quota2.o - obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o - obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o - obj-$(CONFIG_NETFILTER_XT_MATCH_RECENT) += xt_recent.o -diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c -index f407ebc1..f4ba8634 100644 ---- a/net/netfilter/xt_IDLETIMER.c -+++ b/net/netfilter/xt_IDLETIMER.c -@@ -5,6 +5,7 @@ - * After timer expires a kevent will be sent. - * - * Copyright (C) 2004, 2010 Nokia Corporation -+ * - * Written by Timo Teras <ext-timo.teras@nokia.com> - * - * Converted to x_tables and reworked for upstream inclusion -@@ -38,8 +39,10 @@ - #include <linux/netfilter/xt_IDLETIMER.h> - #include <linux/kdev_t.h> - #include <linux/kobject.h> -+#include <linux/skbuff.h> - #include <linux/workqueue.h> - #include <linux/sysfs.h> -+#include <net/net_namespace.h> - - struct idletimer_tg_attr { - struct attribute attr; -@@ -56,6 +59,8 @@ struct idletimer_tg { - struct idletimer_tg_attr attr; - - unsigned int refcnt; -+ bool send_nl_msg; -+ bool active; - }; - - static LIST_HEAD(idletimer_tg_list); -@@ -63,6 +68,32 @@ static DEFINE_MUTEX(list_mutex); - - static struct kobject *idletimer_tg_kobj; - -+static void notify_netlink_uevent(const char *label, struct idletimer_tg *timer) -+{ -+ char label_msg[NLMSG_MAX_SIZE]; -+ char state_msg[NLMSG_MAX_SIZE]; -+ char *envp[] = { label_msg, state_msg, NULL }; -+ int res; -+ -+ res = snprintf(label_msg, NLMSG_MAX_SIZE, "LABEL=%s", -+ label); -+ if (NLMSG_MAX_SIZE <= res) { -+ pr_err("message too long (%d)", res); -+ return; -+ } -+ res = snprintf(state_msg, NLMSG_MAX_SIZE, "STATE=%s", -+ timer->active ? "active" : "inactive"); -+ if (NLMSG_MAX_SIZE <= res) { -+ pr_err("message too long (%d)", res); -+ return; -+ } -+ pr_debug("putting nlmsg: <%s> <%s>\n", label_msg, state_msg); -+ kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp); -+ return; -+ -+ -+} -+ - static - struct idletimer_tg *__idletimer_tg_find_by_label(const char *label) - { -@@ -83,6 +114,7 @@ static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr, - { - struct idletimer_tg *timer; - unsigned long expires = 0; -+ unsigned long now = jiffies; - - mutex_lock(&list_mutex); - -@@ -92,11 +124,15 @@ static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr, - - mutex_unlock(&list_mutex); - -- if (time_after(expires, jiffies)) -+ if (time_after(expires, now)) - return sprintf(buf, "%u\n", -- jiffies_to_msecs(expires - jiffies) / 1000); -+ jiffies_to_msecs(expires - now) / 1000); - -- return sprintf(buf, "0\n"); -+ if (timer->send_nl_msg) -+ return sprintf(buf, "0 %d\n", -+ jiffies_to_msecs(now - expires) / 1000); -+ else -+ return sprintf(buf, "0\n"); - } - - static void idletimer_tg_work(struct work_struct *work) -@@ -105,6 +141,9 @@ static void idletimer_tg_work(struct work_struct *work) - work); - - sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name); -+ -+ if (timer->send_nl_msg) -+ notify_netlink_uevent(timer->attr.attr.name, timer); - } - - static void idletimer_tg_expired(unsigned long data) -@@ -113,6 +152,7 @@ static void idletimer_tg_expired(unsigned long data) - - pr_debug("timer %s expired\n", timer->attr.attr.name); - -+ timer->active = false; - schedule_work(&timer->work); - } - -@@ -145,6 +185,8 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) - setup_timer(&info->timer->timer, idletimer_tg_expired, - (unsigned long) info->timer); - info->timer->refcnt = 1; -+ info->timer->send_nl_msg = (info->send_nl_msg == 0) ? false : true; -+ info->timer->active = true; - - mod_timer(&info->timer->timer, - msecs_to_jiffies(info->timeout * 1000) + jiffies); -@@ -168,14 +210,24 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb, - const struct xt_action_param *par) - { - const struct idletimer_tg_info *info = par->targinfo; -+ unsigned long now = jiffies; - - pr_debug("resetting timer %s, timeout period %u\n", - info->label, info->timeout); - - BUG_ON(!info->timer); - -+ info->timer->active = true; -+ -+ if (time_before(info->timer->timer.expires, now)) { -+ schedule_work(&info->timer->work); -+ pr_debug("Starting timer %s (Expired, Jiffies): %lu, %lu\n", -+ info->label, info->timer->timer.expires, now); -+ } -+ -+ /* TODO: Avoid modifying timers on each packet */ - mod_timer(&info->timer->timer, -- msecs_to_jiffies(info->timeout * 1000) + jiffies); -+ msecs_to_jiffies(info->timeout * 1000) + now); - - return XT_CONTINUE; - } -@@ -184,8 +236,9 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) - { - struct idletimer_tg_info *info = par->targinfo; - int ret; -+ unsigned long now = jiffies; - -- pr_debug("checkentry targinfo%s\n", info->label); -+ pr_debug("checkentry targinfo %s\n", info->label); - - if (info->timeout == 0) { - pr_debug("timeout value is zero\n"); -@@ -204,8 +257,16 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) - info->timer = __idletimer_tg_find_by_label(info->label); - if (info->timer) { - info->timer->refcnt++; -+ info->timer->active = true; -+ -+ if (time_before(info->timer->timer.expires, now)) { -+ schedule_work(&info->timer->work); -+ pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n", -+ info->timer->timer.expires, now); -+ } -+ - mod_timer(&info->timer->timer, -- msecs_to_jiffies(info->timeout * 1000) + jiffies); -+ msecs_to_jiffies(info->timeout * 1000) + now); - - pr_debug("increased refcnt of timer %s to %u\n", - info->label, info->timer->refcnt); -@@ -219,6 +280,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) - } - - mutex_unlock(&list_mutex); -+ - return 0; - } - -@@ -240,7 +302,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) - kfree(info->timer); - } else { - pr_debug("decreased refcnt of timer %s to %u\n", -- info->label, info->timer->refcnt); -+ info->label, info->timer->refcnt); - } - - mutex_unlock(&list_mutex); -@@ -248,6 +310,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) - - static struct xt_target idletimer_tg __read_mostly = { - .name = "IDLETIMER", -+ .revision = 1, - .family = NFPROTO_UNSPEC, - .target = idletimer_tg_target, - .targetsize = sizeof(struct idletimer_tg_info), -@@ -313,3 +376,4 @@ MODULE_DESCRIPTION("Xtables: idle time monitor"); - MODULE_LICENSE("GPL v2"); - MODULE_ALIAS("ipt_IDLETIMER"); - MODULE_ALIAS("ip6t_IDLETIMER"); -+MODULE_ALIAS("arpt_IDLETIMER"); -diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c -new file mode 100644 -index 00000000..495b62ea ---- /dev/null -+++ b/net/netfilter/xt_qtaguid.c -@@ -0,0 +1,2990 @@ -+/* -+ * Kernel iptables module to track stats for packets based on user tags. -+ * -+ * (C) 2011 Google, 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. -+ */ -+ -+/* -+ * There are run-time debug flags enabled via the debug_mask module param, or -+ * via the DEFAULT_DEBUG_MASK. See xt_qtaguid_internal.h. -+ */ -+#define DEBUG -+ -+#include <linux/file.h> -+#include <linux/inetdevice.h> -+#include <linux/module.h> -+#include <linux/netfilter/x_tables.h> -+#include <linux/netfilter/xt_qtaguid.h> -+#include <linux/skbuff.h> -+#include <linux/workqueue.h> -+#include <net/addrconf.h> -+#include <net/sock.h> -+#include <net/tcp.h> -+#include <net/udp.h> -+ -+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) -+#include <linux/netfilter_ipv6/ip6_tables.h> -+#endif -+ -+#include <linux/netfilter/xt_socket.h> -+#include "xt_qtaguid_internal.h" -+#include "xt_qtaguid_print.h" -+ -+/* -+ * We only use the xt_socket funcs within a similar context to avoid unexpected -+ * return values. -+ */ -+#define XT_SOCKET_SUPPORTED_HOOKS \ -+ ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN)) -+ -+ -+static const char *module_procdirname = "xt_qtaguid"; -+static struct proc_dir_entry *xt_qtaguid_procdir; -+ -+static unsigned int proc_iface_perms = S_IRUGO; -+module_param_named(iface_perms, proc_iface_perms, uint, S_IRUGO | S_IWUSR); -+ -+static struct proc_dir_entry *xt_qtaguid_stats_file; -+static unsigned int proc_stats_perms = S_IRUGO; -+module_param_named(stats_perms, proc_stats_perms, uint, S_IRUGO | S_IWUSR); -+ -+static struct proc_dir_entry *xt_qtaguid_ctrl_file; -+ -+/* Everybody can write. But proc_ctrl_write_limited is true by default which -+ * limits what can be controlled. See the can_*() functions. -+ */ -+static unsigned int proc_ctrl_perms = S_IRUGO | S_IWUGO; -+module_param_named(ctrl_perms, proc_ctrl_perms, uint, S_IRUGO | S_IWUSR); -+ -+/* Limited by default, so the gid of the ctrl and stats proc entries -+ * will limit what can be done. See the can_*() functions. -+ */ -+static bool proc_stats_readall_limited = true; -+static bool proc_ctrl_write_limited = true; -+ -+module_param_named(stats_readall_limited, proc_stats_readall_limited, bool, -+ S_IRUGO | S_IWUSR); -+module_param_named(ctrl_write_limited, proc_ctrl_write_limited, bool, -+ S_IRUGO | S_IWUSR); -+ -+/* -+ * Limit the number of active tags (via socket tags) for a given UID. -+ * Multiple processes could share the UID. -+ */ -+static int max_sock_tags = DEFAULT_MAX_SOCK_TAGS; -+module_param(max_sock_tags, int, S_IRUGO | S_IWUSR); -+ -+/* -+ * After the kernel has initiallized this module, it is still possible -+ * to make it passive. -+ * Setting passive to Y: -+ * - the iface stats handling will not act on notifications. -+ * - iptables matches will never match. -+ * - ctrl commands silently succeed. -+ * - stats are always empty. -+ * This is mostly usefull when a bug is suspected. -+ */ -+static bool module_passive; -+module_param_named(passive, module_passive, bool, S_IRUGO | S_IWUSR); -+ -+/* -+ * Control how qtaguid data is tracked per proc/uid. -+ * Setting tag_tracking_passive to Y: -+ * - don't create proc specific structs to track tags -+ * - don't check that active tag stats exceed some limits. -+ * - don't clean up socket tags on process exits. -+ * This is mostly usefull when a bug is suspected. -+ */ -+static bool qtu_proc_handling_passive; -+module_param_named(tag_tracking_passive, qtu_proc_handling_passive, bool, -+ S_IRUGO | S_IWUSR); -+ -+#define QTU_DEV_NAME "xt_qtaguid" -+ -+uint qtaguid_debug_mask = DEFAULT_DEBUG_MASK; -+module_param_named(debug_mask, qtaguid_debug_mask, uint, S_IRUGO | S_IWUSR); -+ -+/*---------------------------------------------------------------------------*/ -+static const char *iface_stat_procdirname = "iface_stat"; -+static struct proc_dir_entry *iface_stat_procdir; -+/* -+ * The iface_stat_all* will go away once userspace gets use to the new fields -+ * that have a format line. -+ */ -+static const char *iface_stat_all_procfilename = "iface_stat_all"; -+static struct proc_dir_entry *iface_stat_all_procfile; -+static const char *iface_stat_fmt_procfilename = "iface_stat_fmt"; -+static struct proc_dir_entry *iface_stat_fmt_procfile; -+ -+ -+/* -+ * Ordering of locks: -+ * outer locks: -+ * iface_stat_list_lock -+ * sock_tag_list_lock -+ * inner locks: -+ * uid_tag_data_tree_lock -+ * tag_counter_set_list_lock -+ * Notice how sock_tag_list_lock is held sometimes when uid_tag_data_tree_lock -+ * is acquired. -+ * -+ * Call tree with all lock holders as of 2012-04-27: -+ * -+ * iface_stat_fmt_proc_read() -+ * iface_stat_list_lock -+ * (struct iface_stat) -+ * -+ * qtaguid_ctrl_proc_read() -+ * sock_tag_list_lock -+ * (sock_tag_tree) -+ * (struct proc_qtu_data->sock_tag_list) -+ * prdebug_full_state() -+ * sock_tag_list_lock -+ * (sock_tag_tree) -+ * uid_tag_data_tree_lock -+ * (uid_tag_data_tree) -+ * (proc_qtu_data_tree) -+ * iface_stat_list_lock -+ * -+ * qtaguid_stats_proc_read() -+ * iface_stat_list_lock -+ * struct iface_stat->tag_stat_list_lock -+ * -+ * qtudev_open() -+ * uid_tag_data_tree_lock -+ * -+ * qtudev_release() -+ * sock_tag_data_list_lock -+ * uid_tag_data_tree_lock -+ * prdebug_full_state() -+ * sock_tag_list_lock -+ * uid_tag_data_tree_lock -+ * iface_stat_list_lock -+ * -+ * iface_netdev_event_handler() -+ * iface_stat_create() -+ * iface_stat_list_lock -+ * iface_stat_update() -+ * iface_stat_list_lock -+ * -+ * iface_inetaddr_event_handler() -+ * iface_stat_create() -+ * iface_stat_list_lock -+ * iface_stat_update() -+ * iface_stat_list_lock -+ * -+ * iface_inet6addr_event_handler() -+ * iface_stat_create_ipv6() -+ * iface_stat_list_lock -+ * iface_stat_update() -+ * iface_stat_list_lock -+ * -+ * qtaguid_mt() -+ * account_for_uid() -+ * if_tag_stat_update() -+ * get_sock_stat() -+ * sock_tag_list_lock -+ * struct iface_stat->tag_stat_list_lock -+ * tag_stat_update() -+ * get_active_counter_set() -+ * tag_counter_set_list_lock -+ * tag_stat_update() -+ * get_active_counter_set() -+ * tag_counter_set_list_lock -+ * -+ * -+ * qtaguid_ctrl_parse() -+ * ctrl_cmd_delete() -+ * sock_tag_list_lock -+ * tag_counter_set_list_lock -+ * iface_stat_list_lock -+ * struct iface_stat->tag_stat_list_lock -+ * uid_tag_data_tree_lock -+ * ctrl_cmd_counter_set() -+ * tag_counter_set_list_lock -+ * ctrl_cmd_tag() -+ * sock_tag_list_lock -+ * (sock_tag_tree) -+ * get_tag_ref() -+ * uid_tag_data_tree_lock -+ * (uid_tag_data_tree) -+ * uid_tag_data_tree_lock -+ * (proc_qtu_data_tree) -+ * ctrl_cmd_untag() -+ * sock_tag_list_lock -+ * uid_tag_data_tree_lock -+ * -+ */ -+static LIST_HEAD(iface_stat_list); -+static DEFINE_SPINLOCK(iface_stat_list_lock); -+ -+static struct rb_root sock_tag_tree = RB_ROOT; -+static DEFINE_SPINLOCK(sock_tag_list_lock); -+ -+static struct rb_root tag_counter_set_tree = RB_ROOT; -+static DEFINE_SPINLOCK(tag_counter_set_list_lock); -+ -+static struct rb_root uid_tag_data_tree = RB_ROOT; -+static DEFINE_SPINLOCK(uid_tag_data_tree_lock); -+ -+static struct rb_root proc_qtu_data_tree = RB_ROOT; -+/* No proc_qtu_data_tree_lock; use uid_tag_data_tree_lock */ -+ -+static struct qtaguid_event_counts qtu_events; -+/*----------------------------------------------*/ -+static bool can_manipulate_uids(void) -+{ -+ /* root pwnd */ -+ return in_egroup_p(xt_qtaguid_ctrl_file->gid) -+ || unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_limited) -+ || unlikely(current_fsuid() == xt_qtaguid_ctrl_file->uid); -+} -+ -+static bool can_impersonate_uid(uid_t uid) -+{ -+ return uid == current_fsuid() || can_manipulate_uids(); -+} -+ -+static bool can_read_other_uid_stats(uid_t uid) -+{ -+ /* root pwnd */ -+ return in_egroup_p(xt_qtaguid_stats_file->gid) -+ || unlikely(!current_fsuid()) || uid == current_fsuid() -+ || unlikely(!proc_stats_readall_limited) -+ || unlikely(current_fsuid() == xt_qtaguid_ctrl_file->uid); -+} -+ -+static inline void dc_add_byte_packets(struct data_counters *counters, int set, -+ enum ifs_tx_rx direction, -+ enum ifs_proto ifs_proto, -+ int bytes, -+ int packets) -+{ -+ counters->bpc[set][direction][ifs_proto].bytes += bytes; -+ counters->bpc[set][direction][ifs_proto].packets += packets; -+} -+ -+static struct tag_node *tag_node_tree_search(struct rb_root *root, tag_t tag) -+{ -+ struct rb_node *node = root->rb_node; -+ -+ while (node) { -+ struct tag_node *data = rb_entry(node, struct tag_node, node); -+ int result; -+ RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): " -+ " node=%p data=%p\n", tag, node, data); -+ result = tag_compare(tag, data->tag); -+ RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): " -+ " data.tag=0x%llx (uid=%u) res=%d\n", -+ tag, data->tag, get_uid_from_tag(data->tag), result); -+ if (result < 0) -+ node = node->rb_left; -+ else if (result > 0) -+ node = node->rb_right; -+ else -+ return data; -+ } -+ return NULL; -+} -+ -+static void tag_node_tree_insert(struct tag_node *data, struct rb_root *root) -+{ -+ struct rb_node **new = &(root->rb_node), *parent = NULL; -+ -+ /* Figure out where to put new node */ -+ while (*new) { -+ struct tag_node *this = rb_entry(*new, struct tag_node, -+ node); -+ int result = tag_compare(data->tag, this->tag); -+ RB_DEBUG("qtaguid: %s(): tag=0x%llx" -+ " (uid=%u)\n", __func__, -+ this->tag, -+ get_uid_from_tag(this->tag)); -+ parent = *new; -+ if (result < 0) -+ new = &((*new)->rb_left); -+ else if (result > 0) -+ new = &((*new)->rb_right); -+ else -+ BUG(); -+ } -+ -+ /* Add new node and rebalance tree. */ -+ rb_link_node(&data->node, parent, new); -+ rb_insert_color(&data->node, root); -+} -+ -+static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root) -+{ -+ tag_node_tree_insert(&data->tn, root); -+} -+ -+static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag) -+{ -+ struct tag_node *node = tag_node_tree_search(root, tag); -+ if (!node) -+ return NULL; -+ return rb_entry(&node->node, struct tag_stat, tn.node); -+} -+ -+static void tag_counter_set_tree_insert(struct tag_counter_set *data, -+ struct rb_root *root) -+{ -+ tag_node_tree_insert(&data->tn, root); -+} -+ -+static struct tag_counter_set *tag_counter_set_tree_search(struct rb_root *root, -+ tag_t tag) -+{ -+ struct tag_node *node = tag_node_tree_search(root, tag); -+ if (!node) -+ return NULL; -+ return rb_entry(&node->node, struct tag_counter_set, tn.node); -+ -+} -+ -+static void tag_ref_tree_insert(struct tag_ref *data, struct rb_root *root) -+{ -+ tag_node_tree_insert(&data->tn, root); -+} -+ -+static struct tag_ref *tag_ref_tree_search(struct rb_root *root, tag_t tag) -+{ -+ struct tag_node *node = tag_node_tree_search(root, tag); -+ if (!node) -+ return NULL; -+ return rb_entry(&node->node, struct tag_ref, tn.node); -+} -+ -+static struct sock_tag *sock_tag_tree_search(struct rb_root *root, -+ const struct sock *sk) -+{ -+ struct rb_node *node = root->rb_node; -+ -+ while (node) { -+ struct sock_tag *data = rb_entry(node, struct sock_tag, -+ sock_node); -+ if (sk < data->sk) -+ node = node->rb_left; -+ else if (sk > data->sk) -+ node = node->rb_right; -+ else -+ return data; -+ } -+ return NULL; -+} -+ -+static void sock_tag_tree_insert(struct sock_tag *data, struct rb_root *root) -+{ -+ struct rb_node **new = &(root->rb_node), *parent = NULL; -+ -+ /* Figure out where to put new node */ -+ while (*new) { -+ struct sock_tag *this = rb_entry(*new, struct sock_tag, -+ sock_node); -+ parent = *new; -+ if (data->sk < this->sk) -+ new = &((*new)->rb_left); -+ else if (data->sk > this->sk) -+ new = &((*new)->rb_right); -+ else -+ BUG(); -+ } -+ -+ /* Add new node and rebalance tree. */ -+ rb_link_node(&data->sock_node, parent, new); -+ rb_insert_color(&data->sock_node, root); -+} -+ -+static void sock_tag_tree_erase(struct rb_root *st_to_free_tree) -+{ -+ struct rb_node *node; -+ struct sock_tag *st_entry; -+ -+ node = rb_first(st_to_free_tree); -+ while (node) { -+ st_entry = rb_entry(node, struct sock_tag, sock_node); -+ node = rb_next(node); -+ CT_DEBUG("qtaguid: %s(): " -+ "erase st: sk=%p tag=0x%llx (uid=%u)\n", __func__, -+ st_entry->sk, -+ st_entry->tag, -+ get_uid_from_tag(st_entry->tag)); -+ rb_erase(&st_entry->sock_node, st_to_free_tree); -+ sockfd_put(st_entry->socket); -+ kfree(st_entry); -+ } -+} -+ -+static struct proc_qtu_data *proc_qtu_data_tree_search(struct rb_root *root, -+ const pid_t pid) -+{ -+ struct rb_node *node = root->rb_node; -+ -+ while (node) { -+ struct proc_qtu_data *data = rb_entry(node, -+ struct proc_qtu_data, -+ node); -+ if (pid < data->pid) -+ node = node->rb_left; -+ else if (pid > data->pid) -+ node = node->rb_right; -+ else -+ return data; -+ } -+ return NULL; -+} -+ -+static void proc_qtu_data_tree_insert(struct proc_qtu_data *data, -+ struct rb_root *root) -+{ -+ struct rb_node **new = &(root->rb_node), *parent = NULL; -+ -+ /* Figure out where to put new node */ -+ while (*new) { -+ struct proc_qtu_data *this = rb_entry(*new, -+ struct proc_qtu_data, -+ node); -+ parent = *new; -+ if (data->pid < this->pid) -+ new = &((*new)->rb_left); -+ else if (data->pid > this->pid) -+ new = &((*new)->rb_right); -+ else -+ BUG(); -+ } -+ -+ /* Add new node and rebalance tree. */ -+ rb_link_node(&data->node, parent, new); -+ rb_insert_color(&data->node, root); -+} -+ -+static void uid_tag_data_tree_insert(struct uid_tag_data *data, -+ struct rb_root *root) -+{ -+ struct rb_node **new = &(root->rb_node), *parent = NULL; -+ -+ /* Figure out where to put new node */ -+ while (*new) { -+ struct uid_tag_data *this = rb_entry(*new, -+ struct uid_tag_data, -+ node); -+ parent = *new; -+ if (data->uid < this->uid) -+ new = &((*new)->rb_left); -+ else if (data->uid > this->uid) -+ new = &((*new)->rb_right); -+ else -+ BUG(); -+ } -+ -+ /* Add new node and rebalance tree. */ -+ rb_link_node(&data->node, parent, new); -+ rb_insert_color(&data->node, root); -+} -+ -+static struct uid_tag_data *uid_tag_data_tree_search(struct rb_root *root, -+ uid_t uid) -+{ -+ struct rb_node *node = root->rb_node; -+ -+ while (node) { -+ struct uid_tag_data *data = rb_entry(node, -+ struct uid_tag_data, -+ node); -+ if (uid < data->uid) -+ node = node->rb_left; -+ else if (uid > data->uid) -+ node = node->rb_right; -+ else -+ return data; -+ } -+ return NULL; -+} -+ -+/* -+ * Allocates a new uid_tag_data struct if needed. -+ * Returns a pointer to the found or allocated uid_tag_data. -+ * Returns a PTR_ERR on failures, and lock is not held. -+ * If found is not NULL: -+ * sets *found to true if not allocated. -+ * sets *found to false if allocated. -+ */ -+struct uid_tag_data *get_uid_data(uid_t uid, bool *found_res) -+{ -+ struct uid_tag_data *utd_entry; -+ -+ /* Look for top level uid_tag_data for the UID */ -+ utd_entry = uid_tag_data_tree_search(&uid_tag_data_tree, uid); -+ DR_DEBUG("qtaguid: get_uid_data(%u) utd=%p\n", uid, utd_entry); -+ -+ if (found_res) -+ *found_res = utd_entry; -+ if (utd_entry) -+ return utd_entry; -+ -+ utd_entry = kzalloc(sizeof(*utd_entry), GFP_ATOMIC); -+ if (!utd_entry) { -+ pr_err("qtaguid: get_uid_data(%u): " -+ "tag data alloc failed\n", uid); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ utd_entry->uid = uid; -+ utd_entry->tag_ref_tree = RB_ROOT; -+ uid_tag_data_tree_insert(utd_entry, &uid_tag_data_tree); -+ DR_DEBUG("qtaguid: get_uid_data(%u) new utd=%p\n", uid, utd_entry); -+ return utd_entry; -+} -+ -+/* Never returns NULL. Either PTR_ERR or a valid ptr. */ -+static struct tag_ref *new_tag_ref(tag_t new_tag, -+ struct uid_tag_data *utd_entry) -+{ -+ struct tag_ref *tr_entry; -+ int res; -+ -+ if (utd_entry->num_active_tags + 1 > max_sock_tags) { -+ pr_info("qtaguid: new_tag_ref(0x%llx): " -+ "tag ref alloc quota exceeded. max=%d\n", -+ new_tag, max_sock_tags); -+ res = -EMFILE; -+ goto err_res; -+ -+ } -+ -+ tr_entry = kzalloc(sizeof(*tr_entry), GFP_ATOMIC); -+ if (!tr_entry) { -+ pr_err("qtaguid: new_tag_ref(0x%llx): " -+ "tag ref alloc failed\n", -+ new_tag); -+ res = -ENOMEM; -+ goto err_res; -+ } -+ tr_entry->tn.tag = new_tag; -+ /* tr_entry->num_sock_tags handled by caller */ -+ utd_entry->num_active_tags++; -+ tag_ref_tree_insert(tr_entry, &utd_entry->tag_ref_tree); -+ DR_DEBUG("qtaguid: new_tag_ref(0x%llx): " -+ " inserted new tag ref %p\n", -+ new_tag, tr_entry); -+ return tr_entry; -+ -+err_res: -+ return ERR_PTR(res); -+} -+ -+static struct tag_ref *lookup_tag_ref(tag_t full_tag, -+ struct uid_tag_data **utd_res) -+{ -+ struct uid_tag_data *utd_entry; -+ struct tag_ref *tr_entry; -+ bool found_utd; -+ uid_t uid = get_uid_from_tag(full_tag); -+ -+ DR_DEBUG("qtaguid: lookup_tag_ref(tag=0x%llx (uid=%u))\n", -+ full_tag, uid); -+ -+ utd_entry = get_uid_data(uid, &found_utd); -+ if (IS_ERR_OR_NULL(utd_entry)) { -+ if (utd_res) -+ *utd_res = utd_entry; -+ return NULL; -+ } -+ -+ tr_entry = tag_ref_tree_search(&utd_entry->tag_ref_tree, full_tag); -+ if (utd_res) -+ *utd_res = utd_entry; -+ DR_DEBUG("qtaguid: lookup_tag_ref(0x%llx) utd_entry=%p tr_entry=%p\n", -+ full_tag, utd_entry, tr_entry); -+ return tr_entry; -+} -+ -+/* Never returns NULL. Either PTR_ERR or a valid ptr. */ -+static struct tag_ref *get_tag_ref(tag_t full_tag, -+ struct uid_tag_data **utd_res) -+{ -+ struct uid_tag_data *utd_entry; -+ struct tag_ref *tr_entry; -+ -+ DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n", -+ full_tag); -+ spin_lock_bh(&uid_tag_data_tree_lock); -+ tr_entry = lookup_tag_ref(full_tag, &utd_entry); -+ BUG_ON(IS_ERR_OR_NULL(utd_entry)); -+ if (!tr_entry) -+ tr_entry = new_tag_ref(full_tag, utd_entry); -+ -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ if (utd_res) -+ *utd_res = utd_entry; -+ DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n", -+ full_tag, utd_entry, tr_entry); -+ return tr_entry; -+} -+ -+/* Checks and maybe frees the UID Tag Data entry */ -+static void put_utd_entry(struct uid_tag_data *utd_entry) -+{ -+ /* Are we done with the UID tag data entry? */ -+ if (RB_EMPTY_ROOT(&utd_entry->tag_ref_tree) && -+ !utd_entry->num_pqd) { -+ DR_DEBUG("qtaguid: %s(): " -+ "erase utd_entry=%p uid=%u " -+ "by pid=%u tgid=%u uid=%u\n", __func__, -+ utd_entry, utd_entry->uid, -+ current->pid, current->tgid, current_fsuid()); -+ BUG_ON(utd_entry->num_active_tags); -+ rb_erase(&utd_entry->node, &uid_tag_data_tree); -+ kfree(utd_entry); -+ } else { -+ DR_DEBUG("qtaguid: %s(): " -+ "utd_entry=%p still has %d tags %d proc_qtu_data\n", -+ __func__, utd_entry, utd_entry->num_active_tags, -+ utd_entry->num_pqd); -+ BUG_ON(!(utd_entry->num_active_tags || -+ utd_entry->num_pqd)); -+ } -+} -+ -+/* -+ * If no sock_tags are using this tag_ref, -+ * decrements refcount of utd_entry, removes tr_entry -+ * from utd_entry->tag_ref_tree and frees. -+ */ -+static void free_tag_ref_from_utd_entry(struct tag_ref *tr_entry, -+ struct uid_tag_data *utd_entry) -+{ -+ DR_DEBUG("qtaguid: %s(): %p tag=0x%llx (uid=%u)\n", __func__, -+ tr_entry, tr_entry->tn.tag, -+ get_uid_from_tag(tr_entry->tn.tag)); -+ if (!tr_entry->num_sock_tags) { -+ BUG_ON(!utd_entry->num_active_tags); -+ utd_entry->num_active_tags--; -+ rb_erase(&tr_entry->tn.node, &utd_entry->tag_ref_tree); -+ DR_DEBUG("qtaguid: %s(): erased %p\n", __func__, tr_entry); -+ kfree(tr_entry); -+ } -+} -+ -+static void put_tag_ref_tree(tag_t full_tag, struct uid_tag_data *utd_entry) -+{ -+ struct rb_node *node; -+ struct tag_ref *tr_entry; -+ tag_t acct_tag; -+ -+ DR_DEBUG("qtaguid: %s(tag=0x%llx (uid=%u))\n", __func__, -+ full_tag, get_uid_from_tag(full_tag)); -+ acct_tag = get_atag_from_tag(full_tag); -+ node = rb_first(&utd_entry->tag_ref_tree); -+ while (node) { -+ tr_entry = rb_entry(node, struct tag_ref, tn.node); -+ node = rb_next(node); -+ if (!acct_tag || tr_entry->tn.tag == full_tag) -+ free_tag_ref_from_utd_entry(tr_entry, utd_entry); -+ } -+} -+ -+static int read_proc_u64(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len; -+ uint64_t value; -+ char *p = page; -+ uint64_t *iface_entry = data; -+ -+ if (!data) -+ return 0; -+ -+ value = *iface_entry; -+ p += sprintf(p, "%llu\n", value); -+ len = (p - page) - off; -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ return len; -+} -+ -+static int read_proc_bool(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len; -+ bool value; -+ char *p = page; -+ bool *bool_entry = data; -+ -+ if (!data) -+ return 0; -+ -+ value = *bool_entry; -+ p += sprintf(p, "%u\n", value); -+ len = (p - page) - off; -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ return len; -+} -+ -+static int get_active_counter_set(tag_t tag) -+{ -+ int active_set = 0; -+ struct tag_counter_set *tcs; -+ -+ MT_DEBUG("qtaguid: get_active_counter_set(tag=0x%llx)" -+ " (uid=%u)\n", -+ tag, get_uid_from_tag(tag)); -+ /* For now we only handle UID tags for active sets */ -+ tag = get_utag_from_tag(tag); -+ spin_lock_bh(&tag_counter_set_list_lock); -+ tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag); -+ if (tcs) -+ active_set = tcs->active_set; -+ spin_unlock_bh(&tag_counter_set_list_lock); -+ return active_set; -+} -+ -+/* -+ * Find the entry for tracking the specified interface. -+ * Caller must hold iface_stat_list_lock -+ */ -+static struct iface_stat *get_iface_entry(const char *ifname) -+{ -+ struct iface_stat *iface_entry; -+ -+ /* Find the entry for tracking the specified tag within the interface */ -+ if (ifname == NULL) { -+ pr_info("qtaguid: iface_stat: get() NULL device name\n"); -+ return NULL; -+ } -+ -+ /* Iterate over interfaces */ -+ list_for_each_entry(iface_entry, &iface_stat_list, list) { -+ if (!strcmp(ifname, iface_entry->ifname)) -+ goto done; -+ } -+ iface_entry = NULL; -+done: -+ return iface_entry; -+} -+ -+/* This is for fmt2 only */ -+static int pp_iface_stat_line(bool header, char *outp, -+ int char_count, struct iface_stat *iface_entry) -+{ -+ int len; -+ if (header) { -+ len = snprintf(outp, char_count, -+ "ifname " -+ "total_skb_rx_bytes total_skb_rx_packets " -+ "total_skb_tx_bytes total_skb_tx_packets " -+ "rx_tcp_bytes rx_tcp_packets " -+ "rx_udp_bytes rx_udp_packets " -+ "rx_other_bytes rx_other_packets " -+ "tx_tcp_bytes tx_tcp_packets " -+ "tx_udp_bytes tx_udp_packets " -+ "tx_other_bytes tx_other_packets\n" -+ ); -+ } else { -+ struct data_counters *cnts; -+ int cnt_set = 0; /* We only use one set for the device */ -+ cnts = &iface_entry->totals_via_skb; -+ len = snprintf( -+ outp, char_count, -+ "%s " -+ "%llu %llu %llu %llu %llu %llu %llu %llu " -+ "%llu %llu %llu %llu %llu %llu %llu %llu\n", -+ iface_entry->ifname, -+ dc_sum_bytes(cnts, cnt_set, IFS_RX), -+ dc_sum_packets(cnts, cnt_set, IFS_RX), -+ dc_sum_bytes(cnts, cnt_set, IFS_TX), -+ dc_sum_packets(cnts, cnt_set, IFS_TX), -+ cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes, -+ cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets, -+ cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes, -+ cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets, -+ cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes, -+ cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets, -+ cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes, -+ cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets, -+ cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes, -+ cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets, -+ cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes, -+ cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets); -+ } -+ return len; -+} -+ -+static int iface_stat_fmt_proc_read(char *page, char **num_items_returned, -+ off_t items_to_skip, int char_count, -+ int *eof, void *data) -+{ -+ char *outp = page; -+ int item_index = 0; -+ int len; -+ int fmt = (int)data; /* The data is just 1 (old) or 2 (uses fmt) */ -+ struct iface_stat *iface_entry; -+ struct rtnl_link_stats64 dev_stats, *stats; -+ struct rtnl_link_stats64 no_dev_stats = {0}; -+ -+ if (unlikely(module_passive)) { -+ *eof = 1; -+ return 0; -+ } -+ -+ CT_DEBUG("qtaguid:proc iface_stat_fmt " -+ "pid=%u tgid=%u uid=%u " -+ "page=%p *num_items_returned=%p off=%ld " -+ "char_count=%d *eof=%d\n", -+ current->pid, current->tgid, current_fsuid(), -+ page, *num_items_returned, -+ items_to_skip, char_count, *eof); -+ -+ if (*eof) -+ return 0; -+ -+ if (fmt == 2 && item_index++ >= items_to_skip) { -+ len = pp_iface_stat_line(true, outp, char_count, NULL); -+ if (len >= char_count) { -+ *outp = '\0'; -+ return outp - page; -+ } -+ outp += len; -+ char_count -= len; -+ (*num_items_returned)++; -+ } -+ -+ /* -+ * This lock will prevent iface_stat_update() from changing active, -+ * and in turn prevent an interface from unregistering itself. -+ */ -+ spin_lock_bh(&iface_stat_list_lock); -+ list_for_each_entry(iface_entry, &iface_stat_list, list) { -+ if (item_index++ < items_to_skip) -+ continue; -+ -+ if (iface_entry->active) { -+ stats = dev_get_stats(iface_entry->net_dev, -+ &dev_stats); -+ } else { -+ stats = &no_dev_stats; -+ } -+ /* -+ * If the meaning of the data changes, then update the fmtX -+ * string. -+ */ -+ if (fmt == 1) { -+ len = snprintf( -+ outp, char_count, -+ "%s %d " -+ "%llu %llu %llu %llu " -+ "%llu %llu %llu %llu\n", -+ iface_entry->ifname, -+ iface_entry->active, -+ iface_entry->totals_via_dev[IFS_RX].bytes, -+ iface_entry->totals_via_dev[IFS_RX].packets, -+ iface_entry->totals_via_dev[IFS_TX].bytes, -+ iface_entry->totals_via_dev[IFS_TX].packets, -+ stats->rx_bytes, stats->rx_packets, -+ stats->tx_bytes, stats->tx_packets -+ ); -+ } else { -+ len = pp_iface_stat_line(false, outp, char_count, -+ iface_entry); -+ } -+ if (len >= char_count) { -+ spin_unlock_bh(&iface_stat_list_lock); -+ *outp = '\0'; -+ return outp - page; -+ } -+ outp += len; -+ char_count -= len; -+ (*num_items_returned)++; -+ } -+ spin_unlock_bh(&iface_stat_list_lock); -+ -+ *eof = 1; -+ return outp - page; -+} -+ -+static void iface_create_proc_worker(struct work_struct *work) -+{ -+ struct proc_dir_entry *proc_entry; -+ struct iface_stat_work *isw = container_of(work, struct iface_stat_work, -+ iface_work); -+ struct iface_stat *new_iface = isw->iface_entry; -+ -+ /* iface_entries are not deleted, so safe to manipulate. */ -+ proc_entry = proc_mkdir(new_iface->ifname, iface_stat_procdir); -+ if (IS_ERR_OR_NULL(proc_entry)) { -+ pr_err("qtaguid: iface_stat: create_proc(): alloc failed.\n"); -+ kfree(isw); -+ return; -+ } -+ -+ new_iface->proc_ptr = proc_entry; -+ -+ create_proc_read_entry("tx_bytes", proc_iface_perms, proc_entry, -+ read_proc_u64, -+ &new_iface->totals_via_dev[IFS_TX].bytes); -+ create_proc_read_entry("rx_bytes", proc_iface_perms, proc_entry, -+ read_proc_u64, -+ &new_iface->totals_via_dev[IFS_RX].bytes); -+ create_proc_read_entry("tx_packets", proc_iface_perms, proc_entry, -+ read_proc_u64, -+ &new_iface->totals_via_dev[IFS_TX].packets); -+ create_proc_read_entry("rx_packets", proc_iface_perms, proc_entry, -+ read_proc_u64, -+ &new_iface->totals_via_dev[IFS_RX].packets); -+ create_proc_read_entry("active", proc_iface_perms, proc_entry, -+ read_proc_bool, &new_iface->active); -+ -+ IF_DEBUG("qtaguid: iface_stat: create_proc(): done " -+ "entry=%p dev=%s\n", new_iface, new_iface->ifname); -+ kfree(isw); -+} -+ -+/* -+ * Will set the entry's active state, and -+ * update the net_dev accordingly also. -+ */ -+static void _iface_stat_set_active(struct iface_stat *entry, -+ struct net_device *net_dev, -+ bool activate) -+{ -+ if (activate) { -+ entry->net_dev = net_dev; -+ entry->active = true; -+ IF_DEBUG("qtaguid: %s(%s): " -+ "enable tracking. rfcnt=%d\n", __func__, -+ entry->ifname, -+ percpu_read(*net_dev->pcpu_refcnt)); -+ } else { -+ entry->active = false; -+ entry->net_dev = NULL; -+ IF_DEBUG("qtaguid: %s(%s): " -+ "disable tracking. rfcnt=%d\n", __func__, -+ entry->ifname, -+ percpu_read(*net_dev->pcpu_refcnt)); -+ -+ } -+} -+ -+/* Caller must hold iface_stat_list_lock */ -+static struct iface_stat *iface_alloc(struct net_device *net_dev) -+{ -+ struct iface_stat *new_iface; -+ struct iface_stat_work *isw; -+ -+ new_iface = kzalloc(sizeof(*new_iface), GFP_ATOMIC); -+ if (new_iface == NULL) { -+ pr_err("qtaguid: iface_stat: create(%s): " -+ "iface_stat alloc failed\n", net_dev->name); -+ return NULL; -+ } -+ new_iface->ifname = kstrdup(net_dev->name, GFP_ATOMIC); -+ if (new_iface->ifname == NULL) { -+ pr_err("qtaguid: iface_stat: create(%s): " -+ "ifname alloc failed\n", net_dev->name); -+ kfree(new_iface); -+ return NULL; -+ } -+ spin_lock_init(&new_iface->tag_stat_list_lock); -+ new_iface->tag_stat_tree = RB_ROOT; -+ _iface_stat_set_active(new_iface, net_dev, true); -+ -+ /* -+ * ipv6 notifier chains are atomic :( -+ * No create_proc_read_entry() for you! -+ */ -+ isw = kmalloc(sizeof(*isw), GFP_ATOMIC); -+ if (!isw) { -+ pr_err("qtaguid: iface_stat: create(%s): " -+ "work alloc failed\n", new_iface->ifname); -+ _iface_stat_set_active(new_iface, net_dev, false); -+ kfree(new_iface->ifname); -+ kfree(new_iface); -+ return NULL; -+ } -+ isw->iface_entry = new_iface; -+ INIT_WORK(&isw->iface_work, iface_create_proc_worker); -+ schedule_work(&isw->iface_work); -+ list_add(&new_iface->list, &iface_stat_list); -+ return new_iface; -+} -+ -+static void iface_check_stats_reset_and_adjust(struct net_device *net_dev, -+ struct iface_stat *iface) -+{ -+ struct rtnl_link_stats64 dev_stats, *stats; -+ bool stats_rewound; -+ -+ stats = dev_get_stats(net_dev, &dev_stats); -+ /* No empty packets */ -+ stats_rewound = -+ (stats->rx_bytes < iface->last_known[IFS_RX].bytes) -+ || (stats->tx_bytes < iface->last_known[IFS_TX].bytes); -+ -+ IF_DEBUG("qtaguid: %s(%s): iface=%p netdev=%p " -+ "bytes rx/tx=%llu/%llu " -+ "active=%d last_known=%d " -+ "stats_rewound=%d\n", __func__, -+ net_dev ? net_dev->name : "?", -+ iface, net_dev, -+ stats->rx_bytes, stats->tx_bytes, -+ iface->active, iface->last_known_valid, stats_rewound); -+ -+ if (iface->active && iface->last_known_valid && stats_rewound) { -+ pr_warn_once("qtaguid: iface_stat: %s(%s): " -+ "iface reset its stats unexpectedly\n", __func__, -+ net_dev->name); -+ -+ iface->totals_via_dev[IFS_TX].bytes += -+ iface->last_known[IFS_TX].bytes; -+ iface->totals_via_dev[IFS_TX].packets += -+ iface->last_known[IFS_TX].packets; -+ iface->totals_via_dev[IFS_RX].bytes += -+ iface->last_known[IFS_RX].bytes; -+ iface->totals_via_dev[IFS_RX].packets += -+ iface->last_known[IFS_RX].packets; -+ iface->last_known_valid = false; -+ IF_DEBUG("qtaguid: %s(%s): iface=%p " -+ "used last known bytes rx/tx=%llu/%llu\n", __func__, -+ iface->ifname, iface, iface->last_known[IFS_RX].bytes, -+ iface->last_known[IFS_TX].bytes); -+ } -+} -+ -+/* -+ * Create a new entry for tracking the specified interface. -+ * Do nothing if the entry already exists. -+ * Called when an interface is configured with a valid IP address. -+ */ -+static void iface_stat_create(struct net_device *net_dev, -+ struct in_ifaddr *ifa) -+{ -+ struct in_device *in_dev = NULL; -+ const char *ifname; -+ struct iface_stat *entry; -+ __be32 ipaddr = 0; -+ struct iface_stat *new_iface; -+ -+ IF_DEBUG("qtaguid: iface_stat: create(%s): ifa=%p netdev=%p\n", -+ net_dev ? net_dev->name : "?", -+ ifa, net_dev); -+ if (!net_dev) { -+ pr_err("qtaguid: iface_stat: create(): no net dev\n"); -+ return; -+ } -+ -+ ifname = net_dev->name; -+ if (!ifa) { -+ in_dev = in_dev_get(net_dev); -+ if (!in_dev) { -+ pr_err("qtaguid: iface_stat: create(%s): no inet dev\n", -+ ifname); -+ return; -+ } -+ IF_DEBUG("qtaguid: iface_stat: create(%s): in_dev=%p\n", -+ ifname, in_dev); -+ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { -+ IF_DEBUG("qtaguid: iface_stat: create(%s): " -+ "ifa=%p ifa_label=%s\n", -+ ifname, ifa, -+ ifa->ifa_label ? ifa->ifa_label : "(null)"); -+ if (ifa->ifa_label && !strcmp(ifname, ifa->ifa_label)) -+ break; -+ } -+ } -+ -+ if (!ifa) { -+ IF_DEBUG("qtaguid: iface_stat: create(%s): no matching IP\n", -+ ifname); -+ goto done_put; -+ } -+ ipaddr = ifa->ifa_local; -+ -+ spin_lock_bh(&iface_stat_list_lock); -+ entry = get_iface_entry(ifname); -+ if (entry != NULL) { -+ IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n", -+ ifname, entry); -+ iface_check_stats_reset_and_adjust(net_dev, entry); -+ _iface_stat_set_active(entry, net_dev, true); -+ IF_DEBUG("qtaguid: %s(%s): " -+ "tracking now %d on ip=%pI4\n", __func__, -+ entry->ifname, true, &ipaddr); -+ goto done_unlock_put; -+ } -+ -+ new_iface = iface_alloc(net_dev); -+ IF_DEBUG("qtaguid: iface_stat: create(%s): done " -+ "entry=%p ip=%pI4\n", ifname, new_iface, &ipaddr); -+done_unlock_put: -+ spin_unlock_bh(&iface_stat_list_lock); -+done_put: -+ if (in_dev) -+ in_dev_put(in_dev); -+} -+ -+static void iface_stat_create_ipv6(struct net_device *net_dev, -+ struct inet6_ifaddr *ifa) -+{ -+ struct in_device *in_dev; -+ const char *ifname; -+ struct iface_stat *entry; -+ struct iface_stat *new_iface; -+ int addr_type; -+ -+ IF_DEBUG("qtaguid: iface_stat: create6(): ifa=%p netdev=%p->name=%s\n", -+ ifa, net_dev, net_dev ? net_dev->name : ""); -+ if (!net_dev) { -+ pr_err("qtaguid: iface_stat: create6(): no net dev!\n"); -+ return; -+ } -+ ifname = net_dev->name; -+ -+ in_dev = in_dev_get(net_dev); -+ if (!in_dev) { -+ pr_err("qtaguid: iface_stat: create6(%s): no inet dev\n", -+ ifname); -+ return; -+ } -+ -+ IF_DEBUG("qtaguid: iface_stat: create6(%s): in_dev=%p\n", -+ ifname, in_dev); -+ -+ if (!ifa) { -+ IF_DEBUG("qtaguid: iface_stat: create6(%s): no matching IP\n", -+ ifname); -+ goto done_put; -+ } -+ addr_type = ipv6_addr_type(&ifa->addr); -+ -+ spin_lock_bh(&iface_stat_list_lock); -+ entry = get_iface_entry(ifname); -+ if (entry != NULL) { -+ IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__, -+ ifname, entry); -+ iface_check_stats_reset_and_adjust(net_dev, entry); -+ _iface_stat_set_active(entry, net_dev, true); -+ IF_DEBUG("qtaguid: %s(%s): " -+ "tracking now %d on ip=%pI6c\n", __func__, -+ entry->ifname, true, &ifa->addr); -+ goto done_unlock_put; -+ } -+ -+ new_iface = iface_alloc(net_dev); -+ IF_DEBUG("qtaguid: iface_stat: create6(%s): done " -+ "entry=%p ip=%pI6c\n", ifname, new_iface, &ifa->addr); -+ -+done_unlock_put: -+ spin_unlock_bh(&iface_stat_list_lock); -+done_put: -+ in_dev_put(in_dev); -+} -+ -+static struct sock_tag *get_sock_stat_nl(const struct sock *sk) -+{ -+ MT_DEBUG("qtaguid: get_sock_stat_nl(sk=%p)\n", sk); -+ return sock_tag_tree_search(&sock_tag_tree, sk); -+} -+ -+static struct sock_tag *get_sock_stat(const struct sock *sk) -+{ -+ struct sock_tag *sock_tag_entry; -+ MT_DEBUG("qtaguid: get_sock_stat(sk=%p)\n", sk); -+ if (!sk) -+ return NULL; -+ spin_lock_bh(&sock_tag_list_lock); -+ sock_tag_entry = get_sock_stat_nl(sk); -+ spin_unlock_bh(&sock_tag_list_lock); -+ return sock_tag_entry; -+} -+ -+static int ipx_proto(const struct sk_buff *skb, -+ struct xt_action_param *par) -+{ -+ int thoff, tproto; -+ -+ switch (par->family) { -+ case NFPROTO_IPV6: -+ tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); -+ if (tproto < 0) -+ MT_DEBUG("%s(): transport header not found in ipv6" -+ " skb=%p\n", __func__, skb); -+ break; -+ case NFPROTO_IPV4: -+ tproto = ip_hdr(skb)->protocol; -+ break; -+ default: -+ tproto = IPPROTO_RAW; -+ } -+ return tproto; -+} -+ -+static void -+data_counters_update(struct data_counters *dc, int set, -+ enum ifs_tx_rx direction, int proto, int bytes) -+{ -+ switch (proto) { -+ case IPPROTO_TCP: -+ dc_add_byte_packets(dc, set, direction, IFS_TCP, bytes, 1); -+ break; -+ case IPPROTO_UDP: -+ dc_add_byte_packets(dc, set, direction, IFS_UDP, bytes, 1); -+ break; -+ case IPPROTO_IP: -+ default: -+ dc_add_byte_packets(dc, set, direction, IFS_PROTO_OTHER, bytes, -+ 1); -+ break; -+ } -+} -+ -+/* -+ * Update stats for the specified interface. Do nothing if the entry -+ * does not exist (when a device was never configured with an IP address). -+ * Called when an device is being unregistered. -+ */ -+static void iface_stat_update(struct net_device *net_dev, bool stash_only) -+{ -+ struct rtnl_link_stats64 dev_stats, *stats; -+ struct iface_stat *entry; -+ -+ stats = dev_get_stats(net_dev, &dev_stats); -+ spin_lock_bh(&iface_stat_list_lock); -+ entry = get_iface_entry(net_dev->name); -+ if (entry == NULL) { -+ IF_DEBUG("qtaguid: iface_stat: update(%s): not tracked\n", -+ net_dev->name); -+ spin_unlock_bh(&iface_stat_list_lock); -+ return; -+ } -+ -+ IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__, -+ net_dev->name, entry); -+ if (!entry->active) { -+ IF_DEBUG("qtaguid: %s(%s): already disabled\n", __func__, -+ net_dev->name); -+ spin_unlock_bh(&iface_stat_list_lock); -+ return; -+ } -+ -+ if (stash_only) { -+ entry->last_known[IFS_TX].bytes = stats->tx_bytes; -+ entry->last_known[IFS_TX].packets = stats->tx_packets; -+ entry->last_known[IFS_RX].bytes = stats->rx_bytes; -+ entry->last_known[IFS_RX].packets = stats->rx_packets; -+ entry->last_known_valid = true; -+ IF_DEBUG("qtaguid: %s(%s): " -+ "dev stats stashed rx/tx=%llu/%llu\n", __func__, -+ net_dev->name, stats->rx_bytes, stats->tx_bytes); -+ spin_unlock_bh(&iface_stat_list_lock); -+ return; -+ } -+ entry->totals_via_dev[IFS_TX].bytes += stats->tx_bytes; -+ entry->totals_via_dev[IFS_TX].packets += stats->tx_packets; -+ entry->totals_via_dev[IFS_RX].bytes += stats->rx_bytes; -+ entry->totals_via_dev[IFS_RX].packets += stats->rx_packets; -+ /* We don't need the last_known[] anymore */ -+ entry->last_known_valid = false; -+ _iface_stat_set_active(entry, net_dev, false); -+ IF_DEBUG("qtaguid: %s(%s): " -+ "disable tracking. rx/tx=%llu/%llu\n", __func__, -+ net_dev->name, stats->rx_bytes, stats->tx_bytes); -+ spin_unlock_bh(&iface_stat_list_lock); -+} -+ -+/* -+ * Update stats for the specified interface from the skb. -+ * Do nothing if the entry -+ * does not exist (when a device was never configured with an IP address). -+ * Called on each sk. -+ */ -+static void iface_stat_update_from_skb(const struct sk_buff *skb, -+ struct xt_action_param *par) -+{ -+ struct iface_stat *entry; -+ const struct net_device *el_dev; -+ enum ifs_tx_rx direction = par->in ? IFS_RX : IFS_TX; -+ int bytes = skb->len; -+ int proto; -+ -+ if (!skb->dev) { -+ MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum); -+ el_dev = par->in ? : par->out; -+ } else { -+ const struct net_device *other_dev; -+ el_dev = skb->dev; -+ other_dev = par->in ? : par->out; -+ if (el_dev != other_dev) { -+ MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs " -+ "par->(in/out)=%p %s\n", -+ par->hooknum, el_dev, el_dev->name, other_dev, -+ other_dev->name); -+ } -+ } -+ -+ if (unlikely(!el_dev)) { -+ pr_err("qtaguid[%d]: %s(): no par->in/out?!!\n", -+ par->hooknum, __func__); -+ BUG(); -+ } else if (unlikely(!el_dev->name)) { -+ pr_err("qtaguid[%d]: %s(): no dev->name?!!\n", -+ par->hooknum, __func__); -+ BUG(); -+ } else { -+ proto = ipx_proto(skb, par); -+ MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n", -+ par->hooknum, el_dev->name, el_dev->type, -+ par->family, proto); -+ } -+ -+ spin_lock_bh(&iface_stat_list_lock); -+ entry = get_iface_entry(el_dev->name); -+ if (entry == NULL) { -+ IF_DEBUG("qtaguid: iface_stat: %s(%s): not tracked\n", -+ __func__, el_dev->name); -+ spin_unlock_bh(&iface_stat_list_lock); -+ return; -+ } -+ -+ IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__, -+ el_dev->name, entry); -+ -+ data_counters_update(&entry->totals_via_skb, 0, direction, proto, -+ bytes); -+ spin_unlock_bh(&iface_stat_list_lock); -+} -+ -+static void tag_stat_update(struct tag_stat *tag_entry, -+ enum ifs_tx_rx direction, int proto, int bytes) -+{ -+ int active_set; -+ active_set = get_active_counter_set(tag_entry->tn.tag); -+ MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%u) set=%d " -+ "dir=%d proto=%d bytes=%d)\n", -+ tag_entry->tn.tag, get_uid_from_tag(tag_entry->tn.tag), -+ active_set, direction, proto, bytes); -+ data_counters_update(&tag_entry->counters, active_set, direction, -+ proto, bytes); -+ if (tag_entry->parent_counters) -+ data_counters_update(tag_entry->parent_counters, active_set, -+ direction, proto, bytes); -+} -+ -+/* -+ * Create a new entry for tracking the specified {acct_tag,uid_tag} within -+ * the interface. -+ * iface_entry->tag_stat_list_lock should be held. -+ */ -+static struct tag_stat *create_if_tag_stat(struct iface_stat *iface_entry, -+ tag_t tag) -+{ -+ struct tag_stat *new_tag_stat_entry = NULL; -+ IF_DEBUG("qtaguid: iface_stat: %s(): ife=%p tag=0x%llx" -+ " (uid=%u)\n", __func__, -+ iface_entry, tag, get_uid_from_tag(tag)); -+ new_tag_stat_entry = kzalloc(sizeof(*new_tag_stat_entry), GFP_ATOMIC); -+ if (!new_tag_stat_entry) { -+ pr_err("qtaguid: iface_stat: tag stat alloc failed\n"); -+ goto done; -+ } -+ new_tag_stat_entry->tn.tag = tag; -+ tag_stat_tree_insert(new_tag_stat_entry, &iface_entry->tag_stat_tree); -+done: -+ return new_tag_stat_entry; -+} -+ -+static void if_tag_stat_update(const char *ifname, uid_t uid, -+ const struct sock *sk, enum ifs_tx_rx direction, -+ int proto, int bytes) -+{ -+ struct tag_stat *tag_stat_entry; -+ tag_t tag, acct_tag; -+ tag_t uid_tag; -+ struct data_counters *uid_tag_counters; -+ struct sock_tag *sock_tag_entry; -+ struct iface_stat *iface_entry; -+ struct tag_stat *new_tag_stat = NULL; -+ MT_DEBUG("qtaguid: if_tag_stat_update(ifname=%s " -+ "uid=%u sk=%p dir=%d proto=%d bytes=%d)\n", -+ ifname, uid, sk, direction, proto, bytes); -+ -+ -+ iface_entry = get_iface_entry(ifname); -+ if (!iface_entry) { -+ pr_err("qtaguid: iface_stat: stat_update() %s not found\n", -+ ifname); -+ return; -+ } -+ /* It is ok to process data when an iface_entry is inactive */ -+ -+ MT_DEBUG("qtaguid: iface_stat: stat_update() dev=%s entry=%p\n", -+ ifname, iface_entry); -+ -+ /* -+ * Look for a tagged sock. -+ * It will have an acct_uid. -+ */ -+ sock_tag_entry = get_sock_stat(sk); -+ if (sock_tag_entry) { -+ tag = sock_tag_entry->tag; -+ acct_tag = get_atag_from_tag(tag); -+ uid_tag = get_utag_from_tag(tag); -+ } else { -+ acct_tag = make_atag_from_value(0); -+ tag = combine_atag_with_uid(acct_tag, uid); -+ uid_tag = make_tag_from_uid(uid); -+ } -+ MT_DEBUG("qtaguid: iface_stat: stat_update(): " -+ " looking for tag=0x%llx (uid=%u) in ife=%p\n", -+ tag, get_uid_from_tag(tag), iface_entry); -+ /* Loop over tag list under this interface for {acct_tag,uid_tag} */ -+ spin_lock_bh(&iface_entry->tag_stat_list_lock); -+ -+ tag_stat_entry = tag_stat_tree_search(&iface_entry->tag_stat_tree, -+ tag); -+ if (tag_stat_entry) { -+ /* -+ * Updating the {acct_tag, uid_tag} entry handles both stats: -+ * {0, uid_tag} will also get updated. -+ */ -+ tag_stat_update(tag_stat_entry, direction, proto, bytes); -+ spin_unlock_bh(&iface_entry->tag_stat_list_lock); -+ return; -+ } -+ -+ /* Loop over tag list under this interface for {0,uid_tag} */ -+ tag_stat_entry = tag_stat_tree_search(&iface_entry->tag_stat_tree, -+ uid_tag); -+ if (!tag_stat_entry) { -+ /* Here: the base uid_tag did not exist */ -+ /* -+ * No parent counters. So -+ * - No {0, uid_tag} stats and no {acc_tag, uid_tag} stats. -+ */ -+ new_tag_stat = create_if_tag_stat(iface_entry, uid_tag); -+ if (!new_tag_stat) -+ goto unlock; -+ uid_tag_counters = &new_tag_stat->counters; -+ } else { -+ uid_tag_counters = &tag_stat_entry->counters; -+ } -+ -+ if (acct_tag) { -+ /* Create the child {acct_tag, uid_tag} and hook up parent. */ -+ new_tag_stat = create_if_tag_stat(iface_entry, tag); -+ if (!new_tag_stat) -+ goto unlock; -+ new_tag_stat->parent_counters = uid_tag_counters; -+ } else { -+ /* -+ * For new_tag_stat to be still NULL here would require: -+ * {0, uid_tag} exists -+ * and {acct_tag, uid_tag} doesn't exist -+ * AND acct_tag == 0. -+ * Impossible. This reassures us that new_tag_stat -+ * below will always be assigned. -+ */ -+ BUG_ON(!new_tag_stat); -+ } -+ tag_stat_update(new_tag_stat, direction, proto, bytes); -+unlock: -+ spin_unlock_bh(&iface_entry->tag_stat_list_lock); -+} -+ -+static int iface_netdev_event_handler(struct notifier_block *nb, -+ unsigned long event, void *ptr) { -+ struct net_device *dev = ptr; -+ -+ if (unlikely(module_passive)) -+ return NOTIFY_DONE; -+ -+ IF_DEBUG("qtaguid: iface_stat: netdev_event(): " -+ "ev=0x%lx/%s netdev=%p->name=%s\n", -+ event, netdev_evt_str(event), dev, dev ? dev->name : ""); -+ -+ switch (event) { -+ case NETDEV_UP: -+ iface_stat_create(dev, NULL); -+ atomic64_inc(&qtu_events.iface_events); -+ break; -+ case NETDEV_DOWN: -+ case NETDEV_UNREGISTER: -+ iface_stat_update(dev, event == NETDEV_DOWN); -+ atomic64_inc(&qtu_events.iface_events); -+ break; -+ } -+ return NOTIFY_DONE; -+} -+ -+static int iface_inet6addr_event_handler(struct notifier_block *nb, -+ unsigned long event, void *ptr) -+{ -+ struct inet6_ifaddr *ifa = ptr; -+ struct net_device *dev; -+ -+ if (unlikely(module_passive)) -+ return NOTIFY_DONE; -+ -+ IF_DEBUG("qtaguid: iface_stat: inet6addr_event(): " -+ "ev=0x%lx/%s ifa=%p\n", -+ event, netdev_evt_str(event), ifa); -+ -+ switch (event) { -+ case NETDEV_UP: -+ BUG_ON(!ifa || !ifa->idev); -+ dev = (struct net_device *)ifa->idev->dev; -+ iface_stat_create_ipv6(dev, ifa); -+ atomic64_inc(&qtu_events.iface_events); -+ break; -+ case NETDEV_DOWN: -+ case NETDEV_UNREGISTER: -+ BUG_ON(!ifa || !ifa->idev); -+ dev = (struct net_device *)ifa->idev->dev; -+ iface_stat_update(dev, event == NETDEV_DOWN); -+ atomic64_inc(&qtu_events.iface_events); -+ break; -+ } -+ return NOTIFY_DONE; -+} -+ -+static int iface_inetaddr_event_handler(struct notifier_block *nb, -+ unsigned long event, void *ptr) -+{ -+ struct in_ifaddr *ifa = ptr; -+ struct net_device *dev; -+ -+ if (unlikely(module_passive)) -+ return NOTIFY_DONE; -+ -+ IF_DEBUG("qtaguid: iface_stat: inetaddr_event(): " -+ "ev=0x%lx/%s ifa=%p\n", -+ event, netdev_evt_str(event), ifa); -+ -+ switch (event) { -+ case NETDEV_UP: -+ BUG_ON(!ifa || !ifa->ifa_dev); -+ dev = ifa->ifa_dev->dev; -+ iface_stat_create(dev, ifa); -+ atomic64_inc(&qtu_events.iface_events); -+ break; -+ case NETDEV_DOWN: -+ case NETDEV_UNREGISTER: -+ BUG_ON(!ifa || !ifa->ifa_dev); -+ dev = ifa->ifa_dev->dev; -+ iface_stat_update(dev, event == NETDEV_DOWN); -+ atomic64_inc(&qtu_events.iface_events); -+ break; -+ } -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block iface_netdev_notifier_blk = { -+ .notifier_call = iface_netdev_event_handler, -+}; -+ -+static struct notifier_block iface_inetaddr_notifier_blk = { -+ .notifier_call = iface_inetaddr_event_handler, -+}; -+ -+static struct notifier_block iface_inet6addr_notifier_blk = { -+ .notifier_call = iface_inet6addr_event_handler, -+}; -+ -+static int __init iface_stat_init(struct proc_dir_entry *parent_procdir) -+{ -+ int err; -+ -+ iface_stat_procdir = proc_mkdir(iface_stat_procdirname, parent_procdir); -+ if (!iface_stat_procdir) { -+ pr_err("qtaguid: iface_stat: init failed to create proc entry\n"); -+ err = -1; -+ goto err; -+ } -+ -+ iface_stat_all_procfile = create_proc_entry(iface_stat_all_procfilename, -+ proc_iface_perms, -+ parent_procdir); -+ if (!iface_stat_all_procfile) { -+ pr_err("qtaguid: iface_stat: init " -+ " failed to create stat_old proc entry\n"); -+ err = -1; -+ goto err_zap_entry; -+ } -+ iface_stat_all_procfile->read_proc = iface_stat_fmt_proc_read; -+ iface_stat_all_procfile->data = (void *)1; /* fmt1 */ -+ -+ iface_stat_fmt_procfile = create_proc_entry(iface_stat_fmt_procfilename, -+ proc_iface_perms, -+ parent_procdir); -+ if (!iface_stat_fmt_procfile) { -+ pr_err("qtaguid: iface_stat: init " -+ " failed to create stat_all proc entry\n"); -+ err = -1; -+ goto err_zap_all_stats_entry; -+ } -+ iface_stat_fmt_procfile->read_proc = iface_stat_fmt_proc_read; -+ iface_stat_fmt_procfile->data = (void *)2; /* fmt2 */ -+ -+ -+ err = register_netdevice_notifier(&iface_netdev_notifier_blk); -+ if (err) { -+ pr_err("qtaguid: iface_stat: init " -+ "failed to register dev event handler\n"); -+ goto err_zap_all_stats_entries; -+ } -+ err = register_inetaddr_notifier(&iface_inetaddr_notifier_blk); -+ if (err) { -+ pr_err("qtaguid: iface_stat: init " -+ "failed to register ipv4 dev event handler\n"); -+ goto err_unreg_nd; -+ } -+ -+ err = register_inet6addr_notifier(&iface_inet6addr_notifier_blk); -+ if (err) { -+ pr_err("qtaguid: iface_stat: init " -+ "failed to register ipv6 dev event handler\n"); -+ goto err_unreg_ip4_addr; -+ } -+ return 0; -+ -+err_unreg_ip4_addr: -+ unregister_inetaddr_notifier(&iface_inetaddr_notifier_blk); -+err_unreg_nd: -+ unregister_netdevice_notifier(&iface_netdev_notifier_blk); -+err_zap_all_stats_entries: -+ remove_proc_entry(iface_stat_fmt_procfilename, parent_procdir); -+err_zap_all_stats_entry: -+ remove_proc_entry(iface_stat_all_procfilename, parent_procdir); -+err_zap_entry: -+ remove_proc_entry(iface_stat_procdirname, parent_procdir); -+err: -+ return err; -+} -+ -+static struct sock *qtaguid_find_sk(const struct sk_buff *skb, -+ struct xt_action_param *par) -+{ -+ struct sock *sk; -+ unsigned int hook_mask = (1 << par->hooknum); -+ -+ MT_DEBUG("qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb, -+ par->hooknum, par->family); -+ -+ /* -+ * Let's not abuse the the xt_socket_get*_sk(), or else it will -+ * return garbage SKs. -+ */ -+ if (!(hook_mask & XT_SOCKET_SUPPORTED_HOOKS)) -+ return NULL; -+ -+ switch (par->family) { -+ case NFPROTO_IPV6: -+ sk = xt_socket_get6_sk(skb, par); -+ break; -+ case NFPROTO_IPV4: -+ sk = xt_socket_get4_sk(skb, par); -+ break; -+ default: -+ return NULL; -+ } -+ -+ /* -+ * Seems to be issues on the file ptr for TCP_TIME_WAIT SKs. -+ * http://kerneltrap.org/mailarchive/linux-netdev/2010/10/21/6287959 -+ * Not fixed in 3.0-r3 :( -+ */ -+ if (sk) { -+ MT_DEBUG("qtaguid: %p->sk_proto=%u " -+ "->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state); -+ if (sk->sk_state == TCP_TIME_WAIT) { -+ xt_socket_put_sk(sk); -+ sk = NULL; -+ } -+ } -+ return sk; -+} -+ -+static void account_for_uid(const struct sk_buff *skb, -+ const struct sock *alternate_sk, uid_t uid, -+ struct xt_action_param *par) -+{ -+ const struct net_device *el_dev; -+ -+ if (!skb->dev) { -+ MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum); -+ el_dev = par->in ? : par->out; -+ } else { -+ const struct net_device *other_dev; -+ el_dev = skb->dev; -+ other_dev = par->in ? : par->out; -+ if (el_dev != other_dev) { -+ MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs " -+ "par->(in/out)=%p %s\n", -+ par->hooknum, el_dev, el_dev->name, other_dev, -+ other_dev->name); -+ } -+ } -+ -+ if (unlikely(!el_dev)) { -+ pr_info("qtaguid[%d]: no par->in/out?!!\n", par->hooknum); -+ } else if (unlikely(!el_dev->name)) { -+ pr_info("qtaguid[%d]: no dev->name?!!\n", par->hooknum); -+ } else { -+ int proto = ipx_proto(skb, par); -+ MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n", -+ par->hooknum, el_dev->name, el_dev->type, -+ par->family, proto); -+ -+ if_tag_stat_update(el_dev->name, uid, -+ skb->sk ? skb->sk : alternate_sk, -+ par->in ? IFS_RX : IFS_TX, -+ proto, skb->len); -+ } -+} -+ -+static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par) -+{ -+ const struct xt_qtaguid_match_info *info = par->matchinfo; -+ const struct file *filp; -+ bool got_sock = false; -+ struct sock *sk; -+ uid_t sock_uid; -+ bool res; -+ -+ if (unlikely(module_passive)) -+ return (info->match ^ info->invert) == 0; -+ -+ MT_DEBUG("qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n", -+ par->hooknum, skb, par->in, par->out, par->family); -+ -+ atomic64_inc(&qtu_events.match_calls); -+ if (skb == NULL) { -+ res = (info->match ^ info->invert) == 0; -+ goto ret_res; -+ } -+ -+ switch (par->hooknum) { -+ case NF_INET_PRE_ROUTING: -+ case NF_INET_POST_ROUTING: -+ atomic64_inc(&qtu_events.match_calls_prepost); -+ iface_stat_update_from_skb(skb, par); -+ /* -+ * We are done in pre/post. The skb will get processed -+ * further alter. -+ */ -+ res = (info->match ^ info->invert); -+ goto ret_res; -+ break; -+ /* default: Fall through and do UID releated work */ -+ } -+ -+ sk = skb->sk; -+ if (sk == NULL) { -+ /* -+ * A missing sk->sk_socket happens when packets are in-flight -+ * and the matching socket is already closed and gone. -+ */ -+ sk = qtaguid_find_sk(skb, par); -+ /* -+ * If we got the socket from the find_sk(), we will need to put -+ * it back, as nf_tproxy_get_sock_v4() got it. -+ */ -+ got_sock = sk; -+ if (sk) -+ atomic64_inc(&qtu_events.match_found_sk_in_ct); -+ else -+ atomic64_inc(&qtu_events.match_found_no_sk_in_ct); -+ } else { -+ atomic64_inc(&qtu_events.match_found_sk); -+ } -+ MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d fam=%d proto=%d\n", -+ par->hooknum, sk, got_sock, par->family, ipx_proto(skb, par)); -+ if (sk != NULL) { -+ MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n", -+ par->hooknum, sk, sk->sk_socket, -+ sk->sk_socket ? sk->sk_socket->file : (void *)-1LL); -+ filp = sk->sk_socket ? sk->sk_socket->file : NULL; -+ MT_DEBUG("qtaguid[%d]: filp...uid=%u\n", -+ par->hooknum, filp ? filp->f_cred->fsuid : -1); -+ } -+ -+ if (sk == NULL || sk->sk_socket == NULL) { -+ /* -+ * Here, the qtaguid_find_sk() using connection tracking -+ * couldn't find the owner, so for now we just count them -+ * against the system. -+ */ -+ /* -+ * TODO: unhack how to force just accounting. -+ * For now we only do iface stats when the uid-owner is not -+ * requested. -+ */ -+ if (!(info->match & XT_QTAGUID_UID)) -+ account_for_uid(skb, sk, 0, par); -+ MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n", -+ par->hooknum, -+ sk ? sk->sk_socket : NULL); -+ res = (info->match ^ info->invert) == 0; -+ atomic64_inc(&qtu_events.match_no_sk); -+ goto put_sock_ret_res; -+ } else if (info->match & info->invert & XT_QTAGUID_SOCKET) { -+ res = false; -+ goto put_sock_ret_res; -+ } -+ filp = sk->sk_socket->file; -+ if (filp == NULL) { -+ MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum); -+ account_for_uid(skb, sk, 0, par); -+ res = ((info->match ^ info->invert) & -+ (XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0; -+ atomic64_inc(&qtu_events.match_no_sk_file); -+ goto put_sock_ret_res; -+ } -+ sock_uid = filp->f_cred->fsuid; -+ /* -+ * TODO: unhack how to force just accounting. -+ * For now we only do iface stats when the uid-owner is not requested -+ */ -+ if (!(info->match & XT_QTAGUID_UID)) -+ account_for_uid(skb, sk, sock_uid, par); -+ -+ /* -+ * The following two tests fail the match when: -+ * id not in range AND no inverted condition requested -+ * or id in range AND inverted condition requested -+ * Thus (!a && b) || (a && !b) == a ^ b -+ */ -+ if (info->match & XT_QTAGUID_UID) -+ if ((filp->f_cred->fsuid >= info->uid_min && -+ filp->f_cred->fsuid <= info->uid_max) ^ -+ !(info->invert & XT_QTAGUID_UID)) { -+ MT_DEBUG("qtaguid[%d]: leaving uid not matching\n", -+ par->hooknum); -+ res = false; -+ goto put_sock_ret_res; -+ } -+ if (info->match & XT_QTAGUID_GID) -+ if ((filp->f_cred->fsgid >= info->gid_min && -+ filp->f_cred->fsgid <= info->gid_max) ^ -+ !(info->invert & XT_QTAGUID_GID)) { -+ MT_DEBUG("qtaguid[%d]: leaving gid not matching\n", -+ par->hooknum); -+ res = false; -+ goto put_sock_ret_res; -+ } -+ -+ MT_DEBUG("qtaguid[%d]: leaving matched\n", par->hooknum); -+ res = true; -+ -+put_sock_ret_res: -+ if (got_sock) -+ xt_socket_put_sk(sk); -+ret_res: -+ MT_DEBUG("qtaguid[%d]: left %d\n", par->hooknum, res); -+ return res; -+} -+ -+#ifdef DDEBUG -+/* This function is not in xt_qtaguid_print.c because of locks visibility */ -+static void prdebug_full_state(int indent_level, const char *fmt, ...) -+{ -+ va_list args; -+ char *fmt_buff; -+ char *buff; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ fmt_buff = kasprintf(GFP_ATOMIC, -+ "qtaguid: %s(): %s {\n", __func__, fmt); -+ BUG_ON(!fmt_buff); -+ va_start(args, fmt); -+ buff = kvasprintf(GFP_ATOMIC, -+ fmt_buff, args); -+ BUG_ON(!buff); -+ pr_debug("%s", buff); -+ kfree(fmt_buff); -+ kfree(buff); -+ va_end(args); -+ -+ spin_lock_bh(&sock_tag_list_lock); -+ prdebug_sock_tag_tree(indent_level, &sock_tag_tree); -+ spin_unlock_bh(&sock_tag_list_lock); -+ -+ spin_lock_bh(&sock_tag_list_lock); -+ spin_lock_bh(&uid_tag_data_tree_lock); -+ prdebug_uid_tag_data_tree(indent_level, &uid_tag_data_tree); -+ prdebug_proc_qtu_data_tree(indent_level, &proc_qtu_data_tree); -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ spin_unlock_bh(&sock_tag_list_lock); -+ -+ spin_lock_bh(&iface_stat_list_lock); -+ prdebug_iface_stat_list(indent_level, &iface_stat_list); -+ spin_unlock_bh(&iface_stat_list_lock); -+ -+ pr_debug("qtaguid: %s(): }\n", __func__); -+} -+#else -+static void prdebug_full_state(int indent_level, const char *fmt, ...) {} -+#endif -+ -+/* -+ * Procfs reader to get all active socket tags using style "1)" as described in -+ * fs/proc/generic.c -+ */ -+static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned, -+ off_t items_to_skip, int char_count, int *eof, -+ void *data) -+{ -+ char *outp = page; -+ int len; -+ uid_t uid; -+ struct rb_node *node; -+ struct sock_tag *sock_tag_entry; -+ int item_index = 0; -+ int indent_level = 0; -+ long f_count; -+ -+ if (unlikely(module_passive)) { -+ *eof = 1; -+ return 0; -+ } -+ -+ if (*eof) -+ return 0; -+ -+ CT_DEBUG("qtaguid: proc ctrl pid=%u tgid=%u uid=%u " -+ "page=%p off=%ld char_count=%d *eof=%d\n", -+ current->pid, current->tgid, current_fsuid(), -+ page, items_to_skip, char_count, *eof); -+ -+ spin_lock_bh(&sock_tag_list_lock); -+ for (node = rb_first(&sock_tag_tree); -+ node; -+ node = rb_next(node)) { -+ if (item_index++ < items_to_skip) -+ continue; -+ sock_tag_entry = rb_entry(node, struct sock_tag, sock_node); -+ uid = get_uid_from_tag(sock_tag_entry->tag); -+ CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u) " -+ "pid=%u\n", -+ sock_tag_entry->sk, -+ sock_tag_entry->tag, -+ uid, -+ sock_tag_entry->pid -+ ); -+ f_count = atomic_long_read( -+ &sock_tag_entry->socket->file->f_count); -+ len = snprintf(outp, char_count, -+ "sock=%p tag=0x%llx (uid=%u) pid=%u " -+ "f_count=%lu\n", -+ sock_tag_entry->sk, -+ sock_tag_entry->tag, uid, -+ sock_tag_entry->pid, f_count); -+ if (len >= char_count) { -+ spin_unlock_bh(&sock_tag_list_lock); -+ *outp = '\0'; -+ return outp - page; -+ } -+ outp += len; -+ char_count -= len; -+ (*num_items_returned)++; -+ } -+ spin_unlock_bh(&sock_tag_list_lock); -+ -+ if (item_index++ >= items_to_skip) { -+ len = snprintf(outp, char_count, -+ "events: sockets_tagged=%llu " -+ "sockets_untagged=%llu " -+ "counter_set_changes=%llu " -+ "delete_cmds=%llu " -+ "iface_events=%llu " -+ "match_calls=%llu " -+ "match_calls_prepost=%llu " -+ "match_found_sk=%llu " -+ "match_found_sk_in_ct=%llu " -+ "match_found_no_sk_in_ct=%llu " -+ "match_no_sk=%llu " -+ "match_no_sk_file=%llu\n", -+ atomic64_read(&qtu_events.sockets_tagged), -+ atomic64_read(&qtu_events.sockets_untagged), -+ atomic64_read(&qtu_events.counter_set_changes), -+ atomic64_read(&qtu_events.delete_cmds), -+ atomic64_read(&qtu_events.iface_events), -+ atomic64_read(&qtu_events.match_calls), -+ atomic64_read(&qtu_events.match_calls_prepost), -+ atomic64_read(&qtu_events.match_found_sk), -+ atomic64_read(&qtu_events.match_found_sk_in_ct), -+ atomic64_read( -+ &qtu_events.match_found_no_sk_in_ct), -+ atomic64_read(&qtu_events.match_no_sk), -+ atomic64_read(&qtu_events.match_no_sk_file)); -+ if (len >= char_count) { -+ *outp = '\0'; -+ return outp - page; -+ } -+ outp += len; -+ char_count -= len; -+ (*num_items_returned)++; -+ } -+ -+ /* Count the following as part of the last item_index */ -+ if (item_index > items_to_skip) { -+ prdebug_full_state(indent_level, "proc ctrl"); -+ } -+ -+ *eof = 1; -+ return outp - page; -+} -+ -+/* -+ * Delete socket tags, and stat tags associated with a given -+ * accouting tag and uid. -+ */ -+static int ctrl_cmd_delete(const char *input) -+{ -+ char cmd; -+ uid_t uid; -+ uid_t entry_uid; -+ tag_t acct_tag; -+ tag_t tag; -+ int res, argc; -+ struct iface_stat *iface_entry; -+ struct rb_node *node; -+ struct sock_tag *st_entry; -+ struct rb_root st_to_free_tree = RB_ROOT; -+ struct tag_stat *ts_entry; -+ struct tag_counter_set *tcs_entry; -+ struct tag_ref *tr_entry; -+ struct uid_tag_data *utd_entry; -+ -+ argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid); -+ CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c " -+ "user_tag=0x%llx uid=%u\n", input, argc, cmd, -+ acct_tag, uid); -+ if (argc < 2) { -+ res = -EINVAL; -+ goto err; -+ } -+ if (!valid_atag(acct_tag)) { -+ pr_info("qtaguid: ctrl_delete(%s): invalid tag\n", input); -+ res = -EINVAL; -+ goto err; -+ } -+ if (argc < 3) { -+ uid = current_fsuid(); -+ } else if (!can_impersonate_uid(uid)) { -+ pr_info("qtaguid: ctrl_delete(%s): " -+ "insufficient priv from pid=%u tgid=%u uid=%u\n", -+ input, current->pid, current->tgid, current_fsuid()); -+ res = -EPERM; -+ goto err; -+ } -+ -+ tag = combine_atag_with_uid(acct_tag, uid); -+ CT_DEBUG("qtaguid: ctrl_delete(%s): " -+ "looking for tag=0x%llx (uid=%u)\n", -+ input, tag, uid); -+ -+ /* Delete socket tags */ -+ spin_lock_bh(&sock_tag_list_lock); -+ node = rb_first(&sock_tag_tree); -+ while (node) { -+ st_entry = rb_entry(node, struct sock_tag, sock_node); -+ entry_uid = get_uid_from_tag(st_entry->tag); -+ node = rb_next(node); -+ if (entry_uid != uid) -+ continue; -+ -+ CT_DEBUG("qtaguid: ctrl_delete(%s): st tag=0x%llx (uid=%u)\n", -+ input, st_entry->tag, entry_uid); -+ -+ if (!acct_tag || st_entry->tag == tag) { -+ rb_erase(&st_entry->sock_node, &sock_tag_tree); -+ /* Can't sockfd_put() within spinlock, do it later. */ -+ sock_tag_tree_insert(st_entry, &st_to_free_tree); -+ tr_entry = lookup_tag_ref(st_entry->tag, NULL); -+ BUG_ON(tr_entry->num_sock_tags <= 0); -+ tr_entry->num_sock_tags--; -+ /* -+ * TODO: remove if, and start failing. -+ * This is a hack to work around the fact that in some -+ * places we have "if (IS_ERR_OR_NULL(pqd_entry))" -+ * and are trying to work around apps -+ * that didn't open the /dev/xt_qtaguid. -+ */ -+ if (st_entry->list.next && st_entry->list.prev) -+ list_del(&st_entry->list); -+ } -+ } -+ spin_unlock_bh(&sock_tag_list_lock); -+ -+ sock_tag_tree_erase(&st_to_free_tree); -+ -+ /* Delete tag counter-sets */ -+ spin_lock_bh(&tag_counter_set_list_lock); -+ /* Counter sets are only on the uid tag, not full tag */ -+ tcs_entry = tag_counter_set_tree_search(&tag_counter_set_tree, tag); -+ if (tcs_entry) { -+ CT_DEBUG("qtaguid: ctrl_delete(%s): " -+ "erase tcs: tag=0x%llx (uid=%u) set=%d\n", -+ input, -+ tcs_entry->tn.tag, -+ get_uid_from_tag(tcs_entry->tn.tag), -+ tcs_entry->active_set); -+ rb_erase(&tcs_entry->tn.node, &tag_counter_set_tree); -+ kfree(tcs_entry); -+ } -+ spin_unlock_bh(&tag_counter_set_list_lock); -+ -+ /* -+ * If acct_tag is 0, then all entries belonging to uid are -+ * erased. -+ */ -+ spin_lock_bh(&iface_stat_list_lock); -+ list_for_each_entry(iface_entry, &iface_stat_list, list) { -+ spin_lock_bh(&iface_entry->tag_stat_list_lock); -+ node = rb_first(&iface_entry->tag_stat_tree); -+ while (node) { -+ ts_entry = rb_entry(node, struct tag_stat, tn.node); -+ entry_uid = get_uid_from_tag(ts_entry->tn.tag); -+ node = rb_next(node); -+ -+ CT_DEBUG("qtaguid: ctrl_delete(%s): " -+ "ts tag=0x%llx (uid=%u)\n", -+ input, ts_entry->tn.tag, entry_uid); -+ -+ if (entry_uid != uid) -+ continue; -+ if (!acct_tag || ts_entry->tn.tag == tag) { -+ CT_DEBUG("qtaguid: ctrl_delete(%s): " -+ "erase ts: %s 0x%llx %u\n", -+ input, iface_entry->ifname, -+ get_atag_from_tag(ts_entry->tn.tag), -+ entry_uid); -+ rb_erase(&ts_entry->tn.node, -+ &iface_entry->tag_stat_tree); -+ kfree(ts_entry); -+ } -+ } -+ spin_unlock_bh(&iface_entry->tag_stat_list_lock); -+ } -+ spin_unlock_bh(&iface_stat_list_lock); -+ -+ /* Cleanup the uid_tag_data */ -+ spin_lock_bh(&uid_tag_data_tree_lock); -+ node = rb_first(&uid_tag_data_tree); -+ while (node) { -+ utd_entry = rb_entry(node, struct uid_tag_data, node); -+ entry_uid = utd_entry->uid; -+ node = rb_next(node); -+ -+ CT_DEBUG("qtaguid: ctrl_delete(%s): " -+ "utd uid=%u\n", -+ input, entry_uid); -+ -+ if (entry_uid != uid) -+ continue; -+ /* -+ * Go over the tag_refs, and those that don't have -+ * sock_tags using them are freed. -+ */ -+ put_tag_ref_tree(tag, utd_entry); -+ put_utd_entry(utd_entry); -+ } -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ -+ atomic64_inc(&qtu_events.delete_cmds); -+ res = 0; -+ -+err: -+ return res; -+} -+ -+static int ctrl_cmd_counter_set(const char *input) -+{ -+ char cmd; -+ uid_t uid = 0; -+ tag_t tag; -+ int res, argc; -+ struct tag_counter_set *tcs; -+ int counter_set; -+ -+ argc = sscanf(input, "%c %d %u", &cmd, &counter_set, &uid); -+ CT_DEBUG("qtaguid: ctrl_counterset(%s): argc=%d cmd=%c " -+ "set=%d uid=%u\n", input, argc, cmd, -+ counter_set, uid); -+ if (argc != 3) { -+ res = -EINVAL; -+ goto err; -+ } -+ if (counter_set < 0 || counter_set >= IFS_MAX_COUNTER_SETS) { -+ pr_info("qtaguid: ctrl_counterset(%s): invalid counter_set range\n", -+ input); -+ res = -EINVAL; -+ goto err; -+ } -+ if (!can_manipulate_uids()) { -+ pr_info("qtaguid: ctrl_counterset(%s): " -+ "insufficient priv from pid=%u tgid=%u uid=%u\n", -+ input, current->pid, current->tgid, current_fsuid()); -+ res = -EPERM; -+ goto err; -+ } -+ -+ tag = make_tag_from_uid(uid); -+ spin_lock_bh(&tag_counter_set_list_lock); -+ tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag); -+ if (!tcs) { -+ tcs = kzalloc(sizeof(*tcs), GFP_ATOMIC); -+ if (!tcs) { -+ spin_unlock_bh(&tag_counter_set_list_lock); -+ pr_err("qtaguid: ctrl_counterset(%s): " -+ "failed to alloc counter set\n", -+ input); -+ res = -ENOMEM; -+ goto err; -+ } -+ tcs->tn.tag = tag; -+ tag_counter_set_tree_insert(tcs, &tag_counter_set_tree); -+ CT_DEBUG("qtaguid: ctrl_counterset(%s): added tcs tag=0x%llx " -+ "(uid=%u) set=%d\n", -+ input, tag, get_uid_from_tag(tag), counter_set); -+ } -+ tcs->active_set = counter_set; -+ spin_unlock_bh(&tag_counter_set_list_lock); -+ atomic64_inc(&qtu_events.counter_set_changes); -+ res = 0; -+ -+err: -+ return res; -+} -+ -+static int ctrl_cmd_tag(const char *input) -+{ -+ char cmd; -+ int sock_fd = 0; -+ uid_t uid = 0; -+ tag_t acct_tag = make_atag_from_value(0); -+ tag_t full_tag; -+ struct socket *el_socket; -+ int res, argc; -+ struct sock_tag *sock_tag_entry; -+ struct tag_ref *tag_ref_entry; -+ struct uid_tag_data *uid_tag_data_entry; -+ struct proc_qtu_data *pqd_entry; -+ -+ /* Unassigned args will get defaulted later. */ -+ argc = sscanf(input, "%c %d %llu %u", &cmd, &sock_fd, &acct_tag, &uid); -+ CT_DEBUG("qtaguid: ctrl_tag(%s): argc=%d cmd=%c sock_fd=%d " -+ "acct_tag=0x%llx uid=%u\n", input, argc, cmd, sock_fd, -+ acct_tag, uid); -+ if (argc < 2) { -+ res = -EINVAL; -+ goto err; -+ } -+ el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */ -+ if (!el_socket) { -+ pr_info("qtaguid: ctrl_tag(%s): failed to lookup" -+ " sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n", -+ input, sock_fd, res, current->pid, current->tgid, -+ current_fsuid()); -+ goto err; -+ } -+ CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%ld ->sk=%p\n", -+ input, atomic_long_read(&el_socket->file->f_count), -+ el_socket->sk); -+ if (argc < 3) { -+ acct_tag = make_atag_from_value(0); -+ } else if (!valid_atag(acct_tag)) { -+ pr_info("qtaguid: ctrl_tag(%s): invalid tag\n", input); -+ res = -EINVAL; -+ goto err_put; -+ } -+ CT_DEBUG("qtaguid: ctrl_tag(%s): " -+ "pid=%u tgid=%u uid=%u euid=%u fsuid=%u " -+ "ctrl.gid=%u in_group()=%d in_egroup()=%d\n", -+ input, current->pid, current->tgid, current_uid(), -+ current_euid(), current_fsuid(), -+ xt_qtaguid_ctrl_file->gid, -+ in_group_p(xt_qtaguid_ctrl_file->gid), -+ in_egroup_p(xt_qtaguid_ctrl_file->gid)); -+ if (argc < 4) { -+ uid = current_fsuid(); -+ } else if (!can_impersonate_uid(uid)) { -+ pr_info("qtaguid: ctrl_tag(%s): " -+ "insufficient priv from pid=%u tgid=%u uid=%u\n", -+ input, current->pid, current->tgid, current_fsuid()); -+ res = -EPERM; -+ goto err_put; -+ } -+ full_tag = combine_atag_with_uid(acct_tag, uid); -+ -+ spin_lock_bh(&sock_tag_list_lock); -+ sock_tag_entry = get_sock_stat_nl(el_socket->sk); -+ tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry); -+ if (IS_ERR(tag_ref_entry)) { -+ res = PTR_ERR(tag_ref_entry); -+ spin_unlock_bh(&sock_tag_list_lock); -+ goto err_put; -+ } -+ tag_ref_entry->num_sock_tags++; -+ if (sock_tag_entry) { -+ struct tag_ref *prev_tag_ref_entry; -+ -+ CT_DEBUG("qtaguid: ctrl_tag(%s): retag for sk=%p " -+ "st@%p ...->f_count=%ld\n", -+ input, el_socket->sk, sock_tag_entry, -+ atomic_long_read(&el_socket->file->f_count)); -+ /* -+ * This is a re-tagging, so release the sock_fd that was -+ * locked at the time of the 1st tagging. -+ * There is still the ref from this call's sockfd_lookup() so -+ * it can be done within the spinlock. -+ */ -+ sockfd_put(sock_tag_entry->socket); -+ prev_tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag, -+ &uid_tag_data_entry); -+ BUG_ON(IS_ERR_OR_NULL(prev_tag_ref_entry)); -+ BUG_ON(prev_tag_ref_entry->num_sock_tags <= 0); -+ prev_tag_ref_entry->num_sock_tags--; -+ sock_tag_entry->tag = full_tag; -+ } else { -+ CT_DEBUG("qtaguid: ctrl_tag(%s): newtag for sk=%p\n", -+ input, el_socket->sk); -+ sock_tag_entry = kzalloc(sizeof(*sock_tag_entry), -+ GFP_ATOMIC); -+ if (!sock_tag_entry) { -+ pr_err("qtaguid: ctrl_tag(%s): " -+ "socket tag alloc failed\n", -+ input); -+ spin_unlock_bh(&sock_tag_list_lock); -+ res = -ENOMEM; -+ goto err_tag_unref_put; -+ } -+ sock_tag_entry->sk = el_socket->sk; -+ sock_tag_entry->socket = el_socket; -+ sock_tag_entry->pid = current->tgid; -+ sock_tag_entry->tag = combine_atag_with_uid(acct_tag, -+ uid); -+ spin_lock_bh(&uid_tag_data_tree_lock); -+ pqd_entry = proc_qtu_data_tree_search( -+ &proc_qtu_data_tree, current->tgid); -+ /* -+ * TODO: remove if, and start failing. -+ * At first, we want to catch user-space code that is not -+ * opening the /dev/xt_qtaguid. -+ */ -+ if (IS_ERR_OR_NULL(pqd_entry)) -+ pr_warn_once( -+ "qtaguid: %s(): " -+ "User space forgot to open /dev/xt_qtaguid? " -+ "pid=%u tgid=%u uid=%u\n", __func__, -+ current->pid, current->tgid, -+ current_fsuid()); -+ else -+ list_add(&sock_tag_entry->list, -+ &pqd_entry->sock_tag_list); -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ -+ sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree); -+ atomic64_inc(&qtu_events.sockets_tagged); -+ } -+ spin_unlock_bh(&sock_tag_list_lock); -+ /* We keep the ref to the socket (file) until it is untagged */ -+ CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->f_count=%ld\n", -+ input, sock_tag_entry, -+ atomic_long_read(&el_socket->file->f_count)); -+ return 0; -+ -+err_tag_unref_put: -+ BUG_ON(tag_ref_entry->num_sock_tags <= 0); -+ tag_ref_entry->num_sock_tags--; -+ free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry); -+err_put: -+ CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->f_count=%ld\n", -+ input, atomic_long_read(&el_socket->file->f_count) - 1); -+ /* Release the sock_fd that was grabbed by sockfd_lookup(). */ -+ sockfd_put(el_socket); -+ return res; -+ -+err: -+ CT_DEBUG("qtaguid: ctrl_tag(%s): done.\n", input); -+ return res; -+} -+ -+static int ctrl_cmd_untag(const char *input) -+{ -+ char cmd; -+ int sock_fd = 0; -+ struct socket *el_socket; -+ int res, argc; -+ struct sock_tag *sock_tag_entry; -+ struct tag_ref *tag_ref_entry; -+ struct uid_tag_data *utd_entry; -+ struct proc_qtu_data *pqd_entry; -+ -+ argc = sscanf(input, "%c %d", &cmd, &sock_fd); -+ CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n", -+ input, argc, cmd, sock_fd); -+ if (argc < 2) { -+ res = -EINVAL; -+ goto err; -+ } -+ el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */ -+ if (!el_socket) { -+ pr_info("qtaguid: ctrl_untag(%s): failed to lookup" -+ " sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n", -+ input, sock_fd, res, current->pid, current->tgid, -+ current_fsuid()); -+ goto err; -+ } -+ CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n", -+ input, atomic_long_read(&el_socket->file->f_count), -+ el_socket->sk); -+ spin_lock_bh(&sock_tag_list_lock); -+ sock_tag_entry = get_sock_stat_nl(el_socket->sk); -+ if (!sock_tag_entry) { -+ spin_unlock_bh(&sock_tag_list_lock); -+ res = -EINVAL; -+ goto err_put; -+ } -+ /* -+ * The socket already belongs to the current process -+ * so it can do whatever it wants to it. -+ */ -+ rb_erase(&sock_tag_entry->sock_node, &sock_tag_tree); -+ -+ tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag, &utd_entry); -+ BUG_ON(!tag_ref_entry); -+ BUG_ON(tag_ref_entry->num_sock_tags <= 0); -+ spin_lock_bh(&uid_tag_data_tree_lock); -+ pqd_entry = proc_qtu_data_tree_search( -+ &proc_qtu_data_tree, current->tgid); -+ /* -+ * TODO: remove if, and start failing. -+ * At first, we want to catch user-space code that is not -+ * opening the /dev/xt_qtaguid. -+ */ -+ if (IS_ERR_OR_NULL(pqd_entry)) -+ pr_warn_once("qtaguid: %s(): " -+ "User space forgot to open /dev/xt_qtaguid? " -+ "pid=%u tgid=%u uid=%u\n", __func__, -+ current->pid, current->tgid, current_fsuid()); -+ else -+ list_del(&sock_tag_entry->list); -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ /* -+ * We don't free tag_ref from the utd_entry here, -+ * only during a cmd_delete(). -+ */ -+ tag_ref_entry->num_sock_tags--; -+ spin_unlock_bh(&sock_tag_list_lock); -+ /* -+ * Release the sock_fd that was grabbed at tag time, -+ * and once more for the sockfd_lookup() here. -+ */ -+ sockfd_put(sock_tag_entry->socket); -+ CT_DEBUG("qtaguid: ctrl_untag(%s): done. st@%p ...->f_count=%ld\n", -+ input, sock_tag_entry, -+ atomic_long_read(&el_socket->file->f_count) - 1); -+ sockfd_put(el_socket); -+ -+ kfree(sock_tag_entry); -+ atomic64_inc(&qtu_events.sockets_untagged); -+ -+ return 0; -+ -+err_put: -+ CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%ld\n", -+ input, atomic_long_read(&el_socket->file->f_count) - 1); -+ /* Release the sock_fd that was grabbed by sockfd_lookup(). */ -+ sockfd_put(el_socket); -+ return res; -+ -+err: -+ CT_DEBUG("qtaguid: ctrl_untag(%s): done.\n", input); -+ return res; -+} -+ -+static int qtaguid_ctrl_parse(const char *input, int count) -+{ -+ char cmd; -+ int res; -+ -+ CT_DEBUG("qtaguid: ctrl(%s): pid=%u tgid=%u uid=%u\n", -+ input, current->pid, current->tgid, current_fsuid()); -+ -+ cmd = input[0]; -+ /* Collect params for commands */ -+ switch (cmd) { -+ case 'd': -+ res = ctrl_cmd_delete(input); -+ break; -+ -+ case 's': -+ res = ctrl_cmd_counter_set(input); -+ break; -+ -+ case 't': -+ res = ctrl_cmd_tag(input); -+ break; -+ -+ case 'u': -+ res = ctrl_cmd_untag(input); -+ break; -+ -+ default: -+ res = -EINVAL; -+ goto err; -+ } -+ if (!res) -+ res = count; -+err: -+ CT_DEBUG("qtaguid: ctrl(%s): res=%d\n", input, res); -+ return res; -+} -+ -+#define MAX_QTAGUID_CTRL_INPUT_LEN 255 -+static int qtaguid_ctrl_proc_write(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ char input_buf[MAX_QTAGUID_CTRL_INPUT_LEN]; -+ -+ if (unlikely(module_passive)) -+ return count; -+ -+ if (count >= MAX_QTAGUID_CTRL_INPUT_LEN) -+ return -EINVAL; -+ -+ if (copy_from_user(input_buf, buffer, count)) -+ return -EFAULT; -+ -+ input_buf[count] = '\0'; -+ return qtaguid_ctrl_parse(input_buf, count); -+} -+ -+struct proc_print_info { -+ char *outp; -+ char **num_items_returned; -+ struct iface_stat *iface_entry; -+ struct tag_stat *ts_entry; -+ int item_index; -+ int items_to_skip; -+ int char_count; -+}; -+ -+static int pp_stats_line(struct proc_print_info *ppi, int cnt_set) -+{ -+ int len; -+ struct data_counters *cnts; -+ -+ if (!ppi->item_index) { -+ if (ppi->item_index++ < ppi->items_to_skip) -+ return 0; -+ len = snprintf(ppi->outp, ppi->char_count, -+ "idx iface acct_tag_hex uid_tag_int cnt_set " -+ "rx_bytes rx_packets " -+ "tx_bytes tx_packets " -+ "rx_tcp_bytes rx_tcp_packets " -+ "rx_udp_bytes rx_udp_packets " -+ "rx_other_bytes rx_other_packets " -+ "tx_tcp_bytes tx_tcp_packets " -+ "tx_udp_bytes tx_udp_packets " -+ "tx_other_bytes tx_other_packets\n"); -+ } else { -+ tag_t tag = ppi->ts_entry->tn.tag; -+ uid_t stat_uid = get_uid_from_tag(tag); -+ /* Detailed tags are not available to everybody */ -+ if (get_atag_from_tag(tag) -+ && !can_read_other_uid_stats(stat_uid)) { -+ CT_DEBUG("qtaguid: stats line: " -+ "%s 0x%llx %u: insufficient priv " -+ "from pid=%u tgid=%u uid=%u stats.gid=%u\n", -+ ppi->iface_entry->ifname, -+ get_atag_from_tag(tag), stat_uid, -+ current->pid, current->tgid, current_fsuid(), -+ xt_qtaguid_stats_file->gid); -+ return 0; -+ } -+ if (ppi->item_index++ < ppi->items_to_skip) -+ return 0; -+ cnts = &ppi->ts_entry->counters; -+ len = snprintf( -+ ppi->outp, ppi->char_count, -+ "%d %s 0x%llx %u %u " -+ "%llu %llu " -+ "%llu %llu " -+ "%llu %llu " -+ "%llu %llu " -+ "%llu %llu " -+ "%llu %llu " -+ "%llu %llu " -+ "%llu %llu\n", -+ ppi->item_index, -+ ppi->iface_entry->ifname, -+ get_atag_from_tag(tag), -+ stat_uid, -+ cnt_set, -+ dc_sum_bytes(cnts, cnt_set, IFS_RX), -+ dc_sum_packets(cnts, cnt_set, IFS_RX), -+ dc_sum_bytes(cnts, cnt_set, IFS_TX), -+ dc_sum_packets(cnts, cnt_set, IFS_TX), -+ cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes, -+ cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets, -+ cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes, -+ cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets, -+ cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes, -+ cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets, -+ cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes, -+ cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets, -+ cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes, -+ cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets, -+ cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes, -+ cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets); -+ } -+ return len; -+} -+ -+static bool pp_sets(struct proc_print_info *ppi) -+{ -+ int len; -+ int counter_set; -+ for (counter_set = 0; counter_set < IFS_MAX_COUNTER_SETS; -+ counter_set++) { -+ len = pp_stats_line(ppi, counter_set); -+ if (len >= ppi->char_count) { -+ *ppi->outp = '\0'; -+ return false; -+ } -+ if (len) { -+ ppi->outp += len; -+ ppi->char_count -= len; -+ (*ppi->num_items_returned)++; -+ } -+ } -+ return true; -+} -+ -+/* -+ * Procfs reader to get all tag stats using style "1)" as described in -+ * fs/proc/generic.c -+ * Groups all protocols tx/rx bytes. -+ */ -+static int qtaguid_stats_proc_read(char *page, char **num_items_returned, -+ off_t items_to_skip, int char_count, int *eof, -+ void *data) -+{ -+ struct proc_print_info ppi; -+ int len; -+ -+ ppi.outp = page; -+ ppi.item_index = 0; -+ ppi.char_count = char_count; -+ ppi.num_items_returned = num_items_returned; -+ ppi.items_to_skip = items_to_skip; -+ -+ if (unlikely(module_passive)) { -+ len = pp_stats_line(&ppi, 0); -+ /* The header should always be shorter than the buffer. */ -+ BUG_ON(len >= ppi.char_count); -+ (*num_items_returned)++; -+ *eof = 1; -+ return len; -+ } -+ -+ CT_DEBUG("qtaguid:proc stats pid=%u tgid=%u uid=%u " -+ "page=%p *num_items_returned=%p off=%ld " -+ "char_count=%d *eof=%d\n", -+ current->pid, current->tgid, current_fsuid(), -+ page, *num_items_returned, -+ items_to_skip, char_count, *eof); -+ -+ if (*eof) -+ return 0; -+ -+ /* The idx is there to help debug when things go belly up. */ -+ len = pp_stats_line(&ppi, 0); -+ /* Don't advance the outp unless the whole line was printed */ -+ if (len >= ppi.char_count) { -+ *ppi.outp = '\0'; -+ return ppi.outp - page; -+ } -+ if (len) { -+ ppi.outp += len; -+ ppi.char_count -= len; -+ (*num_items_returned)++; -+ } -+ -+ spin_lock_bh(&iface_stat_list_lock); -+ list_for_each_entry(ppi.iface_entry, &iface_stat_list, list) { -+ struct rb_node *node; -+ spin_lock_bh(&ppi.iface_entry->tag_stat_list_lock); -+ for (node = rb_first(&ppi.iface_entry->tag_stat_tree); -+ node; -+ node = rb_next(node)) { -+ ppi.ts_entry = rb_entry(node, struct tag_stat, tn.node); -+ if (!pp_sets(&ppi)) { -+ spin_unlock_bh( -+ &ppi.iface_entry->tag_stat_list_lock); -+ spin_unlock_bh(&iface_stat_list_lock); -+ return ppi.outp - page; -+ } -+ } -+ spin_unlock_bh(&ppi.iface_entry->tag_stat_list_lock); -+ } -+ spin_unlock_bh(&iface_stat_list_lock); -+ -+ *eof = 1; -+ return ppi.outp - page; -+} -+ -+/*------------------------------------------*/ -+static int qtudev_open(struct inode *inode, struct file *file) -+{ -+ struct uid_tag_data *utd_entry; -+ struct proc_qtu_data *pqd_entry; -+ struct proc_qtu_data *new_pqd_entry; -+ int res; -+ bool utd_entry_found; -+ -+ if (unlikely(qtu_proc_handling_passive)) -+ return 0; -+ -+ DR_DEBUG("qtaguid: qtudev_open(): pid=%u tgid=%u uid=%u\n", -+ current->pid, current->tgid, current_fsuid()); -+ -+ spin_lock_bh(&uid_tag_data_tree_lock); -+ -+ /* Look for existing uid data, or alloc one. */ -+ utd_entry = get_uid_data(current_fsuid(), &utd_entry_found); -+ if (IS_ERR_OR_NULL(utd_entry)) { -+ res = PTR_ERR(utd_entry); -+ goto err_unlock; -+ } -+ -+ /* Look for existing PID based proc_data */ -+ pqd_entry = proc_qtu_data_tree_search(&proc_qtu_data_tree, -+ current->tgid); -+ if (pqd_entry) { -+ pr_err("qtaguid: qtudev_open(): %u/%u %u " -+ "%s already opened\n", -+ current->pid, current->tgid, current_fsuid(), -+ QTU_DEV_NAME); -+ res = -EBUSY; -+ goto err_unlock_free_utd; -+ } -+ -+ new_pqd_entry = kzalloc(sizeof(*new_pqd_entry), GFP_ATOMIC); -+ if (!new_pqd_entry) { -+ pr_err("qtaguid: qtudev_open(): %u/%u %u: " -+ "proc data alloc failed\n", -+ current->pid, current->tgid, current_fsuid()); -+ res = -ENOMEM; -+ goto err_unlock_free_utd; -+ } -+ new_pqd_entry->pid = current->tgid; -+ INIT_LIST_HEAD(&new_pqd_entry->sock_tag_list); -+ new_pqd_entry->parent_tag_data = utd_entry; -+ utd_entry->num_pqd++; -+ -+ proc_qtu_data_tree_insert(new_pqd_entry, -+ &proc_qtu_data_tree); -+ -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ DR_DEBUG("qtaguid: tracking data for uid=%u in pqd=%p\n", -+ current_fsuid(), new_pqd_entry); -+ file->private_data = new_pqd_entry; -+ return 0; -+ -+err_unlock_free_utd: -+ if (!utd_entry_found) { -+ rb_erase(&utd_entry->node, &uid_tag_data_tree); -+ kfree(utd_entry); -+ } -+err_unlock: -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ return res; -+} -+ -+static int qtudev_release(struct inode *inode, struct file *file) -+{ -+ struct proc_qtu_data *pqd_entry = file->private_data; -+ struct uid_tag_data *utd_entry = pqd_entry->parent_tag_data; -+ struct sock_tag *st_entry; -+ struct rb_root st_to_free_tree = RB_ROOT; -+ struct list_head *entry, *next; -+ struct tag_ref *tr; -+ -+ if (unlikely(qtu_proc_handling_passive)) -+ return 0; -+ -+ /* -+ * Do not trust the current->pid, it might just be a kworker cleaning -+ * up after a dead proc. -+ */ -+ DR_DEBUG("qtaguid: qtudev_release(): " -+ "pid=%u tgid=%u uid=%u " -+ "pqd_entry=%p->pid=%u utd_entry=%p->active_tags=%d\n", -+ current->pid, current->tgid, pqd_entry->parent_tag_data->uid, -+ pqd_entry, pqd_entry->pid, utd_entry, -+ utd_entry->num_active_tags); -+ -+ spin_lock_bh(&sock_tag_list_lock); -+ spin_lock_bh(&uid_tag_data_tree_lock); -+ -+ list_for_each_safe(entry, next, &pqd_entry->sock_tag_list) { -+ st_entry = list_entry(entry, struct sock_tag, list); -+ DR_DEBUG("qtaguid: %s(): " -+ "erase sock_tag=%p->sk=%p pid=%u tgid=%u uid=%u\n", -+ __func__, -+ st_entry, st_entry->sk, -+ current->pid, current->tgid, -+ pqd_entry->parent_tag_data->uid); -+ -+ utd_entry = uid_tag_data_tree_search( -+ &uid_tag_data_tree, -+ get_uid_from_tag(st_entry->tag)); -+ BUG_ON(IS_ERR_OR_NULL(utd_entry)); -+ DR_DEBUG("qtaguid: %s(): " -+ "looking for tag=0x%llx in utd_entry=%p\n", __func__, -+ st_entry->tag, utd_entry); -+ tr = tag_ref_tree_search(&utd_entry->tag_ref_tree, -+ st_entry->tag); -+ BUG_ON(!tr); -+ BUG_ON(tr->num_sock_tags <= 0); -+ tr->num_sock_tags--; -+ free_tag_ref_from_utd_entry(tr, utd_entry); -+ -+ rb_erase(&st_entry->sock_node, &sock_tag_tree); -+ list_del(&st_entry->list); -+ /* Can't sockfd_put() within spinlock, do it later. */ -+ sock_tag_tree_insert(st_entry, &st_to_free_tree); -+ -+ /* -+ * Try to free the utd_entry if no other proc_qtu_data is -+ * using it (num_pqd is 0) and it doesn't have active tags -+ * (num_active_tags is 0). -+ */ -+ put_utd_entry(utd_entry); -+ } -+ -+ rb_erase(&pqd_entry->node, &proc_qtu_data_tree); -+ BUG_ON(pqd_entry->parent_tag_data->num_pqd < 1); -+ pqd_entry->parent_tag_data->num_pqd--; -+ put_utd_entry(pqd_entry->parent_tag_data); -+ kfree(pqd_entry); -+ file->private_data = NULL; -+ -+ spin_unlock_bh(&uid_tag_data_tree_lock); -+ spin_unlock_bh(&sock_tag_list_lock); -+ -+ -+ sock_tag_tree_erase(&st_to_free_tree); -+ -+ prdebug_full_state(0, "%s(): pid=%u tgid=%u", __func__, -+ current->pid, current->tgid); -+ return 0; -+} -+ -+/*------------------------------------------*/ -+static const struct file_operations qtudev_fops = { -+ .owner = THIS_MODULE, -+ .open = qtudev_open, -+ .release = qtudev_release, -+}; -+ -+static struct miscdevice qtu_device = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = QTU_DEV_NAME, -+ .fops = &qtudev_fops, -+ /* How sad it doesn't allow for defaults: .mode = S_IRUGO | S_IWUSR */ -+}; -+ -+/*------------------------------------------*/ -+static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir) -+{ -+ int ret; -+ *res_procdir = proc_mkdir(module_procdirname, init_net.proc_net); -+ if (!*res_procdir) { -+ pr_err("qtaguid: failed to create proc/.../xt_qtaguid\n"); -+ ret = -ENOMEM; -+ goto no_dir; -+ } -+ -+ xt_qtaguid_ctrl_file = create_proc_entry("ctrl", proc_ctrl_perms, -+ *res_procdir); -+ if (!xt_qtaguid_ctrl_file) { -+ pr_err("qtaguid: failed to create xt_qtaguid/ctrl " -+ " file\n"); -+ ret = -ENOMEM; -+ goto no_ctrl_entry; -+ } -+ xt_qtaguid_ctrl_file->read_proc = qtaguid_ctrl_proc_read; -+ xt_qtaguid_ctrl_file->write_proc = qtaguid_ctrl_proc_write; -+ -+ xt_qtaguid_stats_file = create_proc_entry("stats", proc_stats_perms, -+ *res_procdir); -+ if (!xt_qtaguid_stats_file) { -+ pr_err("qtaguid: failed to create xt_qtaguid/stats " -+ "file\n"); -+ ret = -ENOMEM; -+ goto no_stats_entry; -+ } -+ xt_qtaguid_stats_file->read_proc = qtaguid_stats_proc_read; -+ /* -+ * TODO: add support counter hacking -+ * xt_qtaguid_stats_file->write_proc = qtaguid_stats_proc_write; -+ */ -+ return 0; -+ -+no_stats_entry: -+ remove_proc_entry("ctrl", *res_procdir); -+no_ctrl_entry: -+ remove_proc_entry("xt_qtaguid", NULL); -+no_dir: -+ return ret; -+} -+ -+static struct xt_match qtaguid_mt_reg __read_mostly = { -+ /* -+ * This module masquerades as the "owner" module so that iptables -+ * tools can deal with it. -+ */ -+ .name = "owner", -+ .revision = 1, -+ .family = NFPROTO_UNSPEC, -+ .match = qtaguid_mt, -+ .matchsize = sizeof(struct xt_qtaguid_match_info), -+ .me = THIS_MODULE, -+}; -+ -+static int __init qtaguid_mt_init(void) -+{ -+ if (qtaguid_proc_register(&xt_qtaguid_procdir) -+ || iface_stat_init(xt_qtaguid_procdir) -+ || xt_register_match(&qtaguid_mt_reg) -+ || misc_register(&qtu_device)) -+ return -1; -+ return 0; -+} -+ -+/* -+ * TODO: allow unloading of the module. -+ * For now stats are permanent. -+ * Kconfig forces'y/n' and never an 'm'. -+ */ -+ -+module_init(qtaguid_mt_init); -+MODULE_AUTHOR("jpa <jpa@google.com>"); -+MODULE_DESCRIPTION("Xtables: socket owner+tag matching and associated stats"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("ipt_owner"); -+MODULE_ALIAS("ip6t_owner"); -+MODULE_ALIAS("ipt_qtaguid"); -+MODULE_ALIAS("ip6t_qtaguid"); -diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h -new file mode 100644 -index 00000000..6dc14a9c ---- /dev/null -+++ b/net/netfilter/xt_qtaguid_internal.h -@@ -0,0 +1,352 @@ -+/* -+ * Kernel iptables module to track stats for packets based on user tags. -+ * -+ * (C) 2011 Google, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef __XT_QTAGUID_INTERNAL_H__ -+#define __XT_QTAGUID_INTERNAL_H__ -+ -+#include <linux/types.h> -+#include <linux/rbtree.h> -+#include <linux/spinlock_types.h> -+#include <linux/workqueue.h> -+ -+/* Iface handling */ -+#define IDEBUG_MASK (1<<0) -+/* Iptable Matching. Per packet. */ -+#define MDEBUG_MASK (1<<1) -+/* Red-black tree handling. Per packet. */ -+#define RDEBUG_MASK (1<<2) -+/* procfs ctrl/stats handling */ -+#define CDEBUG_MASK (1<<3) -+/* dev and resource tracking */ -+#define DDEBUG_MASK (1<<4) -+ -+/* E.g (IDEBUG_MASK | CDEBUG_MASK | DDEBUG_MASK) */ -+#define DEFAULT_DEBUG_MASK 0 -+ -+/* -+ * (Un)Define these *DEBUG to compile out/in the pr_debug calls. -+ * All undef: text size ~ 0x3030; all def: ~ 0x4404. -+ */ -+#define IDEBUG -+#define MDEBUG -+#define RDEBUG -+#define CDEBUG -+#define DDEBUG -+ -+#define MSK_DEBUG(mask, ...) do { \ -+ if (unlikely(qtaguid_debug_mask & (mask))) \ -+ pr_debug(__VA_ARGS__); \ -+ } while (0) -+#ifdef IDEBUG -+#define IF_DEBUG(...) MSK_DEBUG(IDEBUG_MASK, __VA_ARGS__) -+#else -+#define IF_DEBUG(...) no_printk(__VA_ARGS__) -+#endif -+#ifdef MDEBUG -+#define MT_DEBUG(...) MSK_DEBUG(MDEBUG_MASK, __VA_ARGS__) -+#else -+#define MT_DEBUG(...) no_printk(__VA_ARGS__) -+#endif -+#ifdef RDEBUG -+#define RB_DEBUG(...) MSK_DEBUG(RDEBUG_MASK, __VA_ARGS__) -+#else -+#define RB_DEBUG(...) no_printk(__VA_ARGS__) -+#endif -+#ifdef CDEBUG -+#define CT_DEBUG(...) MSK_DEBUG(CDEBUG_MASK, __VA_ARGS__) -+#else -+#define CT_DEBUG(...) no_printk(__VA_ARGS__) -+#endif -+#ifdef DDEBUG -+#define DR_DEBUG(...) MSK_DEBUG(DDEBUG_MASK, __VA_ARGS__) -+#else -+#define DR_DEBUG(...) no_printk(__VA_ARGS__) -+#endif -+ -+extern uint qtaguid_debug_mask; -+ -+/*---------------------------------------------------------------------------*/ -+/* -+ * Tags: -+ * -+ * They represent what the data usage counters will be tracked against. -+ * By default a tag is just based on the UID. -+ * The UID is used as the base for policing, and can not be ignored. -+ * So a tag will always at least represent a UID (uid_tag). -+ * -+ * A tag can be augmented with an "accounting tag" which is associated -+ * with a UID. -+ * User space can set the acct_tag portion of the tag which is then used -+ * with sockets: all data belonging to that socket will be counted against the -+ * tag. The policing is then based on the tag's uid_tag portion, -+ * and stats are collected for the acct_tag portion separately. -+ * -+ * There could be -+ * a: {acct_tag=1, uid_tag=10003} -+ * b: {acct_tag=2, uid_tag=10003} -+ * c: {acct_tag=3, uid_tag=10003} -+ * d: {acct_tag=0, uid_tag=10003} -+ * a, b, and c represent tags associated with specific sockets. -+ * d is for the totals for that uid, including all untagged traffic. -+ * Typically d is used with policing/quota rules. -+ * -+ * We want tag_t big enough to distinguish uid_t and acct_tag. -+ * It might become a struct if needed. -+ * Nothing should be using it as an int. -+ */ -+typedef uint64_t tag_t; /* Only used via accessors */ -+ -+#define TAG_UID_MASK 0xFFFFFFFFULL -+#define TAG_ACCT_MASK (~0xFFFFFFFFULL) -+ -+static inline int tag_compare(tag_t t1, tag_t t2) -+{ -+ return t1 < t2 ? -1 : t1 == t2 ? 0 : 1; -+} -+ -+static inline tag_t combine_atag_with_uid(tag_t acct_tag, uid_t uid) -+{ -+ return acct_tag | uid; -+} -+static inline tag_t make_tag_from_uid(uid_t uid) -+{ -+ return uid; -+} -+static inline uid_t get_uid_from_tag(tag_t tag) -+{ -+ return tag & TAG_UID_MASK; -+} -+static inline tag_t get_utag_from_tag(tag_t tag) -+{ -+ return tag & TAG_UID_MASK; -+} -+static inline tag_t get_atag_from_tag(tag_t tag) -+{ -+ return tag & TAG_ACCT_MASK; -+} -+ -+static inline bool valid_atag(tag_t tag) -+{ -+ return !(tag & TAG_UID_MASK); -+} -+static inline tag_t make_atag_from_value(uint32_t value) -+{ -+ return (uint64_t)value << 32; -+} -+/*---------------------------------------------------------------------------*/ -+ -+/* -+ * Maximum number of socket tags that a UID is allowed to have active. -+ * Multiple processes belonging to the same UID contribute towards this limit. -+ * Special UIDs that can impersonate a UID also contribute (e.g. download -+ * manager, ...) -+ */ -+#define DEFAULT_MAX_SOCK_TAGS 1024 -+ -+/* -+ * For now we only track 2 sets of counters. -+ * The default set is 0. -+ * Userspace can activate another set for a given uid being tracked. -+ */ -+#define IFS_MAX_COUNTER_SETS 2 -+ -+enum ifs_tx_rx { -+ IFS_TX, -+ IFS_RX, -+ IFS_MAX_DIRECTIONS -+}; -+ -+/* For now, TCP, UDP, the rest */ -+enum ifs_proto { -+ IFS_TCP, -+ IFS_UDP, -+ IFS_PROTO_OTHER, -+ IFS_MAX_PROTOS -+}; -+ -+struct byte_packet_counters { -+ uint64_t bytes; -+ uint64_t packets; -+}; -+ -+struct data_counters { -+ struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS]; -+}; -+ -+static inline uint64_t dc_sum_bytes(struct data_counters *counters, -+ int set, -+ enum ifs_tx_rx direction) -+{ -+ return counters->bpc[set][direction][IFS_TCP].bytes -+ + counters->bpc[set][direction][IFS_UDP].bytes -+ + counters->bpc[set][direction][IFS_PROTO_OTHER].bytes; -+} -+ -+static inline uint64_t dc_sum_packets(struct data_counters *counters, -+ int set, -+ enum ifs_tx_rx direction) -+{ -+ return counters->bpc[set][direction][IFS_TCP].packets -+ + counters->bpc[set][direction][IFS_UDP].packets -+ + counters->bpc[set][direction][IFS_PROTO_OTHER].packets; -+} -+ -+ -+/* Generic X based nodes used as a base for rb_tree ops */ -+struct tag_node { -+ struct rb_node node; -+ tag_t tag; -+}; -+ -+struct tag_stat { -+ struct tag_node tn; -+ struct data_counters counters; -+ /* -+ * If this tag is acct_tag based, we need to count against the -+ * matching parent uid_tag. -+ */ -+ struct data_counters *parent_counters; -+}; -+ -+struct iface_stat { -+ struct list_head list; /* in iface_stat_list */ -+ char *ifname; -+ bool active; -+ /* net_dev is only valid for active iface_stat */ -+ struct net_device *net_dev; -+ -+ struct byte_packet_counters totals_via_dev[IFS_MAX_DIRECTIONS]; -+ struct data_counters totals_via_skb; -+ /* -+ * We keep the last_known, because some devices reset their counters -+ * just before NETDEV_UP, while some will reset just before -+ * NETDEV_REGISTER (which is more normal). -+ * So now, if the device didn't do a NETDEV_UNREGISTER and we see -+ * its current dev stats smaller that what was previously known, we -+ * assume an UNREGISTER and just use the last_known. -+ */ -+ struct byte_packet_counters last_known[IFS_MAX_DIRECTIONS]; -+ /* last_known is usable when last_known_valid is true */ -+ bool last_known_valid; -+ -+ struct proc_dir_entry *proc_ptr; -+ -+ struct rb_root tag_stat_tree; -+ spinlock_t tag_stat_list_lock; -+}; -+ -+/* This is needed to create proc_dir_entries from atomic context. */ -+struct iface_stat_work { -+ struct work_struct iface_work; -+ struct iface_stat *iface_entry; -+}; -+ -+/* -+ * Track tag that this socket is transferring data for, and not necessarily -+ * the uid that owns the socket. -+ * This is the tag against which tag_stat.counters will be billed. -+ * These structs need to be looked up by sock and pid. -+ */ -+struct sock_tag { -+ struct rb_node sock_node; -+ struct sock *sk; /* Only used as a number, never dereferenced */ -+ /* The socket is needed for sockfd_put() */ -+ struct socket *socket; -+ /* Used to associate with a given pid */ -+ struct list_head list; /* in proc_qtu_data.sock_tag_list */ -+ pid_t pid; -+ -+ tag_t tag; -+}; -+ -+struct qtaguid_event_counts { -+ /* Various successful events */ -+ atomic64_t sockets_tagged; -+ atomic64_t sockets_untagged; -+ atomic64_t counter_set_changes; -+ atomic64_t delete_cmds; -+ atomic64_t iface_events; /* Number of NETDEV_* events handled */ -+ -+ atomic64_t match_calls; /* Number of times iptables called mt */ -+ /* Number of times iptables called mt from pre or post routing hooks */ -+ atomic64_t match_calls_prepost; -+ /* -+ * match_found_sk_*: numbers related to the netfilter matching -+ * function finding a sock for the sk_buff. -+ * Total skbs processed is sum(match_found*). -+ */ -+ atomic64_t match_found_sk; /* An sk was already in the sk_buff. */ -+ /* The connection tracker had or didn't have the sk. */ -+ atomic64_t match_found_sk_in_ct; -+ atomic64_t match_found_no_sk_in_ct; -+ /* -+ * No sk could be found. No apparent owner. Could happen with -+ * unsolicited traffic. -+ */ -+ atomic64_t match_no_sk; -+ /* -+ * The file ptr in the sk_socket wasn't there. -+ * This might happen for traffic while the socket is being closed. -+ */ -+ atomic64_t match_no_sk_file; -+}; -+ -+/* Track the set active_set for the given tag. */ -+struct tag_counter_set { -+ struct tag_node tn; -+ int active_set; -+}; -+ -+/*----------------------------------------------*/ -+/* -+ * The qtu uid data is used to track resources that are created directly or -+ * indirectly by processes (uid tracked). -+ * It is shared by the processes with the same uid. -+ * Some of the resource will be counted to prevent further rogue allocations, -+ * some will need freeing once the owner process (uid) exits. -+ */ -+struct uid_tag_data { -+ struct rb_node node; -+ uid_t uid; -+ -+ /* -+ * For the uid, how many accounting tags have been set. -+ */ -+ int num_active_tags; -+ /* Track the number of proc_qtu_data that reference it */ -+ int num_pqd; -+ struct rb_root tag_ref_tree; -+ /* No tag_node_tree_lock; use uid_tag_data_tree_lock */ -+}; -+ -+struct tag_ref { -+ struct tag_node tn; -+ -+ /* -+ * This tracks the number of active sockets that have a tag on them -+ * which matches this tag_ref.tn.tag. -+ * A tag ref can live on after the sockets are untagged. -+ * A tag ref can only be removed during a tag delete command. -+ */ -+ int num_sock_tags; -+}; -+ -+struct proc_qtu_data { -+ struct rb_node node; -+ pid_t pid; -+ -+ struct uid_tag_data *parent_tag_data; -+ -+ /* Tracks the sock_tags that need freeing upon this proc's death */ -+ struct list_head sock_tag_list; -+ /* No spinlock_t sock_tag_list_lock; use the global one. */ -+}; -+ -+/*----------------------------------------------*/ -+#endif /* ifndef __XT_QTAGUID_INTERNAL_H__ */ -diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c -new file mode 100644 -index 00000000..f6a00a35 ---- /dev/null -+++ b/net/netfilter/xt_qtaguid_print.c -@@ -0,0 +1,566 @@ -+/* -+ * Pretty printing Support for iptables xt_qtaguid module. -+ * -+ * (C) 2011 Google, 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. -+ */ -+ -+/* -+ * Most of the functions in this file just waste time if DEBUG is not defined. -+ * The matching xt_qtaguid_print.h will static inline empty funcs if the needed -+ * debug flags ore not defined. -+ * Those funcs that fail to allocate memory will panic as there is no need to -+ * hobble allong just pretending to do the requested work. -+ */ -+ -+#define DEBUG -+ -+#include <linux/fs.h> -+#include <linux/gfp.h> -+#include <linux/net.h> -+#include <linux/rbtree.h> -+#include <linux/slab.h> -+#include <linux/spinlock_types.h> -+ -+ -+#include "xt_qtaguid_internal.h" -+#include "xt_qtaguid_print.h" -+ -+#ifdef DDEBUG -+ -+static void _bug_on_err_or_null(void *ptr) -+{ -+ if (IS_ERR_OR_NULL(ptr)) { -+ pr_err("qtaguid: kmalloc failed\n"); -+ BUG(); -+ } -+} -+ -+char *pp_tag_t(tag_t *tag) -+{ -+ char *res; -+ -+ if (!tag) -+ res = kasprintf(GFP_ATOMIC, "tag_t@null{}"); -+ else -+ res = kasprintf(GFP_ATOMIC, -+ "tag_t@%p{tag=0x%llx, uid=%u}", -+ tag, *tag, get_uid_from_tag(*tag)); -+ _bug_on_err_or_null(res); -+ return res; -+} -+ -+char *pp_data_counters(struct data_counters *dc, bool showValues) -+{ -+ char *res; -+ -+ if (!dc) -+ res = kasprintf(GFP_ATOMIC, "data_counters@null{}"); -+ else if (showValues) -+ res = kasprintf( -+ GFP_ATOMIC, "data_counters@%p{" -+ "set0{" -+ "rx{" -+ "tcp{b=%llu, p=%llu}, " -+ "udp{b=%llu, p=%llu}," -+ "other{b=%llu, p=%llu}}, " -+ "tx{" -+ "tcp{b=%llu, p=%llu}, " -+ "udp{b=%llu, p=%llu}," -+ "other{b=%llu, p=%llu}}}, " -+ "set1{" -+ "rx{" -+ "tcp{b=%llu, p=%llu}, " -+ "udp{b=%llu, p=%llu}," -+ "other{b=%llu, p=%llu}}, " -+ "tx{" -+ "tcp{b=%llu, p=%llu}, " -+ "udp{b=%llu, p=%llu}," -+ "other{b=%llu, p=%llu}}}}", -+ dc, -+ dc->bpc[0][IFS_RX][IFS_TCP].bytes, -+ dc->bpc[0][IFS_RX][IFS_TCP].packets, -+ dc->bpc[0][IFS_RX][IFS_UDP].bytes, -+ dc->bpc[0][IFS_RX][IFS_UDP].packets, -+ dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].bytes, -+ dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].packets, -+ dc->bpc[0][IFS_TX][IFS_TCP].bytes, -+ dc->bpc[0][IFS_TX][IFS_TCP].packets, -+ dc->bpc[0][IFS_TX][IFS_UDP].bytes, -+ dc->bpc[0][IFS_TX][IFS_UDP].packets, -+ dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].bytes, -+ dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].packets, -+ dc->bpc[1][IFS_RX][IFS_TCP].bytes, -+ dc->bpc[1][IFS_RX][IFS_TCP].packets, -+ dc->bpc[1][IFS_RX][IFS_UDP].bytes, -+ dc->bpc[1][IFS_RX][IFS_UDP].packets, -+ dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].bytes, -+ dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].packets, -+ dc->bpc[1][IFS_TX][IFS_TCP].bytes, -+ dc->bpc[1][IFS_TX][IFS_TCP].packets, -+ dc->bpc[1][IFS_TX][IFS_UDP].bytes, -+ dc->bpc[1][IFS_TX][IFS_UDP].packets, -+ dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].bytes, -+ dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].packets); -+ else -+ res = kasprintf(GFP_ATOMIC, "data_counters@%p{...}", dc); -+ _bug_on_err_or_null(res); -+ return res; -+} -+ -+char *pp_tag_node(struct tag_node *tn) -+{ -+ char *tag_str; -+ char *res; -+ -+ if (!tn) { -+ res = kasprintf(GFP_ATOMIC, "tag_node@null{}"); -+ _bug_on_err_or_null(res); -+ return res; -+ } -+ tag_str = pp_tag_t(&tn->tag); -+ res = kasprintf(GFP_ATOMIC, -+ "tag_node@%p{tag=%s}", -+ tn, tag_str); -+ _bug_on_err_or_null(res); -+ kfree(tag_str); -+ return res; -+} -+ -+char *pp_tag_ref(struct tag_ref *tr) -+{ -+ char *tn_str; -+ char *res; -+ -+ if (!tr) { -+ res = kasprintf(GFP_ATOMIC, "tag_ref@null{}"); -+ _bug_on_err_or_null(res); -+ return res; -+ } -+ tn_str = pp_tag_node(&tr->tn); -+ res = kasprintf(GFP_ATOMIC, -+ "tag_ref@%p{%s, num_sock_tags=%d}", -+ tr, tn_str, tr->num_sock_tags); -+ _bug_on_err_or_null(res); -+ kfree(tn_str); -+ return res; -+} -+ -+char *pp_tag_stat(struct tag_stat *ts) -+{ -+ char *tn_str; -+ char *counters_str; -+ char *parent_counters_str; -+ char *res; -+ -+ if (!ts) { -+ res = kasprintf(GFP_ATOMIC, "tag_stat@null{}"); -+ _bug_on_err_or_null(res); -+ return res; -+ } -+ tn_str = pp_tag_node(&ts->tn); -+ counters_str = pp_data_counters(&ts->counters, true); -+ parent_counters_str = pp_data_counters(ts->parent_counters, false); -+ res = kasprintf(GFP_ATOMIC, -+ "tag_stat@%p{%s, counters=%s, parent_counters=%s}", -+ ts, tn_str, counters_str, parent_counters_str); -+ _bug_on_err_or_null(res); -+ kfree(tn_str); -+ kfree(counters_str); -+ kfree(parent_counters_str); -+ return res; -+} -+ -+char *pp_iface_stat(struct iface_stat *is) -+{ -+ char *res; -+ if (!is) { -+ res = kasprintf(GFP_ATOMIC, "iface_stat@null{}"); -+ } else { -+ struct data_counters *cnts = &is->totals_via_skb; -+ res = kasprintf(GFP_ATOMIC, "iface_stat@%p{" -+ "list=list_head{...}, " -+ "ifname=%s, " -+ "total_dev={rx={bytes=%llu, " -+ "packets=%llu}, " -+ "tx={bytes=%llu, " -+ "packets=%llu}}, " -+ "total_skb={rx={bytes=%llu, " -+ "packets=%llu}, " -+ "tx={bytes=%llu, " -+ "packets=%llu}}, " -+ "last_known_valid=%d, " -+ "last_known={rx={bytes=%llu, " -+ "packets=%llu}, " -+ "tx={bytes=%llu, " -+ "packets=%llu}}, " -+ "active=%d, " -+ "net_dev=%p, " -+ "proc_ptr=%p, " -+ "tag_stat_tree=rb_root{...}}", -+ is, -+ is->ifname, -+ is->totals_via_dev[IFS_RX].bytes, -+ is->totals_via_dev[IFS_RX].packets, -+ is->totals_via_dev[IFS_TX].bytes, -+ is->totals_via_dev[IFS_TX].packets, -+ dc_sum_bytes(cnts, 0, IFS_RX), -+ dc_sum_packets(cnts, 0, IFS_RX), -+ dc_sum_bytes(cnts, 0, IFS_TX), -+ dc_sum_packets(cnts, 0, IFS_TX), -+ is->last_known_valid, -+ is->last_known[IFS_RX].bytes, -+ is->last_known[IFS_RX].packets, -+ is->last_known[IFS_TX].bytes, -+ is->last_known[IFS_TX].packets, -+ is->active, -+ is->net_dev, -+ is->proc_ptr); -+ } -+ _bug_on_err_or_null(res); -+ return res; -+} -+ -+char *pp_sock_tag(struct sock_tag *st) -+{ -+ char *tag_str; -+ char *res; -+ -+ if (!st) { -+ res = kasprintf(GFP_ATOMIC, "sock_tag@null{}"); -+ _bug_on_err_or_null(res); -+ return res; -+ } -+ tag_str = pp_tag_t(&st->tag); -+ res = kasprintf(GFP_ATOMIC, "sock_tag@%p{" -+ "sock_node=rb_node{...}, " -+ "sk=%p socket=%p (f_count=%lu), list=list_head{...}, " -+ "pid=%u, tag=%s}", -+ st, st->sk, st->socket, atomic_long_read( -+ &st->socket->file->f_count), -+ st->pid, tag_str); -+ _bug_on_err_or_null(res); -+ kfree(tag_str); -+ return res; -+} -+ -+char *pp_uid_tag_data(struct uid_tag_data *utd) -+{ -+ char *res; -+ -+ if (!utd) -+ res = kasprintf(GFP_ATOMIC, "uid_tag_data@null{}"); -+ else -+ res = kasprintf(GFP_ATOMIC, "uid_tag_data@%p{" -+ "uid=%u, num_active_acct_tags=%d, " -+ "num_pqd=%d, " -+ "tag_node_tree=rb_root{...}, " -+ "proc_qtu_data_tree=rb_root{...}}", -+ utd, utd->uid, -+ utd->num_active_tags, utd->num_pqd); -+ _bug_on_err_or_null(res); -+ return res; -+} -+ -+char *pp_proc_qtu_data(struct proc_qtu_data *pqd) -+{ -+ char *parent_tag_data_str; -+ char *res; -+ -+ if (!pqd) { -+ res = kasprintf(GFP_ATOMIC, "proc_qtu_data@null{}"); -+ _bug_on_err_or_null(res); -+ return res; -+ } -+ parent_tag_data_str = pp_uid_tag_data(pqd->parent_tag_data); -+ res = kasprintf(GFP_ATOMIC, "proc_qtu_data@%p{" -+ "node=rb_node{...}, pid=%u, " -+ "parent_tag_data=%s, " -+ "sock_tag_list=list_head{...}}", -+ pqd, pqd->pid, parent_tag_data_str -+ ); -+ _bug_on_err_or_null(res); -+ kfree(parent_tag_data_str); -+ return res; -+} -+ -+/*------------------------------------------*/ -+void prdebug_sock_tag_tree(int indent_level, -+ struct rb_root *sock_tag_tree) -+{ -+ struct rb_node *node; -+ struct sock_tag *sock_tag_entry; -+ char *str; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ if (RB_EMPTY_ROOT(sock_tag_tree)) { -+ str = "sock_tag_tree=rb_root{}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ return; -+ } -+ -+ str = "sock_tag_tree=rb_root{"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ indent_level++; -+ for (node = rb_first(sock_tag_tree); -+ node; -+ node = rb_next(node)) { -+ sock_tag_entry = rb_entry(node, struct sock_tag, sock_node); -+ str = pp_sock_tag(sock_tag_entry); -+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, str); -+ kfree(str); -+ } -+ indent_level--; -+ str = "}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+} -+ -+void prdebug_sock_tag_list(int indent_level, -+ struct list_head *sock_tag_list) -+{ -+ struct sock_tag *sock_tag_entry; -+ char *str; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ if (list_empty(sock_tag_list)) { -+ str = "sock_tag_list=list_head{}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ return; -+ } -+ -+ str = "sock_tag_list=list_head{"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ indent_level++; -+ list_for_each_entry(sock_tag_entry, sock_tag_list, list) { -+ str = pp_sock_tag(sock_tag_entry); -+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, str); -+ kfree(str); -+ } -+ indent_level--; -+ str = "}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+} -+ -+void prdebug_proc_qtu_data_tree(int indent_level, -+ struct rb_root *proc_qtu_data_tree) -+{ -+ char *str; -+ struct rb_node *node; -+ struct proc_qtu_data *proc_qtu_data_entry; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ if (RB_EMPTY_ROOT(proc_qtu_data_tree)) { -+ str = "proc_qtu_data_tree=rb_root{}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ return; -+ } -+ -+ str = "proc_qtu_data_tree=rb_root{"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ indent_level++; -+ for (node = rb_first(proc_qtu_data_tree); -+ node; -+ node = rb_next(node)) { -+ proc_qtu_data_entry = rb_entry(node, -+ struct proc_qtu_data, -+ node); -+ str = pp_proc_qtu_data(proc_qtu_data_entry); -+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, -+ str); -+ kfree(str); -+ indent_level++; -+ prdebug_sock_tag_list(indent_level, -+ &proc_qtu_data_entry->sock_tag_list); -+ indent_level--; -+ -+ } -+ indent_level--; -+ str = "}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+} -+ -+void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree) -+{ -+ char *str; -+ struct rb_node *node; -+ struct tag_ref *tag_ref_entry; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ if (RB_EMPTY_ROOT(tag_ref_tree)) { -+ str = "tag_ref_tree{}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ return; -+ } -+ -+ str = "tag_ref_tree{"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ indent_level++; -+ for (node = rb_first(tag_ref_tree); -+ node; -+ node = rb_next(node)) { -+ tag_ref_entry = rb_entry(node, -+ struct tag_ref, -+ tn.node); -+ str = pp_tag_ref(tag_ref_entry); -+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, -+ str); -+ kfree(str); -+ } -+ indent_level--; -+ str = "}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+} -+ -+void prdebug_uid_tag_data_tree(int indent_level, -+ struct rb_root *uid_tag_data_tree) -+{ -+ char *str; -+ struct rb_node *node; -+ struct uid_tag_data *uid_tag_data_entry; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ if (RB_EMPTY_ROOT(uid_tag_data_tree)) { -+ str = "uid_tag_data_tree=rb_root{}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ return; -+ } -+ -+ str = "uid_tag_data_tree=rb_root{"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ indent_level++; -+ for (node = rb_first(uid_tag_data_tree); -+ node; -+ node = rb_next(node)) { -+ uid_tag_data_entry = rb_entry(node, struct uid_tag_data, -+ node); -+ str = pp_uid_tag_data(uid_tag_data_entry); -+ pr_debug("%*d: %s,\n", indent_level*2, indent_level, str); -+ kfree(str); -+ if (!RB_EMPTY_ROOT(&uid_tag_data_entry->tag_ref_tree)) { -+ indent_level++; -+ prdebug_tag_ref_tree(indent_level, -+ &uid_tag_data_entry->tag_ref_tree); -+ indent_level--; -+ } -+ } -+ indent_level--; -+ str = "}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+} -+ -+void prdebug_tag_stat_tree(int indent_level, -+ struct rb_root *tag_stat_tree) -+{ -+ char *str; -+ struct rb_node *node; -+ struct tag_stat *ts_entry; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ if (RB_EMPTY_ROOT(tag_stat_tree)) { -+ str = "tag_stat_tree{}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ return; -+ } -+ -+ str = "tag_stat_tree{"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ indent_level++; -+ for (node = rb_first(tag_stat_tree); -+ node; -+ node = rb_next(node)) { -+ ts_entry = rb_entry(node, struct tag_stat, tn.node); -+ str = pp_tag_stat(ts_entry); -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, -+ str); -+ kfree(str); -+ } -+ indent_level--; -+ str = "}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+} -+ -+void prdebug_iface_stat_list(int indent_level, -+ struct list_head *iface_stat_list) -+{ -+ char *str; -+ struct iface_stat *iface_entry; -+ -+ if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK)) -+ return; -+ -+ if (list_empty(iface_stat_list)) { -+ str = "iface_stat_list=list_head{}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ return; -+ } -+ -+ str = "iface_stat_list=list_head{"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ indent_level++; -+ list_for_each_entry(iface_entry, iface_stat_list, list) { -+ str = pp_iface_stat(iface_entry); -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+ kfree(str); -+ -+ spin_lock_bh(&iface_entry->tag_stat_list_lock); -+ if (!RB_EMPTY_ROOT(&iface_entry->tag_stat_tree)) { -+ indent_level++; -+ prdebug_tag_stat_tree(indent_level, -+ &iface_entry->tag_stat_tree); -+ indent_level--; -+ } -+ spin_unlock_bh(&iface_entry->tag_stat_list_lock); -+ } -+ indent_level--; -+ str = "}"; -+ pr_debug("%*d: %s\n", indent_level*2, indent_level, str); -+} -+ -+#endif /* ifdef DDEBUG */ -+/*------------------------------------------*/ -+static const char * const netdev_event_strings[] = { -+ "netdev_unknown", -+ "NETDEV_UP", -+ "NETDEV_DOWN", -+ "NETDEV_REBOOT", -+ "NETDEV_CHANGE", -+ "NETDEV_REGISTER", -+ "NETDEV_UNREGISTER", -+ "NETDEV_CHANGEMTU", -+ "NETDEV_CHANGEADDR", -+ "NETDEV_GOING_DOWN", -+ "NETDEV_CHANGENAME", -+ "NETDEV_FEAT_CHANGE", -+ "NETDEV_BONDING_FAILOVER", -+ "NETDEV_PRE_UP", -+ "NETDEV_PRE_TYPE_CHANGE", -+ "NETDEV_POST_TYPE_CHANGE", -+ "NETDEV_POST_INIT", -+ "NETDEV_UNREGISTER_BATCH", -+ "NETDEV_RELEASE", -+ "NETDEV_NOTIFY_PEERS", -+ "NETDEV_JOIN", -+}; -+ -+const char *netdev_evt_str(int netdev_event) -+{ -+ if (netdev_event < 0 -+ || netdev_event >= ARRAY_SIZE(netdev_event_strings)) -+ return "bad event num"; -+ return netdev_event_strings[netdev_event]; -+} -diff --git a/net/netfilter/xt_qtaguid_print.h b/net/netfilter/xt_qtaguid_print.h -new file mode 100644 -index 00000000..b63871a0 ---- /dev/null -+++ b/net/netfilter/xt_qtaguid_print.h -@@ -0,0 +1,120 @@ -+/* -+ * Pretty printing Support for iptables xt_qtaguid module. -+ * -+ * (C) 2011 Google, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef __XT_QTAGUID_PRINT_H__ -+#define __XT_QTAGUID_PRINT_H__ -+ -+#include "xt_qtaguid_internal.h" -+ -+#ifdef DDEBUG -+ -+char *pp_tag_t(tag_t *tag); -+char *pp_data_counters(struct data_counters *dc, bool showValues); -+char *pp_tag_node(struct tag_node *tn); -+char *pp_tag_ref(struct tag_ref *tr); -+char *pp_tag_stat(struct tag_stat *ts); -+char *pp_iface_stat(struct iface_stat *is); -+char *pp_sock_tag(struct sock_tag *st); -+char *pp_uid_tag_data(struct uid_tag_data *qtd); -+char *pp_proc_qtu_data(struct proc_qtu_data *pqd); -+ -+/*------------------------------------------*/ -+void prdebug_sock_tag_list(int indent_level, -+ struct list_head *sock_tag_list); -+void prdebug_sock_tag_tree(int indent_level, -+ struct rb_root *sock_tag_tree); -+void prdebug_proc_qtu_data_tree(int indent_level, -+ struct rb_root *proc_qtu_data_tree); -+void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree); -+void prdebug_uid_tag_data_tree(int indent_level, -+ struct rb_root *uid_tag_data_tree); -+void prdebug_tag_stat_tree(int indent_level, -+ struct rb_root *tag_stat_tree); -+void prdebug_iface_stat_list(int indent_level, -+ struct list_head *iface_stat_list); -+ -+#else -+ -+/*------------------------------------------*/ -+static inline char *pp_tag_t(tag_t *tag) -+{ -+ return NULL; -+} -+static inline char *pp_data_counters(struct data_counters *dc, bool showValues) -+{ -+ return NULL; -+} -+static inline char *pp_tag_node(struct tag_node *tn) -+{ -+ return NULL; -+} -+static inline char *pp_tag_ref(struct tag_ref *tr) -+{ -+ return NULL; -+} -+static inline char *pp_tag_stat(struct tag_stat *ts) -+{ -+ return NULL; -+} -+static inline char *pp_iface_stat(struct iface_stat *is) -+{ -+ return NULL; -+} -+static inline char *pp_sock_tag(struct sock_tag *st) -+{ -+ return NULL; -+} -+static inline char *pp_uid_tag_data(struct uid_tag_data *qtd) -+{ -+ return NULL; -+} -+static inline char *pp_proc_qtu_data(struct proc_qtu_data *pqd) -+{ -+ return NULL; -+} -+ -+/*------------------------------------------*/ -+static inline -+void prdebug_sock_tag_list(int indent_level, -+ struct list_head *sock_tag_list) -+{ -+} -+static inline -+void prdebug_sock_tag_tree(int indent_level, -+ struct rb_root *sock_tag_tree) -+{ -+} -+static inline -+void prdebug_proc_qtu_data_tree(int indent_level, -+ struct rb_root *proc_qtu_data_tree) -+{ -+} -+static inline -+void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree) -+{ -+} -+static inline -+void prdebug_uid_tag_data_tree(int indent_level, -+ struct rb_root *uid_tag_data_tree) -+{ -+} -+static inline -+void prdebug_tag_stat_tree(int indent_level, -+ struct rb_root *tag_stat_tree) -+{ -+} -+static inline -+void prdebug_iface_stat_list(int indent_level, -+ struct list_head *iface_stat_list) -+{ -+} -+#endif -+/*------------------------------------------*/ -+const char *netdev_evt_str(int netdev_event); -+#endif /* ifndef __XT_QTAGUID_PRINT_H__ */ -diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c -new file mode 100644 -index 00000000..fb2ef46b ---- /dev/null -+++ b/net/netfilter/xt_quota2.c -@@ -0,0 +1,382 @@ -+/* -+ * xt_quota2 - enhanced xt_quota that can count upwards and in packets -+ * as a minimal accounting match. -+ * by Jan Engelhardt <jengelh@medozas.de>, 2008 -+ * -+ * Originally based on xt_quota.c: -+ * netfilter module to enforce network quotas -+ * Sam Johnston <samj@samj.net> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License; either -+ * version 2 of the License, as published by the Free Software Foundation. -+ */ -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/proc_fs.h> -+#include <linux/skbuff.h> -+#include <linux/spinlock.h> -+#include <asm/atomic.h> -+ -+#include <linux/netfilter/x_tables.h> -+#include <linux/netfilter/xt_quota2.h> -+#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG -+#include <linux/netfilter_ipv4/ipt_ULOG.h> -+#endif -+ -+/** -+ * @lock: lock to protect quota writers from each other -+ */ -+struct xt_quota_counter { -+ u_int64_t quota; -+ spinlock_t lock; -+ struct list_head list; -+ atomic_t ref; -+ char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)]; -+ struct proc_dir_entry *procfs_entry; -+}; -+ -+#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG -+/* Harald's favorite number +1 :D From ipt_ULOG.C */ -+static int qlog_nl_event = 112; -+module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(event_num, -+ "Event number for NETLINK_NFLOG message. 0 disables log." -+ "111 is what ipt_ULOG uses."); -+static struct sock *nflognl; -+#endif -+ -+static LIST_HEAD(counter_list); -+static DEFINE_SPINLOCK(counter_list_lock); -+ -+static struct proc_dir_entry *proc_xt_quota; -+static unsigned int quota_list_perms = S_IRUGO | S_IWUSR; -+static unsigned int quota_list_uid = 0; -+static unsigned int quota_list_gid = 0; -+module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR); -+module_param_named(uid, quota_list_uid, uint, S_IRUGO | S_IWUSR); -+module_param_named(gid, quota_list_gid, uint, S_IRUGO | S_IWUSR); -+ -+ -+#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG -+static void quota2_log(unsigned int hooknum, -+ const struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ const char *prefix) -+{ -+ ulog_packet_msg_t *pm; -+ struct sk_buff *log_skb; -+ size_t size; -+ struct nlmsghdr *nlh; -+ -+ if (!qlog_nl_event) -+ return; -+ -+ size = NLMSG_SPACE(sizeof(*pm)); -+ size = max(size, (size_t)NLMSG_GOODSIZE); -+ log_skb = alloc_skb(size, GFP_ATOMIC); -+ if (!log_skb) { -+ pr_err("xt_quota2: cannot alloc skb for logging\n"); -+ return; -+ } -+ -+ /* NLMSG_PUT() uses "goto nlmsg_failure" */ -+ nlh = NLMSG_PUT(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event, -+ sizeof(*pm)); -+ pm = NLMSG_DATA(nlh); -+ if (skb->tstamp.tv64 == 0) -+ __net_timestamp((struct sk_buff *)skb); -+ pm->data_len = 0; -+ pm->hook = hooknum; -+ if (prefix != NULL) -+ strlcpy(pm->prefix, prefix, sizeof(pm->prefix)); -+ else -+ *(pm->prefix) = '\0'; -+ if (in) -+ strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name)); -+ else -+ pm->indev_name[0] = '\0'; -+ -+ if (out) -+ strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); -+ else -+ pm->outdev_name[0] = '\0'; -+ -+ NETLINK_CB(log_skb).dst_group = 1; -+ pr_debug("throwing 1 packets to netlink group 1\n"); -+ netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC); -+ -+nlmsg_failure: /* Used within NLMSG_PUT() */ -+ pr_debug("xt_quota2: error during NLMSG_PUT\n"); -+} -+#else -+static void quota2_log(unsigned int hooknum, -+ const struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ const char *prefix) -+{ -+} -+#endif /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */ -+ -+static int quota_proc_read(char *page, char **start, off_t offset, -+ int count, int *eof, void *data) -+{ -+ struct xt_quota_counter *e = data; -+ int ret; -+ -+ spin_lock_bh(&e->lock); -+ ret = snprintf(page, PAGE_SIZE, "%llu\n", e->quota); -+ spin_unlock_bh(&e->lock); -+ return ret; -+} -+ -+static int quota_proc_write(struct file *file, const char __user *input, -+ unsigned long size, void *data) -+{ -+ struct xt_quota_counter *e = data; -+ char buf[sizeof("18446744073709551616")]; -+ -+ if (size > sizeof(buf)) -+ size = sizeof(buf); -+ if (copy_from_user(buf, input, size) != 0) -+ return -EFAULT; -+ buf[sizeof(buf)-1] = '\0'; -+ -+ spin_lock_bh(&e->lock); -+ e->quota = simple_strtoull(buf, NULL, 0); -+ spin_unlock_bh(&e->lock); -+ return size; -+} -+ -+static struct xt_quota_counter * -+q2_new_counter(const struct xt_quota_mtinfo2 *q, bool anon) -+{ -+ struct xt_quota_counter *e; -+ unsigned int size; -+ -+ /* Do not need all the procfs things for anonymous counters. */ -+ size = anon ? offsetof(typeof(*e), list) : sizeof(*e); -+ e = kmalloc(size, GFP_KERNEL); -+ if (e == NULL) -+ return NULL; -+ -+ e->quota = q->quota; -+ spin_lock_init(&e->lock); -+ if (!anon) { -+ INIT_LIST_HEAD(&e->list); -+ atomic_set(&e->ref, 1); -+ strlcpy(e->name, q->name, sizeof(e->name)); -+ } -+ return e; -+} -+ -+/** -+ * q2_get_counter - get ref to counter or create new -+ * @name: name of counter -+ */ -+static struct xt_quota_counter * -+q2_get_counter(const struct xt_quota_mtinfo2 *q) -+{ -+ struct proc_dir_entry *p; -+ struct xt_quota_counter *e = NULL; -+ struct xt_quota_counter *new_e; -+ -+ if (*q->name == '\0') -+ return q2_new_counter(q, true); -+ -+ /* No need to hold a lock while getting a new counter */ -+ new_e = q2_new_counter(q, false); -+ if (new_e == NULL) -+ goto out; -+ -+ spin_lock_bh(&counter_list_lock); -+ list_for_each_entry(e, &counter_list, list) -+ if (strcmp(e->name, q->name) == 0) { -+ atomic_inc(&e->ref); -+ spin_unlock_bh(&counter_list_lock); -+ kfree(new_e); -+ pr_debug("xt_quota2: old counter name=%s", e->name); -+ return e; -+ } -+ e = new_e; -+ pr_debug("xt_quota2: new_counter name=%s", e->name); -+ list_add_tail(&e->list, &counter_list); -+ /* The entry having a refcount of 1 is not directly destructible. -+ * This func has not yet returned the new entry, thus iptables -+ * has not references for destroying this entry. -+ * For another rule to try to destroy it, it would 1st need for this -+ * func* to be re-invoked, acquire a new ref for the same named quota. -+ * Nobody will access the e->procfs_entry either. -+ * So release the lock. */ -+ spin_unlock_bh(&counter_list_lock); -+ -+ /* create_proc_entry() is not spin_lock happy */ -+ p = e->procfs_entry = create_proc_entry(e->name, quota_list_perms, -+ proc_xt_quota); -+ -+ if (IS_ERR_OR_NULL(p)) { -+ spin_lock_bh(&counter_list_lock); -+ list_del(&e->list); -+ spin_unlock_bh(&counter_list_lock); -+ goto out; -+ } -+ p->data = e; -+ p->read_proc = quota_proc_read; -+ p->write_proc = quota_proc_write; -+ p->uid = quota_list_uid; -+ p->gid = quota_list_gid; -+ return e; -+ -+ out: -+ kfree(e); -+ return NULL; -+} -+ -+static int quota_mt2_check(const struct xt_mtchk_param *par) -+{ -+ struct xt_quota_mtinfo2 *q = par->matchinfo; -+ -+ pr_debug("xt_quota2: check() flags=0x%04x", q->flags); -+ -+ if (q->flags & ~XT_QUOTA_MASK) -+ return -EINVAL; -+ -+ q->name[sizeof(q->name)-1] = '\0'; -+ if (*q->name == '.' || strchr(q->name, '/') != NULL) { -+ printk(KERN_ERR "xt_quota.3: illegal name\n"); -+ return -EINVAL; -+ } -+ -+ q->master = q2_get_counter(q); -+ if (q->master == NULL) { -+ printk(KERN_ERR "xt_quota.3: memory alloc failure\n"); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static void quota_mt2_destroy(const struct xt_mtdtor_param *par) -+{ -+ struct xt_quota_mtinfo2 *q = par->matchinfo; -+ struct xt_quota_counter *e = q->master; -+ -+ if (*q->name == '\0') { -+ kfree(e); -+ return; -+ } -+ -+ spin_lock_bh(&counter_list_lock); -+ if (!atomic_dec_and_test(&e->ref)) { -+ spin_unlock_bh(&counter_list_lock); -+ return; -+ } -+ -+ list_del(&e->list); -+ remove_proc_entry(e->name, proc_xt_quota); -+ spin_unlock_bh(&counter_list_lock); -+ kfree(e); -+} -+ -+static bool -+quota_mt2(const struct sk_buff *skb, struct xt_action_param *par) -+{ -+ struct xt_quota_mtinfo2 *q = (void *)par->matchinfo; -+ struct xt_quota_counter *e = q->master; -+ bool ret = q->flags & XT_QUOTA_INVERT; -+ -+ spin_lock_bh(&e->lock); -+ if (q->flags & XT_QUOTA_GROW) { -+ /* -+ * While no_change is pointless in "grow" mode, we will -+ * implement it here simply to have a consistent behavior. -+ */ -+ if (!(q->flags & XT_QUOTA_NO_CHANGE)) { -+ e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len; -+ } -+ ret = true; -+ } else { -+ if (e->quota >= skb->len) { -+ if (!(q->flags & XT_QUOTA_NO_CHANGE)) -+ e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len; -+ ret = !ret; -+ } else { -+ /* We are transitioning, log that fact. */ -+ if (e->quota) { -+ quota2_log(par->hooknum, -+ skb, -+ par->in, -+ par->out, -+ q->name); -+ } -+ /* we do not allow even small packets from now on */ -+ e->quota = 0; -+ } -+ } -+ spin_unlock_bh(&e->lock); -+ return ret; -+} -+ -+static struct xt_match quota_mt2_reg[] __read_mostly = { -+ { -+ .name = "quota2", -+ .revision = 3, -+ .family = NFPROTO_IPV4, -+ .checkentry = quota_mt2_check, -+ .match = quota_mt2, -+ .destroy = quota_mt2_destroy, -+ .matchsize = sizeof(struct xt_quota_mtinfo2), -+ .me = THIS_MODULE, -+ }, -+ { -+ .name = "quota2", -+ .revision = 3, -+ .family = NFPROTO_IPV6, -+ .checkentry = quota_mt2_check, -+ .match = quota_mt2, -+ .destroy = quota_mt2_destroy, -+ .matchsize = sizeof(struct xt_quota_mtinfo2), -+ .me = THIS_MODULE, -+ }, -+}; -+ -+static int __init quota_mt2_init(void) -+{ -+ int ret; -+ pr_debug("xt_quota2: init()"); -+ -+#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG -+ nflognl = netlink_kernel_create(&init_net, -+ NETLINK_NFLOG, 1, NULL, -+ NULL, THIS_MODULE); -+ if (!nflognl) -+ return -ENOMEM; -+#endif -+ -+ proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net); -+ if (proc_xt_quota == NULL) -+ return -EACCES; -+ -+ ret = xt_register_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg)); -+ if (ret < 0) -+ remove_proc_entry("xt_quota", init_net.proc_net); -+ pr_debug("xt_quota2: init() %d", ret); -+ return ret; -+} -+ -+static void __exit quota_mt2_exit(void) -+{ -+ xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg)); -+ remove_proc_entry("xt_quota", init_net.proc_net); -+} -+ -+module_init(quota_mt2_init); -+module_exit(quota_mt2_exit); -+MODULE_DESCRIPTION("Xtables: countdown quota match; up counter"); -+MODULE_AUTHOR("Sam Johnston <samj@samj.net>"); -+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("ipt_quota2"); -+MODULE_ALIAS("ip6t_quota2"); -diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c -index 72bb07f5..1e48fcf2 100644 ---- a/net/netfilter/xt_socket.c -+++ b/net/netfilter/xt_socket.c -@@ -35,7 +35,7 @@ - #include <net/netfilter/nf_conntrack.h> - #endif - --static void -+void - xt_socket_put_sk(struct sock *sk) - { - if (sk->sk_state == TCP_TIME_WAIT) -@@ -43,6 +43,7 @@ xt_socket_put_sk(struct sock *sk) - else - sock_put(sk); - } -+EXPORT_SYMBOL(xt_socket_put_sk); - - static int - extract_icmp4_fields(const struct sk_buff *skb, -@@ -101,9 +102,8 @@ extract_icmp4_fields(const struct sk_buff *skb, - return 0; - } - --static bool --socket_match(const struct sk_buff *skb, struct xt_action_param *par, -- const struct xt_socket_mtinfo1 *info) -+struct sock* -+xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par) - { - const struct iphdr *iph = ip_hdr(skb); - struct udphdr _hdr, *hp = NULL; -@@ -120,7 +120,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, - hp = skb_header_pointer(skb, ip_hdrlen(skb), - sizeof(_hdr), &_hdr); - if (hp == NULL) -- return false; -+ return NULL; - - protocol = iph->protocol; - saddr = iph->saddr; -@@ -131,9 +131,9 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, - } else if (iph->protocol == IPPROTO_ICMP) { - if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr, - &sport, &dport)) -- return false; -+ return NULL; - } else { -- return false; -+ return NULL; - } - - #ifdef XT_SOCKET_HAVE_CONNTRACK -@@ -157,6 +157,23 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, - - sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol, - saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY); -+ -+ pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n", -+ protocol, &saddr, ntohs(sport), -+ &daddr, ntohs(dport), -+ &iph->daddr, hp ? ntohs(hp->dest) : 0, sk); -+ -+ return sk; -+} -+EXPORT_SYMBOL(xt_socket_get4_sk); -+ -+static bool -+socket_match(const struct sk_buff *skb, struct xt_action_param *par, -+ const struct xt_socket_mtinfo1 *info) -+{ -+ struct sock *sk; -+ -+ sk = xt_socket_get4_sk(skb, par); - if (sk != NULL) { - bool wildcard; - bool transparent = true; -@@ -179,11 +196,6 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, - sk = NULL; - } - -- pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n", -- protocol, &saddr, ntohs(sport), -- &daddr, ntohs(dport), -- &iph->daddr, hp ? ntohs(hp->dest) : 0, sk); -- - return (sk != NULL); - } - -@@ -255,8 +267,8 @@ extract_icmp6_fields(const struct sk_buff *skb, - return 0; - } - --static bool --socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) -+struct sock* -+xt_socket_get6_sk(const struct sk_buff *skb, struct xt_action_param *par) - { - struct ipv6hdr *iph = ipv6_hdr(skb); - struct udphdr _hdr, *hp = NULL; -@@ -264,7 +276,6 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) - struct in6_addr *daddr, *saddr; - __be16 dport, sport; - int thoff, tproto; -- const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; - - tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); - if (tproto < 0) { -@@ -276,7 +287,7 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) - hp = skb_header_pointer(skb, thoff, - sizeof(_hdr), &_hdr); - if (hp == NULL) -- return false; -+ return NULL; - - saddr = &iph->saddr; - sport = hp->source; -@@ -286,13 +297,30 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) - } else if (tproto == IPPROTO_ICMPV6) { - if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr, - &sport, &dport)) -- return false; -+ return NULL; - } else { -- return false; -+ return NULL; - } - - sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto, - saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY); -+ pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu " -+ "(orig %pI6:%hu) sock %p\n", -+ tproto, saddr, ntohs(sport), -+ daddr, ntohs(dport), -+ &iph->daddr, hp ? ntohs(hp->dest) : 0, sk); -+ return sk; -+} -+EXPORT_SYMBOL(xt_socket_get6_sk); -+ -+static bool -+socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) -+{ -+ struct sock *sk; -+ const struct xt_socket_mtinfo1 *info; -+ -+ info = (struct xt_socket_mtinfo1 *) par->matchinfo; -+ sk = xt_socket_get6_sk(skb, par); - if (sk != NULL) { - bool wildcard; - bool transparent = true; -@@ -315,12 +343,6 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) - sk = NULL; - } - -- pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu " -- "(orig %pI6:%hu) sock %p\n", -- tproto, saddr, ntohs(sport), -- daddr, ntohs(dport), -- &iph->daddr, hp ? ntohs(hp->dest) : 0, sk); -- - return (sk != NULL); - } - #endif -diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig -index 78efe895..8e12c8a2 100644 ---- a/net/rfkill/Kconfig -+++ b/net/rfkill/Kconfig -@@ -10,6 +10,11 @@ menuconfig RFKILL - To compile this driver as a module, choose M here: the - module will be called rfkill. - -+config RFKILL_PM -+ bool "Power off on suspend" -+ depends on RFKILL && PM -+ default y -+ - # LED trigger support - config RFKILL_LEDS - bool -diff --git a/net/rfkill/core.c b/net/rfkill/core.c -index f9749617..04afd89a 100644 ---- a/net/rfkill/core.c -+++ b/net/rfkill/core.c -@@ -770,6 +770,7 @@ void rfkill_pause_polling(struct rfkill *rfkill) - } - EXPORT_SYMBOL(rfkill_pause_polling); - -+#ifdef CONFIG_RFKILL_PM - void rfkill_resume_polling(struct rfkill *rfkill) - { - BUG_ON(!rfkill); -@@ -804,14 +805,17 @@ static int rfkill_resume(struct device *dev) - - return 0; - } -+#endif - - static struct class rfkill_class = { - .name = "rfkill", - .dev_release = rfkill_release, - .dev_attrs = rfkill_dev_attrs, - .dev_uevent = rfkill_dev_uevent, -+#ifdef CONFIG_RFKILL_PM - .suspend = rfkill_suspend, - .resume = rfkill_resume, -+#endif - }; - - bool rfkill_blocked(struct rfkill *rfkill) -diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig -index 2e4444fe..8db24da2 100644 ---- a/net/wireless/Kconfig -+++ b/net/wireless/Kconfig -@@ -160,3 +160,14 @@ config LIB80211_DEBUG - from lib80211. - - If unsure, say N. -+ -+config CFG80211_ALLOW_RECONNECT -+ bool "Allow reconnect while already connected" -+ depends on CFG80211 -+ default n -+ help -+ cfg80211 stack doesn't allow to connect if you are already -+ connected. This option allows to make a connection in this case. -+ -+ Select this option ONLY for wlan drivers that are specifically -+ built for such purposes. -diff --git a/net/wireless/scan.c b/net/wireless/scan.c -index 70faadf1..e40104f5 100644 ---- a/net/wireless/scan.c -+++ b/net/wireless/scan.c -@@ -18,7 +18,7 @@ - #include "nl80211.h" - #include "wext-compat.h" - --#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) -+#define IEEE80211_SCAN_RESULT_EXPIRE (3 * HZ) - - void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) - { -diff --git a/net/wireless/sme.c b/net/wireless/sme.c -index f7e937ff..bbbed736 100644 ---- a/net/wireless/sme.c -+++ b/net/wireless/sme.c -@@ -689,8 +689,10 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, - wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) - return; - -+#ifndef CONFIG_CFG80211_ALLOW_RECONNECT - if (wdev->sme_state != CFG80211_SME_CONNECTED) - return; -+#endif - - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); -@@ -767,10 +769,14 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, - - ASSERT_WDEV_LOCK(wdev); - -+#ifndef CONFIG_CFG80211_ALLOW_RECONNECT - if (wdev->sme_state != CFG80211_SME_IDLE) - return -EALREADY; - - if (WARN_ON(wdev->connect_keys)) { -+#else -+ if (wdev->connect_keys) { -+#endif - kfree(wdev->connect_keys); - wdev->connect_keys = NULL; - } -diff --git a/samples/uhid/Makefile b/samples/uhid/Makefile -new file mode 100644 -index 00000000..c95a6965 ---- /dev/null -+++ b/samples/uhid/Makefile -@@ -0,0 +1,10 @@ -+# kbuild trick to avoid linker error. Can be omitted if a module is built. -+obj- := dummy.o -+ -+# List of programs to build -+hostprogs-y := uhid-example -+ -+# Tell kbuild to always build the programs -+always := $(hostprogs-y) -+ -+HOSTCFLAGS_uhid-example.o += -I$(objtree)/usr/include -diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c -new file mode 100644 -index 00000000..03ce3c05 ---- /dev/null -+++ b/samples/uhid/uhid-example.c -@@ -0,0 +1,381 @@ -+/* -+ * UHID Example -+ * -+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com> -+ * -+ * The code may be used by anyone for any purpose, -+ * and can serve as a starting point for developing -+ * applications using uhid. -+ */ -+ -+/* UHID Example -+ * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this -+ * program as root and then use the following keys to control the mouse: -+ * q: Quit the application -+ * 1: Toggle left button (down, up, ...) -+ * 2: Toggle right button -+ * 3: Toggle middle button -+ * a: Move mouse left -+ * d: Move mouse right -+ * w: Move mouse up -+ * s: Move mouse down -+ * r: Move wheel up -+ * f: Move wheel down -+ * -+ * If uhid is not available as /dev/uhid, then you can pass a different path as -+ * first argument. -+ * If <linux/uhid.h> is not installed in /usr, then compile this with: -+ * gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c -+ * And ignore the warning about kernel headers. However, it is recommended to -+ * use the installed uhid.h if available. -+ */ -+ -+#include <errno.h> -+#include <fcntl.h> -+#include <poll.h> -+#include <stdbool.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <termios.h> -+#include <unistd.h> -+#include <linux/uhid.h> -+ -+/* HID Report Desciptor -+ * We emulate a basic 3 button mouse with wheel. This is the report-descriptor -+ * as the kernel will parse it: -+ * -+ * INPUT[INPUT] -+ * Field(0) -+ * Physical(GenericDesktop.Pointer) -+ * Application(GenericDesktop.Mouse) -+ * Usage(3) -+ * Button.0001 -+ * Button.0002 -+ * Button.0003 -+ * Logical Minimum(0) -+ * Logical Maximum(1) -+ * Report Size(1) -+ * Report Count(3) -+ * Report Offset(0) -+ * Flags( Variable Absolute ) -+ * Field(1) -+ * Physical(GenericDesktop.Pointer) -+ * Application(GenericDesktop.Mouse) -+ * Usage(3) -+ * GenericDesktop.X -+ * GenericDesktop.Y -+ * GenericDesktop.Wheel -+ * Logical Minimum(-128) -+ * Logical Maximum(127) -+ * Report Size(8) -+ * Report Count(3) -+ * Report Offset(8) -+ * Flags( Variable Relative ) -+ * -+ * This is the mapping that we expect: -+ * Button.0001 ---> Key.LeftBtn -+ * Button.0002 ---> Key.RightBtn -+ * Button.0003 ---> Key.MiddleBtn -+ * GenericDesktop.X ---> Relative.X -+ * GenericDesktop.Y ---> Relative.Y -+ * GenericDesktop.Wheel ---> Relative.Wheel -+ * -+ * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc -+ * This file should print the same information as showed above. -+ */ -+ -+static unsigned char rdesc[] = { -+ 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, -+ 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, -+ 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, -+ 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, -+ 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, -+ 0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, -+ 0x81, 0x06, 0xc0, 0xc0, -+}; -+ -+static int uhid_write(int fd, const struct uhid_event *ev) -+{ -+ ssize_t ret; -+ -+ ret = write(fd, ev, sizeof(*ev)); -+ if (ret < 0) { -+ fprintf(stderr, "Cannot write to uhid: %m\n"); -+ return -errno; -+ } else if (ret != sizeof(*ev)) { -+ fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n", -+ ret, sizeof(ev)); -+ return -EFAULT; -+ } else { -+ return 0; -+ } -+} -+ -+static int create(int fd) -+{ -+ struct uhid_event ev; -+ -+ memset(&ev, 0, sizeof(ev)); -+ ev.type = UHID_CREATE; -+ strcpy((char*)ev.u.create.name, "test-uhid-device"); -+ ev.u.create.rd_data = rdesc; -+ ev.u.create.rd_size = sizeof(rdesc); -+ ev.u.create.bus = BUS_USB; -+ ev.u.create.vendor = 0x15d9; -+ ev.u.create.product = 0x0a37; -+ ev.u.create.version = 0; -+ ev.u.create.country = 0; -+ -+ return uhid_write(fd, &ev); -+} -+ -+static void destroy(int fd) -+{ -+ struct uhid_event ev; -+ -+ memset(&ev, 0, sizeof(ev)); -+ ev.type = UHID_DESTROY; -+ -+ uhid_write(fd, &ev); -+} -+ -+static int event(int fd) -+{ -+ struct uhid_event ev; -+ ssize_t ret; -+ -+ memset(&ev, 0, sizeof(ev)); -+ ret = read(fd, &ev, sizeof(ev)); -+ if (ret == 0) { -+ fprintf(stderr, "Read HUP on uhid-cdev\n"); -+ return -EFAULT; -+ } else if (ret < 0) { -+ fprintf(stderr, "Cannot read uhid-cdev: %m\n"); -+ return -errno; -+ } else if (ret != sizeof(ev)) { -+ fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n", -+ ret, sizeof(ev)); -+ return -EFAULT; -+ } -+ -+ switch (ev.type) { -+ case UHID_START: -+ fprintf(stderr, "UHID_START from uhid-dev\n"); -+ break; -+ case UHID_STOP: -+ fprintf(stderr, "UHID_STOP from uhid-dev\n"); -+ break; -+ case UHID_OPEN: -+ fprintf(stderr, "UHID_OPEN from uhid-dev\n"); -+ break; -+ case UHID_CLOSE: -+ fprintf(stderr, "UHID_CLOSE from uhid-dev\n"); -+ break; -+ case UHID_OUTPUT: -+ fprintf(stderr, "UHID_OUTPUT from uhid-dev\n"); -+ break; -+ case UHID_OUTPUT_EV: -+ fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n"); -+ break; -+ default: -+ fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type); -+ } -+ -+ return 0; -+} -+ -+static bool btn1_down; -+static bool btn2_down; -+static bool btn3_down; -+static signed char abs_hor; -+static signed char abs_ver; -+static signed char wheel; -+ -+static int send_event(int fd) -+{ -+ struct uhid_event ev; -+ -+ memset(&ev, 0, sizeof(ev)); -+ ev.type = UHID_INPUT; -+ ev.u.input.size = 4; -+ -+ if (btn1_down) -+ ev.u.input.data[0] |= 0x1; -+ if (btn2_down) -+ ev.u.input.data[0] |= 0x2; -+ if (btn3_down) -+ ev.u.input.data[0] |= 0x4; -+ -+ ev.u.input.data[1] = abs_hor; -+ ev.u.input.data[2] = abs_ver; -+ ev.u.input.data[3] = wheel; -+ -+ return uhid_write(fd, &ev); -+} -+ -+static int keyboard(int fd) -+{ -+ char buf[128]; -+ ssize_t ret, i; -+ -+ ret = read(STDIN_FILENO, buf, sizeof(buf)); -+ if (ret == 0) { -+ fprintf(stderr, "Read HUP on stdin\n"); -+ return -EFAULT; -+ } else if (ret < 0) { -+ fprintf(stderr, "Cannot read stdin: %m\n"); -+ return -errno; -+ } -+ -+ for (i = 0; i < ret; ++i) { -+ switch (buf[i]) { -+ case '1': -+ btn1_down = !btn1_down; -+ ret = send_event(fd); -+ if (ret) -+ return ret; -+ break; -+ case '2': -+ btn2_down = !btn2_down; -+ ret = send_event(fd); -+ if (ret) -+ return ret; -+ break; -+ case '3': -+ btn3_down = !btn3_down; -+ ret = send_event(fd); -+ if (ret) -+ return ret; -+ break; -+ case 'a': -+ abs_hor = -20; -+ ret = send_event(fd); -+ abs_hor = 0; -+ if (ret) -+ return ret; -+ break; -+ case 'd': -+ abs_hor = 20; -+ ret = send_event(fd); -+ abs_hor = 0; -+ if (ret) -+ return ret; -+ break; -+ case 'w': -+ abs_ver = -20; -+ ret = send_event(fd); -+ abs_ver = 0; -+ if (ret) -+ return ret; -+ break; -+ case 's': -+ abs_ver = 20; -+ ret = send_event(fd); -+ abs_ver = 0; -+ if (ret) -+ return ret; -+ break; -+ case 'r': -+ wheel = 1; -+ ret = send_event(fd); -+ wheel = 0; -+ if (ret) -+ return ret; -+ break; -+ case 'f': -+ wheel = -1; -+ ret = send_event(fd); -+ wheel = 0; -+ if (ret) -+ return ret; -+ break; -+ case 'q': -+ return -ECANCELED; -+ default: -+ fprintf(stderr, "Invalid input: %c\n", buf[i]); -+ } -+ } -+ -+ return 0; -+} -+ -+int main(int argc, char **argv) -+{ -+ int fd; -+ const char *path = "/dev/uhid"; -+ struct pollfd pfds[2]; -+ int ret; -+ struct termios state; -+ -+ ret = tcgetattr(STDIN_FILENO, &state); -+ if (ret) { -+ fprintf(stderr, "Cannot get tty state\n"); -+ } else { -+ state.c_lflag &= ~ICANON; -+ state.c_cc[VMIN] = 1; -+ ret = tcsetattr(STDIN_FILENO, TCSANOW, &state); -+ if (ret) -+ fprintf(stderr, "Cannot set tty state\n"); -+ } -+ -+ if (argc >= 2) { -+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { -+ fprintf(stderr, "Usage: %s [%s]\n", argv[0], path); -+ return EXIT_SUCCESS; -+ } else { -+ path = argv[1]; -+ } -+ } -+ -+ fprintf(stderr, "Open uhid-cdev %s\n", path); -+ fd = open(path, O_RDWR | O_CLOEXEC); -+ if (fd < 0) { -+ fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path); -+ return EXIT_FAILURE; -+ } -+ -+ fprintf(stderr, "Create uhid device\n"); -+ ret = create(fd); -+ if (ret) { -+ close(fd); -+ return EXIT_FAILURE; -+ } -+ -+ pfds[0].fd = STDIN_FILENO; -+ pfds[0].events = POLLIN; -+ pfds[1].fd = fd; -+ pfds[1].events = POLLIN; -+ -+ fprintf(stderr, "Press 'q' to quit...\n"); -+ while (1) { -+ ret = poll(pfds, 2, -1); -+ if (ret < 0) { -+ fprintf(stderr, "Cannot poll for fds: %m\n"); -+ break; -+ } -+ if (pfds[0].revents & POLLHUP) { -+ fprintf(stderr, "Received HUP on stdin\n"); -+ break; -+ } -+ if (pfds[1].revents & POLLHUP) { -+ fprintf(stderr, "Received HUP on uhid-cdev\n"); -+ break; -+ } -+ -+ if (pfds[0].revents & POLLIN) { -+ ret = keyboard(fd); -+ if (ret) -+ break; -+ } -+ if (pfds[1].revents & POLLIN) { -+ ret = event(fd); -+ if (ret) -+ break; -+ } -+ } -+ -+ fprintf(stderr, "Destroy uhid device\n"); -+ destroy(fd); -+ return EXIT_SUCCESS; -+} -diff --git a/security/capability.c b/security/capability.c -index 5bb21b1c..fc991bca 100644 ---- a/security/capability.c -+++ b/security/capability.c -@@ -12,6 +12,26 @@ - - #include <linux/security.h> - -+static int cap_binder_set_context_mgr(struct task_struct *mgr) -+{ -+ return 0; -+} -+ -+static int cap_binder_transaction(struct task_struct *from, struct task_struct *to) -+{ -+ return 0; -+} -+ -+static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to) -+{ -+ return 0; -+} -+ -+static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) -+{ -+ return 0; -+} -+ - static int cap_syslog(int type) - { - return 0; -@@ -877,6 +897,10 @@ static void cap_audit_rule_free(void *lsmrule) - - void __init security_fixup_ops(struct security_operations *ops) - { -+ set_to_cap_if_null(ops, binder_set_context_mgr); -+ set_to_cap_if_null(ops, binder_transaction); -+ set_to_cap_if_null(ops, binder_transfer_binder); -+ set_to_cap_if_null(ops, binder_transfer_file); - set_to_cap_if_null(ops, ptrace_access_check); - set_to_cap_if_null(ops, ptrace_traceme); - set_to_cap_if_null(ops, capget); -diff --git a/security/commoncap.c b/security/commoncap.c -index 71a166a0..0051ac2d 100644 ---- a/security/commoncap.c -+++ b/security/commoncap.c -@@ -31,6 +31,10 @@ - #include <linux/binfmts.h> - #include <linux/personality.h> - -+#ifdef CONFIG_ANDROID_PARANOID_NETWORK -+#include <linux/android_aid.h> -+#endif -+ - /* - * If a non-root user executes a setuid-root binary in - * !secure(SECURE_NOROOT) mode, then we raise capabilities. -@@ -76,6 +80,13 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb) - int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, - int cap, int audit) - { -+#ifdef CONFIG_ANDROID_PARANOID_NETWORK -+ if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW)) -+ return 0; -+ if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN)) -+ return 0; -+#endif -+ - for (;;) { - /* The creator of the user namespace has all caps. */ - if (targ_ns != &init_user_ns && targ_ns->creator == cred->user) -diff --git a/security/security.c b/security/security.c -index bf619ffc..cecd55e5 100644 ---- a/security/security.c -+++ b/security/security.c -@@ -130,6 +130,26 @@ int __init register_security(struct security_operations *ops) - - /* Security operations */ - -+int security_binder_set_context_mgr(struct task_struct *mgr) -+{ -+ return security_ops->binder_set_context_mgr(mgr); -+} -+ -+int security_binder_transaction(struct task_struct *from, struct task_struct *to) -+{ -+ return security_ops->binder_transaction(from, to); -+} -+ -+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to) -+{ -+ return security_ops->binder_transfer_binder(from, to); -+} -+ -+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) -+{ -+ return security_ops->binder_transfer_file(from, to, file); -+} -+ - int security_ptrace_access_check(struct task_struct *child, unsigned int mode) - { - return security_ops->ptrace_access_check(child, mode); -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index 56262223..1ae096ed 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -1818,6 +1818,67 @@ static inline u32 open_file_to_av(struct file *file) - - /* Hook functions begin here. */ - -+static int selinux_binder_set_context_mgr(struct task_struct *mgr) -+{ -+ u32 mysid = current_sid(); -+ u32 mgrsid = task_sid(mgr); -+ -+ return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL); -+} -+ -+static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to) -+{ -+ u32 mysid = current_sid(); -+ u32 fromsid = task_sid(from); -+ u32 tosid = task_sid(to); -+ int rc; -+ -+ if (mysid != fromsid) { -+ rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL); -+ if (rc) -+ return rc; -+ } -+ -+ return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL); -+} -+ -+static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to) -+{ -+ u32 fromsid = task_sid(from); -+ u32 tosid = task_sid(to); -+ return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL); -+} -+ -+static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file) -+{ -+ u32 sid = task_sid(to); -+ struct file_security_struct *fsec = file->f_security; -+ struct inode *inode = file->f_path.dentry->d_inode; -+ struct inode_security_struct *isec = inode->i_security; -+ struct common_audit_data ad; -+ struct selinux_audit_data sad = {0,}; -+ int rc; -+ -+ COMMON_AUDIT_DATA_INIT(&ad, PATH); -+ ad.u.path = file->f_path; -+ ad.selinux_audit_data = &sad; -+ -+ if (sid != fsec->sid) { -+ rc = avc_has_perm(sid, fsec->sid, -+ SECCLASS_FD, -+ FD__USE, -+ &ad); -+ if (rc) -+ return rc; -+ } -+ -+ if (unlikely(IS_PRIVATE(inode))) -+ return 0; -+ -+ return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), -+ &ad); -+} -+ - static int selinux_ptrace_access_check(struct task_struct *child, - unsigned int mode) - { -@@ -5523,6 +5584,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) - static struct security_operations selinux_ops = { - .name = "selinux", - -+ .binder_set_context_mgr = selinux_binder_set_context_mgr, -+ .binder_transaction = selinux_binder_transaction, -+ .binder_transfer_binder = selinux_binder_transfer_binder, -+ .binder_transfer_file = selinux_binder_transfer_file, -+ - .ptrace_access_check = selinux_ptrace_access_check, - .ptrace_traceme = selinux_ptrace_traceme, - .capget = selinux_capget, -diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h -index b8c53723..4a4a9aeb 100644 ---- a/security/selinux/include/classmap.h -+++ b/security/selinux/include/classmap.h -@@ -149,5 +149,6 @@ struct security_class_mapping secclass_map[] = { - { "kernel_service", { "use_as_override", "create_files_as", NULL } }, - { "tun_socket", - { COMMON_SOCK_PERMS, NULL } }, -+ { "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } }, - { NULL } - }; -diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig -index 885683a3..46caf837 100644 ---- a/sound/arm/Kconfig -+++ b/sound/arm/Kconfig -@@ -11,6 +11,45 @@ menuconfig SND_ARM - - if SND_ARM - -+config SND_AK_PCM -+ tristate "Anyka ADC/DAC sound driver" -+ select SND_PCM -+ help -+ ALSA sound driver fo the AK ADC/DAC. -+ -+choice -+ prompt "Select codec" -+ depends on SND_AK_PCM -+ -+config CODEC_AK39 -+ bool "AK39 internal codec" -+ depends on SND_AK_PCM -+ help -+ ak39 SoC audio codec. -+ -+endchoice -+ -+choice -+ prompt "HP/Speaker switch mode" -+ depends on SND_AK_PCM -+ -+config SPKHP_SWITCH_AUTO -+ bool "auto switch in audio driver(default, for both linux and android)" -+ -+config SPKHP_SWITCH_MIXER -+ bool "notify,but not switch in audio driver(with ALSA lib amixer)" -+ -+config SPKHP_SWITCH_UEVENT -+ bool "detect HP by UEVENT(only for android)" -+ -+endchoice -+ -+config SUPPORT_AEC -+ bool "Support Accoustic Echo Cancllation" -+ depends on SND_AK_PCM -+ help -+ Support Accoustic Echo Cancllation. -+ - config SND_ARMAACI - tristate "ARM PrimeCell PL041 AC Link support" - depends on ARM_AMBA -diff --git a/sound/arm/Makefile b/sound/arm/Makefile -index 8c0c851d..cb258247 100644 ---- a/sound/arm/Makefile -+++ b/sound/arm/Makefile -@@ -14,3 +14,9 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o - - obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o - snd-pxa2xx-ac97-objs := pxa2xx-ac97.o -+ -+obj-$(CONFIG_SND_AK_PCM) += snd-akpcm.o -+snd-akpcm-objs := ak_pcm.o -+ -+obj-$(CONFIG_CODEC_AK39) += snd-codec-ak39.o -+snd-codec-ak39-objs := ak39_codec.o -diff --git a/sound/arm/ak39_codec.c b/sound/arm/ak39_codec.c -new file mode 100644 -index 00000000..cea436db ---- /dev/null -+++ b/sound/arm/ak39_codec.c -@@ -0,0 +1,2219 @@ -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/err.h> -+#include <linux/platform_device.h> -+#include <linux/jiffies.h> -+#include <linux/slab.h> -+#include <linux/time.h> -+#include <linux/wait.h> -+#include <linux/hrtimer.h> -+#include <linux/math64.h> -+#include <linux/module.h> -+#include <linux/completion.h> -+#include <linux/irq.h> -+#include <linux/workqueue.h> -+#include <asm/bitops.h> -+#include <sound/control.h> -+#include <sound/info.h> -+#include <linux/cpufreq.h> -+#include <linux/interrupt.h> -+#include <sound/ak_pcm.h> -+ -+ -+#include <plat/l2.h> -+#include <mach/ak_codec.h> -+#include <mach/gpio.h> -+#include <mach/clock.h> -+#include <linux/vmalloc.h> -+ -+ -+//#define SND_CODEC_DBG -+ -+#ifdef SND_CODEC_DBG -+#ifdef __KERNEL__ -+#define PDEBUG(fmt, args...) printk(KERN_INFO "ak39 codec:" fmt, ##args) -+#else -+#define PDEBUG(fmt, args...) fprintf(stderr, "%s %d:" fmt,__FILE__, __LINE__, ## args) -+#endif -+#else -+#define PDEBUG(fmt, args...) -+#endif -+ -+ -+enum mixer_vol_port { -+ MIXER_PORT_HP_VOL = 0, -+ MIXER_PORT_LINEIN_VOL, -+ MIXER_PORT_MIC_VOL, -+ MIXER_PORT_VOL_COUNT, -+}; -+ -+ -+enum mixer_dst_port { -+ MIXER_ADDR_DST_HP = 0, -+ MIXER_ADDR_DST_ADC2, -+ MIXER_DST_COUNT, -+}; -+ -+enum mixer_detect_port { -+ MIXER_ADDR_HPDET = 0, -+ MIXER_ADDR_MICDET, -+ MIXER_ADDR_LINEINDET, -+ MIXER_SWITCH_COUNT, -+}; -+ -+ -+enum mixer_outmode { -+ MIXER_ADDR_OUTMODE_DAC = 0, -+ MIXER_OUTMODE_COUNT, -+}; -+ -+enum mixer_chnl_duration { -+ MIXER_ADDR_PLAY_DURATION = 0, -+ MIXER_DURATION_COUNT, -+}; -+ -+#define MAX_DACCLK 24000000 -+ -+#define HEADPHONE_DEFAULT_VOL (HEADPHONE_GAIN_MAX - 2) -+#define LINEIN_DEFAULT_VOL 10 -+#define MIC_DEFAULT_VOL 6 -+ -+#define PLAYMODE_STATUS_HP (1) -+#define PLAYMODE_STATUS_SPEAKER (2) -+ -+#define OUTMODE_AUTO (0) -+#define OUTMODE_HP (1) -+#define OUTMODE_LINEOUT (2) -+#define OUTMODE_MIN OUTMODE_AUTO -+#define OUTMODE_MAX OUTMODE_HP -+ -+#define CHNLDURATION_CONSTANT 0 -+#define CHNLDURATION_EVEROPEN 1 -+#define CHNLDURATION_MIN CHNLDURATION_CONSTANT -+#define CHNLDURATION_MAX CHNLDURATION_EVEROPEN -+ -+struct ak39_codec { -+ struct ak_codec_dai dai; -+ void __iomem *analog_ctrl_base; -+ void __iomem *adda_cfg_base; -+ struct delayed_work d_work; -+ -+ int mixer_volume[MIXER_PORT_VOL_COUNT]; -+ int mixer_route[MIXER_DST_COUNT]; -+ int mixer_switch[MIXER_SWITCH_COUNT]; -+ int mixer_outmode[MIXER_OUTMODE_COUNT]; -+ int mixer_ch_duration[MIXER_DURATION_COUNT]; -+ -+ struct gpio_info hpdet_gpio; -+ struct gpio_info spkrshdn_gpio; -+ struct gpio_info hpmute_gpio; -+ -+ int hp_det_irq; -+ int irq_hp_on_type; -+ int hp_on_value; -+ int playmode; -+ int hpmute_en_val; -+ -+ unsigned used_hp_mute:1; // whether to use hardware de-pipa or not -+ unsigned outputing:1; -+ unsigned dac_state:1; -+ unsigned adc2_state:1; -+}; -+ -+struct ak39_volume_info -+{ -+ int vol_default; -+ int vol_min; -+ int vol_max; -+}; -+ -+ -+#define VOL_INFO_DEFAULT 0 -+#define VOL_INFO_MIN 1 -+#define VOL_INFO_MAX 2 -+ -+static struct ak39_volume_info vol_info[MIXER_PORT_VOL_COUNT] = { -+ [MIXER_PORT_HP_VOL] = { -+ .vol_default = HEADPHONE_DEFAULT_VOL, -+ .vol_min = HEADPHONE_GAIN_MIN, -+ .vol_max = HEADPHONE_GAIN_MAX, -+ }, -+ [MIXER_PORT_LINEIN_VOL] = { -+ .vol_default = LINEIN_DEFAULT_VOL, -+ .vol_min = LINEIN_GAIN_MIN, -+ .vol_max = LINEIN_GAIN_MAX, -+ }, -+ [MIXER_PORT_MIC_VOL] = { -+ .vol_default = MIC_DEFAULT_VOL, -+ .vol_min = MIC_GAIN_MIN, -+ .vol_max = MIC_GAIN_MAX, -+ } -+ -+}; -+ -+static int default_route[MIXER_DST_COUNT] = { -+ [MIXER_ADDR_DST_HP] = SOURCE_DAC, -+ [MIXER_ADDR_DST_ADC2] = SOURCE_MIC, -+}; -+ -+extern unsigned long playback_statu; -+ -+#if 0 -+static void dump_codec_reg(struct ak39_codec *codec) -+{ -+ u32 reg_val; -+ -+ reg_val = REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG); -+ printk("\nCLOCK_CTRL_REG(0x0800%04x):%08x.\n", CLOCK_CTRL_REG, reg_val); -+ -+ reg_val = REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG); -+ printk("HIGHSPEED_CLOCK_CTRL_REG(0x0800%04x):%08x.\n", HIGHSPEED_CLOCK_CTRL_REG, reg_val); -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ printk("\nANALOG_CTRL_REG1(0x0800%04x):%08x.\n", ANALOG_CTRL_REG1, reg_val); -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ printk("ANALOG_CTRL_REG2(0x0800%04x):%08x.\n", ANALOG_CTRL_REG2, reg_val); -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG3); -+ printk("ANALOG_CTRL_REG3(0x0800%04x):%08x.\n", ANALOG_CTRL_REG3, reg_val); -+ -+ reg_val = REG32(codec->adda_cfg_base + ADC2_CONFIG_REG); -+ printk("ADC2_CONFIG_REG(0x2011%04x):%08x.\n", ADC2_CONFIG_REG, reg_val); -+ -+ reg_val = REG32(codec->adda_cfg_base + ADC2_DATA_REG); -+ printk("ADC2_DATA_REG(0x2011%04x):%08x.\n", ADC2_DATA_REG, reg_val); -+ -+ reg_val = REG32(codec->adda_cfg_base + DAC_CONFIG_REG); -+ printk("DAC_CONFIG_REG(0x2011%04x):%08x.\n", DAC_CONFIG_REG, reg_val); -+ -+ reg_val = REG32(codec->analog_ctrl_base + ADC1_CONF_REG1); -+ printk("ADC1_CONF_REG1:(0x0800%04x):%08x.\n", ADC1_CONF_REG1, reg_val); -+} -+#endif -+static inline struct ak39_codec *to_ak39_codec(struct ak_codec_dai *dai) -+{ -+ return dai ? container_of(dai, struct ak39_codec, dai): NULL; -+} -+ -+ -+static inline void pd_ref_enable(struct ak39_codec *codec) -+{ -+ u32 reg_val; -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val &= ~PD_REF; //power on codec -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+} -+ -+static inline void pd_ref_disable(struct ak39_codec *codec) -+{ -+ u32 reg_val; -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val |= PD_REF; //power off codec -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+} -+ -+#if 0 -+static void SetHpDisChgCur(unsigned long value) -+{ -+ int reg_val; -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val &= ~(0x7 << 29); -+ reg_val |= (value << 29); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+} -+ -+ -+static void set_cur_pmos(struct ak39_codec *codec, unsigned long value) -+{ -+ int reg_val; -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val &= ~(0xf << 25); -+ reg_val |= (value << 25); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+} -+#endif -+ -+static void set_cur_vcm2_dischg(struct ak39_codec *codec, unsigned long value) -+{ -+ int reg_val; -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val &= ~(0x1f << 4); -+ reg_val |= (value << 4); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+} -+ -+static void set_cur_vcm2(struct ak39_codec *codec, unsigned long value) -+{ -+ int reg_val; -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val &= ~(0x1F << 16); -+ reg_val |= (value << 16); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+} -+ -+ -+/** -+ * @brief select HP in signal -+ * @author -+ * @date -+ * @param[in] (HP_In_Signal)signal: signal desired -+ * @return void -+ */ -+void ak39_set_hp_in(struct ak39_codec *codec, unsigned long signal) -+{ -+ unsigned long reg_val; -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val &= ~(0x7 << 12); -+ reg_val |= ((signal&0x7) << 12); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+} -+ -+ -+/** -+ * @brief set ADC2 source -+ * @author -+ * @date -+ * @param[in] signal: DAC|LINEIN|MIC -+ * @return void -+ */ -+void ak39_set_adc2_in(struct ak39_codec *codec, unsigned long signal) -+{ -+ unsigned long reg_val; -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val &= ~(0x7 << 2); -+ reg_val |= ((signal&0x7) << 2); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+} -+ -+ -+/** -+ * @brief set HP gain -+ * @author -+ * @date -+ * @param[in] x: (0.x)times -+ * @return void -+ */ -+void ak39_set_hp_gain(struct ak39_codec *codec, unsigned long gain) -+{ -+ unsigned long reg_value; -+ unsigned long gain_table[6] = {0x0, 0x18, 0x14, 0x12, 0x11, 0x10}; -+ -+ reg_value = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_value &= ~MASK_HP_GAIN; -+ reg_value |= HP_GAIN(gain_table[gain]); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_value; -+} -+ -+/** -+ * @brief set mic gain -+ * @author -+ * @date -+ * @param[in] gain: 0~7 -+ * @return void -+ */ -+void ak39_set_mic_gain(struct ak39_codec *codec, unsigned long gain) -+{ -+ unsigned long reg_val = 0; -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val &= ~(0x7<<10); -+ reg_val |= ((gain&0x7)<<10); -+ reg_val |= (1<<15); //double Mic gain -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+} -+ -+/** -+ * @brief set linein gain -+ * @author -+ * @date -+ * @param[in] gain: 0~15 -+ * @return void -+ */ -+void ak39_set_linein_gain(struct ak39_codec *codec, unsigned long gain) -+{ -+ unsigned long reg_val = 0; -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val &= ~(0xF<<6); -+ reg_val |= ((gain&0xF)<<6); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+} -+ -+enum depipa_noise_ctrl { -+ DEPIPA_NOISE_NOT_USE, -+ DEPIPA_NOISE_USE_3KOHM_RESISTOR, -+ DEPIPA_NOISE_USE_1KOHM_RESISTOR, -+ DEPIPA_NOISE_USE_MAX_RESISTOR, -+}; -+ -+static void set_bit_depipa_noise_ctrl(struct ak39_codec *codec, int mode) -+{ -+ unsigned long reg_val = 0; -+ -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ -+ if(mode == DEPIPA_NOISE_USE_MAX_RESISTOR) { -+ reg_val |= (PRE_EN1); -+ reg_val |= (PRE_EN2); -+ } else if(mode == DEPIPA_NOISE_USE_3KOHM_RESISTOR) { -+ reg_val |= (PRE_EN1); -+ reg_val &= ~(PRE_EN2); -+ } else if(mode == DEPIPA_NOISE_USE_1KOHM_RESISTOR) { -+ reg_val &= ~(PRE_EN1); -+ reg_val |= (PRE_EN2); -+ } else { -+ reg_val &= ~(PRE_EN1); -+ reg_val &= ~(PRE_EN2); -+ } -+ -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+} -+ -+ -+static void ak39_set_vcm_ref_power(struct ak39_codec *codec, bool bOn) -+{ -+ unsigned long reg_val; -+ if(bOn) -+ { -+ //add power control here for MIC-to-Lineout channel -+ //power on REF -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val &= ~(PD_REF | PL_VCM2 ); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+ -+ //power on vcm2/vcm3 -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val &= ~(PD_VCM2 | PD_VCM3); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+ } -+ else -+ { -+ //power off vcm2/vcm3 -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val |= (PD_VCM2); -+ reg_val |= (PD_VCM3); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+ -+ //power off codec -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val |= (PD_REF | PL_VCM2); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+ } -+} -+ -+ -+/** -+ * @brief power on HP -+ * @author -+ * @date -+ * @param[in] bool poweron or poweroff -+ * @ [in] bool use delay to de-pipa or not -+ * @return void -+ */ -+void ak39_set_hp_power(struct ak39_codec *codec, bool bOn, bool soft_de_pipa) -+{ -+ int reg_value; -+ -+ printk("ak39_set_hp_power %d,soft_de_pipa=%d\n",bOn,soft_de_pipa); -+ if(bOn) -+ { -+// REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) |= (PL_VCM2); -+ set_bit_depipa_noise_ctrl(codec, DEPIPA_NOISE_USE_MAX_RESISTOR); -+ -+ mdelay(10); -+ -+ pd_ref_enable(codec); -+ -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) |= (0x7UL << 29); -+ -+ mdelay(20); -+ reg_value = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_value &= ~(PD1_HP); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_value; -+ -+ mdelay(10); -+ -+ reg_value = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_value &= ~(PD2_HP); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_value; -+ -+ ak39_set_vcm_ref_power(codec, 1); -+ -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~(0x1f << 4); -+ set_cur_vcm2(codec, 0x1e); -+ mdelay(100); -+ -+ set_bit_depipa_noise_ctrl(codec, DEPIPA_NOISE_NOT_USE); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~(RST_DAC); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~(0x7UL << 29); -+ } -+ else -+ { -+ set_bit_depipa_noise_ctrl(codec, DEPIPA_NOISE_USE_3KOHM_RESISTOR); -+ -+ if (!codec->adc2_state) { -+ //off mute -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~(0x7 << 12); -+ // REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) |= (0x1f << 4); -+ -+ ak39_set_vcm_ref_power(codec, 0); -+ set_cur_vcm2_dischg(codec, 0x1f); -+ mdelay(50); -+ } -+ -+ //power off hp -+ reg_value = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_value |= ((PD2_HP)); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_value; -+ -+ //power off hp -+ reg_value = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_value |= (PD1_HP); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_value; -+ } -+} -+ -+ -+/** -+ * @brief set linein interface power -+ * @author -+ * @date -+ * @param[in] bTrue: 1-power on; 0-power off -+ * @return void -+ */ -+static void ak39_set_linein_power(struct ak39_codec *codec, bool bOn) -+{ -+ unsigned long reg_val = 0; -+ if(bOn) -+ { -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val &= ~(1 << 14); //power on the channel -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+ } -+ else -+ { -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val |= (1 << 14); //power off the channel -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+ } -+} -+ -+/** -+ * @brief set DAC to lineout -+ * @author -+ * @date -+ * @param[in] bTrue: 1-connet DACto lineout; 0-disconnect -+ * @return void -+ */ -+static void ak39_set_mic_power(struct ak39_codec *codec, bool bOn) -+{ -+ unsigned long reg_val = 0; -+ if(bOn) -+ { -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val |= VDD_MIC_SEL; -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+ -+ //power on mic interface -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val &= ~(0x1 << 23); //power on differential mic -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+ } -+ else -+ { -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2); -+ reg_val |= (0x1 << 23); //power off differential mic -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) = reg_val; -+ } -+} -+ -+static void ak39_set_sel_vref(struct ak39_codec *codec, bool bOn) -+{ -+ unsigned long reg_val; -+ reg_val = REG32(codec->analog_ctrl_base + ADC1_CONF_REG1); -+ if(bOn) -+ reg_val |= SEL_VREF; -+ else -+ reg_val &= ~SEL_VREF; -+ -+ REG32(codec->analog_ctrl_base + ADC1_CONF_REG1) = reg_val; -+} -+ -+ -+static void set_dac_highspeed(struct ak39_codec *codec, -+ unsigned long sample_rate) -+{ -+ static unsigned long rate_list[] = -+ {8000, 16000, 24000, 48000, 96000}; -+ static unsigned long dac_hclk[sizeof(rate_list)/sizeof(rate_list[0])] = -+ {6, 12, 18, 36, 72}; -+ -+ unsigned long reg_value; -+ unsigned long pllclk; -+ unsigned long hclk_div; -+ unsigned long hclk; -+ unsigned long i; -+ -+ pllclk = ak_get_asic_pll_clk(); -+ pllclk /= 1000000; -+ -+ printk("seths sr %lu,pll %lu\n",sample_rate,pllclk); -+ for(i=0; i < sizeof(rate_list)/sizeof(rate_list[0]); ++i) -+ { -+ if(sample_rate <= rate_list[i]) -+ { -+ break; -+ } -+ } -+ -+ if(sizeof(rate_list)/sizeof(rate_list[0]) == i) -+ { -+ hclk = dac_hclk[i-1]; -+ } -+ else -+ { -+ hclk = dac_hclk[i]; -+ } -+ -+ hclk_div = pllclk / hclk; -+ //04V 3771 chip: when the divider of the DAC CLK is even number, -+ //the DAC MODULE is more steady -+ hclk_div &= ~1; -+ -+ if(0 != hclk_div) -+ { -+ hclk_div = hclk_div - 1; -+ } -+ -+ reg_value = REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG); -+ reg_value &= ~(MASK_DAC_HCLK_DIV); -+ reg_value |= DAC_HSDIV_VLD | DAC_HCLK_DIV(hclk_div); -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) = reg_value; -+ -+ i = 0; -+ while(REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) & (DAC_HSDIV_VLD)) -+ { -+ ++i; -+ if(i > 100000) -+ { -+ printk("set high speed clk reg fail\n"); -+ return ; -+ } -+ } -+} -+ -+static void set_adc_highspeed(struct ak39_codec *codec, -+ unsigned long sample_rate) -+{ -+ unsigned long reg_value; -+ unsigned long pllclk; -+ unsigned long hclk_div; -+ unsigned long hclk; -+ unsigned long i; -+ -+ pllclk = ak_get_asic_pll_clk(); -+ for (i=1; i<=0x40; i++) -+ { -+ hclk = pllclk/i; -+ if ((hclk<=62000000)&&(hclk>=28000000)) -+ { -+ break; -+ } -+ } -+ hclk_div = i-1; -+ -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= ~(1<<29); -+ -+ i = 0; -+ while(REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) & (ADC2_HSDIV_VLD)) -+ { -+ ++i; -+ if(i > 100000) -+ { -+ printk("adc set high speed clk reg fail\n"); -+ return ; -+ } -+ } -+ -+ reg_value = REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG); -+ reg_value &= ~(MASK_ADC2_HCLK_DIV); -+ reg_value |= ADC2_HSDIV_VLD | ADC2_HCLK_DIV(hclk_div); -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) = reg_value; -+ -+ i = 0; -+ while(REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) & (ADC2_HSDIV_VLD)) -+ { -+ ++i; -+ if(i > 100000) -+ { -+ printk("adc set high speed clk reg fail\n"); -+ return ; -+ } -+ } -+ -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) |= (1<<29); -+} -+ -+/** -+ * @brief set ADC2 mode and clk_div -+ * @author -+ * @date -+ * @param[in] des_sr: desired rate to be set -+ * @param[out] mode_sel: reg(0x08000064) bit[12] -+ * @param[out] mclkdiv: reg(0x08000008) bit[11:4] -+ * @return void -+ */ -+static unsigned long get_adc2_osr_div(struct ak39_codec *codec, unsigned char *mode_sel, -+ unsigned char *mclkdiv, unsigned long des_sr) -+{ -+ unsigned short k, max_div; -+ unsigned short OSR_value=256; -+ unsigned long SR_save, out_sr=0; -+ signed long a, b; -+ unsigned long clk168m; -+ unsigned long perfect_pll; -+ -+ clk168m = ak_get_asic_pll_clk(); -+ max_div = 0x40; -+ SR_save = 0; -+ *mode_sel = 0; -+ *mclkdiv = 0; -+ -+ if (des_sr > 24000) -+ { -+ OSR_value = 256; -+ *mode_sel = 1; //48k mode -+ } -+ else -+ { -+ OSR_value = 512; -+ *mode_sel = 0; //16k mode -+ } -+ -+ for(k=0; k<max_div; k++) //DIV -+ { -+ out_sr = clk168m/(k+1)/OSR_value; -+ a = out_sr - des_sr; -+ a = (a>0)? a : (-a); -+ b = SR_save - des_sr; -+ b = (b>0)? b : (-b); -+ if (a<b) -+ { -+ SR_save = out_sr; -+ *mclkdiv = k; -+ -+ perfect_pll = OSR_value * (k+1) *des_sr; -+ } -+ } -+ -+ printk("adc: perfect asic pll clk is:%lu, actual sample rate is %lu.\n", perfect_pll, SR_save); -+ -+ printk( "---ADC clk168m = %lu, SR_save = %lu. des_sr = %lu, div = %d\n",clk168m, SR_save, des_sr, *mclkdiv); -+ return SR_save; -+} -+ -+/** -+ * @brief Get OSR and DACDIV refer to appointed PLL and sample rate -+ * @author -+ * @date -+ * @input des_sr: destination sample rate -+ * @output osrindex: OSR index -+ * @output mclkdiv: mclk div -+ * @return void -+ */ -+static void get_dac_osv_div(struct ak39_codec *codec, unsigned char *osrindex, -+ unsigned char *mclkdiv, unsigned long des_sr) -+{ -+ const unsigned short OSR_table[8] = -+ {256, 272, 264, 248, 240, 136, 128, 120}; -+ -+ unsigned long j; -+ unsigned long max_div; -+ long k; -+ unsigned long SR_save, out_sr=0; -+ long a; -+ long b; -+ unsigned long clk168m; -+ -+ unsigned long perfect_pll; -+ -+ clk168m = ak_get_asic_pll_clk(); -+ -+ max_div = 0x100; -+ SR_save = 0; -+ *osrindex = 0; -+ *mclkdiv = 0xff; -+ for(j=0; j<8; j++) //OSR index -+ { -+ for(k=max_div-1; k>=0; k--) //DAC_DIV value -+ { -+ out_sr = clk168m/(k+1); -+ if (out_sr > MAX_DACCLK) -+ break; -+ out_sr = out_sr/OSR_table[j]; -+ a = out_sr-des_sr; -+ a = (a>0)? a : (-a); -+ b = SR_save-des_sr; -+ b = (b>0)? b : (-b); -+ if (a<b) -+ { -+ SR_save = out_sr; -+ *mclkdiv = k; -+ *osrindex = j; -+ perfect_pll = OSR_table[j]*des_sr *(k + 1); -+ } -+ } -+ } -+ //WARN(1, "111"); -+ printk("perfect asic pll clk is:%lu, actual sample rate is %lu.\n", perfect_pll, SR_save); -+ -+} -+ -+ -+/** -+ *repair the volume range. -+ * -+ * */ -+static inline int volume_repair_range(int port, int vol) -+{ -+ if(vol < vol_info[port].vol_min) -+ vol = vol_info[port].vol_min; -+ else if(vol > vol_info[port].vol_max) -+ vol = vol_info[port].vol_max; -+ -+ return vol; -+} -+ -+static inline int get_volume_info(int port, int type) -+{ -+ int vol; -+ -+ switch(type){ -+ case VOL_INFO_DEFAULT: -+ vol = vol_info[port].vol_default; -+ break; -+ case VOL_INFO_MIN: -+ vol = vol_info[port].vol_min; -+ break; -+ case VOL_INFO_MAX: -+ vol = vol_info[port].vol_max; -+ break; -+ default: -+ vol = 0; -+ break; -+ } -+ return vol; -+} -+ -+ -+/* -+ *set mixer volume by port, -+ *return old volume; -+ * -+ * */ -+static inline int set_mixer_volume(struct ak39_codec *codec, -+ int port, int volume) -+{ -+ int old_vol; -+ -+ old_vol = codec->mixer_volume[port]; -+ codec->mixer_volume[port] = volume; -+ -+ return old_vol; -+} -+ -+static inline int get_mixer_volume(struct ak39_codec *codec, -+ int port) -+{ -+ return codec->mixer_volume[port]; -+} -+ -+/** -+ * @brief set hp/linein/mic gain -+ * @author lixinhai -+ * @date 2013-08-02 -+ * @input codec: handle. -+ * @input port: control port:hp, linein or mic. -+ * @input gain: gain value. -+ * @return void -+ */ -+static void ak39_set_gain(struct ak39_codec *codec, int port, int gain) -+{ -+ switch(port) { -+ case MIXER_PORT_HP_VOL: -+ ak39_set_hp_gain(codec, gain); -+ break; -+ case MIXER_PORT_LINEIN_VOL: -+ ak39_set_linein_gain(codec, gain); -+ break; -+ case MIXER_PORT_MIC_VOL: -+ ak39_set_mic_gain(codec, gain); -+ break; -+ } -+} -+ -+/** -+ * @brief set playback mode: headphone or speaker -+ * @author lixinhai -+ * @date 2013-08-02 -+ * @input codec: handle. -+ * @input plug_in: headphone is plug in. -+ * @return void -+ */ -+static inline void set_playmode_switch(struct ak39_codec *codec, -+ int plug_in) -+{ -+ if(codec->playmode != PLAYMODE_AUTO_SWITCH) -+ return; -+ -+ if(plug_in) -+ codec->mixer_switch[MIXER_ADDR_HPDET] = PLAYMODE_STATUS_HP; -+ else -+ codec->mixer_switch[MIXER_ADDR_HPDET] = PLAYMODE_STATUS_SPEAKER; -+} -+ -+/** -+ * @brief get playback mode: headphone or speaker -+ * @author lixinhai -+ * @date 2013-08-02 -+ * @input codec: handle. -+ * @return void -+ */ -+static int ak39_codec_get_playmode(struct ak39_codec *codec) -+{ -+ if(codec->playmode == PLAYMODE_HP) { -+ return PLAYMODE_STATUS_HP; -+ } else if(codec->playmode == PLAYMODE_SPEAKER) -+ return PLAYMODE_STATUS_SPEAKER; -+ else -+ return codec->mixer_switch[MIXER_ADDR_HPDET]; -+} -+ -+/** -+ * @brief set route source on destation. -+ * @author lixinhai -+ * @date 2013-08-02 -+ * @input codec: handle. -+ * @input dst: destation -+ * @input src: source -+ * @input src_mask: source mask. -+ * @return new destation of route. -+ */ -+static inline int set_route_src_on_dst(struct ak39_codec *codec, -+ int dst, int src, int src_mask) -+{ -+ codec->mixer_route[dst] &= ~src_mask; -+ codec->mixer_route[dst] |= src; -+ -+ PDEBUG("%s: destion:%d, src:%d, src_mask:%d, mixer source:%d.\n", -+ __func__, dst, src, src_mask, codec->mixer_route[dst]); -+ return codec->mixer_route[dst]; -+} -+ -+static inline int get_route_src_on_dst(struct ak39_codec *codec, -+ int dst, int src_mask) -+{ -+ return codec->mixer_route[dst] & src_mask; -+} -+ -+ -+static inline int check_route_src_on_dst(struct ak39_codec *codec, -+ int dst, int src) -+{ -+ return !!(codec->mixer_route[dst] & src); -+} -+ -+static int calc_route_src_status(struct ak39_codec *codec, int dst, int src, int src_mask) -+{ -+ int i; -+ int status = 0; -+ -+ for(i=0; i<MIXER_DST_COUNT; i++) { -+ if(i == dst) -+ status |= codec->mixer_route[i] & (src & src_mask); -+ else -+ status |= codec->mixer_route[i] & src_mask; -+ } -+ -+ return !!status; -+} -+ -+ -+/** -+ * @brief set input device power -+ * @author -+ * @date -+ * @param[in] src: DAC|LINEIN|MIC -+ * addr:route No. -+ * CurSrc:all three route's current src -+ * @return void -+ */ -+static void ak39_set_src_power(struct ak39_codec *codec, int dst, int src) -+{ -+ int s_dac, s_linein, s_mic, s_src; -+ -+ s_dac = calc_route_src_status(codec, dst, src, SOURCE_DAC); -+ s_linein = calc_route_src_status(codec, dst, src, SOURCE_LINEIN); -+ s_mic = calc_route_src_status(codec, dst, src, SOURCE_MIC); -+ -+ -+ s_src = s_dac|s_linein|s_mic; -+ -+ PDEBUG("%s: src:%d, s_dac:%d, s_linein:%d, s_mic:%d.\n", -+ __func__, src, s_dac, s_linein, s_mic); -+ -+ ak39_set_sel_vref(codec, s_src); -+ ak39_set_vcm_ref_power(codec, s_src); -+ -+ //set DAC power in PCM interface function: codec_playback_prepare() -+ ak39_set_linein_power(codec, s_linein); -+ ak39_set_mic_power(codec, s_mic); -+} -+ -+ -+static int ak39_codec_stream_control(struct ak39_codec *codec, -+ int dst, int running) -+{ -+ int src; -+ -+ src = get_route_src_on_dst(codec, dst, SOURCE_MIXED_ALL_MASK); -+ PDEBUG("%s: dst:%d, src:%d, status:%s.\n", -+ __func__, dst, src, running ? "running":"stop"); -+ -+ if(!running) -+ src = 0; -+ -+ switch(dst) { -+ case MIXER_ADDR_DST_HP: -+ if(codec->used_hp_mute) -+ ak_gpio_setpin(codec->hpmute_gpio.pin, codec->hpmute_en_val); -+ -+ ak39_set_hp_power(codec, !!src, !codec->used_hp_mute); -+ -+ if(codec->used_hp_mute) { -+ int dis_val; -+ -+ dis_val = (codec->hpmute_en_val == AK_GPIO_OUT_HIGH)? -+ AK_GPIO_OUT_LOW:AK_GPIO_OUT_HIGH; -+ ak_gpio_setpin(codec->hpmute_gpio.pin, dis_val); -+ } -+ ak39_set_hp_in(codec, src); -+ ak39_set_src_power(codec, dst, src); -+ -+ break; -+ case MIXER_ADDR_DST_ADC2: -+ ak39_set_adc2_in(codec, src); -+ ak39_set_src_power(codec, dst, src); -+ //dump_codec_reg(codec); -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * @brief open a dac device -+ * @author -+ * @date -+ * @return void -+ */ -+void ak39_codec_dac_open(struct ak_codec_dai *dai) -+{ -+ int reg_value; -+ int i; -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ if(codec->dac_state) -+ return; -+ -+ codec->dac_state = 1; -+ -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= ~(1<<4); -+ REG32(codec->analog_ctrl_base + CLOCK_GATE_CTRL_REG) &= ~(1<<4); -+ -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) |= MUTE; -+ -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) &= ~DAC_CTRL_EN; -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) &= ~DAC_CLK_EN; -+ -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) |= DAC_DIV_VLD; -+ i = 0; -+ while(REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) & (DAC_DIV_VLD)) -+ { -+ ++i; -+ if(i > 100000) -+ { -+ printk("set da clk reg fail\n"); -+ return ; -+ } -+ } -+ -+ // to enable DAC CLK -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) |= DAC_CLK_EN; -+ -+ //soft reset DAC -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= ~(DAC_SOFT_RST); -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) |= DAC_SOFT_RST; -+ -+ //to enable internal dac/adc via i2s -+ REG32(codec->analog_ctrl_base + MULTIPLE_FUN_CTRL_REG1) |= IN_DAAD_EN; -+ -+ //set default dac div and osr, for de pipa noise -+ -+ //I2S config reg -+ REG32(codec->adda_cfg_base + I2S_CONFIG_REG) &= (~I2S_CONFIG_WORDLENGTH_MASK); -+ REG32(codec->adda_cfg_base + I2S_CONFIG_REG) |= (16<<0); -+ -+ //config I2S interface DAC -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) |= DAC_CTRL_EN; -+ -+ //enable accept data from l2 -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) |= L2_EN; -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) |= FORMAT; -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) &= ~ARM_INT; -+ REG32(codec->adda_cfg_base + I2S_CONFIG_REG) &= ~POLARITY_SEL; -+ -+ REG32(codec->analog_ctrl_base + FADEOUT_CTRL_REG) |= DAC_FILTER_EN; -+ -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) &= ~MUTE; -+ -+ -+ reg_value = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_value &= ~( PD_OP | PD_CK); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_value; -+} -+ -+ -+/** -+ * @brief Close a dac device -+ * @author -+ * @date -+ * @return void -+ */ -+void ak39_codec_dac_close(struct ak_codec_dai *dai) -+{ -+ int reg_val; -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ if(!codec->dac_state) -+ return; -+ -+ codec->dac_state = 0; -+ REG32(codec->adda_cfg_base + DAC_CONFIG_REG) &= (~L2_EN); -+ -+ // to power off DACs/DAC clock -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val |= (PD_OP); -+ reg_val |= (PD_CK); -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+ -+ mdelay(5); -+ -+ REG32(codec->analog_ctrl_base + MULTIPLE_FUN_CTRL_REG1) &= (~(IN_DAAD_EN));// tdisable internal DAC/ADC -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) &= (~(DAC_CLK_EN|DAC_DIV_VLD));// disable DAC CLK -+ REG32(codec->analog_ctrl_base + DAC_CONFIG_REG) &= (~DAC_CTRL_EN);// to disable DACs -+} -+ -+/** -+ * @brief Set sample rate -+ * @author -+ * @date -+ * @param[in] samplerate: desired sample rate -+ * @return void -+ */ -+void ak39_codec_set_dac_samplerate(struct ak_codec_dai *dai, unsigned int samplerate) -+{ -+ unsigned char osr, mclkdiv; -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ get_dac_osv_div(codec, &osr, &mclkdiv, samplerate); -+ -+ //disable HCLK, and disable DAC interface -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) &= ~(DAC_HCLK_EN); -+ REG32(codec->analog_ctrl_base + DAC_CONFIG_REG) &= ~(DAC_CTRL_EN); -+ -+ set_dac_highspeed(codec, samplerate); -+ -+ // NOTE: should reset DAC!!! -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= (~DAC_SOFT_RST); -+ mdelay(5); -+ -+ //set OSR -+ REG32(codec->analog_ctrl_base + FADEOUT_CTRL_REG) &= (~OSR_MASK); -+ REG32(codec->analog_ctrl_base + FADEOUT_CTRL_REG) |= (OSR(osr)); -+ mdelay(2); -+ -+ //set DIV -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) &= (~(MASK_DAC_DIV_INT)); -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) |= (DAC_DIV_INT(mclkdiv)); -+ -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) &= (~(MASK_DAC_DIV_FRAC)); -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) |= (DAC_DIV_VLD); -+ mdelay(2); -+ -+ //to reset dac -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) |= DAC_SOFT_RST; -+ -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= (~DAC_SOFT_RST); -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) |= DAC_SOFT_RST; -+ -+ //enable HCLK, and enable DAC interface -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) |= (DAC_HCLK_EN); -+ REG32(codec->analog_ctrl_base + DAC_CONFIG_REG) |= (DAC_CTRL_EN); -+} -+ -+/** -+ * @brief Set DAC channels: mono,stereo -+ * @author -+ * @date -+ * @param[in] bool mono: true-mono, false-stereo -+ * @return void -+ */ -+void ak39_codec_set_dac_channels(struct ak_codec_dai *dai, unsigned int chnl) -+{ -+ -+} -+ -+ -+/** -+ * @brief open ADC2 -+ * @author -+ * @date -+ * @param[in] void -+ * @return void -+ */ -+void ak39_codec_adc2_open(struct ak_codec_dai *dai) -+{ -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ //unsigned long i; -+ if(codec->adc2_state) -+ return; -+ -+ codec->adc2_state = 1; -+ -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= ~(1<<3); -+ REG32(codec->analog_ctrl_base + CLOCK_GATE_CTRL_REG) &= ~(1<<3); -+ -+ // soft reset ADC2 controller -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) |= (ADC2_SOFT_RST); -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= ~(ADC2_SOFT_RST); -+ -+// set_cur_pmos(codec, 0x0); //must be set to 0 when ADC2 is working -+ -+ REG32(codec->analog_ctrl_base + MULTIPLE_FUN_CTRL_REG1) |= IN_DAAD_EN; //enable internal -+ -+ //disable vcm2 discharge -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~(0x1f << 4); -+ -+ //SelVcm3 -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) |= VCM3_SEL; -+ -+ //PowerOn Vcm2/3 -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~PD_VCM3; -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~PD_VCM2; -+ -+ //SetVcmNormal -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) &= ~PL_VCM2; -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) &= ~PL_VCM3; -+ -+ //EnableAdc2Limit -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) |= ADC_LIM; -+ -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) &= ~HOST_RD_INT_EN; -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) |= CH_POLARITY_SEL;//Receive the left channel data when the lrclk is high -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) &= ~I2S_EN; //Internal ADC MODE -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) &= ~WORD_LENGTH_MASK; -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) |= (0xF << 8); //WORD LENGTH IS 16 BIT -+ -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) |= (ADC2_SOFT_RST); -+ -+ //Enable adc controller -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) |= ADC2_CTRL_EN; -+ -+ //Enable l2 -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) |= ADC2MODE_L2_EN; -+ -+ //Power on adc2 conversion -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) &= ~PD_S2D; -+ -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) &= ~PD_ADC2; -+ -+ mdelay(1); -+ pd_ref_enable(codec); -+} -+ -+/** -+ * @brief close ADC2 -+ * @author -+ * @date -+ * @param[in] void -+ * @return void -+ */ -+void ak39_codec_adc2_close(struct ak_codec_dai *dai) -+{ -+ unsigned long reg_val; -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ if(!codec->adc2_state) -+ return; -+ -+ codec->adc2_state = 0; -+ -+ //disable l2 -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) &= ~ADC2MODE_L2_EN; -+ -+ //disable adc2 clk -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) &= ~ADC2_CLK_EN; -+ -+ //disable ADC2 interface -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) &= ~ADC2_CTRL_EN; -+ -+ //Power off adc2 -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG2) |= PD_ADC2; -+ -+ if((2 << 12) != (REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) & (2 << 12))) -+ { -+ if(!(REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) & DAC_CLK_EN)) -+ { -+ reg_val = REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1); -+ reg_val |= PD_VCM3; -+ reg_val |= PD_VCM2; -+ reg_val |= PL_VCM2; -+ //reg_val |= PD_REF; -+ REG32(codec->analog_ctrl_base + ANALOG_CTRL_REG1) = reg_val; -+ pd_ref_disable(codec); -+ -+ } -+ } -+ REG32(codec->analog_ctrl_base + CLOCK_CTRL_REG) |= (DAC_DIV_VLD); //inhabit adc2 clock -+ -+} -+ -+/** -+ * @brief set ADC2 sample rate -+ * @author -+ * @date -+ * @param[in] samplerate: desired rate to be set -+ * @return void -+ */ -+unsigned long ak39_codec_set_adc2_samplerate(struct ak_codec_dai *dai, -+ unsigned int samplerate) -+{ -+ unsigned char mode_sel = 0; -+ unsigned char save_div = 0; -+ unsigned long out_sr = 0; -+ unsigned long i = 0; -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ //disable HCLK, and disable ADC interface -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) &= ~(ADC2_CTRL_EN); -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) &= ~(ADC2_HCLK_EN); -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) &= ~(ADC2_CLK_EN); -+ -+ set_adc_highspeed(codec, samplerate); -+ -+ out_sr = get_adc2_osr_div(codec, &mode_sel, &save_div, samplerate); -+ -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) &= ~(1<<27); //reset adc from adc clk -+ i = 0; -+ while(REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) & (ADC2_DIV_VLD)) -+ { -+ ++i; -+ if(i > 100000) -+ { -+ printk("adc set sr fail\n"); -+ return 0; -+ } -+ } -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) &= ~(MASK_ADC2_DIV); -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) |= ADC2_DIV(save_div); -+ -+ REG32(codec->analog_ctrl_base + FADEOUT_CTRL_REG) &= ~(1<<ADC2_OSR_BIT); -+ REG32(codec->analog_ctrl_base + FADEOUT_CTRL_REG) |= (mode_sel << ADC2_OSR_BIT); -+ -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) |= (ADC2_DIV_VLD); -+ i = 0; -+ while(REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) & (ADC2_DIV_VLD)) -+ { -+ ++i; -+ if(i > 100000) -+ { -+ printk("adc set clk reg fail\n"); -+ return 0; -+ } -+ } -+ REG32(codec->analog_ctrl_base + SOFT_RST_CTRL_REG) |= (1<<27); //release the reset adc from adc clk -+ -+ -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) |= (ADC2_CLK_EN);//enable ADC2 Clock -+ REG32(codec->analog_ctrl_base + HIGHSPEED_CLOCK_CTRL_REG) |= (ADC2_HCLK_EN);//enable ADC2 Clock -+ REG32(codec->adda_cfg_base + ADC2_CONFIG_REG) |= (ADC2_CTRL_EN); -+ return out_sr; -+} -+ -+ -+/** -+ * @brief set ADC23 channel -+ * @author -+ * @date -+ * @param[in] chnl: 1-mono; 2-stereo -+ * @return void -+ */ -+void ak39_codec_set_adc2_channels(struct ak_codec_dai *dai, unsigned int chnl) -+{ -+ -+} -+ -+ -+/** -+ * @brief cfg shutdown speaker GPIO -+ * @author -+ * @date -+ * @param[in] bOn: 1-power on; 0-power off -+ * @return void -+ */ -+void ak39_codec_speak_on(struct ak39_codec *codec, bool bOn) -+{ -+ unsigned int pin = codec->spkrshdn_gpio.pin; -+ ak_setpin_as_gpio(pin); -+ ak_gpio_cfgpin(pin, AK_GPIO_DIR_OUTPUT); -+ ak_gpio_setpin(pin, bOn); -+} -+ -+ -+/** -+ * @brief when playback start, ak39_codec_playback_start must be called to start output channel -+ * @author Cheng JunYi -+ * @revisor Wu Daochao(2012-08-23) -+ * @date -+ * @return void -+ */ -+static void ak39_codec_playback_start(struct ak_codec_dai *dai) -+{ -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ if(codec->mixer_ch_duration[MIXER_ADDR_PLAY_DURATION] == CHNLDURATION_EVEROPEN) -+ return; -+ -+ ak39_codec_get_playmode(codec); -+ ak39_codec_stream_control(codec, MIXER_ADDR_DST_HP, 1); -+ -+ codec->outputing = true; -+ -+} -+ -+void ak39_start_to_play(struct ak_codec_dai *dai, -+ unsigned int channels, unsigned int samplerate) -+{ -+ ak39_codec_set_dac_samplerate(dai, samplerate); -+ ak39_codec_set_dac_channels(dai, channels); -+ ak39_codec_dac_open(dai); -+ ak39_codec_playback_start(dai); -+} -+ -+ -+static void ak39_codec_playback_stop(struct ak_codec_dai *dai) -+{ -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ //if we want to open some channel for ever, return -+ if(codec->mixer_ch_duration[MIXER_ADDR_PLAY_DURATION] == CHNLDURATION_EVEROPEN) -+ return; -+ -+ /*close the dac output*/ -+ ak39_codec_stream_control(codec, MIXER_ADDR_DST_HP, 0); -+ codec->outputing = false; -+} -+ -+ -+static void ak39_codec_capture_start(struct ak_codec_dai *dai) -+{ -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ ak39_codec_stream_control(codec, MIXER_ADDR_DST_ADC2, 1); -+} -+ -+static void ak39_codec_capture_stop(struct ak_codec_dai *dai) -+{ -+ struct ak39_codec *codec = to_ak39_codec(dai); -+ -+ ak39_codec_stream_control(codec, MIXER_ADDR_DST_ADC2, 0); -+} -+ -+/**********************HPDet switch**************************/ -+ -+static int set_hpdet_status(struct ak39_codec *codec) -+{ -+ int plug_in = 0; -+ int irq_type; -+ -+ if(ak_gpio_getpin(codec->hpdet_gpio.pin) == codec->hp_on_value) -+ { -+ //hp is plugged in -+ plug_in = 1; -+ irq_type = (codec->irq_hp_on_type == IRQ_TYPE_LEVEL_LOW) ? -+ IRQ_TYPE_LEVEL_HIGH:IRQ_TYPE_LEVEL_LOW; -+ } -+ else -+ { -+ //hp is pulled out -+ plug_in = 0; -+ irq_type = codec->irq_hp_on_type; -+ } -+ -+ printk("detect the headphone plug %s.\n", plug_in ? "on":"out"); -+ irq_set_irq_type(codec->hp_det_irq, irq_type); -+ -+ set_playmode_switch(codec, plug_in); -+ -+ ak39_codec_speak_on(codec, !plug_in); -+ return 0; -+} -+ -+ -+/** -+ * @brief when hp state is changed,schedule hp_det_worker to config output \ -+ channel to speaker or not -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static void hp_det_worker(struct work_struct *work) -+{ -+ struct ak39_codec *codec = container_of(work, struct ak39_codec,d_work.work); -+ -+ set_hpdet_status(codec); -+ -+ ak_codec_ctl_event(SNDRV_CTL_ELEM_IFACE_HWDEP, -+ SNDRV_CTL_EVENT_MASK_VALUE, "HPDet switch"); -+ -+ enable_irq(codec->hp_det_irq); -+} -+ -+/** -+ * @brief hp det -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static irqreturn_t ak39_codec_hpdet_irq(int irq, void *dev_id) -+{ -+ struct ak39_codec *codec = dev_id; -+ -+ disable_irq_nosync(irq); -+ -+ schedule_delayed_work(&codec->d_work, msecs_to_jiffies(100)); -+ return IRQ_HANDLED; -+} -+ -+ -+/************** -+ * mixer interface -+ **************/ -+ -+ -+/***********************config channel duration*******************************/ -+#define AK39PCM_OUTPUTCHNL_DURATION(xname, xindex, addr) \ -+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ -+ .name = xname, .index = xindex, \ -+ .info = codec_ChnlDuration_info, \ -+ .get = codec_ChnlDuration_get, \ -+ .put = codec_ChnlDuration_put, \ -+ .private_value = addr \ -+} -+ -+/** -+ * @brief info callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_ChnlDuration_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ int addr = kcontrol->private_value; -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ if(MIXER_ADDR_PLAY_DURATION == addr) -+ { -+ uinfo->value.integer.min = CHNLDURATION_MIN; -+ uinfo->value.integer.max = CHNLDURATION_MAX; -+ } -+ else -+ { -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief get callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_ChnlDuration_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ -+ int addr = kcontrol->private_value; -+ if(addr != MIXER_ADDR_PLAY_DURATION) -+ { -+ return -EINVAL; -+ } -+ -+ ucontrol->value.integer.value[0] = codec->mixer_ch_duration[addr]; -+ return 0; -+} -+ -+/** -+ * @brief put callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_ChnlDuration_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ -+ int addr = kcontrol->private_value; -+ int duration = ucontrol->value.integer.value[0]; -+ -+ printk("ak39 codec: ChnlDuration_put duration=%d\n",duration); -+ if(duration == codec->mixer_ch_duration[MIXER_ADDR_PLAY_DURATION]){ -+ return 0; -+ } -+ if(addr != MIXER_ADDR_PLAY_DURATION) { -+ return -EINVAL; -+ } -+ if((duration > CHNLDURATION_MAX)||(duration < CHNLDURATION_MIN)) { -+ return -EINVAL; -+ } -+ -+ codec->mixer_ch_duration[MIXER_ADDR_PLAY_DURATION] = duration; -+ if((duration == CHNLDURATION_CONSTANT) && -+ (!test_bit(0, &playback_statu))) { -+ ak39_codec_playback_stop(dai); -+ } -+ -+ return 0; -+} -+ -+/*********************select fixed output channel**********************************/ -+#define AK39PCM_DAC_OUT_MODE(xname, xindex, addr) \ -+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ -+ .name = xname, .index = xindex, \ -+ .info = codec_dac_outmode_info, \ -+ .get = codec_dac_outmode_get, \ -+ .put = codec_dac_outmode_put, \ -+ .private_value = addr \ -+} -+ -+/** -+ * @brief info callback. -+ * becsuse of arch-ak39 has dac output only, -+ * this interface is not used. -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_dac_outmode_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ int addr = kcontrol->private_value; -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ if(MIXER_ADDR_OUTMODE_DAC == addr) -+ { -+ uinfo->value.integer.min = OUTMODE_MIN; -+ uinfo->value.integer.max = OUTMODE_MAX; -+ } -+ else -+ { -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief get callback -+ * becsuse of arch-ak39 has dac output only, -+ * this interface is not used. -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_dac_outmode_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ int addr = kcontrol->private_value; -+ -+ if(addr != MIXER_ADDR_OUTMODE_DAC) -+ { -+ return -EINVAL; -+ } -+ -+ ucontrol->value.integer.value[0] = OUTMODE_HP; -+ return 0; -+} -+ -+/** -+ * @brief put callback -+ * becsuse of arch-ak39 has dac output only, -+ * this interface is not used. -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_dac_outmode_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ printk("ak39 platform not support out mode setting.\n"); -+ return 0; -+} -+ -+/**********************hp detect (read-only)****************************/ -+#define AK39PCM_SWITCH(xname, xindex, addr) \ -+{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ -+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \ -+ .name = xname, .index = xindex, \ -+ .info = codec_switch_info, \ -+ .get = codec_switch_get, \ -+ .private_value = addr \ -+} -+ -+/** -+ * @brief info callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_switch_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ int addr = kcontrol->private_value; -+ if(MIXER_ADDR_HPDET != addr) -+ { -+ return -EINVAL; -+ } -+ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; -+ uinfo->count = 1; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = 1; -+ return 0; -+} -+ -+/** -+ * @brief get callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_switch_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ -+ int addr = kcontrol->private_value; -+ if(MIXER_ADDR_HPDET != addr) -+ { -+ return -EINVAL; -+ } -+ -+ ucontrol->value.integer.value[0] = codec->mixer_switch[addr]; -+ PDEBUG("%s enter, value:%lu.\n", __func__, ucontrol->value.integer.value[0]); -+ return 0; -+} -+ -+/***************************VOLUME*********************/ -+#define AK39PCM_VOLUME(xname, xindex, addr) \ -+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ -+ .name = xname, .index = xindex, \ -+ .info = codec_volume_info, \ -+ .get = codec_volume_get, \ -+ .put = codec_volume_put, \ -+ .private_value = addr \ -+} -+ -+/** -+ * @brief info callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_volume_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ int port = kcontrol->private_value; -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ -+ -+ if(port < 0 || port >= MIXER_PORT_VOL_COUNT) { -+ printk(KERN_ERR "%s port %d is invaild.\n", __func__, port); -+ return -EINVAL; -+ } -+ uinfo->value.integer.min = get_volume_info(port, VOL_INFO_MIN); -+ uinfo->value.integer.max = get_volume_info(port, VOL_INFO_MAX); -+ -+ return 0; -+} -+ -+/** -+ * @brief get callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_volume_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ -+ int port = kcontrol->private_value; -+ if(port < 0 || port >= MIXER_PORT_VOL_COUNT) { -+ printk(KERN_ERR "%s port %d is invaild.\n", __func__, port); -+ return -EINVAL; -+ } -+ -+ ucontrol->value.integer.value[0] = get_mixer_volume(codec, port); -+ PDEBUG("%s enter, port:%d, volume:%lu.\n", -+ __func__, port, ucontrol->value.integer.value[0]); -+ return 0; -+} -+ -+/** -+ * @brief put callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_volume_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ -+ int port = kcontrol->private_value; -+ int vol, old_vol; -+ int change = 0; -+ -+ vol = ucontrol->value.integer.value[0]; -+ -+ PDEBUG("%s enter, port:%d, volume:%d.\n", __func__, port, vol); -+ vol = volume_repair_range(port, vol); -+ -+ old_vol = set_mixer_volume(codec, port, vol); -+ if(vol != old_vol) { -+ change = 1; -+ ak39_set_gain(codec, port, vol); -+ } -+ -+ return change; -+} -+ -+/***************************ROUTE**************************/ -+#define AK39PCM_ROUTE(xname, xindex, addr) \ -+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ -+ .name = xname, \ -+ .index = xindex, \ -+ .info = codec_route_info, \ -+ .get = codec_route_get, \ -+ .put = codec_route_put, \ -+ .private_value = addr \ -+} -+ -+/** -+ * @brief info callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_route_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ int addr = kcontrol->private_value; -+ -+ if(addr >= MIXER_DST_COUNT) -+ { -+ return -EINVAL; -+ } -+ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = SIGNAL_SRC_MAX; -+ -+ PDEBUG("%s enter, min:0, max:%d.\n", __func__, SIGNAL_SRC_MAX); -+ return 0; -+} -+ -+/** -+ * @brief get callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_route_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ int dst = kcontrol->private_value; -+ -+ if(dst >= MIXER_DST_COUNT) -+ { -+ return -EINVAL; -+ } -+ -+ ucontrol->value.integer.value[0] = get_route_src_on_dst(codec, dst, SOURCE_MIXED_ALL_MASK); -+ PDEBUG("%s enter, value:%lu.\n", __func__, ucontrol->value.integer.value[0]); -+ return 0; -+} -+ -+/** -+ * @brief put callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+/*application has to call this callback with params value=0 to power down input&output devices*/ -+static int codec_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ int change = 1; -+ unsigned long dst = kcontrol->private_value; -+ int src = 0; -+ -+ src = ucontrol->value.integer.value[0]; -+ PDEBUG("%s:set route: dst:%lu, src:%d.\n", __func__, dst, src); -+ -+ if((src < SIGNAL_SRC_MUTE) || (src > SIGNAL_SRC_MAX)) -+ return -EINVAL; -+ -+ if(dst == MIXER_ADDR_DST_HP) { -+ int plug_in = 0; -+ -+ if(codec->playmode == PLAYMODE_HP) -+ plug_in = 1; -+ else if(codec->playmode == PLAYMODE_SPEAKER) -+ plug_in = 0; -+ -+ set_playmode_switch(codec, plug_in); -+ -+ /*power on the speaker when headphone plug out.*/ -+ ak39_codec_speak_on(codec, !plug_in); -+ -+ }else if(dst == MIXER_ADDR_DST_ADC2) { -+ } -+ -+ if(get_route_src_on_dst(codec, dst, SOURCE_MIXED_ALL_MASK) == src) { -+ change = 0; -+ } -+ set_route_src_on_dst(codec, dst, src, SOURCE_MIXED_ALL_MASK); -+ -+ return change; -+} -+ -+/***************************ROUTE**************************/ -+#define AK39PCM_AEC(xname, xindex, addr) \ -+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ -+ .name = xname, \ -+ .index = xindex, \ -+ .info = codec_aec_info, \ -+ .get = codec_aec_get, \ -+ .put = codec_aec_put, \ -+ .private_value = addr \ -+} -+ -+/** -+ * @brief info callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_aec_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ //int port = kcontrol->private_value; -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ -+ printk( "get the aec info \n" ); -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = 10; -+ -+ return 0; -+} -+ -+/** -+ * @brief get callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_aec_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ //struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ -+ //int port = kcontrol->private_value; -+ ucontrol->value.integer.value[0] = dai->aec_flag; -+ //printk("%s enter, %d\n", __func__, ucontrol->value.integer.value[0]); -+ return 0; -+} -+ -+/** -+ * @brief put callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int codec_aec_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct ak_codec_dai *dai = snd_kcontrol_chip(kcontrol); -+ //struct ak39_codec *codec = container_of(dai, struct ak39_codec, dai); -+ -+ int src = ucontrol->value.integer.value[0]; -+ int port = kcontrol->private_value; -+ -+ -+ printk("%s enter, %d %d \n", __func__, port, src); -+ dai->aec_flag = src; -+ -+ return 1; -+} -+ -+ -+ -+ -+static struct ak_proc_entry codec_pentries[] = { -+}; -+ -+static struct snd_kcontrol_new codec_controls[] = { -+ AK39PCM_VOLUME("Headphone Playback Volume", 0, MIXER_PORT_HP_VOL), -+ AK39PCM_VOLUME("LineIn Capture Volume", 0, MIXER_PORT_LINEIN_VOL), -+ AK39PCM_VOLUME("Mic Capture Volume", 0, MIXER_PORT_MIC_VOL), -+ AK39PCM_ROUTE("Headphone Playback Route", 0, MIXER_ADDR_DST_HP), -+ AK39PCM_ROUTE("ADC Capture Route", 0, MIXER_ADDR_DST_ADC2), -+ /*AK39PCM_ROUTE("LineIn Capture Route", 0, MIXER_ADDR_LINEINSRC),*/ -+ AK39PCM_SWITCH("HPDet switch", 0, MIXER_ADDR_HPDET), -+ AK39PCM_DAC_OUT_MODE("DAC out mode", 0, MIXER_ADDR_OUTMODE_DAC), -+ AK39PCM_OUTPUTCHNL_DURATION("duration of output channel", 0, MIXER_ADDR_PLAY_DURATION), -+ AK39PCM_AEC("Set the aec", 0, 0), -+}; -+ -+struct ak_codec_ops ak39_codec_ops = { -+ .dac_init = ak39_codec_dac_open, -+ .dac_exit = ak39_codec_dac_close, -+ .adc_init = ak39_codec_adc2_open, -+ .adc_exit = ak39_codec_adc2_close, -+ .set_dac_samplerate = ak39_codec_set_dac_samplerate, -+ .set_adc_samplerate = ak39_codec_set_adc2_samplerate, -+ .set_dac_channels = ak39_codec_set_dac_channels, -+ .set_adc_channels = ak39_codec_set_adc2_channels, -+ .playback_start = ak39_codec_playback_start, -+ .playback_end = ak39_codec_playback_stop, -+ .capture_start = ak39_codec_capture_start, -+ .capture_end = ak39_codec_capture_stop, -+ .start_to_play = ak39_start_to_play, -+}; -+ -+ -+static int ak39_codec_probe(struct platform_device *pdev) -+{ -+ int err = 0; -+ int i; -+ struct ak39_codec_platform_data *pdata = pdev->dev.platform_data; -+ struct ak39_codec *codec; -+ struct resource *res; -+ -+ printk("ak39_codec_probe enter.\n"); -+ -+ codec = kzalloc(sizeof(*codec), GFP_KERNEL); -+ if (!codec) -+ return -ENOMEM; -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "akpcm_AnalogCtrlRegs"); -+ if(!res) -+ { -+ printk(KERN_ERR "no memory resource for analog_ctrl_res\n"); -+ err = -ENXIO; -+ goto out_free_codec; -+ } -+ -+ codec->analog_ctrl_base = ioremap(res->start, res->end - res->start + 1); -+ if (!codec->analog_ctrl_base) { -+ printk(KERN_ERR "could not remap analog_ctrl_res memory"); -+ err = -ENXIO; -+ goto out_free_codec; -+ } -+ -+ -+ //get ADC2 mode registers -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "akpcm_ADC2ModeCfgRegs"); -+ if(!res) -+ { -+ printk(KERN_ERR "no memory resource for adda_cfg_res\n"); -+ err = -ENXIO; -+ goto out_unremap_analog; -+ } -+ codec->adda_cfg_base = ioremap(res->start, res->end - res->start + 1); -+ if (!codec->adda_cfg_base) { -+ printk(KERN_ERR "could not remap adda_cfg_res memory"); -+ err = -ENXIO; -+ goto out_unremap_analog; -+ } -+ -+ -+ for(i=0; i<MIXER_PORT_VOL_COUNT; i++) { -+ set_mixer_volume(codec, i, get_volume_info(i, VOL_INFO_DEFAULT)); -+ ak39_set_gain(codec, i, get_mixer_volume(codec, i)); -+ } -+ -+ for(i=0; i<MIXER_DST_COUNT; i++) { -+ set_route_src_on_dst(codec, i, default_route[i], SOURCE_MIXED_ALL_MASK); -+ } -+ -+ /*only a hp output at arch-ak39*/ -+ codec->mixer_outmode[MIXER_ADDR_OUTMODE_DAC] = OUTMODE_HP; -+ codec->mixer_ch_duration[MIXER_ADDR_PLAY_DURATION] = CHNLDURATION_CONSTANT; -+ -+ /*FIXME:can add the code for worker vaild when switch auto mode*/ -+ INIT_DELAYED_WORK(&codec->d_work, hp_det_worker); -+ -+ codec->playmode = pdata->boutput_only; -+ -+ //config hp det gpio -+ codec->hpdet_gpio = pdata->hpdet_gpio; -+ -+ //config speaker shutdown gpio -+ codec->spkrshdn_gpio = pdata->spk_down_gpio; -+ ak_gpio_set(&(codec->spkrshdn_gpio)); -+ -+ //config speaker shutdown gpio -+ codec->spkrshdn_gpio = pdata->spk_down_gpio; -+ ak_gpio_set(&(codec->spkrshdn_gpio)); -+ -+ //set hp det pin irq -+ if(codec->hpdet_gpio.pin >= 0) { -+ ak_gpio_set(&(codec->hpdet_gpio)); -+ -+ if(AK_GPIO_OUT_LOW == codec->hp_on_value) -+ codec->irq_hp_on_type = IRQ_TYPE_LEVEL_LOW; -+ else if(AK_GPIO_OUT_HIGH == codec->hp_on_value) -+ codec->irq_hp_on_type = IRQ_TYPE_LEVEL_HIGH; -+ -+ codec->hp_det_irq = pdata->hpdet_irq; -+ codec->hp_on_value = pdata->hp_on_value; -+ -+ set_hpdet_status(codec); -+ err = request_irq(codec->hp_det_irq, ak39_codec_hpdet_irq, -+ IRQF_DISABLED, pdev->name, codec); -+ if(err) -+ { -+ printk(KERN_ERR "request irq error!"); -+ goto err_out; -+ } -+ } -+ -+ codec->dai.ops = &ak39_codec_ops; -+ codec->dai.num_kcontrols = ARRAY_SIZE(codec_controls); -+ codec->dai.kcontrols = codec_controls; -+ codec->dai.num_pentries = ARRAY_SIZE(codec_pentries); -+ codec->dai.pentries = codec_pentries; -+ codec->dai.entries_private = codec; -+ -+ if(ak_codec_register(&codec->dai)) -+ goto err_out; -+ -+ codec->used_hp_mute = pdata->bIsHPmuteUsed; -+ codec->hpmute_en_val = pdata->hp_mute_enable_value; -+ -+ if(codec->used_hp_mute){ -+ //config hp mute gpio -+ codec->hpmute_gpio = pdata->hpmute_gpio; -+ ak_gpio_set(&(codec->hpmute_gpio)); -+ } -+ -+ codec->outputing = false; -+ -+ platform_set_drvdata(pdev, codec); -+ return 0; -+ -+err_out: -+//out_unremap_adda: -+ iounmap(codec->adda_cfg_base); -+out_unremap_analog: -+ iounmap(codec->analog_ctrl_base); -+out_free_codec: -+ kfree(codec); -+ return err; -+} -+ -+static int ak39_codec_remove(struct platform_device *pdev) -+{ -+ struct ak39_codec *codec = platform_get_drvdata(pdev); -+ -+ free_irq(codec->hp_det_irq, codec); -+ -+ /*FIXME:can add the code for worker vaild when switch auto mode*/ -+ cancel_delayed_work_sync(&codec->d_work); -+ -+ iounmap(codec->analog_ctrl_base); -+ iounmap(codec->adda_cfg_base); -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver ak39_codec_driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "ak39-codec", -+ }, -+ .probe = ak39_codec_probe, -+ .remove = ak39_codec_remove, -+}; -+ -+static int __init ak39_codec_init(void) -+{ -+ return platform_driver_register(&ak39_codec_driver); -+} -+ -+static void __exit ak39_codec_exit(void) -+{ -+ platform_driver_unregister(&ak39_codec_driver); -+} -+module_init(ak39_codec_init); -+module_exit(ak39_codec_exit); -+ -+MODULE_AUTHOR("anyka"); -+MODULE_DESCRIPTION("ak39 codec Driver"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/sound/arm/ak_pcm.c b/sound/arm/ak_pcm.c -new file mode 100644 -index 00000000..96ace240 ---- /dev/null -+++ b/sound/arm/ak_pcm.c -@@ -0,0 +1,1882 @@ -+/* -+ * akpcm soundcard -+ * Copyright (c) by Anyka, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include <linux/init.h> -+#include <linux/err.h> -+#include <linux/platform_device.h> -+#include <linux/jiffies.h> -+#include <linux/slab.h> -+#include <linux/time.h> -+#include <linux/wait.h> -+#include <linux/hrtimer.h> -+#include <linux/workqueue.h> -+#include <linux/export.h> -+#include <linux/math64.h> -+#include <linux/module.h> -+#include <linux/completion.h> -+#include <linux/irq.h> -+#include <linux/workqueue.h> -+#include <asm/bitops.h> -+#include <sound/core.h> -+#include <sound/control.h> -+#include <sound/tlv.h> -+#include <sound/pcm.h> -+#include <sound/rawmidi.h> -+#include <sound/info.h> -+#include <sound/initval.h> -+#include <linux/cpufreq.h> -+//#include <linux/anyka_cpufreq.h> -+ -+#include <plat/l2.h> -+#include <sound/ak_pcm.h> -+#include <mach/ak_codec.h> -+#include <linux/vmalloc.h> -+#include <linux/reboot.h> -+#include <mach-anyka/aec_interface.h> -+ -+//#define CONFIG_PCM_DUMP 1 -+#define AK_PCM_DELAY_CLOSE_DAC -+ -+unsigned long playback_statu; -+ -+struct snd_akpcm { -+ struct snd_card *card; -+ struct snd_pcm *pcm; -+ spinlock_t mixer_lock; -+ struct snd_pcm_substream *playbacksubstrm; -+ struct snd_pcm_substream *capturesubstrm; -+ struct completion playbackHWDMA_completion; -+ struct completion captureHWDMA_completion; -+ u8 L2BufID_For_DAC; -+ u8 L2BufID_For_ADC23; -+ snd_pcm_uframes_t PlaybackCurrPos; -+ snd_pcm_uframes_t CaptureCurrPos; -+ unsigned long playbackStrmDMARunning;//bit[0]:strm state(running or not). bit[1]:DMA state(running or finished). bit[2]:strm state(suspend in frequest changed). -+ unsigned long captureStrmDMARunning;//bit[0]:strm state(running or not). bit[1]:DMA state(running or finished) -+ -+ struct tasklet_struct fetch_tasklet; -+ void * pp_buf_addr[2]; //Pingpong Buffer address -+ int playing_idx; -+ snd_pcm_uframes_t optimal_period_size; -+ int optimal_period_bytes; -+ bool use_optimal_period; -+ -+ struct timer_list stopoutput_work_timer; -+ struct tasklet_struct close_dac; -+ -+ struct ak_codec_dai *dai; -+ struct ak_codec_ops *ops; -+ -+#ifdef CONFIG_CPU_FREQ -+ struct notifier_block freq_transition; -+#endif -+ -+//#ifdef CONFIG_SUPPORT_AEC -+ struct tasklet_struct capture_aec_tasklet; -+ struct tasklet_struct playback_aec_tasklet; -+ T_AEC_INPUT p_aecin; -+ T_AEC_BUF p_aecbufs; -+ T_VOID *pfilter; -+ unsigned char *playback_data; -+ unsigned char *capture_data; -+ unsigned char *temp; -+//#endif -+ -+#ifdef CONFIG_PCM_DUMP -+ void* pcmDumpDataBuffer; -+ bool enableDump; -+ unsigned long pcmDumpSize; -+ struct timeval pcmDumpTime; -+#endif -+ -+ struct delayed_work ds_work; //delay start work -+}; -+ -+struct captureSync{ -+ unsigned long long adcCapture_bytes; -+ struct timeval tv; -+ unsigned int rate; -+ unsigned int frame_bits; -+}; -+ -+struct captureSync capSync; -+ -+static unsigned long long dac_clock; -+ -+ -+/************* -+ * PCM interface -+ *************/ -+#define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) -+#define USE_RATE (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000) -+#define USE_RATE_MIN 5500 -+#define USE_RATE_MAX 96000 -+ -+#define CAPTURE_USE_CHANNELS_MIN 1 -+#define CAPTURE_USE_CHANNELS_MAX 1 -+ -+#define PLAYBACK_USE_CHANNELS_MIN 2 -+#define PLAYBACK_USE_CHANNELS_MAX 2 -+ -+#define akpcm_playback_buf_bytes_max (64*1024) -+#define akpcm_playback_period_bytes_min 512 -+#define akpcm_playback_period_bytes_max 512 -+#define akpcm_playback_period_aligned 128 -+#define akpcm_playback_periods_min 4 -+#define akpcm_playback_periods_max 128 -+ -+#define DELAY_TIME_FOR_CLOSING_DAC (HZ * 30) -+ -+ -+#define akpcm_capture_buf_bytes_max (64*1024) -+#define akpcm_capture_period_bytes_min 512 -+#define akpcm_capture_periods_min 4 -+#define akpcm_capture_periods_max 64 -+ -+#ifdef CONFIG_PCM_DUMP -+#define akpcm_dump_data_size (2*1024*1024) -+#endif -+ -+ -+//#ifdef CONFIG_SUPPORT_AEC -+#define AEC_NN 128 -+#define AEC_TAIL (AEC_NN*10) -+#define AEC_CHANNELS 1 -+#define AEC_SAMPLERATE 8000 -+#define AEC_BITSPERSAMPLE 16 -+//#endif -+ -+ -+ static DEFINE_MUTEX(reboot_lock); -+ static struct snd_akpcm *reboot_info = NULL; -+ -+ /** -+ * @brief tell camera driver the audio capture samples for AV sync -+ * @author -+ * @date -+ * @input void -+ * @output void * -+ * @return void -+ */ -+void *getRecordSyncSamples(void) -+{ -+ return &capSync; -+} -+EXPORT_SYMBOL(getRecordSyncSamples); -+ -+/* return the dac_clock */ -+unsigned long long getPlaybackEclapseTime(void) -+{ -+ return dac_clock; -+} -+EXPORT_SYMBOL(getPlaybackEclapseTime); -+ -+void ak_close_dac_timer(unsigned long data) -+{ -+ struct snd_akpcm *akpcm = (struct snd_akpcm *)data; -+ -+ if (akpcm->ops->playback_end) { -+ akpcm->ops->playback_end(akpcm->dai); -+ } -+} -+ -+//#ifdef CONFIG_SUPPORT_AEC -+void ak37pcm_playback_aec(unsigned long data) -+{ -+ struct snd_akpcm *ak37pcm = (struct snd_akpcm *)data; -+ struct snd_pcm_substream *substream = ak37pcm->playbacksubstrm; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_substream *capture_substream = ak37pcm->capturesubstrm; -+ struct snd_pcm_runtime *capture_runtime; -+ -+ unsigned int playback_pos; -+ unsigned long period_bytes = frames_to_bytes(runtime,runtime->period_size); -+ unsigned long buffer_bytes = frames_to_bytes(runtime,runtime->buffer_size); -+ -+ -+ //Check if the capture substream is opened yet -+ if (!capture_substream) -+ return; -+ -+ //FIXME: What is the relationship between substream and its belonging runtime -+ capture_runtime = capture_substream->runtime; -+ if (!capture_runtime) -+ return; -+ -+ //Check if the AEC library has been successfully opened. -+ if (runtime->rate != AEC_SAMPLERATE || period_bytes != akpcm_playback_period_bytes_min || !ak37pcm->pfilter) -+ return; -+ -+ //Make sure that the DMA of capturing is running -+ if (test_bit(0,&ak37pcm->captureStrmDMARunning) && -+ test_bit(1,&ak37pcm->captureStrmDMARunning)) { -+ -+ //FIXME: Figure out the position of last period that has just been finished -+ if (ak37pcm->PlaybackCurrPos <= 0) { -+ playback_pos = buffer_bytes - period_bytes; -+ } else { -+ playback_pos = ak37pcm->PlaybackCurrPos - period_bytes; -+ } -+ -+ //Something must go wrong. -+ if (playback_pos % akpcm_playback_period_bytes_min != 0 || playback_pos < 0) -+ printk("ak37pcm_playback_aec==>playback_pos=%d\n", playback_pos); -+ -+ /* -+ * FIXME: The AEC Lib just supports single channel by now. But we make a trick here by -+ * cheating the AEC Lib. Tha input data for the AEC Lib is actully stereo. By doing that, the -+ * system load could be lowered a little bit. -+ */ -+#if 0 -+ short *to = ak37pcm->playback_data; -+ short *from = vaddr + playback_pos; -+ int count = period_bytes / channels / 2; -+ if (count != AEC_NN) -+ printk("ak37pcm_playback_aec==>count=%d\n", count); -+ for (i = 0; i < count; i++) { -+ to[i] = from[i * 2]; -+ } -+#endif -+ /*We assume the channels is stereo basing on the truth */ -+ #if 0 -+ ak37pcm->p_aecbufs.buf_near = ak37pcm->p_aecbufs.buf_out = NULL; -+ ak37pcm->p_aecbufs.len_near = ak37pcm->p_aecbufs.len_out = 0; -+ ak37pcm->p_aecbufs.buf_far = vaddr + playback_pos; -+ ak37pcm->p_aecbufs.len_far = period_bytes / channels; -+ ret = AECLib_Control(ak37pcm->pfilter, &ak37pcm->p_aecbufs); -+ if (ret < 0) -+ printk("p=%d\n", ret); -+ #endif -+ } -+} -+ -+void ak37pcm_capture_aec(unsigned long data) -+{ -+ struct snd_akpcm *ak37pcm = (struct snd_akpcm *)data; -+ struct snd_pcm_substream *substream = ak37pcm->capturesubstrm; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_substream *playback_substream = ak37pcm->playbacksubstrm; -+ struct snd_pcm_runtime *playback_runtime; -+ -+ //dma_addr_t vaddr = runtime->dma_area; -+ dma_addr_t paddr = runtime->dma_addr; -+ int period_bytes = frames_to_bytes(runtime,runtime->period_size); -+ int buffer_bytes = frames_to_bytes(runtime,runtime->buffer_size); -+ int capture_pos; -+ int ret; -+ -+ //Check if the playback substream is open -+ if (!playback_substream) -+ return; -+ -+ //FIXME: What is the relationship between substream and its belonging runtime -+ playback_runtime = playback_substream->runtime; -+ if (!playback_runtime) -+ return; -+ -+ /* -+ *Check if the AEC library has been successfully opened. -+ */ -+ if (runtime->rate != AEC_SAMPLERATE || period_bytes != akpcm_capture_period_bytes_min || !ak37pcm->pfilter) -+ return; -+ -+// if (test_bit(0,&ak37pcm->playbackStrmDMARunning) && -+// test_bit(1,&ak37pcm->playbackStrmDMARunning)) -+ { -+ -+ if (ak37pcm->CaptureCurrPos == 0) { -+ capture_pos = buffer_bytes - period_bytes; -+ } else { -+ capture_pos = ak37pcm->CaptureCurrPos - period_bytes; -+ } -+#if 0 -+ ak37pcm->p_aecbufs.buf_near = vaddr + capture_pos; -+ ak37pcm->p_aecbufs.len_near = period_bytes; -+ ak37pcm->p_aecbufs.buf_out = ak37pcm->p_aecbufs.buf_near; -+ ak37pcm->p_aecbufs.len_out = ak37pcm->p_aecbufs.len_near; -+ ak37pcm->p_aecbufs.buf_far = NULL; -+ ak37pcm->p_aecbufs.len_far = 0; -+ if (ak37pcm->p_aecbufs.len_near != akpcm_capture_period_bytes_min) -+ printk("ak37pcm_capture_aec==>len_near=%d\n", period_bytes); -+ -+ ret = AECLib_Control(ak37pcm->pfilter, &ak37pcm->p_aecbufs); -+ if (ret < 0) -+ printk("c=%d\n", ret); -+#endif -+ ak37pcm->p_aecbufs.buf_out = phys_to_virt(paddr+ak37pcm->CaptureCurrPos); -+ ak37pcm->p_aecbufs.len_out = akpcm_capture_period_bytes_min; -+ ret = AECLib_Control(ak37pcm->pfilter, &ak37pcm->p_aecbufs); -+ } -+} -+//#endif -+ -+/** -+ * @brief create new mixer interface -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static struct snd_card *cur_card; -+static struct snd_pcm *cur_pcm; -+static struct ak_codec_dai *cur_codec; -+int ak_codec_register(struct ak_codec_dai *dai) -+{ -+ int i, err; -+ struct snd_akpcm *akpcm; -+ struct snd_info_entry *entry; -+ -+ if (!dai) -+ return -1; -+ -+ if (!dai->ops) -+ return -1; -+ -+ if (!cur_card || !cur_pcm) { -+ printk("AK PCM: No card, No cur_pcm(failed)\n"); -+ return -1; -+ } -+ -+ akpcm = cur_card->private_data; -+ -+ if (cur_codec) { -+ printk("AK PCM: some codec has registered first(failed)\n"); -+ return -1; -+ } else { -+ cur_codec = dai; -+ akpcm->dai = dai; -+ akpcm->ops = dai->ops; -+ } -+ -+ strcpy(cur_card->mixername, "akpcm Mixer"); -+ -+ for (i = 0; i < dai->num_kcontrols; i++) { -+ err = snd_ctl_add(cur_card, snd_ctl_new1(&dai->kcontrols[i], dai)); -+ if (err < 0) -+ return err; -+ } -+ printk("AK PCM: create num_kcontrols=%d\n", dai->num_kcontrols); -+ -+ // register a proc file to tell user whether the chip DAC module has been fixed -+ for (i = 0; i < dai->num_pentries; i++) { -+ snd_card_proc_new (cur_card, dai->pentries[i].name, &entry); -+ snd_info_set_text_ops(entry, dai->entries_private, dai->pentries[i].cb); -+ } -+ -+ return 0; -+} -+ -+void ak_codec_ctl_event(unsigned int iface, unsigned int event, const char* ctl_name) -+{ -+ struct snd_ctl_elem_id elem_id; -+ struct snd_kcontrol *ctl_switch; -+ -+ /* find the corresponding switch control */ -+ memset(&elem_id, 0, sizeof(elem_id)); -+ elem_id.iface = iface; -+ -+ strcpy(elem_id.name, ctl_name); -+ -+ ctl_switch = snd_ctl_find_id(cur_card, &elem_id); -+ -+ if (ctl_switch) -+ snd_ctl_notify(cur_card, event, &ctl_switch->id); -+} -+ -+void alsabuf_to_ppbuf(unsigned long data) -+{ -+ struct snd_akpcm *akpcm = (struct snd_akpcm *)data; -+ struct snd_pcm_substream *substream = akpcm->playbacksubstrm; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ void *vaddr = runtime->dma_area; -+ snd_pcm_uframes_t avail; -+ int bytespersample = frames_to_bytes(runtime, 1); -+ int buffer_bytes = frames_to_bytes(runtime,runtime->buffer_size); -+ int period_bytes = akpcm->optimal_period_bytes; -+ int pend_bytes; -+ int dst_pos, cur_pos; -+ void *dst_addr = NULL; -+ -+ if (akpcm->playing_idx == 1) -+ dst_addr = akpcm->pp_buf_addr[0]; -+ else -+ dst_addr = akpcm->pp_buf_addr[1]; -+ -+ akpcm->PlaybackCurrPos += period_bytes; -+ if(akpcm->PlaybackCurrPos >= buffer_bytes) -+ { -+ akpcm->PlaybackCurrPos = akpcm->PlaybackCurrPos - buffer_bytes; -+ } -+ -+ avail = snd_pcm_playback_avail(runtime) + akpcm->optimal_period_size; -+ pend_bytes = (runtime->buffer_size - avail) * bytespersample; -+ -+ if (avail >= runtime->stop_threshold) { -+ printk("optimal=%u, original=%u, left=%u\n", (unsigned int)akpcm->optimal_period_size, -+ (unsigned int)runtime->period_size, (unsigned int)(runtime->buffer_size - snd_pcm_playback_avail(runtime))); -+ return; -+ } -+ -+ dst_pos = akpcm->PlaybackCurrPos + period_bytes; -+ cur_pos = akpcm->PlaybackCurrPos; -+ if (dst_pos > buffer_bytes) { -+ memcpy(dst_addr, vaddr + cur_pos, (buffer_bytes - cur_pos)); -+ memcpy(dst_addr + (buffer_bytes - cur_pos), vaddr, dst_pos - buffer_bytes); -+ } else { -+ memcpy(dst_addr, vaddr + cur_pos, period_bytes); -+ } -+ -+ if (pend_bytes < period_bytes) -+ memset(dst_addr + pend_bytes, 0, period_bytes - pend_bytes); -+} -+ -+ -+/* from the previous interrupt hanlder */ -+void dac_exit_tasklet(unsigned long data) -+{ -+ struct snd_akpcm *akpcm = (struct snd_akpcm *)data; -+ -+ if (akpcm->ops->dac_exit) -+ akpcm->ops->dac_exit(akpcm->dai); -+} -+ -+void akpcm_playback_interrupt_optimize(unsigned long data) -+{ -+ struct snd_akpcm *akpcm = (struct snd_akpcm *)data; -+ struct snd_pcm_substream *substream = akpcm->playbacksubstrm; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ u8 id = akpcm->L2BufID_For_DAC; -+ int bytespersample = frames_to_bytes(runtime, 1); -+ void *pdst_addr; -+ -+ snd_pcm_period_elapsed(substream); -+ -+ dac_clock += akpcm->optimal_period_bytes / bytespersample * 1000000 / runtime->rate; -+ -+ if(test_bit(0,&playback_statu) -+ && snd_pcm_playback_avail(runtime) < runtime->stop_threshold)//output stream is running -+ { -+ if (akpcm->playing_idx == 0) -+ akpcm->playing_idx = 1; -+ else -+ akpcm->playing_idx = 0; -+ -+ pdst_addr = (void *)virt_to_phys(akpcm->pp_buf_addr[akpcm->playing_idx]); -+ l2_combuf_dma((unsigned long)pdst_addr, id, akpcm->optimal_period_bytes, -+ (l2_dma_transfer_direction_t)MEM2BUF,1); -+ -+ tasklet_schedule(&akpcm->fetch_tasklet); -+ } -+ else //output strm has been stopped -+ { -+ printk("output stream stopped\n"); -+ clear_bit(1,&akpcm->playbackStrmDMARunning); //DMA has finished -+ complete(&(akpcm->playbackHWDMA_completion)); -+ -+#if defined(AK_PCM_DELAY_CLOSE_DAC) -+ /* delay to close output channel */ -+ akpcm->stopoutput_work_timer.expires = jiffies + DELAY_TIME_FOR_CLOSING_DAC; -+ add_timer(&akpcm->stopoutput_work_timer); -+ -+ //close the dac in order to eliminate the noise caused by interrupt of -+ // DAC data transfer -+ tasklet_schedule(&akpcm->close_dac); -+#endif -+ } -+} -+ -+ -+/** -+ * @brief DMA transfer for playback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+void akpcm_playback_interrupt(unsigned long data) -+{ -+ struct snd_akpcm *akpcm = (struct snd_akpcm *)data; -+ struct snd_pcm_substream *substream = akpcm->playbacksubstrm; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ dma_addr_t paddr = runtime->dma_addr; -+ void *vaddr = runtime->dma_area; -+ -+ u8 id = akpcm->L2BufID_For_DAC; -+ unsigned long period_bytes = 0; -+ unsigned long buffer_bytes = 0; -+ int bytespersample = frames_to_bytes(runtime, 1); -+ snd_pcm_uframes_t avail; -+ unsigned long pend_bytes; -+ -+ period_bytes = frames_to_bytes(runtime,runtime->period_size); -+ buffer_bytes = frames_to_bytes(runtime,runtime->buffer_size); -+ akpcm->PlaybackCurrPos += period_bytes; -+ if(akpcm->PlaybackCurrPos >= buffer_bytes) -+ { -+ akpcm->PlaybackCurrPos = 0; -+ } -+ snd_pcm_period_elapsed(substream); -+ -+ dac_clock += period_bytes / bytespersample * 1000000 / runtime->rate; -+ avail = snd_pcm_playback_avail(runtime); -+ pend_bytes = (runtime->buffer_size - avail) * bytespersample; -+#if 0 -+ int i; -+ unsigned short s; -+ -+ printk("_________________\n"); -+ for (i=0; i<64; i++) -+ { -+ s = *(unsigned short *)__va(paddr+akpcm->CaptureCurrPos+i*2); -+ if (s < 0x8000) -+ printk("%d\n", s); -+ else -+ printk("-%d\n", (unsigned short)(~s+1)); -+ } -+ printk("_________________\n"); -+#endif -+ -+ -+#ifdef CONFING_SUPPORT_AEC -+// tasklet_schedule(&akpcm->playback_aec_tasklet); -+#endif -+ -+ if(test_bit(0,&playback_statu) && avail < runtime->stop_threshold)//output stream is running -+ { -+ //printk(KERN_ERR "begin next dma"); -+ if (pend_bytes < period_bytes) -+ memset(vaddr+akpcm->PlaybackCurrPos + pend_bytes, 0, period_bytes - pend_bytes); -+ -+ //#ifdef CONFIG_SUPPORT_AEC -+ if( akpcm->dai->aec_flag == 1) -+ { -+ AECLib_DacInt(akpcm->pfilter, phys_to_virt(paddr+akpcm->PlaybackCurrPos), period_bytes); -+ } -+ //memcpy(akpcm->playback_data, akpcm->temp, period_bytes); -+ //#endif -+ -+ l2_combuf_dma(paddr+akpcm->PlaybackCurrPos, id, period_bytes, -+ (l2_dma_transfer_direction_t)MEM2BUF,1); -+ -+#ifdef CONFIG_PCM_DUMP -+ if(akpcm->enableDump){ -+ unsigned char *pcmDump_dma_area=runtime->dma_area; -+ if((akpcm->pcmDumpSize+akpcm_playback_period_bytes_min)<=akpcm_dump_data_size){ -+ //printk(KERN_ERR "akpcm->dumpsize=%d,akpcm->PlaybackCurrPos=%d \n",akpcm->dumpsize,akpcm->PlaybackCurrPos); -+ memcpy(akpcm->pcmDumpDataBuffer+akpcm->pcmDumpSize,pcmDump_dma_area+akpcm->PlaybackCurrPos,akpcm_playback_period_bytes_min); -+ akpcm->pcmDumpSize+=akpcm_playback_period_bytes_min; -+ }else{ -+ printk(KERN_ERR "akpcm->enableDump false\n"); -+ akpcm->enableDump=false; -+ } -+ } -+#endif -+ -+ } -+ else //output strm has been stopped -+ { -+ printk("output stream stopped\n"); -+ clear_bit(1,&akpcm->playbackStrmDMARunning); //DMA has finished -+ complete(&(akpcm->playbackHWDMA_completion)); -+ -+#if defined(AK_PCM_DELAY_CLOSE_DAC) -+ /* delay to close output channel */ -+ akpcm->stopoutput_work_timer.expires = jiffies + DELAY_TIME_FOR_CLOSING_DAC; -+ add_timer(&akpcm->stopoutput_work_timer); -+ -+ //close the dac in order to eliminate the noise caused by interrupt of -+ // DAC data transfer -+ tasklet_schedule(&akpcm->close_dac); -+#endif -+ } -+} -+ -+/** -+ * @brief DMA transfer for capture -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+void akpcm_capture_interrupt(unsigned long data) -+{ -+ struct snd_akpcm *akpcm = (struct snd_akpcm *)data; -+ struct snd_pcm_substream *substream = akpcm->capturesubstrm; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ dma_addr_t paddr = runtime->dma_addr; -+ u8 id = akpcm->L2BufID_For_ADC23; -+ -+ unsigned long period_bytes = 0; -+ unsigned long buffer_bytes = 0; -+ period_bytes = frames_to_bytes(runtime,runtime->period_size); -+ buffer_bytes = frames_to_bytes(runtime,runtime->buffer_size); -+ do_gettimeofday(&capSync.tv); -+ capSync.adcCapture_bytes += period_bytes; -+ akpcm->CaptureCurrPos += period_bytes; -+ if(akpcm->CaptureCurrPos >= buffer_bytes) -+ { -+ akpcm->CaptureCurrPos = 0; -+ } -+ snd_pcm_period_elapsed(substream); -+ -+//#ifdef CONFIG_SUPPORT_AEC -+ if( akpcm->dai->aec_flag == 1) -+ { -+ tasklet_schedule(&akpcm->capture_aec_tasklet); -+ } -+//#endif -+ if(test_bit(0,&akpcm->captureStrmDMARunning)) //input stream is running -+ { -+ -+ //#ifdef CONFIG_SUPPORT_AEC -+ if( akpcm->dai->aec_flag == 1) -+ { -+ AECLib_AdcInt(akpcm->pfilter, akpcm->capture_data, akpcm_capture_period_bytes_min); -+ -+ -+ l2_combuf_dma(virt_to_phys(akpcm->capture_data), id, akpcm_capture_period_bytes_min, -+ (l2_dma_transfer_direction_t)BUF2MEM,1); -+ } -+ //#else -+ else -+ { -+ l2_combuf_dma(paddr+akpcm->CaptureCurrPos, id, akpcm_capture_period_bytes_min, -+ (l2_dma_transfer_direction_t)BUF2MEM,1); -+ } -+ //#endif -+ } -+ else //input stream has been stopped -+ { -+ printk("input stream stopped\n"); -+ clear_bit(1,&akpcm->captureStrmDMARunning); -+ complete(&(akpcm->captureHWDMA_completion)); -+ -+ /* FIXME */ -+ if (akpcm->ops->adc_exit) -+ akpcm->ops->adc_exit(akpcm->dai); -+ } -+} -+ -+/** -+ * @brief trigger callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ dma_addr_t paddr = runtime->dma_addr; -+ void *vaddr = runtime->dma_area; -+ snd_pcm_uframes_t avail; -+ int avail_bytes, pend_bytes, period_bytes; -+ int start_pos0, start_pos1; -+ int bytespersample = frames_to_bytes(runtime, 1); -+ -+ void *vdst_addr0 = akpcm->pp_buf_addr[0]; -+ void *vdst_addr1 = akpcm->pp_buf_addr[1]; -+ void *pdst_addr0 = (void *)virt_to_phys(vdst_addr0); -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ { -+ u8 id = akpcm->L2BufID_For_DAC; -+ -+#if defined(AK_PCM_DELAY_CLOSE_DAC) -+ del_timer(&akpcm->stopoutput_work_timer); -+#endif -+ set_bit(0,&playback_statu); //set bit to inform that playback stream is running -+ set_bit(1,&akpcm->playbackStrmDMARunning); //set bit to inform that DMA is working -+ init_completion(&(akpcm->playbackHWDMA_completion)); -+ -+ if (akpcm->use_optimal_period) { -+ avail = snd_pcm_playback_avail(runtime); -+ avail_bytes = avail * bytespersample; -+ pend_bytes = (runtime->buffer_size - avail) * bytespersample; -+ period_bytes = akpcm->optimal_period_bytes; -+ start_pos0 = akpcm->PlaybackCurrPos; -+ start_pos1 = akpcm->PlaybackCurrPos + period_bytes; -+ -+ if (pend_bytes >= 2 * period_bytes) { -+ memcpy(vdst_addr0, vaddr + start_pos0, period_bytes); -+ memcpy(vdst_addr1, vaddr + start_pos1, period_bytes); -+ } else if (pend_bytes > period_bytes) { -+ memcpy(vdst_addr0, vaddr + start_pos0, period_bytes); -+ memcpy(vdst_addr1, vaddr + start_pos1, period_bytes); -+ memset(vdst_addr1 + pend_bytes - period_bytes, 0, 2 * period_bytes - pend_bytes); -+ } else { -+ memcpy(vdst_addr0, vaddr + start_pos0, period_bytes); -+ memset(vdst_addr0 + pend_bytes, 0, period_bytes - pend_bytes); -+ memset(vdst_addr1, 0, period_bytes); -+ } -+ -+ akpcm->playing_idx = 0; -+ akpcm->PlaybackCurrPos += period_bytes; -+ l2_clr_status(id); -+ l2_combuf_dma((unsigned long)pdst_addr0, id, period_bytes, -+ (l2_dma_transfer_direction_t)MEM2BUF,1);//start dma -+ }else { -+ l2_clr_status(id); -+ l2_combuf_dma(paddr + akpcm->PlaybackCurrPos, id, frames_to_bytes(runtime,runtime->period_size), -+ (l2_dma_transfer_direction_t)MEM2BUF,1);//start dma -+ -+ } -+ -+#ifdef CONFIG_PCM_DUMP -+ if(akpcm->enableDump){ -+ unsigned char *pcmDump_dma_area=runtime->dma_area; -+ if((akpcm->pcmDumpSize+akpcm_playback_period_bytes_min)<=akpcm_dump_data_size){ -+ //printk(KERN_ERR "akpcm->dumpsize=%d,akpcm->PlaybackCurrPos=%d \n",akpcm->dumpsize,akpcm->PlaybackCurrPos); -+ memcpy(akpcm->pcmDumpDataBuffer+akpcm->pcmDumpSize,pcmDump_dma_area+akpcm->PlaybackCurrPos,akpcm_playback_period_bytes_min); -+ akpcm->pcmDumpSize+=akpcm_playback_period_bytes_min; -+ }else{ -+ printk(KERN_ERR "akpcm->enableDump false\n"); -+ akpcm->enableDump=false; -+ } -+ } -+#endif -+ return 0; -+ } -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ clear_bit(0,&playback_statu); //stop playback stream -+ return 0; -+ } -+ return -EINVAL; -+} -+ -+/** -+ * @brief trigger callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ //struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ { -+ schedule_delayed_work(&akpcm->ds_work, msecs_to_jiffies(300)); -+ return 0; -+ } -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ clear_bit(0,&akpcm->captureStrmDMARunning); //stop capture stream -+ return 0; -+ } -+ return -EINVAL; -+} -+ -+static void delay_start_work(struct work_struct *work) -+{ -+ struct snd_akpcm *akpcm = container_of(work, struct snd_akpcm, ds_work.work); -+ struct snd_pcm_substream *substream = akpcm->capturesubstrm; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ dma_addr_t paddr = runtime->dma_addr; -+ u8 id = akpcm->L2BufID_For_ADC23; -+ set_bit(0,&akpcm->captureStrmDMARunning); //set bit to inform that capture stream is running -+ set_bit(1,&akpcm->captureStrmDMARunning); //set bit to inform that DMA is working -+ init_completion(&(akpcm->captureHWDMA_completion)); -+ l2_clr_status(id); -+ l2_combuf_dma(paddr, id, akpcm_capture_period_bytes_min, -+ (l2_dma_transfer_direction_t)BUF2MEM,1); //start dma -+ -+} -+ -+/** -+ * @brief prepare callback,open DAC, power on hp/speaker -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_playback_prepare(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int bytespersample = frames_to_bytes(runtime, 1); -+ int last_period_bytes = akpcm->optimal_period_bytes; -+ -+ if(test_bit(1,&akpcm->playbackStrmDMARunning)) -+ { -+ wait_for_completion(&(akpcm->playbackHWDMA_completion)); -+ } -+ akpcm->PlaybackCurrPos = 0; -+ -+ if (((runtime->period_size % akpcm_playback_period_aligned) != 0) || -+ ((runtime->buffer_size % runtime->period_size) != 0)) { -+ -+ /*Calculate the optimal period size depending on the aligned period size*/ -+ if (runtime->period_size % akpcm_playback_period_aligned == 0) { -+ //Doesn't need changed the original period_size -+ akpcm->optimal_period_size = runtime->period_size; -+ } else { -+ akpcm->optimal_period_size = runtime->period_size + akpcm_playback_period_aligned -+ - (runtime->period_size % akpcm_playback_period_aligned); -+ } -+ akpcm->optimal_period_bytes = akpcm->optimal_period_size * bytespersample; -+ -+ /* Allocate or reallocate contigous for Pingpong Buffer */ -+ if ((last_period_bytes != 0) && (last_period_bytes != akpcm->optimal_period_bytes)) { -+ if(akpcm->pp_buf_addr[0]) -+ snd_free_pages(akpcm->pp_buf_addr[0], GFP_KERNEL); -+ -+ akpcm->pp_buf_addr[0] = snd_malloc_pages(akpcm->optimal_period_bytes * 2, GFP_KERNEL); -+ -+ printk(KERN_ERR"Pingpong Buffer Warning: Reallocate memory[old=%d, new=%d]\n", -+ last_period_bytes, akpcm->optimal_period_bytes); -+ } else { -+ if (akpcm->pp_buf_addr[0] == NULL) -+ akpcm->pp_buf_addr[0] = snd_malloc_pages(akpcm->optimal_period_bytes * 2, GFP_KERNEL); -+ } -+ -+ /* Decide whether to start Pingpong Buffer */ -+ if (akpcm->pp_buf_addr[0] == NULL) { -+ printk(KERN_ERR"Pingpong Buffer Warning: allocate memory failed!\n"); -+ akpcm->optimal_period_size = 0; -+ akpcm->optimal_period_bytes = 0; -+ akpcm->use_optimal_period = false; -+ } else { -+ akpcm->pp_buf_addr[1] = akpcm->pp_buf_addr[0] + akpcm->optimal_period_bytes; -+ akpcm->use_optimal_period = true; -+ } -+ } else { -+ akpcm->optimal_period_size = 0; -+ akpcm->optimal_period_bytes = 0; -+ akpcm->use_optimal_period = false; -+ } -+ -+ if (akpcm->use_optimal_period) { -+ l2_set_dma_callback(akpcm->L2BufID_For_DAC, akpcm_playback_interrupt_optimize,(unsigned long)akpcm); -+ }else -+ l2_set_dma_callback(akpcm->L2BufID_For_DAC, akpcm_playback_interrupt,(unsigned long)akpcm); -+ -+ /* FIXME */ -+ if (akpcm->ops->start_to_play) { -+ akpcm->ops->start_to_play(akpcm->dai, runtime->channels, runtime->rate); -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief prepare callback,open ADC23, power on mic -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_capture_prepare(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ l2_set_dma_callback(akpcm->L2BufID_For_ADC23,akpcm_capture_interrupt,(unsigned long)akpcm); -+ do_gettimeofday(&capSync.tv); -+ capSync.adcCapture_bytes = 0; -+ capSync.frame_bits = runtime->frame_bits; -+ capSync.rate = runtime->rate; -+ -+ akpcm->CaptureCurrPos = 0; -+ /* FIXME */ -+ if (akpcm->ops->set_adc_samplerate) -+ capSync.rate = akpcm->ops->set_adc_samplerate(akpcm->dai, runtime->rate); -+ -+ if (akpcm->ops->set_adc_channels) -+ akpcm->ops->set_adc_channels(akpcm->dai, runtime->channels); -+ -+ if (akpcm->ops->adc_init) -+ akpcm->ops->adc_init(akpcm->dai); -+ -+ if (akpcm->ops->capture_start) -+ akpcm->ops->capture_start(akpcm->dai); -+ -+ -+ return 0; -+} -+ -+/** -+ * @brief pointer callback,updata ringbuffer pointer -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static snd_pcm_uframes_t akpcm_playback_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return(bytes_to_frames(runtime,akpcm->PlaybackCurrPos)); //updata ringbuffer pointer -+} -+ -+/** -+ * @brief pointer callback, updata ringbuffer pointer -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static snd_pcm_uframes_t akpcm_capture_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return(bytes_to_frames(runtime,akpcm->CaptureCurrPos)); //updata ringbuffer pointer -+} -+ -+static struct snd_pcm_hardware akpcm_playback_hardware = { -+ .info = (SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_RESUME | -+ SNDRV_PCM_INFO_PAUSE | -+ SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = USE_FORMATS, -+ .rates = USE_RATE, -+ .rate_min = USE_RATE_MIN, -+ .rate_max = USE_RATE_MAX, -+ .channels_min = PLAYBACK_USE_CHANNELS_MIN, -+ .channels_max = PLAYBACK_USE_CHANNELS_MAX, -+ .buffer_bytes_max = akpcm_playback_buf_bytes_max, -+ .period_bytes_min = akpcm_playback_period_bytes_min, -+ .period_bytes_max = akpcm_playback_period_bytes_max, -+ .periods_min = akpcm_playback_periods_min, -+ .periods_max = akpcm_playback_periods_max, -+ .fifo_size = 0, -+}; -+ -+static struct snd_pcm_hardware akpcm_capture_hardware = { -+ .info = (SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_BLOCK_TRANSFER | -+ SNDRV_PCM_INFO_RESUME | -+ SNDRV_PCM_INFO_MMAP_VALID), -+ .formats = USE_FORMATS, -+ .rates = USE_RATE, -+ .rate_min = USE_RATE_MIN, -+ .rate_max = USE_RATE_MAX, -+ .channels_min = CAPTURE_USE_CHANNELS_MIN, -+ .channels_max = CAPTURE_USE_CHANNELS_MAX, -+ .buffer_bytes_max = akpcm_capture_buf_bytes_max, -+ .period_bytes_min = akpcm_capture_period_bytes_min, -+ .period_bytes_max = akpcm_capture_period_bytes_min, -+ .periods_min = akpcm_capture_periods_min, -+ .periods_max = akpcm_capture_periods_max, -+ .fifo_size = 0, -+}; -+ -+/** -+ * @brief hw_params callback, malloc ringbuffer -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_playback_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ if(BUF_NULL==akpcm->L2BufID_For_DAC) -+ { -+ akpcm->L2BufID_For_DAC = l2_alloc((l2_device_t)ADDR_DAC); //alloc l2 buffer for DAC -+ if(BUF_NULL==akpcm->L2BufID_For_DAC) -+ { -+ printk(KERN_ERR "alloc L2 buffer for DAC error!"); -+ return -ENOMEM; -+ } -+ } -+ return(snd_pcm_lib_malloc_pages(substream, -+ params_buffer_bytes(hw_params))); -+} -+ -+/** -+ * @brief hw_params callback, malloc ringbuffer -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_capture_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ if(BUF_NULL==akpcm->L2BufID_For_ADC23) -+ { -+ akpcm->L2BufID_For_ADC23 = l2_alloc((l2_device_t)ADDR_ADC); //alloc l2 buffer for ADC23 -+ if(BUF_NULL==akpcm->L2BufID_For_ADC23) -+ { -+ printk(KERN_ERR "alloc L2 buffer for DAC error!"); -+ return -ENOMEM; -+ } -+ } -+ return(snd_pcm_lib_malloc_pages(substream, -+ params_buffer_bytes(hw_params))); -+} -+ -+/** -+ * @brief hw_free callback, free ringbuffer -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_playback_hw_free(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ -+ if(test_bit(1,&akpcm->playbackStrmDMARunning)) -+ { -+ wait_for_completion(&(akpcm->playbackHWDMA_completion)); -+ } -+ if(BUF_NULL!=akpcm->L2BufID_For_DAC) -+ { -+ /* FIXME */ -+#if !defined(AK_PCM_DELAY_CLOSE_DAC) -+ if (akpcm->ops->playback_end) { -+ akpcm->ops->playback_end(akpcm->dai); -+ } -+#endif -+ if (akpcm->ops->dac_exit) { -+ akpcm->ops->dac_exit(akpcm->dai); -+ } -+ -+ l2_free((l2_device_t)ADDR_DAC); -+ akpcm->L2BufID_For_DAC = BUF_NULL; -+ } -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+/** -+ * @brief hw_free callback, free ringbuffer -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_capture_hw_free(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ -+ if(test_bit(1,&akpcm->captureStrmDMARunning)) -+ { -+ wait_for_completion(&(akpcm->captureHWDMA_completion)); -+ } -+ if(BUF_NULL!=akpcm->L2BufID_For_ADC23) -+ { -+ /* FIXME */ -+ if (akpcm->ops->adc_exit) -+ akpcm->ops->adc_exit(akpcm->dai); -+ if (akpcm->ops->capture_end) -+ akpcm->ops->capture_end(akpcm->dai); -+ -+ l2_free((l2_device_t)ADDR_ADC); -+ akpcm->L2BufID_For_ADC23 = BUF_NULL; -+ } -+ return(snd_pcm_lib_free_pages(substream)); -+} -+ -+/** -+ * @brief open callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_playback_open(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ akpcm->playbacksubstrm = substream; -+ runtime->hw = akpcm_playback_hardware; -+ dac_clock = 0; -+ -+ if (akpcm->pp_buf_addr[0]) { -+ printk(KERN_ERR"akpcm_playback_open==>pp_buf_addr[0]=0x%08x, memory leak happened\n", (unsigned int)akpcm->pp_buf_addr[0]); -+ } else { -+ akpcm->pp_buf_addr[0] = NULL; -+ akpcm->pp_buf_addr[1] = NULL; -+ } -+ akpcm->optimal_period_size = 0; -+ akpcm->optimal_period_bytes = 0; -+ -+ //#ifdef CONFIG_SUPPORT_AEC -+ if (!akpcm->playback_data) -+ { -+ akpcm->playback_data = kmalloc(akpcm_playback_period_bytes_min * 2, GFP_KERNEL); -+ if (!akpcm->playback_data) -+ { -+ printk("ak37pcm_playback_open==>allocate memory for playback_data failed!\n"); -+ } -+ } -+ //#endif -+ return 0; -+} -+ -+/** -+ * @brief open callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_capture_open(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ akpcm->capturesubstrm = substream; -+ runtime->hw = akpcm_capture_hardware; -+ akpcm->CaptureCurrPos = 0; -+ -+//#ifdef CONFIG_SUPPORT_AEC -+ if(!akpcm->capture_data) -+ { -+ akpcm->capture_data = kmalloc(akpcm_capture_period_bytes_min, GFP_KERNEL); -+ if (!akpcm->capture_data) -+ { -+ printk("akpcm_capture_open==>allocate memory for capture_data failed!\n"); -+ } -+ } -+ if(!akpcm->temp) -+ { -+ akpcm->temp= kmalloc(akpcm_capture_period_bytes_min, GFP_KERNEL); -+ if (!akpcm->temp) -+ { -+ printk("akpcm_capture_open==>allocate memory for temp failed!\n"); -+ } -+ //memset(akpcm->temp, 0x) -+ } -+//#endif -+ return 0; -+} -+ -+/** -+ * @brief close callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_playback_close(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ -+ akpcm->playbacksubstrm=NULL; -+ dac_clock = 0; -+ -+ if (akpcm->pp_buf_addr[0] != NULL) { -+ snd_free_pages(akpcm->pp_buf_addr[0], GFP_KERNEL); -+ akpcm->pp_buf_addr[0] = NULL; -+ akpcm->pp_buf_addr[1] = NULL; -+ } -+ -+ //#ifdef CONFIG_SUPPORT_AEC -+ if (akpcm->playback_data) -+ { -+ kfree(akpcm->playback_data); -+ akpcm->playback_data = NULL; -+ } -+ //#endif -+ -+ return 0; -+} -+ -+/** -+ * @brief close callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_capture_close(struct snd_pcm_substream *substream) -+{ -+ struct snd_akpcm *akpcm = snd_pcm_substream_chip(substream); -+ capSync.adcCapture_bytes = 0; -+ akpcm->capturesubstrm=NULL; -+ return 0; -+} -+ -+/** -+ * @brief mmap callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int akpcm_pcm_mmap(struct snd_pcm_substream *substream, -+ struct vm_area_struct *vma) -+{ -+ return remap_pfn_range(vma, vma->vm_start, -+ substream->dma_buffer.addr >> PAGE_SHIFT, -+ vma->vm_end - vma->vm_start, vma->vm_page_prot); -+} -+ -+ -+static struct snd_pcm_ops akpcm_playback_ops = { -+ .open = akpcm_playback_open, -+ .close = akpcm_playback_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = akpcm_playback_hw_params, -+ .hw_free = akpcm_playback_hw_free, -+ .prepare = akpcm_playback_prepare, -+ .trigger = akpcm_playback_trigger, -+ .pointer = akpcm_playback_pointer, -+ .mmap = akpcm_pcm_mmap, -+}; -+ -+static struct snd_pcm_ops akpcm_capture_ops = { -+ .open = akpcm_capture_open, -+ .close = akpcm_capture_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = akpcm_capture_hw_params, -+ .hw_free = akpcm_capture_hw_free, -+ .prepare = akpcm_capture_prepare, -+ .trigger = akpcm_capture_trigger, -+ .pointer = akpcm_capture_pointer, -+ .mmap = akpcm_pcm_mmap, -+}; -+ -+ -+#ifdef CONFIG_CPU_FREQ -+ -+#define freq_to_akpcm(_n) container_of(_n, struct snd_akpcm, freq_transition) -+ -+/** -+ * @brief handle cpu frequency changing -+ * Note: need to handle in PLL changed mode only -+ * @author Cao LianMing -+ * @date 2011-07-26 -+ * @parm [in] nb : the nitifier_block data struct -+ * @parm [in] val : CPUFREQ_PRECHANGE / CPUFREQ_POSTCHANGE -+ * @parm [in] data : argument -+ * @return int : if successful return 0, otherwise return nagative -+ * @retval 0 : handle successful -+ * @retval <0 : handle failed -+ */ -+static int akpcm_cpufreq_transition(struct notifier_block *nb, -+ unsigned long val, void *data) -+{ -+ struct snd_akpcm *akpcm = freq_to_akpcm(nb); -+ struct cpufreq_freqs *freqs = data; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ -+ if (val == CPUFREQ_PRECHANGE) { -+ if (freqs->old_cpufreq.pll_sel != freqs->new_cpufreq.pll_sel) { -+ if (test_bit(0,&playback_statu)) { -+ printk("---- stop pcm playback\n"); -+ -+ substream = akpcm->playbacksubstrm; -+ /* suspend PCM data transmission */ -+ akpcm_playback_trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); -+ set_bit(2, &akpcm->playbackStrmDMARunning); -+ wait_for_completion(&(akpcm->playbackHWDMA_completion)); -+ } else { -+ clear_bit(2, &akpcm->playbackStrmDMARunning); -+ } -+ } -+ } else if (val == CPUFREQ_POSTCHANGE) { -+ if (freqs->old_cpufreq.pll_sel != freqs->new_cpufreq.pll_sel) { -+ if (test_bit(2,&akpcm->playbackStrmDMARunning)) { -+ printk("---- restart pcm playback\n"); -+ -+ substream = akpcm->playbacksubstrm; -+ runtime = substream->runtime; -+ /* reconfig sample rate after PLL has been changed */ -+ /* FIXME */ -+ if (akpcm->ops->set_dac_samplerate) -+ akpcm->ops->set_dac_samplerate(akpcm->dai, runtime->rate); -+ -+ /* resume PCM data transmission */ -+ akpcm_playback_trigger(substream, SNDRV_PCM_TRIGGER_RESUME); -+ clear_bit(2, &akpcm->playbackStrmDMARunning); -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief register the akpcm cpufreq changing handle function to the cpufreq core -+ * @author Cao LianMing -+ * @date 2011-07-26 -+ * @parm [in] akpcm : the private data struct of the akpcm driver -+ * @return int : if register successful return 0, otherwise, return negative -+ * @retval 0 : successful -+ * @retval <0 : failed -+ */ -+static inline int akpcm_cpufreq_register(struct snd_akpcm *akpcm) -+{ -+ akpcm->freq_transition.notifier_call = akpcm_cpufreq_transition; -+ -+ return cpufreq_register_notifier(&akpcm->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+/** -+ * @brief unregister the akpcm cpufreq changing handle function from the cpufreq core -+ * @author Cao LianMing -+ * @date 2011-07-26 -+ * @parm [in] akpcm : the private data struct of the akpcm driver -+ * @return int : if unregister successful return 0, otherwise, return negative -+ * @retval 0 : successful -+ * @retval <0 : failed -+ */ -+static inline void akpcm_cpufreq_deregister(struct snd_akpcm *akpcm) -+{ -+ cpufreq_unregister_notifier(&akpcm->freq_transition, -+ CPUFREQ_TRANSITION_NOTIFIER); -+} -+ -+#else -+static inline int akpcm_cpufreq_register(struct snd_akpcm *akpcm) -+{ -+ return 0; -+} -+ -+static inline void akpcm_cpufreq_deregister(struct snd_akpcm *akpcm) -+{ -+} -+#endif -+ -+/** -+ * @brief Shutdown all ak ad/da modules -+ * @author Cheng JunYi -+ * @date 2011-09-27 -+ * @parm [in] in_akpcm : the private data struct of akpcm driver -+ * @return void -+ * @retval -+ */ -+static inline void akpcm_close(struct snd_akpcm *in_akpcm) -+{ -+ -+ struct snd_akpcm *akpcm = in_akpcm; -+ if(test_bit(1,&akpcm->playbackStrmDMARunning)) -+ { -+ wait_for_completion(&(akpcm->playbackHWDMA_completion)); -+ } -+ -+ if(test_bit(1,&akpcm->captureStrmDMARunning)) -+ { -+ wait_for_completion(&(akpcm->captureHWDMA_completion)); -+ } -+ -+ //close analog module -+ /* FIXME */ -+ if (akpcm->ops->dac_exit) -+ akpcm->ops->dac_exit(akpcm->dai); -+ if (akpcm->ops->playback_end) -+ akpcm->ops->playback_end(akpcm->dai); -+ if (akpcm->ops->adc_exit) -+ akpcm->ops->adc_exit(akpcm->dai); -+ if (akpcm->ops->capture_end) -+ akpcm->ops->capture_end(akpcm->dai); -+} -+ -+ -+/** -+ * @brief create new card -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int __devinit snd_card_akpcm_pcm(struct snd_akpcm *akpcm, int device, -+ int substreams) -+{ -+ struct snd_pcm *pcm; -+ struct snd_pcm_substream *substream; -+ int err; -+ err = snd_pcm_new(akpcm->card, "akpcm PCM", device, -+ substreams, substreams, &pcm); -+ if (err < 0) -+ return err; -+ akpcm->pcm = pcm; -+ cur_pcm = pcm; -+ -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &akpcm_playback_ops); //register callbacks -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &akpcm_capture_ops);//register callbacks -+ pcm->private_data = akpcm; -+ pcm->info_flags = 0; -+ strcpy(pcm->name, "akpcm PCM"); -+ -+ substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; -+ snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, akpcm->card->dev, -+ akpcm_playback_buf_bytes_max, akpcm_playback_buf_bytes_max); -+ -+ substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; -+ snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, akpcm->card->dev, -+ akpcm_capture_buf_bytes_max, akpcm_capture_buf_bytes_max); -+ return 0; -+} -+ -+/************** -+ * proc interface -+ **************/ -+#ifdef CONFIG_PCM_DUMP -+ -+/** -+ * @brief Dump the ak ad/da registers to the proc file -+ * @author Cheng JunYi -+ * @date 2011-08-04 -+ * @parm [in] entry : snd handle of akpcm driver -+ * @parm [in] buffer : buffer of the proc file -+ * @return void -+ * @retval -+ */ -+static void akpcm_registers_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) -+{ -+ -+ //snd_iprintf(buffer,"ADC23 clock Register2 =0x%lu\n",REG32(RegAddr.pAddress0800 + CLK_DIV_REG2)); -+ -+ //snd_iprintf(buffer,"Multi-func Control Register1 =0x%lu\n",REG32(RegAddr.pAddress0800 + MULTIPLE_FUN_CTRL_REG1)); -+ -+ //snd_iprintf(buffer,"Analog Control Register1 =0x%lu\n",REG32(RegAddr.pAddress0800 + ANALOG_CTRL_REG1_READ)); -+ //snd_iprintf(buffer,"Analog Control Register2 =0x%lu\n",REG32(RegAddr.pAddress0800 + ANALOG_CTRL_REG2_READ)); -+ //snd_iprintf(buffer,"Analog Control Register3 =0x%lu\n",REG32(RegAddr.pAddress0800 + ANALOG_CTRL_REG3)); -+ //snd_iprintf(buffer,"Analog Control Register4 =0x%lu\n",REG32(RegAddr.pAddress0800 + ANALOG_CTRL_REG4)); -+ -+ //snd_iprintf(buffer,"ADC2 configuration Register =0x%lu\n",REG32(RegAddr.pAddress2002D + ADC2MODE_CFG_REG)); -+ //snd_iprintf(buffer,"ADC2 Data Register =0x%lu\n",REG32(RegAddr.pAddress2002D + I2S_CONFIG_REG)); -+ -+ //snd_iprintf(buffer,"DAC configuration Register =0x%lu\n",REG32(RegAddr.pAddress2002E + DAC_CONFIG_REG)); -+ //snd_iprintf(buffer,"CPU Data Register =0x%lu\n",REG32(RegAddr.pAddress2002E + CPU_DATA_REG)); -+ -+} -+ -+ -+/** -+ * @brief Handle the write operation of proc file /proc/asound/card0/pcm-dumpctrl -+ * Start or stop dump data to the pcm-dumpdata file -+ * @author Cheng JunYi -+ * @date 2011-08-04 -+ * @parm [in] entry : snd handle of akpcm driver -+ * @parm [in] buffer : "open" means start dump pcm data to /proc/asound/card0/pcm-dumpdata; -+ "close" means stop dump pcm data to /proc/asound/card0/pcm-dumpdata -+ * @return void -+ * @retval -+ */ -+void akpcm_dumpctrl_write(struct snd_info_entry *entry, -+ struct snd_info_buffer *buffer) -+{ -+ char line[256]; -+ char str[256]; -+ struct snd_akpcm *akpcm=entry->private_data; -+ snd_info_get_line(buffer, line, 256); -+ snd_info_get_str(str, line, 256); -+ -+ if(strncmp("open", str, strlen("open"))==0){ -+ -+ memset(akpcm->pcmDumpDataBuffer,0,akpcm_dump_data_size); -+ akpcm->pcmDumpSize=0; -+ akpcm->enableDump=true; -+ do_gettimeofday(&akpcm->pcmDumpTime); -+ printk(KERN_ERR "akpcm->enableDump true\n"); -+ -+ }else if(strncmp("close", str, strlen("close"))==0){ -+ -+ akpcm->enableDump=false; -+ akpcm->pcmDumpSize=0; -+ printk(KERN_ERR "akpcm->enableDump false\n"); -+ -+ } -+} -+ -+ -+/** -+ * @brief Handle the read operation of proc file /proc/asound/card0/pcm-dumpctrl -+ * Show the last dump time -+ * @author Cheng JunYi -+ * @date 2011-08-04 -+ * @parm [in] entry : snd handle of akpcm driver -+ * @parm [in] buffer : buffer of the proc file, will return the last dump time -+ * @return void -+ * @retval -+ */ -+static void akpcm_dumpctrl_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) -+{ -+ -+ struct snd_akpcm *akpcm=entry->private_data; -+ struct tm tm_result; -+ -+ time_to_tm(akpcm->pcmDumpTime.tv_sec,0,&tm_result); -+ snd_iprintf(buffer, "last dump timestamp: %lu-%02d-%02d %02d:%02d:%02d UTC\n",tm_result.tm_year + 1900, tm_result.tm_mon + 1, tm_result.tm_mday, tm_result.tm_hour,tm_result.tm_min,tm_result.tm_sec); -+ -+} -+ -+ -+/** -+ * @brief Handle the read operation of proc file /proc/asound/card0/pcm-dumpdata -+ * Return the pcm data to application -+ * @author Cheng JunYi -+ * @date 2011-08-04 -+ * @parm [in] entry : snd handle of akpcm driver -+ * @parm [in] buffer : buffer of the proc file, will return the pcm data -+ * @return void -+ * @retval -+ */ -+static long akpcm_dumpdata_read(struct snd_info_entry *entry, -+ void *file_private_data, -+ struct file *file, char __user *buf, -+ unsigned long count, unsigned long pos) -+{ -+ -+ long size; -+ -+ struct snd_akpcm *akpcm=entry->private_data; -+ -+ size = count; -+ if (pos + size > akpcm_dump_data_size) -+ size = akpcm_dump_data_size - pos; -+ -+ if (size > 0) { -+ if (copy_to_user(buf,akpcm->pcmDumpDataBuffer+pos,size)) -+ return -EFAULT; -+ } -+ -+ return size; -+} -+ -+ -+static struct snd_info_entry_ops akpcm_dumpdata_proc_ops = { -+ .read = akpcm_dumpdata_read, -+}; -+ -+#endif -+ -+ -+/** -+ * @brief Handle the reboot event -+ * @author Cheng JunYi -+ * @date 2011-09-27 -+ * @parm [in] nb : the nitifier_block data struct -+ * @parm [in] code : message -+ * @parm [in] unused : argument, unused -+ * @return int : handle successful or not -+ * @retval NOTIFY_DONE : handle successful -+ */ -+static int akpcm_reboot_notify(struct notifier_block *nb, -+ unsigned long code, void *unused) -+{ -+ struct snd_akpcm *akpcm; -+ -+ printk(KERN_ERR "akpcm_reboot_notify \n"); -+ -+ mutex_lock(&reboot_lock); -+ -+ if (!reboot_info) -+ goto out; -+ -+ akpcm = reboot_info; -+ akpcm_close(akpcm); -+ -+ out: -+ printk(KERN_ERR "akpcm_reboot_notify out\n"); -+ mutex_unlock(&reboot_lock); -+ -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block akpcm_reboot_notifier = { -+ .notifier_call = akpcm_reboot_notify, -+}; -+ -+ -+//#ifdef CONFIG_SUPPORT_AEC -+T_pVOID akpcm_capture_aec_kmalloc(T_U32 size) -+{ -+ return kmalloc(size, GFP_KERNEL | GFP_ATOMIC); -+} -+T_VOID akpcm_capture_aec_kfree(T_pVOID mem) -+{ -+ kfree(mem); -+} -+//#endif -+ -+/** -+ * @brief Init the device which was probed, and register a snd device -+ * @author Cheng MingJuan -+ * @date 2010-11-20 -+ * @parm [in] pdev : the device definition -+ * @return int : if init successful return 0, otherwise, return negative -+ * @retval 0 : successful -+ * @retval <0 : failed -+ */ -+static int __devinit snd_akpcm_probe(struct platform_device *devptr) -+{ -+ struct snd_card *card; -+ struct snd_akpcm *akpcm; -+ //struct snd_info_entry *entry; -+ int dev_id, err; -+ -+ memset(&capSync, 0, sizeof(capSync)); -+ //get analog control registers -+ -+ dev_id = devptr->id; -+ if (dev_id < 0) -+ dev_id = 0; -+ err = snd_card_create(dev_id, NULL, THIS_MODULE, sizeof(struct snd_akpcm), &card); -+ if (err < 0) -+ return err; -+ -+ snd_card_set_dev(card, &devptr->dev); -+ -+ akpcm = card->private_data; -+ akpcm->card = card; -+ cur_card = card; -+ -+ //init l2 buf for audio -+ akpcm->L2BufID_For_DAC = BUF_NULL; -+ akpcm->L2BufID_For_ADC23 = BUF_NULL; -+ -+ err = snd_card_akpcm_pcm(akpcm, 0, 1); -+ if (err < 0) -+ goto __out_free_card; -+ -+ //init tiimer to stop output channel -+ init_timer(&akpcm->stopoutput_work_timer); -+ akpcm->stopoutput_work_timer.function = ak_close_dac_timer; -+ akpcm->stopoutput_work_timer.data = (unsigned long)akpcm; -+ -+ akpcm->fetch_tasklet.func = alsabuf_to_ppbuf; -+ akpcm->fetch_tasklet.data = (unsigned long)akpcm; -+ akpcm->pp_buf_addr[0] = NULL; -+ -+ akpcm->close_dac.func = dac_exit_tasklet; -+ akpcm->close_dac.data = (unsigned long)akpcm; -+ -+ -+//#ifdef CONFIG_SUPPORT_AEC -+ akpcm->capture_aec_tasklet.func = ak37pcm_capture_aec; -+ akpcm->capture_aec_tasklet.data = (unsigned long)akpcm; -+ -+ akpcm->playback_aec_tasklet.func = ak37pcm_playback_aec; -+ akpcm->playback_aec_tasklet.data = (unsigned long)akpcm; -+//#endif -+ -+ INIT_DELAYED_WORK(&akpcm->ds_work, delay_start_work); -+ -+ clear_bit(0,&playback_statu); -+ clear_bit(1,&akpcm->playbackStrmDMARunning); -+ clear_bit(0,&akpcm->captureStrmDMARunning); -+ clear_bit(1,&akpcm->captureStrmDMARunning); -+ -+#ifdef CONFIG_PCM_DUMP -+ -+ snd_card_proc_new (akpcm->card, "registers", &entry); -+ snd_info_set_text_ops(entry, akpcm, akpcm_registers_read); -+ -+ akpcm->pcmDumpDataBuffer = vmalloc(akpcm_dump_data_size); -+ if (!akpcm->pcmDumpDataBuffer) -+ return -ENOMEM; -+ -+ memset(akpcm->pcmDumpDataBuffer, 0, akpcm_dump_data_size); -+ -+ snd_card_proc_new (akpcm->card, "pcm-dumpctrl", &entry); -+ entry->private_data = akpcm; -+ entry->mode = S_IFREG | S_IRUGO | S_IWUSR; -+ entry->c.text.write = akpcm_dumpctrl_write; -+ snd_info_set_text_ops(entry, akpcm, akpcm_dumpctrl_read); -+ -+ if (! snd_card_proc_new(akpcm->card, "pcm-dumpdata", &entry)) { -+ entry->content = SNDRV_INFO_CONTENT_DATA; -+ entry->private_data = akpcm; -+ entry->c.ops = &akpcm_dumpdata_proc_ops; -+ entry->size = akpcm_dump_data_size; -+ entry->mode = S_IFREG|S_IRUGO; -+ } -+ -+#endif -+ -+ strcpy(card->driver, "akpcm"); -+ strcpy(card->shortname, "Ak AD/DA"); -+ sprintf(card->longname, "Ak ADC DAC pcm input & output module %i", dev_id + 1); -+ -+ err = akpcm_cpufreq_register(akpcm); -+ if (err < 0) { -+ printk(KERN_ERR "Failed to register cpufreq\n"); -+ } -+ -+ mutex_lock(&reboot_lock); -+ reboot_info = akpcm; -+ mutex_unlock(&reboot_lock); -+ -+//#ifdef CONFIG_SUPPORT_AEC -+ memset(&akpcm->p_aecin, 0, sizeof(akpcm->p_aecin)); -+ memset(&akpcm->p_aecbufs, 0, sizeof(akpcm->p_aecbufs)); -+ akpcm->p_aecin.cb_fun.Malloc = akpcm_capture_aec_kmalloc; -+ akpcm->p_aecin.cb_fun.Free = akpcm_capture_aec_kfree; -+ akpcm->p_aecin.cb_fun.printf = (AEC_CALLBACK_FUN_PRINTF)printk; -+ //akpcm->p_aecin.m_info.m_Type = AEC_TYPE_2; -+ //akpcm->p_aecin.m_info.m_BitsPerSample = AEC_BITSPERSAMPLE; -+ akpcm->p_aecin.m_info.m_Channels = AEC_CHANNELS; -+ akpcm->p_aecin.m_info.m_SampleRate = AEC_SAMPLERATE; -+ -+ //akpcm->p_aecin.m_info.m_Private.m_aec.m_PreprocessEna = 0; -+ //akpcm->p_aecin.m_info.m_Private.m_aec.m_framelen = AEC_NN; -+ akpcm->p_aecin.m_info.m_Private.m_aec.m_tail = 1280; -+ akpcm->p_aecin.m_info.m_Private.m_aec.m_aecBypass = 0; -+ akpcm->p_aecin.m_info.m_Private.m_aec.m_framelen = 256; -+ akpcm->p_aecin.m_info.m_Private.m_aec.m_PreprocessEna = 1; -+ akpcm->p_aecin.m_info.m_Private.m_aec.AGClevel = 24576; -+ akpcm->p_aecin.m_info.m_Private.m_aec.maxGain = 3; -+ akpcm->p_aecin.m_info.m_Private.m_aec.DacVolume = 1024; -+ akpcm->p_aecin.m_info.m_Private.m_aec.AdcCutTime = 100; -+ akpcm->p_aecin.m_info.m_Private.m_aec.AdcMinSpeechPow = 1024; -+ akpcm->p_aecin.m_info.m_Private.m_aec.DacMinSpeechPow = 512; -+ akpcm->p_aecin.m_info.m_Private.m_aec.AdcSpeechMultiple = (T_U32)(1.8*(1<<14)); -+ akpcm->p_aecin.m_info.m_Private.m_aec.DacSpeechMultiple = (T_U32)(1.8*(1<<14)); -+ akpcm->p_aecin.m_info.m_Private.m_aec.AdcSpeechHoldTime = 900; -+ akpcm->p_aecin.m_info.m_Private.m_aec.DacSpeechHoldTime = 900; -+ akpcm->p_aecin.m_info.m_Private.m_aec.AdcConvergTime = 10000; -+ akpcm->p_aecin.m_info.m_Private.m_aec.DacConvergTime = 10000; -+ akpcm->pfilter = AECLib_Open(&akpcm->p_aecin); -+ if (akpcm->pfilter) { -+ printk("AEC function has been successfully activated!\n"); -+ } else { -+ printk("Failed to initialize AEC Lib, AEC function is closed\n"); -+ } -+//#endif -+ -+ -+ -+ err = snd_card_register(card); -+ if (err == 0) { -+ platform_set_drvdata(devptr, card); -+ return 0; -+ } -+ -+__out_free_card: -+ snd_card_free(card); -+ -+ return err; -+} -+ -+/** -+ * @brief De-init the device which will be removed, and unregister the snd device -+ * @author Cheng MingJuan -+ * @date 2010-11-22 -+ * @parm [in] pdev : the device definition -+ * @return int : if handle successful return 0, otherwise, return negative -+ * @retval 0 : successful -+ * @retval <0 : failed -+ */ -+static int __devexit snd_akpcm_remove(struct platform_device *devptr) -+{ -+ struct snd_card *card = platform_get_drvdata(devptr); -+ struct snd_akpcm *akpcm = card->private_data; -+ -+ akpcm_close(akpcm); -+ -+ akpcm_cpufreq_deregister(akpcm); -+ -+ del_timer(&akpcm->stopoutput_work_timer); -+ -+//#ifdef CONFIG_SUPPORT_AEC -+ AECLib_Close(akpcm->pfilter); -+ kfree(akpcm->capture_data); -+ kfree(akpcm->playback_data); -+//#endif -+ /* FIXME */ -+ snd_card_set_dev(card, NULL); -+ snd_card_free(card); -+ platform_set_drvdata(devptr, NULL); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+/** -+ * @brief suspend callback -+ * @author Cheng Mingjuan -+ * @revisor Wu Daochao(2012-09-24) -+ * @date -+ * @return void -+ */ -+static int snd_ak_suspend(struct platform_device *pdev, pm_message_t msg) -+{ -+ struct snd_card *card = platform_get_drvdata(pdev); -+ struct snd_akpcm *akpcm = card->private_data; -+ -+ /* FIXME */ -+ akpcm_close(akpcm); -+ -+ return 0; -+} -+ -+/** -+ * @brief resume callback -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int snd_ak_resume(struct platform_device *pdev) -+{ -+ return 0; -+} -+#else -+#define snd_ak_suspend NULL -+#define snd_ak_resume NULL -+#endif -+ -+ -+#define SND_AKPCM_DRIVER "snd_akpcm" -+ -+static struct platform_driver snd_akpcm_driver = { -+ .probe = snd_akpcm_probe, -+ .remove = __devexit_p(snd_akpcm_remove), -+ .suspend = snd_ak_suspend, -+ .resume = snd_ak_resume, -+ .driver = { -+ .name = SND_AKPCM_DRIVER -+ }, -+}; -+ -+/** -+ * @brief register driver -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static int __init alsa_card_akpcm_init(void) -+{ -+ int err; -+ -+ err = platform_driver_register(&snd_akpcm_driver); -+ if (err < 0) -+ return err; -+ -+ register_reboot_notifier(&akpcm_reboot_notifier); -+ -+ return 0; -+} -+ -+/** -+ * @brief unregister driver -+ * @author Cheng Mingjuan -+ * @date -+ * @return void -+ */ -+static void __exit alsa_card_akpcm_exit(void) -+{ -+ platform_driver_unregister(&snd_akpcm_driver); -+ unregister_reboot_notifier(&akpcm_reboot_notifier); -+} -+ -+module_init(alsa_card_akpcm_init); -+module_exit(alsa_card_akpcm_exit); -+ -+MODULE_AUTHOR("Anyka, Inc."); -+MODULE_DESCRIPTION("akpcm soundcard"); -+MODULE_LICENSE("GPL"); -+MODULE_SUPPORTED_DEVICE("{{ALSA,akpcm soundcard}}"); -+ -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index c88d9741..18711a50 100644 ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -1412,7 +1412,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) - struct snd_soc_dai_link *dai_link; - int ret, i, order; - -- mutex_lock(&card->mutex); -+ mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); - - if (card->instantiated) { - mutex_unlock(&card->mutex); -@@ -3123,6 +3123,7 @@ int snd_soc_register_card(struct snd_soc_card *card) - INIT_LIST_HEAD(&card->dapm_dirty); - card->instantiated = 0; - mutex_init(&card->mutex); -+ mutex_init(&card->dapm_mutex); - - mutex_lock(&client_mutex); - list_add(&card->list, &card_list); -diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c -index 9ae82a4e..6201fc54 100644 ---- a/sound/soc/soc-dapm.c -+++ b/sound/soc/soc-dapm.c -@@ -1947,6 +1947,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, - */ - int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) - { -+ int ret; -+ - /* - * Suppress early reports (eg, jacks syncing their state) to avoid - * silly DAPM runs during card startup. -@@ -1954,7 +1956,10 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) - if (!dapm->card || !dapm->card->instantiated) - return 0; - -- return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); -+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); -+ ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); -+ mutex_unlock(&dapm->card->dapm_mutex); -+ return ret; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); - -@@ -2118,19 +2123,21 @@ err: - int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_route *route, int num) - { -- int i, ret; -+ int i, ret = 0; - -+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); - for (i = 0; i < num; i++) { - ret = snd_soc_dapm_add_route(dapm, route); - if (ret < 0) { - dev_err(dapm->dev, "Failed to add route %s->%s\n", - route->source, route->sink); -- return ret; -+ break; - } - route++; - } -+ mutex_unlock(&dapm->card->dapm_mutex); - -- return 0; -+ return ret; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); - -@@ -2201,12 +2208,14 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, - int i, err; - int ret = 0; - -+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); - for (i = 0; i < num; i++) { - err = snd_soc_dapm_weak_route(dapm, route); - if (err) - ret = err; - route++; - } -+ mutex_unlock(&dapm->card->dapm_mutex); - - return ret; - } -@@ -2225,6 +2234,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) - struct snd_soc_dapm_widget *w; - unsigned int val; - -+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); -+ - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (w->new) -@@ -2234,8 +2245,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) - w->kcontrols = kzalloc(w->num_kcontrols * - sizeof(struct snd_kcontrol *), - GFP_KERNEL); -- if (!w->kcontrols) -+ if (!w->kcontrols) { -+ mutex_unlock(&dapm->card->dapm_mutex); - return -ENOMEM; -+ } - } - - switch(w->id) { -@@ -2275,6 +2288,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) - } - - dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); -+ mutex_unlock(&dapm->card->dapm_mutex); - return 0; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); -@@ -2334,6 +2348,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct snd_soc_codec *codec = widget->codec; -+ struct snd_soc_card *card = codec->card; - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; -@@ -2360,7 +2375,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, - /* old connection must be powered down */ - connect = invert ? 1 : 0; - -- mutex_lock(&codec->mutex); -+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); - - change = snd_soc_test_bits(widget->codec, reg, mask, val); - if (change) { -@@ -2382,7 +2397,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, - } - } - -- mutex_unlock(&codec->mutex); -+ mutex_unlock(&card->dapm_mutex); - return 0; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); -@@ -2431,6 +2446,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct snd_soc_codec *codec = widget->codec; -+ struct snd_soc_card *card = codec->card; - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val, mux, change; - unsigned int mask, bitmask; -@@ -2451,7 +2467,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, - mask |= (bitmask - 1) << e->shift_r; - } - -- mutex_lock(&codec->mutex); -+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); - - change = snd_soc_test_bits(widget->codec, e->reg, mask, val); - if (change) { -@@ -2473,7 +2489,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, - } - } - -- mutex_unlock(&codec->mutex); -+ mutex_unlock(&card->dapm_mutex); - return change; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); -@@ -2510,6 +2526,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct snd_soc_codec *codec = widget->codec; -+ struct snd_soc_card *card = codec->card; - struct soc_enum *e = - (struct soc_enum *)kcontrol->private_value; - int change; -@@ -2519,7 +2536,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, - if (ucontrol->value.enumerated.item[0] >= e->max) - return -EINVAL; - -- mutex_lock(&codec->mutex); -+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); - - change = widget->value != ucontrol->value.enumerated.item[0]; - if (change) { -@@ -2532,7 +2549,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, - } - } - -- mutex_unlock(&codec->mutex); -+ mutex_unlock(&card->dapm_mutex); - return ret; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); -@@ -2597,6 +2614,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, - struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); - struct snd_soc_dapm_widget *widget = wlist->widgets[0]; - struct snd_soc_codec *codec = widget->codec; -+ struct snd_soc_card *card = codec->card; - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val, mux, change; - unsigned int mask; -@@ -2615,7 +2633,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, - mask |= e->mask << e->shift_r; - } - -- mutex_lock(&codec->mutex); -+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); - - change = snd_soc_test_bits(widget->codec, e->reg, mask, val); - if (change) { -@@ -2637,7 +2655,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, - } - } - -- mutex_unlock(&codec->mutex); -+ mutex_unlock(&card->dapm_mutex); - return change; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); -@@ -2674,12 +2692,12 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - const char *pin = (const char *)kcontrol->private_value; - -- mutex_lock(&card->mutex); -+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); - - ucontrol->value.integer.value[0] = - snd_soc_dapm_get_pin_status(&card->dapm, pin); - -- mutex_unlock(&card->mutex); -+ mutex_unlock(&card->dapm_mutex); - - return 0; - } -@@ -2697,17 +2715,16 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, - struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); - const char *pin = (const char *)kcontrol->private_value; - -- mutex_lock(&card->mutex); -+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); - - if (ucontrol->value.integer.value[0]) - snd_soc_dapm_enable_pin(&card->dapm, pin); - else - snd_soc_dapm_disable_pin(&card->dapm, pin); - -- snd_soc_dapm_sync(&card->dapm); -- -- mutex_unlock(&card->mutex); -+ mutex_unlock(&card->dapm_mutex); - -+ snd_soc_dapm_sync(&card->dapm); - return 0; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); -@@ -2824,18 +2841,22 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, - { - struct snd_soc_dapm_widget *w; - int i; -+ int ret = 0; - -+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); - for (i = 0; i < num; i++) { - w = snd_soc_dapm_new_control(dapm, widget); - if (!w) { - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); -- return -ENOMEM; -+ ret = -ENOMEM; -+ break; - } - widget++; - } -- return 0; -+ mutex_unlock(&dapm->card->dapm_mutex); -+ return ret; - } - EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); - -@@ -2989,11 +3010,11 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, - int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, - struct snd_soc_dai *dai, int event) - { -- struct snd_soc_codec *codec = rtd->codec; -+ struct snd_soc_card *card = rtd->card; - -- mutex_lock(&codec->mutex); -- soc_dapm_stream_event(&codec->dapm, stream, dai, event); -- mutex_unlock(&codec->mutex); -+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM); -+ soc_dapm_stream_event(&card->dapm, stream, dai, event); -+ mutex_unlock(&card->dapm_mutex); - return 0; - } - diff --git a/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/003-overlayfs-v13-3.4-rc7.patch b/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/003-overlayfs-v13-3.4-rc7.patch deleted file mode 100644 index 9787cc64..00000000 --- a/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/003-overlayfs-v13-3.4-rc7.patch +++ /dev/null @@ -1,3363 +0,0 @@ -diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking -index 4fca82e..42b0539 100644 ---- a/Documentation/filesystems/Locking -+++ b/Documentation/filesystems/Locking -@@ -62,6 +62,7 @@ ata *); - int (*removexattr) (struct dentry *, const char *); - void (*truncate_range)(struct inode *, loff_t, loff_t); - int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); -+ struct file *(*open)(struct dentry *,struct file *,const struct cred *); - - locking rules: - all may block -@@ -89,6 +90,7 @@ listxattr: no - removexattr: yes - truncate_range: yes - fiemap: no -+open: no - Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on - victim. - cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. -diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt -new file mode 100644 -index 0000000..7161dc3 ---- /dev/null -+++ b/Documentation/filesystems/overlayfs.txt -@@ -0,0 +1,199 @@ -+Written by: Neil Brown <neilb@suse.de> -+ -+Overlay Filesystem -+================== -+ -+This document describes a prototype for a new approach to providing -+overlay-filesystem functionality in Linux (sometimes referred to as -+union-filesystems). An overlay-filesystem tries to present a -+filesystem which is the result over overlaying one filesystem on top -+of the other. -+ -+The result will inevitably fail to look exactly like a normal -+filesystem for various technical reasons. The expectation is that -+many use cases will be able to ignore these differences. -+ -+This approach is 'hybrid' because the objects that appear in the -+filesystem do not all appear to belong to that filesystem. In many -+cases an object accessed in the union will be indistinguishable -+from accessing the corresponding object from the original filesystem. -+This is most obvious from the 'st_dev' field returned by stat(2). -+ -+While directories will report an st_dev from the overlay-filesystem, -+all non-directory objects will report an st_dev from the lower or -+upper filesystem that is providing the object. Similarly st_ino will -+only be unique when combined with st_dev, and both of these can change -+over the lifetime of a non-directory object. Many applications and -+tools ignore these values and will not be affected. -+ -+Upper and Lower -+--------------- -+ -+An overlay filesystem combines two filesystems - an 'upper' filesystem -+and a 'lower' filesystem. When a name exists in both filesystems, the -+object in the 'upper' filesystem is visible while the object in the -+'lower' filesystem is either hidden or, in the case of directories, -+merged with the 'upper' object. -+ -+It would be more correct to refer to an upper and lower 'directory -+tree' rather than 'filesystem' as it is quite possible for both -+directory trees to be in the same filesystem and there is no -+requirement that the root of a filesystem be given for either upper or -+lower. -+ -+The lower filesystem can be any filesystem supported by Linux and does -+not need to be writable. The lower filesystem can even be another -+overlayfs. The upper filesystem will normally be writable and if it -+is it must support the creation of trusted.* extended attributes, and -+must provide valid d_type in readdir responses, at least for symbolic -+links - so NFS is not suitable. -+ -+A read-only overlay of two read-only filesystems may use any -+filesystem type. -+ -+Directories -+----------- -+ -+Overlaying mainly involved directories. If a given name appears in both -+upper and lower filesystems and refers to a non-directory in either, -+then the lower object is hidden - the name refers only to the upper -+object. -+ -+Where both upper and lower objects are directories, a merged directory -+is formed. -+ -+At mount time, the two directories given as mount options are combined -+into a merged directory: -+ -+ mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper /overlay -+ -+Then whenever a lookup is requested in such a merged directory, the -+lookup is performed in each actual directory and the combined result -+is cached in the dentry belonging to the overlay filesystem. If both -+actual lookups find directories, both are stored and a merged -+directory is created, otherwise only one is stored: the upper if it -+exists, else the lower. -+ -+Only the lists of names from directories are merged. Other content -+such as metadata and extended attributes are reported for the upper -+directory only. These attributes of the lower directory are hidden. -+ -+whiteouts and opaque directories -+-------------------------------- -+ -+In order to support rm and rmdir without changing the lower -+filesystem, an overlay filesystem needs to record in the upper filesystem -+that files have been removed. This is done using whiteouts and opaque -+directories (non-directories are always opaque). -+ -+The overlay filesystem uses extended attributes with a -+"trusted.overlay." prefix to record these details. -+ -+A whiteout is created as a symbolic link with target -+"(overlay-whiteout)" and with xattr "trusted.overlay.whiteout" set to "y". -+When a whiteout is found in the upper level of a merged directory, any -+matching name in the lower level is ignored, and the whiteout itself -+is also hidden. -+ -+A directory is made opaque by setting the xattr "trusted.overlay.opaque" -+to "y". Where the upper filesystem contains an opaque directory, any -+directory in the lower filesystem with the same name is ignored. -+ -+readdir -+------- -+ -+When a 'readdir' request is made on a merged directory, the upper and -+lower directories are each read and the name lists merged in the -+obvious way (upper is read first, then lower - entries that already -+exist are not re-added). This merged name list is cached in the -+'struct file' and so remains as long as the file is kept open. If the -+directory is opened and read by two processes at the same time, they -+will each have separate caches. A seekdir to the start of the -+directory (offset 0) followed by a readdir will cause the cache to be -+discarded and rebuilt. -+ -+This means that changes to the merged directory do not appear while a -+directory is being read. This is unlikely to be noticed by many -+programs. -+ -+seek offsets are assigned sequentially when the directories are read. -+Thus if -+ - read part of a directory -+ - remember an offset, and close the directory -+ - re-open the directory some time later -+ - seek to the remembered offset -+ -+there may be little correlation between the old and new locations in -+the list of filenames, particularly if anything has changed in the -+directory. -+ -+Readdir on directories that are not merged is simply handled by the -+underlying directory (upper or lower). -+ -+ -+Non-directories -+--------------- -+ -+Objects that are not directories (files, symlinks, device-special -+files etc.) are presented either from the upper or lower filesystem as -+appropriate. When a file in the lower filesystem is accessed in a way -+the requires write-access, such as opening for write access, changing -+some metadata etc., the file is first copied from the lower filesystem -+to the upper filesystem (copy_up). Note that creating a hard-link -+also requires copy_up, though of course creation of a symlink does -+not. -+ -+The copy_up may turn out to be unnecessary, for example if the file is -+opened for read-write but the data is not modified. -+ -+The copy_up process first makes sure that the containing directory -+exists in the upper filesystem - creating it and any parents as -+necessary. It then creates the object with the same metadata (owner, -+mode, mtime, symlink-target etc.) and then if the object is a file, the -+data is copied from the lower to the upper filesystem. Finally any -+extended attributes are copied up. -+ -+Once the copy_up is complete, the overlay filesystem simply -+provides direct access to the newly created file in the upper -+filesystem - future operations on the file are barely noticed by the -+overlay filesystem (though an operation on the name of the file such as -+rename or unlink will of course be noticed and handled). -+ -+ -+Non-standard behavior -+--------------------- -+ -+The copy_up operation essentially creates a new, identical file and -+moves it over to the old name. The new file may be on a different -+filesystem, so both st_dev and st_ino of the file may change. -+ -+Any open files referring to this inode will access the old data and -+metadata. Similarly any file locks obtained before copy_up will not -+apply to the copied up file. -+ -+On a file is opened with O_RDONLY fchmod(2), fchown(2), futimesat(2) -+and fsetxattr(2) will fail with EROFS. -+ -+If a file with multiple hard links is copied up, then this will -+"break" the link. Changes will not be propagated to other names -+referring to the same inode. -+ -+Symlinks in /proc/PID/ and /proc/PID/fd which point to a non-directory -+object in overlayfs will not contain vaid absolute paths, only -+relative paths leading up to the filesystem's root. This will be -+fixed in the future. -+ -+Some operations are not atomic, for example a crash during copy_up or -+rename will leave the filesystem in an inconsitent state. This will -+be addressed in the future. -+ -+Changes to underlying filesystems -+--------------------------------- -+ -+Offline changes, when the overlay is not mounted, are allowed to either -+the upper or the lower trees. -+ -+Changes to the underlying filesystems while part of a mounted overlay -+filesystem are not allowed. If the underlying filesystem is changed, -+the behavior of the overlay is undefined, though it will not result in -+a crash or deadlock. -diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt -index 0d04920..f06c91f 100644 ---- a/Documentation/filesystems/vfs.txt -+++ b/Documentation/filesystems/vfs.txt -@@ -364,6 +364,8 @@ struct inode_operations { - ssize_t (*listxattr) (struct dentry *, char *, size_t); - int (*removexattr) (struct dentry *, const char *); - void (*truncate_range)(struct inode *, loff_t, loff_t); -+ struct file *(*open) (struct dentry *, struct file *, -+ const struct cred *); - }; - - Again, all methods are called without any locks being held, unless -@@ -475,6 +477,12 @@ otherwise noted. - truncate_range: a method provided by the underlying filesystem to truncate a - range of blocks , i.e. punch a hole somewhere in a file. - -+ open: this is an alternative to f_op->open(), the difference is that this -+ method may return any open file, not necessarily originating from the -+ same filesystem as the one i_op->open() was called on. It may be useful -+ for stacking filesystems which want to allow native I/O directly on -+ underlying files. -+ - - The Address Space Object - ======================== -diff --git a/MAINTAINERS b/MAINTAINERS -index b362709..7ba226c 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -4998,6 +4998,13 @@ F: drivers/scsi/osd/ - F: include/scsi/osd_* - F: fs/exofs/ - -+OVERLAYFS FILESYSTEM -+M: Miklos Szeredi <miklos@szeredi.hu> -+L: linux-fsdevel@vger.kernel.org -+S: Supported -+F: fs/overlayfs/* -+F: Documentation/filesystems/overlayfs.txt -+ - P54 WIRELESS DRIVER - M: Christian Lamparter <chunkeey@googlemail.com> - L: linux-wireless@vger.kernel.org -diff --git a/fs/Kconfig b/fs/Kconfig -index f95ae3a..e0c5d43 100644 ---- a/fs/Kconfig -+++ b/fs/Kconfig -@@ -67,6 +67,7 @@ source "fs/quota/Kconfig" - - source "fs/autofs4/Kconfig" - source "fs/fuse/Kconfig" -+source "fs/overlayfs/Kconfig" - - config CUSE - tristate "Character device in Userspace support" -diff --git a/fs/Makefile b/fs/Makefile -index 2fb9779..fcd9788 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -106,6 +106,7 @@ obj-$(CONFIG_QNX6FS_FS) += qnx6/ - obj-$(CONFIG_AUTOFS4_FS) += autofs4/ - obj-$(CONFIG_ADFS_FS) += adfs/ - obj-$(CONFIG_FUSE_FS) += fuse/ -+obj-$(CONFIG_OVERLAYFS_FS) += overlayfs/ - obj-$(CONFIG_UDF_FS) += udf/ - obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ - obj-$(CONFIG_OMFS_FS) += omfs/ -diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c -index 6895493..c54ea90 100644 ---- a/fs/ecryptfs/main.c -+++ b/fs/ecryptfs/main.c -@@ -544,6 +544,13 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags - s->s_maxbytes = path.dentry->d_sb->s_maxbytes; - s->s_blocksize = path.dentry->d_sb->s_blocksize; - s->s_magic = ECRYPTFS_SUPER_MAGIC; -+ s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1; -+ -+ rc = -EINVAL; -+ if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { -+ printk(KERN_ERR "eCryptfs: maximum fs stacking depth exceeded\n"); -+ goto out_free; -+ } - - inode = ecryptfs_get_inode(path.dentry->d_inode, s); - rc = PTR_ERR(inode); -diff --git a/fs/namei.c b/fs/namei.c -index c427919..e172a5b 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -328,6 +328,36 @@ static inline int do_inode_permission(struct inode *inode, int mask) - } - - /** -+ * inode_only_permission - check access rights to a given inode only -+ * @inode: inode to check permissions on -+ * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...) -+ * -+ * Uses to check read/write/execute permissions on an inode directly, we do -+ * not check filesystem permissions. -+ */ -+int inode_only_permission(struct inode *inode, int mask) -+{ -+ int retval; -+ -+ /* -+ * Nobody gets write access to an immutable file. -+ */ -+ if (unlikely(mask & MAY_WRITE) && IS_IMMUTABLE(inode)) -+ return -EACCES; -+ -+ retval = do_inode_permission(inode, mask); -+ if (retval) -+ return retval; -+ -+ retval = devcgroup_inode_permission(inode, mask); -+ if (retval) -+ return retval; -+ -+ return security_inode_permission(inode, mask); -+} -+EXPORT_SYMBOL(inode_only_permission); -+ -+/** - * inode_permission - check for access rights to a given inode - * @inode: inode to check permission on - * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...) -@@ -341,8 +371,6 @@ static inline int do_inode_permission(struct inode *inode, int mask) - */ - int inode_permission(struct inode *inode, int mask) - { -- int retval; -- - if (unlikely(mask & MAY_WRITE)) { - umode_t mode = inode->i_mode; - -@@ -352,23 +380,9 @@ int inode_permission(struct inode *inode, int mask) - if (IS_RDONLY(inode) && - (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) - return -EROFS; -- -- /* -- * Nobody gets write access to an immutable file. -- */ -- if (IS_IMMUTABLE(inode)) -- return -EACCES; - } - -- retval = do_inode_permission(inode, mask); -- if (retval) -- return retval; -- -- retval = devcgroup_inode_permission(inode, mask); -- if (retval) -- return retval; -- -- return security_inode_permission(inode, mask); -+ return inode_only_permission(inode, mask); - } - - /** -diff --git a/fs/namespace.c b/fs/namespace.c -index e608199..2551ec0 100644 ---- a/fs/namespace.c -+++ b/fs/namespace.c -@@ -1325,6 +1325,24 @@ void drop_collected_mounts(struct vfsmount *mnt) - release_mounts(&umount_list); - } - -+struct vfsmount *clone_private_mount(struct path *path) -+{ -+ struct mount *old_mnt = real_mount(path->mnt); -+ struct mount *new_mnt; -+ -+ if (IS_MNT_UNBINDABLE(old_mnt)) -+ return ERR_PTR(-EINVAL); -+ -+ down_read(&namespace_sem); -+ new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); -+ up_read(&namespace_sem); -+ if (!new_mnt) -+ return ERR_PTR(-ENOMEM); -+ -+ return &new_mnt->mnt; -+} -+EXPORT_SYMBOL_GPL(clone_private_mount); -+ - int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, - struct vfsmount *root) - { -diff --git a/fs/open.c b/fs/open.c -index 5720854..3e132ba 100644 ---- a/fs/open.c -+++ b/fs/open.c -@@ -644,24 +644,24 @@ static inline int __get_file_write_access(struct inode *inode, - return error; - } - --static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, -- struct file *f, -- int (*open)(struct inode *, struct file *), -- const struct cred *cred) -+static struct file *__dentry_open(struct path *path, struct file *f, -+ int (*open)(struct inode *, struct file *), -+ const struct cred *cred) - { - static const struct file_operations empty_fops = {}; - struct inode *inode; - int error; - -+ path_get(path); - f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | - FMODE_PREAD | FMODE_PWRITE; - - if (unlikely(f->f_flags & O_PATH)) - f->f_mode = FMODE_PATH; - -- inode = dentry->d_inode; -+ inode = path->dentry->d_inode; - if (f->f_mode & FMODE_WRITE) { -- error = __get_file_write_access(inode, mnt); -+ error = __get_file_write_access(inode, path->mnt); - if (error) - goto cleanup_file; - if (!special_file(inode->i_mode)) -@@ -669,8 +669,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, - } - - f->f_mapping = inode->i_mapping; -- f->f_path.dentry = dentry; -- f->f_path.mnt = mnt; -+ f->f_path = *path; - f->f_pos = 0; - file_sb_list_add(f, inode->i_sb); - -@@ -727,7 +726,7 @@ cleanup_all: - * here, so just reset the state. - */ - file_reset_write(f); -- mnt_drop_write(mnt); -+ mnt_drop_write(path->mnt); - } - } - file_sb_list_del(f); -@@ -735,8 +734,7 @@ cleanup_all: - f->f_path.mnt = NULL; - cleanup_file: - put_filp(f); -- dput(dentry); -- mntput(mnt); -+ path_put(path); - return ERR_PTR(error); - } - -@@ -762,14 +760,14 @@ cleanup_file: - struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, - int (*open)(struct inode *, struct file *)) - { -+ struct path path = { .dentry = dentry, .mnt = nd->path.mnt }; - const struct cred *cred = current_cred(); - - if (IS_ERR(nd->intent.open.file)) - goto out; - if (IS_ERR(dentry)) - goto out_err; -- nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), -- nd->intent.open.file, -+ nd->intent.open.file = __dentry_open(&path, nd->intent.open.file, - open, cred); - out: - return nd->intent.open.file; -@@ -797,11 +795,9 @@ struct file *nameidata_to_filp(struct nameidata *nd) - nd->intent.open.file = NULL; - - /* Has the filesystem initialised the file for us? */ -- if (filp->f_path.dentry == NULL) { -- path_get(&nd->path); -- filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, -- NULL, cred); -- } -+ if (filp->f_path.dentry == NULL) -+ filp = vfs_open(&nd->path, filp, cred); -+ - return filp; - } - -@@ -812,27 +808,48 @@ struct file *nameidata_to_filp(struct nameidata *nd) - struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, - const struct cred *cred) - { -- int error; - struct file *f; -+ struct file *ret; -+ struct path path = { .dentry = dentry, .mnt = mnt }; - - validate_creds(cred); - - /* We must always pass in a valid mount pointer. */ - BUG_ON(!mnt); - -- error = -ENFILE; -+ ret = ERR_PTR(-ENFILE); - f = get_empty_filp(); -- if (f == NULL) { -- dput(dentry); -- mntput(mnt); -- return ERR_PTR(error); -+ if (f != NULL) { -+ f->f_flags = flags; -+ ret = vfs_open(&path, f, cred); - } -+ path_put(&path); - -- f->f_flags = flags; -- return __dentry_open(dentry, mnt, f, NULL, cred); -+ return ret; - } - EXPORT_SYMBOL(dentry_open); - -+/** -+ * vfs_open - open the file at the given path -+ * @path: path to open -+ * @filp: newly allocated file with f_flag initialized -+ * @cred: credentials to use -+ * -+ * Open the file. If successful, the returned file will have acquired -+ * an additional reference for path. -+ */ -+struct file *vfs_open(struct path *path, struct file *filp, -+ const struct cred *cred) -+{ -+ struct inode *inode = path->dentry->d_inode; -+ -+ if (inode->i_op->open) -+ return inode->i_op->open(path->dentry, filp, cred); -+ else -+ return __dentry_open(path, filp, NULL, cred); -+} -+EXPORT_SYMBOL(vfs_open); -+ - static void __put_unused_fd(struct files_struct *files, unsigned int fd) - { - struct fdtable *fdt = files_fdtable(files); -diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig -new file mode 100644 -index 0000000..c4517da ---- /dev/null -+++ b/fs/overlayfs/Kconfig -@@ -0,0 +1,4 @@ -+config OVERLAYFS_FS -+ tristate "Overlay filesystem support" -+ help -+ Add support for overlay filesystem. -diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile -new file mode 100644 -index 0000000..8f91889 ---- /dev/null -+++ b/fs/overlayfs/Makefile -@@ -0,0 +1,7 @@ -+# -+# Makefile for the overlay filesystem. -+# -+ -+obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o -+ -+overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o -diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c -new file mode 100644 -index 0000000..87dbeee ---- /dev/null -+++ b/fs/overlayfs/copy_up.c -@@ -0,0 +1,385 @@ -+/* -+ * -+ * Copyright (C) 2011 Novell 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/fs.h> -+#include <linux/slab.h> -+#include <linux/file.h> -+#include <linux/splice.h> -+#include <linux/xattr.h> -+#include <linux/security.h> -+#include <linux/uaccess.h> -+#include <linux/sched.h> -+#include "overlayfs.h" -+ -+#define OVL_COPY_UP_CHUNK_SIZE (1 << 20) -+ -+static int ovl_copy_up_xattr(struct dentry *old, struct dentry *new) -+{ -+ ssize_t list_size, size; -+ char *buf, *name, *value; -+ int error; -+ -+ if (!old->d_inode->i_op->getxattr || -+ !new->d_inode->i_op->getxattr) -+ return 0; -+ -+ list_size = vfs_listxattr(old, NULL, 0); -+ if (list_size <= 0) { -+ if (list_size == -EOPNOTSUPP) -+ return 0; -+ return list_size; -+ } -+ -+ buf = kzalloc(list_size, GFP_KERNEL); -+ if (!buf) -+ return -ENOMEM; -+ -+ error = -ENOMEM; -+ value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL); -+ if (!value) -+ goto out; -+ -+ list_size = vfs_listxattr(old, buf, list_size); -+ if (list_size <= 0) { -+ error = list_size; -+ goto out_free_value; -+ } -+ -+ for (name = buf; name < (buf + list_size); name += strlen(name) + 1) { -+ size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX); -+ if (size <= 0) { -+ error = size; -+ goto out_free_value; -+ } -+ error = vfs_setxattr(new, name, value, size, 0); -+ if (error) -+ goto out_free_value; -+ } -+ -+out_free_value: -+ kfree(value); -+out: -+ kfree(buf); -+ return error; -+} -+ -+static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len) -+{ -+ struct file *old_file; -+ struct file *new_file; -+ int error = 0; -+ -+ if (len == 0) -+ return 0; -+ -+ old_file = ovl_path_open(old, O_RDONLY); -+ if (IS_ERR(old_file)) -+ return PTR_ERR(old_file); -+ -+ new_file = ovl_path_open(new, O_WRONLY); -+ if (IS_ERR(new_file)) { -+ error = PTR_ERR(new_file); -+ goto out_fput; -+ } -+ -+ /* FIXME: copy up sparse files efficiently */ -+ while (len) { -+ loff_t offset = new_file->f_pos; -+ size_t this_len = OVL_COPY_UP_CHUNK_SIZE; -+ long bytes; -+ -+ if (len < this_len) -+ this_len = len; -+ -+ if (signal_pending_state(TASK_KILLABLE, current)) { -+ error = -EINTR; -+ break; -+ } -+ -+ bytes = do_splice_direct(old_file, &offset, new_file, this_len, -+ SPLICE_F_MOVE); -+ if (bytes <= 0) { -+ error = bytes; -+ break; -+ } -+ -+ len -= bytes; -+ } -+ -+ fput(new_file); -+out_fput: -+ fput(old_file); -+ return error; -+} -+ -+static char *ovl_read_symlink(struct dentry *realdentry) -+{ -+ int res; -+ char *buf; -+ struct inode *inode = realdentry->d_inode; -+ mm_segment_t old_fs; -+ -+ res = -EINVAL; -+ if (!inode->i_op->readlink) -+ goto err; -+ -+ res = -ENOMEM; -+ buf = (char *) __get_free_page(GFP_KERNEL); -+ if (!buf) -+ goto err; -+ -+ old_fs = get_fs(); -+ set_fs(get_ds()); -+ /* The cast to a user pointer is valid due to the set_fs() */ -+ res = inode->i_op->readlink(realdentry, -+ (char __user *)buf, PAGE_SIZE - 1); -+ set_fs(old_fs); -+ if (res < 0) { -+ free_page((unsigned long) buf); -+ goto err; -+ } -+ buf[res] = '\0'; -+ -+ return buf; -+ -+err: -+ return ERR_PTR(res); -+} -+ -+static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) -+{ -+ struct iattr attr = { -+ .ia_valid = -+ ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SET | ATTR_MTIME_SET, -+ .ia_atime = stat->atime, -+ .ia_mtime = stat->mtime, -+ }; -+ -+ return notify_change(upperdentry, &attr); -+} -+ -+static int ovl_set_mode(struct dentry *upperdentry, umode_t mode) -+{ -+ struct iattr attr = { -+ .ia_valid = ATTR_MODE, -+ .ia_mode = mode, -+ }; -+ -+ return notify_change(upperdentry, &attr); -+} -+ -+static int ovl_copy_up_locked(struct dentry *upperdir, struct dentry *dentry, -+ struct path *lowerpath, struct kstat *stat, -+ const char *link) -+{ -+ int err; -+ struct path newpath; -+ umode_t mode = stat->mode; -+ -+ /* Can't properly set mode on creation because of the umask */ -+ stat->mode &= S_IFMT; -+ -+ ovl_path_upper(dentry, &newpath); -+ WARN_ON(newpath.dentry); -+ newpath.dentry = ovl_upper_create(upperdir, dentry, stat, link); -+ if (IS_ERR(newpath.dentry)) -+ return PTR_ERR(newpath.dentry); -+ -+ if (S_ISREG(stat->mode)) { -+ err = ovl_copy_up_data(lowerpath, &newpath, stat->size); -+ if (err) -+ goto err_remove; -+ } -+ -+ err = ovl_copy_up_xattr(lowerpath->dentry, newpath.dentry); -+ if (err) -+ goto err_remove; -+ -+ mutex_lock(&newpath.dentry->d_inode->i_mutex); -+ if (!S_ISLNK(stat->mode)) -+ err = ovl_set_mode(newpath.dentry, mode); -+ if (!err) -+ err = ovl_set_timestamps(newpath.dentry, stat); -+ mutex_unlock(&newpath.dentry->d_inode->i_mutex); -+ if (err) -+ goto err_remove; -+ -+ ovl_dentry_update(dentry, newpath.dentry); -+ -+ /* -+ * Easiest way to get rid of the lower dentry reference is to -+ * drop this dentry. This is neither needed nor possible for -+ * directories. -+ */ -+ if (!S_ISDIR(stat->mode)) -+ d_drop(dentry); -+ -+ return 0; -+ -+err_remove: -+ if (S_ISDIR(stat->mode)) -+ vfs_rmdir(upperdir->d_inode, newpath.dentry); -+ else -+ vfs_unlink(upperdir->d_inode, newpath.dentry); -+ -+ dput(newpath.dentry); -+ -+ return err; -+} -+ -+/* -+ * Copy up a single dentry -+ * -+ * Directory renames only allowed on "pure upper" (already created on -+ * upper filesystem, never copied up). Directories which are on lower or -+ * are merged may not be renamed. For these -EXDEV is returned and -+ * userspace has to deal with it. This means, when copying up a -+ * directory we can rely on it and ancestors being stable. -+ * -+ * Non-directory renames start with copy up of source if necessary. The -+ * actual rename will only proceed once the copy up was successful. Copy -+ * up uses upper parent i_mutex for exclusion. Since rename can change -+ * d_parent it is possible that the copy up will lock the old parent. At -+ * that point the file will have already been copied up anyway. -+ */ -+static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, -+ struct path *lowerpath, struct kstat *stat) -+{ -+ int err; -+ struct kstat pstat; -+ struct path parentpath; -+ struct dentry *upperdir; -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ char *link = NULL; -+ -+ ovl_path_upper(parent, &parentpath); -+ upperdir = parentpath.dentry; -+ -+ err = vfs_getattr(parentpath.mnt, parentpath.dentry, &pstat); -+ if (err) -+ return err; -+ -+ if (S_ISLNK(stat->mode)) { -+ link = ovl_read_symlink(lowerpath->dentry); -+ if (IS_ERR(link)) -+ return PTR_ERR(link); -+ } -+ -+ err = -ENOMEM; -+ override_cred = prepare_creds(); -+ if (!override_cred) -+ goto out_free_link; -+ -+ override_cred->fsuid = stat->uid; -+ override_cred->fsgid = stat->gid; -+ /* -+ * CAP_SYS_ADMIN for copying up extended attributes -+ * CAP_DAC_OVERRIDE for create -+ * CAP_FOWNER for chmod, timestamp update -+ * CAP_FSETID for chmod -+ * CAP_MKNOD for mknod -+ */ -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); -+ cap_raise(override_cred->cap_effective, CAP_FOWNER); -+ cap_raise(override_cred->cap_effective, CAP_FSETID); -+ cap_raise(override_cred->cap_effective, CAP_MKNOD); -+ old_cred = override_creds(override_cred); -+ -+ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); -+ if (ovl_path_type(dentry) != OVL_PATH_LOWER) { -+ err = 0; -+ } else { -+ err = ovl_copy_up_locked(upperdir, dentry, lowerpath, -+ stat, link); -+ if (!err) { -+ /* Restore timestamps on parent (best effort) */ -+ ovl_set_timestamps(upperdir, &pstat); -+ } -+ } -+ -+ mutex_unlock(&upperdir->d_inode->i_mutex); -+ -+ revert_creds(old_cred); -+ put_cred(override_cred); -+ -+out_free_link: -+ if (link) -+ free_page((unsigned long) link); -+ -+ return err; -+} -+ -+int ovl_copy_up(struct dentry *dentry) -+{ -+ int err; -+ -+ err = 0; -+ while (!err) { -+ struct dentry *next; -+ struct dentry *parent; -+ struct path lowerpath; -+ struct kstat stat; -+ enum ovl_path_type type = ovl_path_type(dentry); -+ -+ if (type != OVL_PATH_LOWER) -+ break; -+ -+ next = dget(dentry); -+ /* find the topmost dentry not yet copied up */ -+ for (;;) { -+ parent = dget_parent(next); -+ -+ type = ovl_path_type(parent); -+ if (type != OVL_PATH_LOWER) -+ break; -+ -+ dput(next); -+ next = parent; -+ } -+ -+ ovl_path_lower(next, &lowerpath); -+ err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat); -+ if (!err) -+ err = ovl_copy_up_one(parent, next, &lowerpath, &stat); -+ -+ dput(parent); -+ dput(next); -+ } -+ -+ return err; -+} -+ -+/* Optimize by not copying up the file first and truncating later */ -+int ovl_copy_up_truncate(struct dentry *dentry, loff_t size) -+{ -+ int err; -+ struct kstat stat; -+ struct path lowerpath; -+ struct dentry *parent = dget_parent(dentry); -+ -+ err = ovl_copy_up(parent); -+ if (err) -+ goto out_dput_parent; -+ -+ ovl_path_lower(dentry, &lowerpath); -+ err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat); -+ if (err) -+ goto out_dput_parent; -+ -+ if (size < stat.size) -+ stat.size = size; -+ -+ err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat); -+ -+out_dput_parent: -+ dput(parent); -+ return err; -+} -diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c -new file mode 100644 -index 0000000..c914c97 ---- /dev/null -+++ b/fs/overlayfs/dir.c -@@ -0,0 +1,602 @@ -+/* -+ * -+ * Copyright (C) 2011 Novell 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/fs.h> -+#include <linux/namei.h> -+#include <linux/xattr.h> -+#include <linux/security.h> -+#include <linux/cred.h> -+#include "overlayfs.h" -+ -+static const char *ovl_whiteout_symlink = "(overlay-whiteout)"; -+ -+static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) -+{ -+ int err; -+ struct dentry *newdentry; -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ -+ /* FIXME: recheck lower dentry to see if whiteout is really needed */ -+ -+ err = -ENOMEM; -+ override_cred = prepare_creds(); -+ if (!override_cred) -+ goto out; -+ -+ /* -+ * CAP_SYS_ADMIN for setxattr -+ * CAP_DAC_OVERRIDE for symlink creation -+ * CAP_FOWNER for unlink in sticky directory -+ */ -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); -+ cap_raise(override_cred->cap_effective, CAP_FOWNER); -+ override_cred->fsuid = 0; -+ override_cred->fsgid = 0; -+ old_cred = override_creds(override_cred); -+ -+ newdentry = lookup_one_len(dentry->d_name.name, upperdir, -+ dentry->d_name.len); -+ err = PTR_ERR(newdentry); -+ if (IS_ERR(newdentry)) -+ goto out_put_cred; -+ -+ /* Just been removed within the same locked region */ -+ WARN_ON(newdentry->d_inode); -+ -+ err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink); -+ if (err) -+ goto out_dput; -+ -+ ovl_dentry_version_inc(dentry->d_parent); -+ -+ err = vfs_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0); -+ if (err) -+ vfs_unlink(upperdir->d_inode, newdentry); -+ -+out_dput: -+ dput(newdentry); -+out_put_cred: -+ revert_creds(old_cred); -+ put_cred(override_cred); -+out: -+ if (err) { -+ /* -+ * There's no way to recover from failure to whiteout. -+ * What should we do? Log a big fat error and... ? -+ */ -+ printk(KERN_ERR "overlayfs: ERROR - failed to whiteout '%s'\n", -+ dentry->d_name.name); -+ } -+ -+ return err; -+} -+ -+static struct dentry *ovl_lookup_create(struct dentry *upperdir, -+ struct dentry *template) -+{ -+ int err; -+ struct dentry *newdentry; -+ struct qstr *name = &template->d_name; -+ -+ newdentry = lookup_one_len(name->name, upperdir, name->len); -+ if (IS_ERR(newdentry)) -+ return newdentry; -+ -+ if (newdentry->d_inode) { -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ -+ /* No need to check whiteout if lower parent is non-existent */ -+ err = -EEXIST; -+ if (!ovl_dentry_lower(template->d_parent)) -+ goto out_dput; -+ -+ if (!S_ISLNK(newdentry->d_inode->i_mode)) -+ goto out_dput; -+ -+ err = -ENOMEM; -+ override_cred = prepare_creds(); -+ if (!override_cred) -+ goto out_dput; -+ -+ /* -+ * CAP_SYS_ADMIN for getxattr -+ * CAP_FOWNER for unlink in sticky directory -+ */ -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ cap_raise(override_cred->cap_effective, CAP_FOWNER); -+ old_cred = override_creds(override_cred); -+ -+ err = -EEXIST; -+ if (ovl_is_whiteout(newdentry)) -+ err = vfs_unlink(upperdir->d_inode, newdentry); -+ -+ revert_creds(old_cred); -+ put_cred(override_cred); -+ if (err) -+ goto out_dput; -+ -+ dput(newdentry); -+ newdentry = lookup_one_len(name->name, upperdir, name->len); -+ if (IS_ERR(newdentry)) { -+ ovl_whiteout(upperdir, template); -+ return newdentry; -+ } -+ -+ /* -+ * Whiteout just been successfully removed, parent -+ * i_mutex is still held, there's no way the lookup -+ * could return positive. -+ */ -+ WARN_ON(newdentry->d_inode); -+ } -+ -+ return newdentry; -+ -+out_dput: -+ dput(newdentry); -+ return ERR_PTR(err); -+} -+ -+struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry, -+ struct kstat *stat, const char *link) -+{ -+ int err; -+ struct dentry *newdentry; -+ struct inode *dir = upperdir->d_inode; -+ -+ newdentry = ovl_lookup_create(upperdir, dentry); -+ if (IS_ERR(newdentry)) -+ goto out; -+ -+ switch (stat->mode & S_IFMT) { -+ case S_IFREG: -+ err = vfs_create(dir, newdentry, stat->mode, NULL); -+ break; -+ -+ case S_IFDIR: -+ err = vfs_mkdir(dir, newdentry, stat->mode); -+ break; -+ -+ case S_IFCHR: -+ case S_IFBLK: -+ case S_IFIFO: -+ case S_IFSOCK: -+ err = vfs_mknod(dir, newdentry, stat->mode, stat->rdev); -+ break; -+ -+ case S_IFLNK: -+ err = vfs_symlink(dir, newdentry, link); -+ break; -+ -+ default: -+ err = -EPERM; -+ } -+ if (err) { -+ if (ovl_dentry_is_opaque(dentry)) -+ ovl_whiteout(upperdir, dentry); -+ dput(newdentry); -+ newdentry = ERR_PTR(err); -+ } else if (WARN_ON(!newdentry->d_inode)) { -+ /* -+ * Not quite sure if non-instantiated dentry is legal or not. -+ * VFS doesn't seem to care so check and warn here. -+ */ -+ dput(newdentry); -+ newdentry = ERR_PTR(-ENOENT); -+ } -+ -+out: -+ return newdentry; -+ -+} -+ -+static int ovl_set_opaque(struct dentry *upperdentry) -+{ -+ int err; -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ -+ override_cred = prepare_creds(); -+ if (!override_cred) -+ return -ENOMEM; -+ -+ /* CAP_SYS_ADMIN for setxattr of "trusted" namespace */ -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ old_cred = override_creds(override_cred); -+ err = vfs_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0); -+ revert_creds(old_cred); -+ put_cred(override_cred); -+ -+ return err; -+} -+ -+static int ovl_remove_opaque(struct dentry *upperdentry) -+{ -+ int err; -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ -+ override_cred = prepare_creds(); -+ if (!override_cred) -+ return -ENOMEM; -+ -+ /* CAP_SYS_ADMIN for removexattr of "trusted" namespace */ -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ old_cred = override_creds(override_cred); -+ err = vfs_removexattr(upperdentry, ovl_opaque_xattr); -+ revert_creds(old_cred); -+ put_cred(override_cred); -+ -+ return err; -+} -+ -+static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, -+ struct kstat *stat) -+{ -+ int err; -+ enum ovl_path_type type; -+ struct path realpath; -+ -+ type = ovl_path_real(dentry, &realpath); -+ err = vfs_getattr(realpath.mnt, realpath.dentry, stat); -+ if (err) -+ return err; -+ -+ stat->dev = dentry->d_sb->s_dev; -+ stat->ino = dentry->d_inode->i_ino; -+ -+ /* -+ * It's probably not worth it to count subdirs to get the -+ * correct link count. nlink=1 seems to pacify 'find' and -+ * other utilities. -+ */ -+ if (type == OVL_PATH_MERGE) -+ stat->nlink = 1; -+ -+ return 0; -+} -+ -+static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev, -+ const char *link) -+{ -+ int err; -+ struct dentry *newdentry; -+ struct dentry *upperdir; -+ struct inode *inode; -+ struct kstat stat = { -+ .mode = mode, -+ .rdev = rdev, -+ }; -+ -+ err = -ENOMEM; -+ inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata); -+ if (!inode) -+ goto out; -+ -+ err = ovl_copy_up(dentry->d_parent); -+ if (err) -+ goto out_iput; -+ -+ upperdir = ovl_dentry_upper(dentry->d_parent); -+ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); -+ -+ newdentry = ovl_upper_create(upperdir, dentry, &stat, link); -+ err = PTR_ERR(newdentry); -+ if (IS_ERR(newdentry)) -+ goto out_unlock; -+ -+ ovl_dentry_version_inc(dentry->d_parent); -+ if (ovl_dentry_is_opaque(dentry) && S_ISDIR(mode)) { -+ err = ovl_set_opaque(newdentry); -+ if (err) { -+ vfs_rmdir(upperdir->d_inode, newdentry); -+ ovl_whiteout(upperdir, dentry); -+ goto out_dput; -+ } -+ } -+ ovl_dentry_update(dentry, newdentry); -+ d_instantiate(dentry, inode); -+ inode = NULL; -+ newdentry = NULL; -+ err = 0; -+ -+out_dput: -+ dput(newdentry); -+out_unlock: -+ mutex_unlock(&upperdir->d_inode->i_mutex); -+out_iput: -+ iput(inode); -+out: -+ return err; -+} -+ -+static int ovl_create(struct inode *dir, struct dentry *dentry, umode_t mode, -+ struct nameidata *nd) -+{ -+ return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL); -+} -+ -+static int ovl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -+{ -+ return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL); -+} -+ -+static int ovl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, -+ dev_t rdev) -+{ -+ return ovl_create_object(dentry, mode, rdev, NULL); -+} -+ -+static int ovl_symlink(struct inode *dir, struct dentry *dentry, -+ const char *link) -+{ -+ return ovl_create_object(dentry, S_IFLNK, 0, link); -+} -+ -+static int ovl_do_remove(struct dentry *dentry, bool is_dir) -+{ -+ int err; -+ enum ovl_path_type type; -+ struct path realpath; -+ struct dentry *upperdir; -+ -+ err = ovl_copy_up(dentry->d_parent); -+ if (err) -+ return err; -+ -+ upperdir = ovl_dentry_upper(dentry->d_parent); -+ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); -+ type = ovl_path_real(dentry, &realpath); -+ if (type != OVL_PATH_LOWER) { -+ err = -ESTALE; -+ if (realpath.dentry->d_parent != upperdir) -+ goto out_d_drop; -+ -+ /* FIXME: create whiteout up front and rename to target */ -+ -+ if (is_dir) -+ err = vfs_rmdir(upperdir->d_inode, realpath.dentry); -+ else -+ err = vfs_unlink(upperdir->d_inode, realpath.dentry); -+ if (err) -+ goto out_d_drop; -+ -+ ovl_dentry_version_inc(dentry->d_parent); -+ } -+ -+ if (type != OVL_PATH_UPPER || ovl_dentry_is_opaque(dentry)) -+ err = ovl_whiteout(upperdir, dentry); -+ -+ /* -+ * Keeping this dentry hashed would mean having to release -+ * upperpath/lowerpath, which could only be done if we are the -+ * sole user of this dentry. Too tricky... Just unhash for -+ * now. -+ */ -+out_d_drop: -+ d_drop(dentry); -+ mutex_unlock(&upperdir->d_inode->i_mutex); -+ -+ return err; -+} -+ -+static int ovl_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ return ovl_do_remove(dentry, false); -+} -+ -+ -+static int ovl_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ int err; -+ enum ovl_path_type type; -+ -+ type = ovl_path_type(dentry); -+ if (type != OVL_PATH_UPPER) { -+ err = ovl_check_empty_and_clear(dentry, type); -+ if (err) -+ return err; -+ } -+ -+ return ovl_do_remove(dentry, true); -+} -+ -+static int ovl_link(struct dentry *old, struct inode *newdir, -+ struct dentry *new) -+{ -+ int err; -+ struct dentry *olddentry; -+ struct dentry *newdentry; -+ struct dentry *upperdir; -+ struct inode *newinode; -+ -+ err = ovl_copy_up(old); -+ if (err) -+ goto out; -+ -+ err = ovl_copy_up(new->d_parent); -+ if (err) -+ goto out; -+ -+ upperdir = ovl_dentry_upper(new->d_parent); -+ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); -+ newdentry = ovl_lookup_create(upperdir, new); -+ err = PTR_ERR(newdentry); -+ if (IS_ERR(newdentry)) -+ goto out_unlock; -+ -+ olddentry = ovl_dentry_upper(old); -+ err = vfs_link(olddentry, upperdir->d_inode, newdentry); -+ if (!err) { -+ if (WARN_ON(!newdentry->d_inode)) { -+ dput(newdentry); -+ err = -ENOENT; -+ goto out_unlock; -+ } -+ newinode = ovl_new_inode(old->d_sb, newdentry->d_inode->i_mode, -+ new->d_fsdata); -+ if (!newinode) -+ goto link_fail; -+ -+ ovl_dentry_version_inc(new->d_parent); -+ ovl_dentry_update(new, newdentry); -+ -+ d_instantiate(new, newinode); -+ } else { -+link_fail: -+ if (ovl_dentry_is_opaque(new)) -+ ovl_whiteout(upperdir, new); -+ dput(newdentry); -+ } -+out_unlock: -+ mutex_unlock(&upperdir->d_inode->i_mutex); -+out: -+ return err; -+ -+} -+ -+static int ovl_rename(struct inode *olddir, struct dentry *old, -+ struct inode *newdir, struct dentry *new) -+{ -+ int err; -+ enum ovl_path_type old_type; -+ enum ovl_path_type new_type; -+ struct dentry *old_upperdir; -+ struct dentry *new_upperdir; -+ struct dentry *olddentry; -+ struct dentry *newdentry; -+ struct dentry *trap; -+ bool old_opaque; -+ bool new_opaque; -+ bool new_create = false; -+ bool is_dir = S_ISDIR(old->d_inode->i_mode); -+ -+ /* Don't copy up directory trees */ -+ old_type = ovl_path_type(old); -+ if (old_type != OVL_PATH_UPPER && is_dir) -+ return -EXDEV; -+ -+ if (new->d_inode) { -+ new_type = ovl_path_type(new); -+ -+ if (new_type == OVL_PATH_LOWER && old_type == OVL_PATH_LOWER) { -+ if (ovl_dentry_lower(old)->d_inode == -+ ovl_dentry_lower(new)->d_inode) -+ return 0; -+ } -+ if (new_type != OVL_PATH_LOWER && old_type != OVL_PATH_LOWER) { -+ if (ovl_dentry_upper(old)->d_inode == -+ ovl_dentry_upper(new)->d_inode) -+ return 0; -+ } -+ -+ if (new_type != OVL_PATH_UPPER && -+ S_ISDIR(new->d_inode->i_mode)) { -+ err = ovl_check_empty_and_clear(new, new_type); -+ if (err) -+ return err; -+ } -+ } else { -+ new_type = OVL_PATH_UPPER; -+ } -+ -+ err = ovl_copy_up(old); -+ if (err) -+ return err; -+ -+ err = ovl_copy_up(new->d_parent); -+ if (err) -+ return err; -+ -+ old_upperdir = ovl_dentry_upper(old->d_parent); -+ new_upperdir = ovl_dentry_upper(new->d_parent); -+ -+ trap = lock_rename(new_upperdir, old_upperdir); -+ -+ olddentry = ovl_dentry_upper(old); -+ newdentry = ovl_dentry_upper(new); -+ if (newdentry) { -+ dget(newdentry); -+ } else { -+ new_create = true; -+ newdentry = ovl_lookup_create(new_upperdir, new); -+ err = PTR_ERR(newdentry); -+ if (IS_ERR(newdentry)) -+ goto out_unlock; -+ } -+ -+ err = -ESTALE; -+ if (olddentry->d_parent != old_upperdir) -+ goto out_dput; -+ if (newdentry->d_parent != new_upperdir) -+ goto out_dput; -+ if (olddentry == trap) -+ goto out_dput; -+ if (newdentry == trap) -+ goto out_dput; -+ -+ old_opaque = ovl_dentry_is_opaque(old); -+ new_opaque = ovl_dentry_is_opaque(new) || new_type != OVL_PATH_UPPER; -+ -+ if (is_dir && !old_opaque && new_opaque) { -+ err = ovl_set_opaque(olddentry); -+ if (err) -+ goto out_dput; -+ } -+ -+ err = vfs_rename(old_upperdir->d_inode, olddentry, -+ new_upperdir->d_inode, newdentry); -+ -+ if (err) { -+ if (new_create && ovl_dentry_is_opaque(new)) -+ ovl_whiteout(new_upperdir, new); -+ if (is_dir && !old_opaque && new_opaque) -+ ovl_remove_opaque(olddentry); -+ goto out_dput; -+ } -+ -+ if (old_type != OVL_PATH_UPPER || old_opaque) -+ err = ovl_whiteout(old_upperdir, old); -+ if (is_dir && old_opaque && !new_opaque) -+ ovl_remove_opaque(olddentry); -+ -+ if (old_opaque != new_opaque) -+ ovl_dentry_set_opaque(old, new_opaque); -+ -+ ovl_dentry_version_inc(old->d_parent); -+ ovl_dentry_version_inc(new->d_parent); -+ -+out_dput: -+ dput(newdentry); -+out_unlock: -+ unlock_rename(new_upperdir, old_upperdir); -+ return err; -+} -+ -+const struct inode_operations ovl_dir_inode_operations = { -+ .lookup = ovl_lookup, -+ .mkdir = ovl_mkdir, -+ .symlink = ovl_symlink, -+ .unlink = ovl_unlink, -+ .rmdir = ovl_rmdir, -+ .rename = ovl_rename, -+ .link = ovl_link, -+ .setattr = ovl_setattr, -+ .create = ovl_create, -+ .mknod = ovl_mknod, -+ .permission = ovl_permission, -+ .getattr = ovl_dir_getattr, -+ .setxattr = ovl_setxattr, -+ .getxattr = ovl_getxattr, -+ .listxattr = ovl_listxattr, -+ .removexattr = ovl_removexattr, -+}; -diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c -new file mode 100644 -index 0000000..1a8e232 ---- /dev/null -+++ b/fs/overlayfs/inode.c -@@ -0,0 +1,375 @@ -+/* -+ * -+ * Copyright (C) 2011 Novell 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/fs.h> -+#include <linux/slab.h> -+#include <linux/xattr.h> -+#include "overlayfs.h" -+ -+int ovl_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ struct dentry *upperdentry; -+ int err; -+ -+ if ((attr->ia_valid & ATTR_SIZE) && !ovl_dentry_upper(dentry)) -+ err = ovl_copy_up_truncate(dentry, attr->ia_size); -+ else -+ err = ovl_copy_up(dentry); -+ if (err) -+ return err; -+ -+ upperdentry = ovl_dentry_upper(dentry); -+ -+ if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) -+ attr->ia_valid &= ~ATTR_MODE; -+ -+ mutex_lock(&upperdentry->d_inode->i_mutex); -+ err = notify_change(upperdentry, attr); -+ mutex_unlock(&upperdentry->d_inode->i_mutex); -+ -+ return err; -+} -+ -+static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry, -+ struct kstat *stat) -+{ -+ struct path realpath; -+ -+ ovl_path_real(dentry, &realpath); -+ return vfs_getattr(realpath.mnt, realpath.dentry, stat); -+} -+ -+int ovl_permission(struct inode *inode, int mask) -+{ -+ struct ovl_entry *oe; -+ struct dentry *alias = NULL; -+ struct inode *realinode; -+ struct dentry *realdentry; -+ bool is_upper; -+ int err; -+ -+ if (S_ISDIR(inode->i_mode)) { -+ oe = inode->i_private; -+ } else if (mask & MAY_NOT_BLOCK) { -+ return -ECHILD; -+ } else { -+ /* -+ * For non-directories find an alias and get the info -+ * from there. -+ */ -+ spin_lock(&inode->i_lock); -+ if (WARN_ON(list_empty(&inode->i_dentry))) { -+ spin_unlock(&inode->i_lock); -+ return -ENOENT; -+ } -+ alias = list_entry(inode->i_dentry.next, -+ struct dentry, d_alias); -+ dget(alias); -+ spin_unlock(&inode->i_lock); -+ oe = alias->d_fsdata; -+ } -+ -+ realdentry = ovl_entry_real(oe, &is_upper); -+ -+ /* Careful in RCU walk mode */ -+ realinode = ACCESS_ONCE(realdentry->d_inode); -+ if (!realinode) { -+ WARN_ON(!(mask & MAY_NOT_BLOCK)); -+ err = -ENOENT; -+ goto out_dput; -+ } -+ -+ if (mask & MAY_WRITE) { -+ umode_t mode = realinode->i_mode; -+ -+ /* -+ * Writes will always be redirected to upper layer, so -+ * ignore lower layer being read-only. -+ * -+ * If the overlay itself is read-only then proceed -+ * with the permission check, don't return EROFS. -+ * This will only happen if this is the lower layer of -+ * another overlayfs. -+ * -+ * If upper fs becomes read-only after the overlay was -+ * constructed return EROFS to prevent modification of -+ * upper layer. -+ */ -+ err = -EROFS; -+ if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) && -+ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) -+ goto out_dput; -+ } -+ -+ err = inode_only_permission(realinode, mask); -+out_dput: -+ dput(alias); -+ return err; -+} -+ -+ -+struct ovl_link_data { -+ struct dentry *realdentry; -+ void *cookie; -+}; -+ -+static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd) -+{ -+ void *ret; -+ struct dentry *realdentry; -+ struct inode *realinode; -+ -+ realdentry = ovl_dentry_real(dentry); -+ realinode = realdentry->d_inode; -+ -+ if (WARN_ON(!realinode->i_op->follow_link)) -+ return ERR_PTR(-EPERM); -+ -+ ret = realinode->i_op->follow_link(realdentry, nd); -+ if (IS_ERR(ret)) -+ return ret; -+ -+ if (realinode->i_op->put_link) { -+ struct ovl_link_data *data; -+ -+ data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL); -+ if (!data) { -+ realinode->i_op->put_link(realdentry, nd, ret); -+ return ERR_PTR(-ENOMEM); -+ } -+ data->realdentry = realdentry; -+ data->cookie = ret; -+ -+ return data; -+ } else { -+ return NULL; -+ } -+} -+ -+static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c) -+{ -+ struct inode *realinode; -+ struct ovl_link_data *data = c; -+ -+ if (!data) -+ return; -+ -+ realinode = data->realdentry->d_inode; -+ realinode->i_op->put_link(data->realdentry, nd, data->cookie); -+ kfree(data); -+} -+ -+static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz) -+{ -+ struct path realpath; -+ struct inode *realinode; -+ -+ ovl_path_real(dentry, &realpath); -+ realinode = realpath.dentry->d_inode; -+ -+ if (!realinode->i_op->readlink) -+ return -EINVAL; -+ -+ touch_atime(&realpath); -+ -+ return realinode->i_op->readlink(realpath.dentry, buf, bufsiz); -+} -+ -+ -+static bool ovl_is_private_xattr(const char *name) -+{ -+ return strncmp(name, "trusted.overlay.", 14) == 0; -+} -+ -+int ovl_setxattr(struct dentry *dentry, const char *name, -+ const void *value, size_t size, int flags) -+{ -+ int err; -+ struct dentry *upperdentry; -+ -+ if (ovl_is_private_xattr(name)) -+ return -EPERM; -+ -+ err = ovl_copy_up(dentry); -+ if (err) -+ return err; -+ -+ upperdentry = ovl_dentry_upper(dentry); -+ return vfs_setxattr(upperdentry, name, value, size, flags); -+} -+ -+ssize_t ovl_getxattr(struct dentry *dentry, const char *name, -+ void *value, size_t size) -+{ -+ if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && -+ ovl_is_private_xattr(name)) -+ return -ENODATA; -+ -+ return vfs_getxattr(ovl_dentry_real(dentry), name, value, size); -+} -+ -+ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) -+{ -+ ssize_t res; -+ int off; -+ -+ res = vfs_listxattr(ovl_dentry_real(dentry), list, size); -+ if (res <= 0 || size == 0) -+ return res; -+ -+ if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE) -+ return res; -+ -+ /* filter out private xattrs */ -+ for (off = 0; off < res;) { -+ char *s = list + off; -+ size_t slen = strlen(s) + 1; -+ -+ BUG_ON(off + slen > res); -+ -+ if (ovl_is_private_xattr(s)) { -+ res -= slen; -+ memmove(s, s + slen, res - off); -+ } else { -+ off += slen; -+ } -+ } -+ -+ return res; -+} -+ -+int ovl_removexattr(struct dentry *dentry, const char *name) -+{ -+ int err; -+ struct path realpath; -+ enum ovl_path_type type; -+ -+ if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && -+ ovl_is_private_xattr(name)) -+ return -ENODATA; -+ -+ type = ovl_path_real(dentry, &realpath); -+ if (type == OVL_PATH_LOWER) { -+ err = vfs_getxattr(realpath.dentry, name, NULL, 0); -+ if (err < 0) -+ return err; -+ -+ err = ovl_copy_up(dentry); -+ if (err) -+ return err; -+ -+ ovl_path_upper(dentry, &realpath); -+ } -+ -+ return vfs_removexattr(realpath.dentry, name); -+} -+ -+static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, -+ struct dentry *realdentry) -+{ -+ if (type != OVL_PATH_LOWER) -+ return false; -+ -+ if (special_file(realdentry->d_inode->i_mode)) -+ return false; -+ -+ if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC)) -+ return false; -+ -+ return true; -+} -+ -+static struct file *ovl_open(struct dentry *dentry, struct file *file, -+ const struct cred *cred) -+{ -+ int err; -+ struct path realpath; -+ enum ovl_path_type type; -+ -+ type = ovl_path_real(dentry, &realpath); -+ if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) { -+ if (file->f_flags & O_TRUNC) -+ err = ovl_copy_up_truncate(dentry, 0); -+ else -+ err = ovl_copy_up(dentry); -+ if (err) -+ return ERR_PTR(err); -+ -+ ovl_path_upper(dentry, &realpath); -+ } -+ -+ return vfs_open(&realpath, file, cred); -+} -+ -+static const struct inode_operations ovl_file_inode_operations = { -+ .setattr = ovl_setattr, -+ .permission = ovl_permission, -+ .getattr = ovl_getattr, -+ .setxattr = ovl_setxattr, -+ .getxattr = ovl_getxattr, -+ .listxattr = ovl_listxattr, -+ .removexattr = ovl_removexattr, -+ .open = ovl_open, -+}; -+ -+static const struct inode_operations ovl_symlink_inode_operations = { -+ .setattr = ovl_setattr, -+ .follow_link = ovl_follow_link, -+ .put_link = ovl_put_link, -+ .readlink = ovl_readlink, -+ .getattr = ovl_getattr, -+ .setxattr = ovl_setxattr, -+ .getxattr = ovl_getxattr, -+ .listxattr = ovl_listxattr, -+ .removexattr = ovl_removexattr, -+}; -+ -+struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, -+ struct ovl_entry *oe) -+{ -+ struct inode *inode; -+ -+ inode = new_inode(sb); -+ if (!inode) -+ return NULL; -+ -+ mode &= S_IFMT; -+ -+ inode->i_ino = get_next_ino(); -+ inode->i_mode = mode; -+ inode->i_flags |= S_NOATIME | S_NOCMTIME; -+ -+ switch (mode) { -+ case S_IFDIR: -+ inode->i_private = oe; -+ inode->i_op = &ovl_dir_inode_operations; -+ inode->i_fop = &ovl_dir_operations; -+ break; -+ -+ case S_IFLNK: -+ inode->i_op = &ovl_symlink_inode_operations; -+ break; -+ -+ case S_IFREG: -+ case S_IFSOCK: -+ case S_IFBLK: -+ case S_IFCHR: -+ case S_IFIFO: -+ inode->i_op = &ovl_file_inode_operations; -+ break; -+ -+ default: -+ WARN(1, "illegal file type: %i\n", mode); -+ iput(inode); -+ inode = NULL; -+ } -+ -+ return inode; -+ -+} -diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h -new file mode 100644 -index 0000000..1dd05f7 ---- /dev/null -+++ b/fs/overlayfs/overlayfs.h -@@ -0,0 +1,64 @@ -+/* -+ * -+ * Copyright (C) 2011 Novell 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. -+ */ -+ -+struct ovl_entry; -+ -+enum ovl_path_type { -+ OVL_PATH_UPPER, -+ OVL_PATH_MERGE, -+ OVL_PATH_LOWER, -+}; -+ -+extern const char *ovl_opaque_xattr; -+extern const char *ovl_whiteout_xattr; -+extern const struct dentry_operations ovl_dentry_operations; -+ -+enum ovl_path_type ovl_path_type(struct dentry *dentry); -+u64 ovl_dentry_version_get(struct dentry *dentry); -+void ovl_dentry_version_inc(struct dentry *dentry); -+void ovl_path_upper(struct dentry *dentry, struct path *path); -+void ovl_path_lower(struct dentry *dentry, struct path *path); -+enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path); -+struct dentry *ovl_dentry_upper(struct dentry *dentry); -+struct dentry *ovl_dentry_lower(struct dentry *dentry); -+struct dentry *ovl_dentry_real(struct dentry *dentry); -+struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper); -+bool ovl_dentry_is_opaque(struct dentry *dentry); -+void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque); -+bool ovl_is_whiteout(struct dentry *dentry); -+void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); -+struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, -+ struct nameidata *nd); -+struct file *ovl_path_open(struct path *path, int flags); -+ -+struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry, -+ struct kstat *stat, const char *link); -+ -+/* readdir.c */ -+extern const struct file_operations ovl_dir_operations; -+int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type); -+ -+/* inode.c */ -+int ovl_setattr(struct dentry *dentry, struct iattr *attr); -+int ovl_permission(struct inode *inode, int mask); -+int ovl_setxattr(struct dentry *dentry, const char *name, -+ const void *value, size_t size, int flags); -+ssize_t ovl_getxattr(struct dentry *dentry, const char *name, -+ void *value, size_t size); -+ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); -+int ovl_removexattr(struct dentry *dentry, const char *name); -+ -+struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, -+ struct ovl_entry *oe); -+/* dir.c */ -+extern const struct inode_operations ovl_dir_inode_operations; -+ -+/* copy_up.c */ -+int ovl_copy_up(struct dentry *dentry); -+int ovl_copy_up_truncate(struct dentry *dentry, loff_t size); -diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c -new file mode 100644 -index 0000000..0797efb ---- /dev/null -+++ b/fs/overlayfs/readdir.c -@@ -0,0 +1,566 @@ -+/* -+ * -+ * Copyright (C) 2011 Novell 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/fs.h> -+#include <linux/slab.h> -+#include <linux/namei.h> -+#include <linux/file.h> -+#include <linux/xattr.h> -+#include <linux/rbtree.h> -+#include <linux/security.h> -+#include <linux/cred.h> -+#include "overlayfs.h" -+ -+struct ovl_cache_entry { -+ const char *name; -+ unsigned int len; -+ unsigned int type; -+ u64 ino; -+ bool is_whiteout; -+ struct list_head l_node; -+ struct rb_node node; -+}; -+ -+struct ovl_readdir_data { -+ struct rb_root *root; -+ struct list_head *list; -+ struct list_head *middle; -+ struct dentry *dir; -+ int count; -+ int err; -+}; -+ -+struct ovl_dir_file { -+ bool is_real; -+ bool is_cached; -+ struct list_head cursor; -+ u64 cache_version; -+ struct list_head cache; -+ struct file *realfile; -+}; -+ -+static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n) -+{ -+ return container_of(n, struct ovl_cache_entry, node); -+} -+ -+static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root, -+ const char *name, int len) -+{ -+ struct rb_node *node = root->rb_node; -+ int cmp; -+ -+ while (node) { -+ struct ovl_cache_entry *p = ovl_cache_entry_from_node(node); -+ -+ cmp = strncmp(name, p->name, len); -+ if (cmp > 0) -+ node = p->node.rb_right; -+ else if (cmp < 0 || len < p->len) -+ node = p->node.rb_left; -+ else -+ return p; -+ } -+ -+ return NULL; -+} -+ -+static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len, -+ u64 ino, unsigned int d_type) -+{ -+ struct ovl_cache_entry *p; -+ -+ p = kmalloc(sizeof(*p) + len + 1, GFP_KERNEL); -+ if (p) { -+ char *name_copy = (char *) (p + 1); -+ memcpy(name_copy, name, len); -+ name_copy[len] = '\0'; -+ p->name = name_copy; -+ p->len = len; -+ p->type = d_type; -+ p->ino = ino; -+ p->is_whiteout = false; -+ } -+ -+ return p; -+} -+ -+static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, -+ const char *name, int len, u64 ino, -+ unsigned int d_type) -+{ -+ struct rb_node **newp = &rdd->root->rb_node; -+ struct rb_node *parent = NULL; -+ struct ovl_cache_entry *p; -+ -+ while (*newp) { -+ int cmp; -+ struct ovl_cache_entry *tmp; -+ -+ parent = *newp; -+ tmp = ovl_cache_entry_from_node(*newp); -+ cmp = strncmp(name, tmp->name, len); -+ if (cmp > 0) -+ newp = &tmp->node.rb_right; -+ else if (cmp < 0 || len < tmp->len) -+ newp = &tmp->node.rb_left; -+ else -+ return 0; -+ } -+ -+ p = ovl_cache_entry_new(name, len, ino, d_type); -+ if (p == NULL) -+ return -ENOMEM; -+ -+ list_add_tail(&p->l_node, rdd->list); -+ rb_link_node(&p->node, parent, newp); -+ rb_insert_color(&p->node, rdd->root); -+ -+ return 0; -+} -+ -+static int ovl_fill_lower(void *buf, const char *name, int namelen, -+ loff_t offset, u64 ino, unsigned int d_type) -+{ -+ struct ovl_readdir_data *rdd = buf; -+ struct ovl_cache_entry *p; -+ -+ rdd->count++; -+ p = ovl_cache_entry_find(rdd->root, name, namelen); -+ if (p) { -+ list_move_tail(&p->l_node, rdd->middle); -+ } else { -+ p = ovl_cache_entry_new(name, namelen, ino, d_type); -+ if (p == NULL) -+ rdd->err = -ENOMEM; -+ else -+ list_add_tail(&p->l_node, rdd->middle); -+ } -+ -+ return rdd->err; -+} -+ -+static void ovl_cache_free(struct list_head *list) -+{ -+ struct ovl_cache_entry *p; -+ struct ovl_cache_entry *n; -+ -+ list_for_each_entry_safe(p, n, list, l_node) -+ kfree(p); -+ -+ INIT_LIST_HEAD(list); -+} -+ -+static int ovl_fill_upper(void *buf, const char *name, int namelen, -+ loff_t offset, u64 ino, unsigned int d_type) -+{ -+ struct ovl_readdir_data *rdd = buf; -+ -+ rdd->count++; -+ return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type); -+} -+ -+static inline int ovl_dir_read(struct path *realpath, -+ struct ovl_readdir_data *rdd, filldir_t filler) -+{ -+ struct file *realfile; -+ int err; -+ -+ realfile = ovl_path_open(realpath, O_RDONLY | O_DIRECTORY); -+ if (IS_ERR(realfile)) -+ return PTR_ERR(realfile); -+ -+ do { -+ rdd->count = 0; -+ rdd->err = 0; -+ err = vfs_readdir(realfile, filler, rdd); -+ if (err >= 0) -+ err = rdd->err; -+ } while (!err && rdd->count); -+ fput(realfile); -+ -+ return 0; -+} -+ -+static void ovl_dir_reset(struct file *file) -+{ -+ struct ovl_dir_file *od = file->private_data; -+ enum ovl_path_type type = ovl_path_type(file->f_path.dentry); -+ -+ if (ovl_dentry_version_get(file->f_path.dentry) != od->cache_version) { -+ list_del_init(&od->cursor); -+ ovl_cache_free(&od->cache); -+ od->is_cached = false; -+ } -+ WARN_ON(!od->is_real && type != OVL_PATH_MERGE); -+ if (od->is_real && type == OVL_PATH_MERGE) { -+ fput(od->realfile); -+ od->realfile = NULL; -+ od->is_real = false; -+ } -+} -+ -+static int ovl_dir_mark_whiteouts(struct ovl_readdir_data *rdd) -+{ -+ struct ovl_cache_entry *p; -+ struct dentry *dentry; -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ -+ override_cred = prepare_creds(); -+ if (!override_cred) { -+ ovl_cache_free(rdd->list); -+ return -ENOMEM; -+ } -+ -+ /* -+ * CAP_SYS_ADMIN for getxattr -+ * CAP_DAC_OVERRIDE for lookup -+ */ -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); -+ old_cred = override_creds(override_cred); -+ -+ mutex_lock(&rdd->dir->d_inode->i_mutex); -+ list_for_each_entry(p, rdd->list, l_node) { -+ if (p->type != DT_LNK) -+ continue; -+ -+ dentry = lookup_one_len(p->name, rdd->dir, p->len); -+ if (IS_ERR(dentry)) -+ continue; -+ -+ p->is_whiteout = ovl_is_whiteout(dentry); -+ dput(dentry); -+ } -+ mutex_unlock(&rdd->dir->d_inode->i_mutex); -+ -+ revert_creds(old_cred); -+ put_cred(override_cred); -+ -+ return 0; -+} -+ -+static inline int ovl_dir_read_merged(struct path *upperpath, -+ struct path *lowerpath, -+ struct ovl_readdir_data *rdd) -+{ -+ int err; -+ struct rb_root root = RB_ROOT; -+ struct list_head middle; -+ -+ rdd->root = &root; -+ if (upperpath->dentry) { -+ rdd->dir = upperpath->dentry; -+ err = ovl_dir_read(upperpath, rdd, ovl_fill_upper); -+ if (err) -+ goto out; -+ -+ err = ovl_dir_mark_whiteouts(rdd); -+ if (err) -+ goto out; -+ } -+ /* -+ * Insert lowerpath entries before upperpath ones, this allows -+ * offsets to be reasonably constant -+ */ -+ list_add(&middle, rdd->list); -+ rdd->middle = &middle; -+ err = ovl_dir_read(lowerpath, rdd, ovl_fill_lower); -+ list_del(&middle); -+out: -+ rdd->root = NULL; -+ -+ return err; -+} -+ -+static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) -+{ -+ struct list_head *l; -+ loff_t off; -+ -+ l = od->cache.next; -+ for (off = 0; off < pos; off++) { -+ if (l == &od->cache) -+ break; -+ l = l->next; -+ } -+ list_move_tail(&od->cursor, l); -+} -+ -+static int ovl_readdir(struct file *file, void *buf, filldir_t filler) -+{ -+ struct ovl_dir_file *od = file->private_data; -+ int res; -+ -+ if (!file->f_pos) -+ ovl_dir_reset(file); -+ -+ if (od->is_real) { -+ res = vfs_readdir(od->realfile, filler, buf); -+ file->f_pos = od->realfile->f_pos; -+ -+ return res; -+ } -+ -+ if (!od->is_cached) { -+ struct path lowerpath; -+ struct path upperpath; -+ struct ovl_readdir_data rdd = { .list = &od->cache }; -+ -+ ovl_path_lower(file->f_path.dentry, &lowerpath); -+ ovl_path_upper(file->f_path.dentry, &upperpath); -+ -+ res = ovl_dir_read_merged(&upperpath, &lowerpath, &rdd); -+ if (res) { -+ ovl_cache_free(rdd.list); -+ return res; -+ } -+ -+ od->cache_version = ovl_dentry_version_get(file->f_path.dentry); -+ od->is_cached = true; -+ -+ ovl_seek_cursor(od, file->f_pos); -+ } -+ -+ while (od->cursor.next != &od->cache) { -+ int over; -+ loff_t off; -+ struct ovl_cache_entry *p; -+ -+ p = list_entry(od->cursor.next, struct ovl_cache_entry, l_node); -+ off = file->f_pos; -+ if (!p->is_whiteout) { -+ over = filler(buf, p->name, p->len, off, p->ino, -+ p->type); -+ if (over) -+ break; -+ } -+ file->f_pos++; -+ list_move(&od->cursor, &p->l_node); -+ } -+ -+ return 0; -+} -+ -+static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t res; -+ struct ovl_dir_file *od = file->private_data; -+ -+ mutex_lock(&file->f_dentry->d_inode->i_mutex); -+ if (!file->f_pos) -+ ovl_dir_reset(file); -+ -+ if (od->is_real) { -+ res = vfs_llseek(od->realfile, offset, origin); -+ file->f_pos = od->realfile->f_pos; -+ } else { -+ res = -EINVAL; -+ -+ switch (origin) { -+ case SEEK_CUR: -+ offset += file->f_pos; -+ break; -+ case SEEK_SET: -+ break; -+ default: -+ goto out_unlock; -+ } -+ if (offset < 0) -+ goto out_unlock; -+ -+ if (offset != file->f_pos) { -+ file->f_pos = offset; -+ if (od->is_cached) -+ ovl_seek_cursor(od, offset); -+ } -+ res = offset; -+ } -+out_unlock: -+ mutex_unlock(&file->f_dentry->d_inode->i_mutex); -+ -+ return res; -+} -+ -+static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, -+ int datasync) -+{ -+ struct ovl_dir_file *od = file->private_data; -+ -+ /* May need to reopen directory if it got copied up */ -+ if (!od->realfile) { -+ struct path upperpath; -+ -+ ovl_path_upper(file->f_path.dentry, &upperpath); -+ od->realfile = ovl_path_open(&upperpath, O_RDONLY); -+ if (IS_ERR(od->realfile)) -+ return PTR_ERR(od->realfile); -+ } -+ -+ return vfs_fsync_range(od->realfile, start, end, datasync); -+} -+ -+static int ovl_dir_release(struct inode *inode, struct file *file) -+{ -+ struct ovl_dir_file *od = file->private_data; -+ -+ list_del(&od->cursor); -+ ovl_cache_free(&od->cache); -+ if (od->realfile) -+ fput(od->realfile); -+ kfree(od); -+ -+ return 0; -+} -+ -+static int ovl_dir_open(struct inode *inode, struct file *file) -+{ -+ struct path realpath; -+ struct file *realfile; -+ struct ovl_dir_file *od; -+ enum ovl_path_type type; -+ -+ od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL); -+ if (!od) -+ return -ENOMEM; -+ -+ type = ovl_path_real(file->f_path.dentry, &realpath); -+ realfile = ovl_path_open(&realpath, file->f_flags); -+ if (IS_ERR(realfile)) { -+ kfree(od); -+ return PTR_ERR(realfile); -+ } -+ INIT_LIST_HEAD(&od->cache); -+ INIT_LIST_HEAD(&od->cursor); -+ od->is_cached = false; -+ od->realfile = realfile; -+ od->is_real = (type != OVL_PATH_MERGE); -+ file->private_data = od; -+ -+ return 0; -+} -+ -+const struct file_operations ovl_dir_operations = { -+ .read = generic_read_dir, -+ .open = ovl_dir_open, -+ .readdir = ovl_readdir, -+ .llseek = ovl_dir_llseek, -+ .fsync = ovl_dir_fsync, -+ .release = ovl_dir_release, -+}; -+ -+static int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) -+{ -+ int err; -+ struct path lowerpath; -+ struct path upperpath; -+ struct ovl_cache_entry *p; -+ struct ovl_readdir_data rdd = { .list = list }; -+ -+ ovl_path_upper(dentry, &upperpath); -+ ovl_path_lower(dentry, &lowerpath); -+ -+ err = ovl_dir_read_merged(&upperpath, &lowerpath, &rdd); -+ if (err) -+ return err; -+ -+ err = 0; -+ -+ list_for_each_entry(p, list, l_node) { -+ if (p->is_whiteout) -+ continue; -+ -+ if (p->name[0] == '.') { -+ if (p->len == 1) -+ continue; -+ if (p->len == 2 && p->name[1] == '.') -+ continue; -+ } -+ err = -ENOTEMPTY; -+ break; -+ } -+ -+ return err; -+} -+ -+static int ovl_remove_whiteouts(struct dentry *dir, struct list_head *list) -+{ -+ struct path upperpath; -+ struct dentry *upperdir; -+ struct ovl_cache_entry *p; -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ int err; -+ -+ ovl_path_upper(dir, &upperpath); -+ upperdir = upperpath.dentry; -+ -+ override_cred = prepare_creds(); -+ if (!override_cred) -+ return -ENOMEM; -+ -+ /* -+ * CAP_DAC_OVERRIDE for lookup and unlink -+ * CAP_SYS_ADMIN for setxattr of "trusted" namespace -+ * CAP_FOWNER for unlink in sticky directory -+ */ -+ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ cap_raise(override_cred->cap_effective, CAP_FOWNER); -+ old_cred = override_creds(override_cred); -+ -+ err = vfs_setxattr(upperdir, ovl_opaque_xattr, "y", 1, 0); -+ if (err) -+ goto out_revert_creds; -+ -+ mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); -+ list_for_each_entry(p, list, l_node) { -+ struct dentry *dentry; -+ int ret; -+ -+ if (!p->is_whiteout) -+ continue; -+ -+ dentry = lookup_one_len(p->name, upperdir, p->len); -+ if (IS_ERR(dentry)) { -+ printk(KERN_WARNING -+ "overlayfs: failed to lookup whiteout %.*s: %li\n", -+ p->len, p->name, PTR_ERR(dentry)); -+ continue; -+ } -+ ret = vfs_unlink(upperdir->d_inode, dentry); -+ dput(dentry); -+ if (ret) -+ printk(KERN_WARNING -+ "overlayfs: failed to unlink whiteout %.*s: %i\n", -+ p->len, p->name, ret); -+ } -+ mutex_unlock(&upperdir->d_inode->i_mutex); -+ -+out_revert_creds: -+ revert_creds(old_cred); -+ put_cred(override_cred); -+ -+ return err; -+} -+ -+int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type) -+{ -+ int err; -+ LIST_HEAD(list); -+ -+ err = ovl_check_empty_dir(dentry, &list); -+ if (!err && type == OVL_PATH_MERGE) -+ err = ovl_remove_whiteouts(dentry, &list); -+ -+ ovl_cache_free(&list); -+ -+ return err; -+} -diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c -new file mode 100644 -index 0000000..1d2d1e2 ---- /dev/null -+++ b/fs/overlayfs/super.c -@@ -0,0 +1,664 @@ -+/* -+ * -+ * Copyright (C) 2011 Novell 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/fs.h> -+#include <linux/namei.h> -+#include <linux/xattr.h> -+#include <linux/security.h> -+#include <linux/mount.h> -+#include <linux/slab.h> -+#include <linux/parser.h> -+#include <linux/module.h> -+#include <linux/cred.h> -+#include <linux/sched.h> -+#include <linux/seq_file.h> -+#include "overlayfs.h" -+ -+MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); -+MODULE_DESCRIPTION("Overlay filesystem"); -+MODULE_LICENSE("GPL"); -+ -+struct ovl_config { -+ char *lowerdir; -+ char *upperdir; -+}; -+ -+/* private information held for overlayfs's superblock */ -+struct ovl_fs { -+ struct vfsmount *upper_mnt; -+ struct vfsmount *lower_mnt; -+ /* pathnames of lower and upper dirs, for show_options */ -+ struct ovl_config config; -+}; -+ -+/* private information held for every overlayfs dentry */ -+struct ovl_entry { -+ /* -+ * Keep "double reference" on upper dentries, so that -+ * d_delete() doesn't think it's OK to reset d_inode to NULL. -+ */ -+ struct dentry *__upperdentry; -+ struct dentry *lowerdentry; -+ union { -+ struct { -+ u64 version; -+ bool opaque; -+ }; -+ struct rcu_head rcu; -+ }; -+}; -+ -+const char *ovl_whiteout_xattr = "trusted.overlay.whiteout"; -+const char *ovl_opaque_xattr = "trusted.overlay.opaque"; -+ -+ -+enum ovl_path_type ovl_path_type(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ if (oe->__upperdentry) { -+ if (oe->lowerdentry && S_ISDIR(dentry->d_inode->i_mode)) -+ return OVL_PATH_MERGE; -+ else -+ return OVL_PATH_UPPER; -+ } else { -+ return OVL_PATH_LOWER; -+ } -+} -+ -+static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe) -+{ -+ struct dentry *upperdentry = ACCESS_ONCE(oe->__upperdentry); -+ smp_read_barrier_depends(); -+ return upperdentry; -+} -+ -+void ovl_path_upper(struct dentry *dentry, struct path *path) -+{ -+ struct ovl_fs *ofs = dentry->d_sb->s_fs_info; -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ path->mnt = ofs->upper_mnt; -+ path->dentry = ovl_upperdentry_dereference(oe); -+} -+ -+void ovl_path_lower(struct dentry *dentry, struct path *path) -+{ -+ struct ovl_fs *ofs = dentry->d_sb->s_fs_info; -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ path->mnt = ofs->lower_mnt; -+ path->dentry = oe->lowerdentry; -+} -+ -+enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) -+{ -+ -+ enum ovl_path_type type = ovl_path_type(dentry); -+ -+ if (type == OVL_PATH_LOWER) -+ ovl_path_lower(dentry, path); -+ else -+ ovl_path_upper(dentry, path); -+ -+ return type; -+} -+ -+struct dentry *ovl_dentry_upper(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ return ovl_upperdentry_dereference(oe); -+} -+ -+struct dentry *ovl_dentry_lower(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ return oe->lowerdentry; -+} -+ -+struct dentry *ovl_dentry_real(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ struct dentry *realdentry; -+ -+ realdentry = ovl_upperdentry_dereference(oe); -+ if (!realdentry) -+ realdentry = oe->lowerdentry; -+ -+ return realdentry; -+} -+ -+struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper) -+{ -+ struct dentry *realdentry; -+ -+ realdentry = ovl_upperdentry_dereference(oe); -+ if (realdentry) { -+ *is_upper = true; -+ } else { -+ realdentry = oe->lowerdentry; -+ *is_upper = false; -+ } -+ return realdentry; -+} -+ -+bool ovl_dentry_is_opaque(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ return oe->opaque; -+} -+ -+void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ oe->opaque = opaque; -+} -+ -+void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ WARN_ON(!mutex_is_locked(&upperdentry->d_parent->d_inode->i_mutex)); -+ WARN_ON(oe->__upperdentry); -+ BUG_ON(!upperdentry->d_inode); -+ smp_wmb(); -+ oe->__upperdentry = dget(upperdentry); -+} -+ -+void ovl_dentry_version_inc(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); -+ oe->version++; -+} -+ -+u64 ovl_dentry_version_get(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); -+ return oe->version; -+} -+ -+bool ovl_is_whiteout(struct dentry *dentry) -+{ -+ int res; -+ char val; -+ -+ if (!dentry) -+ return false; -+ if (!dentry->d_inode) -+ return false; -+ if (!S_ISLNK(dentry->d_inode->i_mode)) -+ return false; -+ -+ res = vfs_getxattr(dentry, ovl_whiteout_xattr, &val, 1); -+ if (res == 1 && val == 'y') -+ return true; -+ -+ return false; -+} -+ -+static bool ovl_is_opaquedir(struct dentry *dentry) -+{ -+ int res; -+ char val; -+ -+ if (!S_ISDIR(dentry->d_inode->i_mode)) -+ return false; -+ -+ res = vfs_getxattr(dentry, ovl_opaque_xattr, &val, 1); -+ if (res == 1 && val == 'y') -+ return true; -+ -+ return false; -+} -+ -+static void ovl_entry_free(struct rcu_head *head) -+{ -+ struct ovl_entry *oe = container_of(head, struct ovl_entry, rcu); -+ kfree(oe); -+} -+ -+static void ovl_dentry_release(struct dentry *dentry) -+{ -+ struct ovl_entry *oe = dentry->d_fsdata; -+ -+ if (oe) { -+ dput(oe->__upperdentry); -+ dput(oe->__upperdentry); -+ dput(oe->lowerdentry); -+ call_rcu(&oe->rcu, ovl_entry_free); -+ } -+} -+ -+const struct dentry_operations ovl_dentry_operations = { -+ .d_release = ovl_dentry_release, -+}; -+ -+static struct ovl_entry *ovl_alloc_entry(void) -+{ -+ return kzalloc(sizeof(struct ovl_entry), GFP_KERNEL); -+} -+ -+static inline struct dentry *ovl_lookup_real(struct dentry *dir, -+ struct qstr *name) -+{ -+ struct dentry *dentry; -+ -+ mutex_lock(&dir->d_inode->i_mutex); -+ dentry = lookup_one_len(name->name, dir, name->len); -+ mutex_unlock(&dir->d_inode->i_mutex); -+ -+ if (IS_ERR(dentry)) { -+ if (PTR_ERR(dentry) == -ENOENT) -+ dentry = NULL; -+ } else if (!dentry->d_inode) { -+ dput(dentry); -+ dentry = NULL; -+ } -+ return dentry; -+} -+ -+static int ovl_do_lookup(struct dentry *dentry) -+{ -+ struct ovl_entry *oe; -+ struct dentry *upperdir; -+ struct dentry *lowerdir; -+ struct dentry *upperdentry = NULL; -+ struct dentry *lowerdentry = NULL; -+ struct inode *inode = NULL; -+ int err; -+ -+ err = -ENOMEM; -+ oe = ovl_alloc_entry(); -+ if (!oe) -+ goto out; -+ -+ upperdir = ovl_dentry_upper(dentry->d_parent); -+ lowerdir = ovl_dentry_lower(dentry->d_parent); -+ -+ if (upperdir) { -+ upperdentry = ovl_lookup_real(upperdir, &dentry->d_name); -+ err = PTR_ERR(upperdentry); -+ if (IS_ERR(upperdentry)) -+ goto out_put_dir; -+ -+ if (lowerdir && upperdentry && -+ (S_ISLNK(upperdentry->d_inode->i_mode) || -+ S_ISDIR(upperdentry->d_inode->i_mode))) { -+ const struct cred *old_cred; -+ struct cred *override_cred; -+ -+ err = -ENOMEM; -+ override_cred = prepare_creds(); -+ if (!override_cred) -+ goto out_dput_upper; -+ -+ /* CAP_SYS_ADMIN needed for getxattr */ -+ cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); -+ old_cred = override_creds(override_cred); -+ -+ if (ovl_is_opaquedir(upperdentry)) { -+ oe->opaque = true; -+ } else if (ovl_is_whiteout(upperdentry)) { -+ dput(upperdentry); -+ upperdentry = NULL; -+ oe->opaque = true; -+ } -+ revert_creds(old_cred); -+ put_cred(override_cred); -+ } -+ } -+ if (lowerdir && !oe->opaque) { -+ lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name); -+ err = PTR_ERR(lowerdentry); -+ if (IS_ERR(lowerdentry)) -+ goto out_dput_upper; -+ } -+ -+ if (lowerdentry && upperdentry && -+ (!S_ISDIR(upperdentry->d_inode->i_mode) || -+ !S_ISDIR(lowerdentry->d_inode->i_mode))) { -+ dput(lowerdentry); -+ lowerdentry = NULL; -+ oe->opaque = true; -+ } -+ -+ if (lowerdentry || upperdentry) { -+ struct dentry *realdentry; -+ -+ realdentry = upperdentry ? upperdentry : lowerdentry; -+ err = -ENOMEM; -+ inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, -+ oe); -+ if (!inode) -+ goto out_dput; -+ } -+ -+ if (upperdentry) -+ oe->__upperdentry = dget(upperdentry); -+ -+ if (lowerdentry) -+ oe->lowerdentry = lowerdentry; -+ -+ dentry->d_fsdata = oe; -+ dentry->d_op = &ovl_dentry_operations; -+ d_add(dentry, inode); -+ -+ return 0; -+ -+out_dput: -+ dput(lowerdentry); -+out_dput_upper: -+ dput(upperdentry); -+out_put_dir: -+ kfree(oe); -+out: -+ return err; -+} -+ -+struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, -+ struct nameidata *nd) -+{ -+ int err = ovl_do_lookup(dentry); -+ -+ if (err) -+ return ERR_PTR(err); -+ -+ return NULL; -+} -+ -+struct file *ovl_path_open(struct path *path, int flags) -+{ -+ path_get(path); -+ return dentry_open(path->dentry, path->mnt, flags, current_cred()); -+} -+ -+static void ovl_put_super(struct super_block *sb) -+{ -+ struct ovl_fs *ufs = sb->s_fs_info; -+ -+ if (!(sb->s_flags & MS_RDONLY)) -+ mnt_drop_write(ufs->upper_mnt); -+ -+ mntput(ufs->upper_mnt); -+ mntput(ufs->lower_mnt); -+ -+ kfree(ufs->config.lowerdir); -+ kfree(ufs->config.upperdir); -+ kfree(ufs); -+} -+ -+static int ovl_remount_fs(struct super_block *sb, int *flagsp, char *data) -+{ -+ int flags = *flagsp; -+ struct ovl_fs *ufs = sb->s_fs_info; -+ -+ /* When remounting rw or ro, we need to adjust the write access to the -+ * upper fs. -+ */ -+ if (((flags ^ sb->s_flags) & MS_RDONLY) == 0) -+ /* No change to readonly status */ -+ return 0; -+ -+ if (flags & MS_RDONLY) { -+ mnt_drop_write(ufs->upper_mnt); -+ return 0; -+ } else -+ return mnt_want_write(ufs->upper_mnt); -+} -+ -+/** -+ * ovl_statfs -+ * @sb: The overlayfs super block -+ * @buf: The struct kstatfs to fill in with stats -+ * -+ * Get the filesystem statistics. As writes always target the upper layer -+ * filesystem pass the statfs to the same filesystem. -+ */ -+static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct dentry *root_dentry = dentry->d_sb->s_root; -+ struct path path; -+ ovl_path_upper(root_dentry, &path); -+ -+ if (!path.dentry->d_sb->s_op->statfs) -+ return -ENOSYS; -+ return path.dentry->d_sb->s_op->statfs(path.dentry, buf); -+} -+ -+/** -+ * ovl_show_options -+ * -+ * Prints the mount options for a given superblock. -+ * Returns zero; does not fail. -+ */ -+static int ovl_show_options(struct seq_file *m, struct dentry *dentry) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct ovl_fs *ufs = sb->s_fs_info; -+ -+ seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); -+ seq_printf(m, ",upperdir=%s", ufs->config.upperdir); -+ return 0; -+} -+ -+static const struct super_operations ovl_super_operations = { -+ .put_super = ovl_put_super, -+ .remount_fs = ovl_remount_fs, -+ .statfs = ovl_statfs, -+ .show_options = ovl_show_options, -+}; -+ -+enum { -+ Opt_lowerdir, -+ Opt_upperdir, -+ Opt_err, -+}; -+ -+static const match_table_t ovl_tokens = { -+ {Opt_lowerdir, "lowerdir=%s"}, -+ {Opt_upperdir, "upperdir=%s"}, -+ {Opt_err, NULL} -+}; -+ -+static int ovl_parse_opt(char *opt, struct ovl_config *config) -+{ -+ char *p; -+ -+ config->upperdir = NULL; -+ config->lowerdir = NULL; -+ -+ while ((p = strsep(&opt, ",")) != NULL) { -+ int token; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ if (!*p) -+ continue; -+ -+ token = match_token(p, ovl_tokens, args); -+ switch (token) { -+ case Opt_upperdir: -+ kfree(config->upperdir); -+ config->upperdir = match_strdup(&args[0]); -+ if (!config->upperdir) -+ return -ENOMEM; -+ break; -+ -+ case Opt_lowerdir: -+ kfree(config->lowerdir); -+ config->lowerdir = match_strdup(&args[0]); -+ if (!config->lowerdir) -+ return -ENOMEM; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ } -+ return 0; -+} -+ -+static int ovl_fill_super(struct super_block *sb, void *data, int silent) -+{ -+ struct path lowerpath; -+ struct path upperpath; -+ struct inode *root_inode; -+ struct dentry *root_dentry; -+ struct ovl_entry *oe; -+ struct ovl_fs *ufs; -+ int err; -+ -+ err = -ENOMEM; -+ ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); -+ if (!ufs) -+ goto out; -+ -+ err = ovl_parse_opt((char *) data, &ufs->config); -+ if (err) -+ goto out_free_ufs; -+ -+ err = -EINVAL; -+ if (!ufs->config.upperdir || !ufs->config.lowerdir) { -+ printk(KERN_ERR "overlayfs: missing upperdir or lowerdir\n"); -+ goto out_free_config; -+ } -+ -+ oe = ovl_alloc_entry(); -+ if (oe == NULL) -+ goto out_free_config; -+ -+ err = kern_path(ufs->config.upperdir, LOOKUP_FOLLOW, &upperpath); -+ if (err) -+ goto out_free_oe; -+ -+ err = kern_path(ufs->config.lowerdir, LOOKUP_FOLLOW, &lowerpath); -+ if (err) -+ goto out_put_upperpath; -+ -+ err = -ENOTDIR; -+ if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || -+ !S_ISDIR(lowerpath.dentry->d_inode->i_mode)) -+ goto out_put_lowerpath; -+ -+ sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, -+ lowerpath.mnt->mnt_sb->s_stack_depth) + 1; -+ -+ err = -EINVAL; -+ if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { -+ printk(KERN_ERR "overlayfs: maximum fs stacking depth exceeded\n"); -+ goto out_put_lowerpath; -+ } -+ -+ -+ ufs->upper_mnt = clone_private_mount(&upperpath); -+ err = PTR_ERR(ufs->upper_mnt); -+ if (IS_ERR(ufs->upper_mnt)) { -+ printk(KERN_ERR "overlayfs: failed to clone upperpath\n"); -+ goto out_put_lowerpath; -+ } -+ -+ ufs->lower_mnt = clone_private_mount(&lowerpath); -+ err = PTR_ERR(ufs->lower_mnt); -+ if (IS_ERR(ufs->lower_mnt)) { -+ printk(KERN_ERR "overlayfs: failed to clone lowerpath\n"); -+ goto out_put_upper_mnt; -+ } -+ -+ /* -+ * Make lower_mnt R/O. That way fchmod/fchown on lower file -+ * will fail instead of modifying lower fs. -+ */ -+ ufs->lower_mnt->mnt_flags |= MNT_READONLY; -+ -+ /* If the upper fs is r/o, we mark overlayfs r/o too */ -+ if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) -+ sb->s_flags |= MS_RDONLY; -+ -+ if (!(sb->s_flags & MS_RDONLY)) { -+ err = mnt_want_write(ufs->upper_mnt); -+ if (err) -+ goto out_put_lower_mnt; -+ } -+ -+ err = -ENOMEM; -+ root_inode = ovl_new_inode(sb, S_IFDIR, oe); -+ if (!root_inode) -+ goto out_drop_write; -+ -+ root_dentry = d_make_root(root_inode); -+ if (!root_dentry) -+ goto out_drop_write; -+ -+ mntput(upperpath.mnt); -+ mntput(lowerpath.mnt); -+ -+ oe->__upperdentry = dget(upperpath.dentry); -+ oe->lowerdentry = lowerpath.dentry; -+ -+ root_dentry->d_fsdata = oe; -+ root_dentry->d_op = &ovl_dentry_operations; -+ -+ sb->s_op = &ovl_super_operations; -+ sb->s_root = root_dentry; -+ sb->s_fs_info = ufs; -+ -+ return 0; -+ -+out_drop_write: -+ if (!(sb->s_flags & MS_RDONLY)) -+ mnt_drop_write(ufs->upper_mnt); -+out_put_lower_mnt: -+ mntput(ufs->lower_mnt); -+out_put_upper_mnt: -+ mntput(ufs->upper_mnt); -+out_put_lowerpath: -+ path_put(&lowerpath); -+out_put_upperpath: -+ path_put(&upperpath); -+out_free_oe: -+ kfree(oe); -+out_free_config: -+ kfree(ufs->config.lowerdir); -+ kfree(ufs->config.upperdir); -+out_free_ufs: -+ kfree(ufs); -+out: -+ return err; -+} -+ -+static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags, -+ const char *dev_name, void *raw_data) -+{ -+ return mount_nodev(fs_type, flags, raw_data, ovl_fill_super); -+} -+ -+static struct file_system_type ovl_fs_type = { -+ .owner = THIS_MODULE, -+ .name = "overlayfs", -+ .mount = ovl_mount, -+ .kill_sb = kill_anon_super, -+}; -+ -+static int __init ovl_init(void) -+{ -+ return register_filesystem(&ovl_fs_type); -+} -+ -+static void __exit ovl_exit(void) -+{ -+ unregister_filesystem(&ovl_fs_type); -+} -+ -+module_init(ovl_init); -+module_exit(ovl_exit); -diff --git a/fs/splice.c b/fs/splice.c -index f847684..c124964 100644 ---- a/fs/splice.c -+++ b/fs/splice.c -@@ -1299,6 +1299,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, - - return ret; - } -+EXPORT_SYMBOL(do_splice_direct); - - static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, - struct pipe_inode_info *opipe, -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 8de6755..0b531ab 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -489,6 +489,12 @@ struct iattr { - */ - #include <linux/quota.h> - -+/* -+ * Maximum number of layers of fs stack. Needs to be limited to -+ * prevent kernel stack overflow -+ */ -+#define FILESYSTEM_MAX_STACK_DEPTH 2 -+ - /** - * enum positive_aop_returns - aop return codes with specific semantics - * -@@ -1507,6 +1513,11 @@ struct super_block { - - /* Being remounted read-only */ - int s_readonly_remount; -+ -+ /* -+ * Indicates how deep in a filesystem stack this SB is -+ */ -+ int s_stack_depth; - }; - - /* superblock cache pruning functions */ -@@ -1664,6 +1675,8 @@ struct inode_operations { - void (*truncate_range)(struct inode *, loff_t, loff_t); - int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, - u64 len); -+ struct file *(*open) (struct dentry *, struct file *, -+ const struct cred *); - } ____cacheline_aligned; - - struct seq_file; -@@ -2021,6 +2034,7 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags, - extern struct file *filp_open(const char *, int, umode_t); - extern struct file *file_open_root(struct dentry *, struct vfsmount *, - const char *, int); -+extern struct file *vfs_open(struct path *, struct file *, const struct cred *); - extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, - const struct cred *); - extern int filp_close(struct file *, fl_owner_t id); -@@ -2212,6 +2226,7 @@ extern sector_t bmap(struct inode *, sector_t); - #endif - extern int notify_change(struct dentry *, struct iattr *); - extern int inode_permission(struct inode *, int); -+extern int inode_only_permission(struct inode *, int); - extern int generic_permission(struct inode *, int); - - static inline bool execute_ok(struct inode *inode) -diff --git a/include/linux/mount.h b/include/linux/mount.h -index d7029f4..344a262 100644 ---- a/include/linux/mount.h -+++ b/include/linux/mount.h -@@ -66,6 +66,9 @@ extern void mnt_pin(struct vfsmount *mnt); - extern void mnt_unpin(struct vfsmount *mnt); - extern int __mnt_is_readonly(struct vfsmount *mnt); - -+struct path; -+extern struct vfsmount *clone_private_mount(struct path *path); -+ - struct file_system_type; - extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, - int flags, const char *name, diff --git a/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/20_fix_gcc8.patch b/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/20_fix_gcc8.patch deleted file mode 120000 index 32a424bc..00000000 --- a/br-ext-chip-anyka/board/ak3918ev200/kernel/patches/20_fix_gcc8.patch +++ /dev/null @@ -1 +0,0 @@ -../../../../../patches/linux/3.4.x/gcc8_err_encountered.patch \ No newline at end of file diff --git a/br-ext-chip-anyka/configs/unknown_unknown_ak3918ev200_openipc_defconfig b/br-ext-chip-anyka/configs/unknown_unknown_ak3918ev200_openipc_defconfig deleted file mode 100644 index 228fb26f..00000000 --- a/br-ext-chip-anyka/configs/unknown_unknown_ak3918ev200_openipc_defconfig +++ /dev/null @@ -1,103 +0,0 @@ -# Architecture -BR2_arm=y -BR2_arm926t=y -BR2_ARM_EABI=y -# BR2_ARM_INSTRUCTIONS_THUMB is not set -BR2_KERNEL_HEADERS_VERSION=y -BR2_DEFAULT_KERNEL_VERSION="3.4.35" -BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_3_4=y - -# Toolchain -BR2_PER_PACKAGE_DIRECTORIES=y -BR2_GCC_VERSION_8_X=y -# BR2_TOOLCHAIN_USES_UCLIBC is not set -# BR2_TOOLCHAIN_BUILDROOT_UCLIBC is not set -# BR2_TOOLCHAIN_BUILDROOT_LIBC="uclibc" -BR2_TOOLCHAIN_USES_MUSL=y -BR2_TOOLCHAIN_BUILDROOT_MUSL=y -BR2_TOOLCHAIN_BUILDROOT_LIBC="musl" -BR2_TOOLCHAIN_BUILDROOT_CXX=y -BR2_TOOLCHAIN_BUILDROOT_LOCALE=y -BR2_TOOLCHAIN_BUILDROOT_USE_SSP=y - -# Kernel -BR2_LINUX_KERNEL=y -BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="3.4.35" -BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y -BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_ANYKA_PATH)/board/ak3918ev200/kernel/ak3918ev200.generic.config" -BR2_LINUX_KERNEL_UIMAGE=y -BR2_LINUX_KERNEL_XZ=y -BR2_LINUX_KERNEL_EXT_ANYKA_PATCHER=y -BR2_LINUX_KERNEL_EXT_ANYKA_PATCHER_LIST="$(BR2_EXTERNAL_ANYKA_PATH)/board/ak3918ev200/kernel/patches/ $(BR2_EXTERNAL_ANYKA_PATH)/board/ak3918ev200/kernel/overlay" - -# Filesystem -# BR2_TARGET_TZ_INFO is not set -BR2_TARGET_ROOTFS_CPIO=y -BR2_TARGET_ROOTFS_SQUASHFS=y -BR2_TARGET_ROOTFS_SQUASHFS4_XZ=y -BR2_ROOTFS_OVERLAY="$(TOPDIR)/../general/overlay" -BR2_ROOTFS_POST_BUILD_SCRIPT="$(TOPDIR)/../scripts/executing_commands_for_$(BR2_TOOLCHAIN_BUILDROOT_LIBC).sh" - -# OpenIPC configuration -BR2_TOOLCHAIN_BUILDROOT_VENDOR="openipc" -BR2_TARGET_GENERIC_ISSUE="Welcome to OpenIPC v2.2" -BR2_TARGET_GENERIC_HOSTNAME="openipc-ak3918ev200" -BR2_GLOBAL_PATCH_DIR="$(TOPDIR)/../general/package/all-patches" - -# OpenIPC packages -BR2_PACKAGE_BUSYBOX_CONFIG="$(TOPDIR)/../general/package/busybox/busybox.config" -BR2_PACKAGE_DROPBEAR_OPENIPC=y -# BR2_PACKAGE_FDK_AAC_OPENIPC is not set -BR2_PACKAGE_FWPRINTENV_OPENIPC=y -BR2_PACKAGE_HASERL=y -# BR2_PACKAGE_ANYKA_GPIO is not set -# BR2_PACKAGE_ANYKA_OSDRV_AK3918EV300 is not set -BR2_PACKAGE_IPCTOOL=y -BR2_PACKAGE_JSON_C=y -BR2_PACKAGE_LAME_OPENIPC=y -BR2_PACKAGE_LIBCURL_OPENIPC=y -BR2_PACKAGE_LIBCURL_OPENIPC_CURL=y -# BR2_PACKAGE_LIBCURL_OPENIPC_VERBOSE is not set -# BR2_PACKAGE_LIBCURL_OPENIPC_PROXY_SUPPORT is not set -# BR2_PACKAGE_LIBCURL_OPENIPC_COOKIES_SUPPORT is not set -# BR2_PACKAGE_LIBCURL_OPENIPC_EXTRA_PROTOCOLS_FEATURES is not set -BR2_PACKAGE_LIBCURL_OPENIPC_MBEDTLS=y -BR2_PACKAGE_LIBEVENT_OPENIPC=y -BR2_PACKAGE_LIBEVENT_OPENIPC_REMOVE_PYSCRIPT=y -BR2_PACKAGE_LIBOGG_OPENIPC=y -BR2_PACKAGE_LIBWEBSOCKETS_OPENIPC=y -BR2_PACKAGE_LIBYAML=y -BR2_PACKAGE_MAJESTIC_FONTS=y -# BR2_PACKAGE_MAJESTIC=y -BR2_PACKAGE_MBEDTLS_OPENIPC=y -# BR2_PACKAGE_MBEDTLS_OPENIPC_PROGRAMS is not set -# BR2_PACKAGE_MBEDTLS_OPENIPC_COMPRESSION is not set -BR2_PACKAGE_MICROBE_WEB=y -# BR2_PACKAGE_MINI_SNMPD is not set -BR2_PACKAGE_MOTORS=y -BR2_PACKAGE_OPUS_OPENIPC=y -BR2_PACKAGE_OPUS_OPENIPC_FIXED_POINT=y -# BR2_PACKAGE_SSHPASS is not set -BR2_PACKAGE_UACME_OPENIPC=y -BR2_PACKAGE_VTUND_OPENIPC=y -BR2_PACKAGE_YAML_CLI=y - -# WiFi -BR2_PACKAGE_WIRELESS_TOOLS=y -BR2_PACKAGE_WPA_SUPPLICANT=y -BR2_PACKAGE_WPA_SUPPLICANT_CLI=y -BR2_PACKAGE_WPA_SUPPLICANT_NL80211=y -BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y -BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC=y -BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC_MT7601U=y -BR2_PACKAGE_LINUX_FIRMWARE_OPENIPC_RTL8188EU=y -# BR2_PACKAGE_RTL8188EU is not set - -# WIREGUARD -BR2_PACKAGE_WIREGUARD_LINUX_COMPAT=y -BR2_PACKAGE_WIREGUARD_TOOLS=y - -# DEBUG -BR2_PACKAGE_HOST_GDB=y -BR2_PACKAGE_GDB=y diff --git a/br-ext-chip-anyka/package/anyka-osdrv-ak3918ev200 b/br-ext-chip-anyka/package/anyka-osdrv-ak3918ev200 deleted file mode 120000 index 34dd9713..00000000 --- a/br-ext-chip-anyka/package/anyka-osdrv-ak3918ev200 +++ /dev/null @@ -1 +0,0 @@ -../../general/package/anyka-osdrv-ak3918ev200 \ No newline at end of file diff --git a/building.sh b/building.sh index 2771720b..63cc5827 100755 --- a/building.sh +++ b/building.sh @@ -160,7 +160,6 @@ autoup_rootfs() { FUNCS=( ambarella-s3l - ak3918ev200 ak3916ev300 ak3918ev300 diff --git a/general/package/anyka-osdrv-ak3918ev200/Config.in b/general/package/anyka-osdrv-ak3918ev200/Config.in deleted file mode 100644 index 82144a54..00000000 --- a/general/package/anyka-osdrv-ak3918ev200/Config.in +++ /dev/null @@ -1,6 +0,0 @@ -config BR2_PACKAGE_ANYKA_OSDRV_AK3918EV200 - bool "anyka-osdrv-ak3918ev200" - help - anyka-osdrv-ak3918ev200 - Anyka kernel modules and libs - - https://openipc.org diff --git a/general/package/anyka-osdrv-ak3918ev200/anyka-osdrv-ak3918ev200.mk b/general/package/anyka-osdrv-ak3918ev200/anyka-osdrv-ak3918ev200.mk deleted file mode 100644 index 125c624f..00000000 --- a/general/package/anyka-osdrv-ak3918ev200/anyka-osdrv-ak3918ev200.mk +++ /dev/null @@ -1,34 +0,0 @@ -################################################################################ -# -# anyka-osdrv-ak3918ev200 -# -################################################################################ - -ANYKA_OSDRV_AK3918EV200_VERSION = -ANYKA_OSDRV_AK3918EV200_SITE = -ANYKA_OSDRV_AK3918EV200_LICENSE = MIT -ANYKA_OSDRV_AK3918EV200_LICENSE_FILES = LICENSE - -define ANYKA_OSDRV_AK3918EV200_INSTALL_TARGET_CMDS - $(INSTALL) -m 755 -d $(TARGET_DIR)/etc/init.d - $(INSTALL) -m 755 -t $(TARGET_DIR)/etc/init.d $(BR2_EXTERNAL_ANYKA_PATH)/package/anyka-osdrv-ak3918ev200/files/script/S95anyka - - $(INSTALL) -m 755 -d $(TARGET_DIR)/etc/sensors - $(INSTALL) -m 644 -t $(TARGET_DIR)/etc/sensors $(BR2_EXTERNAL_ANYKA_PATH)/package/anyka-osdrv-ak3918ev200/files/sensor/config/*.conf - - $(INSTALL) -m 755 -d $(TARGET_DIR)/lib/modules/3.4.35/anyka - $(INSTALL) -m 644 -t $(TARGET_DIR)/lib/modules/3.4.35/anyka $(BR2_EXTERNAL_ANYKA_PATH)/package/anyka-osdrv-ak3918ev200/files/kmod/*.ko - - $(INSTALL) -m 755 -d $(TARGET_DIR)/usr/bin - $(INSTALL) -m 755 -t $(TARGET_DIR)/usr/bin $(BR2_EXTERNAL_ANYKA_PATH)/package/anyka-osdrv-ak3918ev200/files/script/load_anyka - # $(INSTALL) -m 755 -t $(TARGET_DIR)/usr/bin $(BR2_EXTERNAL_ANYKA_PATH)/package/anyka-osdrv-ak3918ev200/files/script/ircut_demo - - $(INSTALL) -m 755 -d $(TARGET_DIR)/usr/lib/sensors - # $(INSTALL) -m 644 -t $(TARGET_DIR)/usr/lib/sensors $(BR2_EXTERNAL_ANYKA_PATH)/package/anyka-osdrv-ak3918ev200/files/sensor/*.so - - $(INSTALL) -m 755 -d $(TARGET_DIR)/usr/lib - - # $(INSTALL) -m 644 -t $(TARGET_DIR)/usr/lib/ $(BR2_EXTERNAL_ANYKA_PATH)/package/anyka-osdrv-ak3918ev200/files/lib/xxx.so -endef - -$(eval $(generic-package)) diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/akcamera.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/akcamera.ko deleted file mode 100644 index 80620609..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/akcamera.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_ar0130.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_ar0130.ko deleted file mode 100644 index dd6f7811..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_ar0130.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_gc1024.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_gc1024.ko deleted file mode 100644 index d5dd0c86..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_gc1024.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_gc1034.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_gc1034.ko deleted file mode 100644 index ab3fd161..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_gc1034.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h42.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h42.ko deleted file mode 100644 index 93739ad5..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h42.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h61.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h61.ko deleted file mode 100644 index 1eb7c4cb..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h61.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h62.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h62.ko deleted file mode 100644 index d4642836..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_h62.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_ov9712.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_ov9712.ko deleted file mode 100644 index 2b5c7ed3..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_ov9712.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1035.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1035.ko deleted file mode 100644 index d2258064..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1035.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1045.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1045.ko deleted file mode 100644 index fe12e0c5..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1045.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1135.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1135.ko deleted file mode 100644 index 161c4e39..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1135.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1145.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1145.ko deleted file mode 100644 index de75d0f3..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1145.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1235.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1235.ko deleted file mode 100644 index 0eea6c1b..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1235.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1245.ko b/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1245.ko deleted file mode 100644 index 6322ec69..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/kmod/sensor_sc1245.ko and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/script/S95anyka b/general/package/anyka-osdrv-ak3918ev200/files/script/S95anyka deleted file mode 100755 index 5fed0f8a..00000000 --- a/general/package/anyka-osdrv-ak3918ev200/files/script/S95anyka +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -DAEMON="majestic" -PIDFILE="/var/run/$DAEMON.pid" - -DAEMON_ARGS="-s" - -# shellcheck source=/dev/null -[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON" - -load_majestic() { - printf 'Starting %s: ' "$DAEMON" - [ -f /usr/bin/$DAEMON ] || echo -en "DISABLED, " - # shellcheck disable=SC2086 # we need the word splitting - [ -f /etc/coredump.conf ] && . /etc/coredump.conf - if [ "$coredump_enabled" ]; then - [ "$(yaml-cli -i /etc/majestic.yaml -g .watchdog.timeout)" -lt "30" ] && yaml-cli -i /etc/majestic.yaml -s .watchdog.timeout 30 - ulimit -c unlimited && echo "|/usr/sbin/sendcoredump.sh" >/proc/sys/kernel/core_pattern - fi - start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/usr/bin/$DAEMON" \ - -- $DAEMON_ARGS - status=$? - if [ "$status" -eq 0 ]; then - echo "OK" - else - echo "FAIL" - fi - return "$status" -} - -# The daemon does not create a pidfile, and use "-m" to instruct start-stop-daemon to create one. -start() { - logger -s -p daemon.info -t anyka "Check MAC for Xiongmai devices" - if [ "$(fw_printenv -n ethaddr)" = "00:00:23:34:45:66" ]; then - logger -s -p daemon.info -t anyka "The eth0 interface has a lousy MAC, let's try to change it.." - XMMAC="$(ipcinfo --xm-mac)" && [ -n "${XMMAC}" ] && fw_setenv ethaddr ${XMMAC} && reboot -f || logger -s -p daemon.info -t anyka "It is not possible to install a new MAC on the eth0 interface.." - else - logger -s -p daemon.info -t anyka "The eth0 interface has a correct MAC - $(fw_printenv -n ethaddr)" - fi - # - logger -s -p daemon.info -t anyka "Loading of kernel modules and initialization of the video system has started" - export TZ=$(cat /etc/TZ) - #load_anyka - # - #load_majestic -} - -stop() { - printf 'Stopping %s: ' "$DAEMON" - [ -f /usr/bin/$DAEMON ] || echo -en "DISABLED, " - start-stop-daemon -K -q -p "$PIDFILE" - status=$? - if [ "$status" -eq 0 ]; then - rm -f "$PIDFILE" - echo "OK" - else - echo "FAIL" - fi - return "$status" -} - -restart() { - stop - sleep 1 - reload -} - -reload() { - load_majestic -} - -case "$1" in - start|stop|restart|reload) - "$1";; - *) - echo "Usage: $0 {start|stop|restart|reload}" - exit 1 -esac diff --git a/general/package/anyka-osdrv-ak3918ev200/files/script/ircut_demo b/general/package/anyka-osdrv-ak3918ev200/files/script/ircut_demo deleted file mode 100755 index 2d1f1ea7..00000000 --- a/general/package/anyka-osdrv-ak3918ev200/files/script/ircut_demo +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/sh - -# on EV200: -# GPIO1_0 -> GPIO8 (1*8+0 = 8) -# GPIO1_1 -> GPIO9 (1*8+1 = 9) - -# on EV300: -# GPIO1_3 -> GPIO11 -# GPIO1_2 -> GPIO10 - -#(normal mode) -ir_cut_enable() { - # pin_mux - echo "$gpio_0" >/sys/class/gpio/unexport - echo "$gpio_1" >/sys/class/gpio/unexport - echo "$gpio_0" >/sys/class/gpio/export - echo "$gpio_1" >/sys/class/gpio/export - - # dir - echo "out" >/sys/class/gpio/gpio$gpio_0/direction - echo "out" >/sys/class/gpio/gpio$gpio_1/direction - - # data, gpio_1: 0, gpio_0: 1 (normal mode) - echo "1" >/sys/class/gpio/gpio$gpio_0/value - echo "0" >/sys/class/gpio/gpio$gpio_1/value - - #sleep 1s - sleep 1 - - # back to original - echo "0" >/sys/class/gpio/gpio$gpio_0/value - echo "0" >/sys/class/gpio/gpio$gpio_1/value -} - -# (ir mode) -ir_cut_disable() { - # pin_mux - echo "$gpio_0" >/sys/class/gpio/unexport - echo "$gpio_1" >/sys/class/gpio/unexport - echo "$gpio_0" >/sys/class/gpio/export - echo "$gpio_1" >/sys/class/gpio/export - - # dir - echo "out" >/sys/class/gpio/gpio$gpio_0/direction - echo "out" >/sys/class/gpio/gpio$gpio_1/direction - - # data, gpio_1: 1, gpio_0: 0 (ir mode) - echo "0" >/sys/class/gpio/gpio$gpio_0/value - echo "1" >/sys/class/gpio/gpio$gpio_1/value - - #sleep 1s - sleep 1 - - # back to original - echo "0" >/sys/class/gpio/gpio$gpio_0/value - echo "0" >/sys/class/gpio/gpio$gpio_1/value -} - -gpio_0=0 -gpio_1=0 - -if [ $# -lt 2 ]; then - echo "usage : ./ircut_demo <chip> <mode>" - echo "for example:" - echo "ir mode : ./ircut_demo hi3516ev200 1" -else - if [ $1 = "hi3516ev200" ]; then - gpio_0=8 - gpio_1=9 - elif [ $1 = "hi3516ev300" ]; then - gpio_0=11 - gpio_1=10 - else - echo "wrong chipid: $1, please select: hi3516ev200 or hi3516ev300." - exit - fi - - if [ $2 -eq 0 ]; then - echo "normal mode, ir_cut on" - ir_cut_enable >/dev/null - elif [ $2 -eq 1 ]; then - echo "ir mode, ir_cut off" - ir_cut_disable >/dev/null - else - echo "invalid mode, please slect 0 or 1." - fi -fi diff --git a/general/package/anyka-osdrv-ak3918ev200/files/script/load_anyka b/general/package/anyka-osdrv-ak3918ev200/files/script/load_anyka deleted file mode 100755 index a2792c17..00000000 --- a/general/package/anyka-osdrv-ak3918ev200/files/script/load_anyka +++ /dev/null @@ -1,196 +0,0 @@ -#!/bin/sh -# -# This is part of OpenIPC.org project | 2020.08.01 -# -# ar0237 imx290 imx307 imx323 imx385 jxf22 ov2718 ov2718_2a sc2235 - - -# SoC detect -chipid=$(ipcinfo --chip-name) - -# MMZ config -mem_start=0x80000000; # phy mem start - -mem_total=$(fw_printenv -n totalmem | tr -d 'M') -mem_total=${mem_total:=64} - -os_mem_size=$(fw_printenv -n osmem | tr -d 'M') -os_mem_size=${os_mem_size:=32} - -report_error() -{ - echo "******* Error: There's something wrong, please check! *****" - exit 1 -} - -insert_mmz() -{ -} - -insert_detect() -{ - insert_mmz - insert_isp - SENSOR=ar0130 insert_sns -} - -remove_detect() -{ -} - -remove_sns() -{ - rmmod -w sensor_spi &> /dev/null - rmmod -w sensor_i2c &> /dev/null -} - -insert_isp() -{ -} - -insert_sns() -{ -} - -insert_ko() -{ - find . -maxdepth 1 -type f -name "sensor_*.ko" -exec insmod {} \; - insmod akcamera.ko -} - -remove_ko() -{ -} - -calc_mmz_info() -{ - mmz_start=`echo "$mem_start $os_mem_size" | - awk 'BEGIN { temp = 0; } - { - temp = $1/1024/1024 + $2; - } - END { printf("0x%x00000\n", temp); }'` - - mmz_size=`echo "$mem_total $os_mem_size" | - awk 'BEGIN { temp = 0; } - { - temp = $1 - $2; - } - END { printf("%dM\n", temp); }'` - echo "mmz_start: $mmz_start, mmz_size: $mmz_size" -} - - -######################parse arg################################### -b_arg_os_mem=0 -b_arg_total_mem=0 -b_arg_sensor=0 -b_arg_insmod=0 -b_arg_remove=0 -b_arg_online=1 - -for arg in $@ -do - if [ $b_arg_total_mem -eq 1 ]; then - b_arg_total_mem=0; - mem_total=$arg; - - if [ -z $mem_total ]; then - echo "[error] mem_total is null" - exit; - fi - fi - - if [ $b_arg_os_mem -eq 1 ] ; then - b_arg_os_mem=0; - os_mem_size=$arg; - - if [ -z $os_mem_size ]; then - echo "[error] os_mem_size is null" - exit; - fi - fi - - if [ $b_arg_sensor -eq 1 ] ; then - b_arg_sensor=0 - SENSOR=$arg; - fi - - case $arg in - "-i") - b_arg_insmod=1; - ;; - "-r") - b_arg_remove=1; - ;; - "-a") - b_arg_insmod=1; - b_arg_remove=1; - ;; - "-h") - load_usage; - ;; - "-sensor") - b_arg_sensor=1; - ;; - "-osmem") - b_arg_os_mem=1; - ;; - "-total") - b_arg_total_mem=1; - ;; - "-offline") - b_arg_online=0; - ;; - esac -done -#######################parse arg end######################## - -if [ $os_mem_size -ge $mem_total ] ; then - echo "[err] os_mem[$os_mem_size], over total_mem[$mem_total]" - exit; -fi - -calc_mmz_info; - -#######################Action############################### - -if [ $# -lt 1 ]; then - load_usage; - exit 0; -fi - -# Sensor config -# SENSOR=${SENSOR:=imx307} -# - -if [ -n "$SENSOR" ]; then - logger -s -p daemon.info -t anyka "Manualy set SENSOR as ${SENSOR}" -else - if fw_printenv -n sensor >/dev/null; then - SENSOR_ENV=$(fw_printenv -n sensor) - export SENSOR=${SENSOR_ENV} - logger -s -p daemon.info -t anyka "Get data from environment and set SENSOR as ${SENSOR}" - else - #insert_detect - SENSOR_DETECT=$(ipcinfo --short-sensor) - export SENSOR=${SENSOR_DETECT:=unknown} - #remove_detect - logger -s -p daemon.info -t anyka "Get data from ipcinfo and set SENSOR as ${SENSOR}" - fw_setenv sensor $SENSOR && logger -s -p daemon.info -t anyka "Write detected ${SENSOR} to U-Boot ENV" - fi -fi - -if [ $b_arg_remove -eq 1 ]; then - remove_ko; -fi - -cd /lib/modules/3.4.35/anyka - -if [ "$SENSOR" = "unknown" ]; then - exit 1 -else - if [ $b_arg_insmod -eq 1 ]; then - insert_ko; - fi -fi diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_9712.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_9712.conf deleted file mode 100644 index 8bee9928..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_9712.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_ar0130.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_ar0130.conf deleted file mode 100644 index b3a44cdd..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_ar0130.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_gc1024.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_gc1024.conf deleted file mode 100644 index d8960f37..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_gc1024.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_h42.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_h42.conf deleted file mode 100644 index 1d1bbd78..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_h42.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_h42_krt.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_h42_krt.conf deleted file mode 100644 index 29b475a3..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_h42_krt.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035.conf deleted file mode 100644 index 5acb8fdd..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035_ja.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035_ja.conf deleted file mode 100644 index a13b1d6d..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035_ja.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035_yws.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035_yws.conf deleted file mode 100644 index e189c575..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1035_yws.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045.conf deleted file mode 100644 index a0ff7e4a..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045_ja.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045_ja.conf deleted file mode 100644 index 67b9a87f..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045_ja.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045_yws.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045_yws.conf deleted file mode 100644 index c9f14651..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1045_yws.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1135.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1135.conf deleted file mode 100644 index ade23f3f..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1135.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1135_yws.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1135_yws.conf deleted file mode 100644 index 7173a4f1..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1135_yws.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1145.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1145.conf deleted file mode 100644 index 80d18302..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1145.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1145_yws.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1145_yws.conf deleted file mode 100644 index c561a6e1..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1145_yws.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235.conf deleted file mode 100644 index 0410a559..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235_1.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235_1.conf deleted file mode 100644 index 80390cbb..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235_1.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235_2.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235_2.conf deleted file mode 100644 index 526ccad8..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1235_2.conf and /dev/null differ diff --git a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1245.conf b/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1245.conf deleted file mode 100644 index 19d0f9eb..00000000 Binary files a/general/package/anyka-osdrv-ak3918ev200/files/sensor/config/isp_sc1245.conf and /dev/null differ