+++ /dev/null
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-omap-h6300
-# Sun Oct 30 09:16:57 2005
-#
-CONFIG_ARM=y
-CONFIG_MMU=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# System Type
-#
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-CONFIG_ARCH_OMAP=y
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_AAEC2000 is not set
-
-#
-# TI OMAP Implementations
-#
-CONFIG_ARCH_OMAP1=y
-# CONFIG_ARCH_OMAP2 is not set
-
-#
-# OMAP Feature Selections
-#
-# CONFIG_OMAP_RESET_CLOCKS is not set
-# CONFIG_OMAP_BOOT_TAG is not set
-CONFIG_OMAP_MUX=y
-# CONFIG_OMAP_MUX_DEBUG is not set
-CONFIG_OMAP_MUX_WARNINGS=y
-CONFIG_OMAP_MPU_TIMER=y
-# CONFIG_OMAP_32K_TIMER is not set
-CONFIG_OMAP_LL_DEBUG_UART1=y
-# CONFIG_OMAP_LL_DEBUG_UART2 is not set
-# CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_SERIAL_WAKE=y
-
-#
-# OMAP Core Type
-#
-# CONFIG_ARCH_OMAP730 is not set
-CONFIG_ARCH_OMAP15XX=y
-# CONFIG_ARCH_OMAP16XX is not set
-
-#
-# OMAP Board Type
-#
-# CONFIG_MACH_OMAP_INNOVATOR is not set
-CONFIG_MACH_OMAP_H6300=y
-# CONFIG_MACH_VOICEBLUE is not set
-# CONFIG_MACH_NETSTAR is not set
-# CONFIG_MACH_OMAP_PALMTE is not set
-# CONFIG_MACH_OMAP_GENERIC is not set
-
-#
-# OMAP CPU Speed
-#
-# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
-CONFIG_OMAP_ARM_168MHZ=y
-CONFIG_OMAP_ARM_150MHZ=y
-CONFIG_OMAP_ARM_120MHZ=y
-CONFIG_OMAP_ARM_60MHZ=y
-CONFIG_OMAP_ARM_30MHZ=y
-CONFIG_OMAP_DSP=y
-CONFIG_OMAP_DSP_MBCMD_VERBOSE=y
-CONFIG_OMAP_DSP_TASK_MULTIOPEN=y
-CONFIG_OMAP_DSP_FBEXPORT=y
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_ARM925T=y
-CONFIG_CPU_32v4=y
-CONFIG_CPU_ABRT_EV4T=y
-CONFIG_CPU_CACHE_V4WT=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_COPY_V4WB=y
-CONFIG_CPU_TLB_V4WBI=y
-
-#
-# Processor Features
-#
-CONFIG_ARM_THUMB=y
-# CONFIG_CPU_ICACHE_DISABLE is not set
-# CONFIG_CPU_DCACHE_DISABLE is not set
-CONFIG_CPU_DCACHE_WRITETHROUGH=y
-
-#
-# Bus support
-#
-CONFIG_ISA_DMA_API=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-CONFIG_PCCARD=m
-# CONFIG_PCMCIA_DEBUG is not set
-CONFIG_PCMCIA=m
-CONFIG_PCMCIA_LOAD_CIS=y
-CONFIG_PCMCIA_IOCTL=y
-
-#
-# PC-card bridges
-#
-
-#
-# Kernel Features
-#
-# CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_NO_IDLE_HZ is not set
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_LEDS=y
-CONFIG_LEDS_TIMER=y
-CONFIG_LEDS_CPU=y
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=tty0 root=/dev/nfs nfsroot=192.168.2.1:/opt/h6300/rootfs,rsize=8192,wsize=8192 ip=192.168.2.2:192.168.2.1:192.168.2.1:255.0.0.0:ipaq:"
-# CONFIG_XIP_KERNEL is not set
-
-#
-# CPU Frequency scaling
-#
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
-CONFIG_CPU_FREQ_DEBUG=y
-CONFIG_CPU_FREQ_STAT=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=y
-# CONFIG_FPE_FASTFPE is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_MISC=y
-# CONFIG_ARTHUR is not set
-
-#
-# Power management options
-#
-CONFIG_PM=y
-CONFIG_APM=y
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-CONFIG_INET_TUNNEL=m
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_INET6_TUNNEL=m
-CONFIG_IPV6_TUNNEL=m
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_BRIDGE_NETFILTER=y
-# CONFIG_NETFILTER_NETLINK is not set
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_CT_ACCT=y
-CONFIG_IP_NF_CONNTRACK_MARK=y
-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-CONFIG_IP_NF_CT_PROTO_SCTP=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-CONFIG_IP_NF_TFTP=m
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_PPTP is not set
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-# CONFIG_IP_NF_MATCH_MARK is not set
-# CONFIG_IP_NF_MATCH_MULTIPORT is not set
-# CONFIG_IP_NF_MATCH_TOS is not set
-# CONFIG_IP_NF_MATCH_RECENT is not set
-# CONFIG_IP_NF_MATCH_ECN is not set
-# CONFIG_IP_NF_MATCH_DSCP is not set
-# CONFIG_IP_NF_MATCH_AH_ESP is not set
-# CONFIG_IP_NF_MATCH_LENGTH is not set
-# CONFIG_IP_NF_MATCH_TTL is not set
-# CONFIG_IP_NF_MATCH_TCPMSS is not set
-# CONFIG_IP_NF_MATCH_HELPER is not set
-# CONFIG_IP_NF_MATCH_STATE is not set
-# CONFIG_IP_NF_MATCH_CONNTRACK is not set
-# CONFIG_IP_NF_MATCH_OWNER is not set
-# CONFIG_IP_NF_MATCH_PHYSDEV is not set
-# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-# CONFIG_IP_NF_MATCH_SCTP is not set
-# CONFIG_IP_NF_MATCH_DCCP is not set
-# CONFIG_IP_NF_MATCH_COMMENT is not set
-# CONFIG_IP_NF_MATCH_CONNMARK is not set
-# CONFIG_IP_NF_MATCH_CONNBYTES is not set
-# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
-# CONFIG_IP_NF_MATCH_STRING is not set
-# CONFIG_IP_NF_FILTER is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-# CONFIG_IP_NF_TARGET_ULOG is not set
-# CONFIG_IP_NF_TARGET_TCPMSS is not set
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-# CONFIG_IP_NF_NAT is not set
-CONFIG_IP_NF_MANGLE=m
-# CONFIG_IP_NF_TARGET_TOS is not set
-# CONFIG_IP_NF_TARGET_ECN is not set
-# CONFIG_IP_NF_TARGET_DSCP is not set
-# CONFIG_IP_NF_TARGET_MARK is not set
-# CONFIG_IP_NF_TARGET_CLASSIFY is not set
-# CONFIG_IP_NF_TARGET_TTL is not set
-# CONFIG_IP_NF_TARGET_CONNMARK is not set
-# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
-# CONFIG_IP_NF_RAW is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-
-#
-# IPv6: Netfilter Configuration (EXPERIMENTAL)
-#
-CONFIG_IP6_NF_QUEUE=m
-CONFIG_IP6_NF_IPTABLES=m
-# CONFIG_IP6_NF_MATCH_LIMIT is not set
-CONFIG_IP6_NF_MATCH_MAC=m
-CONFIG_IP6_NF_MATCH_RT=m
-# CONFIG_IP6_NF_MATCH_OPTS is not set
-# CONFIG_IP6_NF_MATCH_FRAG is not set
-# CONFIG_IP6_NF_MATCH_HL is not set
-# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
-# CONFIG_IP6_NF_MATCH_OWNER is not set
-# CONFIG_IP6_NF_MATCH_MARK is not set
-CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-# CONFIG_IP6_NF_MATCH_AHESP is not set
-# CONFIG_IP6_NF_MATCH_LENGTH is not set
-# CONFIG_IP6_NF_MATCH_EUI64 is not set
-# CONFIG_IP6_NF_MATCH_PHYSDEV is not set
-CONFIG_IP6_NF_FILTER=m
-# CONFIG_IP6_NF_TARGET_LOG is not set
-# CONFIG_IP6_NF_TARGET_REJECT is not set
-# CONFIG_IP6_NF_TARGET_NFQUEUE is not set
-CONFIG_IP6_NF_MANGLE=m
-# CONFIG_IP6_NF_TARGET_MARK is not set
-# CONFIG_IP6_NF_TARGET_HL is not set
-CONFIG_IP6_NF_RAW=m
-
-#
-# Bridge: Netfilter Configuration
-#
-CONFIG_BRIDGE_NF_EBTABLES=m
-# CONFIG_BRIDGE_EBT_BROUTE is not set
-# CONFIG_BRIDGE_EBT_T_FILTER is not set
-# CONFIG_BRIDGE_EBT_T_NAT is not set
-# CONFIG_BRIDGE_EBT_802_3 is not set
-# CONFIG_BRIDGE_EBT_AMONG is not set
-# CONFIG_BRIDGE_EBT_ARP is not set
-# CONFIG_BRIDGE_EBT_IP is not set
-# CONFIG_BRIDGE_EBT_LIMIT is not set
-# CONFIG_BRIDGE_EBT_MARK is not set
-# CONFIG_BRIDGE_EBT_PKTTYPE is not set
-# CONFIG_BRIDGE_EBT_STP is not set
-# CONFIG_BRIDGE_EBT_VLAN is not set
-# CONFIG_BRIDGE_EBT_ARPREPLY is not set
-# CONFIG_BRIDGE_EBT_DNAT is not set
-# CONFIG_BRIDGE_EBT_MARK_T is not set
-# CONFIG_BRIDGE_EBT_REDIRECT is not set
-# CONFIG_BRIDGE_EBT_SNAT is not set
-# CONFIG_BRIDGE_EBT_LOG is not set
-# CONFIG_BRIDGE_EBT_ULOG is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM 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_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-CONFIG_IRDA=m
-
-#
-# IrDA protocols
-#
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-CONFIG_IRDA_ULTRA=y
-
-#
-# IrDA options
-#
-CONFIG_IRDA_CACHE_LAST_LSAP=y
-CONFIG_IRDA_FAST_RR=y
-# CONFIG_IRDA_DEBUG is not set
-
-#
-# Infrared-port device drivers
-#
-
-#
-# SIR device drivers
-#
-# CONFIG_IRTTY_SIR is not set
-
-#
-# Dongle support
-#
-
-#
-# Old SIR device drivers
-#
-# CONFIG_IRPORT_SIR is not set
-
-#
-# Old Serial dongle support
-#
-
-#
-# FIR device drivers
-#
-# CONFIG_USB_IRDA is not set
-# CONFIG_SIGMATEL_FIR is not set
-# CONFIG_NSC_FIR is not set
-# CONFIG_WINBOND_FIR is not set
-CONFIG_OMAP1610_IR=m
-CONFIG_SMC_IRCC_FIR=m
-# CONFIG_ALI_FIR is not set
-# CONFIG_VIA_FIR is not set
-CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-# CONFIG_BT_SCO is not set
-CONFIG_BT_RFCOMM=m
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=m
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=m
-
-#
-# Bluetooth device drivers
-#
-# CONFIG_BT_HCIUSB is not set
-CONFIG_BT_HCIUART=m
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-# CONFIG_BT_HCIUART_BCSP_TXCRC is not set
-# CONFIG_BT_HCIBCM203X is not set
-# CONFIG_BT_HCIBPA10X is not set
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIDTL1 is not set
-# CONFIG_BT_HCIBT3C is not set
-# CONFIG_BT_HCIBLUECARD is not set
-# CONFIG_BT_HCIBTUART is not set
-CONFIG_BT_HCIVHCI=m
-CONFIG_BT_H6300=m
-# CONFIG_IEEE80211 is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-# CONFIG_DEBUG_DRIVER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
-# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-# CONFIG_MTD_AFS_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_GEN_PROBE=m
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_NOSWAP=y
-# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_GEOMETRY is not set
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_OTP is not set
-CONFIG_MTD_CFI_INTELEXT=m
-CONFIG_MTD_CFI_AMDSTD=m
-CONFIG_MTD_CFI_AMDSTD_RETRY=1
-CONFIG_MTD_CFI_STAA=m
-CONFIG_MTD_CFI_UTIL=m
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-CONFIG_MTD_ABSENT=m
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
-# CONFIG_MTD_XIP is not set
-
-#
-# Mapping drivers for chip access
-#
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PHYSMAP_START=0x8000000
-CONFIG_MTD_PHYSMAP_LEN=0x4000000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
-# CONFIG_MTD_IMPA7 is not set
-# CONFIG_MTD_OMAP_NOR is not set
-# CONFIG_MTD_PCMCIA is not set
-# CONFIG_MTD_PLATRAM is not set
-
-#
-# Self-contained MTD device drivers
-#
-CONFIG_MTD_SLRAM=m
-CONFIG_MTD_PHRAM=m
-CONFIG_MTD_MTDRAM=m
-CONFIG_MTDRAM_TOTAL_SIZE=4096
-CONFIG_MTDRAM_ERASE_SIZE=128
-CONFIG_MTD_BLKMTD=m
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-CONFIG_MTD_DOC2000=m
-CONFIG_MTD_DOC2001=m
-CONFIG_MTD_DOC2001PLUS=m
-CONFIG_MTD_DOCPROBE=m
-CONFIG_MTD_DOCECC=m
-CONFIG_MTD_DOCPROBE_ADVANCED=y
-CONFIG_MTD_DOCPROBE_ADDRESS=0x0000
-CONFIG_MTD_DOCPROBE_HIGH=y
-CONFIG_MTD_DOCPROBE_55AA=y
-
-#
-# NAND Flash Device Drivers
-#
-CONFIG_MTD_NAND=m
-# CONFIG_MTD_NAND_VERIFY_WRITE is not set
-# CONFIG_MTD_NAND_TOTO is not set
-CONFIG_MTD_NAND_IDS=m
-CONFIG_MTD_NAND_DISKONCHIP=m
-CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
-CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x0
-# CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH is not set
-CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
-# CONFIG_MTD_NAND_NANDSIM is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=m
-# 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=16384
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# PHY device support
-#
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_SMC91X=y
-# CONFIG_DM9000 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-CONFIG_STRIP=y
-# CONFIG_PCMCIA_WAVELAN is not set
-# CONFIG_PCMCIA_NETWAVE is not set
-
-#
-# Wireless 802.11 Frequency Hopping cards support
-#
-# CONFIG_PCMCIA_RAYCS is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_AIRO is not set
-# CONFIG_HERMES is not set
-CONFIG_ATMEL=y
-
-#
-# Wireless 802.11b Pcmcia/Cardbus cards support
-#
-# CONFIG_AIRO_CS is not set
-# CONFIG_PCMCIA_ATMEL is not set
-# CONFIG_PCMCIA_WL3501 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-CONFIG_ACX=m
-# CONFIG_ACX_USB is not set
-CONFIG_ACX_CFI=y
-
-#
-# PCMCIA network device support
-#
-# CONFIG_NET_PCMCIA is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPPOE=y
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-CONFIG_INPUT_TSDEV=y
-CONFIG_INPUT_TSDEV_SCREEN_X=240
-CONFIG_INPUT_TSDEV_SCREEN_Y=320
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-# CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_KEYBOARD_OMAP=m
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-CONFIG_MOUSE_SERIAL=y
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_GUNZE is not set
-# CONFIG_TOUCHSCREEN_ELO is not set
-# CONFIG_TOUCHSCREEN_MTOUCH is not set
-# CONFIG_TOUCHSCREEN_MK712 is not set
-CONFIG_TOUCHSCREEN_OMAP=m
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=m
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-CONFIG_SERIO_LIBPS2=y
-CONFIG_SERIO_RAW=y
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_SERIAL_8250_CS is not set
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-
-#
-# Watchdog Device Drivers
-#
-CONFIG_SOFT_WATCHDOG=m
-
-#
-# USB-based Watchdog Cards
-#
-# CONFIG_USBPCWATCHDOG is not set
-CONFIG_NVRAM=y
-# CONFIG_RTC is not set
-CONFIG_OMAP_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-
-#
-# PCMCIA character devices
-#
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-
-#
-# I2C support
-#
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Algorithms
-#
-CONFIG_I2C_ALGOBIT=m
-CONFIG_I2C_ALGOPCF=m
-CONFIG_I2C_ALGOPCA=m
-
-#
-# I2C Hardware Bus support
-#
-CONFIG_I2C_PARPORT_LIGHT=m
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_PCA_ISA is not set
-CONFIG_I2C_OMAP=m
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-CONFIG_PCA9535=m
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_TPS65010 is not set
-CONFIG_SENSORS_TLV320AIC23=m
-# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
-# Hardware Monitoring support
-#
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
-CONFIG_FB_SOFT_CURSOR=y
-# CONFIG_FB_MACMODES is not set
-CONFIG_FB_MODE_HELPERS=y
-# CONFIG_FB_TILEBLITTING is not set
-# CONFIG_FB_S1D13XXX is not set
-CONFIG_FB_OMAP=y
-CONFIG_FB_OMAP_LCDC_INTERNAL=y
-# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
-CONFIG_FB_OMAP_DMA_TUNE=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_7x14 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-CONFIG_FONT_MINI_4x6=y
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-# CONFIG_FONT_10x18 is not set
-
-#
-# Logo configuration
-#
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-CONFIG_LOGO_LINUX_VGA16=y
-# CONFIG_LOGO_LINUX_CLUT224 is not set
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_DEVICE=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_LCD_DEVICE=y
-
-#
-# Telephony Support
-#
-CONFIG_PHONE=m
-# CONFIG_PHONE_IXJ is not set
-CONFIG_GSM_H6300=m
-
-#
-# Sound
-#
-CONFIG_SOUND=m
-
-#
-# Advanced Linux Sound Architecture
-#
-# CONFIG_SND is not set
-
-#
-# Open Sound System
-#
-CONFIG_SOUND_PRIME=m
-CONFIG_SOUND_OMAP=m
-CONFIG_SOUND_OMAP_TSC2101=m
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_TVMIXER is not set
-# CONFIG_SOUND_AD1980 is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_OTG is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-# CONFIG_USB_SL811_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-
-#
-# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
-#
-CONFIG_USB_ACM=y
-# CONFIG_USB_PRINTER is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-# CONFIG_USB_STORAGE is not set
-
-#
-# USB Input Devices
-#
-# CONFIG_USB_HID is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-CONFIG_USB_USBNET=y
-CONFIG_USB_NET_AX8817X=y
-CONFIG_USB_NET_CDCETHER=y
-# CONFIG_USB_NET_GL620A is not set
-CONFIG_USB_NET_NET1080=y
-# CONFIG_USB_NET_PLUSB is not set
-# CONFIG_USB_NET_RNDIS_HOST is not set
-# CONFIG_USB_NET_CDC_SUBSET is not set
-CONFIG_USB_NET_ZAURUS=y
-# CONFIG_USB_ZD1201 is not set
-CONFIG_USB_MON=y
-
-#
-# USB port drivers
-#
-
-#
-# USB Serial Converter support
-#
-CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_CONSOLE=y
-CONFIG_USB_SERIAL_GENERIC=y
-# CONFIG_USB_SERIAL_AIRPRIME is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_CP2101 is not set
-# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-CONFIG_USB_SERIAL_VISOR=y
-CONFIG_USB_SERIAL_IPAQ=y
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-# CONFIG_USB_SERIAL_GARMIN is not set
-# CONFIG_USB_SERIAL_IPW is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_HP4X is not set
-# CONFIG_USB_SERIAL_SAFE is not set
-# CONFIG_USB_SERIAL_TI is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OPTION is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_SELECTED=y
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_PXA2XX is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-CONFIG_USB_GADGET_OMAP=y
-CONFIG_USB_OMAP=y
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_GADGET_DUALSPEED is not set
-# CONFIG_USB_ZERO is not set
-CONFIG_USB_ETH=y
-# CONFIG_USB_ETH_RNDIS is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
-
-#
-# MMC/SD Card support
-#
-CONFIG_MMC=y
-# CONFIG_MMC_DEBUG is not set
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_BLOCK_BROKEN_RFD=y
-CONFIG_MMC_BULKTRANSFER=y
-CONFIG_MMC_OMAP=y
-# CONFIG_MMC_WBSD is not set
-
-#
-# Synchronous Serial Interfaces (SSI)
-#
-CONFIG_OMAP_UWIRE=y
-CONFIG_OMAP_TSC2101=y
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-# CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_ROMFS_FS=y
-CONFIG_INOTIFY=y
-# CONFIG_QUOTA is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=y
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=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_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_JFFS_FS=y
-CONFIG_JFFS_FS_VERBOSE=0
-CONFIG_JFFS_PROC_FS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=4
-CONFIG_JFFS2_FS_WRITEBUFFER=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_RTIME=y
-CONFIG_JFFS2_RUBIN=y
-# CONFIG_JFFS2_CMODE_NONE is not set
-CONFIG_JFFS2_CMODE_PRIORITY=y
-# CONFIG_JFFS2_CMODE_SIZE is not set
-CONFIG_CRAMFS=y
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-CONFIG_NFS_V4=y
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION 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_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="utf8"
-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
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_LOG_BUF_SHIFT=17
-CONFIG_DETECT_SOFTLOCKUP=y
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
-CONFIG_FRAME_POINTER=y
-# CONFIG_DEBUG_USER is not set
-# CONFIG_DEBUG_WAITQ is not set
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_HMAC=y
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=y
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-CONFIG_CRYPTO_DEFLATE=m
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-CONFIG_CRC_CCITT=y
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-CONFIG_LIBCRC32C=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_REED_SOLOMON=m
-CONFIG_REED_SOLOMON_DEC16=y
+++ /dev/null
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/Kconfig bt_kernel/arch/arm/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/Kconfig 2005-10-30 17:44:14.719521158 +0200
-+++ bt_kernel/arch/arm/Kconfig 2005-10-14 18:55:31.156317000 +0300
-@@ -725,6 +725,8 @@
-
- source "drivers/video/Kconfig"
-
-+source "drivers/telephony/Kconfig"
-+
- source "sound/Kconfig"
-
- source "drivers/usb/Kconfig"
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap1/board-h6300.c bt_kernel/arch/arm/mach-omap1/board-h6300.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap1/board-h6300.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/arch/arm/mach-omap1/board-h6300.c 2005-10-22 03:52:45.687256000 +0300
-@@ -0,0 +1,317 @@
-+/*
-+ * Modified from board-h6300.c
-+ *
-+ * Code for generic OMAP board. Should work on many OMAP systems where
-+ * the device drivers take care of all the necessary hardware initialization.
-+ * Do not put any board specific code to this file; create a new machine
-+ * type if you need custom low-level initializations.
-+ *
-+ * 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/device.h>
-+#include <linux/delay.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include <asm/mach/arch.h>
-+#include <asm/mach/flash.h>
-+#include <asm/mach/map.h>
-+
-+#include <asm/arch/gpio.h>
-+
-+#include <asm/arch/tc.h>
-+#include <asm/arch/usb.h>
-+
-+#include <asm/arch/common.h>
-+
-+#include <asm/arch/h6300_uart_info.h>
-+
-+/*
-+ * Bluetooth - Relies on h6300_bt module,
-+ * so make the calls indirectly through pointers. Requires that the
-+ * h6300_bt bluetooth module be loaded before any attempt to use
-+ * bluetooth (obviously).
-+ */
-+
-+static struct h6300_uart_funcs bt_funcs;
-+static struct h6300_uart_funcs gsm_funcs;
-+
-+static void
-+h6300_bt_configure(struct uart_omap_port *up, int enable)
-+{
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_configure() started\n");
-+ if (bt_funcs.configure != NULL)
-+ bt_funcs.configure(up, enable);
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_configure() done\n");
-+}
-+
-+static void
-+h6300_bt_set_txrx(struct uart_omap_port *up, int txrx)
-+{
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx() started\n");
-+ if (bt_funcs.set_txrx != NULL)
-+ {
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx(), bt_funcs.set_txrx != NULL\n");
-+ bt_funcs.set_txrx(up, txrx);
-+ }
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx() done\n");
-+}
-+
-+static int
-+h6300_bt_get_txrx(struct uart_omap_port *up)
-+{
-+ int retVal;
-+
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx() started\n");
-+ if (bt_funcs.get_txrx != NULL)
-+ {
-+ retVal = bt_funcs.get_txrx(up);
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx(), bt_funcs.get_trx != null, done, retVal %d\n", retVal);
-+ return retVal;
-+ }
-+ else
-+ {
-+ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx() done, returning 0\n");
-+ return 0;
-+ }
-+}
-+
-+static struct platform_omap_serial_funcs h6300_omap_bt_funcs = {
-+ .configure = h6300_bt_configure,
-+ .set_txrx = h6300_bt_set_txrx,
-+ .get_txrx = h6300_bt_get_txrx,
-+};
-+
-+struct platform_device btuart_device = {
-+ .name = "h6300_bt",
-+ .id = 1,
-+};
-+EXPORT_SYMBOL(btuart_device);
-+
-+static void
-+h6300_gsm_configure(struct uart_omap_port *up, int enable)
-+{
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_configure() started\n");
-+ if (gsm_funcs.configure != NULL)
-+ gsm_funcs.configure(up, enable);
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_configure() done\n");
-+}
-+
-+static void
-+h6300_gsm_set_txrx(struct uart_omap_port *up, int txrx)
-+{
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx() started\n");
-+ if (bt_funcs.set_txrx != NULL)
-+ {
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx(), bt_funcs.set_txrx != NULL\n");
-+ gsm_funcs.set_txrx(up, txrx);
-+ }
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx() done\n");
-+}
-+
-+static int
-+h6300_gsm_get_txrx(struct uart_omap_port *up)
-+{
-+ int retVal;
-+
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx() started\n");
-+ if (bt_funcs.get_txrx != NULL)
-+ {
-+ retVal = gsm_funcs.get_txrx(up);
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx(), bt_funcs.get_trx != null, done, retVal %d\n", retVal);
-+ return retVal;
-+ }
-+ else
-+ {
-+ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx() done, returning 0\n");
-+ return 0;
-+ }
-+}
-+
-+static struct platform_omap_serial_funcs h6300_omap_gsm_funcs = {
-+ .configure = h6300_gsm_configure,
-+ .set_txrx = h6300_gsm_set_txrx,
-+ .get_txrx = h6300_gsm_get_txrx,
-+};
-+
-+struct platform_device gsmuart_device = {
-+ .name = "h6300_gsm",
-+ .id = 1,
-+};
-+EXPORT_SYMBOL(gsmuart_device);
-+
-+#if 0
-+static struct mtd_partition h6300_partitions[] = {
-+ /* bootloader (U-Boot, etc) in first sector */
-+ {
-+ .name = "bootloader",
-+ .offset = 0,
-+ .size = SZ_128K,
-+ .mask_flags = MTD_WRITEABLE, /* force read-only */
-+ },
-+ /* bootloader params in the next sector */
-+ {
-+ .name = "params",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = SZ_128K,
-+ .mask_flags = 0,
-+ },
-+ /* kernel */
-+ {
-+ .name = "kernel",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = SZ_2M,
-+ .mask_flags = 0
-+ },
-+ /* rest of flash1 is a file system */
-+ {
-+ .name = "rootfs",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = SZ_16M - SZ_2M - 2 * SZ_128K,
-+ .mask_flags = 0
-+ },
-+ /* file system */
-+ {
-+ .name = "filesystem",
-+ .offset = MTDPART_OFS_APPEND,
-+ .size = MTDPART_SIZ_FULL,
-+ .mask_flags = 0
-+ }
-+};
-+
-+static struct flash_platform_data h6300_flash_data = {
-+ .map_name = "cfi_probe",
-+ .width = 2,
-+ .parts = h6300_partitions,
-+ .nr_parts = ARRAY_SIZE(h6300_partitions),
-+};
-+
-+static struct resource h6300_flash_resource = {
-+ .start = OMAP_CS0_PHYS,
-+ .end = OMAP_CS0_PHYS + SZ_32M - 1,
-+ .flags = IORESOURCE_MEM,
-+};
-+
-+static struct platform_device h6300_flash_device = {
-+ .name = "omapflash",
-+ .id = 0,
-+ .dev = {
-+ .platform_data = &h6300_flash_data,
-+ },
-+ .num_resources = 1,
-+ .resource = &h6300_flash_resource,
-+};
-+#endif
-+
-+static struct resource h6300_wlan_resource[] = {
-+ [0] = {
-+ .start = OMAP_CS1_PHYS,
-+ .end = OMAP_CS1_PHYS + SZ_32M -1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+
-+ [1] = {
-+ .start = OMAP_GPIO_IRQ(11),
-+ .end = OMAP_GPIO_IRQ(11),
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static struct platform_device h6300_wlan_device = {
-+ .name = "tnetw1100b",
-+ .id = 0,
-+ .num_resources = 2,
-+ .resource = h6300_wlan_resource,
-+};
-+
-+static struct platform_device *h6300_devices[] __initdata = {
-+ &btuart_device,
-+ &gsmuart_device,
-+ &h6300_wlan_device,
-+ //&h6300_flash_device,
-+};
-+
-+static void __init h6300_init_irq(void)
-+{
-+ omap_init_irq();
-+ omap_gpio_init();
-+
-+ omap_request_gpio (2);
-+ omap_set_gpio_direction (2, 0);
-+ omap_set_gpio_dataout (2, 1);
-+}
-+
-+/* assume no Mini-AB port */
-+
-+static struct omap_usb_config h6300_usb_config __initdata = {
-+ .hmc_mode = 0,
-+ .register_dev = 1,
-+ .pins[0] = 0,
-+};
-+
-+static struct omap_lcd_config h6300_lcd_config __initdata = {
-+ .panel_name = "h6300",
-+ .ctrl_name = "internal",
-+};
-+
-+static struct omap_mmc_config h6300_mmc_config __initdata = {
-+ .mmc [0] = {
-+ .enabled = 1,
-+ .wire4 = 1,
-+ .wp_pin = OMAP_GPIO_IRQ(13),
-+ .power_pin = -1, /* FPGA F3 UIO42 */
-+ .switch_pin = -1, /* FPGA F4 UIO43 */
-+ },
-+};
-+
-+static struct omap_uart_config h6300_uart_config __initdata = {
-+ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
-+};
-+
-+static struct omap_board_config_kernel h6300_config[] = {
-+ { OMAP_TAG_USB, &h6300_usb_config },
-+ { OMAP_TAG_MMC, &h6300_mmc_config },
-+ { OMAP_TAG_UART, &h6300_uart_config },
-+ { OMAP_TAG_LCD, &h6300_lcd_config },
-+};
-+
-+static void __init h6300_init(void)
-+{
-+ int ret;
-+
-+ ret = platform_add_devices(h6300_devices, ARRAY_SIZE(h6300_devices));
-+ if (ret)
-+ {
-+ printk(KERN_WARNING "Unable to add h6300 platform devices like bluetooth");
-+ }
-+ omap_board_config = h6300_config;
-+ omap_board_config_size = ARRAY_SIZE(h6300_config);
-+ omap_serial_init();
-+}
-+
-+static void __init h6300_map_io(void)
-+{
-+ omap_map_common_io();
-+
-+ btuart_device.dev.platform_data = &h6300_omap_bt_funcs;
-+ gsmuart_device.dev.platform_data = &h6300_omap_gsm_funcs;
-+}
-+
-+MACHINE_START(H6300, "HP iPAQ H6300")
-+ /* MAINTAINER("Everett Coleman II <gcc80x86@fuzzyneural.net>") */
-+ .phys_ram = 0x10000000,
-+ .phys_io = 0xfff00000,
-+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
-+ .boot_params = 0x10000100,
-+ .map_io = h6300_map_io,
-+ .init_irq = h6300_init_irq,
-+ .init_machine = h6300_init,
-+ .timer = &omap_timer,
-+MACHINE_END
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap1/Kconfig bt_kernel/arch/arm/mach-omap1/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap1/Kconfig 2005-10-30 17:44:15.310427101 +0200
-+++ bt_kernel/arch/arm/mach-omap1/Kconfig 2005-10-22 03:52:45.687256000 +0300
-@@ -26,6 +26,12 @@
- TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
- have such a board.
-
-+config MACH_OMAP_H6300
-+ bool "HP IPaq H6300"
-+ depends on ARCH_OMAP1 && ARCH_OMAP15XX
-+ help
-+ HP IPaq H6300 series.
-+
- config MACH_OMAP_H2
- bool "TI H2 Support"
- depends on ARCH_OMAP1 && ARCH_OMAP16XX
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap1/Makefile bt_kernel/arch/arm/mach-omap1/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap1/Makefile 2005-10-30 17:44:15.334423281 +0200
-+++ bt_kernel/arch/arm/mach-omap1/Makefile 2005-10-22 03:52:45.687256000 +0300
-@@ -15,7 +15,8 @@
- obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
- obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
- obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
--obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
-+obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
-+obj-$(CONFIG_MACH_OMAP_H6300) += board-h6300.o
-
- ifeq ($(CONFIG_ARCH_OMAP15XX),y)
- # Innovator-1510 FPGA
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap2/clock.h bt_kernel/arch/arm/mach-omap2/clock.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/mach-omap2/clock.h 2005-10-30 17:44:15.870337978 +0200
-+++ bt_kernel/arch/arm/mach-omap2/clock.h 2005-10-30 16:32:39.609796000 +0200
-@@ -1469,7 +1469,7 @@
- .parent = &l4_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .enable_reg = (void __iomem *)&CM_ICLKEN2_CORE,
-- .enable_bit = 3,
-+ .enable_bit = 2,
- .recalc = &omap2_followparent_recalc,
- };
-
-@@ -1478,7 +1478,7 @@
- .parent = &func_48m_ck,
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .enable_reg = (void __iomem *)&CM_FCLKEN2_CORE,
-- .enable_bit = 3,
-+ .enable_bit = 2,
- .recalc = &omap2_followparent_recalc,
- };
-
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/plat-omap/devices.c bt_kernel/arch/arm/plat-omap/devices.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/plat-omap/devices.c 2005-10-30 17:44:16.144294371 +0200
-+++ bt_kernel/arch/arm/plat-omap/devices.c 2005-10-22 03:52:45.687256000 +0300
-@@ -93,6 +93,9 @@
- (void) platform_device_register(&omap_i2c_device1);
- }
-
-+#else
-+static inline void omap_init_i2c(void) {}
-+
- #endif
-
- /*-------------------------------------------------------------------------*/
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/plat-omap/dma.c bt_kernel/arch/arm/plat-omap/dma.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/plat-omap/dma.c 2005-10-30 17:44:16.167290711 +0200
-+++ bt_kernel/arch/arm/plat-omap/dma.c 2005-10-30 16:32:39.609796000 +0200
-@@ -28,6 +28,7 @@
- #include <asm/hardware.h>
- #include <asm/dma.h>
- #include <asm/io.h>
-+#include <asm/mach-types.h>
-
- #include <asm/arch/tc.h>
-
-@@ -121,7 +122,8 @@
- }
-
- void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
-- int frame_count, int sync_mode)
-+ int frame_count, int sync_mode,
-+ int dma_trigger, int src_or_dst_synch)
- {
- u16 w;
-
-@@ -179,7 +181,8 @@
-
-
- void omap_set_dma_src_params(int lch, int src_port, int src_amode,
-- unsigned long src_start)
-+ unsigned long src_start,
-+ int src_ei, int src_fi)
- {
- u16 w;
-
-@@ -221,7 +224,14 @@
- case OMAP_DMA_DATA_BURST_DIS:
- break;
- case OMAP_DMA_DATA_BURST_4:
-- w |= (0x01 << 7);
-+ if (machine_is_h6300())
-+ {
-+ w |= (0x01 << 7);
-+ }
-+ else
-+ {
-+ w |= (0x02 << 7);
-+ }
- break;
- case OMAP_DMA_DATA_BURST_8:
- /* not supported by current hardware
-@@ -235,7 +245,8 @@
- }
-
- void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
-- unsigned long dest_start)
-+ unsigned long dest_start,
-+ int dst_ei, int dst_fi)
- {
- u16 w;
-
-@@ -277,7 +288,14 @@
- case OMAP_DMA_DATA_BURST_DIS:
- break;
- case OMAP_DMA_DATA_BURST_4:
-- w |= (0x01 << 14);
-+ if (machine_is_h6300())
-+ {
-+ w |= (0x01 << 14);
-+ }
-+ else
-+ {
-+ w |= (0x02 << 14);
-+ }
- break;
- case OMAP_DMA_DATA_BURST_8:
- w |= (0x03 << 14);
-@@ -769,6 +787,10 @@
- }
-
- if (omap_dma_in_1510_mode()) {
-+ u16 l = omap_readw(OMAP1510_DMA_LCD_CTRL);
-+ l &= ~(1 << 6);
-+ omap_writew (l, OMAP1510_DMA_LCD_CTRL);
-+
- omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
- omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
- omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/plat-omap/mcbsp.c bt_kernel/arch/arm/plat-omap/mcbsp.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/plat-omap/mcbsp.c 2005-10-30 17:44:16.477241375 +0200
-+++ bt_kernel/arch/arm/plat-omap/mcbsp.c 2005-10-30 16:32:39.609796000 +0200
-@@ -493,17 +493,20 @@
- omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
- OMAP_DMA_DATA_TYPE_S16,
- length >> 1, 1,
-- OMAP_DMA_SYNC_ELEMENT);
-+ OMAP_DMA_SYNC_ELEMENT,
-+ 0, 0);
-
- omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
-- mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1);
-+ mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1,
-+ 0, 0);
-
- omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
- OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC,
-- buffer);
-+ buffer,
-+ 0, 0);
-
- omap_start_dma(mcbsp[id].dma_tx_lch);
- wait_for_completion(&(mcbsp[id].tx_dma_completion));
-@@ -533,17 +536,20 @@
- omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
- OMAP_DMA_DATA_TYPE_S16,
- length >> 1, 1,
-- OMAP_DMA_SYNC_ELEMENT);
-+ OMAP_DMA_SYNC_ELEMENT,
-+ 0, 0);
-
- omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
-- mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1);
-+ mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1,
-+ 0, 0);
-
- omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
- OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC,
-- buffer);
-+ buffer,
-+ 0, 0);
-
- omap_start_dma(mcbsp[id].dma_rx_lch);
- wait_for_completion(&(mcbsp[id].rx_dma_completion));
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/tools/mach-types bt_kernel/arch/arm/tools/mach-types
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/arch/arm/tools/mach-types 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/arch/arm/tools/mach-types 2005-10-22 03:52:45.687256000 +0300
-@@ -576,7 +576,7 @@
- s3c2460 MACH_S3C2460 S3C2460 560
- pdm MACH_PDM PDM 561
- h4700 MACH_H4700 H4700 562
--h6300 MACH_H6300 H6300 563
-+h6300 MACH_OMAP_H6300 H6300 563
- rz1700 MACH_RZ1700 RZ1700 564
- a716 MACH_A716 A716 565
- estk2440a MACH_ESTK2440A ESTK2440A 566
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/Kconfig bt_kernel/drivers/bluetooth/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/Kconfig 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/bluetooth/Kconfig 2005-10-04 00:58:34.589442000 +0300
-@@ -163,6 +163,16 @@
-
- Say Y here to compile support for virtual HCI devices into the
- kernel or say M to compile it as module (hci_vhci).
-+
-+config BT_H6300
-+ tristate "H6300 BRF6100 BT DRIVER"
-+ help
-+ Bluetooth H6300 BRF6100 driver.
-+ This driver provides the firmware loading mechanism for the BRF6100
-+ bt hardware in iPAQ h6300.
-+
-+ Say Y here to compile support for BRF6100 BT devices into the
-+ kernel or say M to compile it as module (h6300_BT).
-
- endmenu
-
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/Makefile bt_kernel/drivers/bluetooth/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/Makefile 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/bluetooth/Makefile 2005-09-28 01:04:13.052737000 +0300
-@@ -10,10 +10,11 @@
- obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o
- obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
- obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
--obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
-+obj-$(CONFIG_BT_HCIBLUECARD)+= bluecard_cs.o
- obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
-+obj-$(CONFIG_BT_H6300) += omap/
-
--hci_uart-y := hci_ldisc.o
-+hci_uart-y := hci_ldisc.o
- hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
- hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
--hci_uart-objs := $(hci_uart-y)
-+hci_uart-objs := $(hci_uart-y)
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/h6300_bt_brf6100.c bt_kernel/drivers/bluetooth/omap/h6300_bt_brf6100.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/h6300_bt_brf6100.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/bluetooth/omap/h6300_bt_brf6100.c 2005-10-06 02:34:39.057478000 +0300
-@@ -0,0 +1,153 @@
-+/*
-+ * Bluetooth interface driver for TI BRF6100 on h6300
-+ *
-+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
-+ * Ideas taken from the brf6150 bt driver made by Todd Blumer for the pxa hx4700.
-+ *
-+ * 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/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/arch/gpio.h>
-+
-+#include <asm/arch/h6300_uart_info.h>
-+#include "h6300_bt_led.h"
-+
-+static void
-+h6300_bt_configure(struct uart_omap_port *up, int enable)
-+{
-+ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_configure() started, enable = %d\n", enable);
-+
-+ // printk( KERN_NOTICE "h6300 configure bluetooth: %d\n", enable );
-+ if (enable == 0) {
-+ omap_set_gpio_dataout(GPIO_N_BT_RST, 0); // turn off gpio
-+ mdelay(5);
-+ h6300_clear_led(INDEX_BT_LED);
-+ }
-+ else if (enable == 1) {
-+ omap_set_gpio_dataout(GPIO_N_BT_RST, 1); // turn on gpio
-+ mdelay(5);
-+ }
-+ else if (enable == 2) {
-+ /*
-+ * BRF6150's RTS goes low when firmware is ready
-+ * so check for CTS=1 (nCTS=0 -> CTS=1). Typical 150ms
-+ */
-+/*
-+ int tries = 0;
-+ do
-+ {
-+ mdelay(10);
-+ }
-+ while ((BTMSR & MSR_CTS) == 0 && tries++ < 50);
-+*/
-+ h6300_set_led(INDEX_BT_LED, 16, 16);
-+ }
-+ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_configure() done\n");
-+}
-+
-+static void
-+h6300_bt_set_txrx(struct uart_omap_port *up, int txrx)
-+{
-+ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_set_txrx(), txrx = %d done\n", txrx);
-+ /* do nothing */
-+}
-+
-+static int
-+h6300_bt_get_txrx(struct uart_omap_port *up)
-+{
-+ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_get_txrx() done\n");
-+ /* do nothing */
-+ return 0;
-+}
-+
-+static int
-+h6300_bt_probe(struct device *dev)
-+{
-+ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
-+
-+ omap_request_gpio(GPIO_BT_PWR_EN); // ask bt_power_en gpio, remember to release in remove_function
-+ omap_set_gpio_direction(GPIO_BT_PWR_EN, 1); // set gpio direction to be output
-+ omap_set_gpio_dataout(GPIO_BT_PWR_EN, 1); // turn on gpio
-+
-+ mdelay(200);
-+
-+ omap_request_gpio(GPIO_N_BT_RST); // ask bt_reset gpio, remember to release in remove_function
-+ omap_set_gpio_direction(GPIO_N_BT_RST, 1); // set gpio direction to be output
-+ omap_set_gpio_dataout(GPIO_N_BT_RST, 1); // turn on gpio
-+
-+ /* configure bluetooth UART */
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_RXD_MD);
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_TXD_MD);
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_CTS_MD);
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_RTS_MD);
-+
-+ funcs->configure = h6300_bt_configure;
-+ funcs->set_txrx = h6300_bt_set_txrx;
-+ funcs->get_txrx = h6300_bt_get_txrx;
-+
-+ /* Make sure the LED is off */
-+ h6300_clear_led(INDEX_BT_LED);
-+
-+ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_probe() done\n");
-+
-+ return 0;
-+}
-+
-+static int
-+h6300_bt_remove(struct device *dev)
-+{
-+ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
-+
-+ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_remove() started\n");
-+
-+ omap_free_gpio(GPIO_BT_PWR_EN);
-+ omap_free_gpio(GPIO_N_BT_RST);
-+
-+ funcs->configure = NULL;
-+ funcs->set_txrx = NULL;
-+ funcs->get_txrx = NULL;
-+
-+ /* Make sure the LED is off */
-+ h6300_clear_led(INDEX_BT_LED);
-+
-+ printk(KERN_NOTICE "h6300_bt_brf6100.c, h6300_bt_remove() done\n");
-+
-+ return 0;
-+}
-+
-+static struct device_driver bt_driver = {
-+ .name = "h6300_bt",
-+ .bus = &platform_bus_type,
-+ .probe = h6300_bt_probe,
-+ .remove = h6300_bt_remove,
-+};
-+
-+static int __init
-+h6300_bt_init(void)
-+{
-+ printk(KERN_NOTICE "h6300 Bluetooth Driver init()\n");
-+ return driver_register(&bt_driver);
-+}
-+
-+static void __exit
-+h6300_bt_exit(void)
-+{
-+ printk(KERN_NOTICE "h6300 Bluetooth Driver exit()\n");
-+ driver_unregister(&bt_driver);
-+}
-+
-+module_init(h6300_bt_init);
-+module_exit(h6300_bt_exit);
-+
-+MODULE_AUTHOR("Mika Laitio, <lamikr@cc.jyu.fi>");
-+MODULE_DESCRIPTION("iPAQ h6300 BRF6100 Bluetooth driver.");
-+MODULE_LICENSE("GPL");
-+
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/h6300_bt_led.c bt_kernel/drivers/bluetooth/omap/h6300_bt_led.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/h6300_bt_led.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/bluetooth/omap/h6300_bt_led.c 2005-10-06 02:34:39.057478000 +0300
-@@ -0,0 +1,41 @@
-+/*
-+ * Bluetooth interface driver helper for controlling bluetooth leds available in iPAQ h6300.
-+ *
-+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
-+ * Ideas from the brf6150 bt driver made by Todd Blumer for the pxa hx4700.
-+ *
-+ * 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/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/arch/gpio.h>
-+
-+/*
-+ * Low level access for disabling h6300 bt led.
-+ *
-+ * TODO: implement for h6300
-+ */
-+void h6300_clear_led(int led_num)
-+{
-+ printk(KERN_NOTICE "h6300_bt_led.c h6300_clear_led() done\n");
-+ //hx4700_set_led(led_num, 0, 16);
-+}
-+EXPORT_SYMBOL(h6300_clear_led);
-+
-+/*
-+ * Low level access for setting up the bt led.
-+ *
-+ * TODO: implement for h6300
-+ */
-+void h6300_set_led(int led_num, int duty_time, int cycle_time)
-+{
-+ printk(KERN_NOTICE "h6300_bt_led.c h6300_set_led() done\n");
-+}
-+EXPORT_SYMBOL(h6300_set_led);
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/h6300_bt_led.h bt_kernel/drivers/bluetooth/omap/h6300_bt_led.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/h6300_bt_led.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/bluetooth/omap/h6300_bt_led.h 2005-10-06 02:34:39.057478000 +0300
-@@ -0,0 +1,9 @@
-+#ifndef H6300_BT_LED_H_
-+#define H6300_BT_LED_H_
-+
-+#define INDEX_BT_LED 2
-+
-+void h6300_clear_led(int led_num);
-+void h6300_set_led(int led_num, int duty_time, int cycle_time);
-+
-+#endif /*H6300_BT_LED_H_*/
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/Makefile bt_kernel/drivers/bluetooth/omap/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/bluetooth/omap/Makefile 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/bluetooth/omap/Makefile 2005-10-06 02:34:39.057478000 +0300
-@@ -0,0 +1,6 @@
-+#
-+# Makefile for the Linux iPAQ H6300 BRF6100 Bluetooth device drivers.
-+#
-+
-+h6300_bt-objs := h6300_bt_led.o h6300_bt_brf6100.o
-+obj-$(CONFIG_BT_H6300) += h6300_bt.o
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/char/.gitignore bt_kernel/drivers/char/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/char/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/char/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,3 +0,0 @@
--consolemap_deftbl.c
--defkeymap.c
--
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/keyboard/omap-keypad.c bt_kernel/drivers/input/keyboard/omap-keypad.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/keyboard/omap-keypad.c 2005-10-30 17:44:17.444087478 +0200
-+++ bt_kernel/drivers/input/keyboard/omap-keypad.c 2005-10-30 16:34:01.215220000 +0200
-@@ -5,10 +5,11 @@
- *
- * Copyright (C) 2003 Nokia Corporation
- * Written by Timo Teräs <ext-timo.teras@nokia.com>
-+ * iPAQ h6300 key and joypad support added by Mika Laitio. (2005)
- *
- * Added support for H2 & H3 Keypad
- * Copyright (C) 2004 Texas Instruments
-- *
-+ *
- * 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
-@@ -40,6 +41,7 @@
- #include <asm/arch/mux.h>
-
- #undef NEW_BOARD_LEARNING_MODE
-+//#define NEW_BOARD_LEARNING_MODE 1
-
- static void omap_kp_tasklet(unsigned long);
- static void omap_kp_timer(unsigned long);
-@@ -48,6 +50,8 @@
- static unsigned char keypad_state[8];
- static unsigned int keypad_irq = INT_KEYBOARD;
-
-+static int prevJoypadKeycodePressEmulated;
-+
- static struct timer_list kp_timer;
- DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
-
-@@ -165,6 +169,47 @@
- 0
- };
-
-+#define _h6300_KEY_CALENDAR 67 // xmodmap 75 aka F9
-+#define _H6300_KEY_TELEPHONE 68 // xmodmap 76 aka F10
-+#define _H6300_KEY_HOMEPAGE 87 // xmodmap 87 aka Num_Lock
-+#define _H6300_KEY_MAIL 88 // xmodmap 88 aka Scroll_Lock
-+
-+/*
-+ * Following 5 keypad events are not really sent to userspace.
-+ * Instead if the good combination of them is sent, then that is send.
-+ * (up, right, down, left, enter)
-+ */
-+#define _H6300_JOYPAD_UP_RIGHT 1 // 00001
-+#define _H6300_JOYPAD_DOWN_RIGHT 2 // 00010
-+#define _h6300_JOYPAD_DOWN_LEFT 4 // 00100
-+#define _h6300_JOYPAD_UP_LEFT 8 // 01000
-+#define _H6300_JOYPAD_KEY_OK 16 // 10000
-+
-+static int h6300_keymap[] = {
-+ KEY(2, 0, _h6300_KEY_CALENDAR), // address button in the bottom left
-+ KEY(2, 3, _H6300_KEY_TELEPHONE), // start call button in the bottom
-+ KEY(3, 1, _H6300_KEY_HOMEPAGE), // stop call button in the bottom
-+ KEY(3, 4, _H6300_KEY_MAIL), // messaging button in the bottom right
-+
-+ KEY(0, 0, KEY_VOLUMEUP), // volume up button in the right side
-+ KEY(0, 1, KEY_VOLUMEDOWN), // volume down button in the right side
-+ KEY(3, 2, KEY_RECORD), // record button in the left side
-+
-+ KEY(1, 0, _h6300_JOYPAD_UP_LEFT),
-+ KEY(1, 1, _h6300_JOYPAD_DOWN_LEFT),
-+ KEY(1, 2, _H6300_JOYPAD_KEY_OK),
-+ KEY(1, 3, _H6300_JOYPAD_DOWN_RIGHT),
-+ KEY(1, 4, _H6300_JOYPAD_UP_RIGHT),
-+
-+ KEY(5, 0, KEY_RIGHT),
-+ KEY(5, 1, KEY_DOWN),
-+ KEY(5, 2, KEY_LEFT),
-+ KEY(5, 3, KEY_UP),
-+ KEY(5, 4, KEY_ENTER),
-+
-+ 0
-+};
-+
- static int *keymap;
-
- static irqreturn_t omap_kp_interrupt(int irq, void *dev_id,
-@@ -191,7 +236,8 @@
- for (col = 0; col < 8; col++) {
- omap_writew(~(1 << col) & 0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
-
-- if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3()) {
-+ if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3() || machine_is_h6300()) {
-+ // makes keyboard act a little bit slower
- udelay(9);
- } else {
- udelay(4);
-@@ -214,16 +260,24 @@
- return -1;
- }
-
-+int is_key_down(unsigned char new_state[],
-+ int col,
-+ int row)
-+{
-+ return (new_state[col] & (1 << row)) ? 1 : 0;
-+}
-+
- static void omap_kp_tasklet(unsigned long data)
- {
- unsigned char new_state[8], changed, key_down = 0;
- int col, row;
- int spurious = 0;
-+ int report_key, report_col, report_row, joypad_checked; // joypad specific variables
-
- /* check for any changes */
- omap_kp_scan_keypad(new_state);
--
- /* check for changes and print those */
-+ joypad_checked = 0;
- for (col = 0; col < 8; col++) {
- changed = new_state[col] ^ keypad_state[col];
- key_down |= new_state[col];
-@@ -245,9 +299,173 @@
- spurious = 1;
- continue;
- }
--
-- input_report_key(&omap_kp_dev, key,
-- new_state[col] & (1 << row));
-+ if (machine_is_h6300() &&
-+ ((col == 1) || (col == 5)))
-+ {
-+ if (col == 5)
-+ {
-+ continue;
-+ }
-+ if ((joypad_checked == 0) &&
-+ ((key == _H6300_JOYPAD_KEY_OK) ||
-+ (key == _h6300_JOYPAD_UP_LEFT) ||
-+ (key == _H6300_JOYPAD_UP_RIGHT) ||
-+ (key == _H6300_JOYPAD_DOWN_RIGHT) ||
-+ (key == _h6300_JOYPAD_DOWN_LEFT)))
-+ {
-+ if (is_key_down(new_state, col, row))
-+ {
-+ /*
-+ * only enter pressed
-+ * 1 0 0 _H6300_JOYPAD_KEY_OK 0 0
-+ * --> 100100 == 36
-+ */
-+ if (new_state[1] == 36)
-+ {
-+ joypad_checked = 1;
-+ prevJoypadKeycodePressEmulated = KEY_ENTER;
-+ new_state[5] = 48; //110000
-+ report_key = prevJoypadKeycodePressEmulated;
-+ report_col = 5;
-+ report_row = 4;
-+ input_report_key(&omap_kp_dev,
-+ report_key,
-+ new_state[report_col] & (1 << report_row));
-+ }
-+ /*
-+ * enter, up_left and up_right sensors pressed.
-+ * 1 _H6300_JOYPAD_UP_RIGHT 0 _H6300_JOYPAD_KEY_OK 0 _h6300_JOYPAD_UP_LEFT
-+ * --> 110101 == 53
-+ * OR
-+ * 1 KEY_UP_RIGHT 0 0 0 _h6300_JOYPAD_UP_LEFT
-+ * --> 110001 == 42
-+ * --> move to up
-+ */
-+ else if ((new_state[1] == 53) ||
-+ (new_state[1] == 49))
-+ {
-+ joypad_checked = 1;
-+ prevJoypadKeycodePressEmulated = KEY_UP;
-+ new_state[5] = 40; //101000
-+ report_key = prevJoypadKeycodePressEmulated;
-+ report_col = 5;
-+ report_row = 3;
-+ input_report_key(&omap_kp_dev,
-+ report_key,
-+ new_state[report_col] & (1 << report_row));
-+ }
-+ /*
-+ * enter, down_left and down_right sensors pressed
-+ * --> 101110 == 46
-+ * OR
-+ * down_left and down_right
-+ * -->101010 == 42
-+ * --> move to down
-+ */
-+ else if ((new_state[1] == 46) ||
-+ (new_state[1] == 42))
-+ {
-+ joypad_checked = 1;
-+ prevJoypadKeycodePressEmulated = KEY_DOWN;
-+ new_state[5] = 34; //100010
-+ report_key = prevJoypadKeycodePressEmulated;
-+ report_col = 5;
-+ report_row = 1;
-+ input_report_key(&omap_kp_dev,
-+ report_key,
-+ new_state[report_col] & (1 << report_row));
-+ }
-+ /*
-+ * enter, up_right and down_right sensors pressed
-+ * --> 111100 == 60
-+ * or
-+ * down_right and up_right
-+ * --> 111000 == 56
-+ * --> move to right
-+ */
-+ else if ((new_state[1] == 60) ||
-+ (new_state[1] == 56))
-+ {
-+ joypad_checked = 1;
-+ prevJoypadKeycodePressEmulated = KEY_RIGHT;
-+ new_state[5] = 33; //100001
-+ report_key = prevJoypadKeycodePressEmulated;
-+ report_col = 5;
-+ report_row = 0;
-+ input_report_key(&omap_kp_dev,
-+ report_key,
-+ new_state[report_col] & (1 << report_row));
-+ }
-+ /*
-+ * enter, up_left and down_left sensors pressed
-+ * --> 100111 == 39
-+ * or up_left and down_left
-+ * --> 100011 == 35
-+ * --> move to left
-+ */
-+ else if ((new_state[1] == 39) ||
-+ (new_state[1] == 35))
-+ {
-+ joypad_checked = 1;
-+ prevJoypadKeycodePressEmulated = KEY_LEFT;
-+ new_state[5] = 36; //100100
-+ report_key = prevJoypadKeycodePressEmulated;
-+ report_col = 5;
-+ report_row = 2;
-+ input_report_key(&omap_kp_dev,
-+ report_key,
-+ new_state[report_col] & (1 << report_row));
-+ }
-+ else
-+ {
-+ //printk("missed new_state = %d\n", new_state[1]);
-+ }
-+ }
-+ else
-+ {
-+ if (prevJoypadKeycodePressEmulated != 0)
-+ {
-+ // report key up event
-+ joypad_checked = 1;
-+ new_state[5] = 32; //100000
-+ report_key = prevJoypadKeycodePressEmulated;
-+ report_col = 5;
-+ switch(prevJoypadKeycodePressEmulated)
-+ {
-+ case KEY_RIGHT:
-+ report_row = 0;
-+ break;
-+ case KEY_DOWN:
-+ report_row = 1;
-+ break;
-+ case KEY_LEFT:
-+ report_row = 2;
-+ break;
-+ case KEY_UP:
-+ report_row = 3;
-+ break;
-+ case KEY_ENTER:
-+ report_row = 4;
-+ break;
-+ default:
-+ printk(KERN_WARNING "Unknown iPAQ h6300 column 1 key = %d released. This should newer happen!\n",
-+ key);
-+ report_row = 0;
-+ }
-+ input_report_key(&omap_kp_dev,
-+ report_key,
-+ new_state[report_col] & (1 << report_row));
-+ prevJoypadKeycodePressEmulated = 0;
-+ }
-+ }
-+ }
-+ }
-+ else
-+ {
-+ input_report_key(&omap_kp_dev,
-+ key,
-+ new_state[col] & (1 << row));
-+ }
- #endif
- }
- }
-@@ -285,7 +503,12 @@
- } else if (machine_is_omap_perseus2()) {
- keymap = p2_keymap;
- keypad_irq = INT_730_MPUIO_KEYPAD;
-+ } else if (machine_is_h6300()) {
-+ keymap = h6300_keymap;
-+ // set keyboard to send repeated key events if key is hold down
-+ set_bit(EV_REP, omap_kp_dev.evbit);
- } else {
-+ printk("omap_keypad.c, keyMap = test_keymap\n");
- keymap = test_keymap;
- }
-
-@@ -335,6 +558,7 @@
-
- omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
- }
-+ prevJoypadKeycodePressEmulated = 0;
-
- /* scan current status and enable interrupt */
- omap_kp_scan_keypad(keypad_state);
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/touchscreen/omap/Makefile bt_kernel/drivers/input/touchscreen/omap/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/touchscreen/omap/Makefile 2005-10-30 17:44:17.519075542 +0200
-+++ bt_kernel/drivers/input/touchscreen/omap/Makefile 2005-10-22 03:52:45.687256000 +0300
-@@ -8,5 +8,6 @@
- objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o
- objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += ts_inn1510.o
- objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += ts_osk.o
-+objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_H6300) += ts_hx.o
-
- omapts-objs := omap_ts.o $(objs-yy)
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/touchscreen/omap/omap_ts.c bt_kernel/drivers/input/touchscreen/omap/omap_ts.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/touchscreen/omap/omap_ts.c 2005-10-30 17:44:17.542071882 +0200
-+++ bt_kernel/drivers/input/touchscreen/omap/omap_ts.c 2005-10-22 03:52:45.687256000 +0300
-@@ -46,7 +46,7 @@
- #define OMAP_TS_NAME "omap_ts"
-
- static struct ts_device *__initdata ts_devs[] = {
--#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
-+#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H6300)
- &hx_ts,
- #endif
- #ifdef CONFIG_MACH_OMAP_OSK
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/touchscreen/omap/ts_hx.c bt_kernel/drivers/input/touchscreen/omap/ts_hx.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/input/touchscreen/omap/ts_hx.c 2005-10-30 17:44:17.566068062 +0200
-+++ bt_kernel/drivers/input/touchscreen/omap/ts_hx.c 2005-09-28 02:45:59.570809000 +0300
-@@ -33,6 +33,7 @@
- #include <asm/arch/mux.h>
- #include <asm/arch/hardware.h>
- #include <asm/hardware/tsc2101.h>
-+#include <linux/delay.h>
-
- #include "../drivers/ssi/omap-tsc2101.h"
- #include "omap_ts.h"
-@@ -88,14 +89,19 @@
- } else if (machine_is_omap_h3()) {
- gpio = H3_GPIO_NUM;
- omap_cfg_reg(W19_1610_GPIO48);
-+ } else if (machine_is_h6300 ()) {
-+ gpio = 2;
-+ omap_cfg_reg(M14_1510_GPIO2);
- } else
- return -ENODEV;
-
- ts->irq = OMAP_GPIO_IRQ(gpio);
-- if (omap_request_gpio(gpio) != 0) {
-- printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n");
-- return -EINVAL;
-- };
-+ if (!machine_is_h6300 ()){
-+ if (omap_request_gpio(gpio) != 0) {
-+ printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n");
-+ return -EINVAL;
-+ };
-+ }
-
- omap_set_gpio_direction(gpio, 1);
- set_irq_type(ts->irq, IRQT_FALLING);
-@@ -180,5 +186,7 @@
- omap_free_gpio(H2_GPIO_NUM);
- else if (machine_is_omap_h3())
- omap_free_gpio(H3_GPIO_NUM);
-+ else if (machine_is_h6300())
-+ omap_free_gpio(2);
- }
- #endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/busses/i2c-omap.c bt_kernel/drivers/i2c/busses/i2c-omap.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/busses/i2c-omap.c 2005-10-30 17:44:17.091143658 +0200
-+++ bt_kernel/drivers/i2c/busses/i2c-omap.c 2005-10-20 20:53:33.518825000 +0300
-@@ -124,10 +124,10 @@
- /* I2C System Configuration Register (OMAP_I2C_SYSC): */
- #define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
-
-+#undef I2C_OMAP_DEBUG
- /* ------- debugging ---------------------------------------------------*/
-
--#define I2C_OMAP_DEBUG
--#ifdef I2c_OMAP_DEBUG
-+#ifdef I2C_OMAP_DEBUG
- static int i2c_debug;
-
- module_param(i2c_debug, int, 0);
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/chips/Kconfig bt_kernel/drivers/i2c/chips/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/chips/Kconfig 2005-10-30 17:44:17.176130130 +0200
-+++ bt_kernel/drivers/i2c/chips/Kconfig 2005-10-14 18:55:31.156317000 +0300
-@@ -56,6 +56,16 @@
- This driver can also be built as a module. If so, the module
- will be called pca9539.
-
-+config PCA9535
-+ tristate "Philips PCA9535 16-bit I/O port"
-+ depends on I2C
-+ help
-+ If you say yes here you get support for the Philips PCA9535
-+ 16-bit I/O port.
-+
-+ This driver can also be built as a module. If so, the module
-+ will be called pca9539.
-+
- config SENSORS_PCF8591
- tristate "Philips PCF8591"
- depends on I2C && EXPERIMENTAL
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/chips/Makefile bt_kernel/drivers/i2c/chips/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/chips/Makefile 2005-10-30 17:44:17.176130130 +0200
-+++ bt_kernel/drivers/i2c/chips/Makefile 2005-10-14 18:55:31.156317000 +0300
-@@ -16,6 +16,7 @@
- obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o
- obj-$(CONFIG_GPIOEXPANDER_OMAP) += gpio_expander_omap.o
- obj-$(CONFIG_MENELAUS) += menelaus.o
-+obj-$(CONFIG_PCA9535) += pca9535.o
-
- ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
- EXTRA_CFLAGS += -DDEBUG
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/chips/pca9535.c bt_kernel/drivers/i2c/chips/pca9535.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/chips/pca9535.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/i2c/chips/pca9535.c 2005-10-25 22:23:21.875634000 +0300
-@@ -0,0 +1,414 @@
-+/*
-+ Driver for Philips PCA9535 16-bit low power I/O port with interrupt
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
-+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
-+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+ Copyright (C) 2005 Husam Senussi
-+ Framework based on Pawel Kolodziejski's pca9535 driver in
-+ handheld.org's 2.6.13 kernel. Driver updated by Mika Laitio.
-+*/
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/i2c.h>
-+#include <linux/hwmon-sysfs.h>
-+#include <linux/hwmon.h>
-+#include <linux/err.h>
-+
-+#include <asm/arch/pca9535.h>
-+#include <linux/delay.h>
-+
-+#include <linux/interrupt.h>
-+#include <asm/mach-types.h>
-+#include <asm/irq.h>
-+#include <asm/mach/arch.h>
-+#include <asm/hardware.h>
-+
-+EXPORT_SYMBOL(pca9535_gpio_read);
-+EXPORT_SYMBOL(pca9535_gpio_write);
-+EXPORT_SYMBOL(pca9535_gpio_direction);
-+
-+static int pca9535_attach_adapter(struct i2c_adapter *adapter);
-+static int pca9535_detach_client(struct i2c_client *client);
-+static int pca9535_attach(struct i2c_adapter *adapter, int address, int zero_or_minus_one);
-+static u32 pca9535_read_reg(struct i2c_client *client, u8 regaddr);
-+static void pca9535_write_reg(struct i2c_client *client, u8 regaddr, u16 param);
-+
-+enum pca9535_cmd
-+{
-+ PCA9535_INPUT_0 = 0,
-+ PCA9535_INPUT_1 = 1,
-+ PCA9535_OUTPUT_0 = 2,
-+ PCA9535_OUTPUT_1 = 3,
-+ PCA9535_INVERT_0 = 4,
-+ PCA9535_INVERT_1 = 5,
-+ PCA9535_DIRECTION_0 = 6,
-+ PCA9535_DIRECTION_1 = 7,
-+};
-+
-+struct pca9535_data {
-+ struct semaphore lock;
-+ struct i2c_client client;
-+};
-+
-+static struct i2c_driver pca9535_driver = {
-+ .owner = THIS_MODULE,
-+ .name = "pca9535",
-+ .flags = I2C_DF_NOTIFY,
-+ .attach_adapter = pca9535_attach_adapter,
-+ .detach_client = pca9535_detach_client,
-+};
-+
-+static struct i2c_client *pca9535_i2c_client = NULL;
-+static struct pca9535_data pca9535_inited;
-+
-+static unsigned short normal_i2c[] = { 0x20, I2C_CLIENT_END };
-+
-+#define DRIVER_VERSION "20 OCT 2005"
-+#define DRIVER_NAME "PCA9535"
-+
-+/*
-+ * sysfs callback function.
-+ */
-+static ssize_t pca9535_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
-+ struct i2c_client *client = to_i2c_client(dev);
-+ return sprintf(buf, "%02X\n", (pca9535_read_reg(client, psa->index) >> 8));
-+}
-+
-+/*
-+ * sysfs callback function.
-+ */
-+static ssize_t pca9535_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
-+ struct i2c_client *client = to_i2c_client(dev);
-+ unsigned long val = simple_strtoul(buf, NULL, 0);
-+ unsigned long old = pca9535_read_reg(client, psa->index);
-+
-+ if (val > 0xff)
-+ return -EINVAL;
-+
-+ val = (old & 0xff) | (val << 8);
-+ pca9535_write_reg(client, psa->index, val);
-+ return count;
-+}
-+
-+#define PCA9535_ENTRY_RO(name, cmd_idx) \
-+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9535_show, NULL, cmd_idx)
-+
-+#define PCA9535_ENTRY_RW(name, cmd_idx) \
-+ static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9535_show, \
-+ pca9535_store, cmd_idx)
-+
-+PCA9535_ENTRY_RO(input0, PCA9535_INPUT_0);
-+PCA9535_ENTRY_RO(input1, PCA9535_INPUT_1);
-+PCA9535_ENTRY_RW(output0, PCA9535_OUTPUT_0);
-+PCA9535_ENTRY_RW(output1, PCA9535_OUTPUT_1);
-+PCA9535_ENTRY_RW(invert0, PCA9535_INVERT_0);
-+PCA9535_ENTRY_RW(invert1, PCA9535_INVERT_1);
-+PCA9535_ENTRY_RW(direction0, PCA9535_DIRECTION_0);
-+PCA9535_ENTRY_RW(direction1, PCA9535_DIRECTION_1);
-+
-+static struct attribute *pca9535_attributes[] = {
-+ &sensor_dev_attr_input0.dev_attr.attr,
-+ &sensor_dev_attr_input1.dev_attr.attr,
-+ &sensor_dev_attr_output0.dev_attr.attr,
-+ &sensor_dev_attr_output1.dev_attr.attr,
-+ &sensor_dev_attr_invert0.dev_attr.attr,
-+ &sensor_dev_attr_invert1.dev_attr.attr,
-+ &sensor_dev_attr_direction0.dev_attr.attr,
-+ &sensor_dev_attr_direction1.dev_attr.attr,
-+ NULL
-+};
-+
-+static struct attribute_group pca9535_defattr_group = {
-+ .attrs = pca9535_attributes,
-+};
-+//End of sysfs management code.
-+
-+I2C_CLIENT_INSMOD;
-+
-+u32 pca9535_read_input(void)
-+{
-+ return pca9535_read_reg(pca9535_i2c_client, 0);
-+}
-+EXPORT_SYMBOL(pca9535_read_input);
-+
-+void pca9535_write_output(u16 param)
-+{
-+ pca9535_write_reg(pca9535_i2c_client, 2, param);
-+}
-+EXPORT_SYMBOL(pca9535_write_output);
-+
-+void pca9535_set_dir(u16 param)
-+{
-+ pca9535_write_reg(pca9535_i2c_client, 6, param);
-+}
-+EXPORT_SYMBOL(pca9535_set_dir);
-+
-+static int pca9535_attach_adapter(struct i2c_adapter *adapter)
-+{
-+ return i2c_probe(adapter, &addr_data, pca9535_attach);
-+}
-+
-+static int pca9535_attach(struct i2c_adapter *adapter, int address, int zero_or_minus_one)
-+{
-+ struct i2c_client *new_client;
-+ int err = 0;
-+
-+ printk("pca9535_attach() started\n");
-+ new_client = &(pca9535_inited.client);
-+ i2c_set_clientdata(new_client, 0);
-+ new_client->addr = address;
-+ new_client->adapter = adapter;
-+ new_client->driver = &pca9535_driver;
-+ new_client->flags = I2C_CLIENT_ALLOW_USE;
-+ strcpy(new_client->name, DRIVER_NAME);
-+
-+ if ((err = i2c_attach_client(new_client)))
-+ goto exit_free;
-+
-+ pca9535_i2c_client = new_client;
-+
-+ init_MUTEX(&pca9535_inited.lock);
-+ i2c_set_clientdata(pca9535_i2c_client, &pca9535_inited);
-+
-+ sysfs_create_group(&pca9535_i2c_client->dev.kobj, &pca9535_defattr_group);
-+
-+ printk("pca9535_attach() ok\n");
-+ return 0;
-+
-+exit_free:
-+ printk("pca9535_attach() failed, error code = %d\n", err);
-+ return err;
-+}
-+
-+static int pca9535_detach_client(struct i2c_client *client)
-+{
-+ int err;
-+
-+ if ((err = i2c_detach_client(client))) {
-+ dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
-+ return err;
-+ }
-+ pca9535_i2c_client = NULL;
-+
-+ return 0;
-+}
-+
-+static int __init pca9535_init(void)
-+{
-+ return i2c_add_driver(&pca9535_driver);
-+}
-+
-+static void __exit pca9535_exit(void)
-+{
-+ i2c_del_driver(&pca9535_driver);
-+}
-+
-+/*
-+ * Reads the value of GPIO available via I2C.
-+ */
-+int pca9535_gpio_read(int gpio){
-+ unsigned char reg = 0;
-+ unsigned long val = 0;
-+
-+ printk("9535_gpio_read() called\n");
-+ if(!pca9535_i2c_client)
-+ return -ENODEV;
-+
-+ if(gpio < GPIO0 || gpio > GPIO17)
-+ return -EINVAL;
-+
-+ if(gpio >= GPIO0 && gpio <= GPIO7){
-+ reg = PCA9535_INPUT_0;
-+ gpio -= GPIO0;
-+ }else if(gpio >= GPIO8 && gpio <= GPIO17){
-+ reg = PCA9535_INPUT_1;
-+ gpio -= GPIO8;
-+ }
-+
-+ down(&pca9535_inited.lock);
-+
-+ // Read the existing values first
-+ val = pca9535_read_reg(pca9535_i2c_client, reg) >> 8;
-+ val = (val >> gpio) & 0x01;
-+
-+ up(&pca9535_inited.lock);
-+
-+ return val;
-+}
-+
-+/*
-+ * Set the value of I2C GPIO.
-+ */
-+int pca9535_gpio_write(int gpio, unsigned char value){
-+ unsigned char in_reg = 0;
-+ unsigned char out_reg = 0;
-+ unsigned long val = 0;
-+ unsigned long old = 0;
-+ int ret = 0;
-+
-+ if(!pca9535_i2c_client)
-+ return -ENODEV;
-+
-+ if(gpio < GPIO0 || gpio > GPIO17)
-+ return -EINVAL;
-+
-+ if(gpio >= GPIO0 && gpio <= GPIO7){
-+ in_reg = PCA9535_INPUT_0;
-+ out_reg = PCA9535_OUTPUT_0;
-+ gpio -= GPIO0;
-+ }else if(gpio >= GPIO8 && gpio <= GPIO17){
-+ in_reg = PCA9535_INPUT_1;
-+ out_reg = PCA9535_OUTPUT_1;
-+ gpio -= GPIO8;
-+ }
-+
-+ down(&pca9535_inited.lock);
-+
-+ // Read the existing values first
-+ val = pca9535_read_reg(pca9535_i2c_client, in_reg);
-+ old = val >> 8;
-+
-+ switch(value){
-+ case LOW:
-+ old |= (1 << gpio);
-+ break;
-+ case HI:
-+ old &= ~(1 << gpio);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ val = (val & 0xff) | (old << 8);
-+
-+ // write the values back to the register
-+ pca9535_write_reg(pca9535_i2c_client, out_reg, val);
-+error:
-+
-+ up(&pca9535_inited.lock);
-+ return ret;
-+}
-+
-+/*
-+ * Set the direction of I2C GPIO.
-+ */
-+int pca9535_gpio_direction(int gpio, unsigned char direction){
-+ unsigned char reg = 0;
-+ unsigned long val = 0;
-+ unsigned long old = 0;
-+ int ret = 0;
-+
-+ if(!pca9535_i2c_client)
-+ return -ENODEV;
-+
-+ if(gpio < GPIO0 || gpio > GPIO17)
-+ return -EINVAL;
-+
-+ if(gpio >= GPIO0 && gpio <= GPIO7){
-+ reg = PCA9535_DIRECTION_0;
-+ gpio -= GPIO0;
-+ }else if(gpio >= GPIO8 && gpio <= GPIO17){
-+ reg = PCA9535_DIRECTION_1;
-+ gpio -= GPIO8;
-+ }
-+
-+ down(&pca9535_inited.lock);
-+
-+ // Read the existing values first
-+ old = pca9535_read_reg(pca9535_i2c_client, reg);
-+ val = old >> 8;
-+
-+ switch(direction){
-+ case GPIO_INPUT:
-+ val |= (1 << gpio);
-+ break;
-+ case GPIO_OUTPUT:
-+ val &= ~(1 << gpio);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ val = (old & 0xff) | (val << 8);
-+
-+ // write the values back to the register
-+ pca9535_write_reg(pca9535_i2c_client, reg, val);
-+error:
-+
-+ up(&pca9535_inited.lock);
-+ return ret;
-+}
-+
-+static u32 pca9535_read_reg(struct i2c_client *client, u8 regaddr)
-+{
-+ char buffer[3];
-+ int r;
-+ u32 data;
-+
-+ buffer[0] = regaddr;
-+ buffer[1] = 0;
-+ buffer[2] = 0;
-+
-+ r = i2c_master_send(client, buffer, 1);
-+ if (r != 1) {
-+ printk(KERN_ERR "pca9535: read failed, status %d\n", r);
-+ return 0xffffffff;
-+ }
-+
-+ r = i2c_master_recv(client, buffer, 3);
-+ if (r != 3) {
-+ printk(KERN_ERR "pca9535: read failed, status %d\n", r);
-+ return 0xffffffff;
-+ }
-+
-+ data = buffer[1];
-+ data |= buffer[2] << 8;
-+ //printk(KERN_ERR "%s: reading %x in %x\n", __FUNCTION__, data, regaddr);
-+
-+ return data;
-+}
-+
-+static void pca9535_write_reg(struct i2c_client *client, u8 regaddr, u16 data)
-+{
-+ char buffer[3];
-+ int r;
-+
-+ //printk(KERN_ERR "%s: writing %x in %x\n", __FUNCTION__, data, regaddr);
-+ buffer[0] = regaddr;
-+ buffer[1] = data >> 8;
-+ buffer[2] = data & 0xff;
-+
-+ r = i2c_master_send(client, buffer, 3);
-+ if (r != 3) {
-+ printk(KERN_ERR "pca9535: write failed, status %d\n", r);
-+ }
-+}
-+
-+MODULE_AUTHOR("Husam Senussi <husamsenussi@gmail.com>");
-+MODULE_DESCRIPTION("PCA9535 driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(pca9535_init);
-+module_exit(pca9535_exit);
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/i2c-core.c bt_kernel/drivers/i2c/i2c-core.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/i2c/i2c-core.c 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/i2c/i2c-core.c 2005-10-22 03:52:45.687256000 +0300
-@@ -1180,8 +1180,12 @@
- command,size,data);
- up(&adapter->bus_lock);
- } else
-+ {
-+ printk("i2c-core, calling i2c_smbus_xfer_emulated!");
- res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
- command,size,data);
-+ printk("i2c-core, i2c_smbus_xfer_emulated retVal = %d", res);
-+ }
-
- if(res >= 0 && swpec &&
- size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/media/video/omap/omap16xxcam.c bt_kernel/drivers/media/video/omap/omap16xxcam.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/media/video/omap/omap16xxcam.c 2005-10-30 17:44:17.750038779 +0200
-+++ bt_kernel/drivers/media/video/omap/omap16xxcam.c 2005-10-30 16:32:39.609796000 +0200
-@@ -325,18 +325,22 @@
-
- if (machine_is_omap_h3())
- omap_set_dma_src_params(dmach, OMAP_DMA_PORT_OCP_T1,
-- OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG);
-+ OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG,
-+ 0, 0);
- else
- omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB,
-- OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG);
-+ OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG,
-+ 0, 0);
-
- omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF,
-- OMAP_DMA_AMODE_POST_INC, sg_dma_address(sglist));
-+ OMAP_DMA_AMODE_POST_INC, sg_dma_address(sglist),
-+ 0, 0);
-
- omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32,
- FIFO_TRIGGER_LVL,
- sg_dma_len(sglist)/(4 * FIFO_TRIGGER_LVL),
-- OMAP_DMA_SYNC_FRAME);
-+ OMAP_DMA_SYNC_FRAME,
-+ 0, 0);
-
-
- omap_writew(omap_readw(OMAP_DMA_CLNK_CTRL(dmach)) & ~(1<<15),
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/mmc/omap.c bt_kernel/drivers/mmc/omap.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/mmc/omap.c 2005-10-30 17:44:17.905014111 +0200
-+++ bt_kernel/drivers/mmc/omap.c 2005-10-30 16:32:39.609796000 +0200
-@@ -4,6 +4,7 @@
- * Copyright (C) 2004 Nokia Corporation
- * Written by Tuukka Tikkanen and Juha Yrjölä <juha.yrjola@nokia.com>
- * Misc hacks here and there by Tony Lindgren <tony@atomide.com>
-+ * Other hacks (DMA, SD, etc) by David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
-@@ -703,20 +704,24 @@
- buf = 0x800f | ((frame - 1) << 8);
- omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
-- data_addr);
-+ data_addr,
-+ 0, 0);
- omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC,
-- sg_dma_address(sg));
-+ sg_dma_address(sg),
-+ 0, 0);
- omap_set_dma_dest_data_pack(dma_ch, 1);
- omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
- } else {
- buf = 0x0f80 | ((frame - 1) << 0);
- omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
-- data_addr);
-+ data_addr,
-+ 0, 0);
- omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC,
-- sg_dma_address(sg));
-+ sg_dma_address(sg),
-+ 0, 0);
- omap_set_dma_src_data_pack(dma_ch, 1);
- omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
- }
-@@ -727,7 +732,8 @@
-
- OMAP_MMC_WRITE(host->base, BUF, buf);
- omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
-- frame, count, OMAP_DMA_SYNC_FRAME);
-+ frame, count, OMAP_DMA_SYNC_FRAME,
-+ 0, 0);
- }
-
- /* a scatterlist segment completed */
-@@ -767,9 +773,6 @@
-
- host->sg_idx++;
- if (host->sg_idx < host->sg_len) {
-- /* REVISIT we only checked the first segment
-- * for being a dma candidate ...
-- */
- mmc_omap_prepare_dma(host, host->data);
- omap_start_dma(host->dma_ch);
- } else
-@@ -1089,9 +1092,10 @@
- if (dsor > 250)
- dsor = 250;
- dsor++;
-- }
-
-- /* REVISIT: if (ios->bus_width == MMC_BUS_WIDTH_4) dsor |= 1 << 15; */
-+ if (ios->bus_width == MMC_BUS_WIDTH_4)
-+ dsor |= 1 << 15;
-+ }
-
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
-@@ -1132,9 +1136,17 @@
- clk_unuse(host->fclk);
- }
-
-+static int mmc_omap_get_ro(struct mmc_host *mmc)
-+{
-+ struct mmc_omap_host *host = mmc_priv(mmc);
-+
-+ return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
-+}
-+
- static struct mmc_host_ops mmc_omap_ops = {
- .request = mmc_omap_request,
- .set_ios = mmc_omap_set_ios,
-+ .get_ro = mmc_omap_get_ro,
- };
-
- static int __init mmc_omap_probe(struct device *dev)
-@@ -1192,9 +1204,7 @@
- goto out;
- }
-
-- /* REVISIT: SD-only support, when core merged
-- * - if (minfo->wire4) mmc->caps |= MMC_CAP_4_BIT_DATA;
-- * - mmc_omap_ops.get_ro uses wp_pin to sense slider
-+ /* REVISIT:
- * Also, use minfo->cover to decide how to manage
- * the card detect sensing.
- */
-@@ -1212,6 +1222,9 @@
- host->irq = pdev->resource[1].start;
- host->base = (void __iomem *)pdev->resource[0].start;
-
-+ if (minfo->wire4)
-+ mmc->caps |= MMC_CAP_4_BIT_DATA;
-+
- mmc->ops = &mmc_omap_ops;
- mmc->f_min = 400000;
- mmc->f_max = 24000000;
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/mtd/nand/omap-hw.c bt_kernel/drivers/mtd/nand/omap-hw.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/mtd/nand/omap-hw.c 2005-10-30 17:44:18.133977666 +0200
-+++ bt_kernel/drivers/mtd/nand/omap-hw.c 2005-10-30 16:32:39.609796000 +0200
-@@ -232,25 +232,30 @@
- fifo_reg = NAND_BASE + NND_FIFO;
- if (is_write) {
- omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_TIPB,
-- OMAP_DMA_AMODE_CONSTANT, fifo_reg);
-+ OMAP_DMA_AMODE_CONSTANT, fifo_reg,
-+ 0, 0);
- omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC,
-- virt_to_phys(addr));
-+ virt_to_phys(addr),
-+ 0, 0);
- // omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
- /* Set POSTWRITE bit */
- nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 16));
- } else {
- omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_TIPB,
-- OMAP_DMA_AMODE_CONSTANT, fifo_reg);
-+ OMAP_DMA_AMODE_CONSTANT, fifo_reg,
-+ 0, 0);
- omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_EMIFF,
- OMAP_DMA_AMODE_POST_INC,
-- virt_to_phys(addr));
-+ virt_to_phys(addr),
-+ 0, 0);
- // omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_8);
- /* Set PREFETCH bit */
- nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
- }
- omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, block_size / 4,
-- block_count, OMAP_DMA_SYNC_FRAME);
-+ block_count, OMAP_DMA_SYNC_FRAME,
-+ 0, 0);
- init_completion(&comp);
-
- len = u32_count << 2;
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/irda/omap1610-ir.c bt_kernel/drivers/net/irda/omap1610-ir.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/irda/omap1610-ir.c 2005-10-30 17:44:18.200967003 +0200
-+++ bt_kernel/drivers/net/irda/omap1610-ir.c 2005-10-30 16:32:39.609796000 +0200
-@@ -166,14 +166,16 @@
- static void omap1610_irda_start_rx_dma(struct omap1610_irda *si)
- {
- /* Configure DMA */
-- omap_set_dma_src_params(si->rx_dma_channel, 0x3, 0x0, (unsigned long)UART3_RHR);
-+ omap_set_dma_src_params(si->rx_dma_channel, 0x3, 0x0, (unsigned long)UART3_RHR,
-+ 0, 0);
-
- omap_enable_dma_irq(si->rx_dma_channel, 0x01);
-
- omap_set_dma_dest_params(si->rx_dma_channel, 0x0, 0x1,
-- si->rx_buf_dma_phys);
-+ si->rx_buf_dma_phys,
-+ 0, 0);
-
-- omap_set_dma_transfer_params(si->rx_dma_channel, 0x0, 4096, 0x1, 0x0);
-+ omap_set_dma_transfer_params(si->rx_dma_channel, 0x0, 4096, 0x1, 0x0, 0, 0);
-
- omap_start_dma(si->rx_dma_channel);
- }
-@@ -183,14 +185,16 @@
- __ECHO_IN;
-
- /* Configure DMA */
-- omap_set_dma_dest_params(si->tx_dma_channel, 0x03, 0x0, (unsigned long)UART3_THR);
-+ omap_set_dma_dest_params(si->tx_dma_channel, 0x03, 0x0, (unsigned long)UART3_THR,
-+ 0, 0);
-
- omap_enable_dma_irq(si->tx_dma_channel, 0x01);
-
- omap_set_dma_src_params(si->tx_dma_channel, 0x0, 0x1,
-- si->tx_buf_dma_phys);
-+ si->tx_buf_dma_phys,
-+ 0, 0);
-
-- omap_set_dma_transfer_params(si->tx_dma_channel, 0x0, size, 0x1, 0x0);
-+ omap_set_dma_transfer_params(si->tx_dma_channel, 0x0, size, 0x1, 0x0, 0, 0);
-
- HDBG1(1);
-
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/Kconfig bt_kernel/drivers/net/wireless/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/Kconfig 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/net/wireless/Kconfig 2005-10-22 03:52:45.687256000 +0300
-@@ -483,5 +483,7 @@
- depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA)
- default y
-
-+source "drivers/net/wireless/tiacx/Kconfig"
-+
- endmenu
-
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/Makefile bt_kernel/drivers/net/wireless/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/Makefile 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/net/wireless/Makefile 2005-10-14 18:55:31.156317000 +0300
-@@ -39,3 +39,4 @@
- # 16-bit wireless PCMCIA client drivers
- obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
- obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
-+obj-$(CONFIG_ACX) += tiacx/
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx_config.h bt_kernel/drivers/net/wireless/tiacx/acx_config.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx_config.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/acx_config.h 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,44 @@
-+/* temporary hack until proper Kconfig integration */
-+#define CONFIG_ACX_PCI 1
-+#define CONFIG_ACX_USB 1
-+
-+#define WLAN_RELEASE "v0.3.10"
-+
-+/* set to 0 if you don't want any debugging code to be compiled in */
-+/* set to 1 if you want some debugging */
-+/* set to 2 if you want extensive debug log */
-+#define ACX_DEBUG 2
-+
-+/* assume 32bit I/O width
-+ * (16bit is also compatible with Compact Flash) */
-+#define ACX_IO_WIDTH 16
-+
-+/* Set this to 1 if you want monitor mode to use
-+ * phy header. Currently it is not useful anyway since we
-+ * don't know what useful info (if any) is in phy header.
-+ * If you want faster/smaller code, say 0 here */
-+#define WANT_PHY_HDR 0
-+
-+/* whether to do Tx descriptor cleanup in softirq (i.e. not in IRQ
-+ * handler) or not. Note that doing it later does slightly increase
-+ * system load, so still do that stuff in the IRQ handler for now,
-+ * even if that probably means worse latency */
-+#define TX_CLEANUP_IN_SOFTIRQ 0
-+
-+/* set to 1 if you want to have 1 driver per card instead of 1 single driver
-+ * managing all cards (of a particular bus type) in your system
-+ * Useful e.g. if you need to reinitialize single cards from time to time
-+ * LINUX 2.4.X ONLY!! (pci_for_each_dev()) Feel free to implement 2.6.x
-+ * compatibility... */
-+#define SEPARATE_DRIVER_INSTANCES 0
-+
-+/* Locking: */
-+/* very talkative */
-+#define PARANOID_LOCKING 1
-+/* normal (use when bug-free) */
-+/* #define DO_LOCKING 1 */
-+/* else locking is disabled! */
-+
-+/* 0 - normal mode */
-+/* 1 - development/debug: probe for IEs on modprobe */
-+#define CMD_DISCOVERY 0
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx_func.h bt_kernel/drivers/net/wireless/tiacx/acx_func.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx_func.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/acx_func.h 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,660 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+
-+/***********************************************************************
-+** LOGGING
-+**
-+** - Avoid SHOUTING needlessly. Avoid excessive verbosity.
-+** Gradually remove messages which are old debugging aids.
-+**
-+** - Use printk() for messages which are to be always logged.
-+** Supply either 'acx:' or '<devname>:' prefix so that user
-+** can figure out who's speaking among other kernel chatter.
-+** acx: is for general issues (e.g. "acx: no firmware image!")
-+** while <devname>: is related to a particular device
-+** (think about multi-card setup). Double check that message
-+** is not confusing to the average user.
-+**
-+** - use printk KERN_xxx level only if message is not a WARNING
-+** but is INFO, ERR etc.
-+**
-+** - Use printk_ratelimited() for messages which may flood
-+** (e.g. "rx DUP pkt!").
-+**
-+** - Use acxlog() for messages which may be omitted (and they
-+** _will_ be omitted in non-debug builds). Note that
-+** message levels may be disabled at compile-time selectively,
-+** thus select them wisely. Example: L_DEBUG is the lowest
-+** (most likely to be compiled out) -> use for less important stuff.
-+**
-+** - Do not print important stuff with acxlog(), or else people
-+** will never build non-debug driver.
-+**
-+** Style:
-+** hex: capital letters, zero filled (e.g. 0x02AC)
-+** str: dont start from capitals, no trailing periods ("tx: queue is stopped")
-+*/
-+#if ACX_DEBUG > 1
-+
-+void log_fn_enter(const char *funcname);
-+void log_fn_exit(const char *funcname);
-+void log_fn_exit_v(const char *funcname, int v);
-+
-+#define FN_ENTER \
-+ do { \
-+ if (unlikely(acx_debug & L_FUNC)) { \
-+ log_fn_enter(__func__); \
-+ } \
-+ } while (0)
-+
-+#define FN_EXIT1(v) \
-+ do { \
-+ if (unlikely(acx_debug & L_FUNC)) { \
-+ log_fn_exit_v(__func__, v); \
-+ } \
-+ } while (0)
-+#define FN_EXIT0 \
-+ do { \
-+ if (unlikely(acx_debug & L_FUNC)) { \
-+ log_fn_exit(__func__); \
-+ } \
-+ } while (0)
-+
-+#else
-+
-+#define FN_ENTER
-+#define FN_EXIT1(v)
-+#define FN_EXIT0
-+
-+#endif /* ACX_DEBUG > 1 */
-+
-+
-+#if ACX_DEBUG
-+
-+#define acxlog(chan, args...) \
-+ do { \
-+ if (acx_debug & (chan)) \
-+ printk(args); \
-+ } while (0)
-+#define printk_ratelimited(args...) printk(args)
-+
-+#else /* Non-debug build: */
-+
-+#define acxlog(chan, args...)
-+/* Standard way of log flood prevention */
-+#define printk_ratelimited(args...) \
-+do { \
-+ if (printk_ratelimit()) \
-+ printk(args); \
-+} while (0)
-+
-+#endif /* ACX_DEBUG */
-+
-+void acx_print_mac(const char *head, const u8 *mac, const char *tail);
-+
-+/* Optimized out to nothing in non-debug build */
-+static inline void
-+acxlog_mac(int level, const char *head, const u8 *mac, const char *tail)
-+{
-+ if (acx_debug & level) {
-+ acx_print_mac(head, mac, tail);
-+ }
-+}
-+
-+
-+/***********************************************************************
-+** MAC address helpers
-+*/
-+static inline void
-+MAC_COPY(u8 *mac, const u8 *src)
-+{
-+ *(u32*)mac = *(u32*)src;
-+ ((u16*)mac)[2] = ((u16*)src)[2];
-+ /* kernel's memcpy will do the same: memcpy(dst, src, ETH_ALEN); */
-+}
-+
-+static inline void
-+MAC_FILL(u8 *mac, u8 val)
-+{
-+ memset(mac, val, ETH_ALEN);
-+}
-+
-+static inline void
-+MAC_BCAST(u8 *mac)
-+{
-+ ((u16*)mac)[2] = *(u32*)mac = -1;
-+}
-+
-+static inline void
-+MAC_ZERO(u8 *mac)
-+{
-+ ((u16*)mac)[2] = *(u32*)mac = 0;
-+}
-+
-+static inline int
-+mac_is_equal(const u8 *a, const u8 *b)
-+{
-+ /* can't beat this */
-+ return memcmp(a, b, ETH_ALEN) == 0;
-+}
-+
-+static inline int
-+mac_is_bcast(const u8 *mac)
-+{
-+ /* AND together 4 first bytes with sign-entended 2 last bytes
-+ ** Only bcast address gives 0xffffffff. +1 gives 0 */
-+ return ( *(s32*)mac & ((s16*)mac)[2] ) + 1 == 0;
-+}
-+
-+static inline int
-+mac_is_zero(const u8 *mac)
-+{
-+ return ( *(u32*)mac | ((u16*)mac)[2] ) == 0;
-+}
-+
-+static inline int
-+mac_is_directed(const u8 *mac)
-+{
-+ return (mac[0] & 1)==0;
-+}
-+
-+static inline int
-+mac_is_mcast(const u8 *mac)
-+{
-+ return (mac[0] & 1) && !mac_is_bcast(mac);
-+}
-+
-+#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
-+#define MAC(bytevector) \
-+ ((unsigned char *)bytevector)[0], \
-+ ((unsigned char *)bytevector)[1], \
-+ ((unsigned char *)bytevector)[2], \
-+ ((unsigned char *)bytevector)[3], \
-+ ((unsigned char *)bytevector)[4], \
-+ ((unsigned char *)bytevector)[5]
-+
-+
-+/***********************************************************************
-+** Random helpers
-+*/
-+#define TO_STRING(x) #x
-+#define STRING(x) TO_STRING(x)
-+
-+#define CLEAR_BIT(val, mask) ((val) &= ~(mask))
-+#define SET_BIT(val, mask) ((val) |= (mask))
-+
-+/* undefined if v==0 */
-+static inline unsigned int
-+lowest_bit(u16 v)
-+{
-+ unsigned int n = 0;
-+ while (!(v & 0xf)) { v>>=4; n+=4; }
-+ while (!(v & 1)) { v>>=1; n++; }
-+ return n;
-+}
-+
-+/* undefined if v==0 */
-+static inline unsigned int
-+highest_bit(u16 v)
-+{
-+ unsigned int n = 0;
-+ while (v>0xf) { v>>=4; n+=4; }
-+ while (v>1) { v>>=1; n++; }
-+ return n;
-+}
-+
-+/* undefined if v==0 */
-+static inline int
-+has_only_one_bit(u16 v)
-+{
-+ return ((v-1) ^ v) >= v;
-+}
-+
-+
-+/***********************************************************************
-+** LOCKING
-+** We have priv->sem and priv->lock.
-+**
-+** We employ following naming convention in order to get locking right:
-+**
-+** acx_e_xxxx - external entry points called from process context.
-+** It is okay to sleep. priv->sem is to be taken on entry.
-+** acx_i_xxxx - external entry points possibly called from atomic context.
-+** Sleeping is not allowed (and thus down(sem) is not legal!)
-+** acx_s_xxxx - potentially sleeping functions. Do not ever call under lock!
-+** acx_l_xxxx - functions which expect lock to be already taken.
-+** rest - non-sleeping functions which do not require locking
-+** but may be run inder lock
-+**
-+** Theory of operation:
-+**
-+** All process-context entry points (_e_ functions) take sem
-+** immediately. IRQ handler and other 'atomic-context' entry points
-+** (_i_ functions) take lock immediately on entry, but dont take sem
-+** because that might sleep.
-+**
-+** Thus *all* code is either protected by sem or lock, or both.
-+**
-+** Code which must not run concurrently with IRQ takes lock.
-+** Such code is marked with _l_.
-+**
-+** This results in the following rules of thumb useful in code review:
-+**
-+** + If a function calls _s_ fn, it must be an _s_ itself.
-+** + You can call _l_ fn only (a) from another _l_ fn
-+** or (b) from _s_, _e_ or _i_ fn by taking lock, calling _l_,
-+** and dropping lock.
-+** + All IRQ code runs under lock.
-+** + Any _s_ fn is running under sem.
-+** + Code under sem can race only with IRQ code.
-+** + Code under sem+lock cannot race with anything.
-+*/
-+
-+/* These functions *must* be inline or they will break horribly on SPARC, due
-+ * to its weird semantics for save/restore flags */
-+
-+#if defined(PARANOID_LOCKING) /* Lock debugging */
-+
-+void acx_lock_debug(wlandevice_t *priv, const char* where);
-+void acx_unlock_debug(wlandevice_t *priv, const char* where);
-+void acx_down_debug(wlandevice_t *priv, const char* where);
-+void acx_up_debug(wlandevice_t *priv, const char* where);
-+void acx_lock_unhold(void);
-+void acx_sem_unhold(void);
-+
-+static inline void
-+acx_lock_helper(wlandevice_t *priv, unsigned long *fp, const char* where)
-+{
-+ acx_lock_debug(priv, where);
-+ spin_lock_irqsave(&priv->lock, *fp);
-+}
-+static inline void
-+acx_unlock_helper(wlandevice_t *priv, unsigned long *fp, const char* where)
-+{
-+ acx_unlock_debug(priv, where);
-+ spin_unlock_irqrestore(&priv->lock, *fp);
-+}
-+static inline void
-+acx_down_helper(wlandevice_t *priv, const char* where)
-+{
-+ acx_down_debug(priv, where);
-+}
-+static inline void
-+acx_up_helper(wlandevice_t *priv, const char* where)
-+{
-+ acx_up_debug(priv, where);
-+}
-+#define acx_lock(priv, flags) acx_lock_helper(priv, &(flags), __FILE__ ":" STRING(__LINE__))
-+#define acx_unlock(priv, flags) acx_unlock_helper(priv, &(flags), __FILE__ ":" STRING(__LINE__))
-+#define acx_sem_lock(priv) acx_down_helper(priv, __FILE__ ":" STRING(__LINE__))
-+#define acx_sem_unlock(priv) acx_up_helper(priv, __FILE__ ":" STRING(__LINE__))
-+
-+#elif defined(DO_LOCKING)
-+
-+#define acx_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
-+#define acx_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
-+#define acx_sem_lock(priv) down(&priv->sem)
-+#define acx_sem_unlock(priv) up(&priv->sem)
-+#define acx_lock_unhold() ((void)0)
-+#define acx_sem_unhold() ((void)0)
-+
-+#else /* no locking! :( */
-+
-+#define acx_lock(priv, flags) ((void)0)
-+#define acx_unlock(priv, flags) ((void)0)
-+#define acx_sem_lock(priv) ((void)0)
-+#define acx_sem_unlock(priv) ((void)0)
-+#define acx_lock_unhold() ((void)0)
-+#define acx_sem_unhold() ((void)0)
-+
-+#endif
-+
-+
-+/***********************************************************************
-+*/
-+
-+/* Can race with rx path (which is not protected by sem):
-+** rx -> process_[re]assocresp() -> set_status(ASSOCIATED) -> wake_queue()
-+** Can race with tx_complete IRQ:
-+** IRQ -> acx_l_clean_tx_desc -> acx_wake_queue
-+** Review carefully all callsites */
-+static inline void
-+acx_stop_queue(netdevice_t *dev, const char *msg)
-+{
-+ if(netif_queue_stopped(dev))
-+ return;
-+
-+ netif_stop_queue(dev);
-+ if (msg)
-+ acxlog(L_BUFT, "tx: stop queue %s\n", msg);
-+}
-+
-+static inline int
-+acx_queue_stopped(netdevice_t *dev)
-+{
-+ return netif_queue_stopped(dev);
-+}
-+
-+static inline void
-+acx_start_queue(netdevice_t *dev, const char *msg)
-+{
-+ netif_start_queue(dev);
-+ if (msg)
-+ acxlog(L_BUFT, "tx: start queue %s\n", msg);
-+}
-+
-+static inline void
-+acx_wake_queue(netdevice_t *dev, const char *msg)
-+{
-+ netif_wake_queue(dev);
-+ if (msg)
-+ acxlog(L_BUFT, "tx: wake queue %s\n", msg);
-+}
-+
-+static inline void
-+acx_carrier_off(netdevice_t *dev, const char *msg)
-+{
-+ netif_carrier_off(dev);
-+ if (msg)
-+ acxlog(L_BUFT, "tx: carrier off %s\n", msg);
-+}
-+
-+static inline void
-+acx_carrier_on(netdevice_t *dev, const char *msg)
-+{
-+ netif_carrier_on(dev);
-+ if (msg)
-+ acxlog(L_BUFT, "tx: carrier on %s\n", msg);
-+}
-+
-+/* This function does not need locking UNLESS you call it
-+** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
-+** wake queue. This can race with stop_queue elsewhere. */
-+void acx_set_status(wlandevice_t *priv, u16 status);
-+
-+
-+/***********************************************************************
-+** Communication with firmware
-+*/
-+#define CMD_TIMEOUT_MS(n) (n)
-+#define ACX_CMD_TIMEOUT_DEFAULT CMD_TIMEOUT_MS(50)
-+
-+#if ACX_DEBUG
-+
-+/* We want to log cmd names */
-+int acxpci_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
-+int acxusb_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
-+static inline int
-+acx_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr)
-+{
-+#if defined(CONFIG_ACX_CFI)
-+ return acxpci_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
-+#else
-+ if (IS_PCI(priv))
-+ return acxpci_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
-+ return acxusb_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
-+#endif
-+}
-+#define acx_s_issue_cmd(priv,cmd,param,len) \
-+ acx_s_issue_cmd_timeo_debug(priv,cmd,param,len,ACX_CMD_TIMEOUT_DEFAULT,#cmd)
-+#define acx_s_issue_cmd_timeo(priv,cmd,param,len,timeo) \
-+ acx_s_issue_cmd_timeo_debug(priv,cmd,param,len,timeo,#cmd)
-+int acx_s_configure_debug(wlandevice_t *priv, void *pdr, int type, const char* str);
-+#define acx_s_configure(priv,pdr,type) \
-+ acx_s_configure_debug(priv,pdr,type,#type)
-+int acx_s_interrogate_debug(wlandevice_t *priv, void *pdr, int type, const char* str);
-+#define acx_s_interrogate(priv,pdr,type) \
-+ acx_s_interrogate_debug(priv,pdr,type,#type)
-+
-+#else
-+
-+int acxpci_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout);
-+int acxusb_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout);
-+static inline int
-+acx_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout)
-+{
-+ if (IS_PCI(priv))
-+ return acxpci_s_issue_cmd_timeo(priv, cmd, param, len, timeout);
-+ return acxusb_s_issue_cmd_timeo(priv, cmd, param, len, timeout);
-+}
-+static inline int
-+acx_s_issue_cmd(wlandevice_t *priv, unsigned cmd, void *param, unsigned len)
-+{
-+ if (IS_PCI(priv))
-+ return acxpci_s_issue_cmd_timeo(priv, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
-+ return acxusb_s_issue_cmd_timeo(priv, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
-+}
-+int acx_s_configure(wlandevice_t *priv, void *pdr, int type);
-+int acx_s_interrogate(wlandevice_t *priv, void *pdr, int type);
-+
-+#endif
-+
-+void acx_s_cmd_start_scan(wlandevice_t *priv);
-+
-+
-+/***********************************************************************
-+** Ioctls
-+*/
-+int
-+acx111pci_ioctl_info(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra);
-+int
-+acx100pci_ioctl_set_phy_amp_bias(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra);
-+
-+
-+/***********************************************************************
-+** Unsorted yet :)
-+*/
-+int acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf);
-+int acxusb_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf);
-+static inline int
-+acx_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
-+{
-+#if defined(CONFIG_ACX_CFI)
-+ return acxpci_s_read_phy_reg(priv, reg, charbuf);
-+#else
-+ if (IS_PCI(priv))
-+ return acxpci_s_read_phy_reg(priv, reg, charbuf);
-+ return acxusb_s_read_phy_reg(priv, reg, charbuf);
-+#endif
-+}
-+
-+int acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value);
-+int acxusb_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value);
-+static inline int
-+acx_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
-+{
-+#if defined(CONFIG_ACX_CFI)
-+ return acxpci_s_write_phy_reg(priv, reg, value);
-+#else
-+ if (IS_PCI(priv))
-+ return acxpci_s_write_phy_reg(priv, reg, value);
-+ return acxusb_s_write_phy_reg(priv, reg, value);
-+#endif
-+}
-+
-+void acx_s_msleep(int ms);
-+int acx_s_init_mac(netdevice_t *dev);
-+void acx_set_reg_domain(wlandevice_t *priv, unsigned char reg_dom_id);
-+void acx_set_timer(wlandevice_t *priv, int timeout_us);
-+void acx_update_capabilities(wlandevice_t *priv);
-+int acx_read_eeprom_offset(wlandevice_t *priv, u32 addr, u8 *charbuf);
-+void acx_s_start(wlandevice_t *priv);
-+#if USE_FW_LOADER_26
-+firmware_image_t *acx_s_read_fw(struct device *dev, const char *file, u32 *size);
-+#else
-+firmware_image_t *acx_s_read_fw(const char *file, u32 *size);
-+#define acx_s_read_fw(dev, file, size) acx_s_read_fw(file, size)
-+#endif
-+void acx_s_initialize_rx_config(wlandevice_t *priv);
-+void acx_s_update_card_settings(wlandevice_t *priv, int get_all, int set_all);
-+void acx_init_task_scheduler(wlandevice_t *priv);
-+void acx_schedule_after_interrupt_task(wlandevice_t *priv, unsigned int set_flag);
-+int acx_s_upload_radio(wlandevice_t *priv);
-+void acx_read_configoption(wlandevice_t *priv);
-+int acx_proc_register_entries(const struct net_device *dev);
-+int acx_proc_unregister_entries(const struct net_device *dev);
-+void acx_l_update_ratevector(wlandevice_t *priv);
-+
-+int acx_e_ioctl_old(netdevice_t *dev, struct ifreq *ifr, int cmd);
-+
-+client_t *acx_l_sta_list_get(wlandevice_t *priv, const u8 *address);
-+void acx_l_sta_list_del(wlandevice_t *priv, client_t *clt);
-+
-+int acx_l_transmit_disassoc(wlandevice_t *priv, client_t *clt);
-+void acx_i_timer(unsigned long a);
-+int acx_s_complete_scan(wlandevice_t *priv);
-+
-+static inline wlan_hdr_t*
-+acx_get_wlan_hdr(wlandevice_t *priv, const rxbuffer_t *rxbuf)
-+{
-+ if (!(priv->rx_config_1 & RX_CFG1_INCLUDE_PHY_HDR))
-+ return (wlan_hdr_t*)&rxbuf->hdr_a3;
-+
-+ /* take into account phy header in front of packet */
-+ if (IS_ACX111(priv))
-+ return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 8);
-+
-+ return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 4);
-+}
-+
-+struct sk_buff *acx_rxbuf_to_ether(struct wlandevice *priv, rxbuffer_t *rxbuf);
-+
-+void acx_l_power_led(wlandevice_t *priv, int enable);
-+
-+unsigned int acx_l_clean_tx_desc(wlandevice_t *priv);
-+void acx_l_clean_tx_desc_emergency(wlandevice_t *priv);
-+
-+u8 acx_signal_determine_quality(u8 signal, u8 noise);
-+
-+void acx_l_process_rxbuf(wlandevice_t *priv, rxbuffer_t *rxbuf);
-+void acx_l_process_rx_desc(wlandevice_t *priv);
-+
-+tx_t* acxpci_l_alloc_tx(wlandevice_t *priv);
-+tx_t* acxusb_l_alloc_tx(wlandevice_t *priv);
-+static inline tx_t*
-+acx_l_alloc_tx(wlandevice_t *priv)
-+{
-+#if defined(CONFIG_ACX_CFI)
-+ return acxpci_l_alloc_tx(priv);
-+#else
-+ if (IS_PCI(priv))
-+ return acxpci_l_alloc_tx(priv);
-+ return acxusb_l_alloc_tx(priv);
-+#endif
-+}
-+
-+void* acxpci_l_get_txbuf(wlandevice_t *priv, tx_t *tx_opaque);
-+void* acxusb_l_get_txbuf(wlandevice_t *priv, tx_t *tx_opaque);
-+static inline void*
-+acx_l_get_txbuf(wlandevice_t *priv, tx_t *tx_opaque)
-+{
-+#if defined(CONFIG_ACX_CFI)
-+ return acxpci_l_get_txbuf(priv, tx_opaque);
-+#else
-+ if (IS_PCI(priv))
-+ return acxpci_l_get_txbuf(priv, tx_opaque);
-+ return acxusb_l_get_txbuf(priv, tx_opaque);
-+#endif
-+}
-+
-+void acxpci_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len);
-+void acxusb_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len);
-+static inline void
-+acx_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len)
-+{
-+#if defined(CONFIG_ACX_CFI)
-+ acxpci_l_tx_data(priv, tx_opaque, len);
-+#else
-+ if (IS_PCI(priv))
-+ acxpci_l_tx_data(priv, tx_opaque, len);
-+ else
-+ acxusb_l_tx_data(priv, tx_opaque, len);
-+#endif
-+}
-+
-+void acx_dump_bytes(const void *, int);
-+void acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr);
-+
-+u8 acx_rate111to100(u16);
-+
-+void acx100usb_l_tx_data(wlandevice_t *priv, struct txdesc *desc);
-+int acx_s_set_defaults(wlandevice_t *priv);
-+void acx_init_mboxes(wlandevice_t *priv);
-+
-+int acx_l_ether_to_txbuf(wlandevice_t *priv, void *txbuf, const struct sk_buff *skb);
-+
-+#if !ACX_DEBUG
-+static inline const char* acx_get_packet_type_string(u16 fc) { return ""; }
-+#else
-+const char* acx_get_packet_type_string(u16 fc);
-+#endif
-+const char* acx_cmd_status_str(unsigned int state);
-+
-+int acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev);
-+void acx_free_desc_queues(wlandevice_t *priv);
-+
-+int acx_s_create_hostdesc_queues(wlandevice_t *priv);
-+void acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start);
-+
-+int acx100_s_init_wep(wlandevice_t *priv);
-+int acx100_s_init_packet_templates(wlandevice_t *priv);
-+int acx111_s_init_packet_templates(wlandevice_t *priv);
-+
-+void great_inquisitor(wlandevice_t *priv);
-+
-+char* acxpci_s_proc_diag_output(char *p, wlandevice_t *priv);
-+int acx_proc_eeprom_output(char *p, wlandevice_t *priv);
-+void acx_set_interrupt_mask(wlandevice_t *priv);
-+int acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm);
-+
-+#if defined(CONFIG_ACX_CFI)
-+int __init acxcfi_e_init_module(void);
-+#else
-+int __init acxpci_e_init_module(void);
-+int __init acxusb_e_init_module(void);
-+#endif
-+
-+#if defined(CONFIG_ACX_CFI)
-+void __exit acxcfi_e_cleanup_module(void);
-+#else
-+void __exit acxpci_e_cleanup_module(void);
-+void __exit acxusb_e_cleanup_module(void);
-+#endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx.h bt_kernel/drivers/net/wireless/tiacx/acx.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/acx.h 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,6 @@
-+#include "acx_config.h"
-+#include "wlan_compat.h"
-+#include "wlan_hdr.h"
-+#include "wlan_mgmt.h"
-+#include "acx_struct.h"
-+#include "acx_func.h"
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx_struct.h bt_kernel/drivers/net/wireless/tiacx/acx_struct.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/acx_struct.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/acx_struct.h 2005-10-29 22:02:44.690471000 +0300
-@@ -0,0 +1,1966 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+/***********************************************************************
-+** Forward declarations of types
-+*/
-+typedef struct tx tx_t;
-+typedef struct wlandevice wlandevice_t;
-+typedef struct client client_t;
-+typedef struct rxdesc rxdesc_t;
-+typedef struct txdesc txdesc_t;
-+typedef struct rxhostdesc rxhostdesc_t;
-+typedef struct txhostdesc txhostdesc_t;
-+
-+
-+/***********************************************************************
-+** Debug / log functionality
-+*/
-+enum {
-+ L_LOCK = (ACX_DEBUG>1)*0x0001, /* locking debug log */
-+ L_INIT = (ACX_DEBUG>0)*0x0002, /* special card initialization logging */
-+ L_IRQ = (ACX_DEBUG>0)*0x0004, /* interrupt stuff */
-+ L_ASSOC = (ACX_DEBUG>0)*0x0008, /* assocation (network join) and station log */
-+ L_FUNC = (ACX_DEBUG>1)*0x0020, /* logging of function enter / leave */
-+ L_XFER = (ACX_DEBUG>1)*0x0080, /* logging of transfers and mgmt */
-+ L_DATA = (ACX_DEBUG>1)*0x0100, /* logging of transfer data */
-+ L_DEBUG = (ACX_DEBUG>1)*0x0200, /* log of debug info */
-+ L_IOCTL = (ACX_DEBUG>0)*0x0400, /* log ioctl calls */
-+ L_CTL = (ACX_DEBUG>1)*0x0800, /* log of low-level ctl commands */
-+ L_BUFR = (ACX_DEBUG>1)*0x1000, /* debug rx buffer mgmt (ring buffer etc.) */
-+ L_XFER_BEACON = (ACX_DEBUG>1)*0x2000, /* also log beacon packets */
-+ L_BUFT = (ACX_DEBUG>1)*0x4000, /* debug tx buffer mgmt (ring buffer etc.) */
-+ L_USBRXTX = (ACX_DEBUG>0)*0x8000, /* debug USB rx/tx operations */
-+ L_BUF = L_BUFR + L_BUFT,
-+ L_ANY = 0xffff
-+};
-+
-+#if ACX_DEBUG
-+extern unsigned int acx_debug;
-+#else
-+enum { acx_debug = 0 };
-+#endif
-+
-+
-+/*============================================================================*
-+ * Random helpers *
-+ *============================================================================*/
-+#define ACX_PACKED __WLAN_ATTRIB_PACK__
-+
-+#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
-+
-+/* Use worker_queues for 2.5/2.6 Kernels and queue tasks for 2.4 Kernels
-+ (used for the 'bottom half' of the interrupt routine) */
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
-+#include <linux/workqueue.h>
-+/* #define NEWER_KERNELS_ONLY 1 */
-+#define USE_WORKER_TASKS
-+#define WORK_STRUCT struct work_struct
-+#define SCHEDULE_WORK schedule_work
-+#define FLUSH_SCHEDULED_WORK flush_scheduled_work
-+
-+#else
-+#include <linux/tqueue.h>
-+#define USE_QUEUE_TASKS
-+#define WORK_STRUCT struct tq_struct
-+#define SCHEDULE_WORK schedule_task
-+#define INIT_WORK(work, func, ndev) \
-+ do { \
-+ (work)->routine = (func); \
-+ (work)->data = (ndev); \
-+ } while (0)
-+#define FLUSH_SCHEDULED_WORK flush_scheduled_tasks
-+
-+#endif
-+
-+
-+/*============================================================================*
-+ * Constants *
-+ *============================================================================*/
-+#define OK 0
-+#define NOT_OK 1
-+
-+/* The supported chip models */
-+#define CHIPTYPE_ACX100 1
-+#define CHIPTYPE_ACX111 2
-+
-+#define IS_ACX100(priv) ((priv)->chip_type == CHIPTYPE_ACX100)
-+#define IS_ACX111(priv) ((priv)->chip_type == CHIPTYPE_ACX111)
-+
-+/* Supported interfaces */
-+#define DEVTYPE_PCI 0
-+#define DEVTYPE_USB 1
-+
-+#if defined(CONFIG_ACX_PCI)
-+ #if !defined(CONFIG_ACX_USB)
-+ #define IS_PCI(priv) 1
-+ #else
-+ #define IS_PCI(priv) ((priv)->dev_type == DEVTYPE_PCI)
-+ #endif
-+#else
-+ #define IS_PCI(priv) 0
-+#endif
-+
-+#if defined(CONFIG_ACX_USB)
-+ #if !defined(CONFIG_ACX_PCI)
-+ #define IS_USB(priv) 1
-+ #else
-+ #define IS_USB(priv) ((priv)->dev_type == DEVTYPE_USB)
-+ #endif
-+#else
-+ #define IS_USB(priv) 0
-+#endif
-+
-+/* Driver defaults */
-+#define DEFAULT_DTIM_INTERVAL 10
-+/* used to be 2048, but FreeBSD driver changed it to 4096 to work properly
-+** in noisy wlans */
-+#define DEFAULT_MSDU_LIFETIME 4096
-+#define DEFAULT_RTS_THRESHOLD 2312 /* max. size: disable RTS mechanism */
-+#define DEFAULT_BEACON_INTERVAL 100
-+
-+#define ACX100_BAP_DATALEN_MAX 4096
-+#define ACX100_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */
-+#define ACX100_RIDDATA_MAXLEN ACX100_RID_GUESSING_MAXLEN
-+
-+/* Support Constants */
-+/* Radio type names, found in Win98 driver's TIACXLN.INF */
-+#define RADIO_MAXIM_0D 0x0d
-+#define RADIO_RFMD_11 0x11
-+#define RADIO_RALINK_15 0x15
-+/* used in ACX111 cards (WG311v2, WL-121, ...): */
-+#define RADIO_RADIA_16 0x16
-+/* most likely *sometimes* used in ACX111 cards: */
-+#define RADIO_UNKNOWN_17 0x17
-+/* FwRad19.bin was found in a Safecom driver; must be an ACX111 radio: */
-+#define RADIO_UNKNOWN_19 0x19
-+
-+/* Controller Commands */
-+/* can be found in table cmdTable in firmware "Rev. 1.5.0" (FW150) */
-+#define ACX1xx_CMD_RESET 0x00
-+#define ACX1xx_CMD_INTERROGATE 0x01
-+#define ACX1xx_CMD_CONFIGURE 0x02
-+#define ACX1xx_CMD_ENABLE_RX 0x03
-+#define ACX1xx_CMD_ENABLE_TX 0x04
-+#define ACX1xx_CMD_DISABLE_RX 0x05
-+#define ACX1xx_CMD_DISABLE_TX 0x06
-+#define ACX1xx_CMD_FLUSH_QUEUE 0x07
-+#define ACX1xx_CMD_SCAN 0x08
-+#define ACX1xx_CMD_STOP_SCAN 0x09
-+#define ACX1xx_CMD_CONFIG_TIM 0x0a
-+#define ACX1xx_CMD_JOIN 0x0b
-+#define ACX1xx_CMD_WEP_MGMT 0x0c
-+#ifdef OLD_FIRMWARE_VERSIONS
-+#define ACX100_CMD_HALT 0x0e /* mapped to unknownCMD in FW150 */
-+#else
-+#define ACX1xx_CMD_MEM_READ 0x0d
-+#define ACX1xx_CMD_MEM_WRITE 0x0e
-+#endif
-+#define ACX1xx_CMD_SLEEP 0x0f
-+#define ACX1xx_CMD_WAKE 0x10
-+#define ACX1xx_CMD_UNKNOWN_11 0x11 /* mapped to unknownCMD in FW150 */
-+#define ACX100_CMD_INIT_MEMORY 0x12
-+#define ACX1xx_CMD_CONFIG_BEACON 0x13
-+#define ACX1xx_CMD_CONFIG_PROBE_RESPONSE 0x14
-+#define ACX1xx_CMD_CONFIG_NULL_DATA 0x15
-+#define ACX1xx_CMD_CONFIG_PROBE_REQUEST 0x16
-+#define ACX1xx_CMD_TEST 0x17
-+#define ACX1xx_CMD_RADIOINIT 0x18
-+#define ACX111_CMD_RADIOCALIB 0x19
-+
-+/* 'After Interrupt' Commands */
-+#define ACX_AFTER_IRQ_CMD_STOP_SCAN 0x01
-+#define ACX_AFTER_IRQ_CMD_ASSOCIATE 0x02
-+#define ACX_AFTER_IRQ_CMD_RADIO_RECALIB 0x04
-+#define ACX_AFTER_IRQ_UPDATE_CARD_CFG 0x08
-+#define ACX_AFTER_IRQ_TX_CLEANUP 0x10
-+#define ACX_AFTER_IRQ_COMPLETE_SCAN 0x20
-+#define ACX_AFTER_IRQ_RESTART_SCAN 0x40
-+
-+/***********************************************************************
-+** Tx/Rx buffer sizes and watermarks
-+*/
-+/* BTW, this will alloc and use DMAable buffers of
-+** WLAN_A4FR_MAXLEN_WEP_FCS * (RX_CNT + TX_CNT) bytes
-+** RX/TX_CNT=32 -> ~150k DMA buffers
-+** RX/TX_CNT=16 -> ~75k DMA buffers
-+*/
-+#define RX_CNT 32
-+#define TX_CNT 32
-+
-+/* we clean up txdescs when we have N free txdesc: */
-+#define TX_START_CLEAN (TX_CNT - (TX_CNT/4))
-+#define TX_EMERG_CLEAN 2
-+/* we stop queue if we have less than N free txbufs: */
-+#define TX_STOP_QUEUE 3
-+/* we start queue if we have more than N free txbufs: */
-+#define TX_START_QUEUE 6
-+
-+/***********************************************************************
-+** Interrogate/Configure cmd constants
-+**
-+** NB: length includes JUST the data part of the IE
-+** (does not include size of the (type,len) pair)
-+**
-+** TODO: seems that acx100, acx100usb, acx111 have some differences,
-+** fix code with regard to this!
-+*/
-+
-+#define DEF_IE(name, val, len) enum { ACX##name=val, ACX##name##_LEN=len }
-+
-+/* Information Elements: Network Parameters, Static Configuration Entities */
-+/* these are handled by real_cfgtable in firmware "Rev 1.5.0" (FW150) */
-+DEF_IE(1xx_IE_UNKNOWN_00 ,0x0000, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(100_IE_ACX_TIMER ,0x0001, 0x10);
-+DEF_IE(1xx_IE_POWER_MGMT ,0x0002, 0x06);
-+DEF_IE(1xx_IE_QUEUE_CONFIG ,0x0003, 0x1c);
-+DEF_IE(100_IE_BLOCK_SIZE ,0x0004, 0x02);
-+DEF_IE(1xx_IE_MEMORY_CONFIG_OPTIONS ,0x0005, 0x14);
-+DEF_IE(1xx_IE_RATE_FALLBACK ,0x0006, 0x01);
-+DEF_IE(100_IE_WEP_OPTIONS ,0x0007, 0x03);
-+DEF_IE(111_IE_RADIO_BAND ,0x0007, -1);
-+DEF_IE(1xx_IE_MEMORY_MAP ,0x0008, 0x28); /* huh? */
-+DEF_IE(100_IE_SSID ,0x0008, 0x20); /* huh? */
-+DEF_IE(1xx_IE_SCAN_STATUS ,0x0009, 0x04); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(1xx_IE_ASSOC_ID ,0x000a, 0x02);
-+DEF_IE(1xx_IE_UNKNOWN_0B ,0x000b, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(100_IE_UNKNOWN_0C ,0x000c, -1); /* very small implementation in FW150! */
-+DEF_IE(111_IE_CONFIG_OPTIONS ,0x000c, 0x14c);
-+DEF_IE(1xx_IE_FWREV ,0x000d, 0x18);
-+DEF_IE(1xx_IE_FCS_ERROR_COUNT ,0x000e, 0x04);
-+DEF_IE(1xx_IE_MEDIUM_USAGE ,0x000f, 0x08);
-+DEF_IE(1xx_IE_RXCONFIG ,0x0010, 0x04);
-+DEF_IE(100_IE_UNKNOWN_11 ,0x0011, -1); /* NONBINARY: large implementation in FW150! link quality readings or so? */
-+DEF_IE(111_IE_QUEUE_THRESH ,0x0011, -1);
-+DEF_IE(100_IE_UNKNOWN_12 ,0x0012, -1); /* NONBINARY: VERY large implementation in FW150!! */
-+DEF_IE(111_IE_BSS_POWER_SAVE ,0x0012, -1);
-+DEF_IE(1xx_IE_FIRMWARE_STATISTICS ,0x0013, 0x9c);
-+DEF_IE(1xx_IE_FEATURE_CONFIG ,0x0015, 0x08);
-+DEF_IE(111_IE_KEY_CHOOSE ,0x0016, 0x04); /* for rekeying. really len=4?? */
-+DEF_IE(1xx_IE_DOT11_STATION_ID ,0x1001, 0x06);
-+DEF_IE(100_IE_DOT11_UNKNOWN_1002 ,0x1002, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(111_IE_DOT11_FRAG_THRESH ,0x1002, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(100_IE_DOT11_BEACON_PERIOD ,0x1003, 0x02); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(1xx_IE_DOT11_DTIM_PERIOD ,0x1004, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(1xx_IE_DOT11_SHORT_RETRY_LIMIT ,0x1005, 0x01);
-+DEF_IE(1xx_IE_DOT11_LONG_RETRY_LIMIT ,0x1006, 0x01);
-+DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE ,0x1007, 0x20); /* configure default keys */
-+DEF_IE(1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME ,0x1008, 0x04);
-+DEF_IE(1xx_IE_DOT11_GROUP_ADDR ,0x1009, -1);
-+DEF_IE(1xx_IE_DOT11_CURRENT_REG_DOMAIN ,0x100a, 0x02);
-+//It's harmless to have larger struct. Use USB case always.
-+////#ifdef ACX_PCI
-+////DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA ,0x100b, 0x01);
-+////#else
-+DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA ,0x100b, 0x02);
-+////#endif
-+DEF_IE(1xx_IE_DOT11_UNKNOWN_100C ,0x100c, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(1xx_IE_DOT11_TX_POWER_LEVEL ,0x100d, 0x01);
-+////#ifdef ACX_PCI
-+////DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE ,0x100e, 0x01);
-+////#else
-+DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE ,0x100e, 0x02);
-+////#endif
-+//USB doesn't return anything - len==0?!
-+DEF_IE(100_IE_DOT11_ED_THRESHOLD ,0x100f, 0x04);
-+DEF_IE(1xx_IE_DOT11_WEP_DEFAULT_KEY_SET ,0x1010, 0x01); /* set default key ID */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1011 ,0x1011, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1012 ,0x1012, -1); /* mapped to cfgInvalid in FW150 */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1013 ,0x1013, -1); /* mapped to cfgInvalid in FW150 */
-+
-+#if 0
-+/* Experimentally obtained on acx100, fw 1.9.8.b
-+** -1 means that fw returned 'invalid IE'
-+** 0200 FC00 nnnn... are test read contents: u16 type, u16 len, data
-+** (AA are poison bytes marking bytes not written by fw)
-+**
-+** Looks like acx100 fw does not update len field (thus len=256-4=FC here)
-+** A number of IEs seem to trash type,len fields
-+** IEs marked 'huge' return gobs of data (no poison bytes remain)
-+*/
-+DEF_IE(100_IE_INVAL_00, 0x0000, -1);
-+DEF_IE(100_IE_INVAL_01, 0x0001, -1); /* IE_ACX_TIMER, len=16 on older fw */
-+DEF_IE(100_IE_POWER_MGMT, 0x0002, 4); /* 0200FC00 00040000 AAAAAAAA */
-+DEF_IE(100_IE_QUEUE_CONFIG, 0x0003, 28); /* 0300FC00 48060000 9CAD0000 0101AAAA DCB00000 E4B00000 9CAA0000 00AAAAAA */
-+DEF_IE(100_IE_BLOCK_SIZE, 0x0004, 2); /* 0400FC00 0001AAAA AAAAAAAA AAAAAAAA */
-+/* write only: */
-+DEF_IE(100_IE_MEMORY_CONFIG_OPTIONS, 0x0005, 20);
-+DEF_IE(100_IE_RATE_FALLBACK, 0x0006, 1); /* 0600FC00 00AAAAAA AAAAAAAA AAAAAAAA */
-+/* write only: */
-+DEF_IE(100_IE_WEP_OPTIONS, 0x0007, 3);
-+DEF_IE(100_IE_MEMORY_MAP, 0x0008, 40); /* huge: 0800FC00 30000000 6CA20000 70A20000... */
-+/* gives INVAL on read: */
-+DEF_IE(100_IE_SCAN_STATUS, 0x0009, -1);
-+DEF_IE(100_IE_ASSOC_ID, 0x000a, 2); /* huge: 0A00FC00 00000000 01040800 00000000... */
-+DEF_IE(100_IE_INVAL_0B, 0x000b, -1);
-+/* 'command rejected': */
-+DEF_IE(100_IE_CONFIG_OPTIONS, 0x000c, -3);
-+DEF_IE(100_IE_FWREV, 0x000d, 24); /* 0D00FC00 52657620 312E392E 382E6200 AAAAAAAA AAAAAAAA 05050201 AAAAAAAA */
-+DEF_IE(100_IE_FCS_ERROR_COUNT, 0x000e, 4);
-+DEF_IE(100_IE_MEDIUM_USAGE, 0x000f, 8); /* E41F0000 2D780300 FCC91300 AAAAAAAA */
-+DEF_IE(100_IE_RXCONFIG, 0x0010, 4); /* 1000FC00 00280000 AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_QUEUE_THRESH, 0x0011, 12); /* 1100FC00 AAAAAAAA 00000000 00000000 */
-+DEF_IE(100_IE_BSS_POWER_SAVE, 0x0012, 1); /* 1200FC00 00AAAAAA AAAAAAAA AAAAAAAA */
-+/* read only, variable len */
-+DEF_IE(100_IE_FIRMWARE_STATISTICS, 0x0013, 256); /* 0000AC00 00000000 ... */
-+DEF_IE(100_IE_INT_CONFIG, 0x0014, 20); /* 00000000 00000000 00000000 00000000 5D74D105 00000000 AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_FEATURE_CONFIG, 0x0015, 8); /* 1500FC00 16000000 AAAAAAAA AAAAAAAA */
-+/* returns 'invalid MAC': */
-+DEF_IE(100_IE_KEY_CHOOSE, 0x0016, -4);
-+DEF_IE(100_IE_INVAL_17, 0x0017, -1);
-+DEF_IE(100_IE_UNKNOWN_18, 0x0018, 0); /* null len?! 1800FC00 AAAAAAAA AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_UNKNOWN_19, 0x0019, 256); /* huge: 1900FC00 9C1F00EA FEFFFFEA FEFFFFEA... */
-+DEF_IE(100_IE_INVAL_1A, 0x001A, -1);
-+
-+DEF_IE(100_IE_DOT11_INVAL_1000, 0x1000, -1);
-+DEF_IE(100_IE_DOT11_STATION_ID, 0x1001, 6); /* huge: 0110FC00 58B10E2F 03000000 00000000... */
-+DEF_IE(100_IE_DOT11_INVAL_1002, 0x1002, -1);
-+DEF_IE(100_IE_DOT11_INVAL_1003, 0x1003, -1);
-+DEF_IE(100_IE_DOT11_INVAL_1004, 0x1004, -1);
-+DEF_IE(100_IE_DOT11_SHORT_RETRY_LIMIT, 0x1005, 1);
-+DEF_IE(100_IE_DOT11_LONG_RETRY_LIMIT, 0x1006, 1);
-+/* write only: */
-+DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE, 0x1007, 32);
-+DEF_IE(100_IE_DOT11_MAX_XMIT_MSDU_LIFETIME, 0x1008, 4); /* huge: 0810FC00 00020000 F4010000 00000000... */
-+/* undoc but returns something */
-+DEF_IE(100_IE_DOT11_GROUP_ADDR, 0x1009, 12); /* huge: 0910FC00 00000000 00000000 00000000... */
-+DEF_IE(100_IE_DOT11_CURRENT_REG_DOMAIN, 0x100a, 1); /* 0A10FC00 30AAAAAA AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_DOT11_CURRENT_ANTENNA, 0x100b, 1); /* 0B10FC00 8FAAAAAA AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_DOT11_INVAL_100C, 0x100c, -1);
-+DEF_IE(100_IE_DOT11_TX_POWER_LEVEL, 0x100d, 2); /* 00000000 0100AAAA AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_DOT11_CURRENT_CCA_MODE, 0x100e, 1); /* 0E10FC00 0DAAAAAA AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_DOT11_ED_THRESHOLD, 0x100f, 4); /* 0F10FC00 70000000 AAAAAAAA AAAAAAAA */
-+/* set default key ID */
-+DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_SET, 0x1010, 1); /* 1010FC00 00AAAAAA AAAAAAAA AAAAAAAA */
-+DEF_IE(100_IE_DOT11_INVAL_1011, 0x1011, -1);
-+DEF_IE(100_IE_DOT11_INVAL_1012, 0x1012, -1);
-+DEF_IE(100_IE_DOT11_INVAL_1013, 0x1013, -1);
-+DEF_IE(100_IE_DOT11_UNKNOWN_1014, 0x1014, 256); /* huge */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1015, 0x1015, 256); /* huge */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1016, 0x1016, 256); /* huge */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1017, 0x1017, 256); /* huge */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1018, 0x1018, 256); /* huge */
-+DEF_IE(100_IE_DOT11_UNKNOWN_1019, 0x1019, 256); /* huge */
-+#endif
-+
-+#if 0
-+/* Experimentally obtained on PCI acx111 Xterasys XN-2522g, fw 1.2.1.34
-+** -1 means that fw returned 'invalid IE'
-+** 0400 0800 nnnn... are test read contents: u16 type, u16 len, data
-+** (AA are poison bytes marking bytes not written by fw)
-+**
-+** Looks like acx111 fw reports real len!
-+*/
-+DEF_IE(111_IE_INVAL_00, 0x0000, -1);
-+DEF_IE(111_IE_INVAL_01, 0x0001, -1);
-+DEF_IE(111_IE_POWER_MGMT, 0x0002, 12);
-+/* write only, variable len: 12 + rxqueue_cnt*8 + txqueue_cnt*4: */
-+DEF_IE(111_IE_MEMORY_CONFIG, 0x0003, 24);
-+DEF_IE(111_IE_BLOCK_SIZE, 0x0004, 8); /* 04000800 AA00AAAA AAAAAAAA */
-+/* variable len: 8 + rxqueue_cnt*8 + txqueue_cnt*8: */
-+DEF_IE(111_IE_QUEUE_HEAD, 0x0005, 24);
-+DEF_IE(111_IE_RATE_FALLBACK, 0x0006, 1);
-+/* acx100 name:WEP_OPTIONS */
-+/* said to have len:1 (not true, actually returns 12 bytes): */
-+DEF_IE(111_IE_RADIO_BAND, 0x0007, 12); /* 07000C00 AAAA1F00 FF03AAAA AAAAAAAA */
-+DEF_IE(111_IE_MEMORY_MAP, 0x0008, 48);
-+/* said to have len:4, but gives INVAL on read: */
-+DEF_IE(111_IE_SCAN_STATUS, 0x0009, -1);
-+DEF_IE(111_IE_ASSOC_ID, 0x000a, 2);
-+/* write only, len is not known: */
-+DEF_IE(111_IE_UNKNOWN_0B, 0x000b, 0);
-+/* read only, variable len. I see 67 byte reads: */
-+DEF_IE(111_IE_CONFIG_OPTIONS, 0x000c, 67); /* 0C004300 01160500 ... */
-+DEF_IE(111_IE_FWREV, 0x000d, 24);
-+DEF_IE(111_IE_FCS_ERROR_COUNT, 0x000e, 4);
-+DEF_IE(111_IE_MEDIUM_USAGE, 0x000f, 8);
-+DEF_IE(111_IE_RXCONFIG, 0x0010, 4);
-+DEF_IE(111_IE_QUEUE_THRESH, 0x0011, 12);
-+DEF_IE(111_IE_BSS_POWER_SAVE, 0x0012, 1);
-+/* read only, variable len. I see 240 byte reads: */
-+DEF_IE(111_IE_FIRMWARE_STATISTICS, 0x0013, 240); /* 1300F000 00000000 ... */
-+/* said to have len=17. looks like fw pads it to 20: */
-+DEF_IE(111_IE_INT_CONFIG, 0x0014, 20); /* 14001400 00000000 00000000 00000000 00000000 00000000 */
-+DEF_IE(111_IE_FEATURE_CONFIG, 0x0015, 8);
-+/* said to be name:KEY_INDICATOR, len:4, but gives INVAL on read: */
-+DEF_IE(111_IE_KEY_CHOOSE, 0x0016, -1);
-+/* said to have len:4, but in fact returns 8: */
-+DEF_IE(111_IE_MAX_USB_XFR, 0x0017, 8); /* 17000800 00014000 00000000 */
-+DEF_IE(111_IE_INVAL_18, 0x0018, -1);
-+DEF_IE(111_IE_INVAL_19, 0x0019, -1);
-+/* undoc but returns something: */
-+/* huh, fw indicates len=20 but uses 4 more bytes in buffer??? */
-+DEF_IE(111_IE_UNKNOWN_1A, 0x001A, 20); /* 1A001400 AA00AAAA 0000020F FF030000 00020000 00000007 04000000 */
-+
-+DEF_IE(111_IE_DOT11_INVAL_1000, 0x1000, -1);
-+DEF_IE(111_IE_DOT11_STATION_ID, 0x1001, 6);
-+DEF_IE(111_IE_DOT11_FRAG_THRESH, 0x1002, 2);
-+/* acx100 only? gives INVAL on read: */
-+DEF_IE(111_IE_DOT11_BEACON_PERIOD, 0x1003, -1);
-+/* said to be MAX_RECV_MSDU_LIFETIME: */
-+DEF_IE(111_IE_DOT11_DTIM_PERIOD, 0x1004, 4);
-+DEF_IE(111_IE_DOT11_SHORT_RETRY_LIMIT, 0x1005, 1);
-+DEF_IE(111_IE_DOT11_LONG_RETRY_LIMIT, 0x1006, 1);
-+/* acx100 only? gives INVAL on read: */
-+DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_WRITE, 0x1007, -1);
-+DEF_IE(111_IE_DOT11_MAX_XMIT_MSDU_LIFETIME, 0x1008, 4);
-+/* undoc but returns something. maybe it's 2 multicast MACs to listen to? */
-+DEF_IE(111_IE_DOT11_GROUP_ADDR, 0x1009, 12); /* 09100C00 00000000 00000000 00000000 */
-+DEF_IE(111_IE_DOT11_CURRENT_REG_DOMAIN, 0x100a, 1);
-+DEF_IE(111_IE_DOT11_CURRENT_ANTENNA, 0x100b, 2);
-+DEF_IE(111_IE_DOT11_INVAL_100C, 0x100c, -1);
-+DEF_IE(111_IE_DOT11_TX_POWER_LEVEL, 0x100d, 1);
-+/* said to have len=1 but gives INVAL on read: */
-+DEF_IE(111_IE_DOT11_CURRENT_CCA_MODE, 0x100e, -1);
-+/* said to have len=4 but gives INVAL on read: */
-+DEF_IE(111_IE_DOT11_ED_THRESHOLD, 0x100f, -1);
-+/* set default key ID. write only: */
-+DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_SET, 0x1010, 1);
-+/* undoc but returns something: */
-+DEF_IE(111_IE_DOT11_UNKNOWN_1011, 0x1011, 1); /* 11100100 20 */
-+DEF_IE(111_IE_DOT11_INVAL_1012, 0x1012, -1);
-+DEF_IE(111_IE_DOT11_INVAL_1013, 0x1013, -1);
-+#endif
-+
-+
-+/*============================================================================*
-+ * Information Frames Structures *
-+ *============================================================================*/
-+
-+/* Used in beacon frames and the like */
-+#define DOT11RATEBYTE_1 (1*2)
-+#define DOT11RATEBYTE_2 (2*2)
-+#define DOT11RATEBYTE_5_5 (5*2+1)
-+#define DOT11RATEBYTE_11 (11*2)
-+#define DOT11RATEBYTE_22 (22*2)
-+#define DOT11RATEBYTE_6_G (6*2)
-+#define DOT11RATEBYTE_9_G (9*2)
-+#define DOT11RATEBYTE_12_G (12*2)
-+#define DOT11RATEBYTE_18_G (18*2)
-+#define DOT11RATEBYTE_24_G (24*2)
-+#define DOT11RATEBYTE_36_G (36*2)
-+#define DOT11RATEBYTE_48_G (48*2)
-+#define DOT11RATEBYTE_54_G (54*2)
-+#define DOT11RATEBYTE_BASIC 0x80 /* flags rates included in basic rate set */
-+
-+
-+/***********************************************************************
-+** rxbuffer_t
-+**
-+** This is the format of rx data returned by acx
-+*/
-+
-+/* I've hoped it's a 802.11 PHY header, but no...
-+ * so far, I've seen on acx111:
-+ * 0000 3a00 0000 0000 IBBS Beacons
-+ * 0000 3c00 0000 0000 ESS Beacons
-+ * 0000 2700 0000 0000 Probe requests
-+ * --vda
-+ */
-+typedef struct phy_hdr {
-+ u8 unknown[4] ACX_PACKED;
-+ u8 acx111_unknown[4] ACX_PACKED;
-+} phy_hdr_t;
-+
-+/* seems to be a bit similar to hfa384x_rx_frame.
-+ * These fields are still not quite obvious, though.
-+ * Some seem to have different meanings... */
-+
-+#define RXBUF_HDRSIZE 12
-+#define PHY_HDR(rxbuf) ((phy_hdr_t*)&rxbuf->hdr_a3)
-+#define RXBUF_BYTES_RCVD(rxbuf) (le16_to_cpu(rxbuf->mac_cnt_rcvd) & 0xfff)
-+#define RXBUF_BYTES_USED(rxbuf) \
-+ ((le16_to_cpu(rxbuf->mac_cnt_rcvd) & 0xfff) + RXBUF_HDRSIZE)
-+/*
-+mac_cnt_rcvd:
-+ 12 bits: length of frame from control field to last byte of FCS
-+ 4 bits: reserved
-+
-+mac_cnt_mblks:
-+ 6 bits: number of memory block used to store frame in adapter memory
-+ 1 bit: Traffic Indicator bit in TIM of received Beacon was set
-+
-+mac_status: 1 byte (bitmap):
-+ 7 Matching BSSID
-+ 6 Matching SSID
-+ 5 BDCST Address 1 field is a broadcast
-+ 4 VBM received beacon frame has more than one set bit (?!)
-+ 3 TIM Set bit representing this station is set in TIM of received beacon
-+ 2 GROUP Address 1 is a multicast
-+ 1 ADDR1 Address 1 matches our MAC
-+ 0 FCSGD FSC is good
-+
-+phy_stat_baseband: 1 byte (bitmap):
-+ 7 Preamble frame had a long preamble
-+ 6 PLCP Error CRC16 error in PLCP header
-+ 5 Unsup_Mod unsupported modulation
-+ 4 Selected Antenna antenna 1 was used to receive this frame
-+ 3 PBCC/CCK frame used: 1=PBCC, 0=CCK modulation
-+ 2 OFDM frame used OFDM modulation
-+ 1 TI Protection protection frame was detected
-+ 0 Reserved
-+
-+phy_plcp_signal: 1 byte:
-+ Receive PLCP Signal field from the Baseband Processor
-+
-+phy_level: 1 byte:
-+ receive AGC gain level (can be used to measure receive signal strength)
-+
-+phy_snr: 1 byte:
-+ estimated noise power of equalized receive signal
-+ at input of FEC decoder (can be used to measure receive signal quality)
-+
-+time: 4 bytes:
-+ timestamp sampled from either the Access Manager TSF counter
-+ or free-running microsecond counter when the MAC receives
-+ first byte of PLCP header.
-+*/
-+
-+typedef struct rxbuffer {
-+ u16 mac_cnt_rcvd ACX_PACKED; /* only 12 bits are len! (0xfff) */
-+ u8 mac_cnt_mblks ACX_PACKED;
-+ u8 mac_status ACX_PACKED;
-+ u8 phy_stat_baseband ACX_PACKED; /* bit 0x80: used LNA (Low-Noise Amplifier) */
-+ u8 phy_plcp_signal ACX_PACKED;
-+ u8 phy_level ACX_PACKED; /* PHY stat */
-+ u8 phy_snr ACX_PACKED; /* PHY stat */
-+ u32 time ACX_PACKED; /* timestamp upon MAC rcv first byte */
-+/* 4-byte (acx100) or 8-byte (acx111) phy header will be here
-+** if RX_CFG1_INCLUDE_PHY_HDR is in effect:
-+** phy_hdr_t phy */
-+ wlan_hdr_a3_t hdr_a3 ACX_PACKED;
-+ /* maximally sized data part of wlan packet */
-+ u8 data_a3[WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN] ACX_PACKED;
-+ /* can add hdr/data_a4 if needed */
-+} rxbuffer_t;
-+
-+
-+/*--- Firmware statistics ----------------------------------------------------*/
-+typedef struct fw_stats {
-+ u32 val0x0 ACX_PACKED; /* hdr; */
-+ u32 tx_desc_of ACX_PACKED;
-+ u32 rx_oom ACX_PACKED;
-+ u32 rx_hdr_of ACX_PACKED;
-+ u32 rx_hdr_use_next ACX_PACKED;
-+ u32 rx_dropped_frame ACX_PACKED;
-+ u32 rx_frame_ptr_err ACX_PACKED;
-+ u32 rx_xfr_hint_trig ACX_PACKED;
-+
-+ u32 rx_dma_req ACX_PACKED;
-+ u32 rx_dma_err ACX_PACKED;
-+ u32 tx_dma_req ACX_PACKED;
-+ u32 tx_dma_err ACX_PACKED;
-+
-+ u32 cmd_cplt ACX_PACKED;
-+ u32 fiq ACX_PACKED;
-+ u32 rx_hdrs ACX_PACKED;
-+ u32 rx_cmplt ACX_PACKED;
-+ u32 rx_mem_of ACX_PACKED;
-+ u32 rx_rdys ACX_PACKED;
-+ u32 irqs ACX_PACKED;
-+ u32 acx_trans_procs ACX_PACKED;
-+ u32 decrypt_done ACX_PACKED;
-+ u32 dma_0_done ACX_PACKED;
-+ u32 dma_1_done ACX_PACKED;
-+ u32 tx_exch_complet ACX_PACKED;
-+ u32 commands ACX_PACKED;
-+ u32 acx_rx_procs ACX_PACKED;
-+ u32 hw_pm_mode_changes ACX_PACKED;
-+ u32 host_acks ACX_PACKED;
-+ u32 pci_pm ACX_PACKED;
-+ u32 acm_wakeups ACX_PACKED;
-+
-+ u32 wep_key_count ACX_PACKED;
-+ u32 wep_default_key_count ACX_PACKED;
-+ u32 dot11_def_key_mib ACX_PACKED;
-+ u32 wep_key_not_found ACX_PACKED;
-+ u32 wep_decrypt_fail ACX_PACKED;
-+} fw_stats_t;
-+
-+/* Firmware version struct */
-+
-+typedef struct fw_ver {
-+ u16 cmd ACX_PACKED;
-+ u16 size ACX_PACKED;
-+ char fw_id[20] ACX_PACKED;
-+ u32 hw_id ACX_PACKED;
-+} fw_ver_t;
-+
-+#define FW_ID_SIZE 20
-+
-+
-+/*--- WEP stuff --------------------------------------------------------------*/
-+#define DOT11_MAX_DEFAULT_WEP_KEYS 4
-+
-+/* non-firmware struct, no packing necessary */
-+typedef struct wep_key {
-+ size_t size; /* most often used member first */
-+ u8 index;
-+ u8 key[29];
-+ u16 strange_filler;
-+} wep_key_t; /* size = 264 bytes (33*8) */
-+/* FIXME: We don't have size 264! Or is there 2 bytes beyond the key
-+ * (strange_filler)? */
-+
-+/* non-firmware struct, no packing necessary */
-+typedef struct key_struct {
-+ u8 addr[ETH_ALEN]; /* 0x00 */
-+ u16 filler1; /* 0x06 */
-+ u32 filler2; /* 0x08 */
-+ u32 index; /* 0x0c */
-+ u16 len; /* 0x10 */
-+ u8 key[29]; /* 0x12; is this long enough??? */
-+} key_struct_t; /* size = 276. FIXME: where is the remaining space?? */
-+
-+
-+/*--- Client (peer) info -----------------------------------------------------*/
-+/* priv->sta_list[] is used for:
-+** accumulating and processing of scan results
-+** keeping client info in AP mode
-+** keeping AP info in STA mode (AP is the only one 'client')
-+** keeping peer info in ad-hoc mode
-+** non-firmware struct --> no packing necessary */
-+enum {
-+ CLIENT_EMPTY_SLOT_0 = 0,
-+ CLIENT_EXIST_1 = 1,
-+ CLIENT_AUTHENTICATED_2 = 2,
-+ CLIENT_ASSOCIATED_3 = 3,
-+ CLIENT_JOIN_CANDIDATE = 4
-+};
-+struct client {
-+ struct client* next;
-+ unsigned long mtime; /* last time we heard it, in jiffies */
-+ size_t essid_len; /* length of ESSID (without '\0') */
-+ u32 sir; /* Standard IR */
-+ u32 snr; /* Signal to Noise Ratio */
-+ u16 aid; /* association ID */
-+ u16 seq; /* from client's auth req */
-+ u16 auth_alg; /* from client's auth req */
-+ u16 cap_info; /* from client's assoc req */
-+ u16 rate_cap; /* what client supports (all rates) */
-+ u16 rate_bas; /* what client supports (basic rates) */
-+ u16 rate_cfg; /* what is allowed (by iwconfig etc) */
-+ u16 rate_cur; /* currently used rate mask */
-+ u8 rate_100; /* currently used rate byte (acx100 only) */
-+ u8 used; /* misnamed, more like 'status' */
-+ u8 address[ETH_ALEN];
-+ u8 bssid[ETH_ALEN]; /* ad-hoc hosts can have bssid != mac */
-+ u8 channel;
-+ u8 auth_step;
-+ u8 ignore_count;
-+ u8 fallback_count;
-+ u8 stepup_count;
-+ char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID and trailing '\0' */
-+/* FIXME: this one is too damn big */
-+ char challenge_text[WLAN_CHALLENGE_LEN];
-+};
-+
-+
-+/*============================================================================*
-+ * Hardware structures *
-+ *============================================================================*/
-+
-+/* An opaque typesafe helper type
-+ *
-+ * Some hardware fields are actually pointers,
-+ * but they have to remain u32, since using ptr instead
-+ * (8 bytes on 64bit systems!) would disrupt the fixed descriptor
-+ * format the acx firmware expects in the non-user area.
-+ * Since we cannot cram an 8 byte ptr into 4 bytes, we need to
-+ * enforce that pointed to data remains in low memory
-+ * (address value needs to fit in 4 bytes) on 64bit systems.
-+ *
-+ * This is easy to get wrong, thus we are using a small struct
-+ * and special macros to access it. Macros will check for
-+ * attempts to overflow an acx_ptr with value > 0xffffffff.
-+ *
-+ * Attempts to use acx_ptr without macros result in compile-time errors */
-+
-+typedef struct {
-+ u32 v ACX_PACKED;
-+} acx_ptr;
-+
-+#if ACX_DEBUG
-+#define CHECK32(n) BUG_ON(sizeof(n)>4 && (long)(n)>0xffffff00)
-+#else
-+#define CHECK32(n) ((void)0)
-+#endif
-+
-+/* acx_ptr <-> integer conversion */
-+#define cpu2acx(n) ({ CHECK32(n); ((acx_ptr){ .v = cpu_to_le32(n) }); })
-+#define acx2cpu(a) (le32_to_cpu(a.v))
-+
-+/* acx_ptr <-> pointer conversion */
-+#define ptr2acx(p) ({ CHECK32(p); ((acx_ptr){ .v = cpu_to_le32((u32)(long)(p)) }); })
-+#define acx2ptr(a) ((void*)le32_to_cpu(a.v))
-+
-+/* Values for rate field (acx100 only) */
-+#define RATE100_1 10
-+#define RATE100_2 20
-+#define RATE100_5 55
-+#define RATE100_11 110
-+#define RATE100_22 220
-+/* This bit denotes use of PBCC:
-+** (PBCC encoding is usable with 11 and 22 Mbps speeds only) */
-+#define RATE100_PBCC511 0x80
-+
-+/* Bit values for rate111 field */
-+#define RATE111_1 0x0001 /* DBPSK */
-+#define RATE111_2 0x0002 /* DQPSK */
-+#define RATE111_5 0x0004 /* CCK or PBCC */
-+#define RATE111_6 0x0008 /* CCK-OFDM or OFDM */
-+#define RATE111_9 0x0010 /* CCK-OFDM or OFDM */
-+#define RATE111_11 0x0020 /* CCK or PBCC */
-+#define RATE111_12 0x0040 /* CCK-OFDM or OFDM */
-+#define RATE111_18 0x0080 /* CCK-OFDM or OFDM */
-+#define RATE111_22 0x0100 /* PBCC */
-+#define RATE111_24 0x0200 /* CCK-OFDM or OFDM */
-+#define RATE111_36 0x0400 /* CCK-OFDM or OFDM */
-+#define RATE111_48 0x0800 /* CCK-OFDM or OFDM */
-+#define RATE111_54 0x1000 /* CCK-OFDM or OFDM */
-+#define RATE111_RESERVED 0x2000
-+#define RATE111_PBCC511 0x4000 /* PBCC mod at 5.5 or 11Mbit (else CCK) */
-+#define RATE111_SHORTPRE 0x8000 /* short preamble */
-+/* Special 'try everything' value */
-+#define RATE111_ALL 0x1fff
-+/* These bits denote acx100 compatible settings */
-+#define RATE111_ACX100_COMPAT 0x0127
-+/* These bits denote 802.11b compatible settings */
-+#define RATE111_80211B_COMPAT 0x0027
-+
-+/* Descriptor Ctl field bits
-+ * init value is 0x8e, "idle" value is 0x82 (in idle tx descs)
-+ */
-+#define DESC_CTL_SHORT_PREAMBLE 0x01 /* preamble type: 0 = long; 1 = short */
-+#define DESC_CTL_FIRSTFRAG 0x02 /* this is the 1st frag of the frame */
-+#define DESC_CTL_AUTODMA 0x04
-+#define DESC_CTL_RECLAIM 0x08 /* ready to reuse */
-+#define DESC_CTL_HOSTDONE 0x20 /* host has finished processing */
-+#define DESC_CTL_ACXDONE 0x40 /* acx has finished processing */
-+/* host owns the desc [has to be released last, AFTER modifying all other desc fields!] */
-+#define DESC_CTL_HOSTOWN 0x80
-+
-+#define DESC_CTL_INIT (DESC_CTL_HOSTOWN | DESC_CTL_RECLAIM | \
-+ DESC_CTL_AUTODMA | DESC_CTL_FIRSTFRAG)
-+#define DESC_CTL_DONE (DESC_CTL_ACXDONE | DESC_CTL_HOSTOWN)
-+
-+#define DESC_CTL_HOSTOWN_STR "80"
-+#define DESC_CTL_DONE_STR "C0"
-+/* Descriptor Status field
-+ */
-+#define DESC_STATUS_FULL (1 << 31)
-+
-+/* NB: some bits may be interesting for Monitor mode tx (aka Raw tx): */
-+#define DESC_CTL2_SEQ 0x01 /* don't increase sequence field */
-+#define DESC_CTL2_FCS 0x02 /* don't add the FCS */
-+#define DESC_CTL2_MORE_FRAG 0x04
-+#define DESC_CTL2_RETRY 0x08 /* don't increase retry field */
-+#define DESC_CTL2_POWER 0x10 /* don't increase power mgmt. field */
-+#define DESC_CTL2_RTS 0x20 /* do RTS/CTS magic before sending */
-+#define DESC_CTL2_WEP 0x40 /* encrypt this frame */
-+#define DESC_CTL2_DUR 0x80 /* don't increase duration field */
-+
-+/***************************************************************
-+** PCI structures
-+*/
-+/* IRQ Constants
-+** (outside of "#ifdef PCI" because USB (mis)uses HOST_INT_SCAN_COMPLETE) */
-+#define HOST_INT_RX_DATA 0x0001
-+#define HOST_INT_TX_COMPLETE 0x0002
-+#define HOST_INT_TX_XFER 0x0004
-+#define HOST_INT_RX_COMPLETE 0x0008
-+#define HOST_INT_DTIM 0x0010
-+#define HOST_INT_BEACON 0x0020
-+#define HOST_INT_TIMER 0x0040
-+#define HOST_INT_KEY_NOT_FOUND 0x0080
-+#define HOST_INT_IV_ICV_FAILURE 0x0100
-+#define HOST_INT_CMD_COMPLETE 0x0200
-+#define HOST_INT_INFO 0x0400
-+#define HOST_INT_OVERFLOW 0x0800
-+#define HOST_INT_PROCESS_ERROR 0x1000
-+#define HOST_INT_SCAN_COMPLETE 0x2000
-+#define HOST_INT_FCS_THRESHOLD 0x4000
-+#define HOST_INT_UNKNOWN 0x8000
-+
-+/* Outside of "#ifdef PCI" because USB needs to know sizeof()
-+** of txdesc and rxdesc: */
-+struct txdesc {
-+ acx_ptr pNextDesc ACX_PACKED; /* pointer to next txdesc */
-+ acx_ptr HostMemPtr ACX_PACKED; /* 0x04 */
-+ acx_ptr AcxMemPtr ACX_PACKED; /* 0x08 */
-+ u32 tx_time ACX_PACKED; /* 0x0c */
-+ u16 total_length ACX_PACKED; /* 0x10 */
-+ u16 Reserved ACX_PACKED; /* 0x12 */
-+
-+/* The following 16 bytes do not change when acx100 owns the descriptor */
-+/* BUG: fw clears last byte of this area which is supposedly reserved
-+** for driver use. amd64 blew up. We dare not use it now */
-+ u32 dummy[4] ACX_PACKED;
-+
-+ u8 Ctl_8 ACX_PACKED; /* 0x24, 8bit value */
-+ u8 Ctl2_8 ACX_PACKED; /* 0x25, 8bit value */
-+ u8 error ACX_PACKED; /* 0x26 */
-+ u8 ack_failures ACX_PACKED; /* 0x27 */
-+ u8 rts_failures ACX_PACKED; /* 0x28 */
-+ u8 rts_ok ACX_PACKED; /* 0x29 */
-+ union {
-+ struct {
-+ u8 rate ACX_PACKED; /* 0x2a */
-+ u8 queue_ctrl ACX_PACKED; /* 0x2b */
-+ } r1 ACX_PACKED;
-+ struct {
-+ u16 rate111 ACX_PACKED; /* 0x2a */
-+ } r2 ACX_PACKED;
-+ } u ACX_PACKED;
-+ u32 queue_info ACX_PACKED; /* 0x2c (acx100, reserved on acx111) */
-+}; /* size : 48 = 0x30 */
-+/* NB: acx111 txdesc structure is 4 byte larger */
-+/* All these 4 extra bytes are reserved. tx alloc code takes them into account */
-+
-+struct rxdesc {
-+ acx_ptr pNextDesc ACX_PACKED; /* 0x00 */
-+ acx_ptr HostMemPtr ACX_PACKED; /* 0x04 */
-+ acx_ptr ACXMemPtr ACX_PACKED; /* 0x08 */
-+ u32 rx_time ACX_PACKED; /* 0x0c */
-+ u16 total_length ACX_PACKED; /* 0x10 */
-+ u16 WEP_length ACX_PACKED; /* 0x12 */
-+ u32 WEP_ofs ACX_PACKED; /* 0x14 */
-+
-+/* the following 16 bytes do not change when acx100 owns the descriptor */
-+ u8 driverWorkspace[16] ACX_PACKED; /* 0x18 */
-+
-+ u8 Ctl_8 ACX_PACKED;
-+ u8 rate ACX_PACKED;
-+ u8 error ACX_PACKED;
-+ u8 SNR ACX_PACKED; /* Signal-to-Noise Ratio */
-+ u8 RxLevel ACX_PACKED;
-+ u8 queue_ctrl ACX_PACKED;
-+ u16 unknown ACX_PACKED;
-+ u32 unknown2 ACX_PACKED;
-+}; /* size 52 = 0x34 */
-+
-+#ifdef ACX_PCI
-+
-+/* Register I/O offsets */
-+#define ACX100_EEPROM_ID_OFFSET 0x380
-+
-+/* please add further ACX hardware register definitions only when
-+ it turns out you need them in the driver, and please try to use
-+ firmware functionality instead, since using direct I/O access instead
-+ of letting the firmware do it might confuse the firmware's state
-+ machine */
-+
-+/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION
-+** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */
-+enum {
-+ IO_ACX_SOFT_RESET = 0,
-+
-+ IO_ACX_HW_SLAVE_REG_ADDR,
-+ IO_ACX_HW_SLAVE_REG_DATA,
-+ IO_ACX_HW_SLAVE_REG_CTRL,
-+
-+ IO_ACX_SLV_MEM_ADDR,
-+ IO_ACX_SLV_MEM_DATA,
-+ IO_ACX_SLV_MEM_CTL,
-+ IO_ACX_SLV_END_CTL,
-+ IO_ACX_CHIPID,
-+
-+ IO_ACX_FEMR, /* Function Event Mask */
-+
-+ IO_ACX_INT_TRIG,
-+ IO_ACX_IRQ_MASK,
-+ IO_ACX_IRQ_STATUS_NON_DES,
-+ IO_ACX_IRQ_STATUS_CLEAR, /* CLEAR = clear on read */
-+ IO_ACX_IRQ_ACK,
-+ IO_ACX_HINT_TRIG,
-+
-+ IO_ACX_ENABLE,
-+
-+ IO_ACX_EEPROM_CTL,
-+ IO_ACX_EEPROM_ADDR,
-+ IO_ACX_EEPROM_DATA,
-+ IO_ACX_EEPROM_CFG,
-+
-+ IO_ACX_PHY_ADDR,
-+ IO_ACX_PHY_DATA,
-+ IO_ACX_PHY_CTL,
-+
-+ IO_ACX_GPIO_OE,
-+
-+ IO_ACX_GPIO_IN,
-+ IO_ACX_GPIO_OUT,
-+ IO_ACX_GPIO_PD,
-+ IO_ACX_GPIO_CFG,
-+
-+ IO_ACX_CMD_MAILBOX_OFFS,
-+ IO_ACX_INFO_MAILBOX_OFFS,
-+ IO_ACX_EEPROM_INFORMATION,
-+
-+ IO_ACX_EE_START,
-+ IO_ACX_SOR_CFG,
-+ IO_ACX_ECPU_CTRL,
-+
-+ IO_ACX_HI_CTRL,
-+ IO_ACX_LPWR_MGR,
-+
-+ IO_ACX_PCI_ARB_CFG,
-+};
-+/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION
-+** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */
-+
-+/* Values for IO_ACX_INT_TRIG register: */
-+/* inform hw that rxdesc in queue needs processing */
-+#define INT_TRIG_RXPRC 0x08
-+/* inform hw that txdesc in queue needs processing */
-+#define INT_TRIG_TXPRC 0x04
-+/* ack that we received info from info mailbox */
-+#define INT_TRIG_INFOACK 0x02
-+/* inform hw that we have filled command mailbox */
-+#define INT_TRIG_CMD 0x01
-+
-+struct txhostdesc {
-+ acx_ptr data_phy ACX_PACKED; /* 0x00 [u8 *] */
-+ u16 data_offset ACX_PACKED; /* 0x04 */
-+ u16 reserved ACX_PACKED; /* 0x06 */
-+ u16 Ctl_16 ACX_PACKED; /* 16bit value, endianness!! */
-+ u16 length ACX_PACKED; /* 0x0a */
-+ acx_ptr desc_phy_next ACX_PACKED; /* 0x0c [txhostdesc *] */
-+ acx_ptr pNext ACX_PACKED; /* 0x10 [txhostdesc *] */
-+ u32 Status ACX_PACKED; /* 0x14, unused on Tx */
-+/* From here on you can use this area as you want (variable length, too!) */
-+ u8 *data ACX_PACKED;
-+};
-+
-+struct rxhostdesc {
-+ acx_ptr data_phy ACX_PACKED; /* 0x00 [rxbuffer_t *] */
-+ u16 data_offset ACX_PACKED; /* 0x04 */
-+ u16 reserved ACX_PACKED; /* 0x06 */
-+ u16 Ctl_16 ACX_PACKED; /* 0x08; 16bit value, endianness!! */
-+ u16 length ACX_PACKED; /* 0x0a */
-+ acx_ptr desc_phy_next ACX_PACKED; /* 0x0c [rxhostdesc_t *] */
-+ acx_ptr pNext ACX_PACKED; /* 0x10 [rxhostdesc_t *] */
-+ u32 Status ACX_PACKED; /* 0x14 */
-+/* From here on you can use this area as you want (variable length, too!) */
-+ rxbuffer_t *data ACX_PACKED;
-+};
-+
-+#endif /* ACX_PCI */
-+
-+/***************************************************************
-+** USB structures and constants
-+*/
-+#ifdef ACX_USB
-+
-+/* Buffer size for fw upload */
-+#define ACX100_USB_RWMEM_MAXLEN 2048
-+
-+/* Should be sent to the ctrlout endpoint */
-+#define ACX100_USB_ENBULKIN 6
-+
-+/* The number of bulk URBs to use */
-+#define ACX100_USB_NUM_BULK_URBS 8
-+
-+/* Should be sent to the bulkout endpoint */
-+#define ACX_USB_REQ_UPLOAD_FW 0x10
-+#define ACX_USB_REQ_ACK_CS 0x11
-+#define ACX_USB_REQ_CMD 0x12
-+
-+/* Used for usb_txbuffer.desc field */
-+#define USB_TXBUF_TXDESC 0xA
-+/* Used for usb_txbuffer.hostData field */
-+#define USB_TXBUF_HD_ISDATA 0x10000
-+#define USB_TXBUF_HD_DIRECTED 0x20000
-+#define USB_TXBUF_HD_BROADCAST 0x40000
-+/* Size of header (everything up to data[]) */
-+#define USB_TXBUF_HDRSIZE 14
-+typedef struct usb_txbuffer {
-+ u16 desc ACX_PACKED;
-+ u16 MPDUlen ACX_PACKED;
-+ u8 index ACX_PACKED;
-+ u8 txRate ACX_PACKED;
-+ u32 hostData ACX_PACKED;
-+ u8 ctrl1 ACX_PACKED;
-+ u8 ctrl2 ACX_PACKED;
-+ u16 dataLength ACX_PACKED;
-+ /* wlan packet content is placed here: */
-+ u8 data[WLAN_A4FR_MAXLEN_WEP_FCS] ACX_PACKED;
-+} usb_txbuffer_t;
-+
-+typedef struct {
-+ void *device;
-+ int number;
-+} acx_usb_bulk_context_t;
-+
-+typedef struct usb_tx {
-+ unsigned busy:1;
-+ struct urb *urb;
-+ wlandevice_t *priv;
-+ client_t *txc;
-+ /* actual USB bulk output data block is here: */
-+ usb_txbuffer_t bulkout;
-+} usb_tx_t;
-+
-+#endif /* ACX_USB */
-+
-+
-+/*============================================================================*
-+ * Main acx per-device data structure (netdev_priv(dev)) *
-+ *============================================================================*/
-+#define ACX_STATE_FW_LOADED 0x01
-+#define ACX_STATE_IFACE_UP 0x02
-+
-+/* MAC mode (BSS type) defines
-+ * Note that they shouldn't be redefined, since they are also used
-+ * during communication with firmware */
-+#define ACX_MODE_0_ADHOC 0
-+#define ACX_MODE_1_UNUSED 1
-+#define ACX_MODE_2_STA 2
-+#define ACX_MODE_3_AP 3
-+/* These are our own inventions. Sending these to firmware
-+** makes it stop emitting beacons, which is exactly what we want
-+** for these modes */
-+#define ACX_MODE_MONITOR 0xfe
-+#define ACX_MODE_OFF 0xff
-+/* 'Submode': identifies exact status of ADHOC/STA host */
-+#define ACX_STATUS_0_STOPPED 0
-+#define ACX_STATUS_1_SCANNING 1
-+#define ACX_STATUS_2_WAIT_AUTH 2
-+#define ACX_STATUS_3_AUTHENTICATED 3
-+#define ACX_STATUS_4_ASSOCIATED 4
-+
-+/* FIXME: this should be named something like struct acx_priv (typedef'd to
-+ * acx_priv_t) */
-+
-+/* non-firmware struct, no packing necessary */
-+struct wlandevice {
-+ /*** Device chain ***/
-+ struct wlandevice *next; /* link for list of devices */
-+
-+ /*** Linux network device ***/
-+ struct net_device *netdev; /* pointer to linux netdevice */
-+ struct net_device *prev_nd; /* FIXME: We should not chain via our
-+ * private struct wlandevice _and_
-+ * the struct net_device. */
-+ /*** Device statistics ***/
-+ struct net_device_stats stats; /* net device statistics */
-+#ifdef WIRELESS_EXT
-+ struct iw_statistics wstats; /* wireless statistics */
-+#endif
-+ /*** Power managment ***/
-+ struct pm_dev *pm; /* PM crap */
-+
-+ /*** Management timer ***/
-+ struct timer_list mgmt_timer;
-+
-+ /*** Locking ***/
-+ struct semaphore sem;
-+ spinlock_t lock;
-+#if defined(PARANOID_LOCKING) /* Lock debugging */
-+ const char *last_sem;
-+ const char *last_lock;
-+ unsigned long sem_time;
-+ unsigned long lock_time;
-+#endif
-+
-+ /*** Hardware identification ***/
-+ const char *chip_name;
-+ u8 dev_type;
-+ u8 chip_type;
-+ u8 form_factor;
-+ u8 radio_type;
-+ u8 eeprom_version;
-+
-+ /*** Firmware identification ***/
-+ char firmware_version[FW_ID_SIZE+1];
-+ u32 firmware_numver;
-+ u32 firmware_id;
-+
-+ /*** Device state ***/
-+ u16 dev_state_mask;
-+ u8 led_power; /* power LED status */
-+ u32 get_mask; /* mask of settings to fetch from the card */
-+ u32 set_mask; /* mask of settings to write to the card */
-+
-+ /* Barely used in USB case */
-+ u16 irq_status;
-+
-+ u8 after_interrupt_jobs; /* mini job list for doing actions after an interrupt occurred */
-+ WORK_STRUCT after_interrupt_task; /* our task for after interrupt actions */
-+
-+ /*** scanning ***/
-+ u16 scan_count; /* number of times to do channel scan */
-+ u8 scan_mode; /* 0 == active, 1 == passive, 2 == background */
-+ u8 scan_rate;
-+ u16 scan_duration;
-+ u16 scan_probe_delay;
-+#if WIRELESS_EXT > 15
-+ struct iw_spy_data spy_data; /* FIXME: needs to be implemented! */
-+#endif
-+
-+ /*** Wireless network settings ***/
-+ /* copy of the device address (ifconfig hw ether) that we actually use
-+ ** for 802.11; copied over from the network device's MAC address
-+ ** (ifconfig) when it makes sense only */
-+ u8 dev_addr[MAX_ADDR_LEN];
-+ u8 bssid[ETH_ALEN]; /* the BSSID after having joined */
-+ u8 ap[ETH_ALEN]; /* The AP we want, FF:FF:FF:FF:FF:FF is any */
-+ u16 aid; /* The Association ID sent from the AP / last used AID if we're an AP */
-+ u16 mode; /* mode from iwconfig */
-+ u16 status; /* 802.11 association status */
-+ u8 essid_active; /* specific ESSID active, or select any? */
-+ u8 essid_len; /* to avoid dozens of strlen() */
-+ /* INCLUDES \0 termination for easy printf - but many places
-+ ** simply want the string data memcpy'd plus a length indicator!
-+ ** Keep that in mind... */
-+ char essid[IW_ESSID_MAX_SIZE+1];
-+ /* essid we are going to use for association, in case of "essid 'any'"
-+ ** and in case of hidden ESSID (use configured ESSID then) */
-+ char essid_for_assoc[IW_ESSID_MAX_SIZE+1];
-+ char nick[IW_ESSID_MAX_SIZE+1]; /* see essid! */
-+ u8 channel;
-+ u8 reg_dom_id; /* reg domain setting */
-+ u16 reg_dom_chanmask;
-+ u16 auth_or_assoc_retries;
-+ u16 scan_retries;
-+ unsigned long scan_start; /* YES, jiffies is defined as "unsigned long" */
-+
-+ /* stations known to us (if we're an ap) */
-+ client_t sta_list[32]; /* tab is larger than list, so that */
-+ client_t *sta_hash_tab[64]; /* hash collisions are not likely */
-+ client_t *ap_client; /* this one is our AP (STA mode only) */
-+
-+ unsigned long dup_msg_expiry;
-+ int dup_count;
-+ int nondup_count;
-+ u16 last_seq_ctrl; /* duplicate packet detection */
-+
-+ /* 802.11 power save mode */
-+ u8 ps_wakeup_cfg;
-+ u8 ps_listen_interval;
-+ u8 ps_options;
-+ u8 ps_hangover_period;
-+ u16 ps_enhanced_transition_time;
-+
-+ /*** PHY settings ***/
-+ u8 fallback_threshold;
-+ u8 stepup_threshold;
-+ u16 rate_basic;
-+ u16 rate_oper;
-+ u16 rate_bcast;
-+ u16 rate_bcast100;
-+ u8 rate_auto; /* false if "iwconfig rate N" (WITHOUT 'auto'!) */
-+ u8 preamble_mode; /* 0 == Long Preamble, 1 == Short, 2 == Auto */
-+ u8 preamble_cur;
-+
-+ u8 tx_disabled;
-+ u8 tx_level_dbm;
-+ /* u8 tx_level_val; */
-+ /* u8 tx_level_auto; whether to do automatic power adjustment */
-+
-+ unsigned long recalib_time_last_success;
-+ unsigned long recalib_time_last_attempt;
-+ int recalib_failure_count;
-+ int recalib_msg_ratelimit;
-+ int retry_errors_msg_ratelimit;
-+
-+ unsigned long brange_time_last_state_change; /* time the power LED was last changed */
-+ u8 brange_last_state; /* last state of the LED */
-+ u8 brange_max_quality; /* maximum quality that equates to full speed */
-+
-+ u8 sensitivity;
-+ u8 antenna; /* antenna settings */
-+ u8 ed_threshold; /* energy detect threshold */
-+ u8 cca; /* clear channel assessment */
-+
-+ u16 rts_threshold;
-+ u32 short_retry;
-+ u32 long_retry;
-+ u16 msdu_lifetime;
-+ u16 listen_interval; /* given in units of beacon interval */
-+ u32 beacon_interval;
-+
-+ u16 capabilities;
-+ u8 capab_short;
-+ u8 capab_pbcc;
-+ u8 capab_agility;
-+ u8 rate_supported_len;
-+ u8 rate_supported[13];
-+
-+ /*** Encryption settings (WEP) ***/
-+ u32 auth_alg; /* used in transmit_authen1 */
-+ u8 wep_enabled;
-+ u8 wep_restricted;
-+ u8 wep_current_index;
-+ wep_key_t wep_keys[DOT11_MAX_DEFAULT_WEP_KEYS]; /* the default WEP keys */
-+ key_struct_t wep_key_struct[10];
-+
-+ /*** Card Rx/Tx management ***/
-+ u16 rx_config_1;
-+ u16 rx_config_2;
-+ u16 memblocksize;
-+ u32 tx_free;
-+
-+ /*** Unknown ***/
-+ u8 dtim_interval;
-+
-+/*** PCI/USB/... must be last or else hw agnostic code breaks horribly ***/
-+ /* hack to let common code compile. FIXME */
-+ dma_addr_t rxhostdesc_startphy;
-+
-+ /*** PCI stuff ***/
-+#ifdef ACX_PCI
-+ /* pointers to tx buffers, tx host descriptors (in host memory)
-+ ** and tx descrs in device memory */
-+ u8 *txbuf_start;
-+ txhostdesc_t *txhostdesc_start;
-+ txdesc_t *txdesc_start; /* points to PCI-mapped memory */
-+ /* same for rx */
-+ rxbuffer_t *rxbuf_start;
-+ rxhostdesc_t *rxhostdesc_start;
-+ rxdesc_t *rxdesc_start;
-+ /* physical addresses of above host memory areas */
-+ dma_addr_t rxbuf_startphy;
-+ /* dma_addr_t rxhostdesc_startphy; */
-+ dma_addr_t txbuf_startphy;
-+ dma_addr_t txhostdesc_startphy;
-+ /* sizes of above host memory areas */
-+ unsigned int txbuf_area_size;
-+ unsigned int txhostdesc_area_size;
-+ unsigned int rxbuf_area_size;
-+ unsigned int rxhostdesc_area_size;
-+
-+ unsigned int txdesc_size; /* size per tx descr; ACX111 = ACX100 + 4 */
-+ unsigned int tx_head; /* current ring buffer pool member index */
-+ unsigned int tx_tail;
-+ unsigned int rx_tail;
-+
-+ client_t *txc[TX_CNT];
-+
-+ u8 need_radio_fw;
-+ u8 irqs_active; /* whether irq sending is activated */
-+
-+ const u16 *io; /* points to ACX100 or ACX111 I/O register address set */
-+
-+#if defined(CONFIG_ACX_CFI)
-+ struct device *dev;
-+#else
-+ struct pci_dev *pdev;
-+#endif
-+
-+ unsigned long membase;
-+ unsigned long membase2;
-+ void *iobase;
-+ void *iobase2;
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
-+ /* 2.6.9-rc3-mm2 (2.6.9-bk4, too) introduced a shorter API version,
-+ then it made its way into 2.6.10 */
-+ u32 pci_state[16]; /* saved PCI state for suspend/resume */
-+#endif
-+ u16 irq_mask; /* interrupt types to mask out (not wanted) with many IRQs activated */
-+ u16 irq_mask_off; /* interrupt types to mask out (not wanted) with IRQs off */
-+ unsigned int irq_loops_this_jiffy;
-+ unsigned long irq_last_jiffies;
-+
-+ /* command interface */
-+ void *cmd_area; /* points to PCI mapped memory */
-+ void *info_area; /* points to PCI mapped memory */
-+ u16 cmd_type;
-+ u16 cmd_status;
-+ u16 info_type;
-+ u16 info_status;
-+#endif
-+
-+ /*** USB stuff ***/
-+#ifdef ACX_USB
-+ struct usb_device *usbdev;
-+
-+ rxbuffer_t rxtruncbuf;
-+ /* TODO: convert (bulkins,bulkrx_urbs,rxcons) triple into
-+ ** struct usb_rx (see struct usb_tx for an example) */
-+ rxbuffer_t bulkins[ACX100_USB_NUM_BULK_URBS];
-+ struct urb *bulkrx_urbs[ACX100_USB_NUM_BULK_URBS];
-+ /* Used by rx urb completion handler in order to find
-+ ** corresponding priv/index pair */
-+ acx_usb_bulk_context_t rxcons[ACX100_USB_NUM_BULK_URBS];
-+ usb_tx_t usb_tx[ACX100_USB_NUM_BULK_URBS];
-+
-+ int bulkinep; /* bulk-in endpoint */
-+ int bulkoutep; /* bulk-out endpoint */
-+ int rxtruncsize;
-+#endif
-+
-+};
-+
-+/* For use with ACX1xx_IE_RXCONFIG */
-+/* bit description
-+ * 13 include additional header (length etc.) *required*
-+ * struct is defined in 'struct rxbuffer'
-+ * is this bit acx100 only? does acx111 always put the header,
-+ * and bit setting is irrelevant? --vda
-+ * 10 receive frames only with SSID used in last join cmd
-+ * 9 discard broadcast
-+ * 8 receive packets for multicast address 1
-+ * 7 receive packets for multicast address 0
-+ * 6 discard all multicast packets
-+ * 5 discard frames from foreign BSSID
-+ * 4 discard frames with foreign destination MAC address
-+ * 3 promiscuous mode (receive ALL frames, disable filter)
-+ * 2 include FCS
-+ * 1 include phy header
-+ * 0 ???
-+ */
-+#define RX_CFG1_INCLUDE_RXBUF_HDR 0x2000 /* ACX100 only */
-+#define RX_CFG1_FILTER_SSID 0x0400
-+#define RX_CFG1_FILTER_BCAST 0x0200
-+#define RX_CFG1_RCV_MC_ADDR1 0x0100
-+#define RX_CFG1_RCV_MC_ADDR0 0x0080
-+#define RX_CFG1_FILTER_ALL_MULTI 0x0040
-+#define RX_CFG1_FILTER_BSSID 0x0020
-+#define RX_CFG1_FILTER_MAC 0x0010
-+#define RX_CFG1_RCV_PROMISCUOUS 0x0008
-+#define RX_CFG1_INCLUDE_FCS 0x0004
-+#define RX_CFG1_INCLUDE_PHY_HDR (WANT_PHY_HDR ? 0x0002 : 0)
-+/* bit description
-+ * 11 receive association requests etc.
-+ * 10 receive authentication frames
-+ * 9 receive beacon frames
-+ * 8 receive contention free packets
-+ * 7 receive control frames
-+ * 6 receive data frames
-+ * 5 receive broken frames
-+ * 4 receive management frames
-+ * 3 receive probe requests
-+ * 2 receive probe responses
-+ * 1 receive RTS/CTS/ACK frames
-+ * 0 receive other
-+ */
-+#define RX_CFG2_RCV_ASSOC_REQ 0x0800
-+#define RX_CFG2_RCV_AUTH_FRAMES 0x0400
-+#define RX_CFG2_RCV_BEACON_FRAMES 0x0200
-+#define RX_CFG2_RCV_CONTENTION_FREE 0x0100
-+#define RX_CFG2_RCV_CTRL_FRAMES 0x0080
-+#define RX_CFG2_RCV_DATA_FRAMES 0x0040
-+#define RX_CFG2_RCV_BROKEN_FRAMES 0x0020
-+#define RX_CFG2_RCV_MGMT_FRAMES 0x0010
-+#define RX_CFG2_RCV_PROBE_REQ 0x0008
-+#define RX_CFG2_RCV_PROBE_RESP 0x0004
-+#define RX_CFG2_RCV_ACK_FRAMES 0x0002
-+#define RX_CFG2_RCV_OTHER 0x0001
-+
-+/* For use with ACX1xx_IE_FEATURE_CONFIG */
-+#define FEATURE1_80MHZ_CLOCK 0x00000040L
-+#define FEATURE1_4X 0x00000020L
-+#define FEATURE1_LOW_RX 0x00000008L
-+#define FEATURE1_EXTRA_LOW_RX 0x00000001L
-+
-+#define FEATURE2_SNIFFER 0x00000080L
-+#define FEATURE2_NO_TXCRYPT 0x00000001L
-+
-+/*-- get and set mask values --*/
-+#define GETSET_LED_POWER 0x00000001L
-+#define GETSET_STATION_ID 0x00000002L
-+#define SET_TEMPLATES 0x00000004L
-+#define SET_STA_LIST 0x00000008L
-+#define GETSET_TX 0x00000010L
-+#define GETSET_RX 0x00000020L
-+#define SET_RXCONFIG 0x00000040L
-+#define GETSET_ANTENNA 0x00000080L
-+#define GETSET_SENSITIVITY 0x00000100L
-+#define GETSET_TXPOWER 0x00000200L
-+#define GETSET_ED_THRESH 0x00000400L
-+#define GETSET_CCA 0x00000800L
-+#define GETSET_POWER_80211 0x00001000L
-+#define GETSET_RETRY 0x00002000L
-+#define GETSET_REG_DOMAIN 0x00004000L
-+#define GETSET_CHANNEL 0x00008000L
-+/* Used when ESSID changes etc and we need to scan for AP anew */
-+#define GETSET_RESCAN 0x00010000L
-+#define GETSET_MODE 0x00020000L
-+#define GETSET_WEP 0x00040000L
-+#define SET_WEP_OPTIONS 0x00080000L
-+#define SET_MSDU_LIFETIME 0x00100000L
-+#define SET_RATE_FALLBACK 0x00200000L
-+#define GETSET_ALL 0x80000000L
-+
-+
-+/*============================================================================*
-+ * Firmware loading *
-+ *============================================================================*/
-+/* Doh, 2.4.x also has CONFIG_FW_LOADER_MODULE
-+ * (but doesn't have the new device model yet which we require!)
-+ * FIXME: exact version that introduced new device handling? */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-+#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-+#define USE_FW_LOADER_26 1
-+#define USE_FW_LOADER_LEGACY 0
-+#else
-+#define USE_FW_LOADER_26 0
-+#define USE_FW_LOADER_LEGACY 1
-+#endif
-+#endif
-+
-+#if USE_FW_LOADER_26
-+#include <linux/firmware.h> /* request_firmware() */
-+#include <linux/pci.h> /* struct pci_device */
-+#endif
-+
-+
-+/***********************************************************************
-+*/
-+typedef struct acx100_ie_memblocksize {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u16 size ACX_PACKED;
-+} acx100_ie_memblocksize_t;
-+
-+typedef struct acx100_ie_queueconfig {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u32 AreaSize ACX_PACKED;
-+ u32 RxQueueStart ACX_PACKED;
-+ u8 QueueOptions ACX_PACKED;
-+ u8 NumTxQueues ACX_PACKED;
-+ u8 NumRxDesc ACX_PACKED; /* for USB only */
-+ u8 pad1 ACX_PACKED;
-+ u32 QueueEnd ACX_PACKED;
-+ u32 HostQueueEnd ACX_PACKED; /* QueueEnd2 */
-+ u32 TxQueueStart ACX_PACKED;
-+ u8 TxQueuePri ACX_PACKED;
-+ u8 NumTxDesc ACX_PACKED;
-+ u16 pad2 ACX_PACKED;
-+} acx100_ie_queueconfig_t;
-+
-+typedef struct acx111_ie_queueconfig {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u32 tx_memory_block_address ACX_PACKED;
-+ u32 rx_memory_block_address ACX_PACKED;
-+ u32 rx1_queue_address ACX_PACKED;
-+ u32 reserved1 ACX_PACKED;
-+ u32 tx1_queue_address ACX_PACKED;
-+ u8 tx1_attributes ACX_PACKED;
-+ u16 reserved2 ACX_PACKED;
-+ u8 reserved3 ACX_PACKED;
-+} acx111_ie_queueconfig_t;
-+
-+typedef struct acx100_ie_memconfigoption {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u32 DMA_config ACX_PACKED;
-+ acx_ptr pRxHostDesc ACX_PACKED;
-+ u32 rx_mem ACX_PACKED;
-+ u32 tx_mem ACX_PACKED;
-+ u16 RxBlockNum ACX_PACKED;
-+ u16 TxBlockNum ACX_PACKED;
-+} acx100_ie_memconfigoption_t;
-+
-+typedef struct acx111_ie_memoryconfig {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u16 no_of_stations ACX_PACKED;
-+ u16 memory_block_size ACX_PACKED;
-+ u8 tx_rx_memory_block_allocation ACX_PACKED;
-+ u8 count_rx_queues ACX_PACKED;
-+ u8 count_tx_queues ACX_PACKED;
-+ u8 options ACX_PACKED;
-+ u8 fragmentation ACX_PACKED;
-+ u16 reserved1 ACX_PACKED;
-+ u8 reserved2 ACX_PACKED;
-+
-+ /* start of rx1 block */
-+ u8 rx_queue1_count_descs ACX_PACKED;
-+ u8 rx_queue1_reserved1 ACX_PACKED;
-+ u8 rx_queue1_type ACX_PACKED; /* must be set to 7 */
-+ u8 rx_queue1_prio ACX_PACKED; /* must be set to 0 */
-+ acx_ptr rx_queue1_host_rx_start ACX_PACKED;
-+ /* end of rx1 block */
-+
-+ /* start of tx1 block */
-+ u8 tx_queue1_count_descs ACX_PACKED;
-+ u8 tx_queue1_reserved1 ACX_PACKED;
-+ u8 tx_queue1_reserved2 ACX_PACKED;
-+ u8 tx_queue1_attributes ACX_PACKED;
-+ /* end of tx1 block */
-+} acx111_ie_memoryconfig_t;
-+
-+typedef struct acx_ie_memmap {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u32 CodeStart ACX_PACKED;
-+ u32 CodeEnd ACX_PACKED;
-+ u32 WEPCacheStart ACX_PACKED;
-+ u32 WEPCacheEnd ACX_PACKED;
-+ u32 PacketTemplateStart ACX_PACKED;
-+ u32 PacketTemplateEnd ACX_PACKED;
-+ u32 QueueStart ACX_PACKED;
-+ u32 QueueEnd ACX_PACKED;
-+ u32 PoolStart ACX_PACKED;
-+ u32 PoolEnd ACX_PACKED;
-+} acx_ie_memmap_t;
-+
-+typedef struct acx111_ie_feature_config {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u32 feature_options ACX_PACKED;
-+ u32 data_flow_options ACX_PACKED;
-+} acx111_ie_feature_config_t;
-+
-+typedef struct acx111_ie_tx_level {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u8 level ACX_PACKED;
-+} acx111_ie_tx_level_t;
-+
-+#define PS_CFG_ENABLE 0x80
-+#define PS_CFG_PENDING 0x40 /* status flag when entering PS */
-+#define PS_CFG_WAKEUP_MODE_MASK 0x07
-+#define PS_CFG_WAKEUP_BY_HOST 0x03
-+#define PS_CFG_WAKEUP_EACH_ITVL 0x02
-+#define PS_CFG_WAKEUP_ON_DTIM 0x01
-+#define PS_CFG_WAKEUP_ALL_BEAC 0x00
-+
-+/* Enhanced PS mode: sleep until Rx Beacon w/ the STA's AID bit set
-+** in the TIM; newer firmwares only(?) */
-+#define PS_OPT_ENA_ENHANCED_PS 0x04
-+#define PS_OPT_STILL_RCV_BCASTS 0x01
-+
-+typedef struct acx100_ie_powermgmt {
-+ u32 type ACX_PACKED;
-+ u32 len ACX_PACKED;
-+ u8 wakeup_cfg ACX_PACKED;
-+ u8 listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
-+ u8 options ACX_PACKED;
-+ u8 hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
-+ u16 enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
-+} acx100_ie_powermgmt_t;
-+
-+typedef struct acx111_ie_powermgmt {
-+ u32 type ACX_PACKED;
-+ u32 len ACX_PACKED;
-+ u8 wakeup_cfg ACX_PACKED;
-+ u8 listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
-+ u8 options ACX_PACKED;
-+ u8 hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
-+ u32 beaconRxTime ACX_PACKED;
-+ u32 enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
-+} acx111_ie_powermgmt_t;
-+
-+
-+/***********************************************************************
-+** Commands and template structures
-+*/
-+
-+/*
-+** SCAN command structure
-+**
-+** even though acx100 scan rates match RATE100 constants,
-+** acx111 ones do not match! Therefore we do not use RATE100 #defines */
-+#define ACX_SCAN_RATE_1 10
-+#define ACX_SCAN_RATE_2 20
-+#define ACX_SCAN_RATE_5 55
-+#define ACX_SCAN_RATE_11 110
-+#define ACX_SCAN_RATE_22 220
-+#define ACX_SCAN_OPT_ACTIVE 0x00 /* a bit mask */
-+#define ACX_SCAN_OPT_PASSIVE 0x01
-+/* Background scan: we go into Power Save mode (by transmitting
-+** NULL data frame to AP with the power mgmt bit set), do the scan,
-+** and then exit Power Save mode. A plus is that AP buffers frames
-+** for us while we do background scan. Thus we avoid frame losses.
-+** Background scan can be active or passive, just like normal one */
-+#define ACX_SCAN_OPT_BACKGROUND 0x02
-+typedef struct acx100_scan {
-+ u16 count ACX_PACKED; /* number of scans to do, 0xffff == continuous */
-+ u16 start_chan ACX_PACKED;
-+ u16 flags ACX_PACKED; /* channel list mask; 0x8000 == all channels? */
-+ u8 max_rate ACX_PACKED; /* max. probe rate */
-+ u8 options ACX_PACKED; /* bit mask, see defines above */
-+ u16 chan_duration ACX_PACKED;
-+ u16 max_probe_delay ACX_PACKED;
-+} acx100_scan_t; /* length 0xc */
-+
-+#define ACX111_SCAN_RATE_6 0x0B
-+#define ACX111_SCAN_RATE_9 0x0F
-+#define ACX111_SCAN_RATE_12 0x0A
-+#define ACX111_SCAN_RATE_18 0x0E
-+#define ACX111_SCAN_RATE_24 0x09
-+#define ACX111_SCAN_RATE_36 0x0D
-+#define ACX111_SCAN_RATE_48 0x08
-+#define ACX111_SCAN_RATE_54 0x0C
-+#define ACX111_SCAN_OPT_5GHZ 0x04 /* else 2.4GHZ */
-+#define ACX111_SCAN_MOD_SHORTPRE 0x01 /* you can combine SHORTPRE and PBCC */
-+#define ACX111_SCAN_MOD_PBCC 0x80
-+#define ACX111_SCAN_MOD_OFDM 0x40
-+typedef struct acx111_scan {
-+ u16 count ACX_PACKED; /* number of scans to do */
-+ u8 channel_list_select ACX_PACKED; /* 0: scan all channels, 1: from chan_list only */
-+ u16 reserved1 ACX_PACKED;
-+ u8 reserved2 ACX_PACKED;
-+ u8 rate ACX_PACKED; /* rate for probe requests (if active scan) */
-+ u8 options ACX_PACKED; /* bit mask, see defines above */
-+ u16 chan_duration ACX_PACKED; /* min time to wait for reply on one channel (in TU) */
-+ /* (active scan only) (802.11 section 11.1.3.2.2) */
-+ u16 max_probe_delay ACX_PACKED; /* max time to wait for reply on one channel (active scan) */
-+ /* time to listen on a channel (passive scan) */
-+ u8 modulation ACX_PACKED;
-+ u8 channel_list[26] ACX_PACKED; /* bits 7:0 first byte: channels 8:1 */
-+ /* bits 7:0 second byte: channels 16:9 */
-+ /* 26 bytes is enough to cover 802.11a */
-+} acx111_scan_t;
-+
-+
-+/*
-+** Radio calibration command structure
-+*/
-+typedef struct acx111_cmd_radiocalib {
-+/* 0x80000000 == automatic calibration by firmware, according to interval;
-+ * bits 0..3: select calibration methods to go through:
-+ * calib based on DC, AfeDC, Tx mismatch, Tx equilization */
-+ u32 methods ACX_PACKED;
-+ u32 interval ACX_PACKED;
-+} acx111_cmd_radiocalib_t;
-+
-+
-+/*
-+** Packet template structures
-+**
-+** Packet templates store contents of Beacon, Probe response, Probe request,
-+** Null data frame, and TIM data frame. Firmware automatically transmits
-+** contents of template at appropriate time:
-+** - Beacon: when configured as AP or Ad-hoc
-+** - Probe response: when configured as AP or Ad-hoc, whenever
-+** a Probe request frame is received
-+** - Probe request: when host issues SCAN command (active)
-+** - Null data frame: when entering 802.11 power save mode
-+** - TIM data: at the end of Beacon frames (if no TIM template
-+** is configured, then transmits default TIM)
-+** NB:
-+** - size field must be set to size of actual template
-+** (NOT sizeof(struct) - templates are variable in length),
-+** size field is not itself counted.
-+** - members flagged with an asterisk must be initialized with host,
-+** rest must be zero filled.
-+** - variable length fields shown only in comments */
-+typedef struct acx_template_tim {
-+ u16 size ACX_PACKED;
-+ u8 tim_eid ACX_PACKED; /* 00 1 TIM IE ID * */
-+ u8 len ACX_PACKED; /* 01 1 Length * */
-+ u8 dtim_cnt ACX_PACKED; /* 02 1 DTIM Count */
-+ u8 dtim_period ACX_PACKED; /* 03 1 DTIM Period */
-+ u8 bitmap_ctrl ACX_PACKED; /* 04 1 Bitmap Control * (except bit0) */
-+ /* 05 n Partial Virtual Bitmap * */
-+ u8 variable[0x100 - 1-1-1-1-1] ACX_PACKED;
-+} acx_template_tim_t;
-+
-+typedef struct acx100_template_probereq {
-+ u16 size ACX_PACKED;
-+ u16 fc ACX_PACKED; /* 00 2 fc */
-+ u16 dur ACX_PACKED; /* 02 2 Duration */
-+ u8 da[6] ACX_PACKED; /* 04 6 Destination Address * */
-+ u8 sa[6] ACX_PACKED; /* 0A 6 Source Address * */
-+ u8 bssid[6] ACX_PACKED; /* 10 6 BSSID * */
-+ u16 seq ACX_PACKED; /* 16 2 Sequence Control */
-+ u8 timestamp[8] ACX_PACKED;/* 18 8 Timestamp */
-+ u16 beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */
-+ u16 cap ACX_PACKED; /* 22 2 Capability Information * */
-+ /* 24 n SSID * */
-+ /* nn n Supported Rates * */
-+ u8 variable[0x44 - 2-2-6-6-6-2-8-2-2] ACX_PACKED;
-+} acx100_template_probereq_t;
-+
-+typedef struct acx111_template_probereq {
-+ u16 size ACX_PACKED;
-+ u16 fc ACX_PACKED; /* 00 2 fc * */
-+ u16 dur ACX_PACKED; /* 02 2 Duration */
-+ u8 da[6] ACX_PACKED; /* 04 6 Destination Address * */
-+ u8 sa[6] ACX_PACKED; /* 0A 6 Source Address * */
-+ u8 bssid[6] ACX_PACKED; /* 10 6 BSSID * */
-+ u16 seq ACX_PACKED; /* 16 2 Sequence Control */
-+ /* 18 n SSID * */
-+ /* nn n Supported Rates * */
-+ u8 variable[0x44 - 2-2-6-6-6-2] ACX_PACKED;
-+} acx111_template_probereq_t;
-+
-+typedef struct acx_template_proberesp {
-+ u16 size ACX_PACKED;
-+ u16 fc ACX_PACKED; /* 00 2 fc * (bits [15:12] and [10:8] per 802.11 section 7.1.3.1) */
-+ u16 dur ACX_PACKED; /* 02 2 Duration */
-+ u8 da[6] ACX_PACKED; /* 04 6 Destination Address */
-+ u8 sa[6] ACX_PACKED; /* 0A 6 Source Address */
-+ u8 bssid[6] ACX_PACKED; /* 10 6 BSSID */
-+ u16 seq ACX_PACKED; /* 16 2 Sequence Control */
-+ u8 timestamp[8] ACX_PACKED;/* 18 8 Timestamp */
-+ u16 beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */
-+ u16 cap ACX_PACKED; /* 22 2 Capability Information * */
-+ /* 24 n SSID * */
-+ /* nn n Supported Rates * */
-+ /* nn 1 DS Parameter Set * */
-+ u8 variable[0x54 - 2-2-6-6-6-2-8-2-2] ACX_PACKED;
-+} acx_template_proberesp_t;
-+#define acx_template_beacon_t acx_template_proberesp_t
-+#define acx_template_beacon acx_template_proberesp
-+
-+typedef struct acx_template_nullframe {
-+ u16 size ACX_PACKED;
-+ struct wlan_hdr_a3 hdr ACX_PACKED;
-+} acx_template_nullframe_t;
-+
-+
-+/*
-+** JOIN command structure
-+**
-+** as opposed to acx100, acx111 dtim interval is AFTER rates_basic111.
-+** NOTE: took me about an hour to get !@#$%^& packing right --> struct packing is eeeeevil... */
-+typedef struct acx_joinbss {
-+ u8 bssid[ETH_ALEN] ACX_PACKED;
-+ u16 beacon_interval ACX_PACKED;
-+ union {
-+ struct {
-+ u8 dtim_interval ACX_PACKED;
-+ u8 rates_basic ACX_PACKED;
-+ u8 rates_supported ACX_PACKED;
-+ } acx100 ACX_PACKED;
-+ struct {
-+ u16 rates_basic ACX_PACKED;
-+ u8 dtim_interval ACX_PACKED;
-+ } acx111 ACX_PACKED;
-+ } u ACX_PACKED;
-+ u8 genfrm_txrate ACX_PACKED; /* generated frame (bcn, proberesp, RTS, PSpoll) tx rate */
-+ u8 genfrm_mod_pre ACX_PACKED; /* generated frame modulation/preamble:
-+ ** bit7: PBCC, bit6: OFDM (else CCK/DQPSK/DBPSK)
-+ ** bit5: short pre */
-+ u8 macmode ACX_PACKED; /* BSS Type, must be one of ACX_MODE_xxx */
-+ u8 channel ACX_PACKED;
-+ u8 essid_len ACX_PACKED;
-+ char essid[IW_ESSID_MAX_SIZE] ACX_PACKED;
-+} acx_joinbss_t;
-+
-+#define JOINBSS_RATES_1 0x01
-+#define JOINBSS_RATES_2 0x02
-+#define JOINBSS_RATES_5 0x04
-+#define JOINBSS_RATES_11 0x08
-+#define JOINBSS_RATES_22 0x10
-+
-+/* Looks like missing bits are used to indicate 11g rates!
-+** (it follows from the fact that constants below match 1:1 to RATE111_nn)
-+** This was actually seen! Look at that Assoc Request sent by acx111,
-+** it _does_ contain 11g rates in basic set:
-+01:30:20.070772 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1
-+01:30:20.074425 Authentication (Open System)-1: Succesful
-+01:30:20.076539 Authentication (Open System)-2:
-+01:30:20.076620 Acknowledgment
-+01:30:20.088546 Assoc Request (xxx) [1.0* 2.0* 5.5* 6.0* 9.0* 11.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit]
-+01:30:20.122413 Assoc Response AID(1) :: Succesful
-+01:30:20.122679 Acknowledgment
-+01:30:20.173204 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1
-+*/
-+#define JOINBSS_RATES_BASIC111_1 0x0001
-+#define JOINBSS_RATES_BASIC111_2 0x0002
-+#define JOINBSS_RATES_BASIC111_5 0x0004
-+#define JOINBSS_RATES_BASIC111_11 0x0020
-+#define JOINBSS_RATES_BASIC111_22 0x0100
-+
-+
-+/***********************************************************************
-+*/
-+typedef struct mem_read_write {
-+ u16 addr ACX_PACKED;
-+ u16 type ACX_PACKED; /* 0x0 int. RAM / 0xffff MAC reg. / 0x81 PHY RAM / 0x82 PHY reg. */
-+ u32 len ACX_PACKED;
-+ u32 data ACX_PACKED;
-+} mem_read_write_t;
-+
-+typedef struct firmware_image {
-+ u32 chksum ACX_PACKED;
-+ u32 size ACX_PACKED;
-+ u8 data[1] ACX_PACKED; /* the byte array of the actual firmware... */
-+} firmware_image_t;
-+
-+typedef struct acx_cmd_radioinit {
-+ u32 offset ACX_PACKED;
-+ u32 len ACX_PACKED;
-+} acx_cmd_radioinit_t;
-+
-+typedef struct acx100_ie_wep_options {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u16 NumKeys ACX_PACKED; /* max # of keys */
-+ u8 WEPOption ACX_PACKED; /* 0 == decrypt default key only, 1 == override decrypt */
-+ u8 Pad ACX_PACKED; /* used only for acx111 */
-+} acx100_ie_wep_options_t;
-+
-+typedef struct ie_dot11WEPDefaultKey {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u8 action ACX_PACKED;
-+ u8 keySize ACX_PACKED;
-+ u8 defaultKeyNum ACX_PACKED;
-+ u8 key[29] ACX_PACKED; /* check this! was Key[19]. */
-+} ie_dot11WEPDefaultKey_t;
-+
-+typedef struct acx111WEPDefaultKey {
-+ u8 MacAddr[ETH_ALEN] ACX_PACKED;
-+ u16 action ACX_PACKED; /* NOTE: this is a u16, NOT a u8!! */
-+ u16 reserved ACX_PACKED;
-+ u8 keySize ACX_PACKED;
-+ u8 type ACX_PACKED;
-+ u8 index ACX_PACKED;
-+ u8 defaultKeyNum ACX_PACKED;
-+ u8 counter[6] ACX_PACKED;
-+ u8 key[32] ACX_PACKED; /* up to 32 bytes (for TKIP!) */
-+} acx111WEPDefaultKey_t;
-+
-+typedef struct ie_dot11WEPDefaultKeyID {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u8 KeyID ACX_PACKED;
-+} ie_dot11WEPDefaultKeyID_t;
-+
-+typedef struct acx100_cmd_wep_mgmt {
-+ u8 MacAddr[ETH_ALEN] ACX_PACKED;
-+ u16 Action ACX_PACKED;
-+ u16 KeySize ACX_PACKED;
-+ u8 Key[29] ACX_PACKED; /* 29*8 == 232bits == WEP256 */
-+} acx100_cmd_wep_mgmt_t;
-+
-+typedef struct defaultkey {
-+ u8 num;
-+} defaultkey_t;
-+
-+typedef struct acx_ie_generic {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ union {
-+ /* struct wep wp ACX_PACKED; */
-+ /* Association ID IE: just a 16bit value: */
-+ u16 aid;
-+ /* UNUSED? struct defaultkey dkey ACX_PACKED; */
-+ /* generic member for quick implementation of commands */
-+ u8 bytes[32] ACX_PACKED;
-+ } m ACX_PACKED;
-+} acx_ie_generic_t;
-+
-+/* Config Option structs */
-+
-+typedef struct co_antennas {
-+ u8 type ACX_PACKED;
-+ u8 len ACX_PACKED;
-+ u8 list[2] ACX_PACKED;
-+} co_antennas_t;
-+
-+typedef struct co_powerlevels {
-+ u8 type ACX_PACKED;
-+ u8 len ACX_PACKED;
-+ u16 list[8] ACX_PACKED;
-+} co_powerlevels_t;
-+
-+typedef struct co_datarates {
-+ u8 type ACX_PACKED;
-+ u8 len ACX_PACKED;
-+ u8 list[8] ACX_PACKED;
-+} co_datarates_t;
-+
-+typedef struct co_domains {
-+ u8 type ACX_PACKED;
-+ u8 len ACX_PACKED;
-+ u8 list[6] ACX_PACKED;
-+} co_domains_t;
-+
-+typedef struct co_product_id {
-+ u8 type ACX_PACKED;
-+ u8 len ACX_PACKED;
-+ u8 list[128] ACX_PACKED;
-+} co_product_id_t;
-+
-+typedef struct co_manuf_id {
-+ u8 type ACX_PACKED;
-+ u8 len ACX_PACKED;
-+ u8 list[128] ACX_PACKED;
-+} co_manuf_t;
-+
-+typedef struct co_fixed {
-+ u8 type ACX_PACKED;
-+ u8 len ACX_PACKED;
-+ char NVSv[8] ACX_PACKED;
-+ u8 MAC[6] ACX_PACKED;
-+ u16 probe_delay ACX_PACKED;
-+ u32 eof_memory ACX_PACKED;
-+ u8 dot11CCAModes ACX_PACKED;
-+ u8 dot11Diversity ACX_PACKED;
-+ u8 dot11ShortPreambleOption ACX_PACKED;
-+ u8 dot11PBCCOption ACX_PACKED;
-+ u8 dot11ChannelAgility ACX_PACKED;
-+ u8 dot11PhyType ACX_PACKED;
-+/* u8 dot11TempType ACX_PACKED;
-+ u8 num_var ACX_PACKED; seems to be erased */
-+} co_fixed_t;
-+
-+
-+typedef struct acx111_ie_configoption {
-+ co_fixed_t configoption_fixed ACX_PACKED;
-+ co_antennas_t antennas ACX_PACKED;
-+ co_powerlevels_t power_levels ACX_PACKED;
-+ co_datarates_t data_rates ACX_PACKED;
-+ co_domains_t domains ACX_PACKED;
-+ co_product_id_t product_id ACX_PACKED;
-+ co_manuf_t manufacturer ACX_PACKED;
-+} acx111_ie_configoption_t;
-+
-+
-+/***********************************************************************
-+*/
-+#define CHECK_SIZEOF(type,size) { \
-+ extern void BUG_bad_size_for_##type(void); \
-+ if (sizeof(type)!=(size)) BUG_bad_size_for_##type(); \
-+}
-+
-+static inline void
-+acx_struct_size_check(void)
-+{
-+ //CHECK_SIZEOF(txdesc_t, 0x30);
-+ CHECK_SIZEOF(acx100_ie_memconfigoption_t, 24);
-+ CHECK_SIZEOF(acx100_ie_queueconfig_t, 0x20);
-+ //CHECK_SIZEOF(acx_joinbss_t, 0x30);
-+}
-+
-+
-+/*============================================================================*
-+ * Global data *
-+ *============================================================================*/
-+extern const u8 bitpos2ratebyte[];
-+extern const u8 bitpos2rate100[];
-+
-+extern const u8 reg_domain_ids[];
-+extern const u8 reg_domain_ids_len;
-+
-+extern const struct iw_handler_def acx_ioctl_handler_def;
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/cfi.c bt_kernel/drivers/net/wireless/tiacx/cfi.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/cfi.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/cfi.c 2005-10-29 22:02:44.690471000 +0300
-@@ -0,0 +1,4779 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+#define ACX_PCI 1
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-+#include <linux/moduleparam.h>
-+#endif
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/skbuff.h>
-+#include <linux/slab.h>
-+#include <linux/if_arp.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/wireless.h>
-+#if WIRELESS_EXT >= 13
-+#include <net/iw_handler.h>
-+#endif
-+#include <linux/device.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ioport.h>
-+#include <linux/pm.h>
-+#include <linux/vmalloc.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include <asm/sizes.h>
-+#include <asm/arch/tc.h>
-+
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/arch/gpio.h>
-+#include <asm/arch/pca9535.h>
-+
-+#include "acx.h"
-+
-+#define CARDNAME "tnetw1100b"
-+
-+/*================================================================*/
-+/* Local Constants */
-+#define PCI_TYPE (PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
-+#define PCI_ACX100_REGION1 0x01
-+#define PCI_ACX100_REGION1_SIZE 0x1000 /* Memory size - 4K bytes */
-+#define PCI_ACX100_REGION2 0x02
-+#define PCI_ACX100_REGION2_SIZE 0x10000 /* Memory size - 64K bytes */
-+
-+#define PCI_ACX111_REGION1 0x00
-+#define PCI_ACX111_REGION1_SIZE 0x2000 /* Memory size - 8K bytes */
-+#define PCI_ACX111_REGION2 0x01
-+#define PCI_ACX111_REGION2_SIZE 0x20000 /* Memory size - 128K bytes */
-+
-+/* Texas Instruments Vendor ID */
-+#define PCI_VENDOR_ID_TI 0x104c
-+
-+/* ACX100 22Mb/s WLAN controller */
-+#define PCI_DEVICE_ID_TI_TNETW1100A 0x8400
-+#define PCI_DEVICE_ID_TI_TNETW1100B 0x8401
-+
-+/* ACX111 54Mb/s WLAN controller */
-+#define PCI_DEVICE_ID_TI_TNETW1130 0x9066
-+
-+/* PCI Class & Sub-Class code, Network-'Other controller' */
-+#define PCI_CLASS_NETWORK_OTHERS 0x280
-+
-+#define CARD_EEPROM_ID_SIZE 6
-+#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* a la orinoco.c */
-+
-+
-+/***********************************************************************
-+*/
-+static void acx_l_disable_irq(wlandevice_t *priv);
-+static void acx_l_enable_irq(wlandevice_t *priv);
-+static int acx_drv_probe(struct device *dev);
-+static int acx_remove(struct device *dev);
-+
-+static inline void test(wlandevice_t *priv);
-+
-+#ifdef CONFIG_PM
-+static int acx_suspend(struct device *dev, pm_message_t state, u32 level);
-+static int acx_resume(struct device *dev, u32 level);
-+#endif
-+
-+static void acx_i_tx_timeout(netdevice_t *dev);
-+static struct net_device_stats *acx_e_get_stats(netdevice_t *dev);
-+static struct iw_statistics *acx_e_get_wireless_stats(netdevice_t *dev);
-+
-+static irqreturn_t acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-+static void acx_i_set_multicast_list(netdevice_t *dev);
-+
-+static int acx_e_open(netdevice_t *dev);
-+static int acx_e_close(netdevice_t *dev);
-+static void acx_s_up(netdevice_t *dev);
-+static void acx_s_down(netdevice_t *dev);
-+
-+
-+/***********************************************************************
-+** Register access
-+*/
-+
-+/* Pick one */
-+/* #define INLINE_IO static */
-+#define INLINE_IO static inline
-+
-+INLINE_IO u32
-+acx_read_reg32(wlandevice_t *priv, unsigned int offset)
-+{
-+#if ACX_IO_WIDTH == 32
-+ return readl((u8 *)priv->iobase + priv->io[offset]);
-+#else
-+ return readw((u8 *)priv->iobase + priv->io[offset])
-+ + (readw((u8 *)priv->iobase + priv->io[offset] + 2) << 16);
-+#endif
-+}
-+
-+INLINE_IO u16
-+acx_read_reg16(wlandevice_t *priv, unsigned int offset)
-+{
-+ return readw((u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+INLINE_IO u8
-+acx_read_reg8(wlandevice_t *priv, unsigned int offset)
-+{
-+ return readb((u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+INLINE_IO void
-+acx_write_reg32(wlandevice_t *priv, unsigned int offset, u32 val)
-+{
-+#if ACX_IO_WIDTH == 32
-+ writel(val, (u8 *)priv->iobase + priv->io[offset]);
-+#else
-+ writew(val & 0xffff, (u8 *)priv->iobase + priv->io[offset]);
-+ writew(val >> 16, (u8 *)priv->iobase + priv->io[offset] + 2);
-+#endif
-+}
-+
-+INLINE_IO void
-+acx_write_reg16(wlandevice_t *priv, unsigned int offset, u16 val)
-+{
-+ writew(val, (u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+INLINE_IO void
-+acx_write_reg8(wlandevice_t *priv, unsigned int offset, u8 val)
-+{
-+ writeb(val, (u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+/* Handle PCI posting properly:
-+ * Make sure that writes reach the adapter in case they require to be executed
-+ * *before* the next write, by reading a random (and safely accessible) register.
-+ * This call has to be made if there is no read following (which would flush the data
-+ * to the adapter), yet the written data has to reach the adapter immediately. */
-+INLINE_IO void
-+acx_write_flush(wlandevice_t *priv)
-+{
-+ /* readb(priv->iobase + priv->io[IO_ACX_INFO_MAILBOX_OFFS]); */
-+ /* faster version (accesses the first register, IO_ACX_SOFT_RESET,
-+ * which should also be safe): */
-+ readb(priv->iobase);
-+}
-+
-+
-+INLINE_IO void acx_mailbox_fill(wlandevice_t *priv, unsigned int offset, unsigned char val, int len){
-+ unsigned int addr = offset;
-+ unsigned int buff = 0;
-+
-+ // Fill the buffer
-+ memset((void *) &buff, val, len);
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x00010000);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, addr);
-+
-+ while(len >= 4){
-+ // Write data
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,buff);
-+ acx_write_flush(priv);
-+
-+ addr += 4;
-+ len -= 4;
-+ }
-+
-+ if(len > 0) {
-+ val = 0;
-+ memset((void *) &buff, val , len);
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,buff);
-+ acx_write_flush(priv);
-+ }
-+}
-+
-+
-+INLINE_IO void acx_mailbox_write(wlandevice_t *priv, unsigned int offset, void *cmd, int len){
-+ unsigned char *buff = (unsigned char *) cmd;
-+ unsigned int addr = offset;
-+ unsigned int val = 0;
-+
-+ if(!cmd){
-+ return;
-+ }
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x00010000);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, addr);
-+
-+ while(len >= 4){
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,*((unsigned int *) buff));
-+ acx_write_flush(priv);
-+
-+ buff += 4;
-+ addr += 4;
-+ len -= 4;
-+ }
-+
-+ if(len > 0) {
-+ val = 0;
-+ memcpy((void *) &val, (void *) buff, len);
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,val);
-+ acx_write_flush(priv);
-+ }
-+}
-+
-+INLINE_IO void acx_mailbox_read(wlandevice_t *priv, unsigned int offset, void *data, int len){
-+ unsigned char *buff = (unsigned char *) data;
-+ unsigned int addr = offset;
-+ unsigned int value = 0;
-+
-+ if(!data){
-+ return;
-+ }
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x00010000);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, addr);
-+
-+ while(len >= 4){
-+ *buff = 0;
-+ *((unsigned int *) buff) = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+
-+ buff += 4;
-+ addr += 4;
-+ len -= 4;
-+ }
-+
-+ if(len > 0){
-+ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+ memcpy((void *) buff, (void *) &value, len);
-+ }
-+}
-+
-+/***********************************************************************
-+*/
-+static const char name_acx100[] = "ACX100";
-+static const char name_tnetw1100a[] = "TNETW1100A";
-+static const char name_tnetw1100b[] = "TNETW1100B";
-+
-+static const char name_acx111[] = "ACX111";
-+static const char name_tnetw1130[] = "TNETW1130";
-+
-+struct device_driver acx_driver = {
-+ .name = CARDNAME,
-+ .bus = &platform_bus_type,
-+ .probe = acx_drv_probe,
-+ .remove = acx_remove,
-+#ifdef CONFIG_PM
-+ .suspend = acx_suspend,
-+ .resume = acx_resume
-+#endif
-+};
-+
-+typedef struct acx_device {
-+ netdevice_t *newest;
-+} acx_device_t;
-+
-+/* if this driver was only about PCI devices, then we probably wouldn't
-+ * need this linked list.
-+ * But if we want to register ALL kinds of devices in one global list,
-+ * then we need it and need to maintain it properly. */
-+static struct acx_device root_acx_dev = {
-+ .newest = NULL,
-+};
-+DECLARE_MUTEX(root_acx_dev_sem);
-+
-+
-+/***********************************************************************
-+*/
-+static inline txdesc_t*
-+get_txdesc(wlandevice_t* priv, int index)
-+{
-+ return (txdesc_t*) (((u8*)priv->txdesc_start) + index * priv->txdesc_size);
-+}
-+
-+static inline txdesc_t*
-+move_txdesc(wlandevice_t* priv, txdesc_t* txdesc, int inc)
-+{
-+ return (txdesc_t*) (((u8*)txdesc) + inc * priv->txdesc_size);
-+}
-+
-+static txhostdesc_t*
-+acx_get_txhostdesc(wlandevice_t* priv, txdesc_t* txdesc)
-+{
-+ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
-+ if (ACX_DEBUG && (index % priv->txdesc_size)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ index /= priv->txdesc_size;
-+ if (ACX_DEBUG && (index >= TX_CNT)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ return &priv->txhostdesc_start[index*2];
-+}
-+
-+static client_t*
-+acx_get_txc(wlandevice_t* priv, txdesc_t* txdesc)
-+{
-+ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
-+ if (ACX_DEBUG && (index % priv->txdesc_size)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ index /= priv->txdesc_size;
-+ if (ACX_DEBUG && (index >= TX_CNT)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ return priv->txc[index];
-+}
-+
-+static void
-+acx_put_txc(wlandevice_t* priv, txdesc_t* txdesc, client_t* c)
-+{
-+ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
-+ if (ACX_DEBUG && (index % priv->txdesc_size)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return;
-+ }
-+ index /= priv->txdesc_size;
-+ if (ACX_DEBUG && (index >= TX_CNT)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return;
-+ }
-+ priv->txc[index] = c;
-+}
-+
-+/***********************************************************************
-+** EEPROM and PHY read/write helpers
-+*/
-+/***********************************************************************
-+** acx_read_eeprom_offset
-+**
-+** Function called to read an octet in the EEPROM.
-+**
-+** This function is used by acx_probe_pci to check if the
-+** connected card is a legal one or not.
-+**
-+** Arguments:
-+** priv ptr to wlandevice structure
-+** addr address to read in the EEPROM
-+** charbuf ptr to a char. This is where the read octet
-+** will be stored
-+**
-+** Returns:
-+** zero (0) - failed
-+** one (1) - success
-+**
-+** NOT ADAPTED FOR ACX111!!
-+*/
-+int
-+acx_read_eeprom_offset(wlandevice_t *priv, u32 addr, u8 *charbuf)
-+{
-+ int result = NOT_OK;
-+ int count;
-+
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
-+
-+ count = 0xffff;
-+ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
-+ /* scheduling away instead of CPU burning loop
-+ * doesn't seem to work here at all:
-+ * awful delay, sometimes also failure.
-+ * Doesn't matter anyway (only small delay). */
-+ if (unlikely(!--count)) {
-+ printk("%s: timeout waiting for EEPROM read\n",
-+ priv->netdev->name);
-+ goto fail;
-+ }
-+ }
-+
-+ *charbuf = acx_read_reg8(priv, IO_ACX_EEPROM_DATA);
-+ acxlog(L_DEBUG, "EEPROM at 0x%04X = 0x%02X\n", addr, *charbuf);
-+ result = OK;
-+
-+fail:
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** Dummy EEPROM read? why?!
-+*/
-+static int
-+acx_read_eeprom_area(wlandevice_t *priv)
-+{
-+ int offs;
-+ u8 tmp[0x3b];
-+
-+ for (offs = 0x8c; offs < 0xb9; offs++) {
-+ acx_read_eeprom_offset(priv, offs, &tmp[offs - 0x8c]);
-+ }
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+** We don't lock hw accesses here since we never r/w eeprom in IRQ
-+** Note: this function sleeps only because of GFP_KERNEL alloc
-+*/
-+#ifdef UNUSED
-+int
-+acx_s_write_eeprom_offset(wlandevice_t *priv, u32 addr, u32 len, const u8 *charbuf)
-+{
-+ u8 *data_verify = NULL;
-+ unsigned long flags;
-+ int count, i;
-+ int result = NOT_OK;
-+ u16 gpio_orig;
-+
-+ printk("acx: WARNING! I would write to EEPROM now. "
-+ "Since I really DON'T want to unless you know "
-+ "what you're doing (THIS CODE WILL PROBABLY "
-+ "NOT WORK YET!), I will abort that now. And "
-+ "definitely make sure to make a "
-+ "/proc/driver/acx_wlan0_eeprom backup copy first!!! "
-+ "(the EEPROM content includes the PCI config header!! "
-+ "If you kill important stuff, then you WILL "
-+ "get in trouble and people DID get in trouble already)\n");
-+ return OK;
-+
-+ FN_ENTER;
-+
-+ data_verify = kmalloc(len, GFP_KERNEL);
-+ if (!data_verify) {
-+ goto end;
-+ }
-+
-+ /* first we need to enable the OE (EEPROM Output Enable) GPIO line
-+ * to be able to write to the EEPROM.
-+ * NOTE: an EEPROM writing success has been reported,
-+ * but you probably have to modify GPIO_OUT, too,
-+ * and you probably need to activate a different GPIO
-+ * line instead! */
-+ gpio_orig = acx_read_reg16(priv, IO_ACX_GPIO_OE);
-+ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig & ~1);
-+ acx_write_flush(priv);
-+
-+ /* ok, now start writing the data out */
-+ for (i = 0; i < len; i++) {
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_DATA, *(charbuf + i));
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 1);
-+
-+ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
-+ if (unlikely(++count > 0xffff)) {
-+ printk("WARNING, DANGER!!! "
-+ "Timeout waiting for EEPROM write\n");
-+ goto end;
-+ }
-+ }
-+ }
-+
-+ /* disable EEPROM writing */
-+ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig);
-+ acx_write_flush(priv);
-+
-+ /* now start a verification run */
-+ count = 0xffff;
-+ for (i = 0; i < len; i++) {
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
-+
-+ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
-+ if (unlikely(!--count)) {
-+ printk("timeout waiting for EEPROM read\n");
-+ goto end;
-+ }
-+ }
-+
-+ data_verify[i] = acx_read_reg16(priv, IO_ACX_EEPROM_DATA);
-+ }
-+
-+ if (0 == memcmp(charbuf, data_verify, len))
-+ result = OK; /* read data matches, success */
-+
-+end:
-+ kfree(data_verify);
-+ FN_EXIT1(result);
-+ return result;
-+}
-+#endif /* UNUSED */
-+
-+
-+/***********************************************************************
-+** acxpci_s_read_phy_reg
-+**
-+** Messing with rx/tx disabling and enabling here
-+** (acx_write_reg32(priv, IO_ACX_ENABLE, 0b000000xx)) kills traffic
-+*/
-+int
-+acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
-+{
-+ int result = NOT_OK;
-+ int count;
-+
-+ FN_ENTER;
-+
-+ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_PHY_CTL, 2);
-+
-+ count = 0xffff;
-+ while (acx_read_reg32(priv, IO_ACX_PHY_CTL)) {
-+ /* scheduling away instead of CPU burning loop
-+ * doesn't seem to work here at all:
-+ * awful delay, sometimes also failure.
-+ * Doesn't matter anyway (only small delay). */
-+ if (unlikely(!--count)) {
-+ printk("%s: timeout waiting for phy read\n",
-+ priv->netdev->name);
-+ *charbuf = 0;
-+ goto fail;
-+ }
-+ }
-+
-+ acxlog(L_DEBUG, "count was %u\n", count);
-+ *charbuf = acx_read_reg8(priv, IO_ACX_PHY_DATA);
-+
-+ acxlog(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg);
-+ result = OK;
-+ goto fail; /* silence compiler warning */
-+fail:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
-+{
-+ FN_ENTER;
-+
-+ /* FIXME: we didn't use 32bit access here since mprusko said that
-+ * it results in distorted sensitivity on his card (huh!?!?
-+ * doesn't happen with my setup...)
-+ * But with the access reordering and flushing it
-+ * shouldn't happen any more...
-+ * FIXME: which radio is in the problematic card? My working one
-+ * is 0x11 */
-+ acx_write_reg32(priv, IO_ACX_PHY_DATA, value);
-+ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_PHY_CTL, 1);
-+ acx_write_flush(priv);
-+ acxlog(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+#define NO_AUTO_INCREMENT 1
-+
-+/***********************************************************************
-+** acx_s_write_fw
-+**
-+** Write the firmware image into the card.
-+**
-+** Arguments:
-+** priv wlan device structure
-+** apfw_image firmware image.
-+**
-+** Returns:
-+** 1 firmware image corrupted
-+** 0 success
-+*/
-+static int
-+acx_s_write_fw(wlandevice_t *priv, const firmware_image_t *apfw_image, u32 offset)
-+{
-+ int len, size;
-+ u32 sum, v32;
-+ /* we skip the first four bytes which contain the control sum */
-+ const u8 *image = (u8*)apfw_image + 4;
-+
-+ /* start the image checksum by adding the image size value */
-+ sum = image[0]+image[1]+image[2]+image[3];
-+ image += 4;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
-+
-+#if NO_AUTO_INCREMENT
-+ acxlog(L_INIT, "not using auto increment for firmware loading\n");
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
-+#else
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
-+ acx_write_flush(priv);
-+#endif
-+
-+ len = 0;
-+ size = le32_to_cpu(apfw_image->size) & (~3);
-+
-+ while (likely(len < size)) {
-+ v32 = be32_to_cpu(*(u32*)image);
-+ sum += image[0]+image[1]+image[2]+image[3];
-+ image += 4;
-+ len += 4;
-+
-+#if NO_AUTO_INCREMENT
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
-+ acx_write_flush(priv);
-+#endif
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, v32);
-+ }
-+
-+ acxlog(L_DEBUG, "%s: firmware written\n", __func__);
-+
-+ /* compare our checksum with the stored image checksum */
-+ return (sum != le32_to_cpu(apfw_image->chksum));
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_validate_fw
-+**
-+** Compare the firmware image given with
-+** the firmware image written into the card.
-+**
-+** Arguments:
-+** priv wlan device structure
-+** apfw_image firmware image.
-+**
-+** Returns:
-+** NOT_OK firmware image corrupted or not correctly written
-+** OK success
-+*/
-+static int
-+acx_s_validate_fw(wlandevice_t *priv, const firmware_image_t *apfw_image,
-+ u32 offset)
-+{
-+ u32 v32, w32, sum;
-+ int len, size;
-+ int result = OK;
-+ /* we skip the first four bytes which contain the control sum */
-+ const u8 *image = (u8*)apfw_image + 4;
-+
-+ /* start the image checksum by adding the image size value */
-+ sum = image[0]+image[1]+image[2]+image[3];
-+ image += 4;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
-+
-+#if NO_AUTO_INCREMENT
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
-+#else
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
-+#endif
-+
-+ len = 0;
-+ size = le32_to_cpu(apfw_image->size) & (~3);
-+
-+ while (likely(len < size)) {
-+ v32 = be32_to_cpu(*(u32*)image);
-+ image += 4;
-+ len += 4;
-+
-+#if NO_AUTO_INCREMENT
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
-+#endif
-+ w32 = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+
-+ if (unlikely(w32 != v32)) {
-+ printk("acx: FATAL: firmware upload: "
-+ "data parts at offset %d don't match (0x%08X vs. 0x%08X)! "
-+ "I/O timing issues or defective memory, with DWL-xx0+? "
-+ "ACX_IO_WIDTH=16 may help. Please report\n",
-+ len, v32, w32);
-+ result = NOT_OK;
-+ break;
-+ }
-+
-+ sum += (u8)w32 + (u8)(w32>>8) + (u8)(w32>>16) + (u8)(w32>>24);
-+ }
-+
-+ /* sum control verification */
-+ if (result != NOT_OK) {
-+ if (sum != le32_to_cpu(apfw_image->chksum)) {
-+ printk("acx: FATAL: firmware upload: "
-+ "checksums don't match!\n");
-+ result = NOT_OK;
-+ }
-+ }
-+
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_upload_fw
-+**
-+** Arguments:
-+** wlandevice: private device that contains card device
-+** Returns:
-+** NOT_OK: failed
-+** OK: success
-+** Call context:
-+** acx_reset_dev
-+*/
-+static int
-+acx_s_upload_fw(wlandevice_t *priv)
-+{
-+ firmware_image_t *apfw_image = NULL;
-+ int res = NOT_OK;
-+ int try;
-+ u32 size;
-+ char filename[sizeof("tiacx1NNcNN")];
-+
-+ FN_ENTER;
-+
-+ /* Try combined, then main image */
-+ priv->need_radio_fw = 0;
-+ sprintf(filename, "tiacx1%02dc%02X",
-+ IS_ACX111(priv)*11, priv->radio_type);
-+
-+ apfw_image = acx_s_read_fw(priv->dev, filename, &size);
-+ if (!apfw_image) {
-+ priv->need_radio_fw = 1;
-+ filename[sizeof("tiacx1NN")-1] = '\0';
-+ apfw_image = acx_s_read_fw(priv->dev, filename, &size);
-+ if (!apfw_image) {
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+ }
-+ }
-+
-+ for (try = 1; try <= 5; try++) {
-+ res = acx_s_write_fw(priv, apfw_image, 0);
-+ acxlog(L_DEBUG|L_INIT, "acx_write_fw (main/combined):%d\n", res);
-+ if (OK == res) {
-+ res = acx_s_validate_fw(priv, apfw_image, 0);
-+ acxlog(L_DEBUG|L_INIT, "acx_validate_fw "
-+ "(main/combined):%d\n", res);
-+ }
-+
-+ if (OK == res) {
-+ SET_BIT(priv->dev_state_mask, ACX_STATE_FW_LOADED);
-+ break;
-+ }
-+ printk("acx: firmware upload attempt #%d FAILED, "
-+ "retrying...\n", try);
-+ acx_s_msleep(1000); /* better wait for a while... */
-+ }
-+
-+ vfree((void *) apfw_image);
-+
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_upload_radio
-+**
-+** Uploads the appropriate radio module firmware
-+** into the card.
-+*/
-+int
-+acx_s_upload_radio(wlandevice_t *priv)
-+{
-+ acx_ie_memmap_t mm;
-+ firmware_image_t *radio_image = NULL;
-+ acx_cmd_radioinit_t radioinit;
-+ int res = NOT_OK;
-+ int try;
-+ u32 offset;
-+ u32 size;
-+ char filename[sizeof("tiacx1NNrNN")];
-+
-+ if (!priv->need_radio_fw) return OK;
-+
-+ FN_ENTER;
-+
-+ acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
-+ offset = le32_to_cpu(mm.CodeEnd);
-+
-+ sprintf(filename, "tiacx1%02dr%02X",
-+ IS_ACX111(priv)*11,
-+ priv->radio_type);
-+ radio_image = acx_s_read_fw(priv->dev, filename, &size);
-+ if (!radio_image) {
-+ printk("acx: can't load radio module '%s'\n", filename);
-+ goto fail;
-+ }
-+
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_SLEEP, NULL, 0);
-+
-+ for (try = 1; try <= 5; try++) {
-+ res = acx_s_write_fw(priv, radio_image, offset);
-+ acxlog(L_DEBUG|L_INIT, "acx_write_fw (radio): %d\n", res);
-+ if (OK == res) {
-+ res = acx_s_validate_fw(priv, radio_image, offset);
-+ acxlog(L_DEBUG|L_INIT, "acx_validate_fw (radio): %d\n", res);
-+ }
-+
-+ if (OK == res)
-+ break;
-+ printk("acx: radio firmware upload attempt #%d FAILED, "
-+ "retrying...\n", try);
-+ acx_s_msleep(1000); /* better wait for a while... */
-+ }
-+
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
-+ radioinit.offset = cpu_to_le32(offset);
-+ /* no endian conversion needed, remains in card CPU area: */
-+ radioinit.len = radio_image->size;
-+
-+ vfree(radio_image);
-+
-+ if (OK != res)
-+ goto fail;
-+
-+ /* will take a moment so let's have a big timeout */
-+ acx_s_issue_cmd_timeo(priv, ACX1xx_CMD_RADIOINIT,
-+ &radioinit, sizeof(radioinit), CMD_TIMEOUT_MS(1000));
-+
-+ res = acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
-+fail:
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+void write_reg(wlandevice_t *priv, int reg, u32 value){
-+ acx_write_reg32(priv,IO_ACX_HW_SLAVE_REG_ADDR,priv->io[reg]);
-+ acx_write_reg16(priv,IO_ACX_HW_SLAVE_REG_DATA,value);
-+}
-+
-+u32 read_reg(wlandevice_t *priv, int reg){
-+ u32 value;
-+
-+ acx_write_reg32(priv,IO_ACX_HW_SLAVE_REG_ADDR,reg);
-+ value = acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_DATA);
-+
-+ return value;
-+}
-+
-+
-+/***********************************************************************
-+** acx_l_reset_mac
-+**
-+** Arguments:
-+** wlandevice: private device that contains card device
-+** Side effects:
-+** MAC will be reset
-+** Call context:
-+** acx_reset_dev
-+** Comment:
-+** resets onboard acx100 MAC
-+**
-+** Requires lock to be taken
-+*/
-+static void
-+acx_l_reset_mac(wlandevice_t *priv)
-+{
-+ u16 temp;
-+
-+ FN_ENTER;
-+
-+ /* Pocket PC driver setting this register
-+ * with 2.
-+ */
-+ acx_write_reg16(priv,IO_ACX_PCI_ARB_CFG,0x2);
-+
-+ msleep(300);
-+
-+ /* halt eCPU */
-+ acxlog(L_DEBUG, "%s: Halt eCPU ...\n", __func__);
-+ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
-+ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
-+ acx_write_flush(priv);
-+
-+ test(priv);
-+
-+ /* now do soft reset of eCPU */
-+ temp = acx_read_reg16(priv, IO_ACX_SOFT_RESET) | 0x1;
-+ acxlog(L_DEBUG, "%s: enable soft reset...\n", __func__);
-+ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp);
-+ acx_write_flush(priv);
-+
-+ test(priv);
-+
-+ /* now reset bit again */
-+ acxlog(L_DEBUG, "%s: disable soft reset and go to init mode...\n", __func__);
-+ /* deassert eCPU reset */
-+ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp & ~0x1);
-+
-+ /* now start a burst read from initial flash EEPROM */
-+ temp = acx_read_reg16(priv, IO_ACX_EE_START) | 0x1;
-+ acx_write_reg16(priv, IO_ACX_EE_START, temp);
-+ acx_write_flush(priv);
-+
-+ test(priv);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_verify_init
-+*/
-+static int
-+acx_s_verify_init(wlandevice_t *priv)
-+{
-+ int result = NOT_OK;
-+ int timer;
-+
-+ FN_ENTER;
-+
-+ for (timer = 40; timer > 0; timer--) {
-+ u16 irqstat = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
-+ if (irqstat & HOST_INT_FCS_THRESHOLD) {
-+ result = OK;
-+ acx_write_reg16(priv, IO_ACX_IRQ_ACK, HOST_INT_FCS_THRESHOLD);
-+ break;
-+ }
-+ /* HZ / 50 resulted in 24 schedules for ACX100 on my machine,
-+ * so better schedule away longer for greater efficiency,
-+ * decrease loop count */
-+ acx_s_msleep(50);
-+ }
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+
-+/***********************************************************************
-+** A few low-level helpers
-+**
-+** Note: these functions are not protected by lock
-+** and thus are never allowed to be called from IRQ.
-+** Also they must not race with fw upload which uses same hw regs
-+*/
-+
-+/***********************************************************************
-+** acx_read_info_status
-+*/
-+/* Info mailbox format:
-+2 bytes: type
-+2 bytes: status
-+more bytes may follow
-+ docs say about status:
-+ 0x0000 info available (set by hw)
-+ 0x0001 information received (must be set by host)
-+ 0x1000 info available, mailbox overflowed (messages lost) (set by hw)
-+ but in practice we've seen:
-+ 0x9000 when we did not set status to 0x0001 on prev message
-+ 0x1001 when we did set it
-+ 0x0000 was never seen
-+ conclusion: this is really a bitfield:
-+ 0x1000 is 'info available' bit
-+ 'mailbox overflowed' bit is 0x8000, not 0x1000
-+ value of 0x0000 probably means that there is no message at all
-+ P.S. I dunno how in hell hw is supposed to notice that messages are lost -
-+ it does NOT clear bit 0x0001, and this bit will probably stay forever set
-+ after we set it once. Let's hope this will be fixed in firmware someday
-+*/
-+static void
-+acx_read_info_status(wlandevice_t *priv)
-+{
-+ u32 value;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1);
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
-+ acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS));
-+
-+ /* make sure we only read the data once all cfg registers are written: */
-+ acx_write_flush(priv);
-+ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+
-+ priv->info_type = (u16)value;
-+ priv->info_status = (value >> 16);
-+
-+ /* inform hw that we have read this info message */
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, priv->info_type | 0x00010000);
-+ acx_write_flush(priv);
-+ /* now bother hw to notice it: */
-+ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_INFOACK);
-+ acx_write_flush(priv);
-+
-+ acxlog(L_CTL, "info_type 0x%04X, info_status 0x%04X\n",
-+ priv->info_type, priv->info_status);
-+}
-+
-+
-+/***********************************************************************
-+** acx_write_cmd_type_or_status
-+*/
-+static void
-+acx_write_cmd_type_or_status(wlandevice_t *priv, u32 val)
-+{
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
-+ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
-+
-+ /* make sure we only write the data once all config registers are written */
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, val);
-+ acx_write_flush(priv);
-+}
-+static inline void
-+acx_write_cmd_type(wlandevice_t *priv, u32 val)
-+{
-+ acx_write_cmd_type_or_status(priv, val);
-+}
-+static inline void
-+acx_write_cmd_status(wlandevice_t *priv, u32 val)
-+{
-+ acx_write_cmd_type_or_status(priv, val<<16);
-+}
-+
-+
-+/***********************************************************************
-+** acx_read_cmd_status
-+*/
-+static void
-+acx_read_cmd_status(wlandevice_t *priv)
-+{
-+ u32 value;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
-+ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
-+
-+ /* make sure we only read the data once all config registers are written */
-+ acx_write_flush(priv);
-+ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+
-+ priv->cmd_type = (u16)value;
-+ priv->cmd_status = (value >> 16);
-+
-+ acxlog(L_CTL, "cmd_type 0x%04X, cmd_status 0x%04X [%s]\n",
-+ priv->cmd_type, priv->cmd_status,
-+ acx_cmd_status_str(priv->cmd_status));
-+}
-+
-+/***********************************************************************
-+** acx_s_reset_dev
-+**
-+** Arguments:
-+** netdevice that contains the wlandevice priv variable
-+** Returns:
-+** NOT_OK on fail
-+** OK on success
-+** Side effects:
-+** device is hard reset
-+** Call context:
-+** acx_probe_pci
-+** Comment:
-+** This resets the acx100 device using low level hardware calls
-+** as well as uploads and verifies the firmware to the card
-+*/
-+static int
-+acx_s_reset_dev(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ const char* msg = "";
-+ unsigned long flags;
-+ int result = NOT_OK;
-+ u16 hardware_info;
-+ u16 ecpu_ctrl;
-+
-+ FN_ENTER;
-+
-+ /* we're doing a reset, so hardware is unavailable */
-+
-+ /* reset the device to make sure the eCPU is stopped
-+ * to upload the firmware correctly */
-+
-+ acx_lock(priv, flags);
-+
-+ acx_l_reset_mac(priv);
-+
-+ ecpu_ctrl = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) & 1;
-+ if (!ecpu_ctrl) {
-+ msg = "eCPU is already running. ";
-+ goto fail_unlock;
-+ }
-+
-+#ifdef WE_DONT_NEED_THAT_DO_WE
-+ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 2) {
-+ /* eCPU most likely means "embedded CPU" */
-+ msg = "eCPU did not start after boot from flash. ";
-+ goto fail_unlock;
-+ }
-+
-+ /* check sense on reset flags */
-+ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 0x10) {
-+ printk("%s: eCPU did not start after boot (SOR), "
-+ "is this fatal?\n", dev->name);
-+ }
-+#endif
-+ /* scan, if any, is stopped now, setting corresponding IRQ bit */
-+ priv->irq_status |= HOST_INT_SCAN_COMPLETE;
-+
-+ acx_unlock(priv, flags);
-+
-+ /* without this delay acx100 may fail to report hardware_info
-+ ** (see below). Most probably eCPU runs some init code */
-+ acx_s_msleep(10);
-+
-+ /* Need to know radio type before fw load */
-+ hardware_info = acx_read_reg16(priv, IO_ACX_EEPROM_INFORMATION);
-+ priv->form_factor = hardware_info & 0xff;
-+ priv->radio_type = hardware_info >> 8;
-+
-+ /* load the firmware */
-+ if (OK != acx_s_upload_fw(priv)){
-+ printk("Failed to load firmware\n");
-+ goto fail;
-+ }
-+
-+ acx_s_msleep(10);
-+
-+ /* now start eCPU by clearing bit */
-+ acxlog(L_DEBUG, "booted eCPU up and waiting for completion...\n");
-+ //acx_write_reg16(priv, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1);
-+ write_reg(priv, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1);
-+
-+ /* wait for eCPU bootup */
-+ if (OK != acx_s_verify_init(priv)) {
-+ msg = "timeout waiting for eCPU. ";
-+ goto fail;
-+ }
-+
-+ acxlog(L_DEBUG, "eCPU has woken up, card is ready to be configured\n");
-+
-+ if (IS_ACX111(priv)) {
-+ acxlog(L_DEBUG, "cleaning up cmd mailbox access area\n");
-+ acx_write_cmd_status(priv, 0);
-+ acx_read_cmd_status(priv);
-+ if (priv->cmd_status) {
-+ msg = "error cleaning cmd mailbox area. ";
-+ goto fail;
-+ }
-+ }
-+
-+ /* TODO what is this one doing ?? adapt for acx111 */
-+ if ((OK != acx_read_eeprom_area(priv)) && IS_ACX100(priv)) {
-+ /* does "CIS" mean "Card Information Structure"?
-+ * If so, then this would be a PCMCIA message...
-+ */
-+ msg = "CIS error. ";
-+ goto fail;
-+ }
-+
-+ result = OK;
-+ FN_EXIT1(result);
-+ return result;
-+
-+/* Finish error message. Indicate which function failed */
-+fail_unlock:
-+ acx_unlock(priv, flags);
-+fail:
-+ printk("acx: %sreset_dev() FAILED\n", msg);
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_init_mboxes
-+*/
-+void
-+acx_init_mboxes(wlandevice_t *priv)
-+{
-+ u32 cmd_offs, info_offs;
-+
-+ FN_ENTER;
-+
-+ cmd_offs = acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS);
-+ info_offs = acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS);
-+ priv->cmd_area = (u8 *) cmd_offs + 0x4;
-+ priv->info_area = (u8 *) info_offs + 0x4;
-+ acxlog(L_DEBUG, "iobase2=%p\n"
-+ "cmd_mbox_offset=%X cmd_area=%p\n"
-+ "info_mbox_offset=%X info_area=%p\n",
-+ priv->iobase2,
-+ cmd_offs, priv->cmd_area,
-+ info_offs, priv->info_area);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_issue_cmd_timeo
-+* Excecutes a command in the command mailbox
-+*
-+* Arguments:
-+* *pcmdparam = an pointer to the data. The data mustn't include
-+* the 4 byte command header!
-+*
-+* NB: we do _not_ take lock inside, so be sure to not touch anything
-+* which may interfere with IRQ handler operation
-+*
-+* TODO: busy wait is a bit silly, so:
-+* 1) stop doing many iters - go to sleep after first
-+* 2) go to waitqueue based approach: wait, not poll!
-+*----------------------------------------------------------------*/
-+#undef FUNC
-+#define FUNC "issue_cmd"
-+
-+#if !ACX_DEBUG
-+int
-+acxpci_s_issue_cmd_timeo(
-+ wlandevice_t *priv,
-+ unsigned int cmd,
-+ void *buffer,
-+ unsigned buflen,
-+ unsigned timeout)
-+{
-+#else
-+int
-+acxpci_s_issue_cmd_timeo_debug(
-+ wlandevice_t *priv,
-+ unsigned cmd,
-+ void *buffer,
-+ unsigned buflen,
-+ unsigned timeout,
-+ const char* cmdstr)
-+{
-+ unsigned long start = jiffies;
-+#endif
-+ const char *devname;
-+ unsigned counter;
-+ u16 irqtype;
-+ u16 cmd_status;
-+
-+ FN_ENTER;
-+
-+ devname = priv->netdev->name;
-+ if (!devname || !devname[0])
-+ devname = "acx";
-+
-+ acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,timeout:%ums,type:0x%04X)\n",
-+ cmdstr, buflen, timeout,
-+ buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
-+
-+ if (!(priv->dev_state_mask & ACX_STATE_FW_LOADED)) {
-+ printk("%s: "FUNC"(): firmware is not loaded yet, "
-+ "cannot execute commands!\n", devname);
-+ goto bad;
-+ }
-+
-+ if ((acx_debug & L_DEBUG) && (cmd != ACX1xx_CMD_INTERROGATE)) {
-+ printk("input pdr (len=%u):\n", buflen);
-+ acx_dump_bytes(buffer, buflen);
-+ }
-+
-+ /* wait for firmware to become idle for our command submission */
-+ counter = 199; /* in ms */
-+ do {
-+ acx_read_cmd_status(priv);
-+ /* Test for IDLE state */
-+ if (!priv->cmd_status)
-+ break;
-+ if (counter % 10 == 0) {
-+ /* we waited 10 iterations, no luck. Sleep 10 ms */
-+ acx_s_msleep(10);
-+ }
-+ } while (--counter);
-+
-+ if (!counter) {
-+ /* the card doesn't get idle, we're in trouble */
-+ printk("%s: "FUNC"(): cmd_status is not IDLE: 0x%04X!=0\n",
-+ devname, priv->cmd_status);
-+ goto bad;
-+ } else if (counter < 190) { /* if waited >10ms... */
-+ acxlog(L_CTL|L_DEBUG, FUNC"(): waited for IDLE %dms. "
-+ "Please report\n", 199 - counter);
-+ }
-+
-+ /* now write the parameters of the command if needed */
-+ if (buffer && buflen) {
-+ /* if it's an INTERROGATE command, just pass the length
-+ * of parameters to read, as data */
-+#if CMD_DISCOVERY
-+ if (cmd == ACX1xx_CMD_INTERROGATE)
-+ acx_mailbox_fill(priv, (unsigned int) priv->cmd_area, 0xAA, buflen);
-+#endif
-+ acx_mailbox_write(priv,
-+ (unsigned int) priv->cmd_area,
-+ buffer, (cmd == ACX1xx_CMD_INTERROGATE) ? 4 : buflen);
-+ }
-+
-+ /* now write the actual command type */
-+ priv->cmd_type = cmd;
-+ acx_write_cmd_type(priv, cmd);
-+ /* execute command */
-+ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_CMD);
-+ acx_write_flush(priv);
-+
-+ /* wait for firmware to process command */
-+
-+ /* Ensure nonzero and not too large timeout.
-+ ** Also converts e.g. 100->99, 200->199
-+ ** which is nice but not essential */
-+ timeout = (timeout-1) | 1;
-+ if (unlikely(timeout > 1199))
-+ timeout = 1199;
-+ /* clear CMD_COMPLETE bit. can be set only by IRQ handler: */
-+ priv->irq_status &= ~HOST_INT_CMD_COMPLETE;
-+
-+ /* we schedule away sometimes (timeout can be large) */
-+ counter = timeout;
-+ do {
-+ if (!priv->irqs_active) { /* IRQ disabled: poll */
-+ irqtype = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
-+ if (irqtype & HOST_INT_CMD_COMPLETE) {
-+ acx_write_reg16(priv, IO_ACX_IRQ_ACK,
-+ HOST_INT_CMD_COMPLETE);
-+ break;
-+ }
-+ } else { /* Wait when IRQ will set the bit */
-+ irqtype = priv->irq_status;
-+ if (irqtype & HOST_INT_CMD_COMPLETE)
-+ break;
-+ }
-+
-+ if (counter % 10 == 0) {
-+ /* we waited 10 iterations, no luck. Sleep 10 ms */
-+ acx_s_msleep(10);
-+ }
-+ } while (--counter);
-+
-+ /* save state for debugging */
-+ acx_read_cmd_status(priv);
-+ cmd_status = priv->cmd_status;
-+
-+ /* put the card in IDLE state */
-+ priv->cmd_status = 0;
-+ acx_write_cmd_status(priv, 0);
-+
-+ if (!counter) { /* timed out! */
-+ printk("%s: "FUNC"(): timed out %s for CMD_COMPLETE. "
-+ "irq bits:0x%04X irq_status:0x%04X timeout:%dms "
-+ "cmd_status:%d (%s)\n",
-+ devname, (priv->irqs_active) ? "waiting" : "polling",
-+ irqtype, priv->irq_status, timeout,
-+ cmd_status, acx_cmd_status_str(cmd_status));
-+ goto bad;
-+ } else if (timeout - counter > 30) { /* if waited >30ms... */
-+ acxlog(L_CTL|L_DEBUG, FUNC"(): %s for CMD_COMPLETE %dms. "
-+ "count:%d. Please report\n",
-+ (priv->irqs_active) ? "waited" : "polled",
-+ timeout - counter, counter);
-+ }
-+
-+ if (1 != cmd_status) { /* it is not a 'Success' */
-+ printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s). "
-+ "Took %dms of %d\n",
-+ devname, cmd_status, acx_cmd_status_str(cmd_status),
-+ timeout - counter, timeout);
-+ /* zero out result buffer */
-+ if (buffer && buflen)
-+ memset(buffer, 0, buflen);
-+ goto bad;
-+ }
-+
-+ /* read in result parameters if needed */
-+ if (buffer && buflen && (cmd == ACX1xx_CMD_INTERROGATE)) {
-+ //memcpy(buffer, priv->cmd_area, buflen);
-+ acx_mailbox_read(priv, (unsigned int) priv->cmd_area, buffer, buflen);
-+ if (acx_debug & L_DEBUG) {
-+ printk("output buffer (len=%u): ", buflen);
-+ acx_dump_bytes(buffer, buflen);
-+ }
-+ }
-+/* ok: */
-+ acxlog(L_CTL, FUNC"(%s): took %ld jiffies to complete\n",
-+ cmdstr, jiffies - start);
-+ FN_EXIT1(OK);
-+ return OK;
-+
-+bad:
-+ /* Give enough info so that callers can avoid
-+ ** printing their own diagnostic messages */
-+#if ACX_DEBUG
-+ printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
-+#else
-+ printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
-+#endif
-+ dump_stack();
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_get_firmware_version
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_get_firmware_version(wlandevice_t *priv)
-+{
-+ fw_ver_t fw;
-+ u8 hexarr[4] = { 0, 0, 0, 0 };
-+ int hexidx = 0, val = 0;
-+ const char *num;
-+ char c;
-+
-+ FN_ENTER;
-+
-+ acx_s_interrogate(priv, &fw, ACX1xx_IE_FWREV);
-+ memcpy(priv->firmware_version, fw.fw_id, FW_ID_SIZE);
-+ priv->firmware_version[FW_ID_SIZE] = '\0';
-+ acxlog(L_DEBUG, "fw_ver: fw_id='%s' hw_id=%08X\n",
-+ priv->firmware_version, fw.hw_id);
-+
-+ if (strncmp(fw.fw_id, "Rev ", 4) != 0) {
-+ printk("acx: strange firmware version string "
-+ "'%s', please report\n", priv->firmware_version);
-+ priv->firmware_numver = 0x01090407; /* assume 1.9.4.7 */
-+ } else {
-+ num = &fw.fw_id[4];
-+ while (1) {
-+ c = *num++;
-+ if ((c == '.') || (c == '\0')) {
-+ hexarr[hexidx++] = val;
-+ if ((hexidx > 3) || (c == '\0')) /* end? */
-+ break;
-+ val = 0;
-+ continue;
-+ }
-+ if ((c >= '0') && (c <= '9'))
-+ c -= '0';
-+ else
-+ c = c - 'a' + (char)10;
-+ val = val*16 + c;
-+ }
-+
-+ priv->firmware_numver = (u32)(
-+ (hexarr[0] << 24) + (hexarr[1] << 16)
-+ + (hexarr[2] << 8) + hexarr[3]);
-+ acxlog(L_DEBUG, "firmware_numver 0x%08X\n", priv->firmware_numver);
-+ }
-+ if (IS_ACX111(priv)) {
-+ if (priv->firmware_numver == 0x00010011) {
-+ /* This one does not survive floodpinging */
-+ printk("acx: firmware '%s' is known to be buggy, "
-+ "please upgrade\n", priv->firmware_version);
-+ }
-+ if (priv->firmware_numver == 0x02030131) {
-+ /* With this one, all rx packets look mangled
-+ ** Most probably we simply do not know how to use it
-+ ** properly */
-+ printk("acx: firmware '%s' does not work well "
-+ "with this driver\n", priv->firmware_version);
-+ }
-+ }
-+
-+ priv->firmware_id = le32_to_cpu(fw.hw_id);
-+
-+ /* we're able to find out more detailed chip names now */
-+ switch (priv->firmware_id & 0xffff0000) {
-+ case 0x01010000:
-+ case 0x01020000:
-+ priv->chip_name = name_tnetw1100a;
-+ break;
-+ case 0x01030000:
-+ priv->chip_name = name_tnetw1100b;
-+ break;
-+ case 0x03000000:
-+ case 0x03010000:
-+ priv->chip_name = name_tnetw1130;
-+ break;
-+ default:
-+ printk("acx: unknown chip ID 0x%08X, "
-+ "please report\n", priv->firmware_id);
-+ break;
-+ }
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_display_hardware_details
-+*
-+* Arguments:
-+* priv: ptr to wlandevice that contains all the details
-+* displayed by this function
-+* Call context:
-+* acx_probe_pci
-+* Comment:
-+* This function will display strings to the system log according
-+* to device form_factor and radio type. It will needed to be
-+*----------------------------------------------------------------*/
-+static void
-+acx_display_hardware_details(wlandevice_t *priv)
-+{
-+ const char *radio_str, *form_str;
-+
-+ FN_ENTER;
-+
-+ switch (priv->radio_type) {
-+ case RADIO_MAXIM_0D:
-+ /* hmm, the DWL-650+ seems to have two variants,
-+ * according to a windows driver changelog comment:
-+ * RFMD and Maxim. */
-+ radio_str = "Maxim";
-+ break;
-+ case RADIO_RFMD_11:
-+ radio_str = "RFMD";
-+ break;
-+ case RADIO_RALINK_15:
-+ radio_str = "Ralink";
-+ break;
-+ case RADIO_RADIA_16:
-+ radio_str = "Radia";
-+ break;
-+ case RADIO_UNKNOWN_17:
-+ /* TI seems to have a radio which is
-+ * additionally 802.11a capable, too */
-+ radio_str = "802.11a/b/g radio?! Please report";
-+ break;
-+ case RADIO_UNKNOWN_19:
-+ radio_str = "A radio used by Safecom cards?! Please report";
-+ break;
-+ default:
-+ radio_str = "UNKNOWN, please report the radio type name!";
-+ break;
-+ }
-+
-+ switch (priv->form_factor) {
-+ case 0x00:
-+ form_str = "unspecified";
-+ break;
-+ case 0x01:
-+ form_str = "(mini-)PCI / CardBus";
-+ break;
-+ case 0x02:
-+ form_str = "USB";
-+ break;
-+ case 0x03:
-+ form_str = "Compact Flash";
-+ break;
-+ default:
-+ form_str = "UNKNOWN, Please report";
-+ break;
-+ }
-+
-+ printk("acx: form factor 0x%02X (%s), "
-+ "radio type 0x%02X (%s), EEPROM version 0x%02X, "
-+ "uploaded firmware '%s' (0x%08X)\n",
-+ priv->form_factor, form_str, priv->radio_type, radio_str,
-+ priv->eeprom_version, priv->firmware_version,
-+ priv->firmware_id);
-+
-+ FN_EXIT0;
-+}
-+
-+/***********************************************************************
-+*/
-+#ifdef NONESSENTIAL_FEATURES
-+typedef struct device_id {
-+ unsigned char id[6];
-+ char *descr;
-+ char *type;
-+} device_id_t;
-+
-+static const device_id_t
-+device_ids[] =
-+{
-+ {
-+ {'G', 'l', 'o', 'b', 'a', 'l'},
-+ NULL,
-+ NULL,
-+ },
-+ {
-+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-+ "uninitialized",
-+ "SpeedStream SS1021 or Gigafast WF721-AEX"
-+ },
-+ {
-+ {0x80, 0x81, 0x82, 0x83, 0x84, 0x85},
-+ "non-standard",
-+ "DrayTek Vigor 520"
-+ },
-+ {
-+ {'?', '?', '?', '?', '?', '?'},
-+ "non-standard",
-+ "Level One WPC-0200"
-+ },
-+ {
-+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
-+ "empty",
-+ "DWL-650+ variant"
-+ }
-+};
-+
-+static void
-+acx_show_card_eeprom_id(wlandevice_t *priv)
-+{
-+ unsigned char buffer[CARD_EEPROM_ID_SIZE];
-+ int i;
-+
-+ memset(&buffer, 0, CARD_EEPROM_ID_SIZE);
-+ /* use direct EEPROM access */
-+ for (i = 0; i < CARD_EEPROM_ID_SIZE; i++) {
-+ if (OK != acx_read_eeprom_offset(priv,
-+ ACX100_EEPROM_ID_OFFSET + i,
-+ &buffer[i]))
-+ {
-+ printk("acx: reading EEPROM FAILED\n");
-+ break;
-+ }
-+ }
-+
-+ for (i = 0; i < VEC_SIZE(device_ids); i++) {
-+ if (!memcmp(&buffer, device_ids[i].id, CARD_EEPROM_ID_SIZE)) {
-+ if (device_ids[i].descr) {
-+ printk("acx: EEPROM card ID string check "
-+ "found %s card ID: is this %s?\n",
-+ device_ids[i].descr, device_ids[i].type);
-+ }
-+ break;
-+ }
-+ }
-+ if (i == VEC_SIZE(device_ids)) {
-+ printk("acx: EEPROM card ID string check found "
-+ "unknown card: expected 'Global', got '%.*s\'. "
-+ "Please report\n", CARD_EEPROM_ID_SIZE, buffer);
-+ }
-+}
-+#endif /* NONESSENTIAL_FEATURES */
-+
-+
-+/***********************************************************************
-+*/
-+static void
-+acx_s_device_chain_add(struct net_device *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ down(&root_acx_dev_sem);
-+ priv->prev_nd = root_acx_dev.newest;
-+ root_acx_dev.newest = dev;
-+ priv->netdev = dev;
-+ up(&root_acx_dev_sem);
-+}
-+
-+static void
-+acx_s_device_chain_remove(struct net_device *dev)
-+{
-+ struct net_device *querydev;
-+ struct net_device *olderdev;
-+ struct net_device *newerdev;
-+
-+ down(&root_acx_dev_sem);
-+ querydev = root_acx_dev.newest;
-+ newerdev = NULL;
-+ while (querydev) {
-+ olderdev = ((wlandevice_t*)netdev_priv(querydev))->prev_nd;
-+ if (0 == strcmp(querydev->name, dev->name)) {
-+ if (!newerdev) {
-+ /* if we were at the beginning of the
-+ * list, then it's the list head that
-+ * we need to update to point at the
-+ * next older device */
-+ root_acx_dev.newest = olderdev;
-+ } else {
-+ /* it's the device that is newer than us
-+ * that we need to update to point at
-+ * the device older than us */
-+ ((wlandevice_t*)netdev_priv(newerdev))->
-+ prev_nd = olderdev;
-+ }
-+ break;
-+ }
-+ /* "newerdev" is actually the device of the old iteration,
-+ * but since the list starts (root_acx_dev.newest)
-+ * with the newest devices,
-+ * it's newer than the ones following.
-+ * Oh the joys of iterating from newest to oldest :-\ */
-+ newerdev = querydev;
-+
-+ /* keep checking old devices for matches until we hit the end
-+ * of the list */
-+ querydev = olderdev;
-+ }
-+ up(&root_acx_dev_sem);
-+}
-+
-+
-+/***********************************************************************
-+** acx_free_desc_queues
-+**
-+** Releases the queues that have been allocated, the
-+** others have been initialised to NULL so this
-+** function can be used if only part of the queues were allocated.
-+*/
-+static inline void
-+acx_free_coherent(struct pci_dev *hwdev, size_t size,
-+ void *vaddr, dma_addr_t dma_handle)
-+{
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 53)
-+ dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev,
-+ size, vaddr, dma_handle);
-+#else
-+ pci_free_consistent(hwdev, size, vaddr, dma_handle);
-+#endif
-+}
-+
-+void
-+acx_free_desc_queues(wlandevice_t *priv)
-+{
-+#define ACX_FREE_QUEUE(size, ptr, phyaddr) \
-+ if (ptr) { \
-+ acx_free_coherent(0, size, ptr, phyaddr); \
-+ ptr = NULL; \
-+ size = 0; \
-+ }
-+
-+ FN_ENTER;
-+
-+ ACX_FREE_QUEUE(priv->txhostdesc_area_size, priv->txhostdesc_start, priv->txhostdesc_startphy);
-+ ACX_FREE_QUEUE(priv->txbuf_area_size, priv->txbuf_start, priv->txbuf_startphy);
-+
-+ priv->txdesc_start = NULL;
-+
-+ ACX_FREE_QUEUE(priv->rxhostdesc_area_size, priv->rxhostdesc_start, priv->rxhostdesc_startphy);
-+ ACX_FREE_QUEUE(priv->rxbuf_area_size, priv->rxbuf_start, priv->rxbuf_startphy);
-+
-+ priv->rxdesc_start = NULL;
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_delete_dma_regions
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_delete_dma_regions(wlandevice_t *priv)
-+{
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+ /* disable radio Tx/Rx. Shouldn't we use the firmware commands
-+ * here instead? Or are we that much down the road that it's no
-+ * longer possible here? */
-+ acx_write_reg16(priv, IO_ACX_ENABLE, 0);
-+
-+ acx_s_msleep(100);
-+
-+ acx_lock(priv, flags);
-+ acx_free_desc_queues(priv);
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_probe_pci
-+*
-+* Probe routine called when a PCI device w/ matching ID is found.
-+* Here's the sequence:
-+* - Allocate the PCI resources.
-+* - Read the PCMCIA attribute memory to make sure we have a WLAN card
-+* - Reset the MAC
-+* - Initialize the dev and wlan data
-+* - Initialize the MAC
-+*
-+* Arguments:
-+* pdev ptr to pci device structure containing info about
-+* pci configuration.
-+* id ptr to the device id entry that matched this device.
-+*
-+* Returns:
-+* zero - success
-+* negative - failed
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+static const u16
-+IO_ACX100[] =
-+{
-+ 0x0000, /* IO_ACX_SOFT_RESET */
-+
-+ 0x0004, /* IO_ACX_HW_SLAVE_REG_ADDR */
-+ 0x0008, /* IO_ACX_HW_SLAVE_REG_DATA */
-+ 0x000c, /* IO_ACX_HW_SLAVE_REG_REG_CTRL */
-+
-+ 0x0014, /* IO_ACX_SLV_MEM_ADDR */
-+ 0x0018, /* IO_ACX_SLV_MEM_DATA */
-+ 0x001c, /* IO_ACX_SLV_MEM_CTL */
-+ 0x0020, /* IO_ACX_SLV_END_CTL */
-+ 0x0024, /* IO_ACX_CHIPID */
-+
-+ 0x0034, /* IO_ACX_FEMR */
-+
-+ 0x007c, /* IO_ACX_INT_TRIG */
-+ 0x0098, /* IO_ACX_IRQ_MASK */
-+ 0x00a4, /* IO_ACX_IRQ_STATUS_NON_DES */
-+ 0x00a8, /* IO_ACX_IRQ_STATUS_CLEAR */
-+ 0x00ac, /* IO_ACX_IRQ_ACK */
-+ 0x00b0, /* IO_ACX_HINT_TRIG */
-+
-+ 0x0104, /* IO_ACX_ENABLE */
-+
-+ 0x0250, /* IO_ACX_EEPROM_CTL */
-+ 0x0254, /* IO_ACX_EEPROM_ADDR */
-+ 0x0258, /* IO_ACX_EEPROM_DATA */
-+ 0x025c, /* IO_ACX_EEPROM_CFG */
-+
-+ 0x0268, /* IO_ACX_PHY_ADDR */
-+ 0x026c, /* IO_ACX_PHY_DATA */
-+ 0x0270, /* IO_ACX_PHY_CTL */
-+
-+ 0x0290, /* IO_ACX_GPIO_OE */
-+
-+ 0x0294, /* IO_ACX_GPIO_IN */
-+ 0x0298, /* IO_ACX_GPIO_OUT */
-+ 0x029c, /* IO_ACX_GPIO_PD */
-+ 0x02a0, /* IO_ACX_GPIO_CFG */
-+
-+ 0x02a4, /* IO_ACX_CMD_MAILBOX_OFFS */
-+ 0x02a8, /* IO_ACX_INFO_MAILBOX_OFFS */
-+ 0x02ac, /* IO_ACX_EEPROM_INFORMATION */
-+
-+ 0x02d0, /* IO_ACX_EE_START */
-+ 0x02d4, /* IO_ACX_SOR_CFG */
-+ 0x02d8, /* IO_ACX_ECPU_CTRL */
-+
-+ 0x0804, /* IO_ACX_HI_CTL */
-+ 0x0808, /* IO_ACX_LPWR_MGN */
-+
-+ 0x010c, /* IO_ACX_PCI_ARB_CFG */
-+
-+};
-+
-+static void
-+acx_netdev_init(struct net_device *dev) {}
-+
-+//FIXME: do the same for USB
-+static int
-+acx_change_mtu(struct net_device *dev, int mtu)
-+{
-+ enum {
-+ MIN_MTU = 256,
-+ MAX_MTU = WLAN_DATA_MAXLEN - (ETH_HLEN)
-+ };
-+
-+ if (mtu < MIN_MTU || mtu > MAX_MTU)
-+ return -EINVAL;
-+
-+ dev->mtu = mtu;
-+ return 0;
-+}
-+
-+
-+static int acx_enable(struct platform_device *pdev){
-+ unsigned long flags;
-+
-+ /* We need to disabe the interrupt
-+ * around reset.
-+ */
-+ local_irq_save(flags);
-+
-+ /* Now lets turn on and
-+ * reset the device.
-+ */
-+ pca9535_gpio_write(GPIO6, LOW);
-+ pca9535_gpio_write(GPIO12, LOW);
-+
-+ /* TODO: someother configuration needs
-+ * to be done here.
-+ */
-+
-+ // Now we can enable interrupt.
-+ local_irq_restore(flags);
-+
-+
-+ return 0;
-+}
-+
-+static inline void test(wlandevice_t *priv) {
-+ printk("===============================\n");
-+ printk("Reset : %04x\n",acx_read_reg16(priv, IO_ACX_SOFT_RESET));
-+ printk("eCPU CTL: %04x\n",acx_read_reg16(priv, IO_ACX_ECPU_CTRL));
-+ printk("SOR CFG : %08x\n",acx_read_reg32(priv, IO_ACX_SOR_CFG));
-+ printk("EE START: %08x\n",acx_read_reg32(priv, IO_ACX_EE_START));
-+ printk("HI CTRL : %08x\n",acx_read_reg32(priv, IO_ACX_HI_CTRL));
-+// printk("Info : %08x\n",acx_read_reg32(priv, IO_ACX_EEPROM_INFORMATION));
-+ printk("GPIO OE : %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_OE));
-+ printk("GPIO OUT: %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_OUT));
-+ printk("GPIO IN : %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_IN));
-+ printk("GPIO PD : %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_PD));
-+ printk("GPIO CFG: %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_CFG));
-+ printk("Chip ID : %08x\n",acx_read_reg32(priv, IO_ACX_CHIPID));
-+
-+/*
-+ printk("HW CTRL : %08x\n",acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_CTRL));
-+ printk("HW ADDR : %08x\n",acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_ADDR));
-+ printk("HW DATA : %08x\n",acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_DATA));
-+*/
-+
-+ msleep(50);
-+
-+ printk("==============================\n");
-+}
-+
-+static int __init acx_probe(struct net_device *ndev, void __iomem *addr, struct resource *res){
-+ wlandevice_t *priv = netdev_priv(ndev);
-+ int ret = 0;
-+
-+ ether_setup(ndev);
-+
-+ /* now that device init was successful, fill remaining fields... */
-+ ndev->open = &acx_e_open;
-+ ndev->stop = &acx_e_close;
-+ ndev->hard_start_xmit = &acx_i_start_xmit;
-+ ndev->get_stats = &acx_e_get_stats;
-+ ndev->get_wireless_stats = &acx_e_get_wireless_stats;
-+#if WIRELESS_EXT >= 13
-+ ndev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
-+#else
-+ ndev->do_ioctl = &acx_e_ioctl_old;
-+#endif
-+ ndev->set_multicast_list = &acx_i_set_multicast_list;
-+ ndev->tx_timeout = &acx_i_tx_timeout;
-+ ndev->change_mtu = &acx_change_mtu;
-+ ndev->watchdog_timeo = 4 * HZ;
-+
-+ spin_lock_init(&priv->lock); /* initial state: unlocked */
-+ /* We do not start with downed sem: we want PARANOID_LOCKING to work */
-+ sema_init(&priv->sem, 1); /* initial state: 1 (upped) */
-+
-+ priv->iobase = (unsigned char *) addr;
-+ priv->iobase2 = 0;
-+ priv->membase = res->start;
-+ priv->chip_type = CHIPTYPE_ACX100;
-+ priv->chip_name = name_acx100;
-+ priv->io = IO_ACX100;
-+ priv->mgmt_timer.function = (void (*)(unsigned long))0x0000dead;
-+ spin_lock_init(&priv->lock);
-+
-+ test(priv);
-+
-+#ifdef NONESSENTIAL_FEATURES
-+ acx_show_card_eeprom_id(priv);
-+#endif /* NONESSENTIAL_FEATURES */
-+
-+ /* now we have our device, so make sure the kernel doesn't try
-+ * to send packets even though we're not associated to a network yet */
-+ acx_stop_queue(ndev, "after setup");
-+
-+ /* register new dev in linked list */
-+ acx_s_device_chain_add(ndev);
-+
-+ if((ret = acx_s_reset_dev(ndev)) != OK){
-+ /* Failed to reset device */
-+ ret = -EIO;
-+ goto reset_fail;
-+ }
-+
-+ /* ok, basic setup is finished, now start initialising the card */
-+#if 0
-+ hardware_info = acx_read_reg16(priv, IO_ACX_EEPROM_INFORMATION);
-+ priv->form_factor = (u8)(hardware_info & 0xff);
-+ priv->radio_type = (u8)(hardware_info >> 8 & 0xff);
-+#endif
-+
-+ if (OK != acx_read_eeprom_offset(priv, 0x05, &priv->eeprom_version)) {
-+ ret = -EIO;
-+ goto fail_read_eeprom_version;
-+ }
-+
-+ if (OK != acx_s_init_mac(ndev)) {
-+ acxlog(L_DEBUG | L_INIT,
-+ "Danger Will Robinson, MAC did not come back\n");
-+ ret = -EIO;
-+ goto fail_init_mac;
-+ }
-+
-+ if (OK != acx_s_set_defaults(priv)) {
-+ printk("acx: set_defaults() FAILED\n");
-+ goto fail_set_defaults;
-+ }
-+
-+ /* needs to be after acx_init_mac() due to necessary init stuff */
-+ acx_s_get_firmware_version(priv);
-+
-+ acx_display_hardware_details(priv);
-+
-+ /* ...and register the card, AFTER everything else has been set up,
-+ * since otherwise an ioctl could step on our feet due to
-+ * firmware operations happening in parallel or uninitialized data */
-+ ret = register_netdev(ndev);
-+ if (OK != ret) {
-+ printk(KERN_ERR
-+ "%s: Register net device of %s FAILED: %d\n",
-+ __func__, ndev->name, ret);
-+ ret = -EIO;
-+ goto fail_register_netdev;
-+ }
-+ acx_carrier_off(ndev, "on probe");
-+
-+#ifdef CONFIG_PROC_FS
-+ if (OK != acx_proc_register_entries(ndev)) {
-+ ret = -EIO;
-+ goto fail_proc_register_entries;
-+ }
-+#endif
-+
-+#if CMD_DISCOVERY
-+ great_inquisitor(priv);
-+#endif
-+
-+
-+ return 0;
-+
-+#ifdef CONFIG_PROC_FS
-+fail_proc_register_entries:
-+#endif
-+
-+ if (priv->dev_state_mask & ACX_STATE_IFACE_UP)
-+ acx_s_down(ndev);
-+ unregister_netdev(ndev);
-+
-+fail_register_netdev:
-+ acx_s_delete_dma_regions(priv);
-+fail_set_defaults:
-+fail_init_mac:
-+fail_read_eeprom_version:
-+reset_fail:
-+ acx_s_device_chain_remove(ndev);
-+
-+ return ret;
-+}
-+
-+static void dumpRegs(char *msg, unsigned char *base) {
-+ u32 val = 0;
-+ u16 addr = 0;
-+
-+ printk("============= [ %s ] ===============\n",msg);
-+
-+ for(addr = 0; addr <= 0x0be0; addr+=4){
-+ if(addr >= 0x0710 && addr <= 0x0740){
-+ val = 0;
-+ printk("Reg[%04x] : %08x\n",addr, val);
-+ msleep(50);
-+ continue;
-+ }
-+
-+ val = readw((u8 *) base + addr) + (readw((u8 *) base + addr + 2) << 16);
-+
-+ printk("Reg[%04x] : %08x\n",addr, val);
-+ msleep(50);
-+ }
-+
-+ printk("=====================================\n");
-+}
-+
-+
-+static int __init acx_drv_probe(struct device *dev){
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct net_device *ndev = NULL;
-+ struct resource *res = NULL;
-+ unsigned int __iomem *addr = NULL;
-+ wlandevice_t *priv = NULL;
-+ int ret;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res) {
-+ printk(KERN_ERR "Device not found\n");
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+
-+ if (!request_mem_region(res->start, SZ_32M, CARDNAME)) {
-+ printk(KERN_ERR "Device busy\n");
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ // Create new ethernet device
-+ ndev = alloc_netdev(sizeof(wlandevice_t), "wlan%d", acx_netdev_init);
-+ if (!ndev) {
-+ printk("%s: could not allocate device.\n", CARDNAME);
-+ ret = -ENOMEM;
-+ goto out_release_io;
-+ }
-+ SET_MODULE_OWNER(ndev);
-+ SET_NETDEV_DEV(ndev, dev);
-+
-+ // Get driver private data
-+ priv = netdev_priv(ndev);
-+
-+ // Cleanup the private area
-+ memset((void *) priv, 0, sizeof(wlandevice_t));
-+
-+ ndev->dma = (unsigned char)-1;
-+ ndev->irq = platform_get_irq(pdev, 0);
-+ priv->dev = dev;
-+
-+ // Enable device
-+ acx_enable(pdev);
-+
-+ /* Create IOMEM port so we
-+ * can use to to read and write
-+ * from card registers.
-+ */
-+ if(!(addr = ioremap(res->start, SZ_32M))){
-+ printk(KERN_ERR "Failed to map ioport\n");
-+ ret = -ENOMEM;
-+ goto free_device;
-+ }
-+
-+ dev_set_drvdata(dev, ndev);
-+
-+ //dumpRegs("After",addr);
-+
-+
-+ if((ret = acx_probe(ndev, addr,res))){
-+ /* Something wrong we couldn't
-+ * talke to the device.
-+ */
-+ printk(KERN_ERR "Failed to probe ACX\n");
-+ goto out_iounmap;
-+ }
-+
-+ printk("acx "WLAN_RELEASE": net device %s, driver compiled "
-+ "against wireless extensions %d and Linux %s\n",
-+ ndev->name, WIRELESS_EXT, UTS_RELEASE);
-+
-+ return 0;
-+
-+out_iounmap:
-+ dev_set_drvdata(dev, NULL);
-+ iounmap(addr);
-+free_device:
-+ free_netdev(ndev);
-+out_release_io:
-+ release_mem_region(res->start, SZ_32M);
-+out:
-+ return ret;
-+}
-+
-+static int acx_remove(struct device *dev)
-+{
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct net_device *ndev = (dev? dev_get_drvdata(dev) : NULL);
-+ wlandevice_t *priv = (ndev? (wlandevice_t *) netdev_priv(ndev) : NULL);
-+ struct resource *res = NULL;
-+
-+ if(!ndev){
-+ printk(KERN_ERR "Invalid network device structure\n");
-+ return 0;
-+ }
-+
-+ dev_set_drvdata(dev, NULL);
-+ unregister_netdev(ndev);
-+
-+#if 0
-+ free_irq(ndev->irq, ndev);
-+#endif
-+
-+ iounmap(priv->iobase);
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ release_mem_region(res->start, SZ_32M);
-+
-+ free_netdev(ndev);
-+
-+ return 0;
-+}
-+
-+/***********************************************************************
-+*/
-+#ifdef CONFIG_PM
-+static int if_was_up = 0; /* FIXME: HACK, do it correctly sometime instead */
-+static int
-+acx_suspend(struct device *dev, pm_message_t state, u32 level)
-+{
-+#if 0
-+ struct net_device *ndev = pci_get_drvdata(pdev);
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ printk("acx: experimental suspend handler called for %p\n", priv);
-+ if (netif_device_present(ndev)) {
-+ if_was_up = 1;
-+ acx_s_down(ndev);
-+ }
-+ else
-+ if_was_up = 0;
-+
-+ netif_device_detach(ndev); /* This one cannot sleep */
-+ acx_s_delete_dma_regions(priv);
-+
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT0;
-+#endif
-+ return OK;
-+}
-+
-+static int
-+acx_resume(struct device *dev, u32 level)
-+{
-+#if 0
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct net_device *ndev;
-+ wlandevice_t *priv;
-+
-+ printk(KERN_WARNING "rsm: resume\n");
-+ ndev = dev_get_drvdata(dev);
-+ printk(KERN_WARNING "rsm: got dev\n");
-+
-+ if (!netif_running(ndev))
-+ return 0;
-+
-+ priv = netdev_priv(ndev);
-+
-+ acx_sem_lock(priv);
-+
-+ printk(KERN_WARNING "rsm: got priv\n");
-+ FN_ENTER;
-+ printk("acx: experimental resume handler called for %p!\n", priv);
-+ // TODO
-+ acxlog(L_DEBUG, "rsm: power state set\n");
-+
-+ acxlog(L_DEBUG, "rsm: PCI state restored\n");
-+ acx_s_reset_dev(ndev);
-+ acxlog(L_DEBUG, "rsm: device reset done\n");
-+
-+ if (OK != acx_s_init_mac(ndev)) {
-+ printk("rsm: init_mac FAILED\n");
-+ goto fail;
-+ }
-+ acxlog(L_DEBUG, "rsm: init MAC done\n");
-+
-+ if (1 == if_was_up)
-+ acx_s_up(ndev);
-+ acxlog(L_DEBUG, "rsm: acx up\n");
-+
-+ /* now even reload all card parameters as they were before suspend,
-+ * and possibly be back in the network again already :-)
-+ * FIXME: should this be done in that scheduled task instead?? */
-+ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
-+ acx_s_update_card_settings(priv, 0, 1);
-+ acxlog(L_DEBUG, "rsm: settings updated\n");
-+ netif_device_attach(ndev);
-+ acxlog(L_DEBUG, "rsm: device attached\n");
-+fail: /* we need to return OK here anyway, right? */
-+ acx_sem_unlock(priv);
-+ FN_EXIT0;
-+#endif
-+ return OK;
-+}
-+#endif /* CONFIG_PM */
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_up
-+*
-+* Side effects:
-+* - Enables on-card interrupt requests
-+* - calls acx_start
-+* Call context:
-+* - process thread
-+* Comment:
-+* This function is called by acx_open (when ifconfig sets the
-+* device as up).
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_up(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+ acx_l_enable_irq(priv);
-+ acx_unlock(priv, flags);
-+
-+ /* acx fw < 1.9.3.e has a hardware timer, and older drivers
-+ ** used to use it. But we don't do that anymore, our OS
-+ ** has reliable software timers */
-+ init_timer(&priv->mgmt_timer);
-+ priv->mgmt_timer.function = acx_i_timer;
-+ priv->mgmt_timer.data = (unsigned long)priv;
-+
-+ /* Need to set ACX_STATE_IFACE_UP first, or else
-+ ** timer won't be started by acx_set_status() */
-+ SET_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ /* actual scan cmd will happen in start() */
-+ acx_set_status(priv, ACX_STATUS_1_SCANNING); break;
-+ case ACX_MODE_3_AP:
-+ case ACX_MODE_MONITOR:
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED); break;
-+ }
-+
-+ acx_s_start(priv);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_down
-+*
-+* Side effects:
-+* - disables on-card interrupt request
-+* Call context:
-+* process thread
-+* Comment:
-+* this disables the netdevice
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_down(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ /* Disable IRQs first, so that IRQs cannot race with us */
-+ acx_lock(priv, flags);
-+ acx_l_disable_irq(priv);
-+ acx_unlock(priv, flags);
-+
-+ /* we really don't want to have an asynchronous tasklet disturb us
-+ ** after something vital for its job has been shut down, so
-+ ** end all remaining work now.
-+ **
-+ ** NB: carrier_off (done by set_status below) would lead to
-+ ** not yet fully understood deadlock in FLUSH_SCHEDULED_WORK().
-+ ** That's why we do FLUSH first.
-+ **
-+ ** NB2: we have a bad locking bug here: FLUSH_SCHEDULED_WORK()
-+ ** waits for acx_e_after_interrupt_task to complete if it is running
-+ ** on another CPU, but acx_e_after_interrupt_task
-+ ** will sleep on sem forever, because it is taken by us!
-+ ** Work around that by temporary sem unlock.
-+ ** This will fail miserably if we'll be hit by concurrent
-+ ** iwconfig or something in between. TODO! */
-+ acx_sem_unlock(priv);
-+ FLUSH_SCHEDULED_WORK();
-+ acx_sem_lock(priv);
-+
-+ /* This is possible:
-+ ** FLUSH_SCHEDULED_WORK -> acx_e_after_interrupt_task ->
-+ ** -> set_status(ASSOCIATED) -> wake_queue()
-+ ** That's why we stop queue _after_ FLUSH_SCHEDULED_WORK
-+ ** lock/unlock is just paranoia, maybe not needed */
-+ acx_lock(priv, flags);
-+ acx_stop_queue(dev, "during close");
-+ acx_set_status(priv, ACX_STATUS_0_STOPPED);
-+ acx_unlock(priv, flags);
-+
-+ /* kernel/timer.c says it's illegal to del_timer_sync()
-+ ** a timer which restarts itself. We guarantee this cannot
-+ ** ever happen because acx_i_timer() never does this if
-+ ** status is ACX_STATUS_0_STOPPED */
-+ del_timer_sync(&priv->mgmt_timer);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_open
-+*
-+* WLAN device open method. Called from p80211netdev when kernel
-+* device open (start) method is called in response to the
-+* SIOCSIFFLAGS ioctl changing the flags bit IFF_UP
-+* from clear to set.
-+*
-+* Returns:
-+* 0 success
-+* >0 f/w reported error
-+* <0 driver reported error
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+static int
-+acx_e_open(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result = OK;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_INIT, "module count++\n");
-+ WLAN_MOD_INC_USE_COUNT;
-+
-+ acx_sem_lock(priv);
-+
-+ acx_init_task_scheduler(priv);
-+
-+ /* request shared IRQ handler */
-+ if (request_irq(dev->irq, acx_i_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ printk("%s: request_irq FAILED\n", dev->name);
-+ result = -EAGAIN;
-+ goto done;
-+ }
-+ acxlog(L_DEBUG|L_IRQ, "request_irq %d successful\n", dev->irq);
-+
-+ /* ifup device */
-+ acx_s_up(dev);
-+
-+ /* We don't currently have to do anything else.
-+ * The setup of the MAC should be subsequently completed via
-+ * the mlme commands.
-+ * Higher layers know we're ready from dev->start==1 and
-+ * dev->tbusy==0. Our rx path knows to pass up received/
-+ * frames because of dev->flags&IFF_UP is true.
-+ */
-+done:
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_close
-+*
-+* WLAN device close method. Called from network core when kernel
-+* device close method is called in response to the
-+* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
-+* from set to clear.
-+* (i.e. called for "ifconfig DEV down")
-+*
-+* Returns:
-+* 0 success
-+* >0 f/w reported error
-+* <0 driver reported error
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+static int
-+acx_e_close(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ /* ifdown device */
-+ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-+ if (netif_device_present(dev)) {
-+ acx_s_down(dev);
-+ }
-+
-+ /* disable all IRQs, release shared IRQ handler */
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
-+ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
-+ free_irq(dev->irq, dev);
-+
-+ /* We currently don't have to do anything else.
-+ * Higher layers know we're not ready from dev->start==0 and
-+ * dev->tbusy==1. Our rx path knows to not pass up received
-+ * frames because of dev->flags&IFF_UP is false.
-+ */
-+ acxlog(L_INIT, "module count--\n");
-+ WLAN_MOD_DEC_USE_COUNT;
-+
-+ acx_sem_unlock(priv);
-+
-+ acxlog(L_INIT, "closed device\n");
-+ FN_EXIT0;
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_i_tx_timeout
-+*
-+* Called from network core. Must not sleep!
-+*----------------------------------------------------------------*/
-+static void
-+acx_i_tx_timeout(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ unsigned int tx_num_cleaned;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+
-+ /* clean processed tx descs, they may have been completely full */
-+ tx_num_cleaned = acx_l_clean_tx_desc(priv);
-+
-+ /* nothing cleaned, yet (almost) no free buffers available?
-+ * --> clean all tx descs, no matter which status!!
-+ * Note that I strongly suspect that doing emergency cleaning
-+ * may confuse the firmware. This is a last ditch effort to get
-+ * ANYTHING to work again...
-+ *
-+ * TODO: it's best to simply reset & reinit hw from scratch...
-+ */
-+ if ((priv->tx_free <= TX_EMERG_CLEAN) && (tx_num_cleaned == 0)) {
-+ printk("%s: FAILED to free any of the many full tx buffers. "
-+ "Switching to emergency freeing. "
-+ "Please report!\n", dev->name);
-+ acx_l_clean_tx_desc_emergency(priv);
-+ }
-+
-+ if (acx_queue_stopped(dev) && (ACX_STATUS_4_ASSOCIATED == priv->status))
-+ acx_wake_queue(dev, "after tx timeout");
-+
-+ /* stall may have happened due to radio drift, so recalib radio */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-+
-+ /* do unimportant work last */
-+ printk("%s: tx timeout!\n", dev->name);
-+ priv->stats.tx_errors++;
-+
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_get_stats
-+*----------------------------------------------------------------*/
-+static struct net_device_stats*
-+acx_e_get_stats(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ return &priv->stats;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_get_wireless_stats
-+*----------------------------------------------------------------*/
-+static struct iw_statistics*
-+acx_e_get_wireless_stats(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ return &priv->wstats;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_i_set_multicast_list
-+* FIXME: most likely needs refinement
-+*----------------------------------------------------------------*/
-+static void
-+acx_i_set_multicast_list(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+
-+ /* firmwares don't have allmulti capability,
-+ * so just use promiscuous mode instead in this case. */
-+ if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
-+ SET_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
-+ CLEAR_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
-+ SET_BIT(priv->set_mask, SET_RXCONFIG);
-+ /* let kernel know in case *we* needed to set promiscuous */
-+ dev->flags |= (IFF_PROMISC|IFF_ALLMULTI);
-+ } else {
-+ CLEAR_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
-+ SET_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
-+ SET_BIT(priv->set_mask, SET_RXCONFIG);
-+ dev->flags &= ~(IFF_PROMISC|IFF_ALLMULTI);
-+ }
-+
-+ /* cannot update card settings directly here, atomic context */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
-+
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+
-+static void
-+acx_l_update_link_quality_led(wlandevice_t *priv)
-+{
-+ int qual;
-+
-+ qual = acx_signal_determine_quality(priv->wstats.qual.level, priv->wstats.qual.noise);
-+ if (qual > priv->brange_max_quality)
-+ qual = priv->brange_max_quality;
-+
-+ if (time_after(jiffies, priv->brange_time_last_state_change +
-+ (HZ/2 - HZ/2 * (unsigned long) qual/priv->brange_max_quality ) )) {
-+ acx_l_power_led(priv, (priv->brange_last_state == 0));
-+ priv->brange_last_state ^= 1; /* toggle */
-+ priv->brange_time_last_state_change = jiffies;
-+ }
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_enable_irq
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_enable_irq(wlandevice_t *priv)
-+{
-+ FN_ENTER;
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask);
-+ acx_write_reg16(priv, IO_ACX_FEMR, 0x8000);
-+ priv->irqs_active = 1;
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_disable_irq
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_disable_irq(wlandevice_t *priv)
-+{
-+ FN_ENTER;
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask_off);
-+ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
-+ priv->irqs_active = 0;
-+ FN_EXIT0;
-+}
-+
-+/* scan is complete. all frames now on the receive queue are valid */
-+#define INFO_SCAN_COMPLETE 0x0001
-+#define INFO_WEP_KEY_NOT_FOUND 0x0002
-+/* hw has been reset as the result of a watchdog timer timeout */
-+#define INFO_WATCH_DOG_RESET 0x0003
-+/* failed to send out NULL frame from PS mode notification to AP */
-+/* recommended action: try entering 802.11 PS mode again */
-+#define INFO_PS_FAIL 0x0004
-+/* encryption/decryption process on a packet failed */
-+#define INFO_IV_ICV_FAILURE 0x0005
-+
-+static void
-+acx_l_handle_info_irq(wlandevice_t *priv)
-+{
-+#if ACX_DEBUG
-+ static const char * const info_type_msg[] = {
-+ "(unknown)",
-+ "scan complete",
-+ "WEP key not found",
-+ "internal watchdog reset was done",
-+ "failed to send powersave (NULL frame) notification to AP",
-+ "encrypt/decrypt on a packet has failed",
-+ "TKIP tx keys disabled",
-+ "TKIP rx keys disabled",
-+ "TKIP rx: key ID not found",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "TKIP IV value exceeds thresh"
-+ };
-+#endif
-+ acx_read_info_status(priv);
-+ acxlog(L_IRQ, "got Info IRQ: status 0x%04X type 0x%04X: %s\n",
-+ priv->info_status, priv->info_type,
-+ info_type_msg[(priv->info_type >= VEC_SIZE(info_type_msg)) ?
-+ 0 : priv->info_type]
-+ );
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_i_interrupt
-+*
-+* IRQ handler (atomic context, must not sleep, blah, blah)
-+*----------------------------------------------------------------*/
-+static void
-+acx_log_unusual_irq(u16 irqtype) {
-+ /*
-+ if (!printk_ratelimit())
-+ return;
-+ */
-+
-+ printk("acx: got");
-+ if (irqtype & HOST_INT_RX_DATA) {
-+ printk(" Rx_Data");
-+ }
-+ /* HOST_INT_TX_COMPLETE */
-+ if (irqtype & HOST_INT_TX_XFER) {
-+ printk(" Tx_Xfer");
-+ }
-+ /* HOST_INT_RX_COMPLETE */
-+ if (irqtype & HOST_INT_DTIM) {
-+ printk(" DTIM");
-+ }
-+ if (irqtype & HOST_INT_BEACON) {
-+ printk(" Beacon");
-+ }
-+ if (irqtype & HOST_INT_TIMER) {
-+ acxlog(L_IRQ, " Timer");
-+ }
-+ if (irqtype & HOST_INT_KEY_NOT_FOUND) {
-+ printk(" Key_Not_Found");
-+ }
-+ if (irqtype & HOST_INT_IV_ICV_FAILURE) {
-+ printk(" IV_ICV_Failure");
-+ }
-+ /* HOST_INT_CMD_COMPLETE */
-+ /* HOST_INT_INFO */
-+ if (irqtype & HOST_INT_OVERFLOW) {
-+ printk(" Overflow");
-+ }
-+ if (irqtype & HOST_INT_PROCESS_ERROR) {
-+ printk(" Process_Error");
-+ }
-+ /* HOST_INT_SCAN_COMPLETE */
-+ if (irqtype & HOST_INT_FCS_THRESHOLD) {
-+ printk(" FCS_Threshold");
-+ }
-+ if (irqtype & HOST_INT_UNKNOWN) {
-+ printk(" Unknown");
-+ }
-+ printk(" IRQ(s)\n");
-+}
-+
-+static irqreturn_t
-+acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ wlandevice_t *priv;
-+ unsigned long flags;
-+ unsigned int irqcount = MAX_IRQLOOPS_PER_JIFFY;
-+ u16 irqtype, unmasked;
-+
-+ priv = (wlandevice_t *) (((netdevice_t *) dev_id)->priv);
-+
-+ /* LOCKING: can just spin_lock() since IRQs are disabled anyway.
-+ * I am paranoid */
-+ acx_lock(priv, flags);
-+
-+ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
-+ if (unlikely(0xffff == unmasked)) {
-+ /* 0xffff value hints at missing hardware,
-+ * so don't do anything.
-+ * FIXME: that's not very clean - maybe we are able to
-+ * establish a flag which definitely tells us that some
-+ * hardware is absent and which we could check here?
-+ * Hmm, but other drivers do the very same thing... */
-+ acxlog(L_IRQ, "IRQ type:FFFF - device removed? IRQ_NONE\n");
-+ goto none;
-+ }
-+
-+ /* We will check only "interesting" IRQ types */
-+ irqtype = unmasked & ~priv->irq_mask;
-+ if (!irqtype) {
-+ /* We are on a shared IRQ line and it wasn't our IRQ */
-+ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X - all are masked, IRQ_NONE\n",
-+ unmasked, priv->irq_mask);
-+ goto none;
-+ }
-+
-+ /* Done here because IRQ_NONEs taking three lines of log
-+ ** drive me crazy */
-+ FN_ENTER;
-+
-+#define IRQ_ITERATE 1
-+#if IRQ_ITERATE
-+if (jiffies != priv->irq_last_jiffies) {
-+ priv->irq_loops_this_jiffy = 0;
-+ priv->irq_last_jiffies = jiffies;
-+}
-+
-+/* safety condition; we'll normally abort loop below
-+ * in case no IRQ type occurred */
-+while (--irqcount) {
-+#endif
-+ /* ACK all IRQs asap */
-+ acx_write_reg16(priv, IO_ACX_IRQ_ACK, 0xffff);
-+
-+ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X, type & ~mask:%04X\n",
-+ unmasked, priv->irq_mask, irqtype);
-+
-+ /* Handle most important IRQ types first */
-+ if (irqtype & HOST_INT_RX_COMPLETE) {
-+ acxlog(L_IRQ, "got Rx_Complete IRQ\n");
-+ acx_l_process_rx_desc(priv);
-+ }
-+ if (irqtype & HOST_INT_TX_COMPLETE) {
-+ acxlog(L_IRQ, "got Tx_Complete IRQ\n");
-+ /* don't clean up on each Tx complete, wait a bit
-+ * unless we're going towards full, in which case
-+ * we do it immediately, too (otherwise we might lockup
-+ * with a full Tx buffer if we go into
-+ * acx_l_clean_tx_desc() at a time when we won't wakeup
-+ * the net queue in there for some reason...) */
-+ if (priv->tx_free <= TX_START_CLEAN) {
-+#if TX_CLEANUP_IN_SOFTIRQ
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_TX_CLEANUP);
-+#else
-+ acx_l_clean_tx_desc(priv);
-+#endif
-+ }
-+ }
-+
-+ /* Less frequent ones */
-+ if (irqtype & (0
-+ | HOST_INT_CMD_COMPLETE
-+ | HOST_INT_INFO
-+ | HOST_INT_SCAN_COMPLETE
-+ )) {
-+ if (irqtype & HOST_INT_CMD_COMPLETE) {
-+ acxlog(L_IRQ, "got Command_Complete IRQ\n");
-+ /* save the state for the running issue_cmd() */
-+ SET_BIT(priv->irq_status, HOST_INT_CMD_COMPLETE);
-+ }
-+ if (irqtype & HOST_INT_INFO) {
-+ acx_l_handle_info_irq(priv);
-+ }
-+ if (irqtype & HOST_INT_SCAN_COMPLETE) {
-+ acxlog(L_IRQ, "got Scan_Complete IRQ\n");
-+ /* need to do that in process context */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_COMPLETE_SCAN);
-+ /* remember that fw is not scanning anymore */
-+ SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
-+ }
-+ }
-+
-+ /* These we just log, but either they happen rarely
-+ * or we keep them masked out */
-+ if (irqtype & (0
-+ | HOST_INT_RX_DATA
-+ /* | HOST_INT_TX_COMPLETE */
-+ | HOST_INT_TX_XFER
-+ /* | HOST_INT_RX_COMPLETE */
-+ | HOST_INT_DTIM
-+ | HOST_INT_BEACON
-+ | HOST_INT_TIMER
-+ | HOST_INT_KEY_NOT_FOUND
-+ | HOST_INT_IV_ICV_FAILURE
-+ /* | HOST_INT_CMD_COMPLETE */
-+ /* | HOST_INT_INFO */
-+ | HOST_INT_OVERFLOW
-+ | HOST_INT_PROCESS_ERROR
-+ /* | HOST_INT_SCAN_COMPLETE */
-+ | HOST_INT_FCS_THRESHOLD
-+ | HOST_INT_UNKNOWN
-+ )) {
-+ acx_log_unusual_irq(irqtype);
-+ }
-+
-+#if IRQ_ITERATE
-+ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
-+ irqtype = unmasked & ~priv->irq_mask;
-+ /* Bail out if no new IRQ bits or if all are masked out */
-+ if (!irqtype)
-+ break;
-+
-+ if (unlikely(++priv->irq_loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY)) {
-+ printk(KERN_ERR "acx: too many interrupts per jiffy!\n");
-+ /* Looks like card floods us with IRQs! Try to stop that */
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
-+ /* This will short-circuit all future attempts to handle IRQ.
-+ * We cant do much more... */
-+ priv->irq_mask = 0;
-+ break;
-+ }
-+}
-+#endif
-+ /* Routine to perform blink with range */
-+ if (unlikely(priv->led_power == 2))
-+ acx_l_update_link_quality_led(priv);
-+
-+/* handled: */
-+ /* acx_write_flush(priv); - not needed, last op was read anyway */
-+ acx_unlock(priv, flags);
-+ FN_EXIT0;
-+ return IRQ_HANDLED;
-+
-+none:
-+ acx_unlock(priv, flags);
-+ return IRQ_NONE;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_power_led
-+*----------------------------------------------------------------*/
-+void
-+acx_l_power_led(wlandevice_t *priv, int enable)
-+{
-+ u16 gpio_pled = IS_ACX111(priv) ? 0x0040 : 0x0800;
-+
-+ /* A hack. Not moving message rate limiting to priv->xxx
-+ * (it's only a debug message after all) */
-+ static int rate_limit = 0;
-+
-+ if (rate_limit++ < 3)
-+ acxlog(L_IOCTL, "Please report in case toggling the power "
-+ "LED doesn't work for your card!\n");
-+ if (enable)
-+ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
-+ acx_read_reg16(priv, IO_ACX_GPIO_OUT) & ~gpio_pled);
-+ else
-+ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
-+ acx_read_reg16(priv, IO_ACX_GPIO_OUT) | gpio_pled);
-+}
-+
-+
-+/***********************************************************************
-+** Ioctls
-+*/
-+
-+/***********************************************************************
-+*/
-+int
-+acx111pci_ioctl_info(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+#if ACX_DEBUG
-+ wlandevice_t *priv = netdev_priv(dev);
-+ rxdesc_t *rxdesc;
-+ txdesc_t *txdesc;
-+ rxhostdesc_t *rxhostdesc;
-+ txhostdesc_t *txhostdesc;
-+ struct acx111_ie_memoryconfig memconf;
-+ struct acx111_ie_queueconfig queueconf;
-+ unsigned long flags;
-+ int i;
-+ char memmap[0x34];
-+ char rxconfig[0x8];
-+ char fcserror[0x8];
-+ char ratefallback[0x5];
-+
-+ if ( !(acx_debug & (L_IOCTL|L_DEBUG)) )
-+ return OK;
-+ /* using printk() since we checked debug flag already */
-+
-+ acx_sem_lock(priv);
-+
-+ if (!IS_ACX111(priv)) {
-+ printk("acx111-specific function called "
-+ "with non-acx111 chip, aborting\n");
-+ goto end_ok;
-+ }
-+
-+ /* get Acx111 Memory Configuration */
-+ memset(&memconf, 0, sizeof(memconf));
-+ /* BTW, fails with 12 (Write only) error code.
-+ ** Retained for easy testing of issue_cmd error handling :) */
-+ acx_s_interrogate(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG);
-+
-+ /* get Acx111 Queue Configuration */
-+ memset(&queueconf, 0, sizeof(queueconf));
-+ acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
-+
-+ /* get Acx111 Memory Map */
-+ memset(memmap, 0, sizeof(memmap));
-+ acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP);
-+
-+ /* get Acx111 Rx Config */
-+ memset(rxconfig, 0, sizeof(rxconfig));
-+ acx_s_interrogate(priv, &rxconfig, ACX1xx_IE_RXCONFIG);
-+
-+ /* get Acx111 fcs error count */
-+ memset(fcserror, 0, sizeof(fcserror));
-+ acx_s_interrogate(priv, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT);
-+
-+ /* get Acx111 rate fallback */
-+ memset(ratefallback, 0, sizeof(ratefallback));
-+ acx_s_interrogate(priv, &ratefallback, ACX1xx_IE_RATE_FALLBACK);
-+
-+ /* force occurrence of a beacon interrupt */
-+ /* TODO: comment why is this necessary */
-+ acx_write_reg16(priv, IO_ACX_HINT_TRIG, HOST_INT_BEACON);
-+
-+ /* dump Acx111 Mem Configuration */
-+ printk("dump mem config:\n"
-+ "data read: %d, struct size: %d\n"
-+ "Number of stations: %1X\n"
-+ "Memory block size: %1X\n"
-+ "tx/rx memory block allocation: %1X\n"
-+ "count rx: %X / tx: %X queues\n"
-+ "options %1X\n"
-+ "fragmentation %1X\n"
-+ "Rx Queue 1 Count Descriptors: %X\n"
-+ "Rx Queue 1 Host Memory Start: %X\n"
-+ "Tx Queue 1 Count Descriptors: %X\n"
-+ "Tx Queue 1 Attributes: %X\n",
-+ memconf.len, (int) sizeof(memconf),
-+ memconf.no_of_stations,
-+ memconf.memory_block_size,
-+ memconf.tx_rx_memory_block_allocation,
-+ memconf.count_rx_queues, memconf.count_tx_queues,
-+ memconf.options,
-+ memconf.fragmentation,
-+ memconf.rx_queue1_count_descs,
-+ acx2cpu(memconf.rx_queue1_host_rx_start),
-+ memconf.tx_queue1_count_descs,
-+ memconf.tx_queue1_attributes);
-+
-+ /* dump Acx111 Queue Configuration */
-+ printk("dump queue head:\n"
-+ "data read: %d, struct size: %d\n"
-+ "tx_memory_block_address (from card): %X\n"
-+ "rx_memory_block_address (from card): %X\n"
-+ "rx1_queue address (from card): %X\n"
-+ "tx1_queue address (from card): %X\n"
-+ "tx1_queue attributes (from card): %X\n",
-+ queueconf.len, (int) sizeof(queueconf),
-+ queueconf.tx_memory_block_address,
-+ queueconf.rx_memory_block_address,
-+ queueconf.rx1_queue_address,
-+ queueconf.tx1_queue_address,
-+ queueconf.tx1_attributes);
-+
-+ /* dump Acx111 Mem Map */
-+ printk("dump mem map:\n"
-+ "data read: %d, struct size: %d\n"
-+ "Code start: %X\n"
-+ "Code end: %X\n"
-+ "WEP default key start: %X\n"
-+ "WEP default key end: %X\n"
-+ "STA table start: %X\n"
-+ "STA table end: %X\n"
-+ "Packet template start: %X\n"
-+ "Packet template end: %X\n"
-+ "Queue memory start: %X\n"
-+ "Queue memory end: %X\n"
-+ "Packet memory pool start: %X\n"
-+ "Packet memory pool end: %X\n"
-+ "iobase: %p\n"
-+ "iobase2: %p\n",
-+ *((u16 *)&memmap[0x02]), (int) sizeof(memmap),
-+ *((u32 *)&memmap[0x04]),
-+ *((u32 *)&memmap[0x08]),
-+ *((u32 *)&memmap[0x0C]),
-+ *((u32 *)&memmap[0x10]),
-+ *((u32 *)&memmap[0x14]),
-+ *((u32 *)&memmap[0x18]),
-+ *((u32 *)&memmap[0x1C]),
-+ *((u32 *)&memmap[0x20]),
-+ *((u32 *)&memmap[0x24]),
-+ *((u32 *)&memmap[0x28]),
-+ *((u32 *)&memmap[0x2C]),
-+ *((u32 *)&memmap[0x30]),
-+ priv->iobase,
-+ priv->iobase2);
-+
-+ /* dump Acx111 Rx Config */
-+ printk("dump rx config:\n"
-+ "data read: %d, struct size: %d\n"
-+ "rx config: %X\n"
-+ "rx filter config: %X\n",
-+ *((u16 *)&rxconfig[0x02]), (int) sizeof(rxconfig),
-+ *((u16 *)&rxconfig[0x04]),
-+ *((u16 *)&rxconfig[0x06]));
-+
-+ /* dump Acx111 fcs error */
-+ printk("dump fcserror:\n"
-+ "data read: %d, struct size: %d\n"
-+ "fcserrors: %X\n",
-+ *((u16 *)&fcserror[0x02]), (int) sizeof(fcserror),
-+ *((u32 *)&fcserror[0x04]));
-+
-+ /* dump Acx111 rate fallback */
-+ printk("dump rate fallback:\n"
-+ "data read: %d, struct size: %d\n"
-+ "ratefallback: %X\n",
-+ *((u16 *)&ratefallback[0x02]), (int) sizeof(ratefallback),
-+ *((u8 *)&ratefallback[0x04]));
-+
-+ /* protect against IRQ */
-+ acx_lock(priv, flags);
-+
-+ /* dump acx111 internal rx descriptor ring buffer */
-+ rxdesc = priv->rxdesc_start;
-+
-+ /* loop over complete receive pool */
-+ if (rxdesc) for (i = 0; i < RX_CNT; i++) {
-+ printk("\ndump internal rxdesc %d:\n"
-+ "mem pos %p\n"
-+ "next 0x%X\n"
-+ "acx mem pointer (dynamic) 0x%X\n"
-+ "CTL (dynamic) 0x%X\n"
-+ "Rate (dynamic) 0x%X\n"
-+ "RxStatus (dynamic) 0x%X\n"
-+ "Mod/Pre (dynamic) 0x%X\n",
-+ i,
-+ rxdesc,
-+ acx2cpu(rxdesc->pNextDesc),
-+ acx2cpu(rxdesc->ACXMemPtr),
-+ rxdesc->Ctl_8,
-+ rxdesc->rate,
-+ rxdesc->error,
-+ rxdesc->SNR);
-+ rxdesc++;
-+ }
-+
-+ /* dump host rx descriptor ring buffer */
-+
-+ rxhostdesc = priv->rxhostdesc_start;
-+
-+ /* loop over complete receive pool */
-+ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
-+ printk("\ndump host rxdesc %d:\n"
-+ "mem pos %p\n"
-+ "buffer mem pos 0x%X\n"
-+ "buffer mem offset 0x%X\n"
-+ "CTL 0x%X\n"
-+ "Length 0x%X\n"
-+ "next 0x%X\n"
-+ "Status 0x%X\n",
-+ i,
-+ rxhostdesc,
-+ acx2cpu(rxhostdesc->data_phy),
-+ rxhostdesc->data_offset,
-+ le16_to_cpu(rxhostdesc->Ctl_16),
-+ le16_to_cpu(rxhostdesc->length),
-+ acx2cpu(rxhostdesc->desc_phy_next),
-+ rxhostdesc->Status);
-+ rxhostdesc++;
-+ }
-+
-+ /* dump acx111 internal tx descriptor ring buffer */
-+ txdesc = priv->txdesc_start;
-+
-+ /* loop over complete transmit pool */
-+ if (txdesc) for (i = 0; i < TX_CNT; i++) {
-+ printk("\ndump internal txdesc %d:\n"
-+ "size 0x%X\n"
-+ "mem pos %p\n"
-+ "next 0x%X\n"
-+ "acx mem pointer (dynamic) 0x%X\n"
-+ "host mem pointer (dynamic) 0x%X\n"
-+ "length (dynamic) 0x%X\n"
-+ "CTL (dynamic) 0x%X\n"
-+ "CTL2 (dynamic) 0x%X\n"
-+ "Status (dynamic) 0x%X\n"
-+ "Rate (dynamic) 0x%X\n",
-+ i,
-+ (int) sizeof(struct txdesc),
-+ txdesc,
-+ acx2cpu(txdesc->pNextDesc),
-+ acx2cpu(txdesc->AcxMemPtr),
-+ acx2cpu(txdesc->HostMemPtr),
-+ le16_to_cpu(txdesc->total_length),
-+ txdesc->Ctl_8,
-+ txdesc->Ctl2_8, txdesc->error,
-+ txdesc->u.r1.rate);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+
-+ /* dump host tx descriptor ring buffer */
-+
-+ txhostdesc = priv->txhostdesc_start;
-+
-+ /* loop over complete host send pool */
-+ if (txhostdesc) for (i = 0; i < TX_CNT * 2; i++) {
-+ printk("\ndump host txdesc %d:\n"
-+ "mem pos %p\n"
-+ "buffer mem pos 0x%X\n"
-+ "buffer mem offset 0x%X\n"
-+ "CTL 0x%X\n"
-+ "Length 0x%X\n"
-+ "next 0x%X\n"
-+ "Status 0x%X\n",
-+ i,
-+ txhostdesc,
-+ acx2cpu(txhostdesc->data_phy),
-+ txhostdesc->data_offset,
-+ le16_to_cpu(txhostdesc->Ctl_16),
-+ le16_to_cpu(txhostdesc->length),
-+ acx2cpu(txhostdesc->desc_phy_next),
-+ le32_to_cpu(txhostdesc->Status));
-+ txhostdesc++;
-+ }
-+
-+ /* acx_write_reg16(priv, 0xb4, 0x4); */
-+
-+ acx_unlock(priv, flags);
-+end_ok:
-+
-+ acx_sem_unlock(priv);
-+#endif /* ACX_DEBUG */
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acx100pci_ioctl_set_phy_amp_bias(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ u16 gpio_old;
-+
-+ if (!IS_ACX100(priv)) {
-+ /* WARNING!!!
-+ * Removing this check *might* damage
-+ * hardware, since we're tweaking GPIOs here after all!!!
-+ * You've been warned...
-+ * WARNING!!! */
-+ printk("acx: sorry, setting bias level for non-acx100 "
-+ "is not supported yet\n");
-+ return OK;
-+ }
-+
-+ if (*extra > 7) {
-+ printk("acx: invalid bias parameter, range is 0-7\n");
-+ return -EINVAL;
-+ }
-+
-+ acx_sem_lock(priv);
-+
-+ /* Need to lock accesses to [IO_ACX_GPIO_OUT]:
-+ * IRQ handler uses it to update LED */
-+ acx_lock(priv, flags);
-+ gpio_old = acx_read_reg16(priv, IO_ACX_GPIO_OUT);
-+ acx_write_reg16(priv, IO_ACX_GPIO_OUT, (gpio_old & 0xf8ff) | ((u16)*extra << 8));
-+ acx_unlock(priv, flags);
-+
-+ acxlog(L_DEBUG, "gpio_old: 0x%04X\n", gpio_old);
-+ printk("%s: PHY power amplifier bias: old:%d, new:%d\n",
-+ dev->name,
-+ (gpio_old & 0x0700) >> 8, (unsigned char)*extra);
-+
-+ acx_sem_unlock(priv);
-+
-+ return OK;
-+}
-+
-+
-+/***************************************************************
-+** acxpci_l_alloc_tx
-+** Actually returns a txdesc_t* ptr
-+*/
-+tx_t*
-+acxpci_l_alloc_tx(wlandevice_t* priv)
-+{
-+ struct txdesc *txdesc;
-+ u8 ctl8;
-+
-+ FN_ENTER;
-+
-+ txdesc = get_txdesc(priv, priv->tx_head);
-+ ctl8 = txdesc->Ctl_8;
-+ if (unlikely(DESC_CTL_HOSTOWN != (ctl8 & DESC_CTL_DONE))) {
-+ /* whoops, descr at current index is not free, so probably
-+ * ring buffer already full */
-+ /* FIXME: this causes a deadlock situation (endless
-+ * loop) in case the current descriptor remains busy,
-+ * so handle it a bit better in the future!! */
-+ printk("acx: BUG: tx_head->Ctl8=0x%02X, (0x%02X & "
-+ "0x"DESC_CTL_DONE_STR") != 0x"DESC_CTL_HOSTOWN_STR
-+ ": failed to find free tx descr\n",
-+ ctl8, ctl8);
-+ txdesc = NULL;
-+ goto end;
-+ }
-+
-+ priv->tx_free--;
-+ acxlog(L_BUFT, "tx: got desc %u, %u remain\n",
-+ priv->tx_head, priv->tx_free);
-+
-+/*
-+ * This comment is probably not entirely correct, needs further discussion
-+ * (restored commented-out code below to fix Tx ring buffer overflow,
-+ * since it's much better to have a slightly less efficiently used ring
-+ * buffer rather than one which easily overflows):
-+ *
-+ * This doesn't do anything other than limit our maximum number of
-+ * buffers used at a single time (we might as well just declare
-+ * TX_STOP_QUEUE less descriptors when we open up.) We should just let it
-+ * slide here, and back off TX_STOP_QUEUE in acx_l_clean_tx_desc, when given the
-+ * opportunity to let the queue start back up.
-+ */
-+ if (priv->tx_free < TX_STOP_QUEUE) {
-+ acxlog(L_BUF, "stop queue (%u tx desc left)\n",
-+ priv->tx_free);
-+ acx_stop_queue(priv->netdev, NULL);
-+ }
-+
-+ /* returning current descriptor, so advance to next free one */
-+ priv->tx_head = (priv->tx_head + 1) % TX_CNT;
-+end:
-+ FN_EXIT0;
-+
-+ return (tx_t*)txdesc;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+void*
-+acxpci_l_get_txbuf(wlandevice_t *priv, tx_t* tx_opaque)
-+{
-+ return acx_get_txhostdesc(priv, (txdesc_t*)tx_opaque)->data;
-+}
-+
-+
-+/***********************************************************************
-+** acxpci_l_tx_data
-+**
-+** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
-+** Can be called from acx_i_start_xmit (data frames from net core).
-+*/
-+void
-+acxpci_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int len)
-+{
-+ txdesc_t *txdesc = (txdesc_t*)tx_opaque;
-+ txhostdesc_t *hostdesc1, *hostdesc2;
-+ client_t *clt;
-+ u8 Ctl_8, Ctl2_8;
-+
-+ FN_ENTER;
-+
-+ /* fw doesn't tx such packets anyhow */
-+ if (len < WLAN_HDR_A3_LEN)
-+ goto end;
-+
-+ hostdesc1 = acx_get_txhostdesc(priv, txdesc);
-+ hostdesc2 = hostdesc1 + 1;
-+
-+ /* modify flag status in separate variable to be able to write it back
-+ * in one big swoop later (also in order to have less device memory
-+ * accesses) */
-+ Ctl_8 = txdesc->Ctl_8;
-+ Ctl2_8 = txdesc->Ctl2_8;
-+
-+ /* DON'T simply set Ctl field to 0 here globally,
-+ * it needs to maintain a consistent flag status (those are state flags!!),
-+ * otherwise it may lead to severe disruption. Only set or reset particular
-+ * flags at the exact moment this is needed...
-+ * FIXME: what about Ctl2? Equally problematic? */
-+
-+ /* let chip do RTS/CTS handshaking before sending
-+ * in case packet size exceeds threshold */
-+ if (len > priv->rts_threshold)
-+ SET_BIT(Ctl2_8, DESC_CTL2_RTS);
-+ else
-+ CLEAR_BIT(Ctl2_8, DESC_CTL2_RTS);
-+
-+#ifdef DEBUG_WEP
-+ if (priv->wep_enabled)
-+ SET_BIT(Ctl2_8, DESC_CTL2_WEP);
-+ else
-+ CLEAR_BIT(Ctl2_8, DESC_CTL2_WEP);
-+#endif
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_3_AP:
-+ clt = acx_l_sta_list_get(priv, ((wlan_hdr_t*)hostdesc1->data)->a1);
-+ break;
-+ case ACX_MODE_2_STA:
-+ clt = priv->ap_client;
-+ break;
-+#if 0
-+/* testing was done on acx111: */
-+ case ACX_MODE_MONITOR:
-+ SET_BIT(Ctl2_8, 0
-+/* sends CTS to self before packet */
-+ + DESC_CTL2_SEQ /* don't increase sequence field */
-+/* not working (looks like good fcs is still added) */
-+ + DESC_CTL2_FCS /* don't add the FCS */
-+/* not tested */
-+ + DESC_CTL2_MORE_FRAG
-+/* not tested */
-+ + DESC_CTL2_RETRY /* don't increase retry field */
-+/* not tested */
-+ + DESC_CTL2_POWER /* don't increase power mgmt. field */
-+/* no effect */
-+ + DESC_CTL2_WEP /* encrypt this frame */
-+/* not tested */
-+ + DESC_CTL2_DUR /* don't increase duration field */
-+ );
-+ /* fallthrough */
-+#endif
-+ default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
-+ clt = NULL;
-+ break;
-+ }
-+
-+ if (unlikely(clt && !clt->rate_cur)) {
-+ printk("acx: driver bug! bad ratemask\n");
-+ goto end;
-+ }
-+
-+ /* used in tx cleanup routine for auto rate and accounting: */
-+ acx_put_txc(priv, txdesc, clt);
-+
-+ txdesc->total_length = cpu_to_le16(len);
-+ hostdesc2->length = cpu_to_le16(len - WLAN_HDR_A3_LEN);
-+ if (IS_ACX111(priv)) {
-+ u16 rate_cur = clt ? clt->rate_cur : priv->rate_bcast;
-+ /* note that if !txdesc->do_auto, txrate->cur
-+ ** has only one nonzero bit */
-+ txdesc->u.r2.rate111 = cpu_to_le16(
-+ rate_cur
-+ /* WARNING: I was never able to make it work with prism54 AP.
-+ ** It was falling down to 1Mbit where shortpre is not applicable,
-+ ** and not working at all at "5,11 basic rates only" setting.
-+ ** I even didn't see tx packets in radio packet capture.
-+ ** Disabled for now --vda */
-+ /*| ((clt->shortpre && clt->cur!=RATE111_1) ? RATE111_SHORTPRE : 0) */
-+ );
-+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
-+ /* should add this to rate111 above as necessary */
-+ | (clt->pbcc511 ? RATE111_PBCC511 : 0)
-+#endif
-+ hostdesc1->length = cpu_to_le16(len);
-+ } else { /* ACX100 */
-+ u8 rate_100 = clt ? clt->rate_100 : priv->rate_bcast100;
-+ txdesc->u.r1.rate = rate_100;
-+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
-+ if (clt->pbcc511) {
-+ if (n == RATE100_5 || n == RATE100_11)
-+ n |= RATE100_PBCC511;
-+ }
-+
-+ if (clt->shortpre && (clt->cur != RATE111_1))
-+ SET_BIT(Ctl_8, DESC_CTL_SHORT_PREAMBLE); /* set Short Preamble */
-+#endif
-+ /* set autodma and reclaim and 1st mpdu */
-+ SET_BIT(Ctl_8, DESC_CTL_AUTODMA | DESC_CTL_RECLAIM | DESC_CTL_FIRSTFRAG);
-+ hostdesc1->length = cpu_to_le16(WLAN_HDR_A3_LEN);
-+ }
-+ /* don't need to clean ack/rts statistics here, already
-+ * done on descr cleanup */
-+
-+ /* clears Ctl DESC_CTL_HOSTOWN bit, thus telling that the descriptors
-+ * are now owned by the acx100; do this as LAST operation */
-+ CLEAR_BIT(Ctl_8, DESC_CTL_HOSTOWN);
-+ /* flush writes before we release hostdesc to the adapter here */
-+ wmb();
-+ CLEAR_BIT(hostdesc1->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+ CLEAR_BIT(hostdesc2->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+
-+ /* write back modified flags */
-+ txdesc->Ctl2_8 = Ctl2_8;
-+ txdesc->Ctl_8 = Ctl_8;
-+
-+ /* unused: txdesc->tx_time = cpu_to_le32(jiffies); */
-+//TODO: should it be a mmiowb() instead? we are protecting against race with write[bwl]()
-+ /* flush writes before we tell the adapter that it's its turn now */
-+ wmb();
-+ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_TXPRC);
-+ acx_write_flush(priv);
-+
-+ /* log the packet content AFTER sending it,
-+ * in order to not delay sending any further than absolutely needed
-+ * Do separate logs for acx100/111 to have human-readable rates */
-+ if (unlikely(acx_debug & (L_XFER|L_DATA))) {
-+ u16 fc = ((wlan_hdr_t*)hostdesc1->data)->fc;
-+ if (IS_ACX111(priv))
-+ printk("tx: pkt (%s): len %d "
-+ "rate %04X%s status %u\n",
-+ acx_get_packet_type_string(le16_to_cpu(fc)), len,
-+ le16_to_cpu(txdesc->u.r2.rate111),
-+ (le16_to_cpu(txdesc->u.r2.rate111) & RATE111_SHORTPRE) ? "(SPr)" : "",
-+ priv->status);
-+ else
-+ printk("tx: pkt (%s): len %d rate %03u%s status %u\n",
-+ acx_get_packet_type_string(fc), len,
-+ txdesc->u.r1.rate,
-+ (Ctl_8 & DESC_CTL_SHORT_PREAMBLE) ? "(SPr)" : "",
-+ priv->status);
-+
-+ if (acx_debug & L_DATA) {
-+ printk("tx: 802.11 [%d]: ", len);
-+ acx_dump_bytes(hostdesc1->data, len);
-+ }
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static void
-+acx_l_handle_tx_error(wlandevice_t *priv, u8 error, unsigned int finger)
-+{
-+ const char *err = "unknown error";
-+
-+ /* hmm, should we handle this as a mask
-+ * of *several* bits?
-+ * For now I think only caring about
-+ * individual bits is ok... */
-+ switch (error) {
-+ case 0x01:
-+ err = "no Tx due to error in other fragment";
-+ priv->wstats.discard.fragment++;
-+ break;
-+ case 0x02:
-+ err = "Tx aborted";
-+ priv->stats.tx_aborted_errors++;
-+ break;
-+ case 0x04:
-+ err = "Tx desc wrong parameters";
-+ priv->wstats.discard.misc++;
-+ break;
-+ case 0x08:
-+ err = "WEP key not found";
-+ priv->wstats.discard.misc++;
-+ break;
-+ case 0x10:
-+ err = "MSDU lifetime timeout? - try changing "
-+ "'iwconfig retry lifetime XXX'";
-+ priv->wstats.discard.misc++;
-+ break;
-+ case 0x20:
-+ err = "excessive Tx retries due to either distance "
-+ "too high or unable to Tx or Tx frame error - "
-+ "try changing 'iwconfig txpower XXX' or "
-+ "'sens'itivity or 'retry'";
-+ priv->wstats.discard.retries++;
-+ /* FIXME: set (GETSET_TX|GETSET_RX) here
-+ * (this seems to recalib radio on ACX100)
-+ * after some more jiffies passed??
-+ * But OTOH Tx error 0x20 also seems to occur on
-+ * overheating, so I'm not sure whether we
-+ * actually want that, since people maybe won't notice
-+ * then that their hardware is slowly getting
-+ * cooked...
-+ * Or is it still a safe long distance from utter
-+ * radio non-functionality despite many radio
-+ * recalibs
-+ * to final destructive overheating of the hardware?
-+ * In this case we really should do recalib here...
-+ * I guess the only way to find out is to do a
-+ * potentially fatal self-experiment :-\
-+ * Or maybe only recalib in case we're using Tx
-+ * rate auto (on errors switching to lower speed
-+ * --> less heat?) or 802.11 power save mode? */
-+
-+ /* ok, just do it.
-+ * ENABLE_TX|ENABLE_RX helps, so even do
-+ * DISABLE_TX and DISABLE_RX in order to perhaps
-+ * have more impact. */
-+ if (++priv->retry_errors_msg_ratelimit % 4 == 0) {
-+ if (priv->retry_errors_msg_ratelimit <= 20)
-+ printk("%s: several excessive Tx "
-+ "retry errors occurred, attempting "
-+ "to recalibrate radio. Radio "
-+ "drift might be caused by increasing "
-+ "card temperature, please check the card "
-+ "before it's too late!\n",
-+ priv->netdev->name);
-+ if (priv->retry_errors_msg_ratelimit == 20)
-+ printk("disabling above "
-+ "notification message\n");
-+
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-+ }
-+ break;
-+ case 0x40:
-+ err = "Tx buffer overflow";
-+ priv->stats.tx_fifo_errors++;
-+ break;
-+ case 0x80:
-+ err = "DMA error";
-+ priv->wstats.discard.misc++;
-+ break;
-+ }
-+ priv->stats.tx_errors++;
-+ if (priv->stats.tx_errors <= 20)
-+ printk("%s: tx error 0x%02X, buf %02u! (%s)\n",
-+ priv->netdev->name, error, finger, err);
-+ else
-+ printk("%s: tx error 0x%02X, buf %02u!\n",
-+ priv->netdev->name, error, finger);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+/* Theory of operation:
-+** client->rate_cap is a bitmask of rates client is capable of.
-+** client->rate_cfg is a bitmask of allowed (configured) rates.
-+** It is set as a result of iwconfig rate N [auto]
-+** or iwpriv set_rates "N,N,N N,N,N" commands.
-+** It can be fixed (e.g. 0x0080 == 18Mbit only),
-+** auto (0x00ff == 18Mbit or any lower value),
-+** and code handles any bitmask (0x1081 == try 54Mbit,18Mbit,1Mbit _only_).
-+**
-+** client->rate_cur is a value for rate111 field in tx descriptor.
-+** It is always set to txrate_cfg sans zero or more most significant
-+** bits. This routine handles selection of new rate_cur value depending on
-+** outcome of last tx event.
-+**
-+** client->rate_100 is a precalculated rate value for acx100
-+** (we can do without it, but will need to calculate it on each tx).
-+**
-+** You cannot configure mixed usage of 5.5 and/or 11Mbit rate
-+** with PBCC and CCK modulation. Either both at CCK or both at PBCC.
-+** In theory you can implement it, but so far it is considered not worth doing.
-+**
-+** 22Mbit, of course, is PBCC always. */
-+
-+/* maps acx100 tx descr rate field to acx111 one */
-+static u16
-+rate100to111(u8 r)
-+{
-+ switch (r) {
-+ case RATE100_1: return RATE111_1;
-+ case RATE100_2: return RATE111_2;
-+ case RATE100_5:
-+ case (RATE100_5 | RATE100_PBCC511): return RATE111_5;
-+ case RATE100_11:
-+ case (RATE100_11 | RATE100_PBCC511): return RATE111_11;
-+ case RATE100_22: return RATE111_22;
-+ default:
-+ printk("acx: unexpected acx100 txrate: %u! "
-+ "Please report\n", r);
-+ return RATE111_2;
-+ }
-+}
-+
-+
-+static void
-+acx_l_handle_txrate_auto(wlandevice_t *priv, struct client *txc,
-+ unsigned int idx, u8 rate100, u16 rate111, u8 error)
-+{
-+ u16 sent_rate;
-+ u16 cur = txc->rate_cur;
-+ int slower_rate_was_used;
-+
-+ /* FIXME: need to implement some kind of rate success memory
-+ * which stores the success percentage per rate, to be taken
-+ * into account when considering allowing a new rate, since it
-+ * doesn't really help to stupidly count fallback/stepup,
-+ * since one invalid rate will spoil the party anyway
-+ * (such as 22M in case of 11M-only peers) */
-+
-+ /* vda: hmm. current code will do this:
-+ ** 1. send packets at 11 Mbit, stepup++
-+ ** 2. will try to send at 22Mbit. hardware will see no ACK,
-+ ** retries at 11Mbit, success. code notes that used rate
-+ ** is lower. stepup = 0, fallback++
-+ ** 3. repeat step 2 fallback_count times. Fall back to
-+ ** 11Mbit. go to step 1.
-+ ** If stepup_count is large (say, 16) and fallback_count
-+ ** is small (3), this wouldn't be too bad wrt throughput */
-+
-+ /* do some preparations, i.e. calculate the one rate that was
-+ * used to send this packet */
-+ if (IS_ACX111(priv)) {
-+ sent_rate = 1 << highest_bit(rate111 & RATE111_ALL);
-+ } else {
-+ sent_rate = rate100to111(rate100);
-+ }
-+ /* sent_rate has only one bit set now, corresponding to tx rate
-+ * which was used by hardware to tx this particular packet */
-+
-+ /* now do the actual auto rate management */
-+ acxlog(L_DEBUG, "tx: %sclient=%p/"MACSTR" used=%04X cur=%04X cfg=%04X "
-+ "__=%u/%u ^^=%u/%u\n",
-+ (txc->ignore_count > 0) ? "[IGN] " : "",
-+ txc, MAC(txc->address), sent_rate, cur, txc->rate_cfg,
-+ txc->fallback_count, priv->fallback_threshold,
-+ txc->stepup_count, priv->stepup_threshold
-+ );
-+
-+ /* we need to ignore old packets already in the tx queue since
-+ * they use older rate bytes configured before our last rate change,
-+ * otherwise our mechanism will get confused by interpreting old data.
-+ * Do it here only, in order to have the logging above */
-+ if (txc->ignore_count) {
-+ txc->ignore_count--;
-+ return;
-+ }
-+
-+ /* true only if the only nonzero bit in sent_rate is
-+ ** less significant than highest nonzero bit in cur */
-+ slower_rate_was_used = ( cur > ((sent_rate<<1)-1) );
-+
-+ if (slower_rate_was_used || (error & 0x30)) {
-+ txc->stepup_count = 0;
-+ if (++txc->fallback_count <= priv->fallback_threshold)
-+ return;
-+ txc->fallback_count = 0;
-+
-+ /* clear highest 1 bit in cur */
-+ sent_rate = RATE111_54;
-+ while (!(cur & sent_rate)) sent_rate >>= 1;
-+ CLEAR_BIT(cur, sent_rate);
-+
-+ if (cur) { /* we can't disable all rates! */
-+ acxlog(L_XFER, "tx: falling back to ratemask %04X\n", cur);
-+ txc->rate_cur = cur;
-+ txc->ignore_count = TX_CNT - priv->tx_free;
-+ }
-+ } else if (!slower_rate_was_used) {
-+ txc->fallback_count = 0;
-+ if (++txc->stepup_count <= priv->stepup_threshold)
-+ return;
-+ txc->stepup_count = 0;
-+
-+ /* sanitize. Sort of not needed, but I dont trust hw that much...
-+ ** what if it can report bogus tx rates sometimes? */
-+ while (!(cur & sent_rate)) sent_rate >>= 1;
-+ /* try to find a higher sent_rate that isn't yet in our
-+ * current set, but is an allowed cfg */
-+ while (1) {
-+ sent_rate <<= 1;
-+ if (sent_rate > txc->rate_cfg)
-+ /* no higher rates allowed by config */
-+ return;
-+ if (!(cur & sent_rate) && (txc->rate_cfg & sent_rate))
-+ /* found */
-+ break;
-+ /* not found, try higher one */
-+ }
-+ SET_BIT(cur, sent_rate);
-+ acxlog(L_XFER, "tx: stepping up to ratemask %04X\n", cur);
-+ txc->rate_cur = cur;
-+ /* FIXME: totally bogus - we could be sending to many peers at once... */
-+ txc->ignore_count = TX_CNT - priv->tx_free;
-+ }
-+
-+ /* calculate acx100 style rate byte if needed */
-+ if (IS_ACX100(priv)) {
-+ txc->rate_100 = bitpos2rate100[highest_bit(cur)];
-+ }
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_log_txbuffer
-+*----------------------------------------------------------------*/
-+#if !ACX_DEBUG
-+static inline void acx_l_log_txbuffer(const wlandevice_t *priv) {}
-+#else
-+static void
-+acx_l_log_txbuffer(wlandevice_t *priv)
-+{
-+ txdesc_t *txdesc;
-+ int i;
-+
-+ /* no FN_ENTER here, we don't want that */
-+ /* no locks here, since it's entirely non-critical code */
-+ txdesc = priv->txdesc_start;
-+ if (!txdesc) return;
-+ for (i = 0; i < TX_CNT; i++) {
-+ if ((txdesc->Ctl_8 & DESC_CTL_DONE) == DESC_CTL_DONE)
-+ printk("tx: buf %d done\n", i);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+}
-+#endif
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_clean_tx_desc
-+*
-+* This function resets the txdescs' status when the ACX100
-+* signals the TX done IRQ (txdescs have been processed), starting with
-+* the pool index of the descriptor which we would use next,
-+* in order to make sure that we can be as fast as possible
-+* in filling new txdescs.
-+* Oops, now we have our own index, so everytime we get called we know
-+* where the next packet to be cleaned is.
-+* Hmm, still need to loop through the whole ring buffer now,
-+* since we lost sync for some reason when ping flooding or so...
-+* (somehow we don't get the IRQ for acx_l_clean_tx_desc any more when
-+* too many packets are being sent!)
-+* FIXME: currently we only process one packet, but this gets out of
-+* sync for some reason when ping flooding, so we need to loop,
-+* but the previous smart loop implementation causes the ping latency
-+* to rise dramatically (~3000 ms), at least on CardBus PheeNet WL-0022.
-+* Dunno what to do :-\
-+*----------------------------------------------------------------*/
-+unsigned int
-+acx_l_clean_tx_desc(wlandevice_t *priv)
-+{
-+ txdesc_t *txdesc;
-+ struct client *txc;
-+ int finger;
-+ int num_cleaned;
-+ int to_process;
-+ u16 r111;
-+ u8 error, ack_failures, rts_failures, rts_ok, r100;
-+
-+ FN_ENTER;
-+
-+ if (unlikely(acx_debug & L_DEBUG))
-+ acx_l_log_txbuffer(priv);
-+
-+ acxlog(L_BUFT, "tx: cleaning up bufs from %u\n", priv->tx_tail);
-+
-+ finger = priv->tx_tail;
-+ num_cleaned = 0;
-+ to_process = TX_CNT;
-+ do {
-+ txdesc = get_txdesc(priv, finger);
-+
-+ /* abort if txdesc is not marked as "Tx finished" and "owned" */
-+ if ((txdesc->Ctl_8 & DESC_CTL_DONE) != DESC_CTL_DONE) {
-+ /* we do need to have at least one cleaned,
-+ * otherwise we wouldn't get called in the first place
-+ */
-+ if (num_cleaned)
-+ break;
-+ }
-+
-+ /* remember descr values... */
-+ error = txdesc->error;
-+ ack_failures = txdesc->ack_failures;
-+ rts_failures = txdesc->rts_failures;
-+ rts_ok = txdesc->rts_ok;
-+ r100 = txdesc->u.r1.rate;
-+ r111 = txdesc->u.r2.rate111;
-+
-+#if WIRELESS_EXT > 13 /* wireless_send_event() and IWEVTXDROP are WE13 */
-+ /* need to check for certain error conditions before we
-+ * clean the descriptor: we still need valid descr data here */
-+ if (unlikely(0x30 & error)) {
-+ /* only send IWEVTXDROP in case of retry or lifetime exceeded;
-+ * all other errors mean we screwed up locally */
-+ union iwreq_data wrqu;
-+ wlan_hdr_t *hdr;
-+ txhostdesc_t *hostdesc;
-+
-+ hostdesc = acx_get_txhostdesc(priv, txdesc);
-+ hdr = (wlan_hdr_t *)hostdesc->data;
-+ MAC_COPY(wrqu.addr.sa_data, hdr->a1);
-+ wireless_send_event(priv->netdev, IWEVTXDROP, &wrqu, NULL);
-+ }
-+#endif
-+ /* ...and free the descr */
-+ txdesc->error = 0;
-+ txdesc->ack_failures = 0;
-+ txdesc->rts_failures = 0;
-+ txdesc->rts_ok = 0;
-+ /* signal host owning it LAST, since ACX already knows that this
-+ * descriptor is finished since it set Ctl_8 accordingly:
-+ * if _OWN is set at the beginning instead, our own get_tx
-+ * might choose a Tx desc that isn't fully cleared
-+ * (in case of bad locking). */
-+ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
-+ priv->tx_free++;
-+ num_cleaned++;
-+
-+ if ((priv->tx_free >= TX_START_QUEUE)
-+ && (priv->status == ACX_STATUS_4_ASSOCIATED)
-+ && (acx_queue_stopped(priv->netdev))
-+ ) {
-+ acxlog(L_BUF, "tx: wake queue (avail. Tx desc %u)\n",
-+ priv->tx_free);
-+ acx_wake_queue(priv->netdev, NULL);
-+ }
-+
-+ /* do error checking, rate handling and logging
-+ * AFTER having done the work, it's faster */
-+
-+ /* do rate handling */
-+ txc = acx_get_txc(priv, txdesc);
-+ if (txc && priv->rate_auto) {
-+ acx_l_handle_txrate_auto(priv, txc, finger, r100, r111, error);
-+ }
-+
-+ if (unlikely(error))
-+ acx_l_handle_tx_error(priv, error, finger);
-+
-+ if (IS_ACX111(priv))
-+ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u r111=%04X\n",
-+ finger, ack_failures, rts_failures, rts_ok, r111);
-+ else
-+ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u rate=%u\n",
-+ finger, ack_failures, rts_failures, rts_ok, r100);
-+
-+ /* update pointer for descr to be cleaned next */
-+ finger = (finger + 1) % TX_CNT;
-+ } while (--to_process);
-+
-+ /* remember last position */
-+ priv->tx_tail = finger;
-+/* end: */
-+ FN_EXIT1(num_cleaned);
-+ return num_cleaned;
-+}
-+
-+/* clean *all* Tx descriptors, and regardless of their previous state.
-+ * Used for brute-force reset handling. */
-+void
-+acx_l_clean_tx_desc_emergency(wlandevice_t *priv)
-+{
-+ txdesc_t *txdesc;
-+ unsigned int i;
-+
-+ FN_ENTER;
-+
-+ for (i = 0; i < TX_CNT; i++) {
-+ txdesc = get_txdesc(priv, i);
-+
-+ /* free it */
-+ txdesc->ack_failures = 0;
-+ txdesc->rts_failures = 0;
-+ txdesc->rts_ok = 0;
-+ txdesc->error = 0;
-+ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
-+ }
-+
-+ priv->tx_free = TX_CNT;
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_log_rxbuffer
-+*
-+* Called from IRQ context only
-+*----------------------------------------------------------------*/
-+#if !ACX_DEBUG
-+static inline void acx_l_log_rxbuffer(const wlandevice_t *priv) {}
-+#else
-+static void
-+acx_l_log_rxbuffer(const wlandevice_t *priv)
-+{
-+ const struct rxhostdesc *rxhostdesc;
-+ int i;
-+
-+ /* no FN_ENTER here, we don't want that */
-+
-+ rxhostdesc = priv->rxhostdesc_start;
-+ if (!rxhostdesc) return;
-+ for (i = 0; i < RX_CNT; i++) {
-+ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
-+ printk("rx: buf %d full\n", i);
-+ rxhostdesc++;
-+ }
-+}
-+#endif
-+
-+
-+/***************************************************************
-+** acx_l_process_rx_desc
-+**
-+** Called directly and only from the IRQ handler
-+*/
-+void
-+acx_l_process_rx_desc(wlandevice_t *priv)
-+{
-+ rxhostdesc_t *hostdesc;
-+ /* unsigned int curr_idx; */
-+ unsigned int count = 0;
-+
-+ FN_ENTER;
-+
-+ if (unlikely(acx_debug & L_BUFR)) {
-+ acx_l_log_rxbuffer(priv);
-+ }
-+
-+ /* First, have a loop to determine the first descriptor that's
-+ * full, just in case there's a mismatch between our current
-+ * rx_tail and the full descriptor we're supposed to handle. */
-+ while (1) {
-+ /* curr_idx = priv->rx_tail; */
-+ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
-+ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
-+ if ((hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && (hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) {
-+ /* found it! */
-+ break;
-+ }
-+ count++;
-+ if (unlikely(count > RX_CNT)) {
-+ /* hmm, no luck: all descriptors empty, bail out */
-+ goto end;
-+ }
-+ }
-+
-+ /* now process descriptors, starting with the first we figured out */
-+ while (1) {
-+ acxlog(L_BUFR, "rx: tail=%u Ctl_16=%04X Status=%08X\n",
-+ priv->rx_tail, hostdesc->Ctl_16, hostdesc->Status);
-+
-+ acx_l_process_rxbuf(priv, hostdesc->data);
-+
-+ hostdesc->Status = 0;
-+ /* flush all writes before adapter sees CTL_HOSTOWN change */
-+ wmb();
-+ /* Host no longer owns this, needs to be LAST */
-+ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+
-+ /* ok, descriptor is handled, now check the next descriptor */
-+ /* curr_idx = priv->rx_tail; */
-+ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
-+
-+ /* if next descriptor is empty, then bail out */
-+ /* FIXME: is this check really entirely correct?? */
-+ /*
-+//FIXME: inconsistent with check in prev while() loop
-+ if (!(hostdesc->Ctl & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && !(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) */
-+ if (!(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
-+ break;
-+
-+ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_create_tx_host_desc_queue
-+*----------------------------------------------------------------*/
-+static inline void*
-+acx_alloc_coherent(struct device *dev, size_t size,
-+ dma_addr_t *dma_handle, int flag)
-+{
-+ printk("Size : %ld\n",size);
-+ dev->coherent_dma_mask = 0xffffffff;
-+ return dma_alloc_coherent(dev, size, dma_handle, flag);
-+}
-+
-+static void*
-+allocate(wlandevice_t *priv, size_t size, dma_addr_t *phy, const char *msg)
-+{
-+ void *ptr = acx_alloc_coherent(priv->dev, size, phy, GFP_KERNEL);
-+ if (ptr) {
-+ acxlog(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n",
-+ msg, (int)size, ptr, (unsigned long long)*phy);
-+ memset(ptr, 0, size);
-+ return ptr;
-+ }
-+ printk(KERN_ERR "acx: %s allocation FAILED (%d bytes)\n",
-+ msg, (int)size);
-+ return NULL;
-+}
-+
-+static int
-+acx_s_create_tx_host_desc_queue(wlandevice_t *priv)
-+{
-+ txhostdesc_t *hostdesc;
-+ u8 *txbuf;
-+ dma_addr_t hostdesc_phy;
-+ dma_addr_t txbuf_phy;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* allocate TX buffer */
-+ priv->txbuf_area_size = TX_CNT * WLAN_A4FR_MAXLEN_WEP_FCS;
-+ priv->txbuf_start = allocate(priv, priv->txbuf_area_size,
-+ &priv->txbuf_startphy, "txbuf_start");
-+ if (!priv->txbuf_start)
-+ goto fail;
-+
-+ /* allocate the TX host descriptor queue pool */
-+ priv->txhostdesc_area_size = TX_CNT * 2*sizeof(txhostdesc_t);
-+ priv->txhostdesc_start = allocate(priv, priv->txhostdesc_area_size,
-+ &priv->txhostdesc_startphy, "txhostdesc_start");
-+ if (!priv->txhostdesc_start)
-+ goto fail;
-+ /* check for proper alignment of TX host descriptor pool */
-+ if ((long) priv->txhostdesc_start & 3) {
-+ printk("acx: driver bug: dma alloc returns unaligned address\n");
-+ goto fail;
-+ }
-+
-+/* Each tx frame buffer is accessed by hardware via
-+** txdesc -> txhostdesc(s) -> framebuffer(s)
-+** We use only one txhostdesc per txdesc, but it looks like
-+** acx111 is buggy: it accesses second txhostdesc
-+** (via hostdesc.desc_phy_next field) even if
-+** txdesc->length == hostdesc->length and thus
-+** entire packet was placed into first txhostdesc.
-+** Due to this bug acx111 hangs unless second txhostdesc
-+** has hostdesc.length = 3 (or larger)
-+** Storing NULL into hostdesc.desc_phy_next
-+** doesn't seem to help.
-+*/
-+/* It is not known whether we need to have 'extra' second
-+** txhostdescs for acx100. Maybe it is acx111-only bug.
-+*/
-+ hostdesc = priv->txhostdesc_start;
-+ hostdesc_phy = priv->txhostdesc_startphy;
-+ txbuf = priv->txbuf_start;
-+ txbuf_phy = priv->txbuf_startphy;
-+
-+ for (i = 0; i < TX_CNT*2; i++) {
-+ hostdesc_phy += sizeof(txhostdesc_t);
-+ if (!(i & 1)) {
-+ hostdesc->data_phy = cpu2acx(txbuf_phy);
-+ /* done by memset(0): hostdesc->data_offset = 0; */
-+ /* hostdesc->reserved = ... */
-+ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
-+ /* hostdesc->length = ... */
-+ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
-+ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
-+ /* hostdesc->Status = ... */
-+ /* below: non-hardware fields */
-+ hostdesc->data = txbuf;
-+
-+ txbuf += WLAN_HDR_A3_LEN;
-+ txbuf_phy += WLAN_HDR_A3_LEN;
-+ } else {
-+ hostdesc->data_phy = cpu2acx(txbuf_phy);
-+ /* done by memset(0): hostdesc->data_offset = 0; */
-+ /* hostdesc->reserved = ... */
-+ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
-+ /* hostdesc->length = ...; */
-+ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
-+ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
-+ /* hostdesc->Status = ... */
-+ /* below: non-hardware fields */
-+ hostdesc->data = txbuf;
-+
-+ txbuf += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
-+ txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
-+ }
-+ hostdesc++;
-+ }
-+ hostdesc--;
-+ hostdesc->desc_phy_next = cpu2acx(priv->txhostdesc_startphy);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+fail:
-+ printk("acx: create_tx_host_desc_queue FAILED\n");
-+ /* dealloc will be done by free function on error case */
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/***************************************************************
-+** acx_s_create_rx_host_desc_queue
-+*/
-+/* the whole size of a data buffer (header plus data body)
-+ * plus 32 bytes safety offset at the end */
-+#define RX_BUFFER_SIZE (sizeof(rxbuffer_t) + 32)
-+
-+static int
-+acx_s_create_rx_host_desc_queue(wlandevice_t *priv)
-+{
-+ rxhostdesc_t *hostdesc;
-+ rxbuffer_t *rxbuf;
-+ dma_addr_t hostdesc_phy;
-+ dma_addr_t rxbuf_phy;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* allocate the RX host descriptor queue pool */
-+ priv->rxhostdesc_area_size = RX_CNT * sizeof(rxhostdesc_t);
-+ priv->rxhostdesc_start = allocate(priv, priv->rxhostdesc_area_size,
-+ &priv->rxhostdesc_startphy, "rxhostdesc_start");
-+ if (!priv->rxhostdesc_start)
-+ goto fail;
-+ /* check for proper alignment of RX host descriptor pool */
-+ if ((long) priv->rxhostdesc_start & 3) {
-+ printk("acx: driver bug: dma alloc returns unaligned address\n");
-+ goto fail;
-+ }
-+
-+ /* allocate Rx buffer pool which will be used by the acx
-+ * to store the whole content of the received frames in it */
-+ priv->rxbuf_area_size = RX_CNT * RX_BUFFER_SIZE;
-+ priv->rxbuf_start = allocate(priv, priv->rxbuf_area_size,
-+ &priv->rxbuf_startphy, "rxbuf_start");
-+ if (!priv->rxbuf_start)
-+ goto fail;
-+
-+ rxbuf = priv->rxbuf_start;
-+ rxbuf_phy = priv->rxbuf_startphy;
-+ hostdesc = priv->rxhostdesc_start;
-+ hostdesc_phy = priv->rxhostdesc_startphy;
-+
-+ /* don't make any popular C programming pointer arithmetic mistakes
-+ * here, otherwise I'll kill you...
-+ * (and don't dare asking me why I'm warning you about that...) */
-+ for (i = 0; i < RX_CNT; i++) {
-+ hostdesc->data = rxbuf;
-+ hostdesc->data_phy = cpu2acx(rxbuf_phy);
-+ hostdesc->length = cpu_to_le16(RX_BUFFER_SIZE);
-+ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+ rxbuf++;
-+ rxbuf_phy += sizeof(rxbuffer_t);
-+ hostdesc_phy += sizeof(rxhostdesc_t);
-+ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
-+ hostdesc++;
-+ }
-+ hostdesc--;
-+ hostdesc->desc_phy_next = cpu2acx(priv->rxhostdesc_startphy);
-+ FN_EXIT1(OK);
-+ return OK;
-+fail:
-+ printk("acx: create_rx_host_desc_queue FAILED\n");
-+ /* dealloc will be done by free function on error case */
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/***************************************************************
-+** acx_s_create_hostdesc_queues
-+*/
-+int
-+acx_s_create_hostdesc_queues(wlandevice_t *priv)
-+{
-+ int result;
-+ result = acx_s_create_tx_host_desc_queue(priv);
-+ if (OK != result) return result;
-+ result = acx_s_create_rx_host_desc_queue(priv);
-+ return result;
-+}
-+
-+
-+/***************************************************************
-+** acx_create_tx_desc_queue
-+*/
-+static void
-+acx_create_tx_desc_queue(wlandevice_t *priv, u32 tx_queue_start)
-+{
-+ txdesc_t *txdesc;
-+ txhostdesc_t *hostdesc;
-+ dma_addr_t hostmemptr;
-+ u32 mem_offs;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ priv->txdesc_size = sizeof(txdesc_t);
-+
-+ if (IS_ACX111(priv)) {
-+ /* the acx111 txdesc is 4 bytes larger */
-+ priv->txdesc_size = sizeof(txdesc_t) + 4;
-+ }
-+
-+#if 0
-+ priv->txdesc_start = (txdesc_t *) (priv->iobase2 + tx_queue_start);
-+
-+ acxlog(L_DEBUG, "priv->iobase2=%p\n"
-+ "tx_queue_start=%08X\n"
-+ "priv->txdesc_start=%p\n",
-+ priv->iobase2,
-+ tx_queue_start,
-+ priv->txdesc_start);
-+
-+ priv->tx_free = TX_CNT;
-+#endif
-+ /* done by memset: priv->tx_head = 0; */
-+ /* done by memset: priv->tx_tail = 0; */
-+ txdesc = priv->txdesc_start;
-+ mem_offs = tx_queue_start;
-+ hostmemptr = priv->txhostdesc_startphy;
-+ hostdesc = priv->txhostdesc_start;
-+
-+#if 0
-+ if (IS_ACX111(priv)) {
-+ /* ACX111 has a preinitialized Tx buffer! */
-+ /* loop over whole send pool */
-+ /* FIXME: do we have to do the hostmemptr stuff here?? */
-+ for (i = 0; i < TX_CNT; i++) {
-+ txdesc->HostMemPtr = ptr2acx(hostmemptr);
-+ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
-+ /* reserve two (hdr desc and payload desc) */
-+ hostdesc += 2;
-+ hostmemptr += 2 * sizeof(txhostdesc_t);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+ } else {
-+ /* ACX100 Tx buffer needs to be initialized by us */
-+ /* clear whole send pool. sizeof is safe here (we are acx100) */
-+ memset(priv->txdesc_start, 0, TX_CNT * sizeof(txdesc_t));
-+
-+ /* loop over whole send pool */
-+ for (i = 0; i < TX_CNT; i++) {
-+ acxlog(L_DEBUG, "configure card tx descriptor: 0x%p, "
-+ "size: 0x%X\n", txdesc, priv->txdesc_size);
-+
-+ /* pointer to hostdesc memory */
-+ /* FIXME: type-incorrect assignment, might cause trouble
-+ * in some cases */
-+ txdesc->HostMemPtr = ptr2acx(hostmemptr);
-+ /* initialise ctl */
-+ txdesc->Ctl_8 = DESC_CTL_INIT;
-+ txdesc->Ctl2_8 = 0;
-+ /* point to next txdesc */
-+ txdesc->pNextDesc = cpu2acx(mem_offs + priv->txdesc_size);
-+ /* reserve two (hdr desc and payload desc) */
-+ hostdesc += 2;
-+ hostmemptr += 2 * sizeof(txhostdesc_t);
-+ /* go to the next one */
-+ mem_offs += priv->txdesc_size;
-+ /* ++ is safe here (we are acx100) */
-+ txdesc++;
-+ }
-+ /* go back to the last one */
-+ txdesc--;
-+ /* and point to the first making it a ring buffer */
-+ txdesc->pNextDesc = cpu2acx(tx_queue_start);
-+ }
-+#endif
-+ FN_EXIT0;
-+}
-+
-+
-+/***************************************************************
-+** acx_create_rx_desc_queue
-+*/
-+static void
-+acx_create_rx_desc_queue(wlandevice_t *priv, u32 rx_queue_start)
-+{
-+ rxdesc_t *rxdesc;
-+ u32 mem_offs;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* done by memset: priv->rx_tail = 0; */
-+
-+ /* ACX111 doesn't need any further config: preconfigures itself.
-+ * Simply print ring buffer for debugging */
-+ if (IS_ACX111(priv)) {
-+ /* rxdesc_start already set here */
-+
-+ priv->rxdesc_start = (rxdesc_t *) ((u8 *)priv->iobase2 + rx_queue_start);
-+
-+ rxdesc = priv->rxdesc_start;
-+ for (i = 0; i < RX_CNT; i++) {
-+ acxlog(L_DEBUG, "rx descriptor %d @ 0x%p\n", i, rxdesc);
-+ rxdesc = priv->rxdesc_start = (rxdesc_t *)
-+ (priv->iobase2 + acx2cpu(rxdesc->pNextDesc));
-+ }
-+ } else {
-+ /* we didn't pre-calculate rxdesc_start in case of ACX100 */
-+ /* rxdesc_start should be right AFTER Tx pool */
-+ priv->rxdesc_start = (rxdesc_t *)
-+ ((u8 *) priv->txdesc_start + (TX_CNT * sizeof(txdesc_t)));
-+ /* NB: sizeof(txdesc_t) above is valid because we know
-+ ** we are in if(acx100) block. Beware of cut-n-pasting elsewhere!
-+ ** acx111's txdesc is larger! */
-+
-+ memset(priv->rxdesc_start, 0, RX_CNT * sizeof(rxdesc_t));
-+
-+ /* loop over whole receive pool */
-+ rxdesc = priv->rxdesc_start;
-+ mem_offs = rx_queue_start;
-+ for (i = 0; i < RX_CNT; i++) {
-+ acxlog(L_DEBUG, "rx descriptor @ 0x%p\n", rxdesc);
-+ rxdesc->Ctl_8 = DESC_CTL_RECLAIM | DESC_CTL_AUTODMA;
-+ /* point to next rxdesc */
-+ rxdesc->pNextDesc = cpu2acx(mem_offs + sizeof(rxdesc_t));
-+ /* go to the next one */
-+ mem_offs += sizeof(rxdesc_t);
-+ rxdesc++;
-+ }
-+ /* go to the last one */
-+ rxdesc--;
-+
-+ /* and point to the first making it a ring buffer */
-+ rxdesc->pNextDesc = cpu2acx(rx_queue_start);
-+ }
-+ FN_EXIT0;
-+}
-+
-+
-+/***************************************************************
-+** acx_create_desc_queues
-+*/
-+void
-+acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start)
-+{
-+ acx_create_tx_desc_queue(priv, tx_queue_start);
-+ acx_create_rx_desc_queue(priv, rx_queue_start);
-+}
-+
-+
-+/***************************************************************
-+** acxpci_s_proc_diag_output
-+*/
-+char*
-+acxpci_s_proc_diag_output(char *p, wlandevice_t *priv)
-+{
-+ const char *rtl, *thd, *ttl;
-+ rxhostdesc_t *rxhostdesc;
-+ txdesc_t *txdesc;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ p += sprintf(p, "** Rx buf **\n");
-+ rxhostdesc = priv->rxhostdesc_start;
-+ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
-+ rtl = (i == priv->rx_tail) ? " [tail]" : "";
-+ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)) )
-+ p += sprintf(p, "%02u FULL%s\n", i, rtl);
-+ else
-+ p += sprintf(p, "%02u empty%s\n", i, rtl);
-+ rxhostdesc++;
-+ }
-+ p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", priv->tx_free,
-+ acx_queue_stopped(priv->netdev) ? "STOPPED" : "running");
-+ txdesc = priv->txdesc_start;
-+ if (txdesc) for (i = 0; i < TX_CNT; i++) {
-+ thd = (i == priv->tx_head) ? " [head]" : "";
-+ ttl = (i == priv->tx_tail) ? " [tail]" : "";
-+ if (txdesc->Ctl_8 & DESC_CTL_ACXDONE)
-+ p += sprintf(p, "%02u DONE (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
-+ else
-+ if (!(txdesc->Ctl_8 & DESC_CTL_HOSTOWN))
-+ p += sprintf(p, "%02u TxWait (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
-+ else
-+ p += sprintf(p, "%02u empty (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+ p += sprintf(p,
-+ "\n"
-+ "** PCI data **\n"
-+ "txbuf_start %p, txbuf_area_size %u, txbuf_startphy %08llx\n"
-+ "txdesc_size %u, txdesc_start %p\n"
-+ "txhostdesc_start %p, txhostdesc_area_size %u, txhostdesc_startphy %08llx\n"
-+ "rxdesc_start %p\n"
-+ "rxhostdesc_start %p, rxhostdesc_area_size %u, rxhostdesc_startphy %08llx\n"
-+ "rxbuf_start %p, rxbuf_area_size %u, rxbuf_startphy %08llx\n",
-+ priv->txbuf_start, priv->txbuf_area_size, (u64)priv->txbuf_startphy,
-+ priv->txdesc_size, priv->txdesc_start,
-+ priv->txhostdesc_start, priv->txhostdesc_area_size, (u64)priv->txhostdesc_startphy,
-+ priv->rxdesc_start,
-+ priv->rxhostdesc_start, priv->rxhostdesc_area_size, (u64)priv->rxhostdesc_startphy,
-+ priv->rxbuf_start, priv->rxbuf_area_size, (u64)priv->rxbuf_startphy);
-+
-+ FN_EXIT0;
-+ return p;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acx_proc_eeprom_output(char *buf, wlandevice_t *priv)
-+{
-+ char *p = buf;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ for (i = 0; i < 0x400; i++) {
-+ acx_read_eeprom_offset(priv, i, p++);
-+ }
-+
-+ FN_EXIT1(p - buf);
-+ return p - buf;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+void
-+acx_set_interrupt_mask(wlandevice_t *priv)
-+{
-+ if (IS_ACX111(priv)) {
-+ priv->irq_mask = (u16) ~(0
-+ /* | HOST_INT_RX_DATA */
-+ | HOST_INT_TX_COMPLETE
-+ /* | HOST_INT_TX_XFER */
-+ | HOST_INT_RX_COMPLETE
-+ /* | HOST_INT_DTIM */
-+ /* | HOST_INT_BEACON */
-+ /* | HOST_INT_TIMER */
-+ /* | HOST_INT_KEY_NOT_FOUND */
-+ | HOST_INT_IV_ICV_FAILURE
-+ | HOST_INT_CMD_COMPLETE
-+ | HOST_INT_INFO
-+ /* | HOST_INT_OVERFLOW */
-+ /* | HOST_INT_PROCESS_ERROR */
-+ | HOST_INT_SCAN_COMPLETE
-+ | HOST_INT_FCS_THRESHOLD
-+ /* | HOST_INT_UNKNOWN */
-+ );
-+ priv->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */
-+ } else {
-+ priv->irq_mask = (u16) ~(0
-+ /* | HOST_INT_RX_DATA */
-+ | HOST_INT_TX_COMPLETE
-+ /* | HOST_INT_TX_XFER */
-+ | HOST_INT_RX_COMPLETE
-+ /* | HOST_INT_DTIM */
-+ /* | HOST_INT_BEACON */
-+ /* | HOST_INT_TIMER */
-+ /* | HOST_INT_KEY_NOT_FOUND */
-+ /* | HOST_INT_IV_ICV_FAILURE */
-+ | HOST_INT_CMD_COMPLETE
-+ | HOST_INT_INFO
-+ /* | HOST_INT_OVERFLOW */
-+ /* | HOST_INT_PROCESS_ERROR */
-+ | HOST_INT_SCAN_COMPLETE
-+ /* | HOST_INT_FCS_THRESHOLD */
-+ /* | HOST_INT_UNKNOWN */
-+ );
-+ priv->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */
-+ }
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
-+{
-+ /* since it can be assumed that at least the Maxim radio has a
-+ * maximum power output of 20dBm and since it also can be
-+ * assumed that these values drive the DAC responsible for
-+ * setting the linear Tx level, I'd guess that these values
-+ * should be the corresponding linear values for a dBm value,
-+ * in other words: calculate the values from that formula:
-+ * Y [dBm] = 10 * log (X [mW])
-+ * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
-+ * and you're done...
-+ * Hopefully that's ok, but you never know if we're actually
-+ * right... (especially since Windows XP doesn't seem to show
-+ * actual Tx dBm values :-P) */
-+
-+ /* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the
-+ * values are EXACTLY mW!!! Not sure about RFMD and others,
-+ * though... */
-+ static const u8 dbm2val_maxim[21] = {
-+ 63, 63, 63, 62,
-+ 61, 61, 60, 60,
-+ 59, 58, 57, 55,
-+ 53, 50, 47, 43,
-+ 38, 31, 23, 13,
-+ 0
-+ };
-+ static const u8 dbm2val_rfmd[21] = {
-+ 0, 0, 0, 1,
-+ 2, 2, 3, 3,
-+ 4, 5, 6, 8,
-+ 10, 13, 16, 20,
-+ 25, 32, 41, 50,
-+ 63
-+ };
-+ const u8 *table;
-+
-+ switch (priv->radio_type) {
-+ case RADIO_MAXIM_0D:
-+ table = &dbm2val_maxim[0];
-+ break;
-+ case RADIO_RFMD_11:
-+ case RADIO_RALINK_15:
-+ table = &dbm2val_rfmd[0];
-+ break;
-+ default:
-+ printk("%s: unknown/unsupported radio type, "
-+ "cannot modify tx power level yet!\n",
-+ priv->netdev->name);
-+ return NOT_OK;
-+ }
-+ printk("%s: changing radio power level to %u dBm (%u)\n",
-+ priv->netdev->name, level_dbm, table[level_dbm]);
-+ acxpci_s_write_phy_reg(priv, 0x11, table[level_dbm]);
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_init_module
-+*
-+* Module initialization routine, called once at module load time.
-+*
-+* Returns:
-+* 0 - success
-+* ~0 - failure, module is unloaded.
-+*
-+* Call context:
-+* process thread (insmod or modprobe)
-+----------------------------------------------------------------*/
-+int __init
-+acxcfi_e_init_module(void)
-+{
-+ int res;
-+
-+ FN_ENTER;
-+
-+ printk("acx: compiled to use 16bit I/O access only "
-+ "(compatibility mode)\n");
-+
-+ acxlog(L_INIT, "running on a little-endian CPU\n");
-+
-+ acxlog(L_INIT,
-+ "Compact Flash module " WLAN_RELEASE " initialized, "
-+ "waiting for cards to probe...\n");
-+
-+ /*
-+ * Now let configure device
-+ * GPIOs
-+ */
-+ pca9535_gpio_direction(GPIO6, GPIO_OUTPUT);
-+ pca9535_gpio_direction(GPIO12, GPIO_OUTPUT);
-+
-+ if ((omap_request_gpio(11)) < 0) {
-+ printk("Error requesting gpio 11\n");
-+ return -EIO;
-+ }
-+ omap_set_gpio_direction (11, 1);
-+ omap_set_gpio_dataout (11, 1);
-+
-+ res = driver_register(&acx_driver);
-+
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_cleanup_module
-+*
-+* Called at module unload time. This is our last chance to
-+* clean up after ourselves.
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+void __exit
-+acxcfi_e_cleanup_module(void)
-+{
-+ struct net_device *dev;
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ /* Since the whole module is about to be unloaded,
-+ * we recursively shutdown all cards we handled instead
-+ * of doing it in remove_pci() (which will be activated by us
-+ * via pci_unregister_driver at the end).
-+ * remove_pci() might just get called after a card eject,
-+ * that's why hardware operations have to be done here instead
-+ * when the hardware is available. */
-+
-+ down(&root_acx_dev_sem);
-+
-+ dev = root_acx_dev.newest;
-+ while (dev != NULL) {
-+ /* doh, netdev_priv() doesn't have const! */
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ /* disable both Tx and Rx to shut radio down properly */
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0);
-+
-+#ifdef REDUNDANT
-+ /* put the eCPU to sleep to save power
-+ * Halting is not possible currently,
-+ * since not supported by all firmware versions */
-+ acx_s_issue_cmd(priv, ACX100_CMD_SLEEP, NULL, 0);
-+#endif
-+ acx_lock(priv, flags);
-+
-+ /* disable power LED to save power :-) */
-+ acxlog(L_INIT, "switching off power LED to save power :-)\n");
-+ acx_l_power_led(priv, 0);
-+
-+ /* stop our eCPU */
-+ if (IS_ACX111(priv)) {
-+ /* FIXME: does this actually keep halting the eCPU?
-+ * I don't think so...
-+ */
-+ acx_l_reset_mac(priv);
-+ } else {
-+ u16 temp;
-+
-+ /* halt eCPU */
-+ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
-+ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
-+ acx_write_flush(priv);
-+ }
-+
-+ acx_unlock(priv, flags);
-+
-+ acx_sem_unlock(priv);
-+
-+ dev = priv->prev_nd;
-+ }
-+
-+ up(&root_acx_dev_sem);
-+
-+ omap_free_gpio(11);
-+ driver_unregister(&acx_driver);
-+
-+ FN_EXIT0;
-+}
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/common.c bt_kernel/drivers/net/wireless/tiacx/common.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/common.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/common.c 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,6590 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/proc_fs.h>
-+#include <linux/if_arp.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/wireless.h>
-+#include <linux/pm.h>
-+#include <linux/vmalloc.h>
-+#include <asm/bug.h>
-+#if WIRELESS_EXT >= 13
-+#include <net/iw_handler.h>
-+#endif /* WE >= 13 */
-+
-+#include "acx.h"
-+
-+
-+#define rdtscl(a)
-+
-+/***********************************************************************
-+*/
-+static client_t *acx_l_sta_list_alloc(wlandevice_t *priv);
-+static client_t *acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address);
-+
-+static int acx_l_process_data_frame_master(wlandevice_t *priv, rxbuffer_t *rxbuf);
-+static int acx_l_process_data_frame_client(wlandevice_t *priv, rxbuffer_t *rxbuf);
-+/* static int acx_l_process_NULL_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala); */
-+static int acx_l_process_mgmt_frame(wlandevice_t *priv, rxbuffer_t *rxbuf);
-+static void acx_l_process_disassoc_from_sta(wlandevice_t *priv, const wlan_fr_disassoc_t *req);
-+static void acx_l_process_disassoc_from_ap(wlandevice_t *priv, const wlan_fr_disassoc_t *req);
-+static void acx_l_process_deauth_from_sta(wlandevice_t *priv, const wlan_fr_deauthen_t *req);
-+static void acx_l_process_deauth_from_ap(wlandevice_t *priv, const wlan_fr_deauthen_t *req);
-+static int acx_l_process_probe_response(wlandevice_t *priv, wlan_fr_proberesp_t *req, const rxbuffer_t *rxbuf);
-+static int acx_l_process_assocresp(wlandevice_t *priv, const wlan_fr_assocresp_t *req);
-+static int acx_l_process_reassocresp(wlandevice_t *priv, const wlan_fr_reassocresp_t *req);
-+static int acx_l_process_authen(wlandevice_t *priv, const wlan_fr_authen_t *req);
-+static int acx_l_transmit_assocresp(wlandevice_t *priv, const wlan_fr_assocreq_t *req);
-+static int acx_l_transmit_reassocresp(wlandevice_t *priv, const wlan_fr_reassocreq_t *req);
-+static int acx_l_transmit_deauthen(wlandevice_t *priv, const u8 *addr, u16 reason);
-+static int acx_l_transmit_authen1(wlandevice_t *priv);
-+static int acx_l_transmit_authen2(wlandevice_t *priv, const wlan_fr_authen_t *req, client_t *clt);
-+static int acx_l_transmit_authen3(wlandevice_t *priv, const wlan_fr_authen_t *req);
-+static int acx_l_transmit_authen4(wlandevice_t *priv, const wlan_fr_authen_t *req);
-+static int acx_l_transmit_assoc_req(wlandevice_t *priv);
-+
-+
-+/***********************************************************************
-+*/
-+#if ACX_DEBUG
-+unsigned int acx_debug = L_ASSOC|L_INIT;
-+#endif
-+#if USE_FW_LOADER_LEGACY
-+static char *firmware_dir;
-+#endif
-+#if SEPARATE_DRIVER_INSTANCES
-+static int card;
-+#endif
-+
-+/* introduced earlier than 2.6.10, but takes more memory, so don't use it
-+ * if there's no compile warning by kernel */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-+
-+#if ACX_DEBUG
-+/* parameter is 'debug', corresponding var is acx_debug */
-+module_param_named(debug, acx_debug, uint, 0);
-+#endif
-+#if USE_FW_LOADER_LEGACY
-+module_param(firmware_dir, charp, 0);
-+#endif
-+
-+#else
-+
-+#if ACX_DEBUG
-+/* doh, 2.6.x screwed up big time: here the define has its own ";"
-+ * ("double ; detected"), yet in 2.4.x it DOESN'T (the sane thing to do),
-+ * grrrrr! */
-+MODULE_PARM(acx_debug, "i");
-+#endif
-+#if USE_FW_LOADER_LEGACY
-+MODULE_PARM(firmware_dir, "s");
-+#endif
-+
-+#endif
-+
-+#if ACX_DEBUG
-+MODULE_PARM_DESC(debug, "Debug level mask (see L_xxx constants)");
-+#endif
-+#if USE_FW_LOADER_LEGACY
-+MODULE_PARM_DESC(firmware_dir, "Directory to load acx100 firmware files from");
-+#endif
-+#if SEPARATE_DRIVER_INSTANCES
-+MODULE_PARM(card, "i");
-+MODULE_PARM_DESC(card, "Associate only with card-th acx100 card from this driver instance");
-+#endif
-+
-+/* Shoundn't be needed now, acx.firmware_dir= should work */
-+#if 0 /* USE_FW_LOADER_LEGACY */
-+static int __init
-+acx_get_firmware_dir(const char *str)
-+{
-+ /* I've seen other drivers just pass the string pointer,
-+ * so hopefully that's safe */
-+ firmware_dir = str;
-+ return OK;
-+}
-+__setup("acx_firmware_dir=", acx_get_firmware_dir);
-+#endif
-+
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("Dual MPL/GPL");
-+#endif
-+/* USB had this: MODULE_AUTHOR("Martin Wawro <martin.wawro AT uni-dortmund.de>"); */
-+MODULE_AUTHOR("ACX100 Open Source Driver development team");
-+MODULE_DESCRIPTION("Driver for TI ACX1xx based wireless cards (CardBus/PCI/USB)");
-+
-+
-+/***********************************************************************
-+*/
-+/* Probably a number of acx's itermediate buffers for USB transfers,
-+** not to be confused with number of descriptors in tx/rx rings
-+** (which are not directly accessible to host in USB devices) */
-+#define USB_RX_CNT 10
-+#define USB_TX_CNT 10
-+
-+
-+/***********************************************************************
-+*/
-+
-+/* minutes to wait until next radio recalibration: */
-+#define RECALIB_PAUSE 5
-+
-+const u8 reg_domain_ids[] =
-+ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41, 0x51 };
-+/* stupid workaround for the fact that in C the size of an external array
-+ * cannot be determined from within a second file */
-+const u8 reg_domain_ids_len = sizeof(reg_domain_ids);
-+static const u16 reg_domain_channel_masks[] =
-+ { 0x07ff, 0x07ff, 0x1fff, 0x0600, 0x1e00, 0x2000, 0x3fff, 0x01fc };
-+
-+
-+/***********************************************************************
-+** Debugging support
-+*/
-+#ifdef PARANOID_LOCKING
-+static unsigned max_lock_time;
-+static unsigned max_sem_time;
-+
-+void
-+acx_lock_unhold() { max_lock_time = 0; }
-+void
-+acx_sem_unhold() { max_sem_time = 0; }
-+
-+static inline const char*
-+sanitize_str(const char *s)
-+{
-+ const char* t = strrchr(s, '/');
-+ if (t) return t + 1;
-+ return s;
-+}
-+
-+void
-+acx_lock_debug(wlandevice_t *priv, const char* where)
-+{
-+ int count = 100*1000*1000;
-+ where = sanitize_str(where);
-+ while (--count) {
-+ if (!spin_is_locked(&priv->lock)) break;
-+ cpu_relax();
-+ }
-+ if (!count) {
-+ printk(KERN_EMERG "LOCKUP: already taken at %s!\n", priv->last_lock);
-+ BUG();
-+ }
-+ priv->last_lock = where;
-+ rdtscl(priv->lock_time);
-+}
-+void
-+acx_unlock_debug(wlandevice_t *priv, const char* where)
-+{
-+#ifdef SMP
-+ if (!spin_is_locked(&priv->lock)) {
-+ where = sanitize_str(where);
-+ printk(KERN_EMERG "STRAY UNLOCK at %s!\n", where);
-+ BUG();
-+ }
-+#endif
-+ if (acx_debug & L_LOCK) {
-+ unsigned diff;
-+ rdtscl(diff);
-+ diff -= priv->lock_time;
-+ if (diff > max_lock_time) {
-+ where = sanitize_str(where);
-+ printk("max lock hold time %d CPU ticks from %s "
-+ "to %s\n", diff, priv->last_lock, where);
-+ max_lock_time = diff;
-+ }
-+ }
-+}
-+void
-+acx_down_debug(wlandevice_t *priv, const char* where)
-+{
-+ int sem_count;
-+ int count = 5000/5;
-+ where = sanitize_str(where);
-+
-+ while (--count) {
-+ sem_count = atomic_read(&priv->sem.count);
-+ if (sem_count) break;
-+ msleep(5);
-+ }
-+ if (!count) {
-+ printk(KERN_EMERG "D STATE at %s! last sem at %s\n",
-+ where, priv->last_sem);
-+ dump_stack();
-+ }
-+ priv->last_sem = where;
-+ priv->sem_time = jiffies;
-+ down(&priv->sem);
-+ if (acx_debug & L_LOCK) {
-+ printk("%s: sem_down %d -> %d\n",
-+ where, sem_count, atomic_read(&priv->sem.count));
-+ }
-+}
-+void
-+acx_up_debug(wlandevice_t *priv, const char* where)
-+{
-+ int sem_count = atomic_read(&priv->sem.count);
-+ if (sem_count) {
-+ where = sanitize_str(where);
-+ printk(KERN_EMERG "STRAY UP at %s! sem.count=%d\n", where, sem_count);
-+ dump_stack();
-+ }
-+ if (acx_debug & L_LOCK) {
-+ unsigned diff = jiffies - priv->sem_time;
-+ if (diff > max_sem_time) {
-+ where = sanitize_str(where);
-+ printk("max sem hold time %d jiffies from %s "
-+ "to %s\n", diff, priv->last_sem, where);
-+ max_sem_time = diff;
-+ }
-+ }
-+ up(&priv->sem);
-+ if (acx_debug & L_LOCK) {
-+ where = sanitize_str(where);
-+ printk("%s: sem_up %d -> %d\n",
-+ where, sem_count, atomic_read(&priv->sem.count));
-+ }
-+}
-+#endif /* PARANOID_LOCKING */
-+
-+
-+/***********************************************************************
-+*/
-+#if ACX_DEBUG > 1
-+
-+static int acx_debug_func_indent;
-+#define DEBUG_TSC 0
-+#define FUNC_INDENT_INCREMENT 2
-+
-+#if DEBUG_TSC
-+#define TIMESTAMP(d) unsigned long d; rdtscl(d)
-+#else
-+#define TIMESTAMP(d) unsigned long d = jiffies
-+#endif
-+
-+static const char
-+spaces[] = " " " "; /* Nx10 spaces */
-+
-+void
-+log_fn_enter(const char *funcname)
-+{
-+ int indent;
-+ TIMESTAMP(d);
-+
-+ indent = acx_debug_func_indent;
-+ if (indent >= sizeof(spaces))
-+ indent = sizeof(spaces)-1;
-+
-+ printk("%08ld %s==> %s\n",
-+ d % 100000000,
-+ spaces + (sizeof(spaces)-1) - indent,
-+ funcname
-+ );
-+
-+ acx_debug_func_indent += FUNC_INDENT_INCREMENT;
-+}
-+void
-+log_fn_exit(const char *funcname)
-+{
-+ int indent;
-+ TIMESTAMP(d);
-+
-+ acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
-+
-+ indent = acx_debug_func_indent;
-+ if (indent >= sizeof(spaces))
-+ indent = sizeof(spaces)-1;
-+
-+ printk("%08ld %s<== %s\n",
-+ d % 100000000,
-+ spaces + (sizeof(spaces)-1) - indent,
-+ funcname
-+ );
-+}
-+void
-+log_fn_exit_v(const char *funcname, int v)
-+{
-+ int indent;
-+ TIMESTAMP(d);
-+
-+ acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
-+
-+ indent = acx_debug_func_indent;
-+ if (indent >= sizeof(spaces))
-+ indent = sizeof(spaces)-1;
-+
-+ printk("%08ld %s<== %s: %08X\n",
-+ d % 100000000,
-+ spaces + (sizeof(spaces)-1) - indent,
-+ funcname,
-+ v
-+ );
-+}
-+#endif /* ACX_DEBUG > 1 */
-+
-+
-+/***********************************************************************
-+** Basically a msleep with logging
-+*/
-+void
-+acx_s_msleep(int ms)
-+{
-+ FN_ENTER;
-+ msleep(ms);
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** Not inlined: it's larger than it seems
-+*/
-+void
-+acx_print_mac(const char *head, const u8 *mac, const char *tail)
-+{
-+ printk("%s"MACSTR"%s", head, MAC(mac), tail);
-+}
-+
-+
-+/***********************************************************************
-+** acx_get_status_name
-+*/
-+static const char*
-+acx_get_status_name(u16 status)
-+{
-+ static const char * const str[] = {
-+ "STOPPED", "SCANNING", "WAIT_AUTH",
-+ "AUTHENTICATED", "ASSOCIATED", "INVALID??"
-+ };
-+ return str[(status < VEC_SIZE(str)) ? status : VEC_SIZE(str)-1];
-+}
-+
-+
-+/***********************************************************************
-+** acx_get_packet_type_string
-+*/
-+#if ACX_DEBUG
-+const char*
-+acx_get_packet_type_string(u16 fc)
-+{
-+ static const char * const mgmt_arr[] = {
-+ "MGMT/AssocReq", "MGMT/AssocResp", "MGMT/ReassocReq",
-+ "MGMT/ReassocResp", "MGMT/ProbeReq", "MGMT/ProbeResp",
-+ "MGMT/UNKNOWN", "MGMT/UNKNOWN", "MGMT/Beacon", "MGMT/ATIM",
-+ "MGMT/Disassoc", "MGMT/Authen", "MGMT/Deauthen"
-+ };
-+ static const char * const ctl_arr[] = {
-+ "CTL/PSPoll", "CTL/RTS", "CTL/CTS", "CTL/Ack", "CTL/CFEnd",
-+ "CTL/CFEndCFAck"
-+ };
-+ static const char * const data_arr[] = {
-+ "DATA/DataOnly", "DATA/Data CFAck", "DATA/Data CFPoll",
-+ "DATA/Data CFAck/CFPoll", "DATA/Null", "DATA/CFAck",
-+ "DATA/CFPoll", "DATA/CFAck/CFPoll"
-+ };
-+ const char *str = "UNKNOWN";
-+ u8 fstype = (WF_FC_FSTYPE & fc) >> 4;
-+ u8 ctl;
-+
-+ switch (WF_FC_FTYPE & fc) {
-+ case WF_FTYPE_MGMT:
-+ str = "MGMT/UNKNOWN";
-+ if (fstype < VEC_SIZE(mgmt_arr))
-+ str = mgmt_arr[fstype];
-+ break;
-+ case WF_FTYPE_CTL:
-+ ctl = fstype - 0x0a;
-+ str = "CTL/UNKNOWN";
-+ if (ctl < VEC_SIZE(ctl_arr))
-+ str = ctl_arr[ctl];
-+ break;
-+ case WF_FTYPE_DATA:
-+ str = "DATA/UNKNOWN";
-+ if (fstype < VEC_SIZE(data_arr))
-+ str = data_arr[fstype];
-+ break;
-+ }
-+ return str;
-+}
-+#endif
-+
-+
-+/***********************************************************************
-+** acx_cmd_status_str
-+*/
-+const char*
-+acx_cmd_status_str(unsigned int state)
-+{
-+ static const char * const cmd_error_strings[] = {
-+ "Idle",
-+ "Success",
-+ "Unknown Command",
-+ "Invalid Information Element",
-+ "Channel rejected",
-+ "Channel invalid in current regulatory domain",
-+ "MAC invalid",
-+ "Command rejected (read-only information element)",
-+ "Command rejected",
-+ "Already asleep",
-+ "TX in progress",
-+ "Already awake",
-+ "Write only",
-+ "RX in progress",
-+ "Invalid parameter",
-+ "Scan in progress",
-+ "Failed"
-+ };
-+ return state < VEC_SIZE(cmd_error_strings) ?
-+ cmd_error_strings[state] : "UNKNOWN REASON";
-+}
-+
-+
-+/***********************************************************************
-+** get_status_string
-+*/
-+static const char*
-+get_status_string(unsigned int status)
-+{
-+ /* A bit shortened, but hopefully still understandable */
-+ static const char * const status_str[] = {
-+ /* 0 */ "Successful",
-+ /* 1 */ "Unspecified failure",
-+ /* 2 */ "reserved",
-+ /* 3 */ "reserved",
-+ /* 4 */ "reserved",
-+ /* 5 */ "reserved",
-+ /* 6 */ "reserved",
-+ /* 7 */ "reserved",
-+ /* 8 */ "reserved",
-+ /* 9 */ "reserved",
-+ /*10 */ "Cannot support all requested capabilities in Capability Information field",
-+ /*11 */ "Reassoc denied (reason outside of 802.11b scope)",
-+ /*12 */ "Assoc denied (reason outside of 802.11b scope), maybe MAC filtering by peer?",
-+ /*13 */ "Responding station doesnt support specified auth algorithm",
-+ /*14 */ "Auth rejected: wrong transaction sequence number",
-+ /*15 */ "Auth rejected: challenge failure",
-+ /*16 */ "Auth rejected: timeout for next frame in sequence",
-+ /*17 */ "Assoc denied: too many STAs on this AP",
-+ /*18 */ "Assoc denied: requesting STA doesnt support all data rates in basic set",
-+ /*19 */ "Assoc denied: requesting STA doesnt support Short Preamble",
-+ /*20 */ "Assoc denied: requesting STA doesnt support PBCC Modulation",
-+ /*21 */ "Assoc denied: requesting STA doesnt support Channel Agility"
-+ /*22 */ "reserved",
-+ /*23 */ "reserved",
-+ /*24 */ "reserved",
-+ /*25 */ "Assoc denied: requesting STA doesnt support Short Slot Time",
-+ /*26 */ "Assoc denied: requesting STA doesnt support DSSS-OFDM"
-+ };
-+
-+ return status_str[status < VEC_SIZE(status_str) ? status : 2];
-+}
-+
-+
-+/***********************************************************************
-+*/
-+void
-+acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr)
-+{
-+ acxlog(L_ASSOC, "acx: unknown EID %d in mgmt frame at offset %d\n",
-+ ie_ptr->eid, (int) ((u8*)ie_ptr - (u8*)hdr));
-+ if (acx_debug & (L_DATA|L_ASSOC)) {
-+ printk("frame (%s): ",
-+ acx_get_packet_type_string(le16_to_cpu(hdr->fc)));
-+ acx_dump_bytes(hdr, len);
-+ }
-+}
-+
-+
-+/***********************************************************************
-+*/
-+#if ACX_DEBUG
-+void
-+acx_dump_bytes(const void *data, int num)
-+{
-+ const u8* ptr = (const u8*)data;
-+
-+ if (num <= 0) {
-+ printk("\n");
-+ return;
-+ }
-+
-+ while (num >= 16) {
-+ printk( "%02X %02X %02X %02X %02X %02X %02X %02X "
-+ "%02X %02X %02X %02X %02X %02X %02X %02X\n",
-+ ptr[0], ptr[1], ptr[2], ptr[3],
-+ ptr[4], ptr[5], ptr[6], ptr[7],
-+ ptr[8], ptr[9], ptr[10], ptr[11],
-+ ptr[12], ptr[13], ptr[14], ptr[15]);
-+ num -= 16;
-+ ptr += 16;
-+ }
-+ if (num > 0) {
-+ while (--num > 0)
-+ printk("%02X ", *ptr++);
-+ printk("%02X\n", *ptr);
-+ }
-+}
-+#endif
-+
-+
-+/***********************************************************************
-+** maps acx111 tx descr rate field to acx100 one
-+*/
-+const u8
-+bitpos2rate100[] = {
-+ RATE100_1 ,/* 0 */
-+ RATE100_2 ,/* 1 */
-+ RATE100_5 ,/* 2 */
-+ RATE100_2 ,/* 3, should not happen */
-+ RATE100_2 ,/* 4, should not happen */
-+ RATE100_11 ,/* 5 */
-+ RATE100_2 ,/* 6, should not happen */
-+ RATE100_2 ,/* 7, should not happen */
-+ RATE100_22 ,/* 8 */
-+ RATE100_2 ,/* 9, should not happen */
-+ RATE100_2 ,/* 10, should not happen */
-+ RATE100_2 ,/* 11, should not happen */
-+ RATE100_2 ,/* 12, should not happen */
-+ RATE100_2 ,/* 13, should not happen */
-+ RATE100_2 ,/* 14, should not happen */
-+ RATE100_2 ,/* 15, should not happen */
-+};
-+
-+u8
-+acx_rate111to100(u16 r) {
-+ return bitpos2rate100[highest_bit(r)];
-+}
-+
-+
-+/***********************************************************************
-+** Calculate level like the feb 2003 windows driver seems to do
-+*/
-+static u8
-+acx_signal_to_winlevel(u8 rawlevel)
-+{
-+ /* u8 winlevel = (u8) (0.5 + 0.625 * rawlevel); */
-+ u8 winlevel = ((4 + (rawlevel * 5)) / 8);
-+
-+ if (winlevel > 100)
-+ winlevel = 100;
-+ return winlevel;
-+}
-+
-+u8
-+acx_signal_determine_quality(u8 signal, u8 noise)
-+{
-+ int qual;
-+
-+ qual = (((signal - 30) * 100 / 70) + (100 - noise * 4)) / 2;
-+
-+ if (qual > 100)
-+ return 100;
-+ if (qual < 0)
-+ return 0;
-+ return qual;
-+}
-+
-+
-+/***********************************************************************
-+** Interrogate/configure commands
-+*/
-+static const u16
-+CtlLength[] = {
-+ 0,
-+ ACX100_IE_ACX_TIMER_LEN,
-+ ACX1xx_IE_POWER_MGMT_LEN,
-+ ACX1xx_IE_QUEUE_CONFIG_LEN,
-+ ACX100_IE_BLOCK_SIZE_LEN,
-+ ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN,
-+ ACX1xx_IE_RATE_FALLBACK_LEN,
-+ ACX100_IE_WEP_OPTIONS_LEN,
-+ ACX1xx_IE_MEMORY_MAP_LEN, /* ACX1xx_IE_SSID_LEN, */
-+ 0,
-+ ACX1xx_IE_ASSOC_ID_LEN,
-+ 0,
-+ ACX111_IE_CONFIG_OPTIONS_LEN,
-+ ACX1xx_IE_FWREV_LEN,
-+ ACX1xx_IE_FCS_ERROR_COUNT_LEN,
-+ ACX1xx_IE_MEDIUM_USAGE_LEN,
-+ ACX1xx_IE_RXCONFIG_LEN,
-+ 0,
-+ 0,
-+ ACX1xx_IE_FIRMWARE_STATISTICS_LEN,
-+ 0,
-+ ACX1xx_IE_FEATURE_CONFIG_LEN,
-+ ACX111_IE_KEY_CHOOSE_LEN,
-+};
-+
-+static const u16
-+CtlLengthDot11[] = {
-+ 0,
-+ ACX1xx_IE_DOT11_STATION_ID_LEN,
-+ 0,
-+ ACX100_IE_DOT11_BEACON_PERIOD_LEN,
-+ ACX1xx_IE_DOT11_DTIM_PERIOD_LEN,
-+ ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN,
-+ ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN,
-+ ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE_LEN,
-+ ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN,
-+ 0,
-+ ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN,
-+ ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN,
-+ 0,
-+ ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN,
-+ ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN,
-+ ACX100_IE_DOT11_ED_THRESHOLD_LEN,
-+ ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN,
-+ 0,
-+ 0,
-+ 0,
-+};
-+
-+#undef FUNC
-+#define FUNC "configure"
-+#if !ACX_DEBUG
-+int
-+acx_s_configure(wlandevice_t *priv, void *pdr, int type)
-+{
-+#else
-+int
-+acx_s_configure_debug(wlandevice_t *priv, void *pdr, int type, const char* typestr)
-+{
-+#endif
-+ u16 len;
-+ int res;
-+
-+ if (type < 0x1000)
-+ len = CtlLength[type];
-+ else
-+ len = CtlLengthDot11[type - 0x1000];
-+
-+ acxlog(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
-+ if (unlikely(!len)) {
-+ acxlog(L_DEBUG, "zero-length type %s?!\n", typestr);
-+ }
-+
-+ ((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
-+ ((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
-+ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIGURE, pdr, len + 4);
-+ if (OK != res) {
-+#if ACX_DEBUG
-+ printk("%s: "FUNC"(type:%s) FAILED\n", priv->netdev->name, typestr);
-+#else
-+ printk("%s: "FUNC"(type:0x%X) FAILED\n", priv->netdev->name, type);
-+#endif
-+ /* dump_stack() is already done in issue_cmd() */
-+ }
-+ return res;
-+}
-+
-+#undef FUNC
-+#define FUNC "interrogate"
-+#if !ACX_DEBUG
-+int
-+acx_s_interrogate(wlandevice_t *priv, void *pdr, int type)
-+{
-+#else
-+int
-+acx_s_interrogate_debug(wlandevice_t *priv, void *pdr, int type,
-+ const char* typestr)
-+{
-+#endif
-+ u16 len;
-+ int res;
-+
-+ if (type < 0x1000)
-+ len = CtlLength[type];
-+ else
-+ len = CtlLengthDot11[type-0x1000];
-+ acxlog(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
-+
-+ printk("Type : %08x, Len : %04x\n",type,len);
-+
-+ ((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
-+ ((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
-+ res = acx_s_issue_cmd(priv, ACX1xx_CMD_INTERROGATE, pdr, len + 4);
-+ if (OK != res) {
-+#if ACX_DEBUG
-+ printk("%s: "FUNC"(type:%s) FAILED\n", priv->netdev->name, typestr);
-+#else
-+ printk("%s: "FUNC"(type:0x%X) FAILED\n", priv->netdev->name, type);
-+#endif
-+ /* dump_stack() is already done in issue_cmd() */
-+ }
-+ return res;
-+}
-+
-+#if CMD_DISCOVERY
-+void
-+great_inquisitor(wlandevice_t *priv)
-+{
-+ static struct {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ /* 0x200 was too large here: */
-+ u8 data[0x100 - 4] ACX_PACKED;
-+ } ie;
-+ u16 type;
-+
-+ FN_ENTER;
-+
-+ /* 0..0x20, 0x1000..0x1020 */
-+ for (type = 0; type <= 0x1020; type++) {
-+ if (type == 0x21)
-+ type = 0x1000;
-+ ie.type = cpu_to_le16(type);
-+ ie.len = cpu_to_le16(sizeof(ie) - 4);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_INTERROGATE, &ie, sizeof(ie));
-+ }
-+ FN_EXIT0;
-+}
-+#endif
-+
-+
-+#ifdef CONFIG_PROC_FS
-+/***********************************************************************
-+** /proc files
-+*/
-+/***********************************************************************
-+** acx_l_proc_output
-+** Generate content for our /proc entry
-+**
-+** Arguments:
-+** buf is a pointer to write output to
-+** priv is the usual pointer to our private struct wlandevice
-+** Returns:
-+** number of bytes actually written to buf
-+** Side effects:
-+** none
-+*/
-+static int
-+acx_l_proc_output(char *buf, wlandevice_t *priv)
-+{
-+ char *p = buf;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ p += sprintf(p,
-+ "acx driver version:\t\t" WLAN_RELEASE "\n"
-+ "Wireless extension version:\t" STRING(WIRELESS_EXT) "\n"
-+ "chip name:\t\t\t%s (0x%08X)\n"
-+ "radio type:\t\t\t0x%02X\n"
-+ "form factor:\t\t\t0x%02X\n"
-+ "EEPROM version:\t\t\t0x%02X\n"
-+ "firmware version:\t\t%s (0x%08X)\n",
-+ priv->chip_name, priv->firmware_id,
-+ priv->radio_type,
-+ priv->form_factor,
-+ priv->eeprom_version,
-+ priv->firmware_version, priv->firmware_numver);
-+
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ struct client *bss = &priv->sta_list[i];
-+ if (!bss->used) continue;
-+ p += sprintf(p, "BSS %u BSSID "MACSTR" ESSID %s channel %u "
-+ "Cap 0x%X SIR %u SNR %u\n",
-+ i, MAC(bss->bssid), (char*)bss->essid, bss->channel,
-+ bss->cap_info, bss->sir, bss->snr);
-+ }
-+ p += sprintf(p, "status:\t\t\t%u (%s)\n",
-+ priv->status, acx_get_status_name(priv->status));
-+
-+ FN_EXIT1(p - buf);
-+ return p - buf;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_s_proc_diag_output(char *buf, wlandevice_t *priv)
-+{
-+ char *p = buf;
-+ fw_stats_t *fw_stats;
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ fw_stats = kmalloc(sizeof(fw_stats_t), GFP_KERNEL);
-+ if (!fw_stats) {
-+ FN_EXIT1(0);
-+ return 0;
-+ }
-+ memset(fw_stats, 0, sizeof(fw_stats_t));
-+
-+ acx_lock(priv, flags);
-+
-+ if (IS_PCI(priv))
-+ p = acxpci_s_proc_diag_output(p, priv);
-+
-+ p += sprintf(p,
-+ "\n"
-+ "** network status **\n"
-+ "dev_state_mask 0x%04X\n"
-+ "status %u (%s), "
-+ "mode %u, channel %u, "
-+ "reg_dom_id 0x%02X, reg_dom_chanmask 0x%04X, ",
-+ priv->dev_state_mask,
-+ priv->status, acx_get_status_name(priv->status),
-+ priv->mode, priv->channel,
-+ priv->reg_dom_id, priv->reg_dom_chanmask
-+ );
-+ p += sprintf(p,
-+ "ESSID \"%s\", essid_active %d, essid_len %d, "
-+ "essid_for_assoc \"%s\", nick \"%s\"\n"
-+ "WEP ena %d, restricted %d, idx %d\n",
-+ priv->essid, priv->essid_active, (int)priv->essid_len,
-+ priv->essid_for_assoc, priv->nick,
-+ priv->wep_enabled, priv->wep_restricted,
-+ priv->wep_current_index);
-+ p += sprintf(p, "dev_addr "MACSTR"\n", MAC(priv->dev_addr));
-+ p += sprintf(p, "bssid "MACSTR"\n", MAC(priv->bssid));
-+ p += sprintf(p, "ap_filter "MACSTR"\n", MAC(priv->ap));
-+
-+ p += sprintf(p,
-+ "\n"
-+ "** PHY status **\n"
-+ "tx_disabled %d, tx_level_dbm %d\n" /* "tx_level_val %d, tx_level_auto %d\n" */
-+ "sensitivity %d, antenna 0x%02X, ed_threshold %d, cca %d, preamble_mode %d\n"
-+ "rts_threshold %d, short_retry %d, long_retry %d, msdu_lifetime %d, listen_interval %d, beacon_interval %d\n",
-+ priv->tx_disabled, priv->tx_level_dbm, /* priv->tx_level_val, priv->tx_level_auto, */
-+ priv->sensitivity, priv->antenna, priv->ed_threshold, priv->cca, priv->preamble_mode,
-+ priv->rts_threshold, priv->short_retry, priv->long_retry, priv->msdu_lifetime, priv->listen_interval, priv->beacon_interval);
-+
-+ acx_unlock(priv, flags);
-+
-+ if (OK != acx_s_interrogate(priv, fw_stats, ACX1xx_IE_FIRMWARE_STATISTICS))
-+ p += sprintf(p,
-+ "\n"
-+ "** Firmware **\n"
-+ "QUERY FAILED!!\n");
-+ else {
-+ p += sprintf(p,
-+ "\n"
-+ "** Firmware **\n"
-+ "version \"%s\"\n"
-+ "tx_desc_overfl %u, rx_OutOfMem %u, rx_hdr_overfl %u, rx_hdr_use_next %u\n"
-+ "rx_dropped_frame %u, rx_frame_ptr_err %u, rx_xfr_hint_trig %u, rx_dma_req %u\n"
-+ "rx_dma_err %u, tx_dma_req %u, tx_dma_err %u, cmd_cplt %u, fiq %u\n"
-+ "rx_hdrs %u, rx_cmplt %u, rx_mem_overfl %u, rx_rdys %u, irqs %u\n"
-+ "acx_trans_procs %u, decrypt_done %u, dma_0_done %u, dma_1_done %u\n",
-+ priv->firmware_version,
-+ le32_to_cpu(fw_stats->tx_desc_of),
-+ le32_to_cpu(fw_stats->rx_oom),
-+ le32_to_cpu(fw_stats->rx_hdr_of),
-+ le32_to_cpu(fw_stats->rx_hdr_use_next),
-+ le32_to_cpu(fw_stats->rx_dropped_frame),
-+ le32_to_cpu(fw_stats->rx_frame_ptr_err),
-+ le32_to_cpu(fw_stats->rx_xfr_hint_trig),
-+ le32_to_cpu(fw_stats->rx_dma_req),
-+ le32_to_cpu(fw_stats->rx_dma_err),
-+ le32_to_cpu(fw_stats->tx_dma_req),
-+ le32_to_cpu(fw_stats->tx_dma_err),
-+ le32_to_cpu(fw_stats->cmd_cplt),
-+ le32_to_cpu(fw_stats->fiq),
-+ le32_to_cpu(fw_stats->rx_hdrs),
-+ le32_to_cpu(fw_stats->rx_cmplt),
-+ le32_to_cpu(fw_stats->rx_mem_of),
-+ le32_to_cpu(fw_stats->rx_rdys),
-+ le32_to_cpu(fw_stats->irqs),
-+ le32_to_cpu(fw_stats->acx_trans_procs),
-+ le32_to_cpu(fw_stats->decrypt_done),
-+ le32_to_cpu(fw_stats->dma_0_done),
-+ le32_to_cpu(fw_stats->dma_1_done));
-+ p += sprintf(p,
-+ "tx_exch_complet %u, commands %u, acx_rx_procs %u\n"
-+ "hw_pm_mode_changes %u, host_acks %u, pci_pm %u, acm_wakeups %u\n"
-+ "wep_key_count %u, wep_default_key_count %u, dot11_def_key_mib %u\n"
-+ "wep_key_not_found %u, wep_decrypt_fail %u\n",
-+ le32_to_cpu(fw_stats->tx_exch_complet),
-+ le32_to_cpu(fw_stats->commands),
-+ le32_to_cpu(fw_stats->acx_rx_procs),
-+ le32_to_cpu(fw_stats->hw_pm_mode_changes),
-+ le32_to_cpu(fw_stats->host_acks),
-+ le32_to_cpu(fw_stats->pci_pm),
-+ le32_to_cpu(fw_stats->acm_wakeups),
-+ le32_to_cpu(fw_stats->wep_key_count),
-+ le32_to_cpu(fw_stats->wep_default_key_count),
-+ le32_to_cpu(fw_stats->dot11_def_key_mib),
-+ le32_to_cpu(fw_stats->wep_key_not_found),
-+ le32_to_cpu(fw_stats->wep_decrypt_fail));
-+ }
-+
-+ kfree(fw_stats);
-+
-+ FN_EXIT1(p - buf);
-+ return p - buf;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_s_proc_phy_output(char *buf, wlandevice_t *priv)
-+{
-+ char *p = buf;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /*
-+ if (RADIO_RFMD_11 != priv->radio_type) {
-+ printk("sorry, not yet adapted for radio types "
-+ "other than RFMD, please verify "
-+ "PHY size etc. first!\n");
-+ goto end;
-+ }
-+ */
-+
-+ /* The PHY area is only 0x80 bytes long; further pages after that
-+ * only have some page number registers with altered value,
-+ * all other registers remain the same. */
-+ for (i = 0; i < 0x80; i++) {
-+ acx_s_read_phy_reg(priv, i, p++);
-+ }
-+
-+ FN_EXIT1(p - buf);
-+ return p - buf;
-+}
-+
-+
-+/***********************************************************************
-+** acx_e_read_proc_XXXX
-+** Handle our /proc entry
-+**
-+** Arguments:
-+** standard kernel read_proc interface
-+** Returns:
-+** number of bytes written to buf
-+** Side effects:
-+** none
-+*/
-+static int
-+acx_e_read_proc(char *buf, char **start, off_t offset, int count,
-+ int *eof, void *data)
-+{
-+ wlandevice_t *priv = (wlandevice_t *)data;
-+ unsigned long flags;
-+ int length;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+ acx_lock(priv, flags);
-+ /* fill buf */
-+ length = acx_l_proc_output(buf, priv);
-+ acx_unlock(priv, flags);
-+ acx_sem_unlock(priv);
-+
-+ /* housekeeping */
-+ if (length <= offset + count)
-+ *eof = 1;
-+ *start = buf + offset;
-+ length -= offset;
-+ if (length > count)
-+ length = count;
-+ if (length < 0)
-+ length = 0;
-+ FN_EXIT1(length);
-+ return length;
-+}
-+
-+static int
-+acx_e_read_proc_diag(char *buf, char **start, off_t offset, int count,
-+ int *eof, void *data)
-+{
-+ wlandevice_t *priv = (wlandevice_t *)data;
-+ int length;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+ /* fill buf */
-+ length = acx_s_proc_diag_output(buf, priv);
-+ acx_sem_unlock(priv);
-+
-+ /* housekeeping */
-+ if (length <= offset + count)
-+ *eof = 1;
-+ *start = buf + offset;
-+ length -= offset;
-+ if (length > count)
-+ length = count;
-+ if (length < 0)
-+ length = 0;
-+ FN_EXIT1(length);
-+ return length;
-+}
-+
-+static int
-+acx_e_read_proc_eeprom(char *buf, char **start, off_t offset, int count,
-+ int *eof, void *data)
-+{
-+ wlandevice_t *priv = (wlandevice_t *)data;
-+ int length;
-+
-+ FN_ENTER;
-+
-+ /* fill buf */
-+ length = 0;
-+ if (IS_PCI(priv)) {
-+ acx_sem_lock(priv);
-+ length = acx_proc_eeprom_output(buf, priv);
-+ acx_sem_unlock(priv);
-+ }
-+
-+ /* housekeeping */
-+ if (length <= offset + count)
-+ *eof = 1;
-+ *start = buf + offset;
-+ length -= offset;
-+ if (length > count)
-+ length = count;
-+ if (length < 0)
-+ length = 0;
-+ FN_EXIT1(length);
-+ return length;
-+}
-+
-+static int
-+acx_e_read_proc_phy(char *buf, char **start, off_t offset, int count,
-+ int *eof, void *data)
-+{
-+ wlandevice_t *priv = (wlandevice_t *)data;
-+ int length;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+ /* fill buf */
-+ length = acx_s_proc_phy_output(buf, priv);
-+ acx_sem_unlock(priv);
-+
-+ /* housekeeping */
-+ if (length <= offset + count)
-+ *eof = 1;
-+ *start = buf + offset;
-+ length -= offset;
-+ if (length > count)
-+ length = count;
-+ if (length < 0)
-+ length = 0;
-+ FN_EXIT1(length);
-+ return length;
-+}
-+
-+
-+/***********************************************************************
-+** /proc files registration
-+*/
-+static const char * const
-+proc_files[] = { "", "_diag", "_eeprom", "_phy" };
-+
-+static read_proc_t * const
-+acx_proc_funcs[] = {
-+ acx_e_read_proc,
-+ acx_e_read_proc_diag,
-+ acx_e_read_proc_eeprom,
-+ acx_e_read_proc_phy
-+};
-+
-+static int
-+manage_proc_entries(const struct net_device *dev, int remove)
-+{
-+ /* doh, netdev_priv() doesn't have const! */
-+ wlandevice_t *priv = netdev_priv((struct net_device *)dev);
-+ char procbuf[80];
-+ int i;
-+
-+ for (i = 0; i < 4; i++) {
-+ sprintf(procbuf, "driver/acx_%s", dev->name);
-+ strcat(procbuf, proc_files[i]);
-+ if (!remove) {
-+ acxlog(L_INIT, "creating /proc entry %s\n", procbuf);
-+ if (!create_proc_read_entry(procbuf, 0, 0, acx_proc_funcs[i], priv))
-+ return NOT_OK;
-+ } else {
-+ acxlog(L_INIT, "removing /proc entry %s\n", procbuf);
-+ remove_proc_entry(procbuf, NULL);
-+ }
-+ }
-+ return OK;
-+}
-+
-+int
-+acx_proc_register_entries(const struct net_device *dev)
-+{
-+ return manage_proc_entries(dev, 0);
-+}
-+
-+int
-+acx_proc_unregister_entries(const struct net_device *dev)
-+{
-+ return manage_proc_entries(dev, 1);
-+}
-+#endif /* CONFIG_PROC_FS */
-+
-+
-+/***********************************************************************
-+** acx_cmd_join_bssid
-+**
-+** Common code for both acx100 and acx111.
-+*/
-+/* NB: does NOT match RATE100_nn but matches ACX[111]_SCAN_RATE_n */
-+static const u8
-+bitpos2genframe_txrate[] = {
-+ 10, /* 0. 1 Mbit/s */
-+ 20, /* 1. 2 Mbit/s */
-+ 55, /* 2. 5.5 Mbit/s */
-+ 0x0B, /* 3. 6 Mbit/s */
-+ 0x0F, /* 4. 9 Mbit/s */
-+ 110, /* 5. 11 Mbit/s */
-+ 0x0A, /* 6. 12 Mbit/s */
-+ 0x0E, /* 7. 18 Mbit/s */
-+ 220, /* 8. 22 Mbit/s */
-+ 0x09, /* 9. 24 Mbit/s */
-+ 0x0D, /* 10. 36 Mbit/s */
-+ 0x08, /* 11. 48 Mbit/s */
-+ 0x0C, /* 12. 54 Mbit/s */
-+ 10, /* 13. 1 Mbit/s, should never happen */
-+ 10, /* 14. 1 Mbit/s, should never happen */
-+ 10, /* 15. 1 Mbit/s, should never happen */
-+};
-+
-+/* Looks scary, eh?
-+** Actually, each one compiled into one AND and one SHIFT,
-+** 31 bytes in x86 asm (more if uints are replaced by u16/u8) */
-+static unsigned int
-+rate111to5bits(unsigned int rate)
-+{
-+ return (rate & 0x7)
-+ | ( (rate & RATE111_11) / (RATE111_11/JOINBSS_RATES_11) )
-+ | ( (rate & RATE111_22) / (RATE111_22/JOINBSS_RATES_22) )
-+ ;
-+}
-+
-+static void
-+acx_s_cmd_join_bssid(wlandevice_t *priv, const u8 *bssid)
-+{
-+ acx_joinbss_t tmp;
-+ int dtim_interval;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ dtim_interval = (ACX_MODE_0_ADHOC == priv->mode) ?
-+ 1 : priv->dtim_interval;
-+
-+ memset(&tmp, 0, sizeof(tmp));
-+
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ tmp.bssid[i] = bssid[ETH_ALEN-1 - i];
-+ }
-+
-+ tmp.beacon_interval = cpu_to_le16(priv->beacon_interval);
-+
-+ /* basic rate set. Control frame responses (such as ACK or CTS frames)
-+ ** are sent with one of these rates */
-+ if (IS_ACX111(priv)) {
-+ /* It was experimentally determined that rates_basic
-+ ** can take 11g rates as well, not only rates
-+ ** defined with JOINBSS_RATES_BASIC111_nnn.
-+ ** Just use RATE111_nnn constants... */
-+ tmp.u.acx111.dtim_interval = dtim_interval;
-+ tmp.u.acx111.rates_basic = cpu_to_le16(priv->rate_basic);
-+ acxlog(L_ASSOC, "%s rates_basic %04X, rates_supported %04X\n",
-+ __func__, priv->rate_basic, priv->rate_oper);
-+ } else {
-+ tmp.u.acx100.dtim_interval = dtim_interval;
-+ tmp.u.acx100.rates_basic = rate111to5bits(priv->rate_basic);
-+ tmp.u.acx100.rates_supported = rate111to5bits(priv->rate_oper);
-+ acxlog(L_ASSOC, "%s rates_basic %04X->%02X, "
-+ "rates_supported %04X->%02X\n",
-+ __func__,
-+ priv->rate_basic, tmp.u.acx100.rates_basic,
-+ priv->rate_oper, tmp.u.acx100.rates_supported);
-+ }
-+
-+ /* Setting up how Beacon, Probe Response, RTS, and PS-Poll frames
-+ ** will be sent (rate/modulation/preamble) */
-+ tmp.genfrm_txrate = bitpos2genframe_txrate[lowest_bit(priv->rate_basic)];
-+ tmp.genfrm_mod_pre = 0; /* FIXME: was = priv->capab_short (which is always 0); */
-+ /* we can use short pre *if* all peers can understand it */
-+ /* FIXME #2: we need to correctly set PBCC/OFDM bits here too */
-+
-+ /* we switch fw to STA mode in MONITOR mode, it seems to be
-+ ** the only mode where fw does not emit beacons by itself
-+ ** but allows us to send anything (we really want to retain
-+ ** ability to tx arbitrary frames in MONITOR mode)
-+ */
-+ tmp.macmode = (priv->mode != ACX_MODE_MONITOR ? priv->mode : ACX_MODE_2_STA);
-+ tmp.channel = priv->channel;
-+ tmp.essid_len = priv->essid_len;
-+ /* NOTE: the code memcpy'd essid_len + 1 before, which is WRONG! */
-+ memcpy(tmp.essid, priv->essid, tmp.essid_len);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_JOIN, &tmp, tmp.essid_len + 0x11);
-+
-+ acxlog(L_ASSOC|L_DEBUG, "BSS_Type = %u\n", tmp.macmode);
-+ acxlog_mac(L_ASSOC|L_DEBUG, "JoinBSSID MAC:", priv->bssid, "\n");
-+
-+ acx_update_capabilities(priv);
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_cmd_start_scan
-+**
-+** Issue scan command to the hardware
-+*/
-+static void
-+acx100_s_scan_chan(wlandevice_t *priv)
-+{
-+ acx100_scan_t s;
-+
-+ FN_ENTER;
-+
-+ memset(&s, 0, sizeof(s));
-+ s.count = cpu_to_le16(priv->scan_count);
-+ s.start_chan = cpu_to_le16(1);
-+ s.flags = cpu_to_le16(0x8000);
-+ s.max_rate = priv->scan_rate;
-+ s.options = priv->scan_mode;
-+ s.chan_duration = cpu_to_le16(priv->scan_duration);
-+ s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
-+
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
-+ FN_EXIT0;
-+}
-+
-+static void
-+acx111_s_scan_chan(wlandevice_t *priv)
-+{
-+ acx111_scan_t s;
-+
-+ FN_ENTER;
-+
-+ memset(&s, 0, sizeof(s));
-+ s.count = cpu_to_le16(priv->scan_count);
-+ s.channel_list_select = 0; /* scan every allowed channel */
-+ /*s.channel_list_select = 1;*/ /* scan given channels */
-+ s.rate = priv->scan_rate;
-+ s.options = priv->scan_mode;
-+ s.chan_duration = cpu_to_le16(priv->scan_duration);
-+ s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
-+ /*s.modulation = 0x40;*/ /* long preamble? OFDM? -> only for active scan */
-+ s.modulation = 0;
-+ /*s.channel_list[0] = 6;
-+ s.channel_list[1] = 4;*/
-+
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
-+ FN_EXIT0;
-+}
-+
-+void
-+acx_s_cmd_start_scan(wlandevice_t *priv)
-+{
-+ /* time_before check is 'just in case' thing */
-+ if (!(priv->irq_status & HOST_INT_SCAN_COMPLETE)
-+ && time_before(jiffies, priv->scan_start + 10*HZ)
-+ ) {
-+ acxlog(L_INIT, "start_scan: seems like previous scan "
-+ "is still running. Not starting anew. Please report\n");
-+ return;
-+ }
-+
-+ acxlog(L_INIT, "starting radio scan\n");
-+ /* remember that fw is commanded to do scan */
-+ priv->scan_start = jiffies;
-+ CLEAR_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
-+ /* issue it */
-+ if (IS_ACX100(priv)) {
-+ acx100_s_scan_chan(priv);
-+ } else {
-+ acx111_s_scan_chan(priv);
-+ }
-+}
-+
-+
-+/***********************************************************************
-+** acx111 feature config
-+*/
-+static int
-+acx111_s_get_feature_config(wlandevice_t *priv,
-+ u32 *feature_options, u32 *data_flow_options)
-+{
-+ struct acx111_ie_feature_config fc;
-+
-+ if (!IS_ACX111(priv)) {
-+ return NOT_OK;
-+ }
-+
-+ memset(&fc, 0, sizeof(fc));
-+
-+ if (OK != acx_s_interrogate(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
-+ return NOT_OK;
-+ }
-+ acxlog(L_DEBUG,
-+ "got Feature option:0x%X, DataFlow option: 0x%X\n",
-+ fc.feature_options,
-+ fc.data_flow_options);
-+
-+ if (feature_options)
-+ *feature_options = le32_to_cpu(fc.feature_options);
-+ if (data_flow_options)
-+ *data_flow_options = le32_to_cpu(fc.data_flow_options);
-+
-+ return OK;
-+}
-+
-+static int
-+acx111_s_set_feature_config(wlandevice_t *priv,
-+ u32 feature_options, u32 data_flow_options,
-+ unsigned int mode /* 0 == remove, 1 == add, 2 == set */)
-+{
-+ struct acx111_ie_feature_config fc;
-+
-+ if (!IS_ACX111(priv)) {
-+ return NOT_OK;
-+ }
-+
-+ if ((mode < 0) || (mode > 2))
-+ return NOT_OK;
-+
-+ if (mode != 2)
-+ /* need to modify old data */
-+ acx111_s_get_feature_config(priv, &fc.feature_options, &fc.data_flow_options);
-+ else {
-+ /* need to set a completely new value */
-+ fc.feature_options = 0;
-+ fc.data_flow_options = 0;
-+ }
-+
-+ if (mode == 0) { /* remove */
-+ CLEAR_BIT(fc.feature_options, cpu_to_le32(feature_options));
-+ CLEAR_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
-+ } else { /* add or set */
-+ SET_BIT(fc.feature_options, cpu_to_le32(feature_options));
-+ SET_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
-+ }
-+
-+ acxlog(L_DEBUG,
-+ "old: feature 0x%08X dataflow 0x%08X. mode: %u\n"
-+ "new: feature 0x%08X dataflow 0x%08X\n",
-+ feature_options, data_flow_options, mode,
-+ le32_to_cpu(fc.feature_options),
-+ le32_to_cpu(fc.data_flow_options));
-+
-+ if (OK != acx_s_configure(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
-+ return NOT_OK;
-+ }
-+
-+ return OK;
-+}
-+
-+static inline int
-+acx111_s_feature_off(wlandevice_t *priv, u32 f, u32 d)
-+{
-+ return acx111_s_set_feature_config(priv, f, d, 0);
-+}
-+static inline int
-+acx111_s_feature_on(wlandevice_t *priv, u32 f, u32 d)
-+{
-+ return acx111_s_set_feature_config(priv, f, d, 1);
-+}
-+static inline int
-+acx111_s_feature_set(wlandevice_t *priv, u32 f, u32 d)
-+{
-+ return acx111_s_set_feature_config(priv, f, d, 2);
-+}
-+
-+
-+/***********************************************************************
-+** acx100_s_init_memory_pools
-+*/
-+static int
-+acx100_s_init_memory_pools(wlandevice_t *priv, const acx_ie_memmap_t *mmt)
-+{
-+ acx100_ie_memblocksize_t MemoryBlockSize;
-+ acx100_ie_memconfigoption_t MemoryConfigOption;
-+ int TotalMemoryBlocks;
-+ int RxBlockNum;
-+ int TotalRxBlockSize;
-+ int TxBlockNum;
-+ int TotalTxBlockSize;
-+
-+ FN_ENTER;
-+
-+ /* Let's see if we can follow this:
-+ first we select our memory block size (which I think is
-+ completely arbitrary) */
-+ MemoryBlockSize.size = cpu_to_le16(priv->memblocksize);
-+
-+ /* Then we alert the card to our decision of block size */
-+ if (OK != acx_s_configure(priv, &MemoryBlockSize, ACX100_IE_BLOCK_SIZE)) {
-+ goto bad;
-+ }
-+
-+ /* We figure out how many total blocks we can create, using
-+ the block size we chose, and the beginning and ending
-+ memory pointers, i.e.: end-start/size */
-+ TotalMemoryBlocks = (le32_to_cpu(mmt->PoolEnd) - le32_to_cpu(mmt->PoolStart)) / priv->memblocksize;
-+
-+ acxlog(L_DEBUG, "TotalMemoryBlocks=%u (%u bytes)\n",
-+ TotalMemoryBlocks, TotalMemoryBlocks*priv->memblocksize);
-+
-+ /* MemoryConfigOption.DMA_config bitmask:
-+ // access to ACX memory is to be done:
-+ 0x00080000 // using PCI conf space?!
-+ 0x00040000 // using IO instructions?
-+ 0x00000000 // using memory access instructions
-+ 0x00020000 // use local memory block linked list (else what?)
-+ 0x00010000 // use host indirect descriptors (else host must access ACX memory?)
-+ */
-+ if (IS_PCI(priv)) {
-+ MemoryConfigOption.DMA_config = cpu_to_le32(0x30000);
-+ /* Declare start of the Rx host pool */
-+ MemoryConfigOption.pRxHostDesc = cpu2acx(priv->rxhostdesc_startphy);
-+ acxlog(L_DEBUG, "pRxHostDesc 0x%08X, rxhostdesc_startphy 0x%lX\n",
-+ acx2cpu(MemoryConfigOption.pRxHostDesc),
-+ (long)priv->rxhostdesc_startphy);
-+ } else {
-+ MemoryConfigOption.DMA_config = cpu_to_le32(0x20000);
-+ }
-+
-+ /* 50% of the allotment of memory blocks go to tx descriptors */
-+ TxBlockNum = TotalMemoryBlocks / 2;
-+ MemoryConfigOption.TxBlockNum = cpu_to_le16(TxBlockNum);
-+
-+ /* and 50% go to the rx descriptors */
-+ RxBlockNum = TotalMemoryBlocks - TxBlockNum;
-+ MemoryConfigOption.RxBlockNum = cpu_to_le16(RxBlockNum);
-+
-+ /* size of the tx and rx descriptor queues */
-+ TotalTxBlockSize = TxBlockNum * priv->memblocksize;
-+ TotalRxBlockSize = RxBlockNum * priv->memblocksize;
-+ acxlog(L_DEBUG, "TxBlockNum %u RxBlockNum %u TotalTxBlockSize %u "
-+ "TotalTxBlockSize %u\n", TxBlockNum, RxBlockNum,
-+ TotalTxBlockSize, TotalRxBlockSize);
-+
-+
-+ /* align the tx descriptor queue to an alignment of 0x20 (32 bytes) */
-+ MemoryConfigOption.rx_mem =
-+ cpu_to_le32((le32_to_cpu(mmt->PoolStart) + 0x1f) & ~0x1f);
-+
-+ /* align the rx descriptor queue to units of 0x20
-+ * and offset it by the tx descriptor queue */
-+ MemoryConfigOption.tx_mem =
-+ cpu_to_le32((le32_to_cpu(mmt->PoolStart) + TotalRxBlockSize + 0x1f) & ~0x1f);
-+ acxlog(L_DEBUG, "rx_mem %08X rx_mem %08X\n",
-+ MemoryConfigOption.tx_mem, MemoryConfigOption.rx_mem);
-+
-+ /* alert the device to our decision */
-+ if (OK != acx_s_configure(priv, &MemoryConfigOption, ACX1xx_IE_MEMORY_CONFIG_OPTIONS)) {
-+ goto bad;
-+ }
-+
-+ /* and tell the device to kick it into gear */
-+ if (OK != acx_s_issue_cmd(priv, ACX100_CMD_INIT_MEMORY, NULL, 0)) {
-+ goto bad;
-+ }
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/***********************************************************************
-+** acx100_s_create_dma_regions
-+**
-+** Note that this fn messes up heavily with hardware, but we cannot
-+** lock it (we need to sleep). Not a problem since IRQs can't happen
-+*/
-+static int
-+acx100_s_create_dma_regions(wlandevice_t *priv)
-+{
-+ acx100_ie_queueconfig_t queueconf;
-+ acx_ie_memmap_t memmap;
-+ int res = NOT_OK;
-+ u32 tx_queue_start, rx_queue_start;
-+
-+ FN_ENTER;
-+
-+ /* read out the acx100 physical start address for the queues */
-+ if (OK != acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
-+ goto fail;
-+ }
-+
-+ tx_queue_start = le32_to_cpu(memmap.QueueStart);
-+ rx_queue_start = tx_queue_start + TX_CNT * sizeof(txdesc_t);
-+
-+ acxlog(L_DEBUG, "initializing Queue Indicator\n");
-+
-+ memset(&queueconf, 0, sizeof(queueconf));
-+
-+ /* Not needed for PCI, so we can avoid setting them altogether */
-+ if (IS_USB(priv)) {
-+ queueconf.NumTxDesc = USB_TX_CNT;
-+ queueconf.NumRxDesc = USB_RX_CNT;
-+ }
-+
-+ /* calculate size of queues */
-+ queueconf.AreaSize = cpu_to_le32(
-+ TX_CNT * sizeof(txdesc_t) +
-+ RX_CNT * sizeof(rxdesc_t) + 8
-+ );
-+ queueconf.NumTxQueues = 1; /* number of tx queues */
-+ /* sets the beginning of the tx descriptor queue */
-+ queueconf.TxQueueStart = memmap.QueueStart;
-+ /* done by memset: queueconf.TxQueuePri = 0; */
-+ queueconf.RxQueueStart = cpu_to_le32(rx_queue_start);
-+ queueconf.QueueOptions = 1; /* auto reset descriptor */
-+ /* sets the end of the rx descriptor queue */
-+ queueconf.QueueEnd = cpu_to_le32(
-+ rx_queue_start + RX_CNT * sizeof(rxdesc_t)
-+ );
-+ /* sets the beginning of the next queue */
-+ queueconf.HostQueueEnd = cpu_to_le32(le32_to_cpu(queueconf.QueueEnd) + 8);
-+ if (OK != acx_s_configure(priv, &queueconf, ACX1xx_IE_QUEUE_CONFIG)) {
-+ goto fail;
-+ }
-+
-+#if 0
-+ if (IS_PCI(priv)) {
-+ /* sets the beginning of the rx descriptor queue, after the tx descrs */
-+ if (OK != acx_s_create_hostdesc_queues(priv))
-+ goto fail;
-+ acx_create_desc_queues(priv, tx_queue_start, rx_queue_start);
-+ }
-+#endif
-+
-+ if (OK != acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
-+ goto fail;
-+ }
-+
-+ memmap.PoolStart = cpu_to_le32(
-+ (le32_to_cpu(memmap.QueueEnd) + 4 + 0x1f) & ~0x1f
-+ );
-+
-+ if (OK != acx_s_configure(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
-+ goto fail;
-+ }
-+
-+ if (OK != acx100_s_init_memory_pools(priv, &memmap)) {
-+ goto fail;
-+ }
-+
-+ res = OK;
-+ goto end;
-+
-+fail:
-+ acx_s_msleep(1000); /* ? */
-+ if (IS_PCI(priv))
-+ acx_free_desc_queues(priv);
-+end:
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/***********************************************************************
-+** acx111_s_create_dma_regions
-+**
-+** Note that this fn messes up heavily with hardware, but we cannot
-+** lock it (we need to sleep). Not a problem since IRQs can't happen
-+*/
-+#define ACX111_PERCENT(percent) ((percent)/5)
-+
-+static int
-+acx111_s_create_dma_regions(wlandevice_t *priv)
-+{
-+ struct acx111_ie_memoryconfig memconf;
-+ struct acx111_ie_queueconfig queueconf;
-+ u32 tx_queue_start, rx_queue_start;
-+
-+ FN_ENTER;
-+
-+ /* Calculate memory positions and queue sizes */
-+
-+ /* Set up our host descriptor pool + data pool */
-+ if (IS_PCI(priv)) {
-+ if (OK != acx_s_create_hostdesc_queues(priv))
-+ goto fail;
-+ }
-+
-+ memset(&memconf, 0, sizeof(memconf));
-+ /* the number of STAs (STA contexts) to support
-+ ** NB: was set to 1 and everything seemed to work nevertheless... */
-+ memconf.no_of_stations = cpu_to_le16(VEC_SIZE(priv->sta_list));
-+ /* specify the memory block size. Default is 256 */
-+ memconf.memory_block_size = cpu_to_le16(priv->memblocksize);
-+ /* let's use 50%/50% for tx/rx (specify percentage, units of 5%) */
-+ memconf.tx_rx_memory_block_allocation = ACX111_PERCENT(50);
-+ /* set the count of our queues
-+ ** NB: struct acx111_ie_memoryconfig shall be modified
-+ ** if we ever will switch to more than one rx and/or tx queue */
-+ memconf.count_rx_queues = 1;
-+ memconf.count_tx_queues = 1;
-+ /* 0 == Busmaster Indirect Memory Organization, which is what we want
-+ * (using linked host descs with their allocated mem).
-+ * 2 == Generic Bus Slave */
-+ /* done by memset: memconf.options = 0; */
-+ /* let's use 25% for fragmentations and 75% for frame transfers
-+ * (specified in units of 5%) */
-+ memconf.fragmentation = ACX111_PERCENT(75);
-+ /* Rx descriptor queue config */
-+ memconf.rx_queue1_count_descs = RX_CNT;
-+ memconf.rx_queue1_type = 7; /* must be set to 7 */
-+ /* done by memset: memconf.rx_queue1_prio = 0; low prio */
-+ if (IS_PCI(priv)) {
-+ memconf.rx_queue1_host_rx_start = cpu2acx(priv->rxhostdesc_startphy);
-+ }
-+ /* Tx descriptor queue config */
-+ memconf.tx_queue1_count_descs = TX_CNT;
-+ /* done by memset: memconf.tx_queue1_attributes = 0; lowest priority */
-+
-+ /* NB1: this looks wrong: (memconf,ACX1xx_IE_QUEUE_CONFIG),
-+ ** (queueconf,ACX1xx_IE_MEMORY_CONFIG_OPTIONS) look swapped, eh?
-+ ** But it is actually correct wrt IE numbers.
-+ ** NB2: sizeof(memconf) == 28 == 0x1c but configure(ACX1xx_IE_QUEUE_CONFIG)
-+ ** writes 0x20 bytes (because same IE for acx100 uses struct acx100_ie_queueconfig
-+ ** which is 4 bytes larger. what a mess. TODO: clean it up) */
-+ if (OK != acx_s_configure(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG)) {
-+ goto fail;
-+ }
-+
-+ acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
-+
-+ tx_queue_start = le32_to_cpu(queueconf.tx1_queue_address);
-+ rx_queue_start = le32_to_cpu(queueconf.rx1_queue_address);
-+
-+ acxlog(L_INIT, "dump queue head (from card):\n"
-+ "len: %u\n"
-+ "tx_memory_block_address: %X\n"
-+ "rx_memory_block_address: %X\n"
-+ "tx1_queue address: %X\n"
-+ "rx1_queue address: %X\n",
-+ le16_to_cpu(queueconf.len),
-+ le32_to_cpu(queueconf.tx_memory_block_address),
-+ le32_to_cpu(queueconf.rx_memory_block_address),
-+ tx_queue_start,
-+ rx_queue_start);
-+
-+ if (IS_PCI(priv))
-+ acx_create_desc_queues(priv, tx_queue_start, rx_queue_start);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+fail:
-+ if (IS_PCI(priv))
-+ acx_free_desc_queues(priv);
-+
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_set_defaults
-+** Called from acx_s_init_mac
-+*/
-+int
-+acx_s_set_defaults(wlandevice_t *priv)
-+{
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ /* query some settings from the card.
-+ * NOTE: for some settings, e.g. CCA and ED (ACX100!), an initial
-+ * query is REQUIRED, otherwise the card won't work correctly!! */
-+ priv->get_mask = GETSET_ANTENNA|GETSET_SENSITIVITY|GETSET_STATION_ID|GETSET_REG_DOMAIN;
-+ /* Only ACX100 supports ED and CCA */
-+ if (IS_ACX100(priv))
-+ priv->get_mask |= GETSET_CCA|GETSET_ED_THRESH;
-+
-+ acx_s_update_card_settings(priv, 0, 0);
-+
-+ acx_lock(priv, flags);
-+
-+ /* set our global interrupt mask */
-+ if (IS_PCI(priv))
-+ acx_set_interrupt_mask(priv);
-+
-+ priv->led_power = 1; /* LED is active on startup */
-+ priv->brange_max_quality = 60; /* LED blink max quality is 60 */
-+ priv->brange_time_last_state_change = jiffies;
-+
-+ /* copy the MAC address we just got from the card
-+ * into our MAC address used during current 802.11 session */
-+ MAC_COPY(priv->dev_addr, priv->netdev->dev_addr);
-+ sprintf(priv->essid, "STA%02X%02X%02X",
-+ priv->dev_addr[3], priv->dev_addr[4], priv->dev_addr[5]);
-+ priv->essid_len = sizeof("STAxxxxxx") - 1; /* make sure to adapt if changed above! */
-+ priv->essid_active = 1;
-+
-+ /* we have a nick field to waste, so why not abuse it
-+ * to announce the driver version? ;-) */
-+ strncpy(priv->nick, "acx " WLAN_RELEASE, IW_ESSID_MAX_SIZE);
-+
-+ if (IS_PCI(priv)) {
-+ if (IS_ACX111(priv)) {
-+ /* Hope this is correct, only tested with domain 0x30 */
-+ acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
-+ } else if (priv->eeprom_version < 5) {
-+ acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
-+ } else {
-+ acx_read_eeprom_offset(priv, 0x171, &priv->reg_dom_id);
-+ }
-+ }
-+
-+ priv->channel = 1;
-+ /* 0xffff would be better, but then we won't get a "scan complete"
-+ * interrupt, so our current infrastructure will fail: */
-+ priv->scan_count = 1;
-+ priv->scan_mode = ACX_SCAN_OPT_PASSIVE;
-+ /* Doesn't work for acx100, do it only for acx111 for now */
-+ if (IS_ACX111(priv)) {
-+ priv->scan_mode = ACX_SCAN_OPT_ACTIVE;
-+ }
-+ priv->scan_duration = 100;
-+ priv->scan_probe_delay = 200;
-+ priv->scan_rate = ACX_SCAN_RATE_1;
-+
-+ priv->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
-+ priv->preamble_mode = 2; /* auto */
-+ priv->listen_interval = 100;
-+ priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
-+ priv->mode = ACX_MODE_2_STA;
-+ priv->dtim_interval = DEFAULT_DTIM_INTERVAL;
-+
-+ priv->msdu_lifetime = DEFAULT_MSDU_LIFETIME;
-+ SET_BIT(priv->set_mask, SET_MSDU_LIFETIME);
-+
-+ priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
-+
-+ /* use standard default values for retry limits */
-+ priv->short_retry = 7; /* max. retries for (short) non-RTS packets */
-+ priv->long_retry = 4; /* max. retries for long (RTS) packets */
-+ SET_BIT(priv->set_mask, GETSET_RETRY);
-+
-+ priv->fallback_threshold = 3;
-+ priv->stepup_threshold = 10;
-+ priv->rate_bcast = RATE111_1;
-+ priv->rate_bcast100 = RATE100_1;
-+ priv->rate_basic = RATE111_1 | RATE111_2;
-+ priv->rate_auto = 1;
-+ if (IS_ACX111(priv)) {
-+ priv->rate_oper = RATE111_ALL;
-+ } else {
-+ priv->rate_oper = RATE111_ACX100_COMPAT;
-+ }
-+
-+ /* configure card to do rate fallback when in auto rate mode. */
-+ SET_BIT(priv->set_mask, SET_RATE_FALLBACK);
-+
-+ /* Supported Rates element - the rates here are given in units of
-+ * 500 kbit/s, plus 0x80 added. See 802.11-1999.pdf item 7.3.2.2 */
-+ acx_l_update_ratevector(priv);
-+
-+ priv->capab_short = 0;
-+ priv->capab_pbcc = 1;
-+ priv->capab_agility = 0;
-+
-+ SET_BIT(priv->set_mask, SET_RXCONFIG);
-+
-+ /* set some more defaults */
-+ if (IS_ACX111(priv)) {
-+ /* 30mW (15dBm) is default, at least in my acx111 card: */
-+ priv->tx_level_dbm = 15;
-+ } else {
-+ /* don't use max. level, since it might be dangerous
-+ * (e.g. WRT54G people experience
-+ * excessive Tx power damage!) */
-+ priv->tx_level_dbm = 18;
-+ }
-+ /* priv->tx_level_auto = 1; */
-+ SET_BIT(priv->set_mask, GETSET_TXPOWER);
-+
-+ if (IS_ACX111(priv)) {
-+ /* start with sensitivity level 1 out of 3: */
-+ priv->sensitivity = 1;
-+ }
-+
-+ /* better re-init the antenna value we got above */
-+ SET_BIT(priv->set_mask, GETSET_ANTENNA);
-+
-+ priv->ps_wakeup_cfg = 0;
-+ priv->ps_listen_interval = 0;
-+ priv->ps_options = 0;
-+ priv->ps_hangover_period = 0;
-+ priv->ps_enhanced_transition_time = 0;
-+#ifdef POWER_SAVE_80211
-+ SET_BIT(priv->set_mask, GETSET_POWER_80211);
-+#endif
-+
-+ MAC_BCAST(priv->ap);
-+
-+ acx_unlock(priv, flags);
-+ acx_lock_unhold(); // hold time 844814 CPU ticks @2GHz
-+
-+ acx_s_initialize_rx_config(priv);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+** FIXME: this should be solved in a general way for all radio types
-+** by decoding the radio firmware module,
-+** since it probably has some standard structure describing how to
-+** set the power level of the radio module which it controls.
-+** Or maybe not, since the radio module probably has a function interface
-+** instead which then manages Tx level programming :-\
-+*/
-+static int
-+acx111_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
-+{
-+ struct acx111_ie_tx_level tx_level;
-+
-+ /* my acx111 card has two power levels in its configoptions (== EEPROM):
-+ * 1 (30mW) [15dBm]
-+ * 2 (10mW) [10dBm]
-+ * For now, just assume all other acx111 cards have the same.
-+ * Ideally we would query it here, but we first need a
-+ * standard way to query individual configoptions easily. */
-+ if (level_dbm <= 12) {
-+ tx_level.level = 2; /* 10 dBm */
-+ priv->tx_level_dbm = 10;
-+ } else {
-+ tx_level.level = 1; /* 15 dBm */
-+ priv->tx_level_dbm = 15;
-+ }
-+ if (level_dbm != priv->tx_level_dbm)
-+ acxlog(L_INIT, "acx111 firmware has specific "
-+ "power levels only: adjusted %d dBm to %d dBm!\n",
-+ level_dbm, priv->tx_level_dbm);
-+
-+ return acx_s_configure(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
-+}
-+
-+static int
-+acx_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
-+{
-+ if (IS_ACX111(priv)) {
-+ return acx111_s_set_tx_level(priv, level_dbm);
-+ }
-+ if (IS_PCI(priv)) {
-+ return acx100_s_set_tx_level(priv, level_dbm);
-+ }
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+#ifdef UNUSED
-+/* Returns the current tx level (ACX111) */
-+static u8
-+acx111_s_get_tx_level(wlandevice_t *priv)
-+{
-+ struct acx111_ie_tx_level tx_level;
-+
-+ tx_level.level = 0;
-+ acx_s_interrogate(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
-+ return tx_level.level;
-+}
-+#endif
-+
-+
-+/***********************************************************************
-+** acx_s_init_mac
-+*/
-+int
-+acx_s_init_mac(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result = NOT_OK;
-+
-+ FN_ENTER;
-+
-+ if (IS_PCI(priv)) {
-+ priv->memblocksize = 256; /* 256 is default */
-+ acx_init_mboxes(priv);
-+ /* try to load radio for both ACX100 and ACX111, since both
-+ * chips have at least some firmware versions making use of an
-+ * external radio module */
-+ acx_s_upload_radio(priv);
-+ } else {
-+ priv->memblocksize = 128;
-+ }
-+
-+ if (IS_ACX111(priv)) {
-+ /* for ACX111, the order is different from ACX100
-+ 1. init packet templates
-+ 2. create station context and create dma regions
-+ 3. init wep default keys
-+ */
-+ if (OK != acx111_s_init_packet_templates(priv))
-+ goto fail;
-+
-+ if (OK != acx111_s_create_dma_regions(priv)) {
-+ printk("%s: acx111_create_dma_regions FAILED\n",
-+ dev->name);
-+ goto fail;
-+ }
-+#ifdef DEBUG_WEP
-+ /* don't decrypt WEP in firmware */
-+ if (OK != acx111_s_feature_on(priv, 0, FEATURE2_SNIFFER))
-+ goto fail;
-+#endif
-+ } else {
-+ if (OK != acx100_s_init_wep(priv))
-+ goto fail;
-+ acxlog(L_DEBUG, "between init_wep and init_packet_templates\n");
-+ if (OK != acx100_s_init_packet_templates(priv))
-+ goto fail;
-+
-+ if (OK != acx100_s_create_dma_regions(priv)) {
-+ printk("%s: acx100_create_dma_regions FAILED\n",
-+ dev->name);
-+ goto fail;
-+ }
-+ }
-+
-+ MAC_COPY(dev->dev_addr, priv->dev_addr);
-+ result = OK;
-+
-+fail:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_rxmonitor
-+* Called from IRQ context only
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_rxmonitor(wlandevice_t *priv, const rxbuffer_t *rxbuf)
-+{
-+ wlansniffrm_t *msg;
-+ struct sk_buff *skb;
-+ void *datap;
-+ unsigned int skb_len;
-+ int payload_offset;
-+
-+ FN_ENTER;
-+
-+ /* we are in big luck: the acx100 doesn't modify any of the fields */
-+ /* in the 802.11 frame. just pass this packet into the PF_PACKET */
-+ /* subsystem. yeah. */
-+ payload_offset = ((u8*)acx_get_wlan_hdr(priv, rxbuf) - (u8*)rxbuf);
-+ skb_len = RXBUF_BYTES_USED(rxbuf) - payload_offset;
-+
-+ /* sanity check */
-+ if (skb_len > WLAN_A4FR_MAXLEN_WEP) {
-+ printk("%s: monitor mode panic: oversized frame!\n",
-+ priv->netdev->name);
-+ goto end;
-+ }
-+
-+ if (priv->netdev->type == ARPHRD_IEEE80211_PRISM)
-+ skb_len += sizeof(*msg);
-+
-+ /* allocate skb */
-+ skb = dev_alloc_skb(skb_len);
-+ if (!skb) {
-+ printk("%s: no memory for skb (%u bytes)\n",
-+ priv->netdev->name, skb_len);
-+ goto end;
-+ }
-+
-+ skb_put(skb, skb_len);
-+
-+ /* when in raw 802.11 mode, just copy frame as-is */
-+ if (priv->netdev->type == ARPHRD_IEEE80211)
-+ datap = skb->data;
-+ else { /* otherwise, emulate prism header */
-+ msg = (wlansniffrm_t*)skb->data;
-+ datap = msg + 1;
-+
-+ msg->msgcode = WLANSNIFFFRM;
-+ msg->msglen = sizeof(*msg);
-+ strncpy(msg->devname, priv->netdev->name, sizeof(msg->devname)-1);
-+ msg->devname[sizeof(msg->devname)-1] = '\0';
-+
-+ msg->hosttime.did = WLANSNIFFFRM_hosttime;
-+ msg->hosttime.status = WLANITEM_STATUS_data_ok;
-+ msg->hosttime.len = 4;
-+ msg->hosttime.data = jiffies;
-+
-+ msg->mactime.did = WLANSNIFFFRM_mactime;
-+ msg->mactime.status = WLANITEM_STATUS_data_ok;
-+ msg->mactime.len = 4;
-+ msg->mactime.data = rxbuf->time;
-+
-+ msg->channel.did = WLANSNIFFFRM_channel;
-+ msg->channel.status = WLANITEM_STATUS_data_ok;
-+ msg->channel.len = 4;
-+ msg->channel.data = priv->channel;
-+
-+ msg->rssi.did = WLANSNIFFFRM_rssi;
-+ msg->rssi.status = WLANITEM_STATUS_no_value;
-+ msg->rssi.len = 4;
-+ msg->rssi.data = 0;
-+
-+ msg->sq.did = WLANSNIFFFRM_sq;
-+ msg->sq.status = WLANITEM_STATUS_no_value;
-+ msg->sq.len = 4;
-+ msg->sq.data = 0;
-+
-+ msg->signal.did = WLANSNIFFFRM_signal;
-+ msg->signal.status = WLANITEM_STATUS_data_ok;
-+ msg->signal.len = 4;
-+ msg->signal.data = rxbuf->phy_snr;
-+
-+ msg->noise.did = WLANSNIFFFRM_noise;
-+ msg->noise.status = WLANITEM_STATUS_data_ok;
-+ msg->noise.len = 4;
-+ msg->noise.data = rxbuf->phy_level;
-+
-+ msg->rate.did = WLANSNIFFFRM_rate;
-+ msg->rate.status = WLANITEM_STATUS_data_ok;
-+ msg->rate.len = 4;
-+ msg->rate.data = rxbuf->phy_plcp_signal / 5;
-+
-+ msg->istx.did = WLANSNIFFFRM_istx;
-+ msg->istx.status = WLANITEM_STATUS_data_ok;
-+ msg->istx.len = 4;
-+ msg->istx.data = 0; /* tx=0: it's not a tx packet */
-+
-+ skb_len -= sizeof(*msg);
-+
-+ msg->frmlen.did = WLANSNIFFFRM_signal;
-+ msg->frmlen.status = WLANITEM_STATUS_data_ok;
-+ msg->frmlen.len = 4;
-+ msg->frmlen.data = skb_len;
-+ }
-+
-+ memcpy(datap, ((unsigned char*)rxbuf)+payload_offset, skb_len);
-+
-+ skb->dev = priv->netdev;
-+ skb->dev->last_rx = jiffies;
-+
-+ skb->mac.raw = skb->data;
-+ skb->ip_summed = CHECKSUM_NONE;
-+ skb->pkt_type = PACKET_OTHERHOST;
-+ skb->protocol = htons(ETH_P_80211_RAW);
-+ netif_rx(skb);
-+
-+ priv->stats.rx_packets++;
-+ priv->stats.rx_bytes += skb->len;
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx_l_rx_ieee802_11_frame
-+**
-+** Called from IRQ context only
-+*/
-+
-+/* All these contortions are for saner dup logging
-+**
-+** We want: (a) to know about excessive dups
-+** (b) to not spam kernel log about occasional dups
-+**
-+** 1/64 threshold was chosen by running "ping -A"
-+** It gave "rx: 59 DUPs in 2878 packets" only with 4 parallel
-+** "ping -A" streams running. */
-+static inline int
-+acx_l_handle_dup(wlandevice_t *priv, u16 seq)
-+{
-+ if (priv->dup_count) {
-+ priv->nondup_count++;
-+ if (time_after(jiffies, priv->dup_msg_expiry)) {
-+ /* Log only if more than 1 dup in 64 packets */
-+ if (priv->nondup_count/64 < priv->dup_count) {
-+ printk(KERN_INFO "%s: rx: %d DUPs in "
-+ "%d packets received in 10 secs\n",
-+ priv->netdev->name,
-+ priv->dup_count,
-+ priv->nondup_count);
-+ }
-+ priv->dup_count = 0;
-+ priv->nondup_count = 0;
-+ }
-+ }
-+ if (unlikely(seq == priv->last_seq_ctrl)) {
-+ if (!priv->dup_count++)
-+ priv->dup_msg_expiry = jiffies + 10*HZ;
-+ priv->stats.rx_errors++;
-+ return 1; /* a dup */
-+ }
-+ priv->last_seq_ctrl = seq;
-+ return 0;
-+}
-+
-+static int
-+acx_l_rx_ieee802_11_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
-+{
-+ unsigned int ftype, fstype;
-+ const wlan_hdr_t *hdr;
-+ int result = NOT_OK;
-+
-+ FN_ENTER;
-+
-+ hdr = acx_get_wlan_hdr(priv, rxbuf);
-+
-+ /* see IEEE 802.11-1999.pdf chapter 7 "MAC frame formats" */
-+ if ((hdr->fc & WF_FC_PVERi) != 0) {
-+ printk_ratelimited(KERN_INFO "rx: unsupported 802.11 protocol\n");
-+ goto end;
-+ }
-+
-+ ftype = hdr->fc & WF_FC_FTYPEi;
-+ fstype = hdr->fc & WF_FC_FSTYPEi;
-+
-+ switch (ftype) {
-+ /* check data frames first, for speed */
-+ case WF_FTYPE_DATAi:
-+ switch (fstype) {
-+ case WF_FSTYPE_DATAONLYi:
-+ if (acx_l_handle_dup(priv, hdr->seq))
-+ break; /* a dup, simply discard it */
-+
-+ /* TODO:
-+ if (WF_FC_FROMTODSi == (hdr->fc & WF_FC_FROMTODSi)) {
-+ result = acx_l_process_data_frame_wds(priv, rxbuf);
-+ break;
-+ }
-+ */
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_3_AP:
-+ result = acx_l_process_data_frame_master(priv, rxbuf);
-+ break;
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ result = acx_l_process_data_frame_client(priv, rxbuf);
-+ break;
-+ }
-+ case WF_FSTYPE_DATA_CFACKi:
-+ case WF_FSTYPE_DATA_CFPOLLi:
-+ case WF_FSTYPE_DATA_CFACK_CFPOLLi:
-+ case WF_FSTYPE_CFPOLLi:
-+ case WF_FSTYPE_CFACK_CFPOLLi:
-+ /* see above.
-+ acx_process_class_frame(priv, rxbuf, 3); */
-+ break;
-+ case WF_FSTYPE_NULLi:
-+ /* acx_l_process_NULL_frame(priv, rxbuf, 3); */
-+ break;
-+ /* FIXME: same here, see above */
-+ case WF_FSTYPE_CFACKi:
-+ default:
-+ break;
-+ }
-+ break;
-+ case WF_FTYPE_MGMTi:
-+ result = acx_l_process_mgmt_frame(priv, rxbuf);
-+ break;
-+ case WF_FTYPE_CTLi:
-+ if (fstype == WF_FSTYPE_PSPOLLi)
-+ result = OK;
-+ /* this call is irrelevant, since
-+ * acx_process_class_frame is a stub, so return
-+ * immediately instead.
-+ * return acx_process_class_frame(priv, rxbuf, 3); */
-+ break;
-+ default:
-+ break;
-+ }
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_l_process_rxbuf
-+**
-+** NB: used by USB code also
-+*/
-+void
-+acx_l_process_rxbuf(wlandevice_t *priv, rxbuffer_t *rxbuf)
-+{
-+ struct wlan_hdr *hdr;
-+ unsigned int buf_len;
-+ unsigned int qual;
-+ u16 fc;
-+
-+ hdr = acx_get_wlan_hdr(priv, rxbuf);
-+ /* length of frame from control field to last byte of FCS */
-+ buf_len = RXBUF_BYTES_RCVD(rxbuf);
-+ fc = le16_to_cpu(hdr->fc);
-+
-+ if ( ((WF_FC_FSTYPE & fc) != WF_FSTYPE_BEACON)
-+ || (acx_debug & L_XFER_BEACON)
-+ ) {
-+ acxlog(L_XFER|L_DATA, "rx: %s "
-+ "time %u len %u signal %u SNR %u macstat %02X "
-+ "phystat %02X phyrate %u status %u\n",
-+ acx_get_packet_type_string(fc),
-+ le32_to_cpu(rxbuf->time),
-+ buf_len,
-+ acx_signal_to_winlevel(rxbuf->phy_level),
-+ acx_signal_to_winlevel(rxbuf->phy_snr),
-+ rxbuf->mac_status,
-+ rxbuf->phy_stat_baseband,
-+ rxbuf->phy_plcp_signal,
-+ priv->status);
-+ }
-+
-+ if (unlikely(acx_debug & L_DATA)) {
-+ printk("rx: 802.11 buf[%u]: ", buf_len);
-+ acx_dump_bytes(hdr, buf_len);
-+ }
-+
-+ /* FIXME: should check for Rx errors (rxbuf->mac_status?
-+ * discard broken packets - but NOT for monitor!)
-+ * and update Rx packet statistics here */
-+
-+ if (unlikely(priv->mode == ACX_MODE_MONITOR)) {
-+ acx_l_rxmonitor(priv, rxbuf);
-+ } else if (likely(buf_len >= WLAN_HDR_A3_LEN)) {
-+ acx_l_rx_ieee802_11_frame(priv, rxbuf);
-+ } else {
-+ acxlog(L_DEBUG|L_XFER|L_DATA,
-+ "rx: NOT receiving packet (%s): "
-+ "size too small (%u)\n",
-+ acx_get_packet_type_string(fc),
-+ buf_len);
-+ }
-+
-+ /* Now check Rx quality level, AFTER processing packet.
-+ * I tried to figure out how to map these levels to dBm
-+ * values, but for the life of me I really didn't
-+ * manage to get it. Either these values are not meant to
-+ * be expressed in dBm, or it's some pretty complicated
-+ * calculation. */
-+
-+#ifdef FROM_SCAN_SOURCE_ONLY
-+ /* only consider packets originating from the MAC
-+ * address of the device that's managing our BSSID.
-+ * Disable it for now, since it removes information (levels
-+ * from different peers) and slows the Rx path. */
-+ if (priv->ap_client
-+ && mac_is_equal(hdr->a2, priv->ap_client->address)) {
-+#endif
-+ priv->wstats.qual.level = acx_signal_to_winlevel(rxbuf->phy_level);
-+ priv->wstats.qual.noise = acx_signal_to_winlevel(rxbuf->phy_snr);
-+#ifndef OLD_QUALITY
-+ qual = acx_signal_determine_quality(priv->wstats.qual.level,
-+ priv->wstats.qual.noise);
-+#else
-+ qual = (priv->wstats.qual.noise <= 100) ?
-+ 100 - priv->wstats.qual.noise : 0;
-+#endif
-+ priv->wstats.qual.qual = qual;
-+ priv->wstats.qual.updated = 7; /* all 3 indicators updated */
-+#ifdef FROM_SCAN_SOURCE_ONLY
-+ }
-+#endif
-+}
-+
-+
-+/***********************************************************************
-+** acx_i_start_xmit
-+**
-+** Called by network core. Can be called outside of process context.
-+*/
-+int
-+acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ tx_t *tx;
-+ void *txbuf;
-+ unsigned long flags;
-+ int txresult = NOT_OK;
-+ int len;
-+
-+ FN_ENTER;
-+
-+ if (unlikely(!skb)) {
-+ /* indicate success */
-+ txresult = OK;
-+ goto end_no_unlock;
-+ }
-+ if (unlikely(!priv)) {
-+ goto end_no_unlock;
-+ }
-+
-+ acx_lock(priv, flags);
-+
-+ if (unlikely(!(priv->dev_state_mask & ACX_STATE_IFACE_UP))) {
-+ goto end;
-+ }
-+ if (unlikely(priv->mode == ACX_MODE_OFF)) {
-+ goto end;
-+ }
-+ if (unlikely(acx_queue_stopped(dev))) {
-+ acxlog(L_DEBUG, "%s: called when queue stopped\n", __func__);
-+ goto end;
-+ }
-+ if (unlikely(ACX_STATUS_4_ASSOCIATED != priv->status)) {
-+ acxlog(L_XFER, "trying to xmit, but not associated yet: "
-+ "aborting...\n");
-+ /* silently drop the packet, since we're not connected yet */
-+ txresult = OK;
-+ /* ...but indicate an error nevertheless */
-+ priv->stats.tx_errors++;
-+ goto end;
-+ }
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (unlikely(!tx)) {
-+ printk("%s: start_xmit: txdesc ring is full, dropping tx\n",
-+ dev->name);
-+ txresult = NOT_OK;
-+ goto end;
-+ }
-+
-+ txbuf = acx_l_get_txbuf(priv, tx);
-+ if (!txbuf) {
-+ /* Card was removed */
-+ txresult = NOT_OK;
-+ goto end;
-+ }
-+ len = acx_l_ether_to_txbuf(priv, txbuf, skb);
-+ if (len < 0) {
-+ /* Error in packet conversion */
-+ txresult = NOT_OK;
-+ goto end;
-+ }
-+ acx_l_tx_data(priv, tx, len);
-+ dev->trans_start = jiffies;
-+
-+ txresult = OK;
-+ priv->stats.tx_packets++;
-+ priv->stats.tx_bytes += skb->len;
-+
-+end:
-+ acx_unlock(priv, flags);
-+
-+end_no_unlock:
-+ if ((txresult == OK) && skb)
-+ dev_kfree_skb_any(skb);
-+
-+ FN_EXIT1(txresult);
-+ return txresult;
-+}
-+
-+
-+/***********************************************************************
-+** acx_l_update_ratevector
-+**
-+** Updates priv->rate_supported[_len] according to rate_{basic,oper}
-+*/
-+const u8
-+bitpos2ratebyte[] = {
-+ DOT11RATEBYTE_1,
-+ DOT11RATEBYTE_2,
-+ DOT11RATEBYTE_5_5,
-+ DOT11RATEBYTE_6_G,
-+ DOT11RATEBYTE_9_G,
-+ DOT11RATEBYTE_11,
-+ DOT11RATEBYTE_12_G,
-+ DOT11RATEBYTE_18_G,
-+ DOT11RATEBYTE_22,
-+ DOT11RATEBYTE_24_G,
-+ DOT11RATEBYTE_36_G,
-+ DOT11RATEBYTE_48_G,
-+ DOT11RATEBYTE_54_G,
-+};
-+
-+void
-+acx_l_update_ratevector(wlandevice_t *priv)
-+{
-+ u16 bcfg = priv->rate_basic;
-+ u16 ocfg = priv->rate_oper;
-+ u8 *supp = priv->rate_supported;
-+ const u8 *dot11 = bitpos2ratebyte;
-+
-+ FN_ENTER;
-+
-+ while (ocfg) {
-+ if (ocfg & 1) {
-+ *supp = *dot11;
-+ if (bcfg & 1) {
-+ *supp |= 0x80;
-+ }
-+ supp++;
-+ }
-+ dot11++;
-+ ocfg >>= 1;
-+ bcfg >>= 1;
-+ }
-+ priv->rate_supported_len = supp - priv->rate_supported;
-+ if (acx_debug & L_ASSOC) {
-+ printk("new ratevector: ");
-+ acx_dump_bytes(priv->rate_supported, priv->rate_supported_len);
-+ }
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_sta_list_init
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_sta_list_init(wlandevice_t *priv)
-+{
-+ FN_ENTER;
-+ memset(priv->sta_hash_tab, 0, sizeof(priv->sta_hash_tab));
-+ memset(priv->sta_list, 0, sizeof(priv->sta_list));
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_sta_list_get_from_hash
-+*----------------------------------------------------------------*/
-+static inline client_t*
-+acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address)
-+{
-+ return priv->sta_hash_tab[address[5] % VEC_SIZE(priv->sta_hash_tab)];
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_sta_list_get
-+*----------------------------------------------------------------*/
-+client_t*
-+acx_l_sta_list_get(wlandevice_t *priv, const u8 *address)
-+{
-+ client_t *client;
-+ FN_ENTER;
-+ client = acx_l_sta_list_get_from_hash(priv, address);
-+ while (client) {
-+ if (mac_is_equal(address, client->address)) {
-+ client->mtime = jiffies;
-+ break;
-+ }
-+ client = client->next;
-+ }
-+ FN_EXIT0;
-+ return client;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_sta_list_del
-+*----------------------------------------------------------------*/
-+void
-+acx_l_sta_list_del(wlandevice_t *priv, client_t *victim)
-+{
-+ client_t *client, *next;
-+
-+ client = acx_l_sta_list_get_from_hash(priv, victim->address);
-+ next = client;
-+ /* tricky. next = client on first iteration only,
-+ ** on all other iters next = client->next */
-+ while (next) {
-+ if (next == victim) {
-+ client->next = victim->next;
-+ /* Overkill */
-+ memset(victim, 0, sizeof(*victim));
-+ break;
-+ }
-+ client = next;
-+ next = client->next;
-+ }
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_sta_list_alloc
-+*
-+* Never fails - will evict oldest client if needed
-+*----------------------------------------------------------------*/
-+static client_t*
-+acx_l_sta_list_alloc(wlandevice_t *priv)
-+{
-+ int i;
-+ unsigned long age, oldest_age;
-+ client_t *client, *oldest;
-+
-+ FN_ENTER;
-+
-+ oldest = &priv->sta_list[0];
-+ oldest_age = 0;
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ client = &priv->sta_list[i];
-+
-+ if (!client->used) {
-+ goto found;
-+ } else {
-+ age = jiffies - client->mtime;
-+ if (oldest_age < age) {
-+ oldest_age = age;
-+ oldest = client;
-+ }
-+ }
-+ }
-+ acx_l_sta_list_del(priv, oldest);
-+ client = oldest;
-+found:
-+ memset(client, 0, sizeof(*client));
-+ FN_EXIT0;
-+ return client;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_sta_list_add
-+*
-+* Never fails - will evict oldest client if needed
-+*----------------------------------------------------------------*/
-+/* In case we will reimplement it differently... */
-+#define STA_LIST_ADD_CAN_FAIL 0
-+
-+static client_t*
-+acx_l_sta_list_add(wlandevice_t *priv, const u8 *address)
-+{
-+ client_t *client;
-+ int index;
-+
-+ FN_ENTER;
-+
-+ client = acx_l_sta_list_alloc(priv);
-+
-+ client->mtime = jiffies;
-+ MAC_COPY(client->address, address);
-+ client->used = CLIENT_EXIST_1;
-+ client->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
-+ client->auth_step = 1;
-+ /* give some tentative peer rate values
-+ ** (needed because peer may do auth without probing us first,
-+ ** thus we'll have no idea of peer's ratevector yet).
-+ ** Will be overwritten by scanning or assoc code */
-+ client->rate_cap = priv->rate_basic;
-+ client->rate_cfg = priv->rate_basic;
-+ client->rate_cur = 1 << lowest_bit(priv->rate_basic);
-+
-+ index = address[5] % VEC_SIZE(priv->sta_hash_tab);
-+ client->next = priv->sta_hash_tab[index];
-+ priv->sta_hash_tab[index] = client;
-+
-+ acxlog_mac(L_ASSOC, "sta_list_add: sta=", address, "\n");
-+
-+ FN_EXIT0;
-+ return client;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_sta_list_get_or_add
-+*
-+* Never fails - will evict oldest client if needed
-+*----------------------------------------------------------------*/
-+static client_t*
-+acx_l_sta_list_get_or_add(wlandevice_t *priv, const u8 *address)
-+{
-+ client_t *client = acx_l_sta_list_get(priv, address);
-+ if (!client)
-+ client = acx_l_sta_list_add(priv, address);
-+ return client;
-+}
-+
-+
-+/***********************************************************************
-+** acx_set_status
-+**
-+** This function is called in many atomic regions, must not sleep
-+**
-+** This function does not need locking UNLESS you call it
-+** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
-+** wake queue. This can race with stop_queue elsewhere.
-+** See acx_stop_queue comment. */
-+void
-+acx_set_status(wlandevice_t *priv, u16 new_status)
-+{
-+#define QUEUE_OPEN_AFTER_ASSOC 1 /* this really seems to be needed now */
-+ u16 old_status = priv->status;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_ASSOC, "%s(%d):%s\n",
-+ __func__, new_status, acx_get_status_name(new_status));
-+
-+#if WIRELESS_EXT > 13 /* wireless_send_event() and SIOCGIWSCAN */
-+ /* wireless_send_event never sleeps */
-+ if (ACX_STATUS_4_ASSOCIATED == new_status) {
-+ union iwreq_data wrqu;
-+
-+ wrqu.data.length = 0;
-+ wrqu.data.flags = 0;
-+ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
-+
-+ wrqu.data.length = 0;
-+ wrqu.data.flags = 0;
-+ MAC_COPY(wrqu.ap_addr.sa_data, priv->bssid);
-+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
-+ } else {
-+ union iwreq_data wrqu;
-+
-+ /* send event with empty BSSID to indicate we're not associated */
-+ MAC_ZERO(wrqu.ap_addr.sa_data);
-+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-+ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
-+ }
-+#endif
-+
-+ priv->status = new_status;
-+
-+ switch (new_status) {
-+ case ACX_STATUS_1_SCANNING:
-+ priv->scan_retries = 0;
-+ /* 1.0 s initial scan time */
-+ acx_set_timer(priv, 1000000);
-+ break;
-+ case ACX_STATUS_2_WAIT_AUTH:
-+ case ACX_STATUS_3_AUTHENTICATED:
-+ priv->auth_or_assoc_retries = 0;
-+ acx_set_timer(priv, 1500000); /* 1.5 s */
-+ break;
-+ }
-+
-+#if QUEUE_OPEN_AFTER_ASSOC
-+ if (new_status == ACX_STATUS_4_ASSOCIATED) {
-+ if (old_status < ACX_STATUS_4_ASSOCIATED) {
-+ /* ah, we're newly associated now,
-+ * so let's indicate carrier */
-+ acx_carrier_on(priv->netdev, "after association");
-+ acx_wake_queue(priv->netdev, "after association");
-+ }
-+ } else {
-+ /* not associated any more, so let's kill carrier */
-+ if (old_status >= ACX_STATUS_4_ASSOCIATED) {
-+ acx_carrier_off(priv->netdev, "after losing association");
-+ acx_stop_queue(priv->netdev, "after losing association");
-+ }
-+ }
-+#endif
-+ FN_EXIT0;
-+}
-+
-+
-+/*------------------------------------------------------------------------------
-+ * acx_i_timer
-+ *
-+ * Fires up periodically. Used to kick scan/auth/assoc if something goes wrong
-+ *----------------------------------------------------------------------------*/
-+void
-+acx_i_timer(unsigned long address)
-+{
-+ unsigned long flags;
-+ wlandevice_t *priv = (wlandevice_t *)address;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+
-+ acxlog(L_DEBUG|L_ASSOC, "%s: priv->status=%d (%s)\n",
-+ __func__, priv->status, acx_get_status_name(priv->status));
-+
-+ switch (priv->status) {
-+ case ACX_STATUS_1_SCANNING:
-+ /* was set to 0 by set_status() */
-+ if (++priv->scan_retries < 7) {
-+ acx_set_timer(priv, 1000000);
-+ /* used to interrogate for scan status.
-+ ** We rely on SCAN_COMPLETE IRQ instead */
-+ acxlog(L_ASSOC, "continuing scan (%d sec)\n",
-+ priv->scan_retries);
-+ } else {
-+ acxlog(L_ASSOC, "stopping scan\n");
-+ /* send stop_scan cmd when we leave the interrupt context,
-+ * and make a decision what to do next (COMPLETE_SCAN) */
-+ acx_schedule_after_interrupt_task(priv,
-+ ACX_AFTER_IRQ_CMD_STOP_SCAN + ACX_AFTER_IRQ_COMPLETE_SCAN);
-+ }
-+ break;
-+ case ACX_STATUS_2_WAIT_AUTH:
-+ /* was set to 0 by set_status() */
-+ if (++priv->auth_or_assoc_retries < 10) {
-+ acxlog(L_ASSOC, "resend authen1 request (attempt %d)\n",
-+ priv->auth_or_assoc_retries + 1);
-+ acx_l_transmit_authen1(priv);
-+ } else {
-+ /* time exceeded: fall back to scanning mode */
-+ acxlog(L_ASSOC,
-+ "authen1 request reply timeout, giving up\n");
-+ /* we are a STA, need to find AP anyhow */
-+ acx_set_status(priv, ACX_STATUS_1_SCANNING);
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
-+ }
-+ /* used to be 1500000, but some other driver uses 2.5s */
-+ acx_set_timer(priv, 2500000);
-+ break;
-+ case ACX_STATUS_3_AUTHENTICATED:
-+ /* was set to 0 by set_status() */
-+ if (++priv->auth_or_assoc_retries < 10) {
-+ acxlog(L_ASSOC, "resend assoc request (attempt %d)\n",
-+ priv->auth_or_assoc_retries + 1);
-+ acx_l_transmit_assoc_req(priv);
-+ } else {
-+ /* time exceeded: give up */
-+ acxlog(L_ASSOC,
-+ "association request reply timeout, giving up\n");
-+ /* we are a STA, need to find AP anyhow */
-+ acx_set_status(priv, ACX_STATUS_1_SCANNING);
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
-+ }
-+ acx_set_timer(priv, 2500000); /* see above */
-+ break;
-+ case ACX_STATUS_4_ASSOCIATED:
-+ default:
-+ break;
-+ }
-+
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*------------------------------------------------------------------------------
-+ * acx_set_timer
-+ *
-+ * Sets the 802.11 state management timer's timeout.
-+ *----------------------------------------------------------------------------*/
-+void
-+acx_set_timer(wlandevice_t *priv, int timeout_us)
-+{
-+ FN_ENTER;
-+
-+ acxlog(L_DEBUG|L_IRQ, "%s(%u ms)\n", __func__, timeout_us/1000);
-+ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
-+ printk("attempt to set the timer "
-+ "when the card interface is not up!\n");
-+ goto end;
-+ }
-+
-+ /* first check if the timer was already initialized, THEN modify it */
-+ if (priv->mgmt_timer.function) {
-+ mod_timer(&priv->mgmt_timer,
-+ jiffies + (timeout_us * HZ / 1000000));
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_assocresp
-+*
-+* We are an AP here
-+*----------------------------------------------------------------*/
-+static const u8
-+dot11ratebyte[] = {
-+ DOT11RATEBYTE_1,
-+ DOT11RATEBYTE_2,
-+ DOT11RATEBYTE_5_5,
-+ DOT11RATEBYTE_6_G,
-+ DOT11RATEBYTE_9_G,
-+ DOT11RATEBYTE_11,
-+ DOT11RATEBYTE_12_G,
-+ DOT11RATEBYTE_18_G,
-+ DOT11RATEBYTE_22,
-+ DOT11RATEBYTE_24_G,
-+ DOT11RATEBYTE_36_G,
-+ DOT11RATEBYTE_48_G,
-+ DOT11RATEBYTE_54_G,
-+};
-+
-+static int
-+find_pos(const u8 *p, int size, u8 v)
-+{
-+ int i;
-+ for (i = 0; i < size; i++)
-+ if (p[i] == v)
-+ return i;
-+ /* printk a message about strange byte? */
-+ return 0;
-+}
-+
-+static void
-+add_bits_to_ratemasks(u8* ratevec, int len, u16* brate, u16* orate)
-+{
-+ while (len--) {
-+ int n = 1 << find_pos(dot11ratebyte,
-+ sizeof(dot11ratebyte), *ratevec & 0x7f);
-+ if (*ratevec & 0x80)
-+ *brate |= n;
-+ *orate |= n;
-+ ratevec++;
-+ }
-+}
-+
-+static int
-+acx_l_transmit_assocresp(wlandevice_t *priv, const wlan_fr_assocreq_t *req)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct assocresp_frame_body *body;
-+ u8 *p;
-+ const u8 *da;
-+ /* const u8 *sa; */
-+ const u8 *bssid;
-+ client_t *clt;
-+
-+ FN_ENTER;
-+
-+ /* sa = req->hdr->a1; */
-+ da = req->hdr->a2;
-+ bssid = req->hdr->a3;
-+
-+ clt = acx_l_sta_list_get(priv, da);
-+ if (!clt)
-+ goto ok;
-+
-+ /* Assoc without auth is a big no-no */
-+ /* Let's be liberal: if already assoc'ed STA sends assoc req again,
-+ ** we won't be rude */
-+ if (clt->used != CLIENT_AUTHENTICATED_2
-+ && clt->used != CLIENT_ASSOCIATED_3) {
-+ acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
-+ goto bad;
-+ }
-+
-+ clt->used = CLIENT_ASSOCIATED_3;
-+
-+ if (clt->aid == 0) {
-+ clt->aid = ++priv->aid;
-+ }
-+ clt->cap_info = ieee2host16(*(req->cap_info));
-+ /* We cheat here a bit. We don't really care which rates are flagged
-+ ** as basic by the client, so we stuff them in single ratemask */
-+ clt->rate_cap = 0;
-+ if (req->supp_rates)
-+ add_bits_to_ratemasks(req->supp_rates->rates,
-+ req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
-+ if (req->ext_rates)
-+ add_bits_to_ratemasks(req->ext_rates->rates,
-+ req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
-+ /* We can check that client supports all basic rates,
-+ ** and deny assoc if not. But let's be liberal, right? ;) */
-+ clt->rate_cfg = clt->rate_cap & priv->rate_oper;
-+ if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
-+ clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
-+ clt->fallback_count = clt->stepup_count = 0;
-+ clt->ignore_count = 16;
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto bad;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto bad;
-+ body = (void*)(head + 1);
-+
-+ head->fc = WF_FSTYPE_ASSOCRESPi;
-+ head->dur = req->hdr->dur;
-+ MAC_COPY(head->da, da);
-+ /* MAC_COPY(head->sa, sa); */
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, bssid);
-+ head->seq = req->hdr->seq;
-+
-+ body->cap_info = host2ieee16(priv->capabilities);
-+ body->status = host2ieee16(0);
-+ body->aid = host2ieee16(clt->aid);
-+ p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
-+ priv->rate_supported);
-+ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
-+ priv->rate_supported);
-+
-+ acx_l_tx_data(priv, tx, p - (u8*)head);
-+ok:
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_reassocresp
-+
-+You may be wondering, just like me, what a hell is ReAuth.
-+In practice it was seen sent by STA when STA feels like losing connection.
-+
-+[802.11]
-+
-+5.4.2.3 Reassociation
-+
-+Association is sufficient for no-transition message delivery between
-+IEEE 802.11 stations. Additional functionality is needed to support
-+BSS-transition mobility. The additional required functionality
-+is provided by the reassociation service. Reassociation is a DSS.
-+The reassociation service is invoked to 'move' a current association
-+from one AP to another. This keeps the DS informed of the current
-+mapping between AP and STA as the station moves from BSS to BSS within
-+an ESS. Reassociation also enables changing association attributes
-+of an established association while the STA remains associated with
-+the same AP. Reassociation is always initiated by the mobile STA.
-+
-+5.4.3.1 Authentication
-+...
-+A STA may be authenticated with many other STAs at any given instant.
-+
-+5.4.3.1.1 Preauthentication
-+
-+Because the authentication process could be time-consuming (depending
-+on the authentication protocol in use), the authentication service can
-+be invoked independently of the association service. Preauthentication
-+is typically done by a STA while it is already associated with an AP
-+(with which it previously authenticated). IEEE 802.11 does not require
-+that STAs preauthenticate with APs. However, authentication is required
-+before an association can be established. If the authentication is left
-+until reassociation time, this may impact the speed with which a STA can
-+reassociate between APs, limiting BSS-transition mobility performance.
-+The use of preauthentication takes the authentication service overhead
-+out of the time-critical reassociation process.
-+
-+5.7.3 Reassociation
-+
-+For a STA to reassociate, the reassociation service causes the following
-+message to occur:
-+
-+ Reassociation request
-+
-+* Message type: Management
-+* Message subtype: Reassociation request
-+* Information items:
-+ - IEEE address of the STA
-+ - IEEE address of the AP with which the STA will reassociate
-+ - IEEE address of the AP with which the STA is currently associated
-+ - ESSID
-+* Direction of message: From STA to 'new' AP
-+
-+The address of the current AP is included for efficiency. The inclusion
-+of the current AP address facilitates MAC reassociation to be independent
-+of the DS implementation.
-+
-+ Reassociation response
-+* Message type: Management
-+* Message subtype: Reassociation response
-+* Information items:
-+ - Result of the requested reassociation. (success/failure)
-+ - If the reassociation is successful, the response shall include the AID.
-+* Direction of message: From AP to STA
-+
-+7.2.3.6 Reassociation Request frame format
-+
-+The frame body of a management frame of subtype Reassociation Request
-+contains the information shown in Table 9.
-+
-+Table 9 Reassociation Request frame body
-+Order Information
-+1 Capability information
-+2 Listen interval
-+3 Current AP address
-+4 SSID
-+5 Supported rates
-+
-+7.2.3.7 Reassociation Response frame format
-+
-+The frame body of a management frame of subtype Reassociation Response
-+contains the information shown in Table 10.
-+
-+Table 10 Reassociation Response frame body
-+Order Information
-+1 Capability information
-+2 Status code
-+3 Association ID (AID)
-+4 Supported rates
-+
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_transmit_reassocresp(wlandevice_t *priv, const wlan_fr_reassocreq_t *req)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct reassocresp_frame_body *body;
-+ u8 *p;
-+ const u8 *da;
-+ /* const u8 *sa; */
-+ const u8 *bssid;
-+ client_t *clt;
-+
-+ FN_ENTER;
-+
-+ /* sa = req->hdr->a1; */
-+ da = req->hdr->a2;
-+ bssid = req->hdr->a3;
-+
-+ /* Must be already authenticated, so it must be in the list */
-+ clt = acx_l_sta_list_get(priv, da);
-+ if (!clt)
-+ goto ok;
-+
-+ /* Assoc without auth is a big no-no */
-+ /* Already assoc'ed STAs sending ReAssoc req are ok per 802.11 */
-+ if (clt->used != CLIENT_AUTHENTICATED_2
-+ && clt->used != CLIENT_ASSOCIATED_3) {
-+ acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
-+ goto bad;
-+ }
-+
-+ clt->used = CLIENT_ASSOCIATED_3;
-+ if (clt->aid == 0) {
-+ clt->aid = ++priv->aid;
-+ }
-+ if (req->cap_info)
-+ clt->cap_info = ieee2host16(*(req->cap_info));
-+ /* We cheat here a bit. We don't really care which rates are flagged
-+ ** as basic by the client, so we stuff them in single ratemask */
-+ clt->rate_cap = 0;
-+ if (req->supp_rates)
-+ add_bits_to_ratemasks(req->supp_rates->rates,
-+ req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
-+ if (req->ext_rates)
-+ add_bits_to_ratemasks(req->ext_rates->rates,
-+ req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
-+ /* We can check that client supports all basic rates,
-+ ** and deny assoc if not. But let's be liberal, right? ;) */
-+ clt->rate_cfg = clt->rate_cap & priv->rate_oper;
-+ if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
-+ clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
-+ clt->fallback_count = clt->stepup_count = 0;
-+ clt->ignore_count = 16;
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto ok;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto ok;
-+ body = (void*)(head + 1);
-+
-+ head->fc = WF_FSTYPE_REASSOCRESPi;
-+ head->dur = req->hdr->dur;
-+ MAC_COPY(head->da, da);
-+ /* MAC_COPY(head->sa, sa); */
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, bssid);
-+ head->seq = req->hdr->seq;
-+
-+ /* IEs: 1. caps */
-+ body->cap_info = host2ieee16(priv->capabilities);
-+ /* 2. status code */
-+ body->status = host2ieee16(0);
-+ /* 3. AID */
-+ body->aid = host2ieee16(clt->aid);
-+ /* 4. supp rates */
-+ p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
-+ priv->rate_supported);
-+ /* 5. ext supp rates */
-+ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
-+ priv->rate_supported);
-+
-+ acx_l_tx_data(priv, tx, p - (u8*)head);
-+ok:
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_disassoc_from_sta
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_process_disassoc_from_sta(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
-+{
-+ const u8 *ta;
-+ client_t *clt;
-+
-+ FN_ENTER;
-+
-+ ta = req->hdr->a2;
-+ clt = acx_l_sta_list_get(priv, ta);
-+ if (!clt)
-+ goto end;
-+
-+ if (clt->used != CLIENT_ASSOCIATED_3
-+ && clt->used != CLIENT_AUTHENTICATED_2) {
-+ /* it's disassociating, but it's
-+ ** not even authenticated! Let it know that */
-+ acxlog_mac(L_ASSOC|L_XFER, "peer ", ta, "has sent disassoc "
-+ "req but it is not even auth'ed! sending deauth\n");
-+ acx_l_transmit_deauthen(priv, ta,
-+ WLAN_MGMT_REASON_CLASS2_NONAUTH);
-+ clt->used = CLIENT_EXIST_1;
-+ } else {
-+ /* mark it as auth'ed only */
-+ clt->used = CLIENT_AUTHENTICATED_2;
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_deauthen_from_sta
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_process_deauth_from_sta(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
-+{
-+ const wlan_hdr_t *hdr;
-+ client_t *client;
-+
-+ FN_ENTER;
-+
-+ hdr = req->hdr;
-+
-+ if (acx_debug & L_ASSOC) {
-+ acx_print_mac("DEAUTHEN priv->addr=", priv->dev_addr, " ");
-+ acx_print_mac("a1", hdr->a1, " ");
-+ acx_print_mac("a2", hdr->a2, " ");
-+ acx_print_mac("a3", hdr->a3, " ");
-+ acx_print_mac("priv->bssid", priv->bssid, "\n");
-+ }
-+
-+ if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
-+ goto end;
-+ }
-+
-+ acxlog_mac(L_DEBUG, "STA ", hdr->a2, " sent us deauthen packet\n");
-+
-+ client = acx_l_sta_list_get(priv, hdr->a2);
-+ if (!client) {
-+ goto end;
-+ }
-+ client->used = CLIENT_EXIST_1;
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_disassoc_from_ap
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_process_disassoc_from_ap(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
-+{
-+ FN_ENTER;
-+
-+ if (!priv->ap_client) {
-+ /* Hrm, we aren't assoc'ed yet anyhow... */
-+ goto end;
-+ }
-+ if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
-+ acx_l_transmit_deauthen(priv, priv->bssid,
-+ WLAN_MGMT_REASON_DEAUTH_LEAVING);
-+ /* Start scan anew */
-+ SET_BIT(priv->set_mask, GETSET_RESCAN);
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_deauth_from_ap
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_process_deauth_from_ap(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
-+{
-+ FN_ENTER;
-+
-+ if (!priv->ap_client) {
-+ /* Hrm, we aren't assoc'ed yet anyhow... */
-+ goto end;
-+ }
-+ /* Chk: is ta is verified to be from our AP? */
-+ if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
-+ acxlog(L_DEBUG, "AP sent us deauth packet\n");
-+ /* not needed: acx_set_status(priv, ACX_STATUS_1_SCANNING) */
-+ SET_BIT(priv->set_mask, GETSET_RESCAN);
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/*------------------------------------------------------------------------------
-+ * acx_l_rx
-+ *
-+ * The end of the Rx path. Pulls data from a rxhostdesc into a socket
-+ * buffer and feeds it to the network stack via netif_rx().
-+ *
-+ * Arguments:
-+ * rxdesc: the rxhostdesc to pull the data from
-+ * priv: the acx100 private struct of the interface
-+ *----------------------------------------------------------------------------*/
-+static void
-+acx_l_rx(wlandevice_t *priv, rxbuffer_t *rxbuf)
-+{
-+ FN_ENTER;
-+ if (likely(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
-+ struct sk_buff *skb;
-+ skb = acx_rxbuf_to_ether(priv, rxbuf);
-+ if (likely(skb)) {
-+ netif_rx(skb);
-+ priv->netdev->last_rx = jiffies;
-+ priv->stats.rx_packets++;
-+ priv->stats.rx_bytes += skb->len;
-+ }
-+ }
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_data_frame_master
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_process_data_frame_master(wlandevice_t *priv, rxbuffer_t *rxbuf)
-+{
-+ struct wlan_hdr *hdr;
-+ struct tx *tx;
-+ void *txbuf;
-+ int len;
-+ int result = NOT_OK;
-+
-+ FN_ENTER;
-+
-+ hdr = acx_get_wlan_hdr(priv, rxbuf);
-+
-+ switch (WF_FC_FROMTODSi & hdr->fc) {
-+ case 0:
-+ case WF_FC_FROMDSi:
-+ acxlog(L_DEBUG, "ap->sta or adhoc->adhoc data frame ignored\n");
-+ goto done;
-+ case WF_FC_TODSi:
-+ break;
-+ default: /* WF_FC_FROMTODSi */
-+ acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
-+ goto done;
-+ }
-+
-+ /* check if it is our BSSID, if not, leave */
-+ if (!mac_is_equal(priv->bssid, hdr->a1)) {
-+ goto done;
-+ }
-+
-+ if (mac_is_equal(priv->dev_addr, hdr->a3)) {
-+ /* this one is for us */
-+ acx_l_rx(priv, rxbuf);
-+ } else {
-+ if (mac_is_bcast(hdr->a3)) {
-+ /* this one is bcast, rx it too */
-+ acx_l_rx(priv, rxbuf);
-+ }
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx) {
-+ goto fail;
-+ }
-+ /* repackage, tx, and hope it someday reaches its destination */
-+ /* order is important, we do it in-place */
-+ MAC_COPY(hdr->a1, hdr->a3);
-+ MAC_COPY(hdr->a3, hdr->a2);
-+ MAC_COPY(hdr->a2, priv->bssid);
-+ /* To_DS = 0, From_DS = 1 */
-+ hdr->fc = WF_FC_FROMDSi + WF_FTYPE_DATAi;
-+
-+ len = RXBUF_BYTES_RCVD(rxbuf);
-+ txbuf = acx_l_get_txbuf(priv, tx);
-+ if (txbuf) {
-+ memcpy(txbuf, &rxbuf->hdr_a3, len);
-+ acx_l_tx_data(priv, tx, len);
-+ }
-+ }
-+done:
-+ result = OK;
-+fail:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_data_frame_client
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_process_data_frame_client(wlandevice_t *priv, rxbuffer_t *rxbuf)
-+{
-+ const u8 *da, *bssid;
-+ const wlan_hdr_t *hdr;
-+ netdevice_t *dev = priv->netdev;
-+ int result = NOT_OK;
-+
-+ FN_ENTER;
-+
-+ if (ACX_STATUS_4_ASSOCIATED != priv->status)
-+ goto drop;
-+
-+ hdr = acx_get_wlan_hdr(priv, rxbuf);
-+
-+ switch (WF_FC_FROMTODSi & hdr->fc) {
-+ case 0:
-+ if (priv->mode != ACX_MODE_0_ADHOC) {
-+ acxlog(L_DEBUG, "adhoc->adhoc data frame ignored\n");
-+ goto drop;
-+ }
-+ bssid = hdr->a3;
-+ break;
-+ case WF_FC_FROMDSi:
-+ if (priv->mode != ACX_MODE_2_STA) {
-+ acxlog(L_DEBUG, "ap->sta data frame ignored\n");
-+ goto drop;
-+ }
-+ bssid = hdr->a2;
-+ break;
-+ case WF_FC_TODSi:
-+ acxlog(L_DEBUG, "sta->ap data frame ignored\n");
-+ goto drop;
-+ default: /* WF_FC_FROMTODSi: wds->wds */
-+ acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
-+ goto drop;
-+ }
-+
-+ da = hdr->a1;
-+
-+ if (unlikely(acx_debug & L_DEBUG)) {
-+ acx_print_mac("rx: da=", da, "");
-+ acx_print_mac(" bssid=", bssid, "");
-+ acx_print_mac(" priv->bssid=", priv->bssid, "");
-+ acx_print_mac(" priv->addr=", priv->dev_addr, "\n");
-+ }
-+
-+ /* promiscuous mode --> receive all packets */
-+ if (unlikely(dev->flags & IFF_PROMISC))
-+ goto process;
-+
-+ /* FIRST, check if it is our BSSID */
-+ if (!mac_is_equal(priv->bssid, bssid)) {
-+ /* is not our BSSID, so bail out */
-+ goto drop;
-+ }
-+
-+ /* then, check if it is our address */
-+ if (mac_is_equal(priv->dev_addr, da)) {
-+ goto process;
-+ }
-+
-+ /* then, check if it is broadcast */
-+ if (mac_is_bcast(da)) {
-+ goto process;
-+ }
-+
-+ if (mac_is_mcast(da)) {
-+ /* unconditionally receive all multicasts */
-+ if (dev->flags & IFF_ALLMULTI)
-+ goto process;
-+
-+ /* FIXME: check against the list of
-+ * multicast addresses that are configured
-+ * for the interface (ifconfig) */
-+ acxlog(L_XFER, "FIXME: multicast packet, need to check "
-+ "against a list of multicast addresses "
-+ "(to be created!); accepting packet for now\n");
-+ /* for now, just accept it here */
-+ goto process;
-+ }
-+
-+ acxlog(L_DEBUG, "rx: foreign packet, dropping\n");
-+ goto drop;
-+process:
-+ /* receive packet */
-+ acx_l_rx(priv, rxbuf);
-+
-+ result = OK;
-+drop:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_mgmt_frame
-+*
-+* Theory of operation: mgmt packet gets parsed (to make it easy
-+* to access variable-sized IEs), results stored in 'parsed'.
-+* Then we react to the packet.
-+* NB: wlan_mgmt_decode_XXX are dev-independent (shoudnt have been named acx_XXX)
-+*----------------------------------------------------------------*/
-+typedef union parsed_mgmt_req {
-+ wlan_fr_mgmt_t mgmt;
-+ wlan_fr_assocreq_t assocreq;
-+ wlan_fr_reassocreq_t reassocreq;
-+ wlan_fr_assocresp_t assocresp;
-+ wlan_fr_reassocresp_t reassocresp;
-+ wlan_fr_beacon_t beacon;
-+ wlan_fr_disassoc_t disassoc;
-+ wlan_fr_authen_t authen;
-+ wlan_fr_deauthen_t deauthen;
-+ wlan_fr_proberesp_t proberesp;
-+} parsed_mgmt_req_t;
-+
-+void BUG_excessive_stack_usage(void);
-+
-+static int
-+acx_l_process_mgmt_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
-+{
-+ parsed_mgmt_req_t parsed; /* takes ~100 bytes of stack */
-+ wlan_hdr_t *hdr;
-+ int adhoc, sta_scan, sta, ap;
-+ int len;
-+
-+ if (sizeof(parsed) > 256)
-+ BUG_excessive_stack_usage();
-+
-+ FN_ENTER;
-+
-+ hdr = acx_get_wlan_hdr(priv, rxbuf);
-+
-+ /* Management frames never have these set */
-+ if (WF_FC_FROMTODSi & hdr->fc) {
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+ }
-+
-+ len = RXBUF_BYTES_RCVD(rxbuf);
-+ if (WF_FC_ISWEPi & hdr->fc)
-+ len -= 0x10;
-+
-+ adhoc = (priv->mode == ACX_MODE_0_ADHOC);
-+ sta_scan = ((priv->mode == ACX_MODE_2_STA)
-+ && (priv->status != ACX_STATUS_4_ASSOCIATED));
-+ sta = ((priv->mode == ACX_MODE_2_STA)
-+ && (priv->status == ACX_STATUS_4_ASSOCIATED));
-+ ap = (priv->mode == ACX_MODE_3_AP);
-+
-+ switch (WF_FC_FSTYPEi & hdr->fc) {
-+ /* beacons first, for speed */
-+ case WF_FSTYPE_BEACONi:
-+ memset(&parsed.beacon, 0, sizeof(parsed.beacon));
-+ parsed.beacon.hdr = hdr;
-+ parsed.beacon.len = len;
-+ if (acx_debug & L_DATA) {
-+ printk("beacon len:%d fc:%04X dur:%04X seq:%04X",
-+ len, hdr->fc, hdr->dur, hdr->seq);
-+ acx_print_mac(" a1:", hdr->a1, "");
-+ acx_print_mac(" a2:", hdr->a2, "");
-+ acx_print_mac(" a3:", hdr->a3, "\n");
-+ }
-+ wlan_mgmt_decode_beacon(&parsed.beacon);
-+ /* beacon and probe response are very similar, so... */
-+ acx_l_process_probe_response(priv, &parsed.beacon, rxbuf);
-+ break;
-+ case WF_FSTYPE_ASSOCREQi:
-+ if (!ap)
-+ break;
-+ memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
-+ parsed.assocreq.hdr = hdr;
-+ parsed.assocreq.len = len;
-+ wlan_mgmt_decode_assocreq(&parsed.assocreq);
-+ if (mac_is_equal(hdr->a1, priv->bssid)
-+ && mac_is_equal(hdr->a3, priv->bssid)) {
-+ acx_l_transmit_assocresp(priv, &parsed.assocreq);
-+ }
-+ break;
-+ case WF_FSTYPE_REASSOCREQi:
-+ if (!ap)
-+ break;
-+ memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
-+ parsed.assocreq.hdr = hdr;
-+ parsed.assocreq.len = len;
-+ wlan_mgmt_decode_assocreq(&parsed.assocreq);
-+ /* reassocreq and assocreq are equivalent */
-+ acx_l_transmit_reassocresp(priv, &parsed.reassocreq);
-+ break;
-+ case WF_FSTYPE_ASSOCRESPi:
-+ if (!sta_scan)
-+ break;
-+ memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
-+ parsed.assocresp.hdr = hdr;
-+ parsed.assocresp.len = len;
-+ wlan_mgmt_decode_assocresp(&parsed.assocresp);
-+ acx_l_process_assocresp(priv, &parsed.assocresp);
-+ break;
-+ case WF_FSTYPE_REASSOCRESPi:
-+ if (!sta_scan)
-+ break;
-+ memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
-+ parsed.assocresp.hdr = hdr;
-+ parsed.assocresp.len = len;
-+ wlan_mgmt_decode_assocresp(&parsed.assocresp);
-+ acx_l_process_reassocresp(priv, &parsed.reassocresp);
-+ break;
-+ case WF_FSTYPE_PROBEREQi:
-+ if (ap || adhoc) {
-+ /* FIXME: since we're supposed to be an AP,
-+ ** we need to return a Probe Response packet.
-+ ** Currently firmware is doing it for us,
-+ ** but firmware is buggy! See comment elsewhere --vda */
-+ }
-+ break;
-+ case WF_FSTYPE_PROBERESPi:
-+ memset(&parsed.proberesp, 0, sizeof(parsed.proberesp));
-+ parsed.proberesp.hdr = hdr;
-+ parsed.proberesp.len = len;
-+ wlan_mgmt_decode_proberesp(&parsed.proberesp);
-+ acx_l_process_probe_response(priv, &parsed.proberesp, rxbuf);
-+ break;
-+ case 6:
-+ case 7:
-+ /* exit */
-+ break;
-+ case WF_FSTYPE_ATIMi:
-+ /* exit */
-+ break;
-+ case WF_FSTYPE_DISASSOCi:
-+ if (!sta && !ap)
-+ break;
-+ memset(&parsed.disassoc, 0, sizeof(parsed.disassoc));
-+ parsed.disassoc.hdr = hdr;
-+ parsed.disassoc.len = len;
-+ wlan_mgmt_decode_disassoc(&parsed.disassoc);
-+ if (sta)
-+ acx_l_process_disassoc_from_ap(priv, &parsed.disassoc);
-+ else
-+ acx_l_process_disassoc_from_sta(priv, &parsed.disassoc);
-+ break;
-+ case WF_FSTYPE_AUTHENi:
-+ if (!sta_scan && !ap)
-+ break;
-+ memset(&parsed.authen, 0, sizeof(parsed.authen));
-+ parsed.authen.hdr = hdr;
-+ parsed.authen.len = len;
-+ wlan_mgmt_decode_authen(&parsed.authen);
-+ acx_l_process_authen(priv, &parsed.authen);
-+ break;
-+ case WF_FSTYPE_DEAUTHENi:
-+ if (!sta && !ap)
-+ break;
-+ memset(&parsed.deauthen, 0, sizeof(parsed.deauthen));
-+ parsed.deauthen.hdr = hdr;
-+ parsed.deauthen.len = len;
-+ wlan_mgmt_decode_deauthen(&parsed.deauthen);
-+ if (sta)
-+ acx_l_process_deauth_from_ap(priv, &parsed.deauthen);
-+ else
-+ acx_l_process_deauth_from_sta(priv, &parsed.deauthen);
-+ break;
-+ }
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+#ifdef UNUSED
-+/*----------------------------------------------------------------
-+* acx_process_class_frame
-+*
-+* Called from IRQ context only
-+*----------------------------------------------------------------*/
-+static int
-+acx_process_class_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
-+{
-+ return OK;
-+}
-+#endif
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_NULL_frame
-+*----------------------------------------------------------------*/
-+#ifdef BOGUS_ITS_NOT_A_NULL_FRAME_HANDLER_AT_ALL
-+static int
-+acx_l_process_NULL_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
-+{
-+ const signed char *esi;
-+ const u8 *ebx;
-+ const wlan_hdr_t *hdr;
-+ const client_t *client;
-+ int result = NOT_OK;
-+
-+ hdr = acx_get_wlan_hdr(priv, rxbuf);
-+
-+ switch (WF_FC_FROMTODSi & hdr->fc) {
-+ case 0:
-+ esi = hdr->a1;
-+ ebx = hdr->a2;
-+ break;
-+ case WF_FC_FROMDSi:
-+ esi = hdr->a1;
-+ ebx = hdr->a3;
-+ break;
-+ case WF_FC_TODSi:
-+ esi = hdr->a1;
-+ ebx = hdr->a2;
-+ break;
-+ default: /* WF_FC_FROMTODSi */
-+ esi = hdr->a1; /* added by me! --vda */
-+ ebx = hdr->a2;
-+ }
-+
-+ if (esi[0x0] < 0) {
-+ result = OK;
-+ goto done;
-+ }
-+
-+ client = acx_l_sta_list_get(priv, ebx);
-+ if (client)
-+ result = NOT_OK;
-+ else {
-+#ifdef IS_IT_BROKEN
-+ acxlog(L_DEBUG|L_XFER, "<transmit_deauth 7>\n");
-+ acx_l_transmit_deauthen(priv, ebx,
-+ WLAN_MGMT_REASON_CLASS2_NONAUTH);
-+#else
-+ acxlog(L_DEBUG, "received NULL frame from unknown client! "
-+ "We really shouldn't send deauthen here, right?\n");
-+#endif
-+ result = OK;
-+ }
-+done:
-+ return result;
-+}
-+#endif
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_probe_response
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_process_probe_response(wlandevice_t *priv, wlan_fr_proberesp_t *req,
-+ const rxbuffer_t *rxbuf)
-+{
-+ struct client *bss;
-+ wlan_hdr_t *hdr;
-+
-+ FN_ENTER;
-+
-+ hdr = req->hdr;
-+
-+ if (mac_is_equal(hdr->a3, priv->dev_addr)) {
-+ acxlog(L_ASSOC, "huh, scan found our own MAC!?\n");
-+ goto ok; /* just skip this one silently */
-+ }
-+
-+ bss = acx_l_sta_list_get_or_add(priv, hdr->a2);
-+
-+ /* NB: be careful modifying bss data! It may be one
-+ ** of already known clients (like our AP is we are a STA)
-+ ** Thus do not blindly modify e.g. current ratemask! */
-+
-+ if (STA_LIST_ADD_CAN_FAIL && !bss) {
-+ /* uh oh, we found more sites/stations than we can handle with
-+ * our current setup: pull the emergency brake and stop scanning! */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_STOP_SCAN);
-+ /* TODO: a nice comment what below call achieves --vda */
-+ acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
-+ goto ok;
-+ }
-+ /* NB: get_or_add already filled bss->address = hdr->a2 */
-+ MAC_COPY(bss->bssid, hdr->a3);
-+
-+ /* copy the ESSID element */
-+ if (req->ssid && req->ssid->len <= IW_ESSID_MAX_SIZE) {
-+ bss->essid_len = req->ssid->len;
-+ memcpy(bss->essid, req->ssid->ssid, req->ssid->len);
-+ bss->essid[req->ssid->len] = '\0';
-+ } else {
-+ /* Either no ESSID IE or oversized one */
-+ printk("%s: received packet has bogus ESSID\n",
-+ priv->netdev->name);
-+ }
-+
-+ if (req->ds_parms)
-+ bss->channel = req->ds_parms->curr_ch;
-+ if (req->cap_info)
-+ bss->cap_info = ieee2host16(*req->cap_info);
-+
-+ bss->sir = acx_signal_to_winlevel(rxbuf->phy_level);
-+ bss->snr = acx_signal_to_winlevel(rxbuf->phy_snr);
-+
-+ bss->rate_cap = 0; /* operational mask */
-+ bss->rate_bas = 0; /* basic mask */
-+ if (req->supp_rates)
-+ add_bits_to_ratemasks(req->supp_rates->rates,
-+ req->supp_rates->len, &bss->rate_bas, &bss->rate_cap);
-+ if (req->ext_rates)
-+ add_bits_to_ratemasks(req->ext_rates->rates,
-+ req->ext_rates->len, &bss->rate_bas, &bss->rate_cap);
-+ /* Fix up any possible bogosity - code elsewhere
-+ * is not expecting empty masks */
-+ if (!bss->rate_cap)
-+ bss->rate_cap = priv->rate_basic;
-+ if (!bss->rate_bas)
-+ bss->rate_bas = 1 << lowest_bit(bss->rate_cap);
-+ if (!bss->rate_cur)
-+ bss->rate_cur = 1 << lowest_bit(bss->rate_bas);
-+
-+ /* People moan about this being too noisy at L_ASSOC */
-+ acxlog(L_DEBUG,
-+ "found %s: ESSID='%s' ch=%d "
-+ "BSSID="MACSTR" caps=0x%04X SIR=%d SNR=%d\n",
-+ (bss->cap_info & WF_MGMT_CAP_IBSS) ? "Ad-Hoc peer" : "AP",
-+ bss->essid, bss->channel, MAC(bss->bssid), bss->cap_info,
-+ bss->sir, bss->snr);
-+ok:
-+ FN_EXIT0;
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_assocresp
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_process_assocresp(wlandevice_t *priv, const wlan_fr_assocresp_t *req)
-+{
-+ const wlan_hdr_t *hdr;
-+ int res = OK;
-+
-+ FN_ENTER;
-+ hdr = req->hdr;
-+
-+ if ((ACX_MODE_2_STA == priv->mode)
-+ && mac_is_equal(priv->dev_addr, hdr->a1)) {
-+ u16 st = ieee2host16(*(req->status));
-+ if (WLAN_MGMT_STATUS_SUCCESS == st) {
-+ priv->aid = ieee2host16(*(req->aid));
-+ /* tell the card we are associated when we are out of interrupt context */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_ASSOCIATE);
-+ } else {
-+
-+ /* TODO: we shall delete peer from sta_list, and try other candidates... */
-+
-+ printk("%s: association FAILED: peer sent "
-+ "response code %d (%s)\n",
-+ priv->netdev->name, st, get_status_string(st));
-+ res = NOT_OK;
-+ }
-+ }
-+
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_reassocresp
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_process_reassocresp(wlandevice_t *priv, const wlan_fr_reassocresp_t *req)
-+{
-+ const wlan_hdr_t *hdr;
-+ int result = NOT_OK;
-+ u16 st;
-+
-+ FN_ENTER;
-+ hdr = req->hdr;
-+
-+ if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
-+ goto end;
-+ }
-+ st = ieee2host16(*(req->status));
-+ if (st == WLAN_MGMT_STATUS_SUCCESS) {
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-+ result = OK;
-+ } else {
-+ printk("%s: reassociation FAILED: peer sent "
-+ "response code %d (%s)\n",
-+ priv->netdev->name, st, get_status_string(st));
-+ }
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_process_authen
-+*
-+* Called only in STA_SCAN or AP mode
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_process_authen(wlandevice_t *priv, const wlan_fr_authen_t *req)
-+{
-+ const wlan_hdr_t *hdr;
-+ client_t *clt;
-+ wlan_ie_challenge_t *chal;
-+ u16 alg, seq, status;
-+ int ap, result;
-+
-+ FN_ENTER;
-+
-+ hdr = req->hdr;
-+
-+ if (acx_debug & L_ASSOC) {
-+ acx_print_mac("AUTHEN priv->addr=", priv->dev_addr, " ");
-+ acx_print_mac("a1=", hdr->a1, " ");
-+ acx_print_mac("a2=", hdr->a2, " ");
-+ acx_print_mac("a3=", hdr->a3, " ");
-+ acx_print_mac("priv->bssid=", priv->bssid, "\n");
-+ }
-+
-+ if (!mac_is_equal(priv->dev_addr, hdr->a1)
-+ || !mac_is_equal(priv->bssid, hdr->a3)) {
-+ result = OK;
-+ goto end;
-+ }
-+
-+ alg = ieee2host16(*(req->auth_alg));
-+ seq = ieee2host16(*(req->auth_seq));
-+ status = ieee2host16(*(req->status));
-+
-+ ap = (priv->mode == ACX_MODE_3_AP);
-+
-+ if (priv->auth_alg <= 1) {
-+ if (priv->auth_alg != alg) {
-+ acxlog(L_ASSOC, "authentication algorithm mismatch: "
-+ "want: %d, req: %d\n", priv->auth_alg, alg);
-+ result = NOT_OK;
-+ goto end;
-+ }
-+ }
-+ acxlog(L_ASSOC, "algorithm is ok\n");
-+
-+ if (ap) {
-+ clt = acx_l_sta_list_get_or_add(priv, hdr->a2);
-+ if (STA_LIST_ADD_CAN_FAIL && !clt) {
-+ acxlog(L_ASSOC, "could not allocate room for client\n");
-+ result = NOT_OK;
-+ goto end;
-+ }
-+ } else {
-+ clt = priv->ap_client;
-+ if (!mac_is_equal(clt->address, hdr->a2)) {
-+ printk("%s: malformed auth frame from AP?!\n",
-+ priv->netdev->name);
-+ result = NOT_OK;
-+ goto end;
-+ }
-+ }
-+
-+ /* now check which step in the authentication sequence we are
-+ * currently in, and act accordingly */
-+ acxlog(L_ASSOC, "acx_process_authen auth seq step %d\n", seq);
-+ switch (seq) {
-+ case 1:
-+ if (!ap)
-+ break;
-+ acx_l_transmit_authen2(priv, req, clt);
-+ break;
-+ case 2:
-+ if (ap)
-+ break;
-+ if (status == WLAN_MGMT_STATUS_SUCCESS) {
-+ if (alg == WLAN_AUTH_ALG_OPENSYSTEM) {
-+ acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
-+ acx_l_transmit_assoc_req(priv);
-+ } else
-+ if (alg == WLAN_AUTH_ALG_SHAREDKEY) {
-+ acx_l_transmit_authen3(priv, req);
-+ }
-+ } else {
-+ printk("%s: auth FAILED: peer sent "
-+ "response code %d (%s), "
-+ "still waiting for authentication\n",
-+ priv->netdev->name,
-+ status, get_status_string(status));
-+ acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
-+ }
-+ break;
-+ case 3:
-+ if (!ap)
-+ break;
-+ if ((clt->auth_alg != WLAN_AUTH_ALG_SHAREDKEY)
-+ || (alg != WLAN_AUTH_ALG_SHAREDKEY)
-+ || (clt->auth_step != 2))
-+ break;
-+ chal = req->challenge;
-+ if (!chal
-+ || memcmp(chal->challenge, clt->challenge_text, WLAN_CHALLENGE_LEN)
-+ || (chal->eid != WLAN_EID_CHALLENGE)
-+ || (chal->len != WLAN_CHALLENGE_LEN)
-+ )
-+ break;
-+ acx_l_transmit_authen4(priv, req);
-+ MAC_COPY(clt->address, hdr->a2);
-+ clt->used = CLIENT_AUTHENTICATED_2;
-+ clt->auth_step = 4;
-+ clt->seq = ieee2host16(hdr->seq);
-+ break;
-+ case 4:
-+ if (ap)
-+ break;
-+ /* ok, we're through: we're authenticated. Woohoo!! */
-+ acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
-+ acxlog(L_ASSOC, "Authenticated!\n");
-+ /* now that we're authenticated, request association */
-+ acx_l_transmit_assoc_req(priv);
-+ break;
-+ }
-+ result = NOT_OK;
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_gen_challenge
-+*----------------------------------------------------------------*/
-+static void
-+acx_gen_challenge(wlan_ie_challenge_t* d)
-+{
-+ FN_ENTER;
-+ d->eid = WLAN_EID_CHALLENGE;
-+ d->len = WLAN_CHALLENGE_LEN;
-+ get_random_bytes(d->challenge, WLAN_CHALLENGE_LEN);
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_deauthen
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_transmit_deauthen(wlandevice_t *priv, const u8 *addr, u16 reason)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct deauthen_frame_body *body;
-+
-+ FN_ENTER;
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto bad;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto bad;
-+ body = (void*)(head + 1);
-+
-+ head->fc = (WF_FTYPE_MGMTi | WF_FSTYPE_DEAUTHENi);
-+ head->dur = 0;
-+ MAC_COPY(head->da, addr);
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, priv->bssid);
-+ head->seq = 0;
-+
-+ acxlog(L_DEBUG|L_ASSOC|L_XFER,
-+ "sending deauthen to "MACSTR" for %d\n",
-+ MAC(addr), reason);
-+
-+ body->reason = host2ieee16(reason);
-+
-+ /* body is fixed size here, but beware of cutting-and-pasting this -
-+ ** do not use sizeof(*body) for variable sized mgmt packets! */
-+ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_authen1
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_transmit_authen1(wlandevice_t *priv)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct auth_frame_body *body;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_ASSOC, "Sending authentication1 request, "
-+ "awaiting response!\n");
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto bad;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto bad;
-+ body = (void*)(head + 1);
-+
-+ head->fc = WF_FSTYPE_AUTHENi;
-+ head->dur = host2ieee16(0x8000);
-+ MAC_COPY(head->da, priv->bssid);
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, priv->bssid);
-+ head->seq = 0;
-+
-+ body->auth_alg = host2ieee16(priv->auth_alg);
-+ body->auth_seq = host2ieee16(1);
-+ body->status = host2ieee16(0);
-+
-+ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_authen2
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_transmit_authen2(wlandevice_t *priv, const wlan_fr_authen_t *req,
-+ client_t *clt)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct auth_frame_body *body;
-+ unsigned int packet_len;
-+
-+ FN_ENTER;
-+
-+ if (!clt)
-+ goto ok;
-+
-+ MAC_COPY(clt->address, req->hdr->a2);
-+#ifdef UNUSED
-+ clt->ps = ((WF_FC_PWRMGTi & req->hdr->fc) != 0);
-+#endif
-+ clt->auth_alg = ieee2host16(*(req->auth_alg));
-+ clt->auth_step = 2;
-+ clt->seq = ieee2host16(req->hdr->seq);
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto bad;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto bad;
-+ body = (void*)(head + 1);
-+
-+ head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
-+ head->dur = req->hdr->dur;
-+ MAC_COPY(head->da, req->hdr->a2);
-+ /* MAC_COPY(head->sa, req->hdr->a1); */
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, req->hdr->a3);
-+ head->seq = req->hdr->seq;
-+
-+ /* already in IEEE format, no endianness conversion */
-+ body->auth_alg = *(req->auth_alg);
-+ body->auth_seq = host2ieee16(2);
-+ body->status = host2ieee16(0);
-+
-+ packet_len = WLAN_HDR_A3_LEN + 2 + 2 + 2;
-+ if (ieee2host16(*(req->auth_alg)) == WLAN_AUTH_ALG_OPENSYSTEM) {
-+ clt->used = CLIENT_AUTHENTICATED_2;
-+ } else { /* shared key */
-+ acx_gen_challenge(&body->challenge);
-+ memcpy(&clt->challenge_text, body->challenge.challenge, WLAN_CHALLENGE_LEN);
-+ packet_len += 2 + 2 + 2 + 1+1+WLAN_CHALLENGE_LEN;
-+ }
-+
-+ acxlog_mac(L_ASSOC|L_XFER,
-+ "transmit_auth2: BSSID=", head->bssid, "\n");
-+
-+ acx_l_tx_data(priv, tx, packet_len);
-+ok:
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_authen3
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_transmit_authen3(wlandevice_t *priv, const wlan_fr_authen_t *req)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct auth_frame_body *body;
-+ unsigned int packet_len;
-+
-+ FN_ENTER;
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto ok;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto ok;
-+ body = (void*)(head + 1);
-+
-+ head->fc = WF_FC_ISWEPi + WF_FSTYPE_AUTHENi;
-+ /* FIXME: is this needed?? authen4 does it...
-+ head->dur = req->hdr->dur;
-+ head->seq = req->hdr->seq;
-+ */
-+ MAC_COPY(head->da, priv->bssid);
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, priv->bssid);
-+
-+ /* already in IEEE format, no endianness conversion */
-+ body->auth_alg = *(req->auth_alg);
-+ body->auth_seq = host2ieee16(3);
-+ body->status = host2ieee16(0);
-+ memcpy(&body->challenge, req->challenge, req->challenge->len + 2);
-+ packet_len = WLAN_HDR_A3_LEN + 8 + req->challenge->len;
-+
-+ acxlog(L_ASSOC|L_XFER, "transmit_authen3!\n");
-+
-+ acx_l_tx_data(priv, tx, packet_len);
-+ok:
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_authen4
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_transmit_authen4(wlandevice_t *priv, const wlan_fr_authen_t *req)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct auth_frame_body *body;
-+
-+ FN_ENTER;
-+
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto ok;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto ok;
-+ body = (void*)(head + 1);
-+
-+ head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
-+ head->dur = req->hdr->dur;
-+ MAC_COPY(head->da, req->hdr->a2);
-+ /* MAC_COPY(head->sa, req->hdr->a1); */
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, req->hdr->a3);
-+ head->seq = req->hdr->seq;
-+
-+ /* already in IEEE format, no endianness conversion */
-+ body->auth_alg = *(req->auth_alg);
-+ body->auth_seq = host2ieee16(4);
-+ body->status = host2ieee16(0);
-+
-+ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
-+ok:
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_assoc_req
-+*
-+* priv->ap_client is a current candidate AP here
-+*----------------------------------------------------------------*/
-+static int
-+acx_l_transmit_assoc_req(wlandevice_t *priv)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ u8 *body, *p, *prate;
-+ unsigned int packet_len;
-+ u16 cap;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_ASSOC, "sending association request, "
-+ "awaiting response. NOT ASSOCIATED YET\n");
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto bad;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto bad;
-+ body = (void*)(head + 1);
-+
-+ head->fc = WF_FSTYPE_ASSOCREQi;
-+ head->dur = host2ieee16(0x8000);
-+ MAC_COPY(head->da, priv->bssid);
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, priv->bssid);
-+ head->seq = 0;
-+
-+ p = body;
-+ /* now start filling the AssocReq frame body */
-+
-+ /* since this assoc request will most likely only get
-+ * sent in the STA to AP case (and not when Ad-Hoc IBSS),
-+ * the cap combination indicated here will thus be
-+ * WF_MGMT_CAP_ESSi *always* (no IBSS ever)
-+ * The specs are more than non-obvious on all that:
-+ *
-+ * 802.11 7.3.1.4 Capability Information field
-+ ** APs set the ESS subfield to 1 and the IBSS subfield to 0 within
-+ ** Beacon or Probe Response management frames. STAs within an IBSS
-+ ** set the ESS subfield to 0 and the IBSS subfield to 1 in transmitted
-+ ** Beacon or Probe Response management frames
-+ **
-+ ** APs set the Privacy subfield to 1 within transmitted Beacon,
-+ ** Probe Response, Association Response, and Reassociation Response
-+ ** if WEP is required for all data type frames within the BSS.
-+ ** STAs within an IBSS set the Privacy subfield to 1 in Beacon
-+ ** or Probe Response management frames if WEP is required
-+ ** for all data type frames within the IBSS */
-+
-+ /* note that returning 0 will be refused by several APs...
-+ * (so this indicates that you're probably supposed to
-+ * "confirm" the ESS mode) */
-+ cap = WF_MGMT_CAP_ESSi;
-+
-+ /* this one used to be a check on wep_restricted,
-+ * but more likely it's wep_enabled instead */
-+ if (priv->wep_enabled)
-+ SET_BIT(cap, WF_MGMT_CAP_PRIVACYi);
-+
-+ /* Probably we can just set these always, because our hw is
-+ ** capable of shortpre and PBCC --vda */
-+ /* only ask for short preamble if the peer station supports it */
-+ if (priv->ap_client->cap_info & WF_MGMT_CAP_SHORT)
-+ SET_BIT(cap, WF_MGMT_CAP_SHORTi);
-+ /* only ask for PBCC support if the peer station supports it */
-+ if (priv->ap_client->cap_info & WF_MGMT_CAP_PBCC)
-+ SET_BIT(cap, WF_MGMT_CAP_PBCCi);
-+
-+ /* IEs: 1. caps */
-+ *(u16*)p = cap; p += 2;
-+ /* 2. listen interval */
-+ *(u16*)p = host2ieee16(priv->listen_interval); p += 2;
-+ /* 3. ESSID */
-+ p = wlan_fill_ie_ssid(p,
-+ strlen(priv->essid_for_assoc), priv->essid_for_assoc);
-+ /* 4. supp rates */
-+ prate = p;
-+ p = wlan_fill_ie_rates(p,
-+ priv->rate_supported_len, priv->rate_supported);
-+ /* 5. ext supp rates */
-+ p = wlan_fill_ie_rates_ext(p,
-+ priv->rate_supported_len, priv->rate_supported);
-+
-+ if (acx_debug & L_DEBUG) {
-+ printk("association: rates element\n");
-+ acx_dump_bytes(prate, p - prate);
-+ }
-+
-+ /* calculate lengths */
-+ packet_len = WLAN_HDR_A3_LEN + (p - body);
-+
-+ acxlog(L_ASSOC, "association: requesting caps 0x%04X, ESSID '%s'\n",
-+ cap, priv->essid_for_assoc);
-+
-+ acx_l_tx_data(priv, tx, packet_len);
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_transmit_disassoc
-+*
-+* FIXME: looks like incomplete implementation of a helper:
-+* acx_l_transmit_disassoc(priv, clt) - kick this client (we're an AP)
-+* acx_l_transmit_disassoc(priv, NULL) - leave BSSID (we're a STA)
-+*----------------------------------------------------------------*/
-+#ifdef BROKEN
-+int
-+acx_l_transmit_disassoc(wlandevice_t *priv, client_t *clt)
-+{
-+ struct tx *tx;
-+ struct wlan_hdr_mgmt *head;
-+ struct disassoc_frame_body *body;
-+
-+ FN_ENTER;
-+/* if (clt != NULL) { */
-+ tx = acx_l_alloc_tx(priv);
-+ if (!tx)
-+ goto bad;
-+ head = acx_l_get_txbuf(priv, tx);
-+ if (!head)
-+ goto bad;
-+ body = (void*)(head + 1);
-+
-+/* clt->used = CLIENT_AUTHENTICATED_2; - not (yet?) associated */
-+
-+ head->fc = WF_FSTYPE_DISASSOCi;
-+ head->dur = 0;
-+ /* huh? It muchly depends on whether we're STA or AP...
-+ ** sta->ap: da=bssid, sa=own, bssid=bssid
-+ ** ap->sta: da=sta, sa=bssid, bssid=bssid. FIXME! */
-+ MAC_COPY(head->da, priv->bssid);
-+ MAC_COPY(head->sa, priv->dev_addr);
-+ MAC_COPY(head->bssid, priv->dev_addr);
-+ head->seq = 0;
-+
-+ /* "Class 3 frame received from nonassociated station." */
-+ body->reason = host2ieee16(7);
-+
-+ /* fixed size struct, ok to sizeof */
-+ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
-+/* } */
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+#endif
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_complete_scan
-+*
-+* Called either from after_interrupt_task() if:
-+* 1) there was Scan_Complete IRQ, or
-+* 2) scanning expired in timer()
-+* We need to decide which ESS or IBSS to join.
-+* Iterates thru priv->sta_list:
-+* if priv->ap is not bcast, will join only specified
-+* ESS or IBSS with this bssid
-+* checks peers' caps for ESS/IBSS bit
-+* checks peers' SSID, allows exact match or hidden SSID
-+* If station to join is chosen:
-+* points priv->ap_client to the chosen struct client
-+* sets priv->essid_for_assoc for future assoc attempt
-+* Auth/assoc is not yet performed
-+* Returns OK if there is no need to restart scan
-+*----------------------------------------------------------------*/
-+int
-+acx_s_complete_scan(wlandevice_t *priv)
-+{
-+ struct client *bss;
-+ unsigned long flags;
-+ u16 needed_cap;
-+ int i;
-+ int idx_found = -1;
-+ int result = OK;
-+
-+ FN_ENTER;
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ needed_cap = WF_MGMT_CAP_IBSS; /* 2, we require Ad-Hoc */
-+ break;
-+ case ACX_MODE_2_STA:
-+ needed_cap = WF_MGMT_CAP_ESS; /* 1, we require Managed */
-+ break;
-+ default:
-+ printk("acx: driver bug: mode=%d in complete_scan()\n", priv->mode);
-+ dump_stack();
-+ goto end;
-+ }
-+
-+ acx_lock(priv, flags);
-+
-+ /* TODO: sta_iterator hiding implementation would be nice here... */
-+
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ bss = &priv->sta_list[i];
-+ if (!bss->used) continue;
-+
-+ acxlog(L_ASSOC, "Scan Table: SSID='%s' CH=%d SIR=%d SNR=%d\n",
-+ bss->essid, bss->channel, bss->sir, bss->snr);
-+
-+ if (!mac_is_bcast(priv->ap))
-+ if (!mac_is_equal(bss->bssid, priv->ap))
-+ continue; /* keep looking */
-+
-+ /* broken peer with no mode flags set? */
-+ if (unlikely(!(bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)))) {
-+ printk("%s: strange peer "MACSTR" found with "
-+ "neither ESS (AP) nor IBSS (Ad-Hoc) "
-+ "capability - skipped\n",
-+ priv->netdev->name, MAC(bss->address));
-+ continue;
-+ }
-+ acxlog(L_ASSOC, "peer_cap 0x%04X, needed_cap 0x%04X\n",
-+ bss->cap_info, needed_cap);
-+
-+ /* does peer station support what we need? */
-+ if ((bss->cap_info & needed_cap) != needed_cap)
-+ continue; /* keep looking */
-+
-+ /* strange peer with NO basic rates?! */
-+ if (unlikely(!bss->rate_bas)) {
-+ printk("%s: strange peer "MACSTR" with empty rate set "
-+ "- skipped\n",
-+ priv->netdev->name, MAC(bss->address));
-+ continue;
-+ }
-+
-+ /* do we support all basic rates of this peer? */
-+ if ((bss->rate_bas & priv->rate_oper) != bss->rate_bas) {
-+/* we probably need to have all rates as operational rates,
-+ even in case of an 11M-only configuration */
-+#ifdef THIS_IS_TROUBLESOME
-+ printk("%s: peer "MACSTR": incompatible basic rates "
-+ "(AP requests 0x%04X, we have 0x%04X) "
-+ "- skipped\n",
-+ priv->netdev->name, MAC(bss->address),
-+ bss->rate_bas, priv->rate_oper);
-+ continue;
-+#else
-+ printk("%s: peer "MACSTR": incompatible basic rates "
-+ "(AP requests 0x%04X, we have 0x%04X). "
-+ "Considering anyway...\n",
-+ priv->netdev->name, MAC(bss->address),
-+ bss->rate_bas, priv->rate_oper);
-+#endif
-+ }
-+
-+ if ( !(priv->reg_dom_chanmask & (1<<(bss->channel-1))) ) {
-+ printk("%s: warning: peer "MACSTR" is on channel %d "
-+ "outside of channel range of current "
-+ "regulatory domain - couldn't join "
-+ "even if other settings match. "
-+ "You might want to adapt your config\n",
-+ priv->netdev->name, MAC(bss->address),
-+ bss->channel);
-+ continue; /* keep looking */
-+ }
-+
-+ if (!priv->essid_active || !strcmp(bss->essid, priv->essid)) {
-+ acxlog(L_ASSOC,
-+ "found station with matching ESSID! ('%s' "
-+ "station, '%s' config)\n",
-+ bss->essid,
-+ (priv->essid_active) ? priv->essid : "[any]");
-+ /* TODO: continue looking for peer with better SNR */
-+ bss->used = CLIENT_JOIN_CANDIDATE;
-+ idx_found = i;
-+
-+ /* stop searching if this station is
-+ * on the current channel, otherwise
-+ * keep looking for an even better match */
-+ if (bss->channel == priv->channel)
-+ break;
-+ } else
-+ if (!bss->essid[0]
-+ || ((' ' == bss->essid[0]) && !bss->essid[1])
-+ ) {
-+ /* hmm, station with empty or single-space SSID:
-+ * using hidden SSID broadcast?
-+ */
-+ /* This behaviour is broken: which AP from zillion
-+ ** of APs with hidden SSID you'd try?
-+ ** We should use Probe requests to get Probe responses
-+ ** and check for real SSID (are those never hidden?) */
-+ bss->used = CLIENT_JOIN_CANDIDATE;
-+ if (idx_found == -1)
-+ idx_found = i;
-+ acxlog(L_ASSOC, "found station with empty or "
-+ "single-space (hidden) SSID, considering "
-+ "for assoc attempt\n");
-+ /* ...and keep looking for better matches */
-+ } else {
-+ acxlog(L_ASSOC, "ESSID doesn't match! ('%s' "
-+ "station, '%s' config)\n",
-+ bss->essid,
-+ (priv->essid_active) ? priv->essid : "[any]");
-+ }
-+ }
-+
-+ /* TODO: iterate thru join candidates instead */
-+ /* TODO: rescan if not associated within some timeout */
-+ if (idx_found != -1) {
-+ char *essid_src;
-+ size_t essid_len;
-+
-+ bss = &priv->sta_list[idx_found];
-+ priv->ap_client = bss;
-+
-+ if (bss->essid[0] == '\0') {
-+ /* if the ESSID of the station we found is empty
-+ * (no broadcast), then use user configured ESSID
-+ * instead */
-+ essid_src = priv->essid;
-+ essid_len = priv->essid_len;
-+ } else {
-+ essid_src = bss->essid;
-+ essid_len = strlen(bss->essid);
-+ }
-+
-+ acx_update_capabilities(priv);
-+
-+ memcpy(priv->essid_for_assoc, essid_src, essid_len);
-+ priv->essid_for_assoc[essid_len] = '\0';
-+ priv->channel = bss->channel;
-+ MAC_COPY(priv->bssid, bss->bssid);
-+
-+ bss->rate_cfg = (bss->rate_cap & priv->rate_oper);
-+ bss->rate_cur = 1 << lowest_bit(bss->rate_cfg);
-+ bss->rate_100 = acx_rate111to100(bss->rate_cur);
-+
-+ acxlog_mac(L_ASSOC,
-+ "matching station found: ", priv->bssid, ", joining\n");
-+
-+ /* TODO: do we need to switch to the peer's channel first? */
-+
-+ if (ACX_MODE_0_ADHOC == priv->mode) {
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-+ } else {
-+ acx_l_transmit_authen1(priv);
-+ acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
-+ }
-+ } else { /* idx_found == -1 */
-+ /* uh oh, no station found in range */
-+ if (ACX_MODE_0_ADHOC == priv->mode) {
-+ printk("%s: no matching station found in range, "
-+ "generating our own IBSS instead\n",
-+ priv->netdev->name);
-+ /* we do it hostap way: */
-+ MAC_COPY(priv->bssid, priv->dev_addr);
-+ priv->bssid[0] |= 0x02; /* 'local assigned addr' bit */
-+ /* add IBSS bit to our caps... */
-+ acx_update_capabilities(priv);
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-+ /* In order to cmd_join be called below */
-+ idx_found = 0;
-+ } else {
-+ /* we shall scan again, AP can be
-+ ** just temporarily powered off */
-+ acxlog(L_ASSOC,
-+ "no matching station found in range yet\n");
-+ acx_set_status(priv, ACX_STATUS_1_SCANNING);
-+ result = NOT_OK;
-+ }
-+ }
-+
-+ acx_unlock(priv, flags);
-+
-+ if (idx_found != -1) {
-+ if (ACX_MODE_0_ADHOC == priv->mode) {
-+ /* need to update channel in beacon template */
-+ SET_BIT(priv->set_mask, SET_TEMPLATES);
-+ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
-+ acx_s_update_card_settings(priv, 0, 0);
-+ }
-+ /* Inform firmware on our decision to start or join BSS */
-+ acx_s_cmd_join_bssid(priv, priv->bssid);
-+ }
-+
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_read_fw
-+**
-+** Loads a firmware image
-+**
-+** Returns:
-+** 0 unable to load file
-+** pointer to firmware success
-+*/
-+#if USE_FW_LOADER_26
-+firmware_image_t*
-+acx_s_read_fw(struct device *dev, const char *file, u32 *size)
-+#else
-+#undef acx_s_read_fw
-+firmware_image_t*
-+acx_s_read_fw(const char *file, u32 *size)
-+#endif
-+{
-+ firmware_image_t *res;
-+
-+#if USE_FW_LOADER_LEGACY
-+ mm_segment_t orgfs;
-+ unsigned long page;
-+ char *buffer;
-+ struct file *inf;
-+ int retval;
-+ int offset;
-+ char *filename;
-+#endif
-+
-+#if USE_FW_LOADER_26
-+ const struct firmware *fw_entry;
-+
-+ res = NULL;
-+ acxlog(L_DEBUG, "requesting firmware image '%s'\n", file);
-+ if (!request_firmware(&fw_entry, file, dev)) {
-+ *size = 8;
-+ if (fw_entry->size >= 8)
-+ *size = 8 + le32_to_cpu(*(u32 *)(fw_entry->data + 4));
-+ if (fw_entry->size != *size) {
-+ printk("acx: firmware size does not match "
-+ "firmware header: %d != %d, "
-+ "aborting fw upload\n",
-+ (int) fw_entry->size, (int) *size);
-+ goto release_ret;
-+ }
-+ res = vmalloc(*size);
-+ if (!res) {
-+ printk("acx: no memory for firmware "
-+ "(%u bytes)\n", *size);
-+ goto release_ret;
-+ }
-+ memcpy(res, fw_entry->data, fw_entry->size);
-+release_ret:
-+ release_firmware(fw_entry);
-+ return res;
-+ }
-+ printk("acx: firmware image '%s' was not provided. "
-+ "Check your hotplug scripts\n", file);
-+#endif
-+
-+#if USE_FW_LOADER_LEGACY
-+ printk("acx: firmware upload via firmware_dir module parameter "
-+ "is deprecated. Switch to using hotplug\n");
-+
-+ res = NULL;
-+ orgfs = get_fs(); /* store original fs */
-+ set_fs(KERNEL_DS);
-+
-+ /* Read in whole file then check the size */
-+ page = __get_free_page(GFP_KERNEL);
-+ if (unlikely(0 == page)) {
-+ printk("acx: no memory for firmware upload\n");
-+ goto fail;
-+ }
-+
-+ filename = kmalloc(PATH_MAX, GFP_KERNEL);
-+ if (unlikely(!filename)) {
-+ printk("acx: no memory for firmware upload\n");
-+ goto fail;
-+ }
-+ if (!firmware_dir) {
-+ firmware_dir = "/usr/share/acx";
-+ acxlog(L_DEBUG, "no firmware directory specified "
-+ "via module parameter firmware_dir, "
-+ "using default %s\n", firmware_dir);
-+ }
-+ snprintf(filename, PATH_MAX, "%s/%s", firmware_dir, file);
-+ acxlog(L_DEBUG, "reading firmware image '%s'\n", filename);
-+
-+ buffer = (char*)page;
-+
-+ /* Note that file must be given as absolute path:
-+ * a relative path works on first loading,
-+ * but any subsequent firmware loading during card
-+ * eject/insert will fail, most likely since the first
-+ * module loading happens in user space (and thus
-+ * filp_open can figure out the absolute path from a
-+ * relative path) whereas the card reinsert processing
-+ * probably happens in kernel space where you don't have
-+ * a current directory to be able to figure out an
-+ * absolute path from a relative path... */
-+ inf = filp_open(filename, O_RDONLY, 0);
-+ kfree(filename);
-+ if (OK != IS_ERR(inf)) {
-+ const char *err;
-+
-+ switch (-PTR_ERR(inf)) {
-+ case 2: err = "file not found";
-+ break;
-+ default:
-+ err = "unknown error";
-+ break;
-+ }
-+ printk("acx: error %ld trying to open file '%s': %s\n",
-+ -PTR_ERR(inf), file, err);
-+ goto fail;
-+ }
-+
-+ if (unlikely((NULL == inf->f_op) || (NULL == inf->f_op->read))) {
-+ printk("acx: %s does not have a read method?!\n", file);
-+ goto fail_close;
-+ }
-+
-+ offset = 0;
-+ do {
-+ retval = inf->f_op->read(inf, buffer, PAGE_SIZE, &inf->f_pos);
-+
-+ if (unlikely(0 > retval)) {
-+ printk("acx: error %d reading file '%s'\n",
-+ -retval, file);
-+ vfree(res);
-+ res = NULL;
-+ } else if (0 == retval) {
-+ if (0 == offset) {
-+ printk("acx: firmware image file "
-+ "'%s' is empty?!\n", file);
-+ }
-+ } else if (0 < retval) {
-+ /* allocate result buffer here if needed,
-+ * since we don't want to waste resources/time
-+ * (in case file opening/reading fails)
-+ * by doing allocation in front of the loop instead. */
-+ if (NULL == res) {
-+ *size = 8 + le32_to_cpu(*(u32 *)(4 + buffer));
-+
-+ res = vmalloc(*size);
-+ if (NULL == res) {
-+ printk("acx: unable to "
-+ "allocate %u bytes for "
-+ "firmware module upload\n",
-+ *size);
-+ goto fail_close;
-+ }
-+ acxlog(L_DEBUG, "allocated %u bytes "
-+ "for firmware module loading\n",
-+ *size);
-+ }
-+ if ((unlikely(offset + retval > *size))) {
-+ printk("acx: ERROR: allocation "
-+ "was less than firmware image size?!\n");
-+ goto fail_close;
-+ }
-+ memcpy((u8*)res + offset, buffer, retval);
-+ offset += retval;
-+ }
-+ } while (0 < retval);
-+
-+fail_close:
-+ retval = filp_close(inf, NULL);
-+
-+ if (unlikely(retval)) {
-+ printk("acx: error %d closing file '%s'\n", -retval, file);
-+ }
-+
-+ if (unlikely((NULL != res) && (offset != le32_to_cpu(res->size) + 8))) {
-+ printk("acx: firmware is reporting a different size "
-+ "(0x%08X; 0x%08X was read)\n",
-+ le32_to_cpu(res->size) + 8, offset);
-+ vfree(res);
-+ res = NULL;
-+ }
-+
-+fail:
-+ if (page)
-+ free_page(page);
-+ set_fs(orgfs);
-+#endif
-+
-+ /* checksum will be verified in write_fw, so don't bother here */
-+ return res;
-+}
-+
-+
-+#ifdef POWER_SAVE_80211
-+/*----------------------------------------------------------------
-+* acx_s_activate_power_save_mode
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_activate_power_save_mode(wlandevice_t *priv)
-+{
-+ acx100_ie_powermgmt_t pm;
-+
-+ FN_ENTER;
-+
-+ acx_s_interrogate(priv, &pm, ACX1xx_IE_POWER_MGMT);
-+ if (pm.wakeup_cfg != 0x81)
-+ goto end;
-+
-+ pm.wakeup_cfg = 0;
-+ pm.options = 0;
-+ pm.hangover_period = 0;
-+ acx_s_configure(priv, &pm, ACX1xx_IE_POWER_MGMT);
-+end:
-+ FN_EXIT0;
-+}
-+#endif
-+
-+
-+/***********************************************************************
-+** acx_s_set_wepkey
-+*/
-+static void
-+acx100_s_set_wepkey(wlandevice_t *priv)
-+{
-+ ie_dot11WEPDefaultKey_t dk;
-+ int i;
-+
-+ for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
-+ if (priv->wep_keys[i].size != 0) {
-+ acxlog(L_INIT, "setting WEP key: %d with "
-+ "total size: %d\n", i, (int) priv->wep_keys[i].size);
-+ dk.action = 1;
-+ dk.keySize = priv->wep_keys[i].size;
-+ dk.defaultKeyNum = i;
-+ memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
-+ acx_s_configure(priv, &dk, ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE);
-+ }
-+ }
-+}
-+
-+static void
-+acx111_s_set_wepkey(wlandevice_t *priv)
-+{
-+ acx111WEPDefaultKey_t dk;
-+ int i;
-+
-+ for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
-+ if (priv->wep_keys[i].size != 0) {
-+ acxlog(L_INIT, "setting WEP key: %d with "
-+ "total size: %d\n", i, (int) priv->wep_keys[i].size);
-+ memset(&dk, 0, sizeof(dk));
-+ dk.action = cpu_to_le16(1); /* "add key"; yes, that's a 16bit value */
-+ dk.keySize = priv->wep_keys[i].size;
-+
-+ /* are these two lines necessary? */
-+ dk.type = 0; /* default WEP key */
-+ dk.index = 0; /* ignored when setting default key */
-+
-+ dk.defaultKeyNum = i;
-+ memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &dk, sizeof(dk));
-+ }
-+ }
-+}
-+
-+static void
-+acx_s_set_wepkey(wlandevice_t *priv)
-+{
-+ if (IS_ACX111(priv))
-+ acx111_s_set_wepkey(priv);
-+ else
-+ acx100_s_set_wepkey(priv);
-+}
-+
-+
-+/***********************************************************************
-+** acx100_s_init_wep
-+**
-+** FIXME: this should probably be moved into the new card settings
-+** management, but since we're also modifying the memory map layout here
-+** due to the WEP key space we want, we should take care...
-+*/
-+int
-+acx100_s_init_wep(wlandevice_t *priv)
-+{
-+/* int i;
-+ acx100_cmd_wep_mgmt_t wep_mgmt; size = 37 bytes */
-+ acx100_ie_wep_options_t options;
-+ ie_dot11WEPDefaultKeyID_t dk;
-+ acx_ie_memmap_t pt;
-+ int res = NOT_OK;
-+
-+ FN_ENTER;
-+
-+ if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-+ goto fail;
-+ }
-+
-+ acxlog(L_DEBUG, "CodeEnd:%X\n", pt.CodeEnd);
-+
-+ pt.WEPCacheStart = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
-+ pt.WEPCacheEnd = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
-+
-+ if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-+ goto fail;
-+ }
-+
-+ /* let's choose maximum setting: 4 default keys, plus 10 other keys: */
-+ options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
-+ options.WEPOption = 0x00;
-+
-+ acxlog(L_ASSOC, "%s: writing WEP options\n", __func__);
-+ acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
-+
-+ acx100_s_set_wepkey(priv);
-+
-+ if (priv->wep_keys[priv->wep_current_index].size != 0) {
-+ acxlog(L_ASSOC, "setting active default WEP key number: %d\n",
-+ priv->wep_current_index);
-+ dk.KeyID = priv->wep_current_index;
-+ acx_s_configure(priv, &dk, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); /* 0x1010 */
-+ }
-+ /* FIXME!!! wep_key_struct is filled nowhere! But priv
-+ * is initialized to 0, and we don't REALLY need those keys either */
-+/* for (i = 0; i < 10; i++) {
-+ if (priv->wep_key_struct[i].len != 0) {
-+ MAC_COPY(wep_mgmt.MacAddr, priv->wep_key_struct[i].addr);
-+ wep_mgmt.KeySize = cpu_to_le16(priv->wep_key_struct[i].len);
-+ memcpy(&wep_mgmt.Key, priv->wep_key_struct[i].key, le16_to_cpu(wep_mgmt.KeySize));
-+ wep_mgmt.Action = cpu_to_le16(1);
-+ acxlog(L_ASSOC, "writing WEP key %d (len %d)\n", i, le16_to_cpu(wep_mgmt.KeySize));
-+ if (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &wep_mgmt, sizeof(wep_mgmt))) {
-+ priv->wep_key_struct[i].index = i;
-+ }
-+ }
-+ } */
-+
-+ /* now retrieve the updated WEPCacheEnd pointer... */
-+ if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-+ printk("%s: ACX1xx_IE_MEMORY_MAP read #2 FAILED\n",
-+ priv->netdev->name);
-+ goto fail;
-+ }
-+ /* ...and tell it to start allocating templates at that location */
-+ /* (no endianness conversion needed) */
-+ pt.PacketTemplateStart = pt.WEPCacheEnd;
-+
-+ if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
-+ printk("%s: ACX1xx_IE_MEMORY_MAP write #2 FAILED\n",
-+ priv->netdev->name);
-+ goto fail;
-+ }
-+ res = OK;
-+
-+fail:
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_s_init_max_null_data_template(wlandevice_t *priv)
-+{
-+ struct acx_template_nullframe b;
-+ int result;
-+
-+ FN_ENTER;
-+ memset(&b, 0, sizeof(b));
-+ b.size = cpu_to_le16(sizeof(b) - 2);
-+ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_NULL_DATA, &b, sizeof(b));
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_init_max_beacon_template
-+*/
-+static int
-+acx_s_init_max_beacon_template(wlandevice_t *priv)
-+{
-+ struct acx_template_beacon b;
-+ int result;
-+
-+ FN_ENTER;
-+ memset(&b, 0, sizeof(b));
-+ b.size = cpu_to_le16(sizeof(b) - 2);
-+ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &b, sizeof(b));
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+/***********************************************************************
-+** acx_s_init_max_tim_template
-+*/
-+static int
-+acx_s_init_max_tim_template(wlandevice_t *priv)
-+{
-+ acx_template_tim_t t;
-+
-+ memset(&t, 0, sizeof(t));
-+ t.size = cpu_to_le16(sizeof(t) - 2);
-+ return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_init_max_probe_response_template
-+*/
-+static int
-+acx_s_init_max_probe_response_template(wlandevice_t *priv)
-+{
-+ struct acx_template_proberesp pr;
-+
-+ memset(&pr, 0, sizeof(pr));
-+ pr.size = cpu_to_le16(sizeof(pr) - 2);
-+
-+ return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, sizeof(pr));
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_init_max_probe_request_template
-+*/
-+static int
-+acx_s_init_max_probe_request_template(wlandevice_t *priv)
-+{
-+ union {
-+ acx100_template_probereq_t p100;
-+ acx111_template_probereq_t p111;
-+ } pr;
-+ int res;
-+
-+ FN_ENTER;
-+ memset(&pr, 0, sizeof(pr));
-+ pr.p100.size = cpu_to_le16(sizeof(pr) - 2);
-+ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &pr, sizeof(pr));
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_set_tim_template
-+**
-+** In full blown driver we will regularly update partial virtual bitmap
-+** by calling this function
-+** (it can be done by irq handler on each DTIM irq or by timer...)
-+
-+[802.11 7.3.2.6] TIM information element:
-+- 1 EID
-+- 1 Length
-+1 1 DTIM Count
-+ indicates how many beacons (including this) appear before next DTIM
-+ (0=this one is a DTIM)
-+2 1 DTIM Period
-+ number of beacons between successive DTIMs
-+ (0=reserved, 1=all TIMs are DTIMs, 2=every other, etc)
-+3 1 Bitmap Control
-+ bit0: Traffic Indicator bit associated with Assoc ID 0 (Bcast AID?)
-+ set to 1 in TIM elements with a value of 0 in the DTIM Count field
-+ when one or more broadcast or multicast frames are buffered at the AP.
-+ bit1-7: Bitmap Offset (logically Bitmap_Offset = Bitmap_Control & 0xFE).
-+4 n Partial Virtual Bitmap
-+ Visible part of traffic-indication bitmap.
-+ Full bitmap consists of 2008 bits (251 octets) such that bit number N
-+ (0<=N<=2007) in the bitmap corresponds to bit number (N mod 8)
-+ in octet number N/8 where the low-order bit of each octet is bit0,
-+ and the high order bit is bit7.
-+ Each set bit in virtual bitmap corresponds to traffic buffered by AP
-+ for a specific station (with corresponding AID?).
-+ Partial Virtual Bitmap shows a part of bitmap which has non-zero.
-+ Bitmap Offset is a number of skipped zero octets (see above).
-+ 'Missing' octets at the tail are also assumed to be zero.
-+ Example: Length=6, Bitmap_Offset=2, Partial_Virtual_Bitmap=55 55 55
-+ This means that traffic-indication bitmap is:
-+ 00000000 00000000 01010101 01010101 01010101 00000000 00000000...
-+ (is bit0 in the map is always 0 and real value is in Bitmap Control bit0?)
-+*/
-+static int
-+acx_s_set_tim_template(wlandevice_t *priv)
-+{
-+/* For now, configure smallish test bitmap, all zero ("no pending data") */
-+ enum { bitmap_size = 5 };
-+
-+ acx_template_tim_t t;
-+ int result;
-+
-+ FN_ENTER;
-+
-+ memset(&t, 0, sizeof(t));
-+ t.size = 5 + bitmap_size; /* eid+len+count+period+bmap_ctrl + bmap */
-+ t.tim_eid = WLAN_EID_TIM;
-+ t.len = 3 + bitmap_size; /* count+period+bmap_ctrl + bmap */
-+ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_fill_beacon_or_proberesp_template
-+**
-+** For frame format info, please see 802.11-1999.pdf item 7.2.3.9 and below!!
-+**
-+** NB: we use the fact that
-+** struct acx_template_proberesp and struct acx_template_beacon are the same
-+** (well, almost...)
-+**
-+** [802.11] Beacon's body consist of these IEs:
-+** 1 Timestamp
-+** 2 Beacon interval
-+** 3 Capability information
-+** 4 SSID
-+** 5 Supported rates (up to 8 rates)
-+** 6 FH Parameter Set (frequency-hopping PHYs only)
-+** 7 DS Parameter Set (direct sequence PHYs only)
-+** 8 CF Parameter Set (only if PCF is supported)
-+** 9 IBSS Parameter Set (ad-hoc only)
-+**
-+** Beacon only:
-+** 10 TIM (AP only) (see 802.11 7.3.2.6)
-+** 11 Country Information (802.11d)
-+** 12 FH Parameters (802.11d)
-+** 13 FH Pattern Table (802.11d)
-+** ... (?!! did not yet find relevant PDF file... --vda)
-+** 19 ERP Information (extended rate PHYs)
-+** 20 Extended Supported Rates (if more than 8 rates)
-+**
-+** Proberesp only:
-+** 10 Country information (802.11d)
-+** 11 FH Parameters (802.11d)
-+** 12 FH Pattern Table (802.11d)
-+** 13-n Requested information elements (802.11d)
-+** ????
-+** 18 ERP Information (extended rate PHYs)
-+** 19 Extended Supported Rates (if more than 8 rates)
-+*/
-+static int
-+acx_fill_beacon_or_proberesp_template(wlandevice_t *priv,
-+ struct acx_template_beacon *templ,
-+ u16 fc /* in host order! */)
-+{
-+ int len;
-+ u8 *p;
-+
-+ FN_ENTER;
-+
-+ memset(templ, 0, sizeof(*templ));
-+ MAC_BCAST(templ->da);
-+ MAC_COPY(templ->sa, priv->dev_addr);
-+ MAC_COPY(templ->bssid, priv->bssid);
-+
-+ templ->beacon_interval = cpu_to_le16(priv->beacon_interval);
-+ acx_update_capabilities(priv);
-+ templ->cap = cpu_to_le16(priv->capabilities);
-+
-+ p = templ->variable;
-+ p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
-+ p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
-+ p = wlan_fill_ie_ds_parms(p, priv->channel);
-+ /* NB: should go AFTER tim, but acx seem to keep tim last always */
-+ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ /* ATIM window */
-+ p = wlan_fill_ie_ibss_parms(p, 0); break;
-+ case ACX_MODE_3_AP:
-+ /* TIM IE is set up as separate template */
-+ break;
-+ }
-+
-+ len = p - (u8*)templ;
-+ templ->fc = cpu_to_le16(WF_FTYPE_MGMT | fc);
-+ /* - 2: do not count 'u16 size' field */
-+ templ->size = cpu_to_le16(len - 2);
-+
-+ FN_EXIT1(len);
-+ return len;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_set_beacon_template
-+*/
-+static int
-+acx_s_set_beacon_template(wlandevice_t *priv)
-+{
-+ struct acx_template_beacon bcn;
-+ int len, result;
-+
-+ FN_ENTER;
-+
-+ len = acx_fill_beacon_or_proberesp_template(priv, &bcn, WF_FSTYPE_BEACON);
-+ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &bcn, len);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_set_probe_response_template
-+*/
-+static int
-+acx_s_set_probe_response_template(wlandevice_t *priv)
-+{
-+ struct acx_template_proberesp pr;
-+ int len, result;
-+
-+ FN_ENTER;
-+
-+ len = acx_fill_beacon_or_proberesp_template(priv, &pr, WF_FSTYPE_PROBERESP);
-+ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, len);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx100_s_init_packet_templates()
-+**
-+** NOTE: order is very important here, to have a correct memory layout!
-+** init templates: max Probe Request (station mode), max NULL data,
-+** max Beacon, max TIM, max Probe Response.
-+*/
-+int
-+acx100_s_init_packet_templates(wlandevice_t *priv)
-+{
-+ acx_ie_memmap_t mm;
-+ int result = NOT_OK;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_DEBUG, "sizeof(memmap)=%d bytes\n", (int)sizeof(mm));
-+
-+ /* acx100 still do not emit probe requests, thus this call
-+ ** is sourt of not needed. But we want it to work someday */
-+ if (OK != acx_s_init_max_probe_request_template(priv))
-+ goto failed;
-+
-+#ifdef NOT_WORKING_YET
-+ /* FIXME: creating the NULL data template breaks
-+ * communication right now, needs further testing.
-+ * Also, need to set the template once we're joining a network. */
-+ if (OK != acx_s_init_max_null_data_template(priv))
-+ goto failed;
-+#endif
-+
-+ if (OK != acx_s_init_max_beacon_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_init_max_tim_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_init_max_probe_response_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_set_tim_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
-+ goto failed;
-+ }
-+
-+ mm.QueueStart = cpu_to_le32(le32_to_cpu(mm.PacketTemplateEnd) + 4);
-+ if (OK != acx_s_configure(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
-+ goto failed;
-+ }
-+
-+ result = OK;
-+ goto success;
-+
-+failed:
-+ acxlog(L_DEBUG|L_INIT,
-+ /* "cb=0x%X\n" */
-+ "pACXMemoryMap:\n"
-+ ".CodeStart=0x%X\n"
-+ ".CodeEnd=0x%X\n"
-+ ".WEPCacheStart=0x%X\n"
-+ ".WEPCacheEnd=0x%X\n"
-+ ".PacketTemplateStart=0x%X\n"
-+ ".PacketTemplateEnd=0x%X\n",
-+ /* len, */
-+ le32_to_cpu(mm.CodeStart),
-+ le32_to_cpu(mm.CodeEnd),
-+ le32_to_cpu(mm.WEPCacheStart),
-+ le32_to_cpu(mm.WEPCacheEnd),
-+ le32_to_cpu(mm.PacketTemplateStart),
-+ le32_to_cpu(mm.PacketTemplateEnd));
-+
-+success:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+int
-+acx111_s_init_packet_templates(wlandevice_t *priv)
-+{
-+ int result = NOT_OK;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_DEBUG|L_INIT, "initializing max packet templates\n");
-+
-+ if (OK != acx_s_init_max_probe_request_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_init_max_null_data_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_init_max_beacon_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_init_max_tim_template(priv))
-+ goto failed;
-+
-+ if (OK != acx_s_init_max_probe_response_template(priv))
-+ goto failed;
-+
-+ /* the other templates will be set later (acx_start) */
-+ /*
-+ if (OK != acx_s_set_tim_template(priv))
-+ goto failed;*/
-+
-+ result = OK;
-+ goto success;
-+
-+failed:
-+ printk("%s: acx111_init_packet_templates() FAILED\n", priv->netdev->name);
-+
-+success:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx100_s_set_probe_request_template(wlandevice_t *priv)
-+{
-+ struct acx100_template_probereq probereq;
-+ char *p;
-+ int res;
-+ int frame_len;
-+
-+ FN_ENTER;
-+
-+ memset(&probereq, 0, sizeof(probereq));
-+
-+ probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
-+ MAC_BCAST(probereq.da);
-+ MAC_COPY(probereq.sa, priv->dev_addr);
-+ MAC_BCAST(probereq.bssid);
-+
-+ probereq.beacon_interval = cpu_to_le16(priv->beacon_interval);
-+ acx_update_capabilities(priv);
-+ probereq.cap = cpu_to_le16(priv->capabilities);
-+
-+ p = probereq.variable;
-+ acxlog(L_ASSOC, "SSID='%s' len=%d\n", priv->essid, priv->essid_len);
-+ p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
-+ p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
-+ /* FIXME: should these be here or AFTER ds_parms? */
-+ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
-+ /* HUH?? who said it must be here? I've found nothing in 802.11! --vda*/
-+ /* p = wlan_fill_ie_ds_parms(p, priv->channel); */
-+ frame_len = p - (char*)&probereq;
-+ probereq.size = frame_len - 2;
-+
-+ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
-+ FN_EXIT0;
-+ return res;
-+}
-+
-+static int
-+acx111_s_set_probe_request_template(wlandevice_t *priv)
-+{
-+ struct acx111_template_probereq probereq;
-+ char *p;
-+ int res;
-+ int frame_len;
-+
-+ FN_ENTER;
-+
-+ memset(&probereq, 0, sizeof(probereq));
-+
-+ probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
-+ MAC_BCAST(probereq.da);
-+ MAC_COPY(probereq.sa, priv->dev_addr);
-+ MAC_BCAST(probereq.bssid);
-+
-+ p = probereq.variable;
-+ p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
-+ p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
-+ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
-+ frame_len = p - (char*)&probereq;
-+ probereq.size = frame_len - 2;
-+
-+ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
-+ FN_EXIT0;
-+ return res;
-+}
-+
-+static int
-+acx_s_set_probe_request_template(wlandevice_t *priv)
-+{
-+ if (IS_ACX111(priv)) {
-+ return acx111_s_set_probe_request_template(priv);
-+ } else {
-+ return acx100_s_set_probe_request_template(priv);
-+ }
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_update_card_settings
-+**
-+** Applies accumulated changes in various priv->xxxx members
-+** Called by ioctl commit handler, acx_start, acx_set_defaults,
-+** acx_s_after_interrupt_task (if IRQ_CMD_UPDATE_CARD_CFG),
-+*/
-+static void
-+acx111_s_sens_radio_16_17(wlandevice_t *priv)
-+{
-+ u32 feature1, feature2;
-+
-+ if ((priv->sensitivity < 1) || (priv->sensitivity > 3)) {
-+ printk("%s: invalid sensitivity setting (1..3), "
-+ "setting to 1\n", priv->netdev->name);
-+ priv->sensitivity = 1;
-+ }
-+ acx111_s_get_feature_config(priv, &feature1, &feature2);
-+ CLEAR_BIT(feature1, FEATURE1_LOW_RX|FEATURE1_EXTRA_LOW_RX);
-+ if (priv->sensitivity > 1)
-+ SET_BIT(feature1, FEATURE1_LOW_RX);
-+ if (priv->sensitivity > 2)
-+ SET_BIT(feature1, FEATURE1_EXTRA_LOW_RX);
-+ acx111_s_feature_set(priv, feature1, feature2);
-+}
-+
-+void
-+acx_s_update_card_settings(wlandevice_t *priv, int get_all, int set_all)
-+{
-+ unsigned long flags;
-+ unsigned int start_scan = 0;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ if (get_all)
-+ SET_BIT(priv->get_mask, GETSET_ALL);
-+ if (set_all)
-+ SET_BIT(priv->set_mask, GETSET_ALL);
-+ /* Why not just set masks to 0xffffffff? We can get rid of GETSET_ALL */
-+
-+ acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X\n",
-+ priv->get_mask, priv->set_mask);
-+
-+ /* Track dependencies betweed various settings */
-+
-+ if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_WEP)) {
-+ acxlog(L_INIT, "important setting has been changed. "
-+ "Need to update packet templates, too\n");
-+ SET_BIT(priv->set_mask, SET_TEMPLATES);
-+ }
-+ if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
-+ /* This will actually tune RX/TX to the channel */
-+ SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX);
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_3_AP:
-+ /* Beacons contain channel# - update them */
-+ SET_BIT(priv->set_mask, SET_TEMPLATES);
-+ }
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ start_scan = 1;
-+ }
-+ }
-+
-+ /* Apply settings */
-+
-+#ifdef WHY_SHOULD_WE_BOTHER /* imagine we were just powered off */
-+ /* send a disassoc request in case it's required */
-+ if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_CHANNEL|GETSET_WEP|GETSET_ALL)) {
-+ if (ACX_MODE_2_STA == priv->mode) {
-+ if (ACX_STATUS_4_ASSOCIATED == priv->status) {
-+ acxlog(L_ASSOC, "we were ASSOCIATED - "
-+ "sending disassoc request\n");
-+ acx_lock(priv, flags);
-+ acx_l_transmit_disassoc(priv, NULL);
-+ /* FIXME: deauth? */
-+ acx_unlock(priv, flags);
-+ }
-+ /* need to reset some other stuff as well */
-+ acxlog(L_DEBUG, "resetting bssid\n");
-+ MAC_ZERO(priv->bssid);
-+ SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST);
-+ /* FIXME: should start scanning */
-+ start_scan = 1;
-+ }
-+ }
-+#endif
-+
-+ if (priv->get_mask & (GETSET_STATION_ID|GETSET_ALL)) {
-+ u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
-+ const u8 *paddr;
-+
-+ acx_s_interrogate(priv, stationID, ACX1xx_IE_DOT11_STATION_ID);
-+ paddr = &stationID[4];
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ /* we copy the MAC address (reversed in
-+ * the card) to the netdevice's MAC
-+ * address, and on ifup it will be
-+ * copied into iwpriv->dev_addr */
-+ priv->netdev->dev_addr[ETH_ALEN - 1 - i] = paddr[i];
-+ }
-+ CLEAR_BIT(priv->get_mask, GETSET_STATION_ID);
-+ }
-+
-+ if (priv->get_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
-+ if ((RADIO_RFMD_11 == priv->radio_type)
-+ || (RADIO_MAXIM_0D == priv->radio_type)
-+ || (RADIO_RALINK_15 == priv->radio_type)) {
-+ acx_s_read_phy_reg(priv, 0x30, &priv->sensitivity);
-+ } else {
-+ acxlog(L_INIT, "don't know how to get sensitivity "
-+ "for radio type 0x%02X\n", priv->radio_type);
-+ priv->sensitivity = 0;
-+ }
-+ acxlog(L_INIT, "got sensitivity value %u\n", priv->sensitivity);
-+
-+ CLEAR_BIT(priv->get_mask, GETSET_SENSITIVITY);
-+ }
-+
-+ if (priv->get_mask & (GETSET_ANTENNA|GETSET_ALL)) {
-+ u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
-+
-+ memset(antenna, 0, sizeof(antenna));
-+ acx_s_interrogate(priv, antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
-+ priv->antenna = antenna[4];
-+ acxlog(L_INIT, "got antenna value 0x%02X\n", priv->antenna);
-+ CLEAR_BIT(priv->get_mask, GETSET_ANTENNA);
-+ }
-+
-+ if (priv->get_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
-+ if (IS_ACX100(priv)) {
-+ u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
-+
-+ memset(ed_threshold, 0, sizeof(ed_threshold));
-+ acx_s_interrogate(priv, ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
-+ priv->ed_threshold = ed_threshold[4];
-+ } else {
-+ acxlog(L_INIT, "acx111 doesn't support ED\n");
-+ priv->ed_threshold = 0;
-+ }
-+ acxlog(L_INIT, "got Energy Detect (ED) threshold %u\n", priv->ed_threshold);
-+ CLEAR_BIT(priv->get_mask, GETSET_ED_THRESH);
-+ }
-+
-+ if (priv->get_mask & (GETSET_CCA|GETSET_ALL)) {
-+ if (IS_ACX100(priv)) {
-+ u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
-+
-+ memset(cca, 0, sizeof(priv->cca));
-+ acx_s_interrogate(priv, cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
-+ priv->cca = cca[4];
-+ } else {
-+ acxlog(L_INIT, "acx111 doesn't support CCA\n");
-+ priv->cca = 0;
-+ }
-+ acxlog(L_INIT, "got Channel Clear Assessment (CCA) value %u\n", priv->cca);
-+ CLEAR_BIT(priv->get_mask, GETSET_CCA);
-+ }
-+
-+ if (priv->get_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
-+ acx_ie_generic_t dom;
-+
-+ acx_s_interrogate(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
-+ priv->reg_dom_id = dom.m.bytes[0];
-+ /* FIXME: should also set chanmask somehow */
-+ acxlog(L_INIT, "got regulatory domain 0x%02X\n", priv->reg_dom_id);
-+ CLEAR_BIT(priv->get_mask, GETSET_REG_DOMAIN);
-+ }
-+
-+ if (priv->set_mask & (GETSET_STATION_ID|GETSET_ALL)) {
-+ u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
-+ u8 *paddr;
-+
-+ paddr = &stationID[4];
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ /* copy the MAC address we obtained when we noticed
-+ * that the ethernet iface's MAC changed
-+ * to the card (reversed in
-+ * the card!) */
-+ paddr[i] = priv->dev_addr[ETH_ALEN - 1 - i];
-+ }
-+ acx_s_configure(priv, &stationID, ACX1xx_IE_DOT11_STATION_ID);
-+ CLEAR_BIT(priv->set_mask, GETSET_STATION_ID);
-+ }
-+
-+ if (priv->set_mask & (SET_TEMPLATES|GETSET_ALL)) {
-+ acxlog(L_INIT, "updating packet templates\n");
-+ /* Doesn't work for acx100, do it only for acx111 for now */
-+ if (IS_ACX111(priv)) {
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ acx_s_set_probe_request_template(priv);
-+ }
-+ }
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_3_AP:
-+ /* FIXME: why only for AP? STA need probe req templates... */
-+ acx_s_set_beacon_template(priv);
-+ acx_s_set_tim_template(priv);
-+ /* BTW acx111 firmware would not send probe responses
-+ ** if probe request does not have all basic rates flagged
-+ ** by 0x80! Thus firmware does not conform to 802.11,
-+ ** it should ignore 0x80 bit in ratevector from STA.
-+ ** We can 'fix' it by not using this template and
-+ ** sending probe responses by hand. TODO --vda */
-+ acx_s_set_probe_response_template(priv);
-+ }
-+ /* Needed if generated frames are to be emitted at different tx rate now */
-+ acxlog(L_IRQ, "redoing cmd_join_bssid() after template cfg\n");
-+ acx_s_cmd_join_bssid(priv, priv->bssid);
-+ CLEAR_BIT(priv->set_mask, SET_TEMPLATES);
-+ }
-+ if (priv->set_mask & (SET_STA_LIST|GETSET_ALL)) {
-+ acx_lock(priv, flags);
-+ acx_l_sta_list_init(priv);
-+ CLEAR_BIT(priv->set_mask, SET_STA_LIST);
-+ acx_unlock(priv, flags);
-+ }
-+ if (priv->set_mask & (SET_RATE_FALLBACK|GETSET_ALL)) {
-+ u8 rate[4 + ACX1xx_IE_RATE_FALLBACK_LEN];
-+
-+ /* configure to not do fallbacks when not in auto rate mode */
-+ rate[4] = (priv->rate_auto) ? /* priv->txrate_fallback_retries */ 1 : 0;
-+ acxlog(L_INIT, "updating Tx fallback to %u retries\n", rate[4]);
-+ acx_s_configure(priv, &rate, ACX1xx_IE_RATE_FALLBACK);
-+ CLEAR_BIT(priv->set_mask, SET_RATE_FALLBACK);
-+ }
-+ if (priv->set_mask & (GETSET_TXPOWER|GETSET_ALL)) {
-+ acxlog(L_INIT, "updating transmit power: %u dBm\n",
-+ priv->tx_level_dbm);
-+ acx_s_set_tx_level(priv, priv->tx_level_dbm);
-+ CLEAR_BIT(priv->set_mask, GETSET_TXPOWER);
-+ }
-+
-+ if (priv->set_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
-+ acxlog(L_INIT, "updating sensitivity value: %u\n",
-+ priv->sensitivity);
-+ switch (priv->radio_type) {
-+ case RADIO_RFMD_11:
-+ case RADIO_MAXIM_0D:
-+ case RADIO_RALINK_15:
-+ acx_s_write_phy_reg(priv, 0x30, priv->sensitivity);
-+ break;
-+ case RADIO_RADIA_16:
-+ case RADIO_UNKNOWN_17:
-+ acx111_s_sens_radio_16_17(priv);
-+ break;
-+ default:
-+ acxlog(L_INIT, "don't know how to modify sensitivity "
-+ "for radio type 0x%02X\n", priv->radio_type);
-+ }
-+ CLEAR_BIT(priv->set_mask, GETSET_SENSITIVITY);
-+ }
-+
-+ if (priv->set_mask & (GETSET_ANTENNA|GETSET_ALL)) {
-+ /* antenna */
-+ u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
-+
-+ memset(antenna, 0, sizeof(antenna));
-+ antenna[4] = priv->antenna;
-+ acxlog(L_INIT, "updating antenna value: 0x%02X\n",
-+ priv->antenna);
-+ acx_s_configure(priv, &antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
-+ CLEAR_BIT(priv->set_mask, GETSET_ANTENNA);
-+ }
-+
-+ if (priv->set_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
-+ /* ed_threshold */
-+ acxlog(L_INIT, "updating Energy Detect (ED) threshold: %u\n",
-+ priv->ed_threshold);
-+ if (IS_ACX100(priv)) {
-+ u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
-+
-+ memset(ed_threshold, 0, sizeof(ed_threshold));
-+ ed_threshold[4] = priv->ed_threshold;
-+ acx_s_configure(priv, &ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
-+ }
-+ else
-+ acxlog(L_INIT, "acx111 doesn't support ED!\n");
-+ CLEAR_BIT(priv->set_mask, GETSET_ED_THRESH);
-+ }
-+
-+ if (priv->set_mask & (GETSET_CCA|GETSET_ALL)) {
-+ /* CCA value */
-+ acxlog(L_INIT, "updating Channel Clear Assessment "
-+ "(CCA) value: 0x%02X\n", priv->cca);
-+ if (IS_ACX100(priv)) {
-+ u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
-+
-+ memset(cca, 0, sizeof(cca));
-+ cca[4] = priv->cca;
-+ acx_s_configure(priv, &cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
-+ }
-+ else
-+ acxlog(L_INIT, "acx111 doesn't support CCA!\n");
-+ CLEAR_BIT(priv->set_mask, GETSET_CCA);
-+ }
-+
-+ if (priv->set_mask & (GETSET_LED_POWER|GETSET_ALL)) {
-+ /* Enable Tx */
-+ acxlog(L_INIT, "updating power LED status: %u\n", priv->led_power);
-+
-+ acx_lock(priv, flags);
-+ if (IS_PCI(priv))
-+ acx_l_power_led(priv, priv->led_power);
-+ CLEAR_BIT(priv->set_mask, GETSET_LED_POWER);
-+ acx_unlock(priv, flags);
-+ }
-+
-+/* this seems to cause Tx lockup after some random time (Tx error 0x20),
-+ * so let's disable it for now until further investigation */
-+/* Maybe fixed now after locking is fixed. Need to retest */
-+#ifdef POWER_SAVE_80211
-+ if (priv->set_mask & (GETSET_POWER_80211|GETSET_ALL)) {
-+ acx100_ie_powermgmt_t pm;
-+
-+ /* change 802.11 power save mode settings */
-+ acxlog(L_INIT, "updating 802.11 power save mode settings: "
-+ "wakeup_cfg 0x%02X, listen interval %u, "
-+ "options 0x%02X, hangover period %u, "
-+ "enhanced_ps_transition_time %d\n",
-+ priv->ps_wakeup_cfg, priv->ps_listen_interval,
-+ priv->ps_options, priv->ps_hangover_period,
-+ priv->ps_enhanced_transition_time);
-+ acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
-+ acxlog(L_INIT, "Previous PS mode settings: wakeup_cfg 0x%02X, "
-+ "listen interval %u, options 0x%02X, "
-+ "hangover period %u, "
-+ "enhanced_ps_transition_time %d\n",
-+ pm.wakeup_cfg, pm.listen_interval, pm.options,
-+ pm.hangover_period, pm.enhanced_ps_transition_time);
-+ pm.wakeup_cfg = priv->ps_wakeup_cfg;
-+ pm.listen_interval = priv->ps_listen_interval;
-+ pm.options = priv->ps_options;
-+ pm.hangover_period = priv->ps_hangover_period;
-+ pm.enhanced_ps_transition_time = cpu_to_le16(priv->ps_enhanced_transition_time);
-+ acx_s_configure(priv, &pm, ACX100_IE_POWER_MGMT);
-+ acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
-+ acxlog(L_INIT, "wakeup_cfg: 0x%02X\n", pm.wakeup_cfg);
-+ acx_s_msleep(40);
-+ acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
-+ acxlog(L_INIT, "power save mode change %s\n",
-+ (pm.wakeup_cfg & PS_CFG_PENDING) ? "FAILED" : "was successful");
-+ /* FIXME: maybe verify via PS_CFG_PENDING bit here
-+ * that power save mode change was successful. */
-+ /* FIXME: we shouldn't trigger a scan immediately after
-+ * fiddling with power save mode (since the firmware is sending
-+ * a NULL frame then). Does this need locking?? */
-+ CLEAR_BIT(priv->set_mask, GETSET_POWER_80211);
-+ }
-+#endif
-+
-+ if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
-+ /* channel */
-+ acxlog(L_INIT, "updating channel to: %u\n", priv->channel);
-+ CLEAR_BIT(priv->set_mask, GETSET_CHANNEL);
-+ }
-+
-+ if (priv->set_mask & (GETSET_TX|GETSET_ALL)) {
-+ /* set Tx */
-+ acxlog(L_INIT, "updating: %s Tx\n",
-+ priv->tx_disabled ? "disable" : "enable");
-+ if (priv->tx_disabled)
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
-+ /* ^ */
-+ /* FIXME: this used to be 1, but since we don't transfer a parameter... */
-+ else
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1);
-+ CLEAR_BIT(priv->set_mask, GETSET_TX);
-+ }
-+
-+ if (priv->set_mask & (GETSET_RX|GETSET_ALL)) {
-+ /* Enable Rx */
-+ acxlog(L_INIT, "updating: enable Rx on channel: %u\n",
-+ priv->channel);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1);
-+ CLEAR_BIT(priv->set_mask, GETSET_RX);
-+ }
-+
-+ if (priv->set_mask & (GETSET_RETRY|GETSET_ALL)) {
-+ u8 short_retry[4 + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN];
-+ u8 long_retry[4 + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN];
-+
-+ acxlog(L_INIT, "updating short retry limit: %u, long retry limit: %u\n",
-+ priv->short_retry, priv->long_retry);
-+ short_retry[0x4] = priv->short_retry;
-+ long_retry[0x4] = priv->long_retry;
-+ acx_s_configure(priv, &short_retry, ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT);
-+ acx_s_configure(priv, &long_retry, ACX1xx_IE_DOT11_LONG_RETRY_LIMIT);
-+ CLEAR_BIT(priv->set_mask, GETSET_RETRY);
-+ }
-+
-+ if (priv->set_mask & (SET_MSDU_LIFETIME|GETSET_ALL)) {
-+ u8 xmt_msdu_lifetime[4 + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN];
-+
-+ acxlog(L_INIT, "updating tx MSDU lifetime: %u\n",
-+ priv->msdu_lifetime);
-+ *(u32 *)&xmt_msdu_lifetime[4] = cpu_to_le32((u32)priv->msdu_lifetime);
-+ acx_s_configure(priv, &xmt_msdu_lifetime, ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME);
-+ CLEAR_BIT(priv->set_mask, SET_MSDU_LIFETIME);
-+ }
-+
-+ if (priv->set_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
-+ /* reg_domain */
-+ acx_ie_generic_t dom;
-+ unsigned mask;
-+
-+ acxlog(L_INIT, "updating regulatory domain: 0x%02X\n",
-+ priv->reg_dom_id);
-+ for (i = 0; i < sizeof(reg_domain_ids); i++)
-+ if (reg_domain_ids[i] == priv->reg_dom_id)
-+ break;
-+
-+ if (sizeof(reg_domain_ids) == i) {
-+ acxlog(L_INIT, "Invalid or unsupported regulatory "
-+ "domain 0x%02X specified, falling back to "
-+ "FCC (USA)! Please report if this sounds "
-+ "fishy!\n", priv->reg_dom_id);
-+ i = 0;
-+ priv->reg_dom_id = reg_domain_ids[i];
-+ }
-+
-+ priv->reg_dom_chanmask = reg_domain_channel_masks[i];
-+ dom.m.bytes[0] = priv->reg_dom_id;
-+ acx_s_configure(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
-+
-+ mask = (1 << (priv->channel - 1));
-+ if (!(priv->reg_dom_chanmask & mask)) {
-+ /* hmm, need to adjust our channel to reside within domain */
-+ mask = 1;
-+ for (i = 1; i <= 14; i++) {
-+ if (priv->reg_dom_chanmask & mask) {
-+ printk("%s: adjusting "
-+ "selected channel from %d "
-+ "to %d due to new regulatory "
-+ "domain\n", priv->netdev->name,
-+ priv->channel, i);
-+ priv->channel = i;
-+ break;
-+ }
-+ mask <<= 1;
-+ }
-+ }
-+ CLEAR_BIT(priv->set_mask, GETSET_REG_DOMAIN);
-+ }
-+
-+ if (priv->set_mask & (GETSET_MODE|GETSET_ALL)) {
-+ priv->netdev->type = ARPHRD_ETHER;
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_3_AP:
-+
-+ acx_lock(priv, flags);
-+ acx_l_sta_list_init(priv);
-+ priv->aid = 0;
-+ priv->ap_client = NULL;
-+ MAC_COPY(priv->bssid, priv->dev_addr);
-+ /* this basically says "we're connected" */
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-+ acx_unlock(priv, flags);
-+
-+ acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
-+ /* start sending beacons */
-+ acx_s_cmd_join_bssid(priv, priv->bssid);
-+ break;
-+ case ACX_MODE_MONITOR:
-+ /* priv->netdev->type = ARPHRD_ETHER; */
-+ /* priv->netdev->type = ARPHRD_IEEE80211; */
-+ priv->netdev->type = ARPHRD_IEEE80211_PRISM;
-+ acx111_s_feature_on(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
-+ /* this stops beacons */
-+ acx_s_cmd_join_bssid(priv, priv->bssid);
-+ /* this basically says "we're connected" */
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-+ SET_BIT(priv->set_mask, SET_RXCONFIG|SET_WEP_OPTIONS);
-+ break;
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
-+ priv->aid = 0;
-+ priv->ap_client = NULL;
-+ /* we want to start looking for peer or AP */
-+ start_scan = 1;
-+ break;
-+ case ACX_MODE_OFF:
-+ /* TODO: disable RX/TX, stop any scanning activity etc: */
-+ /* priv->tx_disabled = 1; */
-+ /* SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX); */
-+
-+ /* This stops beacons (invalid macmode...) */
-+ acx_s_cmd_join_bssid(priv, priv->bssid);
-+ acx_set_status(priv, ACX_STATUS_0_STOPPED);
-+ break;
-+ }
-+ CLEAR_BIT(priv->set_mask, GETSET_MODE);
-+ }
-+
-+ if (priv->set_mask & (SET_RXCONFIG|GETSET_ALL)) {
-+ acx_s_initialize_rx_config(priv);
-+ CLEAR_BIT(priv->set_mask, SET_RXCONFIG);
-+ }
-+
-+ if (priv->set_mask & (GETSET_RESCAN|GETSET_ALL)) {
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ start_scan = 1;
-+ break;
-+ }
-+ CLEAR_BIT(priv->set_mask, GETSET_RESCAN);
-+ }
-+
-+ if (priv->set_mask & (GETSET_WEP|GETSET_ALL)) {
-+ /* encode */
-+
-+ ie_dot11WEPDefaultKeyID_t dkey;
-+#ifdef DEBUG_WEP
-+ struct {
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u8 val ACX_PACKED;
-+ } keyindic;
-+#endif
-+ acxlog(L_INIT, "updating WEP key settings\n");
-+
-+ acx_s_set_wepkey(priv);
-+
-+ dkey.KeyID = priv->wep_current_index;
-+ acxlog(L_INIT, "setting WEP key %u as default\n", dkey.KeyID);
-+ acx_s_configure(priv, &dkey, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET);
-+#ifdef DEBUG_WEP
-+ keyindic.val = 3;
-+ acx_s_configure(priv, &keyindic, ACX111_IE_KEY_CHOOSE);
-+#endif
-+ start_scan = 1;
-+ CLEAR_BIT(priv->set_mask, GETSET_WEP);
-+ }
-+
-+ if (priv->set_mask & (SET_WEP_OPTIONS|GETSET_ALL)) {
-+ acx100_ie_wep_options_t options;
-+
-+ if (IS_ACX111(priv)) {
-+ acxlog(L_DEBUG, "setting WEP Options for acx111 is not supported\n");
-+ } else {
-+ acxlog(L_INIT, "setting WEP Options\n");
-+
-+ /* let's choose maximum setting: 4 default keys,
-+ * plus 10 other keys: */
-+ options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
-+ /* don't decrypt default key only,
-+ * don't override decryption: */
-+ options.WEPOption = 0;
-+ if (priv->mode == ACX_MODE_MONITOR) {
-+ /* don't decrypt default key only,
-+ * override decryption mechanism: */
-+ options.WEPOption = 2;
-+ }
-+
-+ acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
-+ }
-+ CLEAR_BIT(priv->set_mask, SET_WEP_OPTIONS);
-+ }
-+
-+ /* Rescan was requested */
-+ if (start_scan) {
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ /* We can avoid clearing list if join code
-+ ** will be a bit more clever about not picking
-+ ** 'bad' AP over and over again */
-+ acx_lock(priv, flags);
-+ priv->ap_client = NULL;
-+ acx_l_sta_list_init(priv);
-+ acx_set_status(priv, ACX_STATUS_1_SCANNING);
-+ acx_unlock(priv, flags);
-+
-+ acx_s_cmd_start_scan(priv);
-+ }
-+ }
-+
-+ /* debug, rate, and nick don't need any handling */
-+ /* what about sniffing mode?? */
-+
-+ acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X - after update\n",
-+ priv->get_mask, priv->set_mask);
-+
-+/* end: */
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+void
-+acx_s_initialize_rx_config(wlandevice_t *priv)
-+{
-+ struct {
-+ u16 id ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u16 rx_cfg1 ACX_PACKED;
-+ u16 rx_cfg2 ACX_PACKED;
-+ } cfg;
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_OFF:
-+ priv->rx_config_1 = (u16) (0
-+ /* | RX_CFG1_INCLUDE_RXBUF_HDR */
-+ /* | RX_CFG1_FILTER_SSID */
-+ /* | RX_CFG1_FILTER_BCAST */
-+ /* | RX_CFG1_RCV_MC_ADDR1 */
-+ /* | RX_CFG1_RCV_MC_ADDR0 */
-+ /* | RX_CFG1_FILTER_ALL_MULTI */
-+ /* | RX_CFG1_FILTER_BSSID */
-+ /* | RX_CFG1_FILTER_MAC */
-+ /* | RX_CFG1_RCV_PROMISCUOUS */
-+ /* | RX_CFG1_INCLUDE_FCS */
-+ /* | RX_CFG1_INCLUDE_PHY_HDR */
-+ );
-+ priv->rx_config_2 = (u16) (0
-+ /*| RX_CFG2_RCV_ASSOC_REQ */
-+ /*| RX_CFG2_RCV_AUTH_FRAMES */
-+ /*| RX_CFG2_RCV_BEACON_FRAMES */
-+ /*| RX_CFG2_RCV_CONTENTION_FREE */
-+ /*| RX_CFG2_RCV_CTRL_FRAMES */
-+ /*| RX_CFG2_RCV_DATA_FRAMES */
-+ /*| RX_CFG2_RCV_BROKEN_FRAMES */
-+ /*| RX_CFG2_RCV_MGMT_FRAMES */
-+ /*| RX_CFG2_RCV_PROBE_REQ */
-+ /*| RX_CFG2_RCV_PROBE_RESP */
-+ /*| RX_CFG2_RCV_ACK_FRAMES */
-+ /*| RX_CFG2_RCV_OTHER */
-+ );
-+ break;
-+ case ACX_MODE_MONITOR:
-+ priv->rx_config_1 = (u16) (0
-+ /* | RX_CFG1_INCLUDE_RXBUF_HDR */
-+ /* | RX_CFG1_FILTER_SSID */
-+ /* | RX_CFG1_FILTER_BCAST */
-+ /* | RX_CFG1_RCV_MC_ADDR1 */
-+ /* | RX_CFG1_RCV_MC_ADDR0 */
-+ /* | RX_CFG1_FILTER_ALL_MULTI */
-+ /* | RX_CFG1_FILTER_BSSID */
-+ /* | RX_CFG1_FILTER_MAC */
-+ | RX_CFG1_RCV_PROMISCUOUS
-+ /* | RX_CFG1_INCLUDE_FCS */
-+ /* | RX_CFG1_INCLUDE_PHY_HDR */
-+ );
-+ priv->rx_config_2 = (u16) (0
-+ | RX_CFG2_RCV_ASSOC_REQ
-+ | RX_CFG2_RCV_AUTH_FRAMES
-+ | RX_CFG2_RCV_BEACON_FRAMES
-+ | RX_CFG2_RCV_CONTENTION_FREE
-+ | RX_CFG2_RCV_CTRL_FRAMES
-+ | RX_CFG2_RCV_DATA_FRAMES
-+ | RX_CFG2_RCV_BROKEN_FRAMES
-+ | RX_CFG2_RCV_MGMT_FRAMES
-+ | RX_CFG2_RCV_PROBE_REQ
-+ | RX_CFG2_RCV_PROBE_RESP
-+ | RX_CFG2_RCV_ACK_FRAMES
-+ | RX_CFG2_RCV_OTHER
-+ );
-+ break;
-+ default:
-+ priv->rx_config_1 = (u16) (0
-+ /* | RX_CFG1_INCLUDE_RXBUF_HDR */
-+ /* | RX_CFG1_FILTER_SSID */
-+ /* | RX_CFG1_FILTER_BCAST */
-+ /* | RX_CFG1_RCV_MC_ADDR1 */
-+ /* | RX_CFG1_RCV_MC_ADDR0 */
-+ /* | RX_CFG1_FILTER_ALL_MULTI */
-+ /* | RX_CFG1_FILTER_BSSID */
-+ | RX_CFG1_FILTER_MAC
-+ /* | RX_CFG1_RCV_PROMISCUOUS */
-+ /* | RX_CFG1_INCLUDE_FCS */
-+ /* | RX_CFG1_INCLUDE_PHY_HDR */
-+ );
-+ priv->rx_config_2 = (u16) (0
-+ | RX_CFG2_RCV_ASSOC_REQ
-+ | RX_CFG2_RCV_AUTH_FRAMES
-+ | RX_CFG2_RCV_BEACON_FRAMES
-+ | RX_CFG2_RCV_CONTENTION_FREE
-+ | RX_CFG2_RCV_CTRL_FRAMES
-+ | RX_CFG2_RCV_DATA_FRAMES
-+ /*| RX_CFG2_RCV_BROKEN_FRAMES */
-+ | RX_CFG2_RCV_MGMT_FRAMES
-+ | RX_CFG2_RCV_PROBE_REQ
-+ | RX_CFG2_RCV_PROBE_RESP
-+ /*| RX_CFG2_RCV_ACK_FRAMES */
-+ | RX_CFG2_RCV_OTHER
-+ );
-+ break;
-+ }
-+#ifdef DEBUG_WEP
-+ if (IS_ACX100(priv))
-+ /* only ACX100 supports that */
-+#endif
-+ priv->rx_config_1 |= RX_CFG1_INCLUDE_RXBUF_HDR;
-+
-+ acxlog(L_INIT, "setting RXconfig to %04X:%04X\n",
-+ priv->rx_config_1, priv->rx_config_2);
-+ cfg.rx_cfg1 = cpu_to_le16(priv->rx_config_1);
-+ cfg.rx_cfg2 = cpu_to_le16(priv->rx_config_2);
-+ acx_s_configure(priv, &cfg, ACX1xx_IE_RXCONFIG);
-+}
-+
-+
-+/***********************************************************************
-+** acx_e_after_interrupt_task
-+*/
-+static int
-+acx_s_recalib_radio(wlandevice_t *priv)
-+{
-+ if (IS_ACX111(priv)) {
-+ acx111_cmd_radiocalib_t cal;
-+
-+ printk("%s: recalibrating radio\n", priv->netdev->name);
-+ /* automatic recalibration, choose all methods: */
-+ cal.methods = cpu_to_le32(0x8000000f);
-+ /* automatic recalibration every 60 seconds (value in TUs)
-+ * FIXME: what is the firmware default here?? */
-+ cal.interval = cpu_to_le32(58594);
-+ return acx_s_issue_cmd_timeo(priv, ACX111_CMD_RADIOCALIB,
-+ &cal, sizeof(cal), CMD_TIMEOUT_MS(100));
-+ } else {
-+ if (/* (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0)) &&
-+ (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0)) && */
-+ (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1)) &&
-+ (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1)) )
-+ return OK;
-+ return NOT_OK;
-+ }
-+}
-+
-+static void
-+acx_s_after_interrupt_recalib(wlandevice_t *priv)
-+{
-+ int res;
-+
-+ /* this helps with ACX100 at least;
-+ * hopefully ACX111 also does a
-+ * recalibration here */
-+
-+ /* clear flag beforehand, since we want to make sure
-+ * it's cleared; then only set it again on specific circumstances */
-+ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-+
-+ /* better wait a bit between recalibrations to
-+ * prevent overheating due to torturing the card
-+ * into working too long despite high temperature
-+ * (just a safety measure) */
-+ if (priv->recalib_time_last_success
-+ && time_before(jiffies, priv->recalib_time_last_success
-+ + RECALIB_PAUSE * 60 * HZ)) {
-+ priv->recalib_msg_ratelimit++;
-+ if (priv->recalib_msg_ratelimit <= 5)
-+ printk("%s: less than " STRING(RECALIB_PAUSE)
-+ " minutes since last radio recalibration, "
-+ "not recalibrating (maybe card is too hot?)\n",
-+ priv->netdev->name);
-+ if (priv->recalib_msg_ratelimit == 5)
-+ printk("disabling above message\n");
-+ return;
-+ }
-+
-+ priv->recalib_msg_ratelimit = 0;
-+
-+ /* note that commands sometimes fail (card busy),
-+ * so only clear flag if we were fully successful */
-+ res = acx_s_recalib_radio(priv);
-+ if (res == OK) {
-+ printk("%s: successfully recalibrated radio\n",
-+ priv->netdev->name);
-+ priv->recalib_time_last_success = jiffies;
-+ priv->recalib_failure_count = 0;
-+ } else {
-+ /* failed: resubmit, but only limited
-+ * amount of times within some time range
-+ * to prevent endless loop */
-+
-+ priv->recalib_time_last_success = 0; /* we failed */
-+
-+ /* if some time passed between last
-+ * attempts, then reset failure retry counter
-+ * to be able to do next recalib attempt */
-+ if (time_after(jiffies, priv->recalib_time_last_attempt + HZ))
-+ priv->recalib_failure_count = 0;
-+
-+ if (++priv->recalib_failure_count <= 5) {
-+ priv->recalib_time_last_attempt = jiffies;
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-+ }
-+ }
-+}
-+
-+static void
-+acx_e_after_interrupt_task(void *data)
-+{
-+ netdevice_t *dev = (netdevice_t *) data;
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ if (!priv->after_interrupt_jobs)
-+ goto end; /* no jobs to do */
-+
-+#if TX_CLEANUP_IN_SOFTIRQ
-+ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_TX_CLEANUP) {
-+ acx_lock(priv, flags);
-+ acx_l_clean_tx_desc(priv);
-+ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_TX_CLEANUP);
-+ acx_unlock(priv, flags);
-+ }
-+#endif
-+ /* we see lotsa tx errors */
-+ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_RADIO_RECALIB) {
-+ acx_s_after_interrupt_recalib(priv);
-+ }
-+
-+ /* a poor interrupt code wanted to do update_card_settings() */
-+ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_UPDATE_CARD_CFG) {
-+ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
-+ acx_s_update_card_settings(priv, 0, 0);
-+ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
-+ }
-+
-+ /* 1) we detected that no Scan_Complete IRQ came from fw, or
-+ ** 2) we found too many STAs */
-+ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_STOP_SCAN) {
-+ acxlog(L_IRQ, "sending a stop scan cmd...\n");
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_STOP_SCAN, NULL, 0);
-+ /* HACK: set the IRQ bit, since we won't get a
-+ * scan complete IRQ any more on ACX111 (works on ACX100!),
-+ * since _we_, not a fw, have stopped the scan */
-+ SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
-+ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_STOP_SCAN);
-+ }
-+
-+ /* either fw sent Scan_Complete or we detected that
-+ ** no Scan_Complete IRQ came from fw. Finish scanning,
-+ ** pick join partner if any */
-+ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_COMPLETE_SCAN) {
-+ if (priv->status == ACX_STATUS_1_SCANNING) {
-+ if (OK != acx_s_complete_scan(priv)) {
-+ SET_BIT(priv->after_interrupt_jobs,
-+ ACX_AFTER_IRQ_RESTART_SCAN);
-+ }
-+ } else {
-+ /* + scan kills current join status - restore it
-+ ** (do we need it for STA?) */
-+ /* + does it happen only with active scans?
-+ ** active and passive scans? ALL scans including
-+ ** background one? */
-+ /* + was not verified that everything is restored
-+ ** (but at least we start to emit beacons again) */
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_3_AP:
-+ acxlog(L_IRQ, "redoing cmd_join_bssid() after scan\n");
-+ acx_s_cmd_join_bssid(priv, priv->bssid);
-+ }
-+ }
-+ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_COMPLETE_SCAN);
-+ }
-+
-+ /* STA auth or assoc timed out, start over again */
-+ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_RESTART_SCAN) {
-+ acxlog(L_IRQ, "sending a start_scan cmd...\n");
-+ acx_s_cmd_start_scan(priv);
-+ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_RESTART_SCAN);
-+ }
-+
-+ /* whee, we got positive assoc response! 8) */
-+ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_ASSOCIATE) {
-+ acx_ie_generic_t pdr;
-+ /* tiny race window exists, checking that we still a STA */
-+ switch (priv->mode) {
-+ case ACX_MODE_2_STA:
-+ pdr.m.aid = cpu_to_le16(priv->aid);
-+ acx_s_configure(priv, &pdr, ACX1xx_IE_ASSOC_ID);
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
-+ acxlog(L_ASSOC|L_DEBUG, "ASSOCIATED!\n");
-+ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_ASSOCIATE);
-+ }
-+ }
-+end:
-+ acx_sem_unlock(priv);
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx_schedule_after_interrupt_task
-+**
-+** Schedule the call of the after_interrupt method after leaving
-+** the interrupt context.
-+*/
-+void
-+acx_schedule_after_interrupt_task(wlandevice_t *priv, unsigned int set_flag)
-+{
-+ SET_BIT(priv->after_interrupt_jobs, set_flag);
-+ SCHEDULE_WORK(&priv->after_interrupt_task);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+void
-+acx_init_task_scheduler(wlandevice_t *priv)
-+{
-+ /* configure task scheduler */
-+ INIT_WORK(&priv->after_interrupt_task, acx_e_after_interrupt_task,
-+ priv->netdev);
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_start
-+*/
-+void
-+acx_s_start(wlandevice_t *priv)
-+{
-+ FN_ENTER;
-+
-+ /*
-+ * Ok, now we do everything that can possibly be done with ioctl
-+ * calls to make sure that when it was called before the card
-+ * was up we get the changes asked for
-+ */
-+
-+ SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST|GETSET_WEP
-+ |GETSET_TXPOWER|GETSET_ANTENNA|GETSET_ED_THRESH|GETSET_CCA
-+ |GETSET_REG_DOMAIN|GETSET_MODE|GETSET_CHANNEL
-+ |GETSET_TX|GETSET_RX);
-+
-+ acxlog(L_INIT, "updating initial settings on iface activation...\n");
-+ acx_s_update_card_settings(priv, 0, 0);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx_update_capabilities
-+*/
-+void
-+acx_update_capabilities(wlandevice_t *priv)
-+{
-+ u16 cap = 0;
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_3_AP:
-+ SET_BIT(cap, WF_MGMT_CAP_ESS); break;
-+ case ACX_MODE_0_ADHOC:
-+ SET_BIT(cap, WF_MGMT_CAP_IBSS); break;
-+ /* other types of stations do not emit beacons */
-+ }
-+
-+ if (priv->wep_restricted) {
-+ SET_BIT(cap, WF_MGMT_CAP_PRIVACY);
-+ }
-+ if (priv->capab_short) {
-+ SET_BIT(cap, WF_MGMT_CAP_SHORT);
-+ }
-+ if (priv->capab_pbcc) {
-+ SET_BIT(cap, WF_MGMT_CAP_PBCC);
-+ }
-+ if (priv->capab_agility) {
-+ SET_BIT(cap, WF_MGMT_CAP_AGILITY);
-+ }
-+ acxlog(L_DEBUG, "caps updated from 0x%04X to 0x%04X\n",
-+ priv->capabilities, cap);
-+ priv->capabilities = cap;
-+}
-+
-+#ifdef UNUSED
-+/***********************************************************************
-+** FIXME: check whether this function is indeed acx111 only,
-+** rename ALL relevant definitions to indicate actual card scope!
-+*/
-+void
-+acx111_s_read_configoption(wlandevice_t *priv)
-+{
-+ acx111_ie_configoption_t co, co2;
-+ int i;
-+ const u8 *pEle;
-+
-+ if (OK != acx_s_interrogate(priv, &co, ACX111_IE_CONFIG_OPTIONS) ) {
-+ return;
-+ };
-+ if (!(acx_debug & L_DEBUG))
-+ return;
-+
-+ memcpy(&co2.configoption_fixed, &co.configoption_fixed,
-+ sizeof(co.configoption_fixed));
-+
-+ pEle = (u8 *)&co.configoption_fixed + sizeof(co.configoption_fixed) - 4;
-+
-+ co2.antennas.type = pEle[0];
-+ co2.antennas.len = pEle[1];
-+ printk("AntennaID:%02X Len:%02X Data:",
-+ co2.antennas.type, co2.antennas.len);
-+ for (i = 0; i < pEle[1]; i++) {
-+ co2.antennas.list[i] = pEle[i+2];
-+ printk("%02X ", pEle[i+2]);
-+ }
-+ printk("\n");
-+
-+ pEle += pEle[1] + 2;
-+ co2.power_levels.type = pEle[0];
-+ co2.power_levels.len = pEle[1];
-+ printk("PowerLevelID:%02X Len:%02X Data:",
-+ co2.power_levels.type, co2.power_levels.len);
-+ for (i = 0; i < pEle[1]*2; i++) {
-+ co2.power_levels.list[i] = pEle[i+2];
-+ printk("%02X ", pEle[i+2]);
-+ }
-+ printk("\n");
-+
-+ pEle += pEle[1]*2 + 2;
-+ co2.data_rates.type = pEle[0];
-+ co2.data_rates.len = pEle[1];
-+ printk("DataRatesID:%02X Len:%02X Data:",
-+ co2.data_rates.type, co2.data_rates.len);
-+ for (i = 0; i < pEle[1]; i++) {
-+ co2.data_rates.list[i] = pEle[i+2];
-+ printk("%02X ", pEle[i+2]);
-+ }
-+ printk("\n");
-+
-+ pEle += pEle[1] + 2;
-+ co2.domains.type = pEle[0];
-+ co2.domains.len = pEle[1];
-+ printk("DomainID:%02X Len:%02X Data:",
-+ co2.domains.type, co2.domains.len);
-+ for (i = 0; i < pEle[1]; i++) {
-+ co2.domains.list[i] = pEle[i+2];
-+ printk("%02X ", pEle[i+2]);
-+ }
-+ printk("\n");
-+
-+ pEle += pEle[1] + 2;
-+ co2.product_id.type = pEle[0];
-+ co2.product_id.len = pEle[1];
-+ for (i = 0; i < pEle[1]; i++) {
-+ co2.product_id.list[i] = pEle[i+2];
-+ }
-+ printk("ProductID:%02X Len:%02X Data:%.*s\n",
-+ co2.product_id.type, co2.product_id.len,
-+ co2.product_id.len, (char *)co2.product_id.list);
-+
-+ pEle += pEle[1] + 2;
-+ co2.manufacturer.type = pEle[0];
-+ co2.manufacturer.len = pEle[1];
-+ for (i = 0; i < pEle[1]; i++) {
-+ co2.manufacturer.list[i] = pEle[i+2];
-+ }
-+ printk("ManufacturerID:%02X Len:%02X Data:%.*s\n",
-+ co2.manufacturer.type, co2.manufacturer.len,
-+ co2.manufacturer.len, (char *)co2.manufacturer.list);
-+/*
-+ printk("EEPROM part:\n");
-+ for (i=0; i<58; i++) {
-+ printk("%02X =======> 0x%02X\n",
-+ i, (u8 *)co.configoption_fixed.NVSv[i-2]);
-+ }
-+*/
-+}
-+#endif
-+
-+
-+/***********************************************************************
-+*/
-+static int __init
-+acx_e_init_module(void)
-+{
-+ int r1;
-+
-+ acx_struct_size_check();
-+
-+ printk("acx: this driver is still EXPERIMENTAL\n"
-+ "acx: reading README file and/or Craig's HOWTO is "
-+ "recommended, visit http://acx100.sf.net in case "
-+ "of further questions/discussion\n");
-+
-+#if defined(CONFIG_ACX_CFI)
-+ r1 = acxcfi_e_init_module();
-+#elif defined(CONFIG_ACX_PCI)
-+ r1 = acxpci_e_init_module();
-+#elif defined(CONFIG_ACX_USB)
-+ r1 = acxusb_e_init_module();
-+#else
-+ r1 = -EINVAL;
-+#endif
-+ if (r1) /* both failed! */
-+ return r1;
-+ /* return success if at least one succeeded */
-+ return 0;
-+}
-+
-+static void __exit
-+acx_e_cleanup_module(void)
-+{
-+#if defined(CONFIG_ACX_PCI)
-+ acxcfi_e_cleanup_module();
-+#elif defined(CONFIG_ACX_PCI)
-+ acxpci_e_cleanup_module();
-+#elif defined(CONFIG_ACX_USB)
-+ acxusb_e_cleanup_module();
-+#endif
-+}
-+
-+module_init(acx_e_init_module)
-+module_exit(acx_e_cleanup_module)
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/conv.c bt_kernel/drivers/net/wireless/tiacx/conv.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/conv.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/conv.c 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,508 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/skbuff.h>
-+#include <linux/if_arp.h>
-+#include <linux/etherdevice.h>
-+#include <linux/wireless.h>
-+#if WIRELESS_EXT >= 13
-+#include <net/iw_handler.h>
-+#endif
-+
-+#include "acx.h"
-+
-+
-+/*----------------------------------------------------------------
-+* proto_is_stt
-+*
-+* Searches the 802.1h Selective Translation Table for a given
-+* protocol.
-+*
-+* Arguments:
-+* prottype protocol number (in host order) to search for.
-+*
-+* Returns:
-+* 1 - if the table is empty or a match is found.
-+* 0 - if the table is non-empty and a match is not found.
-+*
-+* Comment:
-+* Based largely on p80211conv.c of the linux-wlan-ng project
-+*----------------------------------------------------------------*/
-+static inline int
-+proto_is_stt(unsigned int proto)
-+{
-+ /* Always return found for now. This is the behavior used by the */
-+ /* Zoom Win95 driver when 802.1h mode is selected */
-+ /* TODO: If necessary, add an actual search we'll probably
-+ need this to match the CMAC's way of doing things.
-+ Need to do some testing to confirm.
-+ */
-+
-+ if (proto == 0x80f3) /* APPLETALK */
-+ return 1;
-+
-+ return 0;
-+/* return ((prottype == ETH_P_AARP) || (prottype == ETH_P_IPX)); */
-+}
-+
-+/* Helpers */
-+
-+static inline void
-+store_llc_snap(struct wlan_llc *llc)
-+{
-+ llc->dsap = 0xaa; /* SNAP, see IEEE 802 */
-+ llc->ssap = 0xaa;
-+ llc->ctl = 0x03;
-+}
-+static inline int
-+llc_is_snap(const struct wlan_llc *llc)
-+{
-+ return (llc->dsap == 0xaa)
-+ && (llc->ssap == 0xaa)
-+ && (llc->ctl == 0x03);
-+}
-+static inline void
-+store_oui_rfc1042(struct wlan_snap *snap)
-+{
-+ snap->oui[0] = 0;
-+ snap->oui[1] = 0;
-+ snap->oui[2] = 0;
-+}
-+static inline int
-+oui_is_rfc1042(const struct wlan_snap *snap)
-+{
-+ return (snap->oui[0] == 0)
-+ && (snap->oui[1] == 0)
-+ && (snap->oui[2] == 0);
-+}
-+static inline void
-+store_oui_8021h(struct wlan_snap *snap)
-+{
-+ snap->oui[0] = 0;
-+ snap->oui[1] = 0;
-+ snap->oui[2] = 0xf8;
-+}
-+static inline int
-+oui_is_8021h(const struct wlan_snap *snap)
-+{
-+ return (snap->oui[0] == 0)
-+ && (snap->oui[1] == 0)
-+ && (snap->oui[2] == 0xf8);
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_ether_to_txbuf
-+*
-+* Uses the contents of the ether frame to build the elements of
-+* the 802.11 frame.
-+*
-+* We don't actually set up the frame header here. That's the
-+* MAC's job. We're only handling conversion of DIXII or 802.3+LLC
-+* frames to something that works with 802.11.
-+*
-+* Comment:
-+* Based largely on p80211conv.c of the linux-wlan-ng project
-+*----------------------------------------------------------------*/
-+int
-+acx_l_ether_to_txbuf(wlandevice_t *priv, void *txbuf, const struct sk_buff *skb)
-+{
-+ struct wlan_hdr_a3 *w_hdr;
-+ struct wlan_ethhdr *e_hdr;
-+ struct wlan_llc *e_llc;
-+ struct wlan_snap *e_snap;
-+ const u8 *a1, *a3;
-+ int header_len, payload_len;
-+ int result = -1;
-+ /* protocol type or data length, depending on whether
-+ * DIX or 802.3 ethernet format */
-+ u16 proto;
-+ u16 fc;
-+
-+ FN_ENTER;
-+
-+ if (unlikely(!skb->len)) {
-+ acxlog(L_DEBUG, "zero-length skb!\n");
-+ goto end;
-+ }
-+
-+ w_hdr = (struct wlan_hdr_a3*)txbuf;
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_MONITOR:
-+ /* NB: one day we might want to play with DESC_CTL2_FCS
-+ ** Will need to stop doing "- WLAN_FCS_LEN" here then */
-+ if (skb->len >= WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_FCS_LEN) {
-+ printk("%s: can't tx oversized frame (%d bytes)\n",
-+ priv->netdev->name, skb->len);
-+ goto end;
-+ }
-+ memcpy(w_hdr, skb->data, skb->len);
-+ result = skb->len;
-+ goto end;
-+ }
-+
-+ /* step 1: classify ether frame, DIX or 802.3? */
-+ e_hdr = (wlan_ethhdr_t *)skb->data;
-+ proto = ntohs(e_hdr->type);
-+ if (proto <= 1500) {
-+ acxlog(L_DEBUG, "tx: 802.3 len: %d\n", skb->len);
-+ /* codes <= 1500 reserved for 802.3 lengths */
-+ /* it's 802.3, pass ether payload unchanged, */
-+ /* trim off ethernet header and copy payload to txdesc */
-+ header_len = WLAN_HDR_A3_LEN;
-+ } else {
-+ /* it's DIXII, time for some conversion */
-+ /* Create 802.11 packet. Header also contains llc and snap. */
-+
-+ acxlog(L_DEBUG, "tx: DIXII len: %d\n", skb->len);
-+
-+ /* size of header is 802.11 header + llc + snap */
-+ header_len = WLAN_HDR_A3_LEN + sizeof(wlan_llc_t) + sizeof(wlan_snap_t);
-+ /* llc is located behind the 802.11 header */
-+ e_llc = (wlan_llc_t*)(w_hdr + 1);
-+ /* snap is located behind the llc */
-+ e_snap = (wlan_snap_t*)(e_llc + 1);
-+
-+ /* setup the LLC header */
-+ store_llc_snap(e_llc);
-+
-+ /* setup the SNAP header */
-+ e_snap->type = htons(proto);
-+ if (proto_is_stt(proto)) {
-+ store_oui_8021h(e_snap);
-+ } else {
-+ store_oui_rfc1042(e_snap);
-+ }
-+ }
-+ /* trim off ethernet header and copy payload to txbuf */
-+ payload_len = skb->len - sizeof(wlan_ethhdr_t);
-+ /* TODO: can we just let acx DMA payload from skb instead? */
-+ memcpy((u8*)txbuf + header_len, skb->data + sizeof(wlan_ethhdr_t), payload_len);
-+ payload_len += header_len;
-+ result = payload_len;
-+
-+ /* Set up the 802.11 header */
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi);
-+ a1 = e_hdr->daddr;
-+ a3 = priv->bssid;
-+ break;
-+ case ACX_MODE_2_STA:
-+ fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_TODSi);
-+ a1 = priv->bssid;
-+ a3 = e_hdr->daddr;
-+ break;
-+ case ACX_MODE_3_AP:
-+ fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_FROMDSi);
-+ a1 = e_hdr->daddr;
-+ a3 = e_hdr->saddr;
-+ break;
-+ default:
-+ printk("%s: error - converting eth to wlan in unknown mode\n",
-+ priv->netdev->name);
-+ result = -1;
-+ goto end;
-+ }
-+ if (priv->wep_enabled)
-+ SET_BIT(fc, WF_FC_ISWEPi);
-+
-+ w_hdr->fc = fc;
-+ w_hdr->dur = 0;
-+ MAC_COPY(w_hdr->a1, a1);
-+ MAC_COPY(w_hdr->a2, priv->dev_addr);
-+ MAC_COPY(w_hdr->a3, a3);
-+ w_hdr->seq = 0;
-+
-+#ifdef DEBUG_CONVERT
-+ if (acx_debug & L_DATA) {
-+ printk("original eth frame [%d]: ", skb->len);
-+ acx_dump_bytes(skb->data, skb->len);
-+ printk("802.11 frame [%d]: ", payload_len);
-+ acx_dump_bytes(w_hdr, payload_len);
-+ }
-+#endif
-+
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_rxbuf_to_ether
-+*
-+* Uses the contents of a received 802.11 frame to build an ether
-+* frame.
-+*
-+* This function extracts the src and dest address from the 802.11
-+* frame to use in the construction of the eth frame.
-+*
-+* Based largely on p80211conv.c of the linux-wlan-ng project
-+*----------------------------------------------------------------*/
-+struct sk_buff*
-+acx_rxbuf_to_ether(wlandevice_t *priv, rxbuffer_t *rxbuf)
-+{
-+ struct wlan_hdr *w_hdr;
-+ struct wlan_ethhdr *e_hdr;
-+ struct wlan_llc *e_llc;
-+ struct wlan_snap *e_snap;
-+ struct sk_buff *skb;
-+ const u8 *daddr;
-+ const u8 *saddr;
-+ const u8 *e_payload;
-+ int buflen, payload_length;
-+ unsigned int payload_offset, mtu;
-+ u16 fc;
-+
-+ FN_ENTER;
-+
-+ /* This looks complex because it must handle possible
-+ ** phy header in rxbuff */
-+ w_hdr = acx_get_wlan_hdr(priv, rxbuf);
-+ payload_offset = WLAN_HDR_A3_LEN; /* it is relative to w_hdr */
-+ payload_length = RXBUF_BYTES_USED(rxbuf) /* entire rxbuff... */
-+ - ((u8*)w_hdr - (u8*)rxbuf) /* minus space before 802.11 frame */
-+ - WLAN_HDR_A3_LEN; /* minus 802.11 header */
-+
-+ /* setup some vars for convenience */
-+ fc = w_hdr->fc;
-+ switch (WF_FC_FROMTODSi & fc) {
-+ case 0:
-+ daddr = w_hdr->a1;
-+ saddr = w_hdr->a2;
-+ break;
-+ case WF_FC_FROMDSi:
-+ daddr = w_hdr->a1;
-+ saddr = w_hdr->a3;
-+ break;
-+ case WF_FC_TODSi:
-+ daddr = w_hdr->a3;
-+ saddr = w_hdr->a2;
-+ break;
-+ default: /* WF_FC_FROMTODSi */
-+ payload_offset += (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
-+ payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
-+ daddr = w_hdr->a3;
-+ saddr = w_hdr->a4;
-+ }
-+
-+ if ((WF_FC_ISWEPi & fc) && IS_ACX100(priv)) {
-+ /* chop off the IV+ICV WEP header and footer */
-+ acxlog(L_DATA|L_DEBUG, "rx: WEP packet, "
-+ "chopping off IV and ICV\n");
-+ payload_offset += WLAN_WEP_IV_LEN;
-+ payload_length -= WLAN_WEP_IV_LEN + WLAN_WEP_ICV_LEN;
-+ }
-+
-+ if (unlikely(payload_length < 0)) {
-+ printk("%s: rx frame too short, ignored\n", priv->netdev->name);
-+ goto ret_null;
-+ }
-+
-+ e_hdr = (wlan_ethhdr_t*) ((u8*) w_hdr + payload_offset);
-+ e_llc = (wlan_llc_t*) e_hdr;
-+ e_snap = (wlan_snap_t*) (e_llc + 1);
-+ e_payload = (u8*) (e_snap + 1);
-+ mtu = priv->netdev->mtu;
-+
-+ acxlog(L_DATA, "rx: payload_offset %d, payload_length %d\n",
-+ payload_offset, payload_length);
-+ acxlog(L_XFER|L_DATA,
-+ "rx: frame info: llc=%02X%02X%02X "
-+ "snap.oui=%02X%02X%02X snap.type=%04X\n",
-+ e_llc->dsap, e_llc->ssap, e_llc->ctl,
-+ e_snap->oui[0], e_snap->oui[1], e_snap->oui[2],
-+ ntohs(e_snap->type));
-+
-+ /* Test for the various encodings */
-+ if ((payload_length >= sizeof(wlan_ethhdr_t))
-+ && ((e_llc->dsap != 0xaa) || (e_llc->ssap != 0xaa))
-+ && ( (mac_is_equal(daddr, e_hdr->daddr))
-+ || (mac_is_equal(saddr, e_hdr->saddr))
-+ )
-+ ) {
-+ /* 802.3 Encapsulated: */
-+ /* wlan frame body contains complete eth frame (header+body) */
-+ acxlog(L_DEBUG|L_DATA, "rx: 802.3 ENCAP len=%d\n", payload_length);
-+
-+ if (unlikely(payload_length > (mtu + ETH_HLEN))) {
-+ printk("%s: rx: ENCAP frame too large (%d > %d)\n",
-+ priv->netdev->name,
-+ payload_length, mtu + ETH_HLEN);
-+ goto ret_null;
-+ }
-+
-+ /* allocate space and setup host buffer */
-+ buflen = payload_length;
-+ /* Attempt to align IP header (14 bytes eth header + 2 = 16) */
-+ skb = dev_alloc_skb(buflen + 2);
-+ if (unlikely(!skb))
-+ goto no_skb;
-+ skb_reserve(skb, 2);
-+ skb_put(skb, buflen); /* make room */
-+
-+ /* now copy the data from the 80211 frame */
-+ memcpy(skb->data, e_hdr, payload_length);
-+
-+ } else if ( (payload_length >= sizeof(wlan_llc_t)+sizeof(wlan_snap_t))
-+ && llc_is_snap(e_llc) ) {
-+ /* wlan frame body contains: AA AA 03 ... (it's a SNAP) */
-+
-+ if ( !oui_is_rfc1042(e_snap)
-+ || (proto_is_stt(ieee2host16(e_snap->type)) /* && (ethconv == WLAN_ETHCONV_8021h) */)) {
-+ acxlog(L_DEBUG|L_DATA, "rx: SNAP+RFC1042 len=%d\n", payload_length);
-+ /* wlan frame body contains: AA AA 03 !(00 00 00) ... -or- */
-+ /* wlan frame body contains: AA AA 03 00 00 00 0x80f3 ... */
-+ /* build eth hdr, type = len, copy AA AA 03... as eth body */
-+ /* it's a SNAP + RFC1042 frame && protocol is in STT */
-+
-+ if (unlikely(payload_length > mtu)) {
-+ printk("%s: rx: SNAP frame too large (%d > %d)\n",
-+ priv->netdev->name,
-+ payload_length, mtu);
-+ goto ret_null;
-+ }
-+
-+ /* allocate space and setup host buffer */
-+ buflen = payload_length + ETH_HLEN;
-+ skb = dev_alloc_skb(buflen + 2);
-+ if (unlikely(!skb))
-+ goto no_skb;
-+ skb_reserve(skb, 2);
-+ skb_put(skb, buflen); /* make room */
-+
-+ /* create 802.3 header */
-+ e_hdr = (wlan_ethhdr_t*) skb->data;
-+ MAC_COPY(e_hdr->daddr, daddr);
-+ MAC_COPY(e_hdr->saddr, saddr);
-+ e_hdr->type = htons(payload_length);
-+
-+ /* Now copy the data from the 80211 frame.
-+ Make room in front for the eth header, and keep the
-+ llc and snap from the 802.11 payload */
-+ memcpy(skb->data + ETH_HLEN,
-+ e_llc, payload_length);
-+
-+ } else {
-+ /* wlan frame body contains: AA AA 03 00 00 00 [type] [tail] */
-+ /* build eth hdr, type=[type], copy [tail] as eth body */
-+ acxlog(L_DEBUG|L_DATA, "rx: 802.1h/RFC1042 len=%d\n",
-+ payload_length);
-+ /* it's an 802.1h frame (an RFC1042 && protocol is not in STT) */
-+ /* build a DIXII + RFC894 */
-+
-+ payload_length -= sizeof(wlan_llc_t) + sizeof(wlan_snap_t);
-+ if (unlikely(payload_length > mtu)) {
-+ printk("%s: rx: DIXII frame too large (%d > %d)\n",
-+ priv->netdev->name,
-+ payload_length, mtu);
-+ goto ret_null;
-+ }
-+
-+ /* allocate space and setup host buffer */
-+ buflen = payload_length + ETH_HLEN;
-+ skb = dev_alloc_skb(buflen + 2);
-+ if (unlikely(!skb))
-+ goto no_skb;
-+ skb_reserve(skb, 2);
-+ skb_put(skb, buflen); /* make room */
-+
-+ /* create 802.3 header */
-+ e_hdr = (wlan_ethhdr_t *) skb->data;
-+ MAC_COPY(e_hdr->daddr, daddr);
-+ MAC_COPY(e_hdr->saddr, saddr);
-+ e_hdr->type = e_snap->type;
-+
-+ /* Now copy the data from the 80211 frame.
-+ Make room in front for the eth header, and cut off the
-+ llc and snap from the 802.11 payload */
-+ memcpy(skb->data + ETH_HLEN,
-+ e_payload, payload_length);
-+ }
-+
-+ } else {
-+ acxlog(L_DEBUG|L_DATA, "rx: NON-ENCAP len=%d\n", payload_length);
-+ /* build eth hdr, type=len, copy wlan body as eth body */
-+ /* any NON-ENCAP */
-+ /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
-+ /* build an 802.3 frame */
-+
-+ if (unlikely(payload_length > mtu)) {
-+ printk("%s: rx: OTHER frame too large (%d > %d)\n",
-+ priv->netdev->name, payload_length, mtu);
-+ goto ret_null;
-+ }
-+
-+ /* allocate space and setup host buffer */
-+ buflen = payload_length + ETH_HLEN;
-+ skb = dev_alloc_skb(buflen + 2);
-+ if (unlikely(!skb))
-+ goto no_skb;
-+ skb_reserve(skb, 2);
-+ skb_put(skb, buflen); /* make room */
-+
-+ /* set up the 802.3 header */
-+ e_hdr = (wlan_ethhdr_t *) skb->data;
-+ MAC_COPY(e_hdr->daddr, daddr);
-+ MAC_COPY(e_hdr->saddr, saddr);
-+ e_hdr->type = htons(payload_length);
-+
-+ /* now copy the data from the 80211 frame */
-+ memcpy(skb->data + ETH_HLEN, e_llc, payload_length);
-+ }
-+
-+ skb->dev = priv->netdev;
-+ skb->protocol = eth_type_trans(skb, priv->netdev);
-+
-+#ifdef DEBUG_CONVERT
-+ if (acx_debug & L_DATA) {
-+ printk("p802.11 frame [%d]: ", RXBUF_BYTES_RCVD(rxbuf));
-+ acx_dump_bytes(w_hdr, RXBUF_BYTES_RCVD(rxbuf));
-+ printk("eth frame [%d]: ", skb->len);
-+ acx_dump_bytes(skb->data, skb->len);
-+ }
-+#endif
-+
-+ FN_EXIT0;
-+ return skb;
-+
-+no_skb:
-+ printk("%s: rx: no memory for skb (%d bytes)\n",
-+ priv->netdev->name, buflen + 2);
-+ret_null:
-+ FN_EXIT1((int)NULL);
-+ return NULL;
-+}
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/ioctl.c bt_kernel/drivers/net/wireless/tiacx/ioctl.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/ioctl.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/ioctl.c 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,3060 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <asm/io.h>
-+#include <asm/uaccess.h> /* required for 2.4.x kernels; verify_write() */
-+
-+#include <linux/if_arp.h>
-+#include <linux/wireless.h>
-+#if WIRELESS_EXT >= 13
-+#include <net/iw_handler.h>
-+#endif /* WE >= 13 */
-+
-+#include "acx.h"
-+
-+
-+/*================================================================*/
-+
-+/* if you plan to reorder something, make sure to reorder all other places
-+ * accordingly! */
-+/* someone broke SET/GET convention: SETs must have even position, GETs odd */
-+#define ACX100_IOCTL SIOCIWFIRSTPRIV
-+enum {
-+ ACX100_IOCTL_DEBUG = ACX100_IOCTL,
-+ ACX100_IOCTL_GET__________UNUSED1,
-+ ACX100_IOCTL_SET_PLED,
-+ ACX100_IOCTL_GET_PLED,
-+ ACX100_IOCTL_SET_RATES,
-+ ACX100_IOCTL_LIST_DOM,
-+ ACX100_IOCTL_SET_DOM,
-+ ACX100_IOCTL_GET_DOM,
-+ ACX100_IOCTL_SET_SCAN_PARAMS,
-+ ACX100_IOCTL_GET_SCAN_PARAMS,
-+ ACX100_IOCTL_SET_PREAMB,
-+ ACX100_IOCTL_GET_PREAMB,
-+ ACX100_IOCTL_SET_ANT,
-+ ACX100_IOCTL_GET_ANT,
-+ ACX100_IOCTL_RX_ANT,
-+ ACX100_IOCTL_TX_ANT,
-+ ACX100_IOCTL_SET_PHY_AMP_BIAS,
-+ ACX100_IOCTL_GET_PHY_CHAN_BUSY,
-+ ACX100_IOCTL_SET_ED,
-+ ACX100_IOCTL_GET__________UNUSED3,
-+ ACX100_IOCTL_SET_CCA,
-+ ACX100_IOCTL_GET__________UNUSED4,
-+ ACX100_IOCTL_MONITOR,
-+ ACX100_IOCTL_TEST,
-+ ACX100_IOCTL_DBG_SET_MASKS,
-+ ACX111_IOCTL_INFO,
-+ ACX100_IOCTL_DBG_SET_IO,
-+ ACX100_IOCTL_DBG_GET_IO
-+};
-+
-+/* channel frequencies
-+ * TODO: Currently, every other 802.11 driver keeps its own copy of this. In
-+ * the long run this should be integrated into ieee802_11.h or wireless.h or
-+ * whatever IEEE802.11x framework evolves */
-+static const u16 acx_channel_freq[] = {
-+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
-+ 2447, 2452, 2457, 2462, 2467, 2472, 2484,
-+};
-+
-+static const struct iw_priv_args acx_ioctl_private_args[] = {
-+#if ACX_DEBUG
-+{ cmd : ACX100_IOCTL_DEBUG,
-+ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetDebug" },
-+#endif
-+{ cmd : ACX100_IOCTL_SET_PLED,
-+ set_args : IW_PRIV_TYPE_BYTE | 2,
-+ get_args : 0,
-+ name : "SetLEDPower" },
-+{ cmd : ACX100_IOCTL_GET_PLED,
-+ set_args : 0,
-+ get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2,
-+ name : "GetLEDPower" },
-+{ cmd : ACX100_IOCTL_SET_RATES,
-+ set_args : IW_PRIV_TYPE_CHAR | 256,
-+ get_args : 0,
-+ name : "SetRates" },
-+{ cmd : ACX100_IOCTL_LIST_DOM,
-+ set_args : 0,
-+ get_args : 0,
-+ name : "ListRegDomain" },
-+{ cmd : ACX100_IOCTL_SET_DOM,
-+ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetRegDomain" },
-+{ cmd : ACX100_IOCTL_GET_DOM,
-+ set_args : 0,
-+ get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ name : "GetRegDomain" },
-+{ cmd : ACX100_IOCTL_SET_SCAN_PARAMS,
-+ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
-+ get_args : 0,
-+ name : "SetScanParams" },
-+{ cmd : ACX100_IOCTL_GET_SCAN_PARAMS,
-+ set_args : 0,
-+ get_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
-+ name : "GetScanParams" },
-+{ cmd : ACX100_IOCTL_SET_PREAMB,
-+ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetSPreamble" },
-+{ cmd : ACX100_IOCTL_GET_PREAMB,
-+ set_args : 0,
-+ get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ name : "GetSPreamble" },
-+{ cmd : ACX100_IOCTL_SET_ANT,
-+ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetAntenna" },
-+{ cmd : ACX100_IOCTL_GET_ANT,
-+ set_args : 0,
-+ get_args : 0,
-+ name : "GetAntenna" },
-+{ cmd : ACX100_IOCTL_RX_ANT,
-+ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetRxAnt" },
-+{ cmd : ACX100_IOCTL_TX_ANT,
-+ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetTxAnt" },
-+{ cmd : ACX100_IOCTL_SET_PHY_AMP_BIAS,
-+ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetPhyAmpBias"},
-+{ cmd : ACX100_IOCTL_GET_PHY_CHAN_BUSY,
-+ set_args : 0,
-+ get_args : 0,
-+ name : "GetPhyChanBusy" },
-+{ cmd : ACX100_IOCTL_SET_ED,
-+ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetED" },
-+{ cmd : ACX100_IOCTL_SET_CCA,
-+ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-+ get_args : 0,
-+ name : "SetCCA" },
-+{ cmd : ACX100_IOCTL_MONITOR,
-+ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
-+ get_args : 0,
-+ name : "monitor" },
-+{ cmd : ACX100_IOCTL_TEST,
-+ set_args : 0,
-+ get_args : 0,
-+ name : "Test" },
-+{ cmd : ACX100_IOCTL_DBG_SET_MASKS,
-+ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
-+ get_args : 0,
-+ name : "DbgSetMasks" },
-+{ cmd : ACX111_IOCTL_INFO,
-+ set_args : 0,
-+ get_args : 0,
-+ name : "GetAcx111Info" },
-+{ cmd : ACX100_IOCTL_DBG_SET_IO,
-+ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
-+ get_args : 0,
-+ name : "DbgSetIO" },
-+{ cmd : ACX100_IOCTL_DBG_GET_IO,
-+ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
-+ get_args : 0,
-+ name : "DbgGetIO" },
-+};
-+
-+
-+/*------------------------------------------------------------------------------
-+ * acx_ioctl_commit
-+ *----------------------------------------------------------------------------*/
-+static int
-+acx_ioctl_commit(struct net_device *dev,
-+ struct iw_request_info *info,
-+ void *zwrq, char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
-+ acx_s_update_card_settings(priv, 0, 0);
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT0;
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_get_name(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ char *cwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ static const char * const names[] = { "IEEE 802.11b+/g+", "IEEE 802.11b+" };
-+
-+ strcpy(cwrq, names[IS_ACX111(priv) ? 0 : 1]);
-+
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_freq
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_freq(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_freq *fwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int channel = -1;
-+ unsigned int mult = 1;
-+ int result;
-+
-+ FN_ENTER;
-+
-+ if (fwrq->e == 0 && fwrq->m <= 1000) {
-+ /* Setting by channel number */
-+ channel = fwrq->m;
-+ } else {
-+ /* If setting by frequency, convert to a channel */
-+ int i;
-+
-+ for (i = 0; i < (6 - fwrq->e); i++)
-+ mult *= 10;
-+
-+ for (i = 1; i <= 14; i++)
-+ if (fwrq->m == acx_channel_freq[i - 1] * mult)
-+ channel = i;
-+ }
-+
-+ if (channel > 14) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ acx_sem_lock(priv);
-+
-+ priv->channel = channel;
-+ /* hmm, the following code part is strange, but this is how
-+ * it was being done before... */
-+ acxlog(L_IOCTL, "Changing to channel %d\n", channel);
-+ SET_BIT(priv->set_mask, GETSET_CHANNEL);
-+
-+ result = -EINPROGRESS; /* need to call commit handler */
-+
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static inline int
-+acx_ioctl_get_freq(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_freq *fwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ fwrq->e = 0;
-+ fwrq->m = priv->channel;
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_mode
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_mode(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ u32 *uwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ switch (*uwrq) {
-+ case IW_MODE_AUTO:
-+ priv->mode = ACX_MODE_OFF;
-+ break;
-+#if WIRELESS_EXT > 14
-+ case IW_MODE_MONITOR:
-+ priv->mode = ACX_MODE_MONITOR;
-+ break;
-+#endif /* WIRELESS_EXT > 14 */
-+ case IW_MODE_ADHOC:
-+ priv->mode = ACX_MODE_0_ADHOC;
-+ break;
-+ case IW_MODE_INFRA:
-+ priv->mode = ACX_MODE_2_STA;
-+ break;
-+ case IW_MODE_MASTER:
-+ printk("acx: master mode (HostAP) is very, very "
-+ "experimental! It might work partially, but "
-+ "better get prepared for nasty surprises "
-+ "at any time\n");
-+ priv->mode = ACX_MODE_3_AP;
-+ break;
-+ case IW_MODE_REPEAT:
-+ case IW_MODE_SECOND:
-+ default:
-+ result = -EOPNOTSUPP;
-+ goto end_unlock;
-+ }
-+
-+ acxlog(L_ASSOC, "new priv->mode=%d\n", priv->mode);
-+ SET_BIT(priv->set_mask, GETSET_MODE);
-+ result = -EINPROGRESS;
-+
-+end_unlock:
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_get_mode(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ u32 *uwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result = 0;
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_OFF:
-+ *uwrq = IW_MODE_AUTO; break;
-+#if WIRELESS_EXT > 14
-+ case ACX_MODE_MONITOR:
-+ *uwrq = IW_MODE_MONITOR; break;
-+#endif /* WIRELESS_EXT > 14 */
-+ case ACX_MODE_0_ADHOC:
-+ *uwrq = IW_MODE_ADHOC; break;
-+ case ACX_MODE_2_STA:
-+ *uwrq = IW_MODE_INFRA; break;
-+ case ACX_MODE_3_AP:
-+ *uwrq = IW_MODE_MASTER; break;
-+ default:
-+ result = -EOPNOTSUPP;
-+ }
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_set_sens(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ priv->sensitivity = (1 == vwrq->disabled) ? 0 : vwrq->value;
-+ SET_BIT(priv->set_mask, GETSET_SENSITIVITY);
-+
-+ acx_sem_unlock(priv);
-+
-+ return -EINPROGRESS;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_get_sens(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ /* acx_sem_lock(priv); */
-+
-+ vwrq->value = priv->sensitivity;
-+ vwrq->disabled = (vwrq->value == 0);
-+ vwrq->fixed = 1;
-+
-+ /* acx_sem_unlock(priv); */
-+
-+ return OK;
-+}
-+
-+
-+/*------------------------------------------------------------------------------
-+ * acx_ioctl_set_ap
-+ *
-+ * Sets the MAC address of the AP to associate with
-+ *----------------------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_ap(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct sockaddr *awrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result = 0;
-+ const u8 *ap;
-+
-+ FN_ENTER;
-+ if (NULL == awrq) {
-+ result = -EFAULT;
-+ goto end;
-+ }
-+ if (ARPHRD_ETHER != awrq->sa_family) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ ap = awrq->sa_data;
-+ acxlog_mac(L_IOCTL, "Set AP=", ap, "\n");
-+
-+ MAC_COPY(priv->ap, ap);
-+
-+ /* We want to start rescan in managed or ad-hoc mode,
-+ ** otherwise just set priv->ap.
-+ ** "iwconfig <if> ap <mac> mode managed": we must be able
-+ ** to set ap _first_ and _then_ set mode */
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ /* FIXME: if there is a convention on what zero AP means,
-+ ** please add a comment about that. I don't know of any --vda */
-+ if (mac_is_zero(ap)) {
-+ /* "off" == 00:00:00:00:00:00 */
-+ MAC_BCAST(priv->ap);
-+ acxlog(L_IOCTL, "Not reassociating\n");
-+ } else {
-+ acxlog(L_IOCTL, "Forcing reassociation\n");
-+ SET_BIT(priv->set_mask, GETSET_RESCAN);
-+ }
-+ break;
-+ }
-+ result = -EINPROGRESS;
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_get_ap(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct sockaddr *awrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ if (ACX_STATUS_4_ASSOCIATED == priv->status) {
-+ /* as seen in Aironet driver, airo.c */
-+ MAC_COPY(awrq->sa_data, priv->bssid);
-+ } else {
-+ MAC_ZERO(awrq->sa_data);
-+ }
-+ awrq->sa_family = ARPHRD_ETHER;
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_aplist
-+*
-+* Comment: deprecated in favour of iwscan.
-+* We simply return the list of currently available stations in range,
-+* don't do a new scan.
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_aplist(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ struct sockaddr *address = (struct sockaddr *) extra;
-+ struct iw_quality qual[IW_MAX_AP];
-+ int i, cur;
-+ int result = OK;
-+
-+ FN_ENTER;
-+
-+ /* we have AP list only in STA mode */
-+ if (ACX_MODE_2_STA != priv->mode) {
-+ result = -EOPNOTSUPP;
-+ goto end;
-+ }
-+
-+ cur = 0;
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ struct client *bss = &priv->sta_list[i];
-+ if (!bss->used) continue;
-+ MAC_COPY(address[cur].sa_data, bss->bssid);
-+ address[cur].sa_family = ARPHRD_ETHER;
-+ qual[cur].level = bss->sir;
-+ qual[cur].noise = bss->snr;
-+#ifndef OLD_QUALITY
-+ qual[cur].qual = acx_signal_determine_quality(qual[cur].level,
-+ qual[cur].noise);
-+#else
-+ qual[cur].qual = (qual[cur].noise <= 100) ?
-+ 100 - qual[cur].noise : 0;
-+#endif
-+ /* no scan: level/noise/qual not updated: */
-+ qual[cur].updated = 0;
-+ cur++;
-+ }
-+ if (cur) {
-+ dwrq->flags = 1;
-+ memcpy(extra + sizeof(struct sockaddr)*cur, &qual,
-+ sizeof(struct iw_quality)*cur);
-+ }
-+ dwrq->length = cur;
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_set_scan(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ /* don't start scan if device is not up yet */
-+ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
-+ result = -EAGAIN;
-+ goto end_unlock;
-+ }
-+
-+ /* This is NOT a rescan for new AP!
-+ ** Do not use SET_BIT(GETSET_RESCAN); */
-+ acx_s_cmd_start_scan(priv);
-+ result = OK;
-+
-+end_unlock:
-+ acx_sem_unlock(priv);
-+/* end: */
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+#if WIRELESS_EXT > 13
-+/***********************************************************************
-+** acx_s_scan_add_station
-+*/
-+/* helper. not sure wheter it's really a _s_leeping fn */
-+static char*
-+acx_s_scan_add_station(
-+ wlandevice_t *priv,
-+ char *ptr,
-+ char *end_buf,
-+ struct client *bss)
-+{
-+ struct iw_event iwe;
-+ char *ptr_rate;
-+
-+ FN_ENTER;
-+
-+ /* MAC address has to be added first */
-+ iwe.cmd = SIOCGIWAP;
-+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-+ MAC_COPY(iwe.u.ap_addr.sa_data, bss->bssid);
-+ acxlog_mac(L_IOCTL, "scan, station address: ", bss->bssid, "\n");
-+ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_ADDR_LEN);
-+
-+ /* Add ESSID */
-+ iwe.cmd = SIOCGIWESSID;
-+ iwe.u.data.length = bss->essid_len;
-+ iwe.u.data.flags = 1;
-+ acxlog(L_IOCTL, "scan, essid: %s\n", bss->essid);
-+ ptr = iwe_stream_add_point(ptr, end_buf, &iwe, bss->essid);
-+
-+ /* Add mode */
-+ iwe.cmd = SIOCGIWMODE;
-+ if (bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)) {
-+ if (bss->cap_info & WF_MGMT_CAP_ESS)
-+ iwe.u.mode = IW_MODE_MASTER;
-+ else
-+ iwe.u.mode = IW_MODE_ADHOC;
-+ acxlog(L_IOCTL, "scan, mode: %d\n", iwe.u.mode);
-+ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_UINT_LEN);
-+ }
-+
-+ /* Add frequency */
-+ iwe.cmd = SIOCGIWFREQ;
-+ iwe.u.freq.m = acx_channel_freq[bss->channel - 1] * 100000;
-+ iwe.u.freq.e = 1;
-+ acxlog(L_IOCTL, "scan, frequency: %d\n", iwe.u.freq.m);
-+ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_FREQ_LEN);
-+
-+ /* Add link quality */
-+ iwe.cmd = IWEVQUAL;
-+ /* FIXME: these values should be expressed in dBm, but we don't know
-+ * how to calibrate it yet */
-+ iwe.u.qual.level = bss->sir;
-+ iwe.u.qual.noise = bss->snr;
-+#ifndef OLD_QUALITY
-+ iwe.u.qual.qual = acx_signal_determine_quality(iwe.u.qual.level,
-+ iwe.u.qual.noise);
-+#else
-+ iwe.u.qual.qual = (iwe.u.qual.noise <= 100) ?
-+ 100 - iwe.u.qual.noise : 0;
-+#endif
-+ iwe.u.qual.updated = 7;
-+ acxlog(L_IOCTL, "scan, link quality: %d/%d/%d\n",
-+ iwe.u.qual.level, iwe.u.qual.noise, iwe.u.qual.qual);
-+ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_QUAL_LEN);
-+
-+ /* Add encryption */
-+ iwe.cmd = SIOCGIWENCODE;
-+ if (bss->cap_info & WF_MGMT_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;
-+ acxlog(L_IOCTL, "scan, encryption flags: %X\n", iwe.u.data.flags);
-+ ptr = iwe_stream_add_point(ptr, end_buf, &iwe, bss->essid);
-+
-+ /* add rates */
-+ iwe.cmd = SIOCGIWRATE;
-+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-+ ptr_rate = ptr + IW_EV_LCP_LEN;
-+
-+ {
-+ u16 rate = bss->rate_cap;
-+ const u8* p = bitpos2ratebyte;
-+ while (rate) {
-+ if (rate & 1) {
-+ iwe.u.bitrate.value = *p * 500000; /* units of 500kb/s */
-+ acxlog(L_IOCTL, "scan, rate: %d\n", iwe.u.bitrate.value);
-+ ptr = iwe_stream_add_value(ptr, ptr_rate, end_buf, &iwe, IW_EV_PARAM_LEN);
-+ }
-+ rate >>= 1;
-+ p++;
-+ }}
-+
-+ if ((ptr_rate - ptr) > (ptrdiff_t)IW_EV_LCP_LEN)
-+ ptr = ptr_rate;
-+
-+ /* drop remaining station data items for now */
-+
-+ FN_EXIT0;
-+ return ptr;
-+}
-+
-+
-+/***********************************************************************
-+ * acx_ioctl_get_scan
-+ */
-+static int
-+acx_ioctl_get_scan(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ char *ptr = extra;
-+ int i;
-+ int result = OK;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ /* no scan available if device is not up yet */
-+ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
-+ acxlog(L_IOCTL, "iface not up yet\n");
-+ result = -EAGAIN;
-+ goto end_unlock;
-+ }
-+#if 0 /* Why is this needed? If needed, add a comment */
-+ if (priv->scan_start && time_before(jiffies, priv->scan_start + 3*HZ)) {
-+ acxlog(L_IOCTL, "scan in progress, no results yet\n");
-+ result = -EAGAIN;
-+ goto end_unlock;
-+ }
-+#endif
-+
-+#ifdef ENODATA_TO_BE_USED_AFTER_SCAN_ERROR_ONLY
-+ if (priv->bss_table_count == 0) {
-+ /* no stations found */
-+ result = -ENODATA;
-+ goto end_unlock;
-+ }
-+#endif
-+
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ struct client *bss = &priv->sta_list[i];
-+ if (!bss->used) continue;
-+ ptr = acx_s_scan_add_station(priv, ptr,
-+ extra + IW_SCAN_MAX_DATA, bss);
-+ }
-+ dwrq->length = ptr - extra;
-+ dwrq->flags = 0;
-+
-+end_unlock:
-+ acx_sem_unlock(priv);
-+/* end: */
-+ FN_EXIT1(result);
-+ return result;
-+}
-+#endif /* WIRELESS_EXT > 13 */
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_essid
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_essid(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int len = dwrq->length;
-+ int result;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_IOCTL, "Set ESSID '%*s', length %d, flags 0x%04X\n",
-+ len, extra, len, dwrq->flags);
-+
-+ if (len < 0) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ acx_sem_lock(priv);
-+
-+ /* ESSID disabled? */
-+ if (0 == dwrq->flags) {
-+ priv->essid_active = 0;
-+
-+ } else {
-+ if (dwrq->length > IW_ESSID_MAX_SIZE+1) {
-+ result = -E2BIG;
-+ goto end_unlock;
-+ }
-+
-+ if (len > sizeof(priv->essid))
-+ len = sizeof(priv->essid);
-+ memcpy(priv->essid, extra, len-1);
-+ priv->essid[len-1] = '\0';
-+ /* Paranoia: just in case there is a '\0'... */
-+ priv->essid_len = strlen(priv->essid);
-+ priv->essid_active = 1;
-+ }
-+
-+ SET_BIT(priv->set_mask, GETSET_RESCAN);
-+
-+ result = -EINPROGRESS;
-+
-+end_unlock:
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_get_essid(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ dwrq->flags = priv->essid_active;
-+ if (priv->essid_active) {
-+ memcpy(extra, priv->essid, priv->essid_len);
-+ extra[priv->essid_len] = '\0';
-+ dwrq->length = priv->essid_len + 1;
-+ dwrq->flags = 1;
-+ }
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_update_client_rates
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_update_client_rates(wlandevice_t *priv, u16 rate)
-+{
-+ int i;
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ client_t *clt = &priv->sta_list[i];
-+ if (!clt->used) continue;
-+ clt->rate_cfg = (clt->rate_cap & rate);
-+ if (!clt->rate_cfg) {
-+ /* no compatible rates left: kick client */
-+ acxlog_mac(L_ASSOC, "client ",clt->address," kicked: "
-+ "rates are not compatible anymore\n");
-+ acx_l_sta_list_del(priv, clt);
-+ continue;
-+ }
-+ clt->rate_cur &= clt->rate_cfg;
-+ if (!clt->rate_cur) {
-+ /* current rate become invalid, choose a valid one */
-+ clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
-+ }
-+ clt->fallback_count = clt->stepup_count = 0;
-+ clt->ignore_count = 16;
-+ }
-+ switch (priv->mode) {
-+ case ACX_MODE_2_STA:
-+ if (priv->ap_client && !priv->ap_client->used) {
-+ /* Owwww... we kicked our AP!! :) */
-+ SET_BIT(priv->set_mask, GETSET_RESCAN);
-+ }
-+ }
-+}
-+
-+
-+/***********************************************************************
-+*/
-+/* maps bits from acx111 rate to rate in Mbits */
-+static const unsigned int
-+acx111_rate_tbl[] = {
-+ 1000000, /* 0 */
-+ 2000000, /* 1 */
-+ 5500000, /* 2 */
-+ 6000000, /* 3 */
-+ 9000000, /* 4 */
-+ 11000000, /* 5 */
-+ 12000000, /* 6 */
-+ 18000000, /* 7 */
-+ 22000000, /* 8 */
-+ 24000000, /* 9 */
-+ 36000000, /* 10 */
-+ 48000000, /* 11 */
-+ 54000000, /* 12 */
-+ 500000, /* 13, should not happen */
-+ 500000, /* 14, should not happen */
-+ 500000, /* 15, should not happen */
-+};
-+
-+/***********************************************************************
-+ * acx_ioctl_set_rate
-+ */
-+static int
-+acx_ioctl_set_rate(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ u16 txrate_cfg = 1;
-+ unsigned long flags;
-+ int autorate;
-+ int result = -EINVAL;
-+
-+ FN_ENTER;
-+ acxlog(L_IOCTL,
-+ "rate %d fixed 0x%X disabled 0x%X flags 0x%X\n",
-+ vwrq->value, vwrq->fixed, vwrq->disabled, vwrq->flags);
-+
-+ if ((0 == vwrq->fixed) || (1 == vwrq->fixed)) {
-+ int i = VEC_SIZE(acx111_rate_tbl)-1;
-+ if (vwrq->value == -1)
-+ /* "iwconfig rate auto" --> choose highest */
-+ vwrq->value = IS_ACX100(priv) ? 22000000 : 54000000;
-+ while (i >= 0) {
-+ if (vwrq->value == acx111_rate_tbl[i]) {
-+ txrate_cfg <<= i;
-+ i = 0;
-+ break;
-+ }
-+ i--;
-+ }
-+ if (i == -1) { /* no matching rate */
-+ result = -EINVAL;
-+ goto end;
-+ }
-+ } else { /* rate N, N<1000 (driver specific): we don't use this */
-+ result = -EOPNOTSUPP;
-+ goto end;
-+ }
-+ /* now: only one bit is set in txrate_cfg, corresponding to
-+ ** indicated rate */
-+
-+ autorate = (vwrq->fixed == 0) && (RATE111_1 != txrate_cfg);
-+ if (autorate) {
-+ /* convert 00100000 -> 00111111 */
-+ txrate_cfg = (txrate_cfg<<1)-1;
-+ }
-+
-+ if (IS_ACX100(priv)) {
-+ txrate_cfg &= RATE111_ACX100_COMPAT;
-+ if (!txrate_cfg) {
-+ result = -ENOTSUPP; /* rate is not supported by acx100 */
-+ goto end;
-+ }
-+ }
-+
-+ acx_sem_lock(priv);
-+ acx_lock(priv, flags);
-+
-+ priv->rate_auto = autorate;
-+ priv->rate_oper = txrate_cfg;
-+ priv->rate_basic = txrate_cfg;
-+ /* only do that in auto mode, non-auto will be able to use
-+ * one specific Tx rate only anyway */
-+ if (autorate) {
-+ /* only use 802.11b base rates, for standard 802.11b H/W
-+ * compatibility */
-+ priv->rate_basic &= RATE111_80211B_COMPAT;
-+ }
-+ priv->rate_bcast = 1 << lowest_bit(txrate_cfg);
-+ if (IS_ACX100(priv))
-+ priv->rate_bcast100 = acx_rate111to100(priv->rate_bcast);
-+ acx_l_update_ratevector(priv);
-+ acx_l_update_client_rates(priv, txrate_cfg);
-+
-+ /* Do/don't do tx rate fallback; beacon contents and rate */
-+ SET_BIT(priv->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES);
-+ result = -EINPROGRESS;
-+
-+ acx_unlock(priv, flags);
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_rate
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_rate(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ /* TODO: remember rate of last tx, show it. think about multiple peers... */
-+ wlandevice_t *priv = netdev_priv(dev);
-+ vwrq->value = acx111_rate_tbl[highest_bit(priv->rate_oper)];
-+ vwrq->fixed = !priv->rate_auto;
-+ vwrq->disabled = 0;
-+ return OK;
-+}
-+
-+static int
-+acx_ioctl_set_rts(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int val = vwrq->value;
-+
-+ if (vwrq->disabled)
-+ val = 2312;
-+ if ((val < 0) || (val > 2312))
-+ return -EINVAL;
-+
-+ priv->rts_threshold = val;
-+ return OK;
-+}
-+
-+static inline int
-+acx_ioctl_get_rts(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ vwrq->value = priv->rts_threshold;
-+ vwrq->disabled = (vwrq->value >= 2312);
-+ vwrq->fixed = 1;
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_encode
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_encode(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int index;
-+ int result;
-+
-+ FN_ENTER;
-+ acxlog(L_IOCTL,
-+ "Set Encoding flags=0x%04X, size=%d, key: %s\n",
-+ dwrq->flags, dwrq->length, extra ? "set" : "No key");
-+
-+ acx_sem_lock(priv);
-+
-+ index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-+
-+ if (dwrq->length > 0) {
-+ /* if index is 0 or invalid, use default key */
-+ if ((index < 0) || (index > 3))
-+ index = (int)priv->wep_current_index;
-+
-+ if (0 == (dwrq->flags & IW_ENCODE_NOKEY)) {
-+ if (dwrq->length > 29)
-+ dwrq->length = 29; /* restrict it */
-+
-+ if (dwrq->length > 13)
-+ priv->wep_keys[index].size = 29; /* 29*8 == 232, WEP256 */
-+ else
-+ if (dwrq->length > 5)
-+ priv->wep_keys[index].size = 13; /* 13*8 == 104bit, WEP128 */
-+ else
-+ if (dwrq->length > 0)
-+ priv->wep_keys[index].size = 5; /* 5*8 == 40bit, WEP64 */
-+ else
-+ /* disable key */
-+ priv->wep_keys[index].size = 0;
-+
-+ memset(priv->wep_keys[index].key, 0, sizeof(priv->wep_keys[index].key));
-+ memcpy(priv->wep_keys[index].key, extra, dwrq->length);
-+ }
-+
-+ } else {
-+ /* set transmit key */
-+ if ((index >= 0) && (index <= 3))
-+ priv->wep_current_index = index;
-+ else
-+ if (0 == (dwrq->flags & IW_ENCODE_MODE)) {
-+ /* complain if we were not just setting
-+ * the key mode */
-+ result = -EINVAL;
-+ goto end_unlock;
-+ }
-+ }
-+
-+ priv->wep_enabled = !(dwrq->flags & IW_ENCODE_DISABLED);
-+
-+ if (dwrq->flags & IW_ENCODE_OPEN) {
-+ priv->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
-+ priv->wep_restricted = 0;
-+
-+ } else if (dwrq->flags & IW_ENCODE_RESTRICTED) {
-+ priv->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
-+ priv->wep_restricted = 1;
-+ }
-+
-+ /* set flag to make sure the card WEP settings get updated */
-+ SET_BIT(priv->set_mask, GETSET_WEP);
-+
-+ acxlog(L_IOCTL, "len=%d, key at 0x%p, flags=0x%X\n",
-+ dwrq->length, extra,
-+ dwrq->flags);
-+
-+ for (index = 0; index <= 3; index++) {
-+ if (priv->wep_keys[index].size) {
-+ acxlog(L_IOCTL,
-+ "index=%d, size=%d, key at 0x%p\n",
-+ priv->wep_keys[index].index,
-+ (int) priv->wep_keys[index].size,
-+ priv->wep_keys[index].key);
-+ }
-+ }
-+ result = -EINPROGRESS;
-+
-+end_unlock:
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_encode
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_encode(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-+
-+ if (priv->wep_enabled == 0) {
-+ dwrq->flags = IW_ENCODE_DISABLED;
-+
-+ } else {
-+ if ((index < 0) || (index > 3))
-+ index = (int)priv->wep_current_index;
-+
-+ dwrq->flags =
-+ (priv->wep_restricted == 1) ? IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN;
-+ dwrq->length = priv->wep_keys[index].size;
-+
-+ memcpy(extra,
-+ priv->wep_keys[index].key,
-+ priv->wep_keys[index].size);
-+ }
-+
-+ /* set the current index */
-+ SET_BIT(dwrq->flags, index + 1);
-+
-+ acxlog(L_IOCTL, "len=%d, key=%p, flags=0x%X\n",
-+ dwrq->length, dwrq->pointer,
-+ dwrq->flags);
-+
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_set_power(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acxlog(L_IOCTL, "Set 802.11 Power Save flags=0x%04X\n", vwrq->flags);
-+ if (vwrq->disabled) {
-+ CLEAR_BIT(priv->ps_wakeup_cfg, PS_CFG_ENABLE);
-+ SET_BIT(priv->set_mask, GETSET_POWER_80211);
-+ return -EINPROGRESS;
-+ }
-+ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-+ u16 ps_timeout = (vwrq->value * 1024) / 1000;
-+
-+ if (ps_timeout > 255)
-+ ps_timeout = 255;
-+ acxlog(L_IOCTL, "setting PS timeout value to %d time units "
-+ "due to %dus\n", ps_timeout, vwrq->value);
-+ priv->ps_hangover_period = ps_timeout;
-+ } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
-+ u16 ps_periods = vwrq->value / 1000000;
-+
-+ if (ps_periods > 255)
-+ ps_periods = 255;
-+ acxlog(L_IOCTL, "setting PS period value to %d periods "
-+ "due to %dus\n", ps_periods, vwrq->value);
-+ priv->ps_listen_interval = ps_periods;
-+ CLEAR_BIT(priv->ps_wakeup_cfg, PS_CFG_WAKEUP_MODE_MASK);
-+ SET_BIT(priv->ps_wakeup_cfg, PS_CFG_WAKEUP_EACH_ITVL);
-+ }
-+ switch (vwrq->flags & IW_POWER_MODE) {
-+ /* FIXME: are we doing the right thing here? */
-+ case IW_POWER_UNICAST_R:
-+ CLEAR_BIT(priv->ps_options, PS_OPT_STILL_RCV_BCASTS);
-+ break;
-+ case IW_POWER_MULTICAST_R:
-+ SET_BIT(priv->ps_options, PS_OPT_STILL_RCV_BCASTS);
-+ break;
-+ case IW_POWER_ALL_R:
-+ SET_BIT(priv->ps_options, PS_OPT_STILL_RCV_BCASTS);
-+ break;
-+ case IW_POWER_ON:
-+ break;
-+ default:
-+ acxlog(L_IOCTL, "unknown PS mode\n");
-+ return -EINVAL;
-+ }
-+
-+ SET_BIT(priv->ps_wakeup_cfg, PS_CFG_ENABLE);
-+ SET_BIT(priv->set_mask, GETSET_POWER_80211);
-+
-+ return -EINPROGRESS;
-+
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx_ioctl_get_power(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acxlog(L_IOCTL, "Get 802.11 Power Save flags = 0x%04X\n", vwrq->flags);
-+ vwrq->disabled = ((priv->ps_wakeup_cfg & PS_CFG_ENABLE) == 0);
-+ if (vwrq->disabled)
-+ return OK;
-+ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-+ vwrq->value = priv->ps_hangover_period * 1000 / 1024;
-+ vwrq->flags = IW_POWER_TIMEOUT;
-+ } else {
-+ vwrq->value = priv->ps_listen_interval * 1000000;
-+ vwrq->flags = IW_POWER_PERIOD|IW_POWER_RELATIVE;
-+ }
-+ if (priv->ps_options & PS_OPT_STILL_RCV_BCASTS)
-+ SET_BIT(vwrq->flags, IW_POWER_ALL_R);
-+ else
-+ SET_BIT(vwrq->flags, IW_POWER_UNICAST_R);
-+
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_txpow
-+*----------------------------------------------------------------*/
-+static inline int
-+acx_ioctl_get_txpow(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ vwrq->flags = IW_TXPOW_DBM;
-+ vwrq->disabled = 0;
-+ vwrq->fixed = 1;
-+ vwrq->value = priv->tx_level_dbm;
-+
-+ acxlog(L_IOCTL, "get txpower:%d dBm\n", priv->tx_level_dbm);
-+
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_txpow
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_txpow(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+ acxlog(L_IOCTL, "set txpower:%d, disabled:%d, flags:0x%04X\n",
-+ vwrq->value, vwrq->disabled, vwrq->flags);
-+
-+ acx_sem_lock(priv);
-+
-+ if (vwrq->disabled != priv->tx_disabled) {
-+ SET_BIT(priv->set_mask, GETSET_TX); /* Tx status needs update later */
-+ }
-+
-+ priv->tx_disabled = vwrq->disabled;
-+ if (vwrq->value == -1) {
-+ if (vwrq->disabled) {
-+ priv->tx_level_dbm = 0;
-+ acxlog(L_IOCTL, "disable radio tx\n");
-+ } else {
-+ /* priv->tx_level_auto = 1; */
-+ acxlog(L_IOCTL, "set tx power auto (NIY)\n");
-+ }
-+ } else {
-+ priv->tx_level_dbm = vwrq->value <= 20 ? vwrq->value : 20;
-+ /* priv->tx_level_auto = 0; */
-+ acxlog(L_IOCTL, "set txpower=%d dBm\n", priv->tx_level_dbm);
-+ }
-+ SET_BIT(priv->set_mask, GETSET_TXPOWER);
-+
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_range
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_range(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ if (dwrq->pointer != NULL) {
-+ struct iw_range *range = (struct iw_range *)extra;
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned int i;
-+
-+ dwrq->length = sizeof(struct iw_range);
-+ memset(range, 0, sizeof(struct iw_range));
-+ range->num_channels = 0;
-+ for (i = 1; i <= 14; i++) {
-+ if (priv->reg_dom_chanmask & (1 << (i - 1))) {
-+ range->freq[range->num_channels].i = i;
-+ range->freq[range->num_channels].m = acx_channel_freq[i - 1] * 100000;
-+ range->freq[range->num_channels++].e = 1; /* MHz values */
-+ }
-+ }
-+ range->num_frequency = range->num_channels;
-+
-+ range->min_rts = 0;
-+ range->max_rts = 2312;
-+ /* range->min_frag = 256;
-+ * range->max_frag = 2312;
-+ */
-+
-+ range->encoding_size[0] = 5;
-+ range->encoding_size[1] = 13;
-+ range->encoding_size[2] = 29;
-+ range->num_encoding_sizes = 3;
-+ range->max_encoding_tokens = 4;
-+
-+ range->min_pmp = 0;
-+ range->max_pmp = 5000000;
-+ range->min_pmt = 0;
-+ range->max_pmt = 65535 * 1000;
-+ range->pmp_flags = IW_POWER_PERIOD;
-+ range->pmt_flags = IW_POWER_TIMEOUT;
-+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
-+
-+ for (i = 0; i <= IW_MAX_TXPOWER - 1; i++)
-+ range->txpower[i] = 20 * i / (IW_MAX_TXPOWER - 1);
-+ range->num_txpower = IW_MAX_TXPOWER;
-+ range->txpower_capa = IW_TXPOW_DBM;
-+
-+ range->we_version_compiled = WIRELESS_EXT;
-+ range->we_version_source = 0x9;
-+
-+ range->retry_capa = IW_RETRY_LIMIT;
-+ range->retry_flags = IW_RETRY_LIMIT;
-+ range->min_retry = 1;
-+ range->max_retry = 255;
-+
-+ range->r_time_flags = IW_RETRY_LIFETIME;
-+ range->min_r_time = 0;
-+ /* FIXME: lifetime ranges and orders of magnitude are strange?? */
-+ range->max_r_time = 65535;
-+
-+ if (IS_USB(priv))
-+ range->sensitivity = 0;
-+ else if (IS_ACX111(priv))
-+ range->sensitivity = 3;
-+ else
-+ range->sensitivity = 255;
-+
-+ for (i=0; i < priv->rate_supported_len; i++) {
-+ range->bitrate[i] = (priv->rate_supported[i] & ~0x80) * 500000;
-+ /* never happens, but keep it, to be safe: */
-+ if (range->bitrate[i] == 0)
-+ break;
-+ }
-+ range->num_bitrates = i;
-+
-+ range->max_qual.qual = 100;
-+ range->max_qual.level = 100;
-+ range->max_qual.noise = 100;
-+ /* TODO: better values */
-+ range->avg_qual.qual = 90;
-+ range->avg_qual.level = 80;
-+ range->avg_qual.noise = 2;
-+ }
-+
-+ return OK;
-+}
-+
-+
-+/*================================================================*/
-+/* Private functions */
-+/*================================================================*/
-+
-+#if WIRELESS_EXT < 13
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_iw_priv
-+*
-+* Comment: I added the monitor mode and changed the stuff below
-+* to look more like the orinoco driver
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_iw_priv(struct iwreq *iwr)
-+{
-+ int result = -EINVAL;
-+
-+ if (!iwr->u.data.pointer)
-+ return -EINVAL;
-+ result = verify_area(VERIFY_WRITE, iwr->u.data.pointer,
-+ sizeof(acx_ioctl_private_args));
-+ if (result)
-+ return result;
-+
-+ iwr->u.data.length = VEC_SIZE(acx_ioctl_private_args);
-+ if (copy_to_user(iwr->u.data.pointer, acx_ioctl_private_args, sizeof(acx_ioctl_private_args)) != 0)
-+ result = -EFAULT;
-+
-+ return result;
-+}
-+#endif
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_nick
-+*----------------------------------------------------------------*/
-+static inline int
-+acx_ioctl_get_nick(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ /* FIXME : consider spinlock here */
-+ strcpy(extra, priv->nick);
-+ /* FIXME : consider spinlock here */
-+
-+ dwrq->length = strlen(extra) + 1;
-+
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_nick
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_nick(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_point *dwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
-+ result = -E2BIG;
-+ goto end_unlock;
-+ }
-+
-+ /* extra includes trailing \0, so it's ok */
-+ strcpy(priv->nick, extra);
-+ result = OK;
-+
-+end_unlock:
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*------------------------------------------------------------------------------
-+ * acx_ioctl_get_retry
-+ *----------------------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_retry(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned int type = vwrq->flags & IW_RETRY_TYPE;
-+ unsigned int modifier = vwrq->flags & IW_RETRY_MODIFIER;
-+ int result;
-+
-+ acx_sem_lock(priv);
-+
-+ /* return the short retry number by default */
-+ if (type == IW_RETRY_LIFETIME) {
-+ vwrq->flags = IW_RETRY_LIFETIME;
-+ vwrq->value = priv->msdu_lifetime;
-+ } else if (modifier == IW_RETRY_MAX) {
-+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-+ vwrq->value = priv->long_retry;
-+ } else {
-+ vwrq->flags = IW_RETRY_LIMIT;
-+ if (priv->long_retry != priv->short_retry)
-+ SET_BIT(vwrq->flags, IW_RETRY_MIN);
-+ vwrq->value = priv->short_retry;
-+ }
-+
-+ /* can't be disabled */
-+ vwrq->disabled = (u8)0;
-+ result = OK;
-+
-+ acx_sem_unlock(priv);
-+
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_retry
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_retry(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ if (!vwrq) {
-+ result = -EFAULT;
-+ goto end;
-+ }
-+ if (vwrq->disabled) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ acx_sem_lock(priv);
-+
-+ result = -EINVAL;
-+ if (IW_RETRY_LIMIT == (vwrq->flags & IW_RETRY_TYPE)) {
-+ printk("old retry limits: short %d long %d\n",
-+ priv->short_retry, priv->long_retry);
-+ if (vwrq->flags & IW_RETRY_MAX) {
-+ priv->long_retry = vwrq->value;
-+ } else if (vwrq->flags & IW_RETRY_MIN) {
-+ priv->short_retry = vwrq->value;
-+ } else {
-+ /* no modifier: set both */
-+ priv->long_retry = vwrq->value;
-+ priv->short_retry = vwrq->value;
-+ }
-+ printk("new retry limits: short %d long %d\n",
-+ priv->short_retry, priv->long_retry);
-+ SET_BIT(priv->set_mask, GETSET_RETRY);
-+ result = -EINPROGRESS;
-+ }
-+ else if (vwrq->flags & IW_RETRY_LIFETIME) {
-+ priv->msdu_lifetime = vwrq->value;
-+ printk("new MSDU lifetime: %d\n", priv->msdu_lifetime);
-+ SET_BIT(priv->set_mask, SET_MSDU_LIFETIME);
-+ result = -EINPROGRESS;
-+ }
-+
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/******************************* private ioctls ******************************/
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_debug
-+*----------------------------------------------------------------*/
-+#if ACX_DEBUG
-+static int
-+acx_ioctl_set_debug(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ unsigned int debug_new = *((unsigned int *)extra);
-+ int result = -EINVAL;
-+
-+ acxlog(L_ANY, "setting debug from %04X to %04X\n", acx_debug, debug_new);
-+ acx_debug = debug_new;
-+
-+ result = OK;
-+ return result;
-+
-+}
-+#endif
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_list_reg_domain
-+*----------------------------------------------------------------*/
-+static const char * const
-+reg_domain_strings[] = {
-+ " 1-11 FCC (USA)",
-+ " 1-11 DOC/IC (Canada)",
-+ /* BTW: WLAN use in ETSI is regulated by
-+ * ETSI standard EN 300 328-2 V1.1.2 */
-+ " 1-13 ETSI (Europe)",
-+ "10-11 Spain",
-+ "10-13 France",
-+ " 14 MKK (Japan)",
-+ " 1-14 MKK1",
-+ " 3-9 Israel (not all firmware versions)",
-+ NULL /* needs to remain as last entry */
-+};
-+
-+static int
-+acx_ioctl_list_reg_domain(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+
-+ int i = 1;
-+ const char * const *entry = reg_domain_strings;
-+
-+ printk("dom# chan# domain/country\n");
-+ while (*entry)
-+ printk("%4d %s\n", i++, *entry++);
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_reg_domain
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_reg_domain(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ if ((*extra < 1) || ((size_t)*extra > reg_domain_ids_len)) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ acx_sem_lock(priv);
-+
-+ priv->reg_dom_id = reg_domain_ids[*extra - 1];
-+ SET_BIT(priv->set_mask, GETSET_REG_DOMAIN);
-+
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_reg_domain
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_reg_domain(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int dom,i;
-+
-+ /* no locking */
-+ dom = priv->reg_dom_id;
-+
-+ for (i=1; i <= 7; i++) {
-+ if (reg_domain_ids[i-1] == dom) {
-+ acxlog(L_IOCTL, "regulatory domain is currently set "
-+ "to %d (0x%X): %s\n", i, dom,
-+ reg_domain_strings[i-1]);
-+ *extra = i;
-+ break;
-+ }
-+ }
-+
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_short_preamble
-+*----------------------------------------------------------------*/
-+static const char * const
-+preamble_modes[] = {
-+ "off",
-+ "on",
-+ "auto (peer capability dependent)",
-+ "unknown mode, error"
-+};
-+
-+static int
-+acx_ioctl_set_short_preamble(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int i;
-+ int result;
-+
-+ FN_ENTER;
-+
-+ if ((unsigned char)*extra > 2) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ acx_sem_lock(priv);
-+
-+ priv->preamble_mode = (u8)*extra;
-+ switch (priv->preamble_mode) {
-+ case 0: /* long */
-+ priv->preamble_cur = 0;
-+ break;
-+ case 1:
-+ /* short, kick incapable peers */
-+ priv->preamble_cur = 1;
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ client_t *clt = &priv->sta_list[i];
-+ if (!clt->used) continue;
-+ if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) {
-+ clt->used = CLIENT_EMPTY_SLOT_0;
-+ }
-+ }
-+ switch (priv->mode) {
-+ case ACX_MODE_2_STA:
-+ if (priv->ap_client && !priv->ap_client->used) {
-+ /* We kicked our AP :) */
-+ SET_BIT(priv->set_mask, GETSET_RESCAN);
-+ }
-+ }
-+ break;
-+ case 2: /* auto. short only if all peers are short-capable */
-+ priv->preamble_cur = 1;
-+ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
-+ client_t *clt = &priv->sta_list[i];
-+ if (!clt->used) continue;
-+ if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) {
-+ priv->preamble_cur = 0;
-+ break;
-+ }
-+ }
-+ break;
-+ }
-+ printk("new short preamble setting: configured %s, active %s\n",
-+ preamble_modes[priv->preamble_mode],
-+ preamble_modes[priv->preamble_cur]);
-+ result = OK;
-+
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_short_preamble
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_short_preamble(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ printk("current short preamble setting: configured %s, active %s\n",
-+ preamble_modes[priv->preamble_mode],
-+ preamble_modes[priv->preamble_cur]);
-+
-+ *extra = (char)priv->preamble_mode;
-+
-+ acx_sem_unlock(priv);
-+
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_antenna
-+*
-+* Comment: TX and RX antenna can be set separately but this function good
-+* for testing 0-4 bits
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_antenna(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ printk("old antenna value: 0x%02X (COMBINED bit mask)\n"
-+ "Rx antenna selection:\n"
-+ "0x00 ant. 1\n"
-+ "0x40 ant. 2\n"
-+ "0x80 full diversity\n"
-+ "0xc0 partial diversity\n"
-+ "0x0f dwell time mask (in units of us)\n"
-+ "Tx antenna selection:\n"
-+ "0x00 ant. 2\n" /* yep, those ARE reversed! */
-+ "0x20 ant. 1\n"
-+ "new antenna value: 0x%02X\n",
-+ priv->antenna, (u8)*extra);
-+
-+ priv->antenna = (u8)*extra;
-+ SET_BIT(priv->set_mask, GETSET_ANTENNA);
-+
-+ acx_sem_unlock(priv);
-+
-+ return -EINPROGRESS;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_antenna
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_antenna(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ /* no locking. it's pointless to lock a single load */
-+ printk("current antenna value: 0x%02X (COMBINED bit mask)\n"
-+ "Rx antenna selection:\n"
-+ "0x00 ant. 1\n"
-+ "0x40 ant. 2\n"
-+ "0x80 full diversity\n"
-+ "0xc0 partial diversity\n"
-+ "Tx antenna selection:\n"
-+ "0x00 ant. 2\n" /* yep, those ARE reversed! */
-+ "0x20 ant. 1\n", priv->antenna);
-+
-+ return 0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_rx_antenna
-+*
-+*
-+* Arguments:
-+* 0 = antenna1; 1 = antenna2; 2 = full diversity; 3 = partial diversity
-+* Comment: Could anybody test which antenna is the external one
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_rx_antenna(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ if (*extra > 3) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ printk("old antenna value: 0x%02X\n", priv->antenna);
-+
-+ acx_sem_lock(priv);
-+
-+ priv->antenna &= 0x3f;
-+ SET_BIT(priv->antenna, (*extra << 6));
-+ SET_BIT(priv->set_mask, GETSET_ANTENNA);
-+ printk("new antenna value: 0x%02X\n", priv->antenna);
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_tx_antenna
-+*
-+*
-+* Arguments: 0 == antenna2; 1 == antenna1;
-+* Comment: Could anybody test which antenna is the external one
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_set_tx_antenna(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ if (*extra > 1) {
-+ result = -EINVAL;
-+ goto end;
-+ }
-+
-+ printk("old antenna value: 0x%02X\n", priv->antenna);
-+
-+ acx_sem_lock(priv);
-+
-+ priv->antenna &= ~0x30;
-+ SET_BIT(priv->antenna, ((*extra & 0x01) << 5));
-+ SET_BIT(priv->set_mask, GETSET_ANTENNA);
-+ printk("new antenna value: 0x%02X\n", priv->antenna);
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_wlansniff
-+*
-+* can we just remove this in favor of monitor mode? --vda
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_wlansniff(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned int *params = (unsigned int*)extra;
-+ unsigned int enable = (unsigned int)(params[0] > 0);
-+ int result;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ /* not using printk() here, since it distorts kismet display
-+ * when printk messages activated */
-+ acxlog(L_IOCTL, "setting monitor to: 0x%02X\n", params[0]);
-+
-+ switch (params[0]) {
-+ case 0:
-+ priv->netdev->type = ARPHRD_ETHER;
-+ break;
-+ case 1:
-+ priv->netdev->type = ARPHRD_IEEE80211_PRISM;
-+ break;
-+ case 2:
-+ priv->netdev->type = ARPHRD_IEEE80211;
-+ break;
-+ }
-+
-+ if (params[0]) {
-+ priv->mode = ACX_MODE_MONITOR;
-+ SET_BIT(priv->set_mask, GETSET_MODE);
-+ }
-+
-+ if (enable) {
-+ priv->channel = params[1];
-+ SET_BIT(priv->set_mask, GETSET_RX);
-+ }
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_unknown11
-+* FIXME: looks like some sort of "iwpriv kick_sta MAC" but it's broken
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_unknown11(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+#ifdef BROKEN
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ client_t client;
-+ int result;
-+
-+ acx_sem_lock(priv);
-+ acx_lock(priv, flags);
-+
-+ acx_l_transmit_disassoc(priv, &client);
-+ result = OK;
-+
-+ acx_unlock(priv, flags);
-+ acx_sem_unlock(priv);
-+
-+ return result;
-+#endif
-+ return -EINVAL;
-+}
-+
-+
-+/***********************************************************************
-+** debug helper function to be able to debug various issues relatively easily
-+*/
-+static int
-+acx_ioctl_dbg_set_masks(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ const unsigned int *params = (unsigned int*)extra;
-+ int result;
-+
-+ acx_sem_lock(priv);
-+
-+ acxlog(L_IOCTL, "setting flags in settings mask: "
-+ "get_mask %08X set_mask %08X\n"
-+ "before: get_mask %08X set_mask %08X\n",
-+ params[0], params[1],
-+ priv->get_mask, priv->set_mask);
-+ SET_BIT(priv->get_mask, params[0]);
-+ SET_BIT(priv->set_mask, params[1]);
-+ acxlog(L_IOCTL, "after: get_mask %08X set_mask %08X\n",
-+ priv->get_mask, priv->set_mask);
-+ result = -EINPROGRESS; /* immediately call commit handler */
-+
-+ acx_sem_unlock(priv);
-+
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_rates
-+*
-+* This ioctl takes string parameter. Examples:
-+* iwpriv wlan0 SetRates "1,2"
-+* use 1 and 2 Mbit rates, both are in basic rate set
-+* iwpriv wlan0 SetRates "1,2 5,11"
-+* use 1,2,5.5,11 Mbit rates. 1 and 2 are basic
-+* iwpriv wlan0 SetRates "1,2 5c,11c"
-+* same ('c' means 'CCK modulation' and it is a default for 5 and 11)
-+* iwpriv wlan0 SetRates "1,2 5p,11p"
-+* use 1,2,5.5,11 Mbit, 1,2 are basic. 5 and 11 are using PBCC
-+* iwpriv wlan0 SetRates "1,2,5,11 22p"
-+* use 1,2,5.5,11,22 Mbit. 1,2,5.5 and 11 are basic. 22 is using PBCC
-+* (this is the maximum acx100 can do (modulo x4 mode))
-+* iwpriv wlan0 SetRates "1,2,5,11 22"
-+* same. 802.11 defines only PBCC modulation
-+* for 22 and 33 Mbit rates, so there is no ambiguity
-+* iwpriv wlan0 SetRates "1,2,5,11 6o,9o,12o,18o,24o,36o,48o,54o"
-+* 1,2,5.5 and 11 are basic. 11g OFDM rates are enabled but
-+* they are not in basic rate set. 22 Mbit is disabled.
-+* iwpriv wlan0 SetRates "1,2,5,11 6,9,12,18,24,36,48,54"
-+* same. OFDM is default for 11g rates except 22 and 33 Mbit,
-+* thus 'o' is optional
-+* iwpriv wlan0 SetRates "1,2,5,11 6d,9d,12d,18d,24d,36d,48d,54d"
-+* 1,2,5.5 and 11 are basic. 11g CCK-OFDM rates are enabled
-+* (acx111 does not support CCK-OFDM, driver will reject this cmd)
-+* iwpriv wlan0 SetRates "6,9,12 18,24,36,48,54"
-+* 6,9,12 are basic, rest of 11g rates is enabled. Using OFDM
-+*----------------------------------------------------------------*/
-+#include "setrate.c"
-+
-+/* disallow: 33Mbit (unsupported by hw) */
-+/* disallow: CCKOFDM (unsupported by hw) */
-+static int
-+acx111_supported(int mbit, int modulation, void *opaque)
-+{
-+ if (mbit==33) return -ENOTSUPP;
-+ if (modulation==DOT11_MOD_CCKOFDM) return -ENOTSUPP;
-+ return OK;
-+}
-+
-+static const u16
-+acx111mask[] = {
-+ [DOT11_RATE_1 ] = RATE111_1 ,
-+ [DOT11_RATE_2 ] = RATE111_2 ,
-+ [DOT11_RATE_5 ] = RATE111_5 ,
-+ [DOT11_RATE_11] = RATE111_11,
-+ [DOT11_RATE_22] = RATE111_22,
-+ /* [DOT11_RATE_33] = */
-+ [DOT11_RATE_6 ] = RATE111_6 ,
-+ [DOT11_RATE_9 ] = RATE111_9 ,
-+ [DOT11_RATE_12] = RATE111_12,
-+ [DOT11_RATE_18] = RATE111_18,
-+ [DOT11_RATE_24] = RATE111_24,
-+ [DOT11_RATE_36] = RATE111_36,
-+ [DOT11_RATE_48] = RATE111_48,
-+ [DOT11_RATE_54] = RATE111_54,
-+};
-+
-+static u32
-+acx111_gen_mask(int mbit, int modulation, void *opaque)
-+{
-+ /* lower 16 bits show selected 1, 2, CCK and OFDM rates */
-+ /* upper 16 bits show selected PBCC rates */
-+ u32 m = acx111mask[rate_mbit2enum(mbit)];
-+ if (modulation==DOT11_MOD_PBCC)
-+ return m<<16;
-+ return m;
-+}
-+
-+static int
-+verify_rate(u32 rate, int chip_type)
-+{
-+ /* never happens. be paranoid */
-+ if (!rate) return -EINVAL;
-+
-+ /* disallow: mixing PBCC and CCK at 5 and 11Mbit
-+ ** (can be supported, but needs complicated handling in tx code) */
-+ if (( rate & ((RATE111_11+RATE111_5)<<16) )
-+ && ( rate & (RATE111_11+RATE111_5) )
-+ ) {
-+ return -ENOTSUPP;
-+ }
-+ if (CHIPTYPE_ACX100 == chip_type) {
-+ if ( rate & ~(RATE111_ACX100_COMPAT+(RATE111_ACX100_COMPAT<<16)) )
-+ return -ENOTSUPP;
-+ }
-+ return 0;
-+}
-+
-+static int
-+acx_ioctl_set_rates(struct net_device *dev, struct iw_request_info *info,
-+ struct iw_param *vwrq, char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ int result;
-+ u32 brate = 0, orate = 0; /* basic, operational rate set */
-+
-+ FN_ENTER;
-+
-+ acxlog(L_IOCTL, "set_rates %s\n", extra);
-+ result = fill_ratemasks(extra, &brate, &orate,
-+ acx111_supported, acx111_gen_mask, 0);
-+ if (result) goto end;
-+ SET_BIT(orate, brate);
-+ acxlog(L_IOCTL, "brate %08X orate %08X\n", brate, orate);
-+
-+ result = verify_rate(brate, priv->chip_type);
-+ if (result) goto end;
-+ result = verify_rate(orate, priv->chip_type);
-+ if (result) goto end;
-+
-+ acx_sem_lock(priv);
-+ acx_lock(priv, flags);
-+
-+ priv->rate_basic = brate;
-+ priv->rate_oper = orate;
-+ /* TODO: ideally, we shall monitor highest basic rate
-+ ** which was successfully sent to every peer
-+ ** (say, last we checked, everybody could hear 5.5 Mbits)
-+ ** and use that for bcasts when we want to reach all peers.
-+ ** For beacons, we probably shall use lowest basic rate
-+ ** because we want to reach all *potential* new peers too */
-+ priv->rate_bcast = 1 << lowest_bit(brate);
-+ if (IS_ACX100(priv))
-+ priv->rate_bcast100 = acx_rate111to100(priv->rate_bcast);
-+ priv->rate_auto = !has_only_one_bit(orate);
-+ acx_l_update_client_rates(priv, orate);
-+ /* TODO: get rid of ratevector, build it only when needed */
-+ acx_l_update_ratevector(priv);
-+
-+ /* Do/don't do tx rate fallback; beacon contents and rate */
-+ SET_BIT(priv->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES);
-+ result = -EINPROGRESS;
-+
-+ acx_unlock(priv, flags);
-+ acx_sem_unlock(priv);
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_get_phy_chan_busy_percentage
-+*----------------------------------------------------------------*/
-+static int
-+acx_ioctl_get_phy_chan_busy_percentage(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ struct { /* added ACX_PACKED, not tested --vda */
-+ u16 type ACX_PACKED;
-+ u16 len ACX_PACKED;
-+ u32 busytime ACX_PACKED;
-+ u32 totaltime ACX_PACKED;
-+ } usage;
-+
-+ acx_sem_lock(priv);
-+
-+ if (OK != acx_s_interrogate(priv, &usage, ACX1xx_IE_MEDIUM_USAGE))
-+ goto bad_unlock;
-+
-+ printk("%s: average busy percentage since last invocation: %d%% "
-+ "(microseconds: %u of %u)\n",
-+ dev->name,
-+ 100 * (le32_to_cpu(usage.busytime) / 100) / (le32_to_cpu(usage.totaltime) / 100),
-+ le32_to_cpu(usage.busytime), le32_to_cpu(usage.totaltime));
-+ /* prevent calculation overflow */
-+
-+ acx_sem_unlock(priv);
-+
-+ return OK;
-+
-+bad_unlock:
-+ acx_sem_unlock(priv);
-+
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_ed_threshold
-+*----------------------------------------------------------------*/
-+static inline int
-+acx_ioctl_set_ed_threshold(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ printk("old ED threshold value: %d\n", priv->ed_threshold);
-+ priv->ed_threshold = (unsigned char)*extra;
-+ printk("new ED threshold value: %d\n", (unsigned char)*extra);
-+ SET_BIT(priv->set_mask, GETSET_ED_THRESH);
-+
-+ acx_sem_unlock(priv);
-+
-+ return -EINPROGRESS;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_ioctl_set_cca
-+*----------------------------------------------------------------*/
-+static inline int
-+acx_ioctl_set_cca(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ acx_sem_lock(priv);
-+
-+ printk("old CCA value: 0x%02X\n", priv->cca);
-+ priv->cca = (unsigned char)*extra;
-+ printk("new CCA value: 0x%02X\n", (unsigned char)*extra);
-+ SET_BIT(priv->set_mask, GETSET_CCA);
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static const char * const
-+scan_modes[] = { "active", "passive", "background" };
-+
-+static void
-+acx_print_scan_params(wlandevice_t *priv, const char* head)
-+{
-+ printk("%s: %smode %d (%s), min chan time %dTU, "
-+ "max chan time %dTU, max scan rate byte: %d\n",
-+ priv->netdev->name, head,
-+ priv->scan_mode, scan_modes[priv->scan_mode],
-+ priv->scan_probe_delay, priv->scan_duration, priv->scan_rate);
-+}
-+
-+static int
-+acx_ioctl_set_scan_params(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+ const int *params = (int *)extra;
-+
-+ acx_sem_lock(priv);
-+
-+ acx_print_scan_params(priv, "old scan parameters: ");
-+ if ((params[0] != -1) && (params[0] >= 0) && (params[0] <= 2))
-+ priv->scan_mode = params[0];
-+ if (params[1] != -1)
-+ priv->scan_probe_delay = params[1];
-+ if (params[2] != -1)
-+ priv->scan_duration = params[2];
-+ if ((params[3] != -1) && (params[3] <= 255))
-+ priv->scan_rate = params[3];
-+ acx_print_scan_params(priv, "new scan parameters: ");
-+ SET_BIT(priv->set_mask, GETSET_RESCAN);
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+
-+ return result;
-+}
-+
-+static int
-+acx_ioctl_get_scan_params(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+ int *params = (int *)extra;
-+
-+ acx_sem_lock(priv);
-+
-+ acx_print_scan_params(priv, "current scan parameters: ");
-+ params[0] = priv->scan_mode;
-+ params[1] = priv->scan_probe_delay;
-+ params[2] = priv->scan_duration;
-+ params[3] = priv->scan_rate;
-+ result = OK;
-+
-+ acx_sem_unlock(priv);
-+
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx100_ioctl_set_led_power(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ static const char * const led_modes[] = { "off", "on", "LinkQuality" };
-+
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result;
-+
-+ acx_sem_lock(priv);
-+
-+ printk("%s: power LED status: old %d (%s), ",
-+ dev->name,
-+ priv->led_power,
-+ led_modes[priv->led_power]);
-+ priv->led_power = extra[0];
-+ if (priv->led_power > 2) priv->led_power = 2;
-+ printk("new %d (%s)\n",
-+ priv->led_power,
-+ led_modes[priv->led_power]);
-+
-+ if (priv->led_power == 2) {
-+ printk("%s: max link quality setting: old %d, ",
-+ dev->name, priv->brange_max_quality);
-+ if (extra[1])
-+ priv->brange_max_quality = extra[1];
-+ printk("new %d\n", priv->brange_max_quality);
-+ }
-+
-+ SET_BIT(priv->set_mask, GETSET_LED_POWER);
-+
-+ result = -EINPROGRESS;
-+
-+ acx_sem_unlock(priv);
-+
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static inline int
-+acx100_ioctl_get_led_power(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ extra[0] = priv->led_power;
-+ if (priv->led_power == 2)
-+ extra[1] = priv->brange_max_quality;
-+ else
-+ extra[1] = -1;
-+
-+ acx_sem_unlock(priv);
-+
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx111_ioctl_info(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ if (!IS_PCI((wlandevice_t*)netdev_priv(dev)))
-+ return OK;
-+ return acx111pci_ioctl_info(dev, info, vwrq, extra);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static int
-+acx100_ioctl_set_phy_amp_bias(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ if (!IS_PCI((wlandevice_t*)netdev_priv(dev))) {
-+ printk("acx: set_phy_amp_bias() is not supported on USB\n");
-+ return OK;
-+ }
-+ return acx100pci_ioctl_set_phy_amp_bias(dev, info, vwrq, extra);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+#if WIRELESS_EXT >= 13
-+static const iw_handler acx_ioctl_handler[] =
-+{
-+ (iw_handler) acx_ioctl_commit, /* SIOCSIWCOMMIT */
-+ (iw_handler) acx_ioctl_get_name, /* SIOCGIWNAME */
-+ (iw_handler) NULL, /* SIOCSIWNWID */
-+ (iw_handler) NULL, /* SIOCGIWNWID */
-+ (iw_handler) acx_ioctl_set_freq, /* SIOCSIWFREQ */
-+ (iw_handler) acx_ioctl_get_freq, /* SIOCGIWFREQ */
-+ (iw_handler) acx_ioctl_set_mode, /* SIOCSIWMODE */
-+ (iw_handler) acx_ioctl_get_mode, /* SIOCGIWMODE */
-+ (iw_handler) acx_ioctl_set_sens, /* SIOCSIWSENS */
-+ (iw_handler) acx_ioctl_get_sens, /* SIOCGIWSENS */
-+ (iw_handler) NULL, /* SIOCSIWRANGE */
-+ (iw_handler) acx_ioctl_get_range, /* SIOCGIWRANGE */
-+ (iw_handler) NULL, /* SIOCSIWPRIV */
-+ (iw_handler) NULL, /* SIOCGIWPRIV */
-+ (iw_handler) NULL, /* SIOCSIWSTATS */
-+ (iw_handler) NULL, /* SIOCGIWSTATS */
-+#if IW_HANDLER_VERSION > 4
-+ iw_handler_set_spy, /* SIOCSIWSPY */
-+ iw_handler_get_spy, /* SIOCGIWSPY */
-+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
-+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
-+#else /* IW_HANDLER_VERSION > 4 */
-+#ifdef WIRELESS_SPY
-+ (iw_handler) NULL /* acx_ioctl_set_spy FIXME */, /* SIOCSIWSPY */
-+ (iw_handler) NULL /* acx_ioctl_get_spy FIXME */, /* SIOCGIWSPY */
-+#else /* WSPY */
-+ (iw_handler) NULL, /* SIOCSIWSPY */
-+ (iw_handler) NULL, /* SIOCGIWSPY */
-+#endif /* WSPY */
-+ (iw_handler) NULL, /* [nothing] */
-+ (iw_handler) NULL, /* [nothing] */
-+#endif /* IW_HANDLER_VERSION > 4 */
-+ (iw_handler) acx_ioctl_set_ap, /* SIOCSIWAP */
-+ (iw_handler) acx_ioctl_get_ap, /* SIOCGIWAP */
-+ (iw_handler) NULL, /* [nothing] */
-+ (iw_handler) acx_ioctl_get_aplist, /* SIOCGIWAPLIST */
-+#if WIRELESS_EXT > 13
-+ (iw_handler) acx_ioctl_set_scan, /* SIOCSIWSCAN */
-+ (iw_handler) acx_ioctl_get_scan, /* SIOCGIWSCAN */
-+#else /* WE > 13 */
-+ (iw_handler) NULL, /* SIOCSIWSCAN */
-+ (iw_handler) NULL, /* SIOCGIWSCAN */
-+#endif /* WE > 13 */
-+ (iw_handler) acx_ioctl_set_essid, /* SIOCSIWESSID */
-+ (iw_handler) acx_ioctl_get_essid, /* SIOCGIWESSID */
-+ (iw_handler) acx_ioctl_set_nick, /* SIOCSIWNICKN */
-+ (iw_handler) acx_ioctl_get_nick, /* SIOCGIWNICKN */
-+ (iw_handler) NULL, /* [nothing] */
-+ (iw_handler) NULL, /* [nothing] */
-+ (iw_handler) acx_ioctl_set_rate, /* SIOCSIWRATE */
-+ (iw_handler) acx_ioctl_get_rate, /* SIOCGIWRATE */
-+ (iw_handler) acx_ioctl_set_rts, /* SIOCSIWRTS */
-+ (iw_handler) acx_ioctl_get_rts, /* SIOCGIWRTS */
-+ (iw_handler) NULL /* acx_ioctl_set_frag FIXME */, /* SIOCSIWFRAG */
-+ (iw_handler) NULL /* acx_ioctl_get_frag FIXME */, /* SIOCGIWFRAG */
-+ (iw_handler) acx_ioctl_set_txpow, /* SIOCSIWTXPOW */
-+ (iw_handler) acx_ioctl_get_txpow, /* SIOCGIWTXPOW */
-+ (iw_handler) acx_ioctl_set_retry, /* SIOCSIWRETRY */
-+ (iw_handler) acx_ioctl_get_retry, /* SIOCGIWRETRY */
-+ (iw_handler) acx_ioctl_set_encode, /* SIOCSIWENCODE */
-+ (iw_handler) acx_ioctl_get_encode, /* SIOCGIWENCODE */
-+ (iw_handler) acx_ioctl_set_power, /* SIOCSIWPOWER */
-+ (iw_handler) acx_ioctl_get_power, /* SIOCGIWPOWER */
-+};
-+
-+static const iw_handler acx_ioctl_private_handler[] =
-+{
-+#if ACX_DEBUG
-+[ACX100_IOCTL_DEBUG - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_debug,
-+#else
-+[ACX100_IOCTL_DEBUG - ACX100_IOCTL] = (iw_handler) NULL,
-+#endif
-+[ACX100_IOCTL_SET_PLED - ACX100_IOCTL] = (iw_handler) acx100_ioctl_set_led_power,
-+[ACX100_IOCTL_GET_PLED - ACX100_IOCTL] = (iw_handler) acx100_ioctl_get_led_power,
-+[ACX100_IOCTL_SET_RATES - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_rates,
-+[ACX100_IOCTL_LIST_DOM - ACX100_IOCTL] = (iw_handler) acx_ioctl_list_reg_domain,
-+[ACX100_IOCTL_SET_DOM - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_reg_domain,
-+[ACX100_IOCTL_GET_DOM - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_reg_domain,
-+[ACX100_IOCTL_SET_SCAN_PARAMS - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_scan_params,
-+[ACX100_IOCTL_GET_SCAN_PARAMS - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_scan_params,
-+[ACX100_IOCTL_SET_PREAMB - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_short_preamble,
-+[ACX100_IOCTL_GET_PREAMB - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_short_preamble,
-+[ACX100_IOCTL_SET_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_antenna,
-+[ACX100_IOCTL_GET_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_antenna,
-+[ACX100_IOCTL_RX_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_rx_antenna,
-+[ACX100_IOCTL_TX_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_tx_antenna,
-+[ACX100_IOCTL_SET_PHY_AMP_BIAS - ACX100_IOCTL] = (iw_handler) acx100_ioctl_set_phy_amp_bias,
-+[ACX100_IOCTL_GET_PHY_CHAN_BUSY - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_phy_chan_busy_percentage,
-+[ACX100_IOCTL_SET_ED - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_ed_threshold,
-+[ACX100_IOCTL_SET_CCA - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_cca,
-+[ACX100_IOCTL_MONITOR - ACX100_IOCTL] = (iw_handler) acx_ioctl_wlansniff,
-+[ACX100_IOCTL_TEST - ACX100_IOCTL] = (iw_handler) acx_ioctl_unknown11,
-+[ACX100_IOCTL_DBG_SET_MASKS - ACX100_IOCTL] = (iw_handler) acx_ioctl_dbg_set_masks,
-+[ACX111_IOCTL_INFO - ACX100_IOCTL] = (iw_handler) acx111_ioctl_info,
-+};
-+
-+const struct iw_handler_def acx_ioctl_handler_def =
-+{
-+ .num_standard = VEC_SIZE(acx_ioctl_handler),
-+ .num_private = VEC_SIZE(acx_ioctl_private_handler),
-+ .num_private_args = VEC_SIZE(acx_ioctl_private_args),
-+ .standard = (iw_handler *) acx_ioctl_handler,
-+ .private = (iw_handler *) acx_ioctl_private_handler,
-+ .private_args = (struct iw_priv_args *) acx_ioctl_private_args,
-+};
-+
-+#endif /* WE >= 13 */
-+
-+
-+#if WIRELESS_EXT < 13
-+/*================================================================*/
-+/* Main function */
-+/*================================================================*/
-+/*----------------------------------------------------------------
-+* acx_e_ioctl_old
-+*
-+* Comment:
-+* This is the *OLD* ioctl handler.
-+* Make sure to not only place your additions here, but instead mainly
-+* in the new one (acx_ioctl_handler[])!
-+*----------------------------------------------------------------*/
-+int
-+acx_e_ioctl_old(netdevice_t *dev, struct ifreq *ifr, int cmd)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result = 0;
-+ struct iwreq *iwr = (struct iwreq *)ifr;
-+
-+ acxlog(L_IOCTL, "%s cmd = 0x%04X\n", __func__, cmd);
-+
-+ /* This is the way it is done in the orinoco driver.
-+ * Check to see if device is present.
-+ */
-+ if (0 == netif_device_present(dev)) {
-+ return -ENODEV;
-+ }
-+
-+ switch (cmd) {
-+/* WE 13 and higher will use acx_ioctl_handler_def */
-+ case SIOCGIWNAME:
-+ /* get name == wireless protocol */
-+ result = acx_ioctl_get_name(dev, NULL,
-+ (char *)&(iwr->u.name), NULL);
-+ break;
-+
-+ case SIOCSIWNWID: /* pre-802.11, */
-+ case SIOCGIWNWID: /* not supported. */
-+ result = -EOPNOTSUPP;
-+ break;
-+
-+ case SIOCSIWFREQ:
-+ /* set channel/frequency (Hz)
-+ data can be frequency or channel :
-+ 0-1000 = channel
-+ > 1000 = frequency in Hz */
-+ result = acx_ioctl_set_freq(dev, NULL, &(iwr->u.freq), NULL);
-+ break;
-+
-+ case SIOCGIWFREQ:
-+ /* get channel/frequency (Hz) */
-+ result = acx_ioctl_get_freq(dev, NULL, &(iwr->u.freq), NULL);
-+ break;
-+
-+ case SIOCSIWMODE:
-+ /* set operation mode */
-+ result = acx_ioctl_set_mode(dev, NULL, &(iwr->u.mode), NULL);
-+ break;
-+
-+ case SIOCGIWMODE:
-+ /* get operation mode */
-+ result = acx_ioctl_get_mode(dev, NULL, &(iwr->u.mode), NULL);
-+ break;
-+
-+ case SIOCSIWSENS:
-+ /* Set sensitivity */
-+ result = acx_ioctl_set_sens(dev, NULL, &(iwr->u.sens), NULL);
-+ break;
-+
-+ case SIOCGIWSENS:
-+ /* Get sensitivity */
-+ result = acx_ioctl_get_sens(dev, NULL, &(iwr->u.sens), NULL);
-+ break;
-+
-+#if WIRELESS_EXT > 10
-+ case SIOCGIWRANGE:
-+ /* Get range of parameters */
-+ {
-+ struct iw_range range;
-+ result = acx_ioctl_get_range(dev, NULL,
-+ &(iwr->u.data), (char *)&range);
-+ if (copy_to_user(iwr->u.data.pointer, &range,
-+ sizeof(struct iw_range)))
-+ result = -EFAULT;
-+ }
-+ break;
-+#endif
-+
-+ case SIOCGIWPRIV:
-+ result = acx_ioctl_get_iw_priv(iwr);
-+ break;
-+
-+ /* FIXME: */
-+ /* case SIOCSIWSPY: */
-+ /* case SIOCGIWSPY: */
-+ /* case SIOCSIWTHRSPY: */
-+ /* case SIOCGIWTHRSPY: */
-+
-+ case SIOCSIWAP:
-+ /* set access point by MAC address */
-+ result = acx_ioctl_set_ap(dev, NULL, &(iwr->u.ap_addr),
-+ NULL);
-+ break;
-+
-+ case SIOCGIWAP:
-+ /* get access point MAC address */
-+ result = acx_ioctl_get_ap(dev, NULL, &(iwr->u.ap_addr),
-+ NULL);
-+ break;
-+
-+ case SIOCGIWAPLIST:
-+ /* get list of access points in range */
-+ result = acx_ioctl_get_aplist(dev, NULL, &(iwr->u.data),
-+ NULL);
-+ break;
-+
-+#if NOT_FINISHED_YET
-+ /* FIXME: do proper interfacing to activate that! */
-+ case SIOCSIWSCAN:
-+ /* start a station scan */
-+ result = acx_ioctl_set_scan(iwr, priv);
-+ break;
-+
-+ case SIOCGIWSCAN:
-+ /* get list of stations found during scan */
-+ result = acx_ioctl_get_scan(iwr, priv);
-+ break;
-+#endif
-+
-+ case SIOCSIWESSID:
-+ /* set ESSID (network name) */
-+ {
-+ char essid[IW_ESSID_MAX_SIZE+1];
-+
-+ if (iwr->u.essid.length > IW_ESSID_MAX_SIZE)
-+ {
-+ result = -E2BIG;
-+ break;
-+ }
-+ if (copy_from_user(essid, iwr->u.essid.pointer,
-+ iwr->u.essid.length))
-+ {
-+ result = -EFAULT;
-+ break;
-+ }
-+ result = acx_ioctl_set_essid(dev, NULL,
-+ &(iwr->u.essid), essid);
-+ }
-+ break;
-+
-+ case SIOCGIWESSID:
-+ /* get ESSID */
-+ {
-+ char essid[IW_ESSID_MAX_SIZE+1];
-+ if (iwr->u.essid.pointer)
-+ result = acx_ioctl_get_essid(dev, NULL,
-+ &(iwr->u.essid), essid);
-+ if (copy_to_user(iwr->u.essid.pointer, essid,
-+ iwr->u.essid.length))
-+ result = -EFAULT;
-+ }
-+ break;
-+
-+ case SIOCSIWNICKN:
-+ /* set nick */
-+ {
-+ char nick[IW_ESSID_MAX_SIZE+1];
-+
-+ if (iwr->u.data.length > IW_ESSID_MAX_SIZE)
-+ {
-+ result = -E2BIG;
-+ break;
-+ }
-+ if (copy_from_user(nick, iwr->u.data.pointer,
-+ iwr->u.data.length))
-+ {
-+ result = -EFAULT;
-+ break;
-+ }
-+ result = acx_ioctl_set_nick(dev, NULL,
-+ &(iwr->u.data), nick);
-+ }
-+ break;
-+
-+ case SIOCGIWNICKN:
-+ /* get nick */
-+ {
-+ char nick[IW_ESSID_MAX_SIZE+1];
-+ if (iwr->u.data.pointer)
-+ result = acx_ioctl_get_nick(dev, NULL,
-+ &(iwr->u.data), nick);
-+ if (copy_to_user(iwr->u.data.pointer, nick,
-+ iwr->u.data.length))
-+ result = -EFAULT;
-+ }
-+ break;
-+
-+ case SIOCSIWRATE:
-+ /* set default bit rate (bps) */
-+ result = acx_ioctl_set_rate(dev, NULL, &(iwr->u.bitrate),
-+ NULL);
-+ break;
-+
-+ case SIOCGIWRATE:
-+ /* get default bit rate (bps) */
-+ result = acx_ioctl_get_rate(dev, NULL, &(iwr->u.bitrate),
-+ NULL);
-+ break;
-+
-+ case SIOCSIWRTS:
-+ /* set RTS threshold value */
-+ result = acx_ioctl_set_rts(dev, NULL, &(iwr->u.rts), NULL);
-+ break;
-+ case SIOCGIWRTS:
-+ /* get RTS threshold value */
-+ result = acx_ioctl_get_rts(dev, NULL, &(iwr->u.rts), NULL);
-+ break;
-+
-+ /* FIXME: */
-+ /* case SIOCSIWFRAG: */
-+ /* case SIOCGIWFRAG: */
-+
-+#if WIRELESS_EXT > 9
-+ case SIOCGIWTXPOW:
-+ /* get tx power */
-+ result = acx_ioctl_get_txpow(dev, NULL, &(iwr->u.txpower),
-+ NULL);
-+ break;
-+
-+ case SIOCSIWTXPOW:
-+ /* set tx power */
-+ result = acx_ioctl_set_txpow(dev, NULL, &(iwr->u.txpower),
-+ NULL);
-+ break;
-+#endif
-+
-+ case SIOCSIWRETRY:
-+ result = acx_ioctl_set_retry(dev, NULL, &(iwr->u.retry), NULL);
-+ break;
-+
-+ case SIOCGIWRETRY:
-+ result = acx_ioctl_get_retry(dev, NULL, &(iwr->u.retry), NULL);
-+ break;
-+
-+ case SIOCSIWENCODE:
-+ {
-+ /* set encoding token & mode */
-+ u8 key[29];
-+ if (iwr->u.encoding.pointer) {
-+ if (iwr->u.encoding.length > 29) {
-+ result = -E2BIG;
-+ break;
-+ }
-+ if (copy_from_user(key, iwr->u.encoding.pointer,
-+ iwr->u.encoding.length)) {
-+ result = -EFAULT;
-+ break;
-+ }
-+ }
-+ else
-+ if (iwr->u.encoding.length) {
-+ result = -EINVAL;
-+ break;
-+ }
-+ result = acx_ioctl_set_encode(dev, NULL,
-+ &(iwr->u.encoding), key);
-+ }
-+ break;
-+
-+ case SIOCGIWENCODE:
-+ {
-+ /* get encoding token & mode */
-+ u8 key[29];
-+
-+ result = acx_ioctl_get_encode(dev, NULL,
-+ &(iwr->u.encoding), key);
-+ if (iwr->u.encoding.pointer) {
-+ if (copy_to_user(iwr->u.encoding.pointer,
-+ key, iwr->u.encoding.length))
-+ result = -EFAULT;
-+ }
-+ }
-+ break;
-+
-+ /******************** iwpriv ioctls below ********************/
-+#if ACX_DEBUG
-+ case ACX100_IOCTL_DEBUG:
-+ acx_ioctl_set_debug(dev, NULL, NULL, iwr->u.name);
-+ break;
-+#endif
-+
-+ case ACX100_IOCTL_SET_PLED:
-+ acx100_ioctl_set_led_power(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_GET_PLED:
-+ acx100_ioctl_get_led_power(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_LIST_DOM:
-+ acx_ioctl_list_reg_domain(dev, NULL, NULL, NULL);
-+ break;
-+
-+ case ACX100_IOCTL_SET_DOM:
-+ acx_ioctl_set_reg_domain(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_GET_DOM:
-+ acx_ioctl_get_reg_domain(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_SET_SCAN_PARAMS:
-+ acx_ioctl_set_scan_params(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_GET_SCAN_PARAMS:
-+ acx_ioctl_get_scan_params(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_SET_PREAMB:
-+ acx_ioctl_set_short_preamble(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_GET_PREAMB:
-+ acx_ioctl_get_short_preamble(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_SET_ANT:
-+ acx_ioctl_set_antenna(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_GET_ANT:
-+ acx_ioctl_get_antenna(dev, NULL, NULL, NULL);
-+ break;
-+
-+ case ACX100_IOCTL_RX_ANT:
-+ acx_ioctl_set_rx_antenna(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_TX_ANT:
-+ acx_ioctl_set_tx_antenna(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_SET_ED:
-+ acx_ioctl_set_ed_threshold(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_SET_CCA:
-+ acx_ioctl_set_cca(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_MONITOR: /* set sniff (monitor) mode */
-+ acxlog(L_IOCTL, "%s: IWPRIV monitor\n", dev->name);
-+
-+ /* can only be done by admin */
-+ if (!capable(CAP_NET_ADMIN)) {
-+ result = -EPERM;
-+ break;
-+ }
-+ result = acx_ioctl_wlansniff(dev, NULL, NULL, iwr->u.name);
-+ break;
-+
-+ case ACX100_IOCTL_TEST:
-+ acx_ioctl_unknown11(dev, NULL, NULL, NULL);
-+ break;
-+
-+ case ACX111_IOCTL_INFO:
-+ acx111_ioctl_info(dev, NULL, NULL, NULL);
-+ break;
-+
-+ default:
-+ acxlog(L_IOCTL, "wireless ioctl 0x%04X queried "
-+ "but not implemented yet\n", cmd);
-+ result = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ if ((priv->dev_state_mask & ACX_STATE_IFACE_UP) && priv->set_mask) {
-+ acx_sem_lock(priv);
-+ acx_s_update_card_settings(priv, 0, 0);
-+ acx_sem_unlock(priv);
-+ }
-+
-+ /* older WEs don't have a commit handler,
-+ * so we need to fix return code in this case */
-+ if (-EINPROGRESS == result)
-+ result = 0;
-+
-+ return result;
-+}
-+#endif /* WE < 13 */
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/Kconfig bt_kernel/drivers/net/wireless/tiacx/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/Kconfig 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/Kconfig 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,59 @@
-+config ACX
-+ tristate "TI acx100/acx111 802.11b/g wireless chipsets"
-+ depends on NET_RADIO && EXPERIMENTAL && FW_LOADER
-+ ---help---
-+ A driver for 802.11b/g wireless cards based on
-+ Texas Instruments acx100 and acx111 chipsets.
-+
-+ This driver supports Host AP mode that allows
-+ your computer to act as an IEEE 802.11 access point.
-+ This driver is quite new and experimental.
-+
-+ These chipsets need their firmware loaded at startup.
-+ You will need to provide a firmware image via hotplug.
-+
-+ Firmware may be in a form of single image 40-100kb in size
-+ (a 'combined' firmware) or two images - main image
-+ (again 40-100kb) and radio image (~10kb or less).
-+
-+ Firmware images are requested from hotplug using following names:
-+
-+ tiacx100 - main firmware image for acx100 chipset
-+ tiacx100rNN - radio acx100 firmware for radio type NN
-+ tiacx100cNN - combined acx100 firmware for radio type NN
-+ tiacx111 - main acx111 firmware
-+ tiacx111rNN - radio acx111 firmware for radio type NN
-+ tiacx111cNN - combined acx111 firmware for radio type NN
-+
-+ Driver will attempt to load combined image first.
-+ If no such image is found, it will try to load main image
-+ and radio image instead.
-+
-+ Firmware files are not covered by GPL and are not distributed
-+ with this driver for legal reasons.
-+
-+ Texas Instruments did not take part in development of this driver
-+ in any way, shape or form.
-+
-+ The driver can be compiled as a module and will be named "acx".
-+
-+config ACX_PCI
-+ bool "TI acx100/acx111 802.11b/g PCI"
-+ depends on PCI && ACX
-+ ---help---
-+ Include PCI and CardBus support in acx.
-+
-+config ACX_USB
-+ bool "TI acx100/acx111 802.11b/g USB"
-+ depends on USB && ACX && BROKEN
-+ ---help---
-+ Include USB support in acx.
-+
-+ There is only one currently known device in this category,
-+ D-Link DWL-120+, but newer devices seem to be on the horizon.
-+
-+config ACX_CFI
-+ bool "TI acx100 802.11b/g Compact Flash"
-+ depends on ACX
-+ ---help---
-+ Include Compact Flash support.
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/macros.h bt_kernel/drivers/net/wireless/tiacx/macros.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/macros.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/macros.h 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,33 @@
-+#ifndef _MACROS_H
-+#define _MACROS_H
-+
-+
-+
-+#define HW_SLAVE_REG_ADDR_REG 0x00000004
-+#define HW_SLAVE_REG_DATA_REG 0x00000008
-+#define HW_SLAVE_REG_CTRL_REG 0x0000000c
-+#define HW_SLAVE_MEM_ADDR_REG 0x00000014
-+#define HW_SLAVE_MEM_DATA_REG 0x00000018
-+
-+#define REG_LO(b,r) ((u8 *) b + r)
-+#define REG_HI(b,r) ((u8 *) b + r + 2)
-+
-+static inline u32 acx_readl(unsigned char *iobase, unsigned int reg)
-+{
-+ u16 hi,lo;
-+
-+ writew( 0, REG_LO(iobase, HW_SLAVE_REG_CTRL_REG));
-+ writew( 1, REG_HI(iobase,HW_SLAVE_REG_CTRL_REG));
-+
-+ writew( reg, REG_LO(iobase, HW_SLAVE_REG_ADDR_REG));
-+ writew( 0, REG_HI(iobase,HW_SLAVE_REG_ADDR_REG));
-+
-+ lo = readw(REG_LO(iobase,HW_SLAVE_REG_DATA_REG));
-+ hi = readw(REG_HI(iobase,HW_SLAVE_REG_DATA_REG));
-+
-+ printk("hi=%04x,lo=%04x\n",hi,lo);
-+
-+ return ((u32)hi<<16) | lo;
-+}
-+
-+#endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/Makefile bt_kernel/drivers/net/wireless/tiacx/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/Makefile 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/Makefile 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,9 @@
-+#Use this if you have proper Kconfig integration:
-+
-+obj-$(CONFIG_ACX) += acx.o
-+
-+acx-obj-$(CONFIG_ACX_PCI) += pci.o
-+acx-obj-$(CONFIG_ACX_USB) += usb.o
-+acx-obj-$(CONFIG_ACX_CFI) += cfi.o
-+
-+acx-objs := wlan.o conv.o ioctl.o common.o $(acx-obj-y)
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/pci.c bt_kernel/drivers/net/wireless/tiacx/pci.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/pci.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/pci.c 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,4840 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+#define ACX_PCI 1
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-+#include <linux/moduleparam.h>
-+#endif
-+#include <linux/sched.h>
-+#include <linux/types.h>
-+#include <linux/skbuff.h>
-+#include <linux/slab.h>
-+#include <linux/if_arp.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/wireless.h>
-+#if WIRELESS_EXT >= 13
-+#include <net/iw_handler.h>
-+#endif
-+#include <linux/netdevice.h>
-+#include <linux/ioport.h>
-+#include <linux/pci.h>
-+#include <linux/pm.h>
-+
-+#include "acx.h"
-+
-+
-+/*================================================================*/
-+/* Local Constants */
-+#define PCI_TYPE (PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
-+#define PCI_ACX100_REGION1 0x01
-+#define PCI_ACX100_REGION1_SIZE 0x1000 /* Memory size - 4K bytes */
-+#define PCI_ACX100_REGION2 0x02
-+#define PCI_ACX100_REGION2_SIZE 0x10000 /* Memory size - 64K bytes */
-+
-+#define PCI_ACX111_REGION1 0x00
-+#define PCI_ACX111_REGION1_SIZE 0x2000 /* Memory size - 8K bytes */
-+#define PCI_ACX111_REGION2 0x01
-+#define PCI_ACX111_REGION2_SIZE 0x20000 /* Memory size - 128K bytes */
-+
-+/* Texas Instruments Vendor ID */
-+#define PCI_VENDOR_ID_TI 0x104c
-+
-+/* ACX100 22Mb/s WLAN controller */
-+#define PCI_DEVICE_ID_TI_TNETW1100A 0x8400
-+#define PCI_DEVICE_ID_TI_TNETW1100B 0x8401
-+
-+/* ACX111 54Mb/s WLAN controller */
-+#define PCI_DEVICE_ID_TI_TNETW1130 0x9066
-+
-+/* PCI Class & Sub-Class code, Network-'Other controller' */
-+#define PCI_CLASS_NETWORK_OTHERS 0x280
-+
-+#define CARD_EEPROM_ID_SIZE 6
-+#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* a la orinoco.c */
-+
-+
-+/***********************************************************************
-+*/
-+static void acx_l_disable_irq(wlandevice_t *priv);
-+static void acx_l_enable_irq(wlandevice_t *priv);
-+static int acx_e_probe_pci(struct pci_dev *pdev,
-+ const struct pci_device_id *id);
-+static void acx_e_remove_pci(struct pci_dev *pdev);
-+
-+#ifdef CONFIG_PM
-+static int acx_e_suspend(struct pci_dev *pdev, pm_message_t state);
-+static int acx_e_resume(struct pci_dev *pdev);
-+#endif
-+
-+static void acx_i_tx_timeout(netdevice_t *dev);
-+static struct net_device_stats *acx_e_get_stats(netdevice_t *dev);
-+static struct iw_statistics *acx_e_get_wireless_stats(netdevice_t *dev);
-+
-+static irqreturn_t acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-+static void acx_i_set_multicast_list(netdevice_t *dev);
-+
-+static int acx_e_open(netdevice_t *dev);
-+static int acx_e_close(netdevice_t *dev);
-+static void acx_s_up(netdevice_t *dev);
-+static void acx_s_down(netdevice_t *dev);
-+
-+
-+/***********************************************************************
-+** Register access
-+*/
-+
-+/* Pick one */
-+/* #define INLINE_IO static */
-+#define INLINE_IO static inline
-+
-+INLINE_IO u32
-+acx_read_reg32(wlandevice_t *priv, unsigned int offset)
-+{
-+#if ACX_IO_WIDTH == 32
-+ return readl((u8 *)priv->iobase + priv->io[offset]);
-+#else
-+ return readw((u8 *)priv->iobase + priv->io[offset])
-+ + (readw((u8 *)priv->iobase + priv->io[offset] + 2) << 16);
-+#endif
-+}
-+
-+INLINE_IO u16
-+acx_read_reg16(wlandevice_t *priv, unsigned int offset)
-+{
-+ return readw((u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+INLINE_IO u8
-+acx_read_reg8(wlandevice_t *priv, unsigned int offset)
-+{
-+ return readb((u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+INLINE_IO void
-+acx_write_reg32(wlandevice_t *priv, unsigned int offset, u32 val)
-+{
-+#if ACX_IO_WIDTH == 32
-+ writel(val, (u8 *)priv->iobase + priv->io[offset]);
-+#else
-+ writew(val & 0xffff, (u8 *)priv->iobase + priv->io[offset]);
-+ writew(val >> 16, (u8 *)priv->iobase + priv->io[offset] + 2);
-+#endif
-+}
-+
-+INLINE_IO void
-+acx_write_reg16(wlandevice_t *priv, unsigned int offset, u16 val)
-+{
-+ writew(val, (u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+INLINE_IO void
-+acx_write_reg8(wlandevice_t *priv, unsigned int offset, u8 val)
-+{
-+ writeb(val, (u8 *)priv->iobase + priv->io[offset]);
-+}
-+
-+/* Handle PCI posting properly:
-+ * Make sure that writes reach the adapter in case they require to be executed
-+ * *before* the next write, by reading a random (and safely accessible) register.
-+ * This call has to be made if there is no read following (which would flush the data
-+ * to the adapter), yet the written data has to reach the adapter immediately. */
-+INLINE_IO void
-+acx_write_flush(wlandevice_t *priv)
-+{
-+ /* readb(priv->iobase + priv->io[IO_ACX_INFO_MAILBOX_OFFS]); */
-+ /* faster version (accesses the first register, IO_ACX_SOFT_RESET,
-+ * which should also be safe): */
-+ readb(priv->iobase);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static const char name_acx100[] = "ACX100";
-+static const char name_tnetw1100a[] = "TNETW1100A";
-+static const char name_tnetw1100b[] = "TNETW1100B";
-+
-+static const char name_acx111[] = "ACX111";
-+static const char name_tnetw1130[] = "TNETW1130";
-+
-+static const struct pci_device_id
-+acx_pci_id_tbl[] __devinitdata = {
-+ {
-+ .vendor = PCI_VENDOR_ID_TI,
-+ .device = PCI_DEVICE_ID_TI_TNETW1100A,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = CHIPTYPE_ACX100,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_TI,
-+ .device = PCI_DEVICE_ID_TI_TNETW1100B,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = CHIPTYPE_ACX100,
-+ },
-+ {
-+ .vendor = PCI_VENDOR_ID_TI,
-+ .device = PCI_DEVICE_ID_TI_TNETW1130,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = CHIPTYPE_ACX111,
-+ },
-+ {
-+ .vendor = 0,
-+ .device = 0,
-+ .subvendor = 0,
-+ .subdevice = 0,
-+ .driver_data = 0,
-+ }
-+};
-+
-+MODULE_DEVICE_TABLE(pci, acx_pci_id_tbl);
-+
-+/* FIXME: checks should be removed once driver is included in the kernel */
-+#ifndef __devexit_p
-+#warning *** your kernel is EXTREMELY old since it does not even know about
-+#warning __devexit_p - this driver could easily FAIL to work, so better
-+#warning upgrade your kernel! ***
-+#define __devexit_p(x) x
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
-+/* pci_name() got introduced at start of 2.6.x,
-+ * got mandatory (slot_name member removed) in 2.6.11-bk1 */
-+#define pci_name(x) x->slot_name
-+#endif
-+
-+static struct pci_driver acx_pci_drv_id = {
-+ .name = "acx_pci",
-+ .id_table = acx_pci_id_tbl,
-+ .probe = acx_e_probe_pci,
-+ .remove = __devexit_p(acx_e_remove_pci),
-+#ifdef CONFIG_PM
-+ .suspend = acx_e_suspend,
-+ .resume = acx_e_resume
-+#endif /* CONFIG_PM */
-+};
-+
-+typedef struct acx_device {
-+ netdevice_t *newest;
-+} acx_device_t;
-+
-+/* if this driver was only about PCI devices, then we probably wouldn't
-+ * need this linked list.
-+ * But if we want to register ALL kinds of devices in one global list,
-+ * then we need it and need to maintain it properly. */
-+static struct acx_device root_acx_dev = {
-+ .newest = NULL,
-+};
-+DECLARE_MUTEX(root_acx_dev_sem);
-+
-+
-+/***********************************************************************
-+*/
-+static inline txdesc_t*
-+get_txdesc(wlandevice_t* priv, int index)
-+{
-+ return (txdesc_t*) (((u8*)priv->txdesc_start) + index * priv->txdesc_size);
-+}
-+
-+static inline txdesc_t*
-+move_txdesc(wlandevice_t* priv, txdesc_t* txdesc, int inc)
-+{
-+ return (txdesc_t*) (((u8*)txdesc) + inc * priv->txdesc_size);
-+}
-+
-+static txhostdesc_t*
-+acx_get_txhostdesc(wlandevice_t* priv, txdesc_t* txdesc)
-+{
-+ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
-+ if (ACX_DEBUG && (index % priv->txdesc_size)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ index /= priv->txdesc_size;
-+ if (ACX_DEBUG && (index >= TX_CNT)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ return &priv->txhostdesc_start[index*2];
-+}
-+
-+static client_t*
-+acx_get_txc(wlandevice_t* priv, txdesc_t* txdesc)
-+{
-+ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
-+ if (ACX_DEBUG && (index % priv->txdesc_size)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ index /= priv->txdesc_size;
-+ if (ACX_DEBUG && (index >= TX_CNT)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return NULL;
-+ }
-+ return priv->txc[index];
-+}
-+
-+static void
-+acx_put_txc(wlandevice_t* priv, txdesc_t* txdesc, client_t* c)
-+{
-+ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
-+ if (ACX_DEBUG && (index % priv->txdesc_size)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return;
-+ }
-+ index /= priv->txdesc_size;
-+ if (ACX_DEBUG && (index >= TX_CNT)) {
-+ printk("bad txdesc ptr %p\n", txdesc);
-+ return;
-+ }
-+ priv->txc[index] = c;
-+}
-+
-+/***********************************************************************
-+** EEPROM and PHY read/write helpers
-+*/
-+/***********************************************************************
-+** acx_read_eeprom_offset
-+**
-+** Function called to read an octet in the EEPROM.
-+**
-+** This function is used by acx_probe_pci to check if the
-+** connected card is a legal one or not.
-+**
-+** Arguments:
-+** priv ptr to wlandevice structure
-+** addr address to read in the EEPROM
-+** charbuf ptr to a char. This is where the read octet
-+** will be stored
-+**
-+** Returns:
-+** zero (0) - failed
-+** one (1) - success
-+**
-+** NOT ADAPTED FOR ACX111!!
-+*/
-+int
-+acx_read_eeprom_offset(wlandevice_t *priv, u32 addr, u8 *charbuf)
-+{
-+ int result = NOT_OK;
-+ int count;
-+
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
-+
-+ count = 0xffff;
-+ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
-+ /* scheduling away instead of CPU burning loop
-+ * doesn't seem to work here at all:
-+ * awful delay, sometimes also failure.
-+ * Doesn't matter anyway (only small delay). */
-+ if (unlikely(!--count)) {
-+ printk("%s: timeout waiting for EEPROM read\n",
-+ priv->netdev->name);
-+ goto fail;
-+ }
-+ }
-+
-+ *charbuf = acx_read_reg8(priv, IO_ACX_EEPROM_DATA);
-+ acxlog(L_DEBUG, "EEPROM at 0x%04X = 0x%02X\n", addr, *charbuf);
-+ result = OK;
-+
-+fail:
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** Dummy EEPROM read? why?!
-+*/
-+static int
-+acx_read_eeprom_area(wlandevice_t *priv)
-+{
-+ int offs;
-+ u8 tmp[0x3b];
-+
-+ for (offs = 0x8c; offs < 0xb9; offs++) {
-+ acx_read_eeprom_offset(priv, offs, &tmp[offs - 0x8c]);
-+ }
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+** We don't lock hw accesses here since we never r/w eeprom in IRQ
-+** Note: this function sleeps only because of GFP_KERNEL alloc
-+*/
-+#ifdef UNUSED
-+int
-+acx_s_write_eeprom_offset(wlandevice_t *priv, u32 addr, u32 len, const u8 *charbuf)
-+{
-+ u8 *data_verify = NULL;
-+ unsigned long flags;
-+ int count, i;
-+ int result = NOT_OK;
-+ u16 gpio_orig;
-+
-+ printk("acx: WARNING! I would write to EEPROM now. "
-+ "Since I really DON'T want to unless you know "
-+ "what you're doing (THIS CODE WILL PROBABLY "
-+ "NOT WORK YET!), I will abort that now. And "
-+ "definitely make sure to make a "
-+ "/proc/driver/acx_wlan0_eeprom backup copy first!!! "
-+ "(the EEPROM content includes the PCI config header!! "
-+ "If you kill important stuff, then you WILL "
-+ "get in trouble and people DID get in trouble already)\n");
-+ return OK;
-+
-+ FN_ENTER;
-+
-+ data_verify = kmalloc(len, GFP_KERNEL);
-+ if (!data_verify) {
-+ goto end;
-+ }
-+
-+ /* first we need to enable the OE (EEPROM Output Enable) GPIO line
-+ * to be able to write to the EEPROM.
-+ * NOTE: an EEPROM writing success has been reported,
-+ * but you probably have to modify GPIO_OUT, too,
-+ * and you probably need to activate a different GPIO
-+ * line instead! */
-+ gpio_orig = acx_read_reg16(priv, IO_ACX_GPIO_OE);
-+ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig & ~1);
-+ acx_write_flush(priv);
-+
-+ /* ok, now start writing the data out */
-+ for (i = 0; i < len; i++) {
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_DATA, *(charbuf + i));
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 1);
-+
-+ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
-+ if (unlikely(++count > 0xffff)) {
-+ printk("WARNING, DANGER!!! "
-+ "Timeout waiting for EEPROM write\n");
-+ goto end;
-+ }
-+ }
-+ }
-+
-+ /* disable EEPROM writing */
-+ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig);
-+ acx_write_flush(priv);
-+
-+ /* now start a verification run */
-+ count = 0xffff;
-+ for (i = 0; i < len; i++) {
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
-+
-+ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
-+ if (unlikely(!--count)) {
-+ printk("timeout waiting for EEPROM read\n");
-+ goto end;
-+ }
-+ }
-+
-+ data_verify[i] = acx_read_reg16(priv, IO_ACX_EEPROM_DATA);
-+ }
-+
-+ if (0 == memcmp(charbuf, data_verify, len))
-+ result = OK; /* read data matches, success */
-+
-+end:
-+ kfree(data_verify);
-+ FN_EXIT1(result);
-+ return result;
-+}
-+#endif /* UNUSED */
-+
-+
-+/***********************************************************************
-+** acxpci_s_read_phy_reg
-+**
-+** Messing with rx/tx disabling and enabling here
-+** (acx_write_reg32(priv, IO_ACX_ENABLE, 0b000000xx)) kills traffic
-+*/
-+int
-+acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
-+{
-+ int result = NOT_OK;
-+ int count;
-+
-+ FN_ENTER;
-+
-+ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_PHY_CTL, 2);
-+
-+ count = 0xffff;
-+ while (acx_read_reg32(priv, IO_ACX_PHY_CTL)) {
-+ /* scheduling away instead of CPU burning loop
-+ * doesn't seem to work here at all:
-+ * awful delay, sometimes also failure.
-+ * Doesn't matter anyway (only small delay). */
-+ if (unlikely(!--count)) {
-+ printk("%s: timeout waiting for phy read\n",
-+ priv->netdev->name);
-+ *charbuf = 0;
-+ goto fail;
-+ }
-+ }
-+
-+ acxlog(L_DEBUG, "count was %u\n", count);
-+ *charbuf = acx_read_reg8(priv, IO_ACX_PHY_DATA);
-+
-+ acxlog(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg);
-+ result = OK;
-+ goto fail; /* silence compiler warning */
-+fail:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
-+{
-+ FN_ENTER;
-+
-+ /* FIXME: we didn't use 32bit access here since mprusko said that
-+ * it results in distorted sensitivity on his card (huh!?!?
-+ * doesn't happen with my setup...)
-+ * But with the access reordering and flushing it
-+ * shouldn't happen any more...
-+ * FIXME: which radio is in the problematic card? My working one
-+ * is 0x11 */
-+ acx_write_reg32(priv, IO_ACX_PHY_DATA, value);
-+ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_PHY_CTL, 1);
-+ acx_write_flush(priv);
-+ acxlog(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+#define NO_AUTO_INCREMENT 1
-+
-+/***********************************************************************
-+** acx_s_write_fw
-+**
-+** Write the firmware image into the card.
-+**
-+** Arguments:
-+** priv wlan device structure
-+** apfw_image firmware image.
-+**
-+** Returns:
-+** 1 firmware image corrupted
-+** 0 success
-+*/
-+static int
-+acx_s_write_fw(wlandevice_t *priv, const firmware_image_t *apfw_image, u32 offset)
-+{
-+ int len, size;
-+ u32 sum, v32;
-+ /* we skip the first four bytes which contain the control sum */
-+ const u8 *image = (u8*)apfw_image + 4;
-+
-+ /* start the image checksum by adding the image size value */
-+ sum = image[0]+image[1]+image[2]+image[3];
-+ image += 4;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
-+
-+#if NO_AUTO_INCREMENT
-+ acxlog(L_INIT, "not using auto increment for firmware loading\n");
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
-+#else
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
-+ acx_write_flush(priv);
-+#endif
-+
-+ len = 0;
-+ size = le32_to_cpu(apfw_image->size) & (~3);
-+
-+ while (likely(len < size)) {
-+ v32 = be32_to_cpu(*(u32*)image);
-+ sum += image[0]+image[1]+image[2]+image[3];
-+ image += 4;
-+ len += 4;
-+
-+#if NO_AUTO_INCREMENT
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
-+ acx_write_flush(priv);
-+#endif
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, v32);
-+ }
-+
-+ acxlog(L_DEBUG, "%s: firmware written\n", __func__);
-+
-+ /* compare our checksum with the stored image checksum */
-+ return (sum != le32_to_cpu(apfw_image->chksum));
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_validate_fw
-+**
-+** Compare the firmware image given with
-+** the firmware image written into the card.
-+**
-+** Arguments:
-+** priv wlan device structure
-+** apfw_image firmware image.
-+**
-+** Returns:
-+** NOT_OK firmware image corrupted or not correctly written
-+** OK success
-+*/
-+static int
-+acx_s_validate_fw(wlandevice_t *priv, const firmware_image_t *apfw_image,
-+ u32 offset)
-+{
-+ u32 v32, w32, sum;
-+ int len, size;
-+ int result = OK;
-+ /* we skip the first four bytes which contain the control sum */
-+ const u8 *image = (u8*)apfw_image + 4;
-+
-+ /* start the image checksum by adding the image size value */
-+ sum = image[0]+image[1]+image[2]+image[3];
-+ image += 4;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
-+
-+#if NO_AUTO_INCREMENT
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
-+#else
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
-+#endif
-+
-+ len = 0;
-+ size = le32_to_cpu(apfw_image->size) & (~3);
-+
-+ while (likely(len < size)) {
-+ v32 = be32_to_cpu(*(u32*)image);
-+ image += 4;
-+ len += 4;
-+
-+#if NO_AUTO_INCREMENT
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
-+#endif
-+ w32 = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+
-+ if (unlikely(w32 != v32)) {
-+ printk("acx: FATAL: firmware upload: "
-+ "data parts at offset %d don't match (0x%08X vs. 0x%08X)! "
-+ "I/O timing issues or defective memory, with DWL-xx0+? "
-+ "ACX_IO_WIDTH=16 may help. Please report\n",
-+ len, v32, w32);
-+ result = NOT_OK;
-+ break;
-+ }
-+
-+ sum += (u8)w32 + (u8)(w32>>8) + (u8)(w32>>16) + (u8)(w32>>24);
-+ }
-+
-+ /* sum control verification */
-+ if (result != NOT_OK) {
-+ if (sum != le32_to_cpu(apfw_image->chksum)) {
-+ printk("acx: FATAL: firmware upload: "
-+ "checksums don't match!\n");
-+ result = NOT_OK;
-+ }
-+ }
-+
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_upload_fw
-+**
-+** Arguments:
-+** wlandevice: private device that contains card device
-+** Returns:
-+** NOT_OK: failed
-+** OK: success
-+** Call context:
-+** acx_reset_dev
-+*/
-+static int
-+acx_s_upload_fw(wlandevice_t *priv)
-+{
-+ firmware_image_t *apfw_image = NULL;
-+ int res = NOT_OK;
-+ int try;
-+ u32 size;
-+ char filename[sizeof("tiacx1NNcNN")];
-+
-+ FN_ENTER;
-+
-+ /* Try combined, then main image */
-+ priv->need_radio_fw = 0;
-+ sprintf(filename, "tiacx1%02dc%02X",
-+ IS_ACX111(priv)*11, priv->radio_type);
-+
-+ apfw_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
-+ if (!apfw_image) {
-+ priv->need_radio_fw = 1;
-+ filename[sizeof("tiacx1NN")-1] = '\0';
-+ apfw_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
-+ if (!apfw_image) {
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+ }
-+ }
-+
-+ for (try = 1; try <= 5; try++) {
-+ res = acx_s_write_fw(priv, apfw_image, 0);
-+ acxlog(L_DEBUG|L_INIT, "acx_write_fw (main/combined):%d\n", res);
-+ if (OK == res) {
-+ res = acx_s_validate_fw(priv, apfw_image, 0);
-+ acxlog(L_DEBUG|L_INIT, "acx_validate_fw "
-+ "(main/combined):%d\n", res);
-+ }
-+
-+ if (OK == res) {
-+ SET_BIT(priv->dev_state_mask, ACX_STATE_FW_LOADED);
-+ break;
-+ }
-+ printk("acx: firmware upload attempt #%d FAILED, "
-+ "retrying...\n", try);
-+ acx_s_msleep(1000); /* better wait for a while... */
-+ }
-+
-+ vfree(apfw_image);
-+
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_upload_radio
-+**
-+** Uploads the appropriate radio module firmware
-+** into the card.
-+*/
-+int
-+acx_s_upload_radio(wlandevice_t *priv)
-+{
-+ acx_ie_memmap_t mm;
-+ firmware_image_t *radio_image = NULL;
-+ acx_cmd_radioinit_t radioinit;
-+ int res = NOT_OK;
-+ int try;
-+ u32 offset;
-+ u32 size;
-+ char filename[sizeof("tiacx1NNrNN")];
-+
-+ if (!priv->need_radio_fw) return OK;
-+
-+ FN_ENTER;
-+
-+ acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
-+ offset = le32_to_cpu(mm.CodeEnd);
-+
-+ sprintf(filename, "tiacx1%02dr%02X",
-+ IS_ACX111(priv)*11,
-+ priv->radio_type);
-+ radio_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
-+ if (!radio_image) {
-+ printk("acx: can't load radio module '%s'\n", filename);
-+ goto fail;
-+ }
-+
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_SLEEP, NULL, 0);
-+
-+ for (try = 1; try <= 5; try++) {
-+ res = acx_s_write_fw(priv, radio_image, offset);
-+ acxlog(L_DEBUG|L_INIT, "acx_write_fw (radio): %d\n", res);
-+ if (OK == res) {
-+ res = acx_s_validate_fw(priv, radio_image, offset);
-+ acxlog(L_DEBUG|L_INIT, "acx_validate_fw (radio): %d\n", res);
-+ }
-+
-+ if (OK == res)
-+ break;
-+ printk("acx: radio firmware upload attempt #%d FAILED, "
-+ "retrying...\n", try);
-+ acx_s_msleep(1000); /* better wait for a while... */
-+ }
-+
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
-+ radioinit.offset = cpu_to_le32(offset);
-+ /* no endian conversion needed, remains in card CPU area: */
-+ radioinit.len = radio_image->size;
-+
-+ vfree(radio_image);
-+
-+ if (OK != res)
-+ goto fail;
-+
-+ /* will take a moment so let's have a big timeout */
-+ acx_s_issue_cmd_timeo(priv, ACX1xx_CMD_RADIOINIT,
-+ &radioinit, sizeof(radioinit), CMD_TIMEOUT_MS(1000));
-+
-+ res = acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
-+fail:
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/***********************************************************************
-+** acx_l_reset_mac
-+**
-+** Arguments:
-+** wlandevice: private device that contains card device
-+** Side effects:
-+** MAC will be reset
-+** Call context:
-+** acx_reset_dev
-+** Comment:
-+** resets onboard acx100 MAC
-+**
-+** Requires lock to be taken
-+*/
-+static void
-+acx_l_reset_mac(wlandevice_t *priv)
-+{
-+ u16 temp;
-+
-+ FN_ENTER;
-+
-+ /* halt eCPU */
-+ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
-+ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
-+
-+ /* now do soft reset of eCPU */
-+ temp = acx_read_reg16(priv, IO_ACX_SOFT_RESET) | 0x1;
-+ acxlog(L_DEBUG, "%s: enable soft reset...\n", __func__);
-+ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp);
-+ acx_write_flush(priv);
-+
-+ /* now reset bit again */
-+ acxlog(L_DEBUG, "%s: disable soft reset and go to init mode...\n", __func__);
-+ /* deassert eCPU reset */
-+ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp & ~0x1);
-+
-+ /* now start a burst read from initial flash EEPROM */
-+ temp = acx_read_reg16(priv, IO_ACX_EE_START) | 0x1;
-+ acx_write_reg16(priv, IO_ACX_EE_START, temp);
-+ acx_write_flush(priv);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_verify_init
-+*/
-+static int
-+acx_s_verify_init(wlandevice_t *priv)
-+{
-+ int result = NOT_OK;
-+ int timer;
-+
-+ FN_ENTER;
-+
-+ for (timer = 40; timer > 0; timer--) {
-+ u16 irqstat = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
-+ if (irqstat & HOST_INT_FCS_THRESHOLD) {
-+ result = OK;
-+ acx_write_reg16(priv, IO_ACX_IRQ_ACK, HOST_INT_FCS_THRESHOLD);
-+ break;
-+ }
-+ /* HZ / 50 resulted in 24 schedules for ACX100 on my machine,
-+ * so better schedule away longer for greater efficiency,
-+ * decrease loop count */
-+ acx_s_msleep(50);
-+ }
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** A few low-level helpers
-+**
-+** Note: these functions are not protected by lock
-+** and thus are never allowed to be called from IRQ.
-+** Also they must not race with fw upload which uses same hw regs
-+*/
-+
-+/***********************************************************************
-+** acx_read_info_status
-+*/
-+/* Info mailbox format:
-+2 bytes: type
-+2 bytes: status
-+more bytes may follow
-+ docs say about status:
-+ 0x0000 info available (set by hw)
-+ 0x0001 information received (must be set by host)
-+ 0x1000 info available, mailbox overflowed (messages lost) (set by hw)
-+ but in practice we've seen:
-+ 0x9000 when we did not set status to 0x0001 on prev message
-+ 0x1001 when we did set it
-+ 0x0000 was never seen
-+ conclusion: this is really a bitfield:
-+ 0x1000 is 'info available' bit
-+ 'mailbox overflowed' bit is 0x8000, not 0x1000
-+ value of 0x0000 probably means that there is no message at all
-+ P.S. I dunno how in hell hw is supposed to notice that messages are lost -
-+ it does NOT clear bit 0x0001, and this bit will probably stay forever set
-+ after we set it once. Let's hope this will be fixed in firmware someday
-+*/
-+static void
-+acx_read_info_status(wlandevice_t *priv)
-+{
-+ u32 value;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1);
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
-+ acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS));
-+
-+ /* make sure we only read the data once all cfg registers are written: */
-+ acx_write_flush(priv);
-+ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+
-+ priv->info_type = (u16)value;
-+ priv->info_status = (value >> 16);
-+
-+ /* inform hw that we have read this info message */
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, priv->info_type | 0x00010000);
-+ acx_write_flush(priv);
-+ /* now bother hw to notice it: */
-+ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_INFOACK);
-+ acx_write_flush(priv);
-+
-+ acxlog(L_CTL, "info_type 0x%04X, info_status 0x%04X\n",
-+ priv->info_type, priv->info_status);
-+}
-+
-+
-+/***********************************************************************
-+** acx_write_cmd_type_or_status
-+*/
-+static void
-+acx_write_cmd_type_or_status(wlandevice_t *priv, u32 val)
-+{
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
-+ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
-+
-+ /* make sure we only write the data once all config registers are written */
-+ acx_write_flush(priv);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, val);
-+ acx_write_flush(priv);
-+}
-+static inline void
-+acx_write_cmd_type(wlandevice_t *priv, u32 val)
-+{
-+ acx_write_cmd_type_or_status(priv, val);
-+}
-+static inline void
-+acx_write_cmd_status(wlandevice_t *priv, u32 val)
-+{
-+ acx_write_cmd_type_or_status(priv, val<<16);
-+}
-+
-+
-+/***********************************************************************
-+** acx_read_cmd_status
-+*/
-+static void
-+acx_read_cmd_status(wlandevice_t *priv)
-+{
-+ u32 value;
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
-+
-+ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
-+ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
-+
-+ /* make sure we only read the data once all config registers are written */
-+ acx_write_flush(priv);
-+ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
-+
-+ priv->cmd_type = (u16)value;
-+ priv->cmd_status = (value >> 16);
-+
-+ acxlog(L_CTL, "cmd_type 0x%04X, cmd_status 0x%04X [%s]\n",
-+ priv->cmd_type, priv->cmd_status,
-+ acx_cmd_status_str(priv->cmd_status));
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_reset_dev
-+**
-+** Arguments:
-+** netdevice that contains the wlandevice priv variable
-+** Returns:
-+** NOT_OK on fail
-+** OK on success
-+** Side effects:
-+** device is hard reset
-+** Call context:
-+** acx_probe_pci
-+** Comment:
-+** This resets the acx100 device using low level hardware calls
-+** as well as uploads and verifies the firmware to the card
-+*/
-+static int
-+acx_s_reset_dev(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ const char* msg = "";
-+ unsigned long flags;
-+ int result = NOT_OK;
-+ u16 hardware_info;
-+ u16 ecpu_ctrl;
-+
-+ FN_ENTER;
-+
-+ /* we're doing a reset, so hardware is unavailable */
-+
-+ /* reset the device to make sure the eCPU is stopped
-+ * to upload the firmware correctly */
-+
-+ acx_lock(priv, flags);
-+
-+ acx_l_reset_mac(priv);
-+
-+ ecpu_ctrl = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) & 1;
-+ if (!ecpu_ctrl) {
-+ msg = "eCPU is already running. ";
-+ goto fail_unlock;
-+ }
-+
-+#ifdef WE_DONT_NEED_THAT_DO_WE
-+ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 2) {
-+ /* eCPU most likely means "embedded CPU" */
-+ msg = "eCPU did not start after boot from flash. ";
-+ goto fail_unlock;
-+ }
-+
-+ /* check sense on reset flags */
-+ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 0x10) {
-+ printk("%s: eCPU did not start after boot (SOR), "
-+ "is this fatal?\n", dev->name);
-+ }
-+#endif
-+ /* scan, if any, is stopped now, setting corresponding IRQ bit */
-+ priv->irq_status |= HOST_INT_SCAN_COMPLETE;
-+
-+ acx_unlock(priv, flags);
-+
-+ /* without this delay acx100 may fail to report hardware_info
-+ ** (see below). Most probably eCPU runs some init code */
-+ acx_s_msleep(10);
-+
-+ /* Need to know radio type before fw load */
-+ hardware_info = acx_read_reg16(priv, IO_ACX_EEPROM_INFORMATION);
-+ priv->form_factor = hardware_info & 0xff;
-+ priv->radio_type = hardware_info >> 8;
-+
-+ /* load the firmware */
-+ if (OK != acx_s_upload_fw(priv))
-+ goto fail;
-+
-+ acx_s_msleep(10);
-+
-+ /* now start eCPU by clearing bit */
-+ acxlog(L_DEBUG, "booted eCPU up and waiting for completion...\n");
-+ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1);
-+
-+ /* wait for eCPU bootup */
-+ if (OK != acx_s_verify_init(priv)) {
-+ msg = "timeout waiting for eCPU. ";
-+ goto fail;
-+ }
-+
-+ acxlog(L_DEBUG, "eCPU has woken up, card is ready to be configured\n");
-+
-+ if (IS_ACX111(priv)) {
-+ acxlog(L_DEBUG, "cleaning up cmd mailbox access area\n");
-+ acx_write_cmd_status(priv, 0);
-+ acx_read_cmd_status(priv);
-+ if (priv->cmd_status) {
-+ msg = "error cleaning cmd mailbox area. ";
-+ goto fail;
-+ }
-+ }
-+
-+ /* TODO what is this one doing ?? adapt for acx111 */
-+ if ((OK != acx_read_eeprom_area(priv)) && IS_ACX100(priv)) {
-+ /* does "CIS" mean "Card Information Structure"?
-+ * If so, then this would be a PCMCIA message...
-+ */
-+ msg = "CIS error. ";
-+ goto fail;
-+ }
-+
-+ result = OK;
-+ FN_EXIT1(result);
-+ return result;
-+
-+/* Finish error message. Indicate which function failed */
-+fail_unlock:
-+ acx_unlock(priv, flags);
-+fail:
-+ printk("acx: %sreset_dev() FAILED\n", msg);
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx_init_mboxes
-+*/
-+void
-+acx_init_mboxes(wlandevice_t *priv)
-+{
-+ u32 cmd_offs, info_offs;
-+
-+ FN_ENTER;
-+
-+ cmd_offs = acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS);
-+ info_offs = acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS);
-+ priv->cmd_area = (u8 *)priv->iobase2 + cmd_offs + 0x4;
-+ priv->info_area = (u8 *)priv->iobase2 + info_offs + 0x4;
-+ acxlog(L_DEBUG, "iobase2=%p\n"
-+ "cmd_mbox_offset=%X cmd_area=%p\n"
-+ "info_mbox_offset=%X info_area=%p\n",
-+ priv->iobase2,
-+ cmd_offs, priv->cmd_area,
-+ info_offs, priv->info_area);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_issue_cmd_timeo
-+* Excecutes a command in the command mailbox
-+*
-+* Arguments:
-+* *pcmdparam = an pointer to the data. The data mustn't include
-+* the 4 byte command header!
-+*
-+* NB: we do _not_ take lock inside, so be sure to not touch anything
-+* which may interfere with IRQ handler operation
-+*
-+* TODO: busy wait is a bit silly, so:
-+* 1) stop doing many iters - go to sleep after first
-+* 2) go to waitqueue based approach: wait, not poll!
-+*----------------------------------------------------------------*/
-+#undef FUNC
-+#define FUNC "issue_cmd"
-+
-+#if !ACX_DEBUG
-+int
-+acxpci_s_issue_cmd_timeo(
-+ wlandevice_t *priv,
-+ unsigned int cmd,
-+ void *buffer,
-+ unsigned buflen,
-+ unsigned timeout)
-+{
-+#else
-+int
-+acxpci_s_issue_cmd_timeo_debug(
-+ wlandevice_t *priv,
-+ unsigned cmd,
-+ void *buffer,
-+ unsigned buflen,
-+ unsigned timeout,
-+ const char* cmdstr)
-+{
-+ unsigned long start = jiffies;
-+#endif
-+ const char *devname;
-+ unsigned counter;
-+ u16 irqtype;
-+ u16 cmd_status;
-+
-+ FN_ENTER;
-+
-+ devname = priv->netdev->name;
-+ if (!devname || !devname[0])
-+ devname = "acx";
-+
-+ acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,timeout:%ums,type:0x%04X)\n",
-+ cmdstr, buflen, timeout,
-+ buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
-+
-+ if (!(priv->dev_state_mask & ACX_STATE_FW_LOADED)) {
-+ printk("%s: "FUNC"(): firmware is not loaded yet, "
-+ "cannot execute commands!\n", devname);
-+ goto bad;
-+ }
-+
-+ if ((acx_debug & L_DEBUG) && (cmd != ACX1xx_CMD_INTERROGATE)) {
-+ printk("input pdr (len=%u):\n", buflen);
-+ acx_dump_bytes(buffer, buflen);
-+ }
-+
-+ /* wait for firmware to become idle for our command submission */
-+ counter = 199; /* in ms */
-+ do {
-+ acx_read_cmd_status(priv);
-+ /* Test for IDLE state */
-+ if (!priv->cmd_status)
-+ break;
-+ if (counter % 10 == 0) {
-+ /* we waited 10 iterations, no luck. Sleep 10 ms */
-+ acx_s_msleep(10);
-+ }
-+ } while (--counter);
-+
-+ if (!counter) {
-+ /* the card doesn't get idle, we're in trouble */
-+ printk("%s: "FUNC"(): cmd_status is not IDLE: 0x%04X!=0\n",
-+ devname, priv->cmd_status);
-+ goto bad;
-+ } else if (counter < 190) { /* if waited >10ms... */
-+ acxlog(L_CTL|L_DEBUG, FUNC"(): waited for IDLE %dms. "
-+ "Please report\n", 199 - counter);
-+ }
-+
-+ /* now write the parameters of the command if needed */
-+ if (buffer && buflen) {
-+ /* if it's an INTERROGATE command, just pass the length
-+ * of parameters to read, as data */
-+#if CMD_DISCOVERY
-+ if (cmd == ACX1xx_CMD_INTERROGATE)
-+ memset(priv->cmd_area, 0xAA, buflen);
-+#endif
-+ memcpy(priv->cmd_area, buffer,
-+ (cmd == ACX1xx_CMD_INTERROGATE) ? 4 : buflen);
-+ }
-+ /* now write the actual command type */
-+ priv->cmd_type = cmd;
-+ acx_write_cmd_type(priv, cmd);
-+ /* execute command */
-+ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_CMD);
-+ acx_write_flush(priv);
-+
-+ /* wait for firmware to process command */
-+
-+ /* Ensure nonzero and not too large timeout.
-+ ** Also converts e.g. 100->99, 200->199
-+ ** which is nice but not essential */
-+ timeout = (timeout-1) | 1;
-+ if (unlikely(timeout > 1199))
-+ timeout = 1199;
-+ /* clear CMD_COMPLETE bit. can be set only by IRQ handler: */
-+ priv->irq_status &= ~HOST_INT_CMD_COMPLETE;
-+
-+ /* we schedule away sometimes (timeout can be large) */
-+ counter = timeout;
-+ do {
-+ if (!priv->irqs_active) { /* IRQ disabled: poll */
-+ irqtype = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
-+ if (irqtype & HOST_INT_CMD_COMPLETE) {
-+ acx_write_reg16(priv, IO_ACX_IRQ_ACK,
-+ HOST_INT_CMD_COMPLETE);
-+ break;
-+ }
-+ } else { /* Wait when IRQ will set the bit */
-+ irqtype = priv->irq_status;
-+ if (irqtype & HOST_INT_CMD_COMPLETE)
-+ break;
-+ }
-+
-+ if (counter % 10 == 0) {
-+ /* we waited 10 iterations, no luck. Sleep 10 ms */
-+ acx_s_msleep(10);
-+ }
-+ } while (--counter);
-+
-+ /* save state for debugging */
-+ acx_read_cmd_status(priv);
-+ cmd_status = priv->cmd_status;
-+
-+ /* put the card in IDLE state */
-+ priv->cmd_status = 0;
-+ acx_write_cmd_status(priv, 0);
-+
-+ if (!counter) { /* timed out! */
-+ printk("%s: "FUNC"(): timed out %s for CMD_COMPLETE. "
-+ "irq bits:0x%04X irq_status:0x%04X timeout:%dms "
-+ "cmd_status:%d (%s)\n",
-+ devname, (priv->irqs_active) ? "waiting" : "polling",
-+ irqtype, priv->irq_status, timeout,
-+ cmd_status, acx_cmd_status_str(cmd_status));
-+ goto bad;
-+ } else if (timeout - counter > 30) { /* if waited >30ms... */
-+ acxlog(L_CTL|L_DEBUG, FUNC"(): %s for CMD_COMPLETE %dms. "
-+ "count:%d. Please report\n",
-+ (priv->irqs_active) ? "waited" : "polled",
-+ timeout - counter, counter);
-+ }
-+
-+ if (1 != cmd_status) { /* it is not a 'Success' */
-+ printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s). "
-+ "Took %dms of %d\n",
-+ devname, cmd_status, acx_cmd_status_str(cmd_status),
-+ timeout - counter, timeout);
-+ /* zero out result buffer */
-+ if (buffer && buflen)
-+ memset(buffer, 0, buflen);
-+ goto bad;
-+ }
-+
-+ /* read in result parameters if needed */
-+ if (buffer && buflen && (cmd == ACX1xx_CMD_INTERROGATE)) {
-+ memcpy(buffer, priv->cmd_area, buflen);
-+ if (acx_debug & L_DEBUG) {
-+ printk("output buffer (len=%u): ", buflen);
-+ acx_dump_bytes(buffer, buflen);
-+ }
-+ }
-+/* ok: */
-+ acxlog(L_CTL, FUNC"(%s): took %ld jiffies to complete\n",
-+ cmdstr, jiffies - start);
-+ FN_EXIT1(OK);
-+ return OK;
-+
-+bad:
-+ /* Give enough info so that callers can avoid
-+ ** printing their own diagnostic messages */
-+#if ACX_DEBUG
-+ printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
-+#else
-+ printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
-+#endif
-+ dump_stack();
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_get_firmware_version
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_get_firmware_version(wlandevice_t *priv)
-+{
-+ fw_ver_t fw;
-+ u8 hexarr[4] = { 0, 0, 0, 0 };
-+ int hexidx = 0, val = 0;
-+ const char *num;
-+ char c;
-+
-+ FN_ENTER;
-+
-+ acx_s_interrogate(priv, &fw, ACX1xx_IE_FWREV);
-+ memcpy(priv->firmware_version, fw.fw_id, FW_ID_SIZE);
-+ priv->firmware_version[FW_ID_SIZE] = '\0';
-+ acxlog(L_DEBUG, "fw_ver: fw_id='%s' hw_id=%08X\n",
-+ priv->firmware_version, fw.hw_id);
-+
-+ if (strncmp(fw.fw_id, "Rev ", 4) != 0) {
-+ printk("acx: strange firmware version string "
-+ "'%s', please report\n", priv->firmware_version);
-+ priv->firmware_numver = 0x01090407; /* assume 1.9.4.7 */
-+ } else {
-+ num = &fw.fw_id[4];
-+ while (1) {
-+ c = *num++;
-+ if ((c == '.') || (c == '\0')) {
-+ hexarr[hexidx++] = val;
-+ if ((hexidx > 3) || (c == '\0')) /* end? */
-+ break;
-+ val = 0;
-+ continue;
-+ }
-+ if ((c >= '0') && (c <= '9'))
-+ c -= '0';
-+ else
-+ c = c - 'a' + (char)10;
-+ val = val*16 + c;
-+ }
-+
-+ priv->firmware_numver = (u32)(
-+ (hexarr[0] << 24) + (hexarr[1] << 16)
-+ + (hexarr[2] << 8) + hexarr[3]);
-+ acxlog(L_DEBUG, "firmware_numver 0x%08X\n", priv->firmware_numver);
-+ }
-+ if (IS_ACX111(priv)) {
-+ if (priv->firmware_numver == 0x00010011) {
-+ /* This one does not survive floodpinging */
-+ printk("acx: firmware '%s' is known to be buggy, "
-+ "please upgrade\n", priv->firmware_version);
-+ }
-+ if (priv->firmware_numver == 0x02030131) {
-+ /* With this one, all rx packets look mangled
-+ ** Most probably we simply do not know how to use it
-+ ** properly */
-+ printk("acx: firmware '%s' does not work well "
-+ "with this driver\n", priv->firmware_version);
-+ }
-+ }
-+
-+ priv->firmware_id = le32_to_cpu(fw.hw_id);
-+
-+ /* we're able to find out more detailed chip names now */
-+ switch (priv->firmware_id & 0xffff0000) {
-+ case 0x01010000:
-+ case 0x01020000:
-+ priv->chip_name = name_tnetw1100a;
-+ break;
-+ case 0x01030000:
-+ priv->chip_name = name_tnetw1100b;
-+ break;
-+ case 0x03000000:
-+ case 0x03010000:
-+ priv->chip_name = name_tnetw1130;
-+ break;
-+ default:
-+ printk("acx: unknown chip ID 0x%08X, "
-+ "please report\n", priv->firmware_id);
-+ break;
-+ }
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_display_hardware_details
-+*
-+* Arguments:
-+* priv: ptr to wlandevice that contains all the details
-+* displayed by this function
-+* Call context:
-+* acx_probe_pci
-+* Comment:
-+* This function will display strings to the system log according
-+* to device form_factor and radio type. It will needed to be
-+*----------------------------------------------------------------*/
-+static void
-+acx_display_hardware_details(wlandevice_t *priv)
-+{
-+ const char *radio_str, *form_str;
-+
-+ FN_ENTER;
-+
-+ switch (priv->radio_type) {
-+ case RADIO_MAXIM_0D:
-+ /* hmm, the DWL-650+ seems to have two variants,
-+ * according to a windows driver changelog comment:
-+ * RFMD and Maxim. */
-+ radio_str = "Maxim";
-+ break;
-+ case RADIO_RFMD_11:
-+ radio_str = "RFMD";
-+ break;
-+ case RADIO_RALINK_15:
-+ radio_str = "Ralink";
-+ break;
-+ case RADIO_RADIA_16:
-+ radio_str = "Radia";
-+ break;
-+ case RADIO_UNKNOWN_17:
-+ /* TI seems to have a radio which is
-+ * additionally 802.11a capable, too */
-+ radio_str = "802.11a/b/g radio?! Please report";
-+ break;
-+ case RADIO_UNKNOWN_19:
-+ radio_str = "A radio used by Safecom cards?! Please report";
-+ break;
-+ default:
-+ radio_str = "UNKNOWN, please report the radio type name!";
-+ break;
-+ }
-+
-+ switch (priv->form_factor) {
-+ case 0x00:
-+ form_str = "unspecified";
-+ break;
-+ case 0x01:
-+ form_str = "(mini-)PCI / CardBus";
-+ break;
-+ case 0x02:
-+ form_str = "USB";
-+ break;
-+ case 0x03:
-+ form_str = "Compact Flash";
-+ break;
-+ default:
-+ form_str = "UNKNOWN, Please report";
-+ break;
-+ }
-+
-+ printk("acx: form factor 0x%02X (%s), "
-+ "radio type 0x%02X (%s), EEPROM version 0x%02X, "
-+ "uploaded firmware '%s' (0x%08X)\n",
-+ priv->form_factor, form_str, priv->radio_type, radio_str,
-+ priv->eeprom_version, priv->firmware_version,
-+ priv->firmware_id);
-+
-+ FN_EXIT0;
-+}
-+
-+/***********************************************************************
-+*/
-+#ifdef NONESSENTIAL_FEATURES
-+typedef struct device_id {
-+ unsigned char id[6];
-+ char *descr;
-+ char *type;
-+} device_id_t;
-+
-+static const device_id_t
-+device_ids[] =
-+{
-+ {
-+ {'G', 'l', 'o', 'b', 'a', 'l'},
-+ NULL,
-+ NULL,
-+ },
-+ {
-+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-+ "uninitialized",
-+ "SpeedStream SS1021 or Gigafast WF721-AEX"
-+ },
-+ {
-+ {0x80, 0x81, 0x82, 0x83, 0x84, 0x85},
-+ "non-standard",
-+ "DrayTek Vigor 520"
-+ },
-+ {
-+ {'?', '?', '?', '?', '?', '?'},
-+ "non-standard",
-+ "Level One WPC-0200"
-+ },
-+ {
-+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
-+ "empty",
-+ "DWL-650+ variant"
-+ }
-+};
-+
-+static void
-+acx_show_card_eeprom_id(wlandevice_t *priv)
-+{
-+ unsigned char buffer[CARD_EEPROM_ID_SIZE];
-+ int i;
-+
-+ memset(&buffer, 0, CARD_EEPROM_ID_SIZE);
-+ /* use direct EEPROM access */
-+ for (i = 0; i < CARD_EEPROM_ID_SIZE; i++) {
-+ if (OK != acx_read_eeprom_offset(priv,
-+ ACX100_EEPROM_ID_OFFSET + i,
-+ &buffer[i]))
-+ {
-+ printk("acx: reading EEPROM FAILED\n");
-+ break;
-+ }
-+ }
-+
-+ for (i = 0; i < VEC_SIZE(device_ids); i++) {
-+ if (!memcmp(&buffer, device_ids[i].id, CARD_EEPROM_ID_SIZE)) {
-+ if (device_ids[i].descr) {
-+ printk("acx: EEPROM card ID string check "
-+ "found %s card ID: is this %s?\n",
-+ device_ids[i].descr, device_ids[i].type);
-+ }
-+ break;
-+ }
-+ }
-+ if (i == VEC_SIZE(device_ids)) {
-+ printk("acx: EEPROM card ID string check found "
-+ "unknown card: expected 'Global', got '%.*s\'. "
-+ "Please report\n", CARD_EEPROM_ID_SIZE, buffer);
-+ }
-+}
-+#endif /* NONESSENTIAL_FEATURES */
-+
-+
-+/***********************************************************************
-+*/
-+static void
-+acx_s_device_chain_add(struct net_device *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ down(&root_acx_dev_sem);
-+ priv->prev_nd = root_acx_dev.newest;
-+ root_acx_dev.newest = dev;
-+ priv->netdev = dev;
-+ up(&root_acx_dev_sem);
-+}
-+
-+static void
-+acx_s_device_chain_remove(struct net_device *dev)
-+{
-+ struct net_device *querydev;
-+ struct net_device *olderdev;
-+ struct net_device *newerdev;
-+
-+ down(&root_acx_dev_sem);
-+ querydev = root_acx_dev.newest;
-+ newerdev = NULL;
-+ while (querydev) {
-+ olderdev = ((wlandevice_t*)netdev_priv(querydev))->prev_nd;
-+ if (0 == strcmp(querydev->name, dev->name)) {
-+ if (!newerdev) {
-+ /* if we were at the beginning of the
-+ * list, then it's the list head that
-+ * we need to update to point at the
-+ * next older device */
-+ root_acx_dev.newest = olderdev;
-+ } else {
-+ /* it's the device that is newer than us
-+ * that we need to update to point at
-+ * the device older than us */
-+ ((wlandevice_t*)netdev_priv(newerdev))->
-+ prev_nd = olderdev;
-+ }
-+ break;
-+ }
-+ /* "newerdev" is actually the device of the old iteration,
-+ * but since the list starts (root_acx_dev.newest)
-+ * with the newest devices,
-+ * it's newer than the ones following.
-+ * Oh the joys of iterating from newest to oldest :-\ */
-+ newerdev = querydev;
-+
-+ /* keep checking old devices for matches until we hit the end
-+ * of the list */
-+ querydev = olderdev;
-+ }
-+ up(&root_acx_dev_sem);
-+}
-+
-+
-+/***********************************************************************
-+** acx_free_desc_queues
-+**
-+** Releases the queues that have been allocated, the
-+** others have been initialised to NULL so this
-+** function can be used if only part of the queues were allocated.
-+*/
-+static inline void
-+acx_free_coherent(struct pci_dev *hwdev, size_t size,
-+ void *vaddr, dma_addr_t dma_handle)
-+{
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 53)
-+ dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev,
-+ size, vaddr, dma_handle);
-+#else
-+ pci_free_consistent(hwdev, size, vaddr, dma_handle);
-+#endif
-+}
-+
-+void
-+acx_free_desc_queues(wlandevice_t *priv)
-+{
-+#define ACX_FREE_QUEUE(size, ptr, phyaddr) \
-+ if (ptr) { \
-+ acx_free_coherent(0, size, ptr, phyaddr); \
-+ ptr = NULL; \
-+ size = 0; \
-+ }
-+
-+ FN_ENTER;
-+
-+ ACX_FREE_QUEUE(priv->txhostdesc_area_size, priv->txhostdesc_start, priv->txhostdesc_startphy);
-+ ACX_FREE_QUEUE(priv->txbuf_area_size, priv->txbuf_start, priv->txbuf_startphy);
-+
-+ priv->txdesc_start = NULL;
-+
-+ ACX_FREE_QUEUE(priv->rxhostdesc_area_size, priv->rxhostdesc_start, priv->rxhostdesc_startphy);
-+ ACX_FREE_QUEUE(priv->rxbuf_area_size, priv->rxbuf_start, priv->rxbuf_startphy);
-+
-+ priv->rxdesc_start = NULL;
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_delete_dma_regions
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_delete_dma_regions(wlandevice_t *priv)
-+{
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+ /* disable radio Tx/Rx. Shouldn't we use the firmware commands
-+ * here instead? Or are we that much down the road that it's no
-+ * longer possible here? */
-+ acx_write_reg16(priv, IO_ACX_ENABLE, 0);
-+
-+ acx_s_msleep(100);
-+
-+ acx_lock(priv, flags);
-+ acx_free_desc_queues(priv);
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_probe_pci
-+*
-+* Probe routine called when a PCI device w/ matching ID is found.
-+* Here's the sequence:
-+* - Allocate the PCI resources.
-+* - Read the PCMCIA attribute memory to make sure we have a WLAN card
-+* - Reset the MAC
-+* - Initialize the dev and wlan data
-+* - Initialize the MAC
-+*
-+* Arguments:
-+* pdev ptr to pci device structure containing info about
-+* pci configuration.
-+* id ptr to the device id entry that matched this device.
-+*
-+* Returns:
-+* zero - success
-+* negative - failed
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+static const u16
-+IO_ACX100[] =
-+{
-+ 0x0000, /* IO_ACX_SOFT_RESET */
-+
-+ 0x0014, /* IO_ACX_SLV_MEM_ADDR */
-+ 0x0018, /* IO_ACX_SLV_MEM_DATA */
-+ 0x001c, /* IO_ACX_SLV_MEM_CTL */
-+ 0x0020, /* IO_ACX_SLV_END_CTL */
-+
-+ 0x0034, /* IO_ACX_FEMR */
-+
-+ 0x007c, /* IO_ACX_INT_TRIG */
-+ 0x0098, /* IO_ACX_IRQ_MASK */
-+ 0x00a4, /* IO_ACX_IRQ_STATUS_NON_DES */
-+ 0x00a8, /* IO_ACX_IRQ_STATUS_CLEAR */
-+ 0x00ac, /* IO_ACX_IRQ_ACK */
-+ 0x00b0, /* IO_ACX_HINT_TRIG */
-+
-+ 0x0104, /* IO_ACX_ENABLE */
-+
-+ 0x0250, /* IO_ACX_EEPROM_CTL */
-+ 0x0254, /* IO_ACX_EEPROM_ADDR */
-+ 0x0258, /* IO_ACX_EEPROM_DATA */
-+ 0x025c, /* IO_ACX_EEPROM_CFG */
-+
-+ 0x0268, /* IO_ACX_PHY_ADDR */
-+ 0x026c, /* IO_ACX_PHY_DATA */
-+ 0x0270, /* IO_ACX_PHY_CTL */
-+
-+ 0x0290, /* IO_ACX_GPIO_OE */
-+
-+ 0x0298, /* IO_ACX_GPIO_OUT */
-+
-+ 0x02a4, /* IO_ACX_CMD_MAILBOX_OFFS */
-+ 0x02a8, /* IO_ACX_INFO_MAILBOX_OFFS */
-+ 0x02ac, /* IO_ACX_EEPROM_INFORMATION */
-+
-+ 0x02d0, /* IO_ACX_EE_START */
-+ 0x02d4, /* IO_ACX_SOR_CFG */
-+ 0x02d8 /* IO_ACX_ECPU_CTRL */
-+};
-+
-+static const u16
-+IO_ACX111[] =
-+{
-+ 0x0000, /* IO_ACX_SOFT_RESET */
-+
-+ 0x0014, /* IO_ACX_SLV_MEM_ADDR */
-+ 0x0018, /* IO_ACX_SLV_MEM_DATA */
-+ 0x001c, /* IO_ACX_SLV_MEM_CTL */
-+ 0x0020, /* IO_ACX_SLV_END_CTL */
-+
-+ 0x0034, /* IO_ACX_FEMR */
-+
-+ 0x00b4, /* IO_ACX_INT_TRIG */
-+ 0x00d4, /* IO_ACX_IRQ_MASK */
-+ /* we need NON_DES (0xf0), not NON_DES_MASK which is at 0xe0: */
-+ 0x00f0, /* IO_ACX_IRQ_STATUS_NON_DES */
-+ 0x00e4, /* IO_ACX_IRQ_STATUS_CLEAR */
-+ 0x00e8, /* IO_ACX_IRQ_ACK */
-+ 0x00ec, /* IO_ACX_HINT_TRIG */
-+
-+ 0x01d0, /* IO_ACX_ENABLE */
-+
-+ 0x0338, /* IO_ACX_EEPROM_CTL */
-+ 0x033c, /* IO_ACX_EEPROM_ADDR */
-+ 0x0340, /* IO_ACX_EEPROM_DATA */
-+ 0x0344, /* IO_ACX_EEPROM_CFG */
-+
-+ 0x0350, /* IO_ACX_PHY_ADDR */
-+ 0x0354, /* IO_ACX_PHY_DATA */
-+ 0x0358, /* IO_ACX_PHY_CTL */
-+
-+ 0x0374, /* IO_ACX_GPIO_OE */
-+
-+ 0x037c, /* IO_ACX_GPIO_OUT */
-+
-+ 0x0388, /* IO_ACX_CMD_MAILBOX_OFFS */
-+ 0x038c, /* IO_ACX_INFO_MAILBOX_OFFS */
-+ 0x0390, /* IO_ACX_EEPROM_INFORMATION */
-+
-+ 0x0100, /* IO_ACX_EE_START */
-+ 0x0104, /* IO_ACX_SOR_CFG */
-+ 0x0108, /* IO_ACX_ECPU_CTRL */
-+};
-+
-+static void
-+acx_netdev_init(struct net_device *dev) {}
-+
-+//FIXME: do the same for USB
-+static int
-+acx_change_mtu(struct net_device *dev, int mtu)
-+{
-+ enum {
-+ MIN_MTU = 256,
-+ MAX_MTU = WLAN_DATA_MAXLEN - (ETH_HLEN)
-+ };
-+
-+ if (mtu < MIN_MTU || mtu > MAX_MTU)
-+ return -EINVAL;
-+
-+ dev->mtu = mtu;
-+ return 0;
-+}
-+
-+static int __devinit
-+acx_e_probe_pci(struct pci_dev *pdev, const struct pci_device_id *id)
-+{
-+ unsigned long mem_region1 = 0;
-+ unsigned long mem_region2 = 0;
-+ unsigned long mem_region1_size;
-+ unsigned long mem_region2_size;
-+ unsigned long phymem1;
-+ unsigned long phymem2;
-+ void *mem1 = NULL;
-+ void *mem2 = NULL;
-+ wlandevice_t *priv = NULL;
-+ struct net_device *dev = NULL;
-+ const char *chip_name;
-+ int result = -EIO;
-+ int err;
-+ u8 chip_type;
-+
-+#if SEPARATE_DRIVER_INSTANCES
-+ struct pci_dev *tdev;
-+ unsigned int inited;
-+ static int turn = 0;
-+#endif /* SEPARATE_DRIVER_INSTANCES */
-+
-+ FN_ENTER;
-+
-+#if SEPARATE_DRIVER_INSTANCES
-+ if (card) {
-+ turn++;
-+ inited = 0;
-+ pci_for_each_dev(tdev) {
-+ if (tdev->vendor != PCI_VENDOR_ID_TI)
-+ continue;
-+
-+ if (tdev == pdev)
-+ break;
-+ if (pci_get_drvdata(tdev))
-+ inited++;
-+ }
-+ if (inited + turn != card) {
-+ result = -ENODEV;
-+ goto done;
-+ }
-+ }
-+#endif /* SEPARATE_DRIVER_INSTANCES */
-+
-+ /* Enable the PCI device */
-+ if (pci_enable_device(pdev)) {
-+ printk("acx: pci_enable_device() FAILED\n");
-+ result = -ENODEV;
-+ goto fail_pci_enable_device;
-+ }
-+
-+ /* enable busmastering (required for CardBus) */
-+ pci_set_master(pdev);
-+
-+ /* chiptype is u8 but id->driver_data is ulong
-+ ** Works for now (possible values are 1 and 2) */
-+ chip_type = (u8)id->driver_data;
-+ /* acx100 and acx111 have different PCI memory regions */
-+ if (chip_type == CHIPTYPE_ACX100) {
-+ chip_name = name_acx100;
-+ mem_region1 = PCI_ACX100_REGION1;
-+ mem_region1_size = PCI_ACX100_REGION1_SIZE;
-+
-+ mem_region2 = PCI_ACX100_REGION2;
-+ mem_region2_size = PCI_ACX100_REGION2_SIZE;
-+ } else if (chip_type == CHIPTYPE_ACX111) {
-+ chip_name = name_acx111;
-+ mem_region1 = PCI_ACX111_REGION1;
-+ mem_region1_size = PCI_ACX111_REGION1_SIZE;
-+
-+ mem_region2 = PCI_ACX111_REGION2;
-+ mem_region2_size = PCI_ACX111_REGION2_SIZE;
-+ } else {
-+ printk("acx: unknown chip type 0x%04X\n", chip_type);
-+ goto fail_unknown_chiptype;
-+ }
-+
-+ /* Figure out our resources */
-+ phymem1 = pci_resource_start(pdev, mem_region1);
-+ phymem2 = pci_resource_start(pdev, mem_region2);
-+
-+ if (!request_mem_region(phymem1, pci_resource_len(pdev, mem_region1), "ACX1xx_1")) {
-+ printk("acx: cannot reserve PCI memory region 1 (are you sure "
-+ "you have CardBus support in kernel?)\n");
-+ goto fail_request_mem_region1;
-+ }
-+
-+ if (!request_mem_region(phymem2, pci_resource_len(pdev, mem_region2), "ACX1xx_2")) {
-+ printk("acx: cannot reserve PCI memory region 2\n");
-+ goto fail_request_mem_region2;
-+ }
-+
-+ mem1 = ioremap(phymem1, mem_region1_size);
-+ if (NULL == mem1) {
-+ printk("acx: ioremap() FAILED\n");
-+ goto fail_ioremap1;
-+ }
-+
-+ mem2 = ioremap(phymem2, mem_region2_size);
-+ if (NULL == mem2) {
-+ printk("acx: ioremap() #2 FAILED\n");
-+ goto fail_ioremap2;
-+ }
-+
-+ /* Log the device */
-+ printk("acx: found %s-based wireless network card at %s, irq:%d, "
-+ "phymem1:0x%lX, phymem2:0x%lX, mem1:0x%p, mem1_size:%ld, "
-+ "mem2:0x%p, mem2_size:%ld\n",
-+ chip_name, pci_name(pdev), pdev->irq, phymem1, phymem2,
-+ mem1, mem_region1_size,
-+ mem2, mem_region2_size);
-+ acxlog(L_ANY, "initial debug setting is 0x%04X\n", acx_debug);
-+
-+ if (0 == pdev->irq) {
-+ printk("acx: can't use IRQ 0\n");
-+ goto fail_irq;
-+ }
-+
-+ dev = alloc_netdev(sizeof(wlandevice_t), "wlan%d", acx_netdev_init);
-+ /* (NB: memsets to 0 entire area) */
-+ if (!dev) {
-+ printk("acx: no memory for netdevice structure\n");
-+ goto fail_alloc_netdev;
-+ }
-+
-+ ether_setup(dev);
-+ dev->open = &acx_e_open;
-+ dev->stop = &acx_e_close;
-+ dev->hard_start_xmit = &acx_i_start_xmit;
-+ dev->get_stats = &acx_e_get_stats;
-+ dev->get_wireless_stats = &acx_e_get_wireless_stats;
-+#if WIRELESS_EXT >= 13
-+ dev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
-+#else
-+ dev->do_ioctl = &acx_e_ioctl_old;
-+#endif
-+ dev->set_multicast_list = &acx_i_set_multicast_list;
-+ dev->tx_timeout = &acx_i_tx_timeout;
-+ dev->change_mtu = &acx_change_mtu;
-+ dev->watchdog_timeo = 4 * HZ;
-+ dev->irq = pdev->irq;
-+ dev->base_addr = pci_resource_start(pdev, 0);
-+
-+ priv = netdev_priv(dev);
-+ spin_lock_init(&priv->lock); /* initial state: unlocked */
-+ /* We do not start with downed sem: we want PARANOID_LOCKING to work */
-+ sema_init(&priv->sem, 1); /* initial state: 1 (upped) */
-+ /* since nobody can see new netdev yet, we can as well
-+ ** just _presume_ that we're under sem (instead of actually taking it): */
-+ /* acx_sem_lock(priv); */
-+ priv->pdev = pdev;
-+ priv->dev_type = DEVTYPE_PCI;
-+ priv->chip_type = chip_type;
-+ priv->chip_name = chip_name;
-+ priv->io = (CHIPTYPE_ACX100 == chip_type) ? IO_ACX100 : IO_ACX111;
-+ priv->membase = phymem1;
-+ priv->iobase = mem1;
-+ priv->membase2 = phymem2;
-+ priv->iobase2 = mem2;
-+ /* to find crashes due to weird driver access
-+ * to unconfigured interface (ifup) */
-+ priv->mgmt_timer.function = (void (*)(unsigned long))0x0000dead;
-+
-+#ifdef NONESSENTIAL_FEATURES
-+ acx_show_card_eeprom_id(priv);
-+#endif /* NONESSENTIAL_FEATURES */
-+
-+ /* now we have our device, so make sure the kernel doesn't try
-+ * to send packets even though we're not associated to a network yet */
-+ acx_stop_queue(dev, "after setup");
-+
-+#ifdef SET_MODULE_OWNER
-+ SET_MODULE_OWNER(dev);
-+#endif
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70)
-+ /* this define and its netdev member exist since 2.5.70 */
-+ SET_NETDEV_DEV(dev, &pdev->dev);
-+#endif
-+
-+ /* register new dev in linked list */
-+ acx_s_device_chain_add(dev);
-+
-+ acxlog(L_IRQ|L_INIT, "using IRQ %d\n", pdev->irq);
-+
-+ /* need to be able to restore PCI state after a suspend */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-+ /* 2.6.9-rc3-mm2 (2.6.9-bk4, too) introduced this shorter version,
-+ then it made its way into 2.6.10 */
-+ pci_save_state(pdev);
-+#else
-+ pci_save_state(pdev, priv->pci_state);
-+#endif
-+
-+ /* NB: acx_read_reg() reads may return bogus data before reset_dev().
-+ ** acx100 seems to be more affected than acx111 */
-+ if (OK != acx_s_reset_dev(dev)) {
-+ goto fail_reset;
-+ }
-+
-+ /* ok, basic setup is finished, now start initialising the card */
-+
-+ if (OK != acx_read_eeprom_offset(priv, 0x05, &priv->eeprom_version)) {
-+ goto fail_read_eeprom_version;
-+ }
-+
-+ if (OK != acx_s_init_mac(dev)) {
-+ printk("acx: init_mac() FAILED\n");
-+ goto fail_init_mac;
-+ }
-+ if (OK != acx_s_set_defaults(priv)) {
-+ printk("acx: set_defaults() FAILED\n");
-+ goto fail_set_defaults;
-+ }
-+
-+ /* needs to be after acx_s_init_mac() due to necessary init stuff */
-+ acx_s_get_firmware_version(priv);
-+
-+ acx_display_hardware_details(priv);
-+
-+ pci_set_drvdata(pdev, dev);
-+
-+ /* ...and register the card, AFTER everything else has been set up,
-+ * since otherwise an ioctl could step on our feet due to
-+ * firmware operations happening in parallel or uninitialized data */
-+ err = register_netdev(dev);
-+ if (OK != err) {
-+ printk("acx: register_netdev() FAILED: %d\n", err);
-+ goto fail_register_netdev;
-+ }
-+
-+ acx_carrier_off(dev, "on probe");
-+
-+#ifdef CONFIG_PROC_FS
-+ if (OK != acx_proc_register_entries(dev)) {
-+ goto fail_proc_register_entries;
-+ }
-+#endif
-+
-+ /* after register_netdev() userspace may start working with dev
-+ * (in particular, on other CPUs), we only need to up the sem */
-+ /* acx_sem_unlock(priv); */
-+
-+ printk("acx "WLAN_RELEASE": net device %s, driver compiled "
-+ "against wireless extensions %d and Linux %s\n",
-+ dev->name, WIRELESS_EXT, UTS_RELEASE);
-+
-+#if CMD_DISCOVERY
-+ great_inquisitor(priv);
-+#endif
-+
-+ result = OK;
-+ goto done;
-+
-+ /* error paths: undo everything in reverse order... */
-+
-+#ifdef CONFIG_PROC_FS
-+fail_proc_register_entries:
-+
-+ if (priv->dev_state_mask & ACX_STATE_IFACE_UP)
-+ acx_s_down(dev);
-+
-+ unregister_netdev(dev);
-+
-+ /* after unregister_netdev() userspace is guaranteed to finish
-+ * working with it. netdev does not exist anymore.
-+ * For paranoid reasons I am taking sem anyway */
-+ acx_sem_lock(priv);
-+#endif
-+
-+fail_register_netdev:
-+
-+ acx_s_delete_dma_regions(priv);
-+ pci_set_drvdata(pdev, NULL);
-+
-+fail_set_defaults:
-+fail_init_mac:
-+fail_read_eeprom_version:
-+fail_reset:
-+
-+ acx_s_device_chain_remove(dev);
-+ free_netdev(dev);
-+fail_alloc_netdev:
-+fail_irq:
-+
-+ iounmap(mem2);
-+fail_ioremap2:
-+
-+ iounmap(mem1);
-+fail_ioremap1:
-+
-+ release_mem_region(pci_resource_start(pdev, mem_region2),
-+ pci_resource_len(pdev, mem_region2));
-+fail_request_mem_region2:
-+
-+ release_mem_region(pci_resource_start(pdev, mem_region1),
-+ pci_resource_len(pdev, mem_region1));
-+fail_request_mem_region1:
-+fail_unknown_chiptype:
-+
-+ pci_disable_device(pdev);
-+fail_pci_enable_device:
-+
-+ pci_set_power_state(pdev, 3);
-+
-+done:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_remove_pci
-+*
-+* Deallocate PCI resources for the ACX100 chip.
-+*
-+* This should NOT execute any other hardware operations on the card,
-+* since the card might already be ejected. Instead, that should be done
-+* in cleanup_module, since the card is most likely still available there.
-+*
-+* Arguments:
-+* pdev ptr to PCI device structure containing info about
-+* PCI configuration.
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+static void __devexit
-+acx_e_remove_pci(struct pci_dev *pdev)
-+{
-+ struct net_device *dev;
-+ wlandevice_t *priv;
-+ unsigned long mem_region1, mem_region2;
-+
-+ FN_ENTER;
-+
-+ dev = (struct net_device *) pci_get_drvdata(pdev);
-+ if (!dev) {
-+ acxlog(L_DEBUG, "%s: card is unused. Skipping any release code\n",
-+ __func__);
-+ goto end;
-+ }
-+
-+ priv = netdev_priv(dev);
-+
-+ /* unregister the device to not let the kernel
-+ * (e.g. ioctls) access a half-deconfigured device
-+ * NB: this will cause acx_e_close() to be called,
-+ * thus we shouldn't call it under sem! */
-+ acxlog(L_INIT, "removing device %s\n", dev->name);
-+ unregister_netdev(dev);
-+
-+ /* unregister_netdev ensures that no references to us left.
-+ * For paranoid reasons we continue to follow the rules */
-+ acx_sem_lock(priv);
-+
-+ if (IS_ACX100(priv)) {
-+ mem_region1 = PCI_ACX100_REGION1;
-+ mem_region2 = PCI_ACX100_REGION2;
-+ } else {
-+ mem_region1 = PCI_ACX111_REGION1;
-+ mem_region2 = PCI_ACX111_REGION2;
-+ }
-+
-+#ifdef CONFIG_PROC_FS
-+ acx_proc_unregister_entries(dev);
-+#endif
-+
-+ /* find our PCI device in the global acx list and remove it */
-+ acx_s_device_chain_remove(dev);
-+
-+ if (priv->dev_state_mask & ACX_STATE_IFACE_UP)
-+ acx_s_down(dev);
-+
-+ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-+
-+ acx_s_delete_dma_regions(priv);
-+
-+ /* finally, clean up PCI bus state */
-+ if (priv->iobase) iounmap(priv->iobase);
-+ if (priv->iobase2) iounmap(priv->iobase2);
-+
-+ release_mem_region(pci_resource_start(pdev, mem_region1),
-+ pci_resource_len(pdev, mem_region1));
-+
-+ release_mem_region(pci_resource_start(pdev, mem_region2),
-+ pci_resource_len(pdev, mem_region2));
-+
-+ pci_disable_device(pdev);
-+
-+ /* remove dev registration */
-+ pci_set_drvdata(pdev, NULL);
-+
-+ /* Free netdev (quite late,
-+ * since otherwise we might get caught off-guard
-+ * by a netdev timeout handler execution
-+ * expecting to see a working dev...)
-+ * But don't use free_netdev() here,
-+ * it's supported by newer kernels only */
-+ free_netdev(dev);
-+
-+ /* put device into ACPI D3 mode (shutdown) */
-+ pci_set_power_state(pdev, 3);
-+
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+#ifdef CONFIG_PM
-+static int if_was_up = 0; /* FIXME: HACK, do it correctly sometime instead */
-+static int
-+acx_e_suspend(struct pci_dev *pdev, pm_message_t state)
-+{
-+ struct net_device *dev = pci_get_drvdata(pdev);
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ printk("acx: experimental suspend handler called for %p\n", priv);
-+ if (netif_device_present(dev)) {
-+ if_was_up = 1;
-+ acx_s_down(dev);
-+ }
-+ else
-+ if_was_up = 0;
-+
-+ netif_device_detach(dev); /* This one cannot sleep */
-+ acx_s_delete_dma_regions(priv);
-+
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT0;
-+ return OK;
-+}
-+
-+static int
-+acx_e_resume(struct pci_dev *pdev)
-+{
-+ struct net_device *dev;
-+ wlandevice_t *priv;
-+
-+ printk(KERN_WARNING "rsm: resume\n");
-+ dev = pci_get_drvdata(pdev);
-+ printk(KERN_WARNING "rsm: got dev\n");
-+
-+ if (!netif_running(dev))
-+ return 0;
-+
-+ priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ printk(KERN_WARNING "rsm: got priv\n");
-+ FN_ENTER;
-+ printk("acx: experimental resume handler called for %p!\n", priv);
-+ pci_set_power_state(pdev, 0);
-+ acxlog(L_DEBUG, "rsm: power state set\n");
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-+ /* 2.6.9-rc3-mm2 (2.6.9-bk4, too) introduced this shorter version,
-+ then it made its way into 2.6.10 */
-+ pci_restore_state(pdev);
-+#else
-+ pci_restore_state(pdev, priv->pci_state);
-+#endif
-+ acxlog(L_DEBUG, "rsm: PCI state restored\n");
-+ acx_s_reset_dev(dev);
-+ acxlog(L_DEBUG, "rsm: device reset done\n");
-+
-+ if (OK != acx_s_init_mac(dev)) {
-+ printk("rsm: init_mac FAILED\n");
-+ goto fail;
-+ }
-+ acxlog(L_DEBUG, "rsm: init MAC done\n");
-+
-+ if (1 == if_was_up)
-+ acx_s_up(dev);
-+ acxlog(L_DEBUG, "rsm: acx up\n");
-+
-+ /* now even reload all card parameters as they were before suspend,
-+ * and possibly be back in the network again already :-)
-+ * FIXME: should this be done in that scheduled task instead?? */
-+ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
-+ acx_s_update_card_settings(priv, 0, 1);
-+ acxlog(L_DEBUG, "rsm: settings updated\n");
-+ netif_device_attach(dev);
-+ acxlog(L_DEBUG, "rsm: device attached\n");
-+fail: /* we need to return OK here anyway, right? */
-+ acx_sem_unlock(priv);
-+ FN_EXIT0;
-+ return OK;
-+}
-+#endif /* CONFIG_PM */
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_up
-+*
-+* Side effects:
-+* - Enables on-card interrupt requests
-+* - calls acx_start
-+* Call context:
-+* - process thread
-+* Comment:
-+* This function is called by acx_open (when ifconfig sets the
-+* device as up).
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_up(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+ acx_l_enable_irq(priv);
-+ acx_unlock(priv, flags);
-+
-+ /* acx fw < 1.9.3.e has a hardware timer, and older drivers
-+ ** used to use it. But we don't do that anymore, our OS
-+ ** has reliable software timers */
-+ init_timer(&priv->mgmt_timer);
-+ priv->mgmt_timer.function = acx_i_timer;
-+ priv->mgmt_timer.data = (unsigned long)priv;
-+
-+ /* Need to set ACX_STATE_IFACE_UP first, or else
-+ ** timer won't be started by acx_set_status() */
-+ SET_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_2_STA:
-+ /* actual scan cmd will happen in start() */
-+ acx_set_status(priv, ACX_STATUS_1_SCANNING); break;
-+ case ACX_MODE_3_AP:
-+ case ACX_MODE_MONITOR:
-+ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED); break;
-+ }
-+
-+ acx_s_start(priv);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_down
-+*
-+* Side effects:
-+* - disables on-card interrupt request
-+* Call context:
-+* process thread
-+* Comment:
-+* this disables the netdevice
-+*----------------------------------------------------------------*/
-+static void
-+acx_s_down(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ /* Disable IRQs first, so that IRQs cannot race with us */
-+ acx_lock(priv, flags);
-+ acx_l_disable_irq(priv);
-+ acx_unlock(priv, flags);
-+
-+ /* we really don't want to have an asynchronous tasklet disturb us
-+ ** after something vital for its job has been shut down, so
-+ ** end all remaining work now.
-+ **
-+ ** NB: carrier_off (done by set_status below) would lead to
-+ ** not yet fully understood deadlock in FLUSH_SCHEDULED_WORK().
-+ ** That's why we do FLUSH first.
-+ **
-+ ** NB2: we have a bad locking bug here: FLUSH_SCHEDULED_WORK()
-+ ** waits for acx_e_after_interrupt_task to complete if it is running
-+ ** on another CPU, but acx_e_after_interrupt_task
-+ ** will sleep on sem forever, because it is taken by us!
-+ ** Work around that by temporary sem unlock.
-+ ** This will fail miserably if we'll be hit by concurrent
-+ ** iwconfig or something in between. TODO! */
-+ acx_sem_unlock(priv);
-+ FLUSH_SCHEDULED_WORK();
-+ acx_sem_lock(priv);
-+
-+ /* This is possible:
-+ ** FLUSH_SCHEDULED_WORK -> acx_e_after_interrupt_task ->
-+ ** -> set_status(ASSOCIATED) -> wake_queue()
-+ ** That's why we stop queue _after_ FLUSH_SCHEDULED_WORK
-+ ** lock/unlock is just paranoia, maybe not needed */
-+ acx_lock(priv, flags);
-+ acx_stop_queue(dev, "during close");
-+ acx_set_status(priv, ACX_STATUS_0_STOPPED);
-+ acx_unlock(priv, flags);
-+
-+ /* kernel/timer.c says it's illegal to del_timer_sync()
-+ ** a timer which restarts itself. We guarantee this cannot
-+ ** ever happen because acx_i_timer() never does this if
-+ ** status is ACX_STATUS_0_STOPPED */
-+ del_timer_sync(&priv->mgmt_timer);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_open
-+*
-+* WLAN device open method. Called from p80211netdev when kernel
-+* device open (start) method is called in response to the
-+* SIOCSIFFLAGS ioctl changing the flags bit IFF_UP
-+* from clear to set.
-+*
-+* Returns:
-+* 0 success
-+* >0 f/w reported error
-+* <0 driver reported error
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+static int
-+acx_e_open(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ int result = OK;
-+
-+ FN_ENTER;
-+
-+ acxlog(L_INIT, "module count++\n");
-+ WLAN_MOD_INC_USE_COUNT;
-+
-+ acx_sem_lock(priv);
-+
-+ acx_init_task_scheduler(priv);
-+
-+ /* request shared IRQ handler */
-+ if (request_irq(dev->irq, acx_i_interrupt, SA_SHIRQ, dev->name, dev)) {
-+ printk("%s: request_irq FAILED\n", dev->name);
-+ result = -EAGAIN;
-+ goto done;
-+ }
-+ acxlog(L_DEBUG|L_IRQ, "request_irq %d successful\n", dev->irq);
-+
-+ /* ifup device */
-+ acx_s_up(dev);
-+
-+ /* We don't currently have to do anything else.
-+ * The setup of the MAC should be subsequently completed via
-+ * the mlme commands.
-+ * Higher layers know we're ready from dev->start==1 and
-+ * dev->tbusy==0. Our rx path knows to pass up received/
-+ * frames because of dev->flags&IFF_UP is true.
-+ */
-+done:
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_close
-+*
-+* WLAN device close method. Called from network core when kernel
-+* device close method is called in response to the
-+* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
-+* from set to clear.
-+* (i.e. called for "ifconfig DEV down")
-+*
-+* Returns:
-+* 0 success
-+* >0 f/w reported error
-+* <0 driver reported error
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+static int
-+acx_e_close(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ /* ifdown device */
-+ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-+ if (netif_device_present(dev)) {
-+ acx_s_down(dev);
-+ }
-+
-+ /* disable all IRQs, release shared IRQ handler */
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
-+ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
-+ free_irq(dev->irq, dev);
-+
-+ /* We currently don't have to do anything else.
-+ * Higher layers know we're not ready from dev->start==0 and
-+ * dev->tbusy==1. Our rx path knows to not pass up received
-+ * frames because of dev->flags&IFF_UP is false.
-+ */
-+ acxlog(L_INIT, "module count--\n");
-+ WLAN_MOD_DEC_USE_COUNT;
-+
-+ acx_sem_unlock(priv);
-+
-+ acxlog(L_INIT, "closed device\n");
-+ FN_EXIT0;
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_i_tx_timeout
-+*
-+* Called from network core. Must not sleep!
-+*----------------------------------------------------------------*/
-+static void
-+acx_i_tx_timeout(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ unsigned int tx_num_cleaned;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+
-+ /* clean processed tx descs, they may have been completely full */
-+ tx_num_cleaned = acx_l_clean_tx_desc(priv);
-+
-+ /* nothing cleaned, yet (almost) no free buffers available?
-+ * --> clean all tx descs, no matter which status!!
-+ * Note that I strongly suspect that doing emergency cleaning
-+ * may confuse the firmware. This is a last ditch effort to get
-+ * ANYTHING to work again...
-+ *
-+ * TODO: it's best to simply reset & reinit hw from scratch...
-+ */
-+ if ((priv->tx_free <= TX_EMERG_CLEAN) && (tx_num_cleaned == 0)) {
-+ printk("%s: FAILED to free any of the many full tx buffers. "
-+ "Switching to emergency freeing. "
-+ "Please report!\n", dev->name);
-+ acx_l_clean_tx_desc_emergency(priv);
-+ }
-+
-+ if (acx_queue_stopped(dev) && (ACX_STATUS_4_ASSOCIATED == priv->status))
-+ acx_wake_queue(dev, "after tx timeout");
-+
-+ /* stall may have happened due to radio drift, so recalib radio */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-+
-+ /* do unimportant work last */
-+ printk("%s: tx timeout!\n", dev->name);
-+ priv->stats.tx_errors++;
-+
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_get_stats
-+*----------------------------------------------------------------*/
-+static struct net_device_stats*
-+acx_e_get_stats(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ return &priv->stats;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_get_wireless_stats
-+*----------------------------------------------------------------*/
-+static struct iw_statistics*
-+acx_e_get_wireless_stats(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ return &priv->wstats;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_i_set_multicast_list
-+* FIXME: most likely needs refinement
-+*----------------------------------------------------------------*/
-+static void
-+acx_i_set_multicast_list(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+
-+ /* firmwares don't have allmulti capability,
-+ * so just use promiscuous mode instead in this case. */
-+ if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
-+ SET_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
-+ CLEAR_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
-+ SET_BIT(priv->set_mask, SET_RXCONFIG);
-+ /* let kernel know in case *we* needed to set promiscuous */
-+ dev->flags |= (IFF_PROMISC|IFF_ALLMULTI);
-+ } else {
-+ CLEAR_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
-+ SET_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
-+ SET_BIT(priv->set_mask, SET_RXCONFIG);
-+ dev->flags &= ~(IFF_PROMISC|IFF_ALLMULTI);
-+ }
-+
-+ /* cannot update card settings directly here, atomic context */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
-+
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+
-+static void
-+acx_l_update_link_quality_led(wlandevice_t *priv)
-+{
-+ int qual;
-+
-+ qual = acx_signal_determine_quality(priv->wstats.qual.level, priv->wstats.qual.noise);
-+ if (qual > priv->brange_max_quality)
-+ qual = priv->brange_max_quality;
-+
-+ if (time_after(jiffies, priv->brange_time_last_state_change +
-+ (HZ/2 - HZ/2 * (unsigned long) qual/priv->brange_max_quality ) )) {
-+ acx_l_power_led(priv, (priv->brange_last_state == 0));
-+ priv->brange_last_state ^= 1; /* toggle */
-+ priv->brange_time_last_state_change = jiffies;
-+ }
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_enable_irq
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_enable_irq(wlandevice_t *priv)
-+{
-+ FN_ENTER;
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask);
-+ acx_write_reg16(priv, IO_ACX_FEMR, 0x8000);
-+ priv->irqs_active = 1;
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_disable_irq
-+*----------------------------------------------------------------*/
-+static void
-+acx_l_disable_irq(wlandevice_t *priv)
-+{
-+ FN_ENTER;
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask_off);
-+ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
-+ priv->irqs_active = 0;
-+ FN_EXIT0;
-+}
-+
-+/* scan is complete. all frames now on the receive queue are valid */
-+#define INFO_SCAN_COMPLETE 0x0001
-+#define INFO_WEP_KEY_NOT_FOUND 0x0002
-+/* hw has been reset as the result of a watchdog timer timeout */
-+#define INFO_WATCH_DOG_RESET 0x0003
-+/* failed to send out NULL frame from PS mode notification to AP */
-+/* recommended action: try entering 802.11 PS mode again */
-+#define INFO_PS_FAIL 0x0004
-+/* encryption/decryption process on a packet failed */
-+#define INFO_IV_ICV_FAILURE 0x0005
-+
-+static void
-+acx_l_handle_info_irq(wlandevice_t *priv)
-+{
-+#if ACX_DEBUG
-+ static const char * const info_type_msg[] = {
-+ "(unknown)",
-+ "scan complete",
-+ "WEP key not found",
-+ "internal watchdog reset was done",
-+ "failed to send powersave (NULL frame) notification to AP",
-+ "encrypt/decrypt on a packet has failed",
-+ "TKIP tx keys disabled",
-+ "TKIP rx keys disabled",
-+ "TKIP rx: key ID not found",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "???",
-+ "TKIP IV value exceeds thresh"
-+ };
-+#endif
-+ acx_read_info_status(priv);
-+ acxlog(L_IRQ, "got Info IRQ: status 0x%04X type 0x%04X: %s\n",
-+ priv->info_status, priv->info_type,
-+ info_type_msg[(priv->info_type >= VEC_SIZE(info_type_msg)) ?
-+ 0 : priv->info_type]
-+ );
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_i_interrupt
-+*
-+* IRQ handler (atomic context, must not sleep, blah, blah)
-+*----------------------------------------------------------------*/
-+static void
-+acx_log_unusual_irq(u16 irqtype) {
-+ /*
-+ if (!printk_ratelimit())
-+ return;
-+ */
-+
-+ printk("acx: got");
-+ if (irqtype & HOST_INT_RX_DATA) {
-+ printk(" Rx_Data");
-+ }
-+ /* HOST_INT_TX_COMPLETE */
-+ if (irqtype & HOST_INT_TX_XFER) {
-+ printk(" Tx_Xfer");
-+ }
-+ /* HOST_INT_RX_COMPLETE */
-+ if (irqtype & HOST_INT_DTIM) {
-+ printk(" DTIM");
-+ }
-+ if (irqtype & HOST_INT_BEACON) {
-+ printk(" Beacon");
-+ }
-+ if (irqtype & HOST_INT_TIMER) {
-+ acxlog(L_IRQ, " Timer");
-+ }
-+ if (irqtype & HOST_INT_KEY_NOT_FOUND) {
-+ printk(" Key_Not_Found");
-+ }
-+ if (irqtype & HOST_INT_IV_ICV_FAILURE) {
-+ printk(" IV_ICV_Failure");
-+ }
-+ /* HOST_INT_CMD_COMPLETE */
-+ /* HOST_INT_INFO */
-+ if (irqtype & HOST_INT_OVERFLOW) {
-+ printk(" Overflow");
-+ }
-+ if (irqtype & HOST_INT_PROCESS_ERROR) {
-+ printk(" Process_Error");
-+ }
-+ /* HOST_INT_SCAN_COMPLETE */
-+ if (irqtype & HOST_INT_FCS_THRESHOLD) {
-+ printk(" FCS_Threshold");
-+ }
-+ if (irqtype & HOST_INT_UNKNOWN) {
-+ printk(" Unknown");
-+ }
-+ printk(" IRQ(s)\n");
-+}
-+
-+static irqreturn_t
-+acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ wlandevice_t *priv;
-+ unsigned long flags;
-+ unsigned int irqcount = MAX_IRQLOOPS_PER_JIFFY;
-+ u16 irqtype, unmasked;
-+
-+ priv = (wlandevice_t *) (((netdevice_t *) dev_id)->priv);
-+
-+ /* LOCKING: can just spin_lock() since IRQs are disabled anyway.
-+ * I am paranoid */
-+ acx_lock(priv, flags);
-+
-+ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
-+ if (unlikely(0xffff == unmasked)) {
-+ /* 0xffff value hints at missing hardware,
-+ * so don't do anything.
-+ * FIXME: that's not very clean - maybe we are able to
-+ * establish a flag which definitely tells us that some
-+ * hardware is absent and which we could check here?
-+ * Hmm, but other drivers do the very same thing... */
-+ acxlog(L_IRQ, "IRQ type:FFFF - device removed? IRQ_NONE\n");
-+ goto none;
-+ }
-+
-+ /* We will check only "interesting" IRQ types */
-+ irqtype = unmasked & ~priv->irq_mask;
-+ if (!irqtype) {
-+ /* We are on a shared IRQ line and it wasn't our IRQ */
-+ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X - all are masked, IRQ_NONE\n",
-+ unmasked, priv->irq_mask);
-+ goto none;
-+ }
-+
-+ /* Done here because IRQ_NONEs taking three lines of log
-+ ** drive me crazy */
-+ FN_ENTER;
-+
-+#define IRQ_ITERATE 1
-+#if IRQ_ITERATE
-+if (jiffies != priv->irq_last_jiffies) {
-+ priv->irq_loops_this_jiffy = 0;
-+ priv->irq_last_jiffies = jiffies;
-+}
-+
-+/* safety condition; we'll normally abort loop below
-+ * in case no IRQ type occurred */
-+while (--irqcount) {
-+#endif
-+ /* ACK all IRQs asap */
-+ acx_write_reg16(priv, IO_ACX_IRQ_ACK, 0xffff);
-+
-+ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X, type & ~mask:%04X\n",
-+ unmasked, priv->irq_mask, irqtype);
-+
-+ /* Handle most important IRQ types first */
-+ if (irqtype & HOST_INT_RX_COMPLETE) {
-+ acxlog(L_IRQ, "got Rx_Complete IRQ\n");
-+ acx_l_process_rx_desc(priv);
-+ }
-+ if (irqtype & HOST_INT_TX_COMPLETE) {
-+ acxlog(L_IRQ, "got Tx_Complete IRQ\n");
-+ /* don't clean up on each Tx complete, wait a bit
-+ * unless we're going towards full, in which case
-+ * we do it immediately, too (otherwise we might lockup
-+ * with a full Tx buffer if we go into
-+ * acx_l_clean_tx_desc() at a time when we won't wakeup
-+ * the net queue in there for some reason...) */
-+ if (priv->tx_free <= TX_START_CLEAN) {
-+#if TX_CLEANUP_IN_SOFTIRQ
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_TX_CLEANUP);
-+#else
-+ acx_l_clean_tx_desc(priv);
-+#endif
-+ }
-+ }
-+
-+ /* Less frequent ones */
-+ if (irqtype & (0
-+ | HOST_INT_CMD_COMPLETE
-+ | HOST_INT_INFO
-+ | HOST_INT_SCAN_COMPLETE
-+ )) {
-+ if (irqtype & HOST_INT_CMD_COMPLETE) {
-+ acxlog(L_IRQ, "got Command_Complete IRQ\n");
-+ /* save the state for the running issue_cmd() */
-+ SET_BIT(priv->irq_status, HOST_INT_CMD_COMPLETE);
-+ }
-+ if (irqtype & HOST_INT_INFO) {
-+ acx_l_handle_info_irq(priv);
-+ }
-+ if (irqtype & HOST_INT_SCAN_COMPLETE) {
-+ acxlog(L_IRQ, "got Scan_Complete IRQ\n");
-+ /* need to do that in process context */
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_COMPLETE_SCAN);
-+ /* remember that fw is not scanning anymore */
-+ SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
-+ }
-+ }
-+
-+ /* These we just log, but either they happen rarely
-+ * or we keep them masked out */
-+ if (irqtype & (0
-+ | HOST_INT_RX_DATA
-+ /* | HOST_INT_TX_COMPLETE */
-+ | HOST_INT_TX_XFER
-+ /* | HOST_INT_RX_COMPLETE */
-+ | HOST_INT_DTIM
-+ | HOST_INT_BEACON
-+ | HOST_INT_TIMER
-+ | HOST_INT_KEY_NOT_FOUND
-+ | HOST_INT_IV_ICV_FAILURE
-+ /* | HOST_INT_CMD_COMPLETE */
-+ /* | HOST_INT_INFO */
-+ | HOST_INT_OVERFLOW
-+ | HOST_INT_PROCESS_ERROR
-+ /* | HOST_INT_SCAN_COMPLETE */
-+ | HOST_INT_FCS_THRESHOLD
-+ | HOST_INT_UNKNOWN
-+ )) {
-+ acx_log_unusual_irq(irqtype);
-+ }
-+
-+#if IRQ_ITERATE
-+ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
-+ irqtype = unmasked & ~priv->irq_mask;
-+ /* Bail out if no new IRQ bits or if all are masked out */
-+ if (!irqtype)
-+ break;
-+
-+ if (unlikely(++priv->irq_loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY)) {
-+ printk(KERN_ERR "acx: too many interrupts per jiffy!\n");
-+ /* Looks like card floods us with IRQs! Try to stop that */
-+ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
-+ /* This will short-circuit all future attempts to handle IRQ.
-+ * We cant do much more... */
-+ priv->irq_mask = 0;
-+ break;
-+ }
-+}
-+#endif
-+ /* Routine to perform blink with range */
-+ if (unlikely(priv->led_power == 2))
-+ acx_l_update_link_quality_led(priv);
-+
-+/* handled: */
-+ /* acx_write_flush(priv); - not needed, last op was read anyway */
-+ acx_unlock(priv, flags);
-+ FN_EXIT0;
-+ return IRQ_HANDLED;
-+
-+none:
-+ acx_unlock(priv, flags);
-+ return IRQ_NONE;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_power_led
-+*----------------------------------------------------------------*/
-+void
-+acx_l_power_led(wlandevice_t *priv, int enable)
-+{
-+ u16 gpio_pled = IS_ACX111(priv) ? 0x0040 : 0x0800;
-+
-+ /* A hack. Not moving message rate limiting to priv->xxx
-+ * (it's only a debug message after all) */
-+ static int rate_limit = 0;
-+
-+ if (rate_limit++ < 3)
-+ acxlog(L_IOCTL, "Please report in case toggling the power "
-+ "LED doesn't work for your card!\n");
-+ if (enable)
-+ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
-+ acx_read_reg16(priv, IO_ACX_GPIO_OUT) & ~gpio_pled);
-+ else
-+ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
-+ acx_read_reg16(priv, IO_ACX_GPIO_OUT) | gpio_pled);
-+}
-+
-+
-+/***********************************************************************
-+** Ioctls
-+*/
-+
-+/***********************************************************************
-+*/
-+int
-+acx111pci_ioctl_info(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+#if ACX_DEBUG
-+ wlandevice_t *priv = netdev_priv(dev);
-+ rxdesc_t *rxdesc;
-+ txdesc_t *txdesc;
-+ rxhostdesc_t *rxhostdesc;
-+ txhostdesc_t *txhostdesc;
-+ struct acx111_ie_memoryconfig memconf;
-+ struct acx111_ie_queueconfig queueconf;
-+ unsigned long flags;
-+ int i;
-+ char memmap[0x34];
-+ char rxconfig[0x8];
-+ char fcserror[0x8];
-+ char ratefallback[0x5];
-+
-+ if ( !(acx_debug & (L_IOCTL|L_DEBUG)) )
-+ return OK;
-+ /* using printk() since we checked debug flag already */
-+
-+ acx_sem_lock(priv);
-+
-+ if (!IS_ACX111(priv)) {
-+ printk("acx111-specific function called "
-+ "with non-acx111 chip, aborting\n");
-+ goto end_ok;
-+ }
-+
-+ /* get Acx111 Memory Configuration */
-+ memset(&memconf, 0, sizeof(memconf));
-+ /* BTW, fails with 12 (Write only) error code.
-+ ** Retained for easy testing of issue_cmd error handling :) */
-+ acx_s_interrogate(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG);
-+
-+ /* get Acx111 Queue Configuration */
-+ memset(&queueconf, 0, sizeof(queueconf));
-+ acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
-+
-+ /* get Acx111 Memory Map */
-+ memset(memmap, 0, sizeof(memmap));
-+ acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP);
-+
-+ /* get Acx111 Rx Config */
-+ memset(rxconfig, 0, sizeof(rxconfig));
-+ acx_s_interrogate(priv, &rxconfig, ACX1xx_IE_RXCONFIG);
-+
-+ /* get Acx111 fcs error count */
-+ memset(fcserror, 0, sizeof(fcserror));
-+ acx_s_interrogate(priv, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT);
-+
-+ /* get Acx111 rate fallback */
-+ memset(ratefallback, 0, sizeof(ratefallback));
-+ acx_s_interrogate(priv, &ratefallback, ACX1xx_IE_RATE_FALLBACK);
-+
-+ /* force occurrence of a beacon interrupt */
-+ /* TODO: comment why is this necessary */
-+ acx_write_reg16(priv, IO_ACX_HINT_TRIG, HOST_INT_BEACON);
-+
-+ /* dump Acx111 Mem Configuration */
-+ printk("dump mem config:\n"
-+ "data read: %d, struct size: %d\n"
-+ "Number of stations: %1X\n"
-+ "Memory block size: %1X\n"
-+ "tx/rx memory block allocation: %1X\n"
-+ "count rx: %X / tx: %X queues\n"
-+ "options %1X\n"
-+ "fragmentation %1X\n"
-+ "Rx Queue 1 Count Descriptors: %X\n"
-+ "Rx Queue 1 Host Memory Start: %X\n"
-+ "Tx Queue 1 Count Descriptors: %X\n"
-+ "Tx Queue 1 Attributes: %X\n",
-+ memconf.len, (int) sizeof(memconf),
-+ memconf.no_of_stations,
-+ memconf.memory_block_size,
-+ memconf.tx_rx_memory_block_allocation,
-+ memconf.count_rx_queues, memconf.count_tx_queues,
-+ memconf.options,
-+ memconf.fragmentation,
-+ memconf.rx_queue1_count_descs,
-+ acx2cpu(memconf.rx_queue1_host_rx_start),
-+ memconf.tx_queue1_count_descs,
-+ memconf.tx_queue1_attributes);
-+
-+ /* dump Acx111 Queue Configuration */
-+ printk("dump queue head:\n"
-+ "data read: %d, struct size: %d\n"
-+ "tx_memory_block_address (from card): %X\n"
-+ "rx_memory_block_address (from card): %X\n"
-+ "rx1_queue address (from card): %X\n"
-+ "tx1_queue address (from card): %X\n"
-+ "tx1_queue attributes (from card): %X\n",
-+ queueconf.len, (int) sizeof(queueconf),
-+ queueconf.tx_memory_block_address,
-+ queueconf.rx_memory_block_address,
-+ queueconf.rx1_queue_address,
-+ queueconf.tx1_queue_address,
-+ queueconf.tx1_attributes);
-+
-+ /* dump Acx111 Mem Map */
-+ printk("dump mem map:\n"
-+ "data read: %d, struct size: %d\n"
-+ "Code start: %X\n"
-+ "Code end: %X\n"
-+ "WEP default key start: %X\n"
-+ "WEP default key end: %X\n"
-+ "STA table start: %X\n"
-+ "STA table end: %X\n"
-+ "Packet template start: %X\n"
-+ "Packet template end: %X\n"
-+ "Queue memory start: %X\n"
-+ "Queue memory end: %X\n"
-+ "Packet memory pool start: %X\n"
-+ "Packet memory pool end: %X\n"
-+ "iobase: %p\n"
-+ "iobase2: %p\n",
-+ *((u16 *)&memmap[0x02]), (int) sizeof(memmap),
-+ *((u32 *)&memmap[0x04]),
-+ *((u32 *)&memmap[0x08]),
-+ *((u32 *)&memmap[0x0C]),
-+ *((u32 *)&memmap[0x10]),
-+ *((u32 *)&memmap[0x14]),
-+ *((u32 *)&memmap[0x18]),
-+ *((u32 *)&memmap[0x1C]),
-+ *((u32 *)&memmap[0x20]),
-+ *((u32 *)&memmap[0x24]),
-+ *((u32 *)&memmap[0x28]),
-+ *((u32 *)&memmap[0x2C]),
-+ *((u32 *)&memmap[0x30]),
-+ priv->iobase,
-+ priv->iobase2);
-+
-+ /* dump Acx111 Rx Config */
-+ printk("dump rx config:\n"
-+ "data read: %d, struct size: %d\n"
-+ "rx config: %X\n"
-+ "rx filter config: %X\n",
-+ *((u16 *)&rxconfig[0x02]), (int) sizeof(rxconfig),
-+ *((u16 *)&rxconfig[0x04]),
-+ *((u16 *)&rxconfig[0x06]));
-+
-+ /* dump Acx111 fcs error */
-+ printk("dump fcserror:\n"
-+ "data read: %d, struct size: %d\n"
-+ "fcserrors: %X\n",
-+ *((u16 *)&fcserror[0x02]), (int) sizeof(fcserror),
-+ *((u32 *)&fcserror[0x04]));
-+
-+ /* dump Acx111 rate fallback */
-+ printk("dump rate fallback:\n"
-+ "data read: %d, struct size: %d\n"
-+ "ratefallback: %X\n",
-+ *((u16 *)&ratefallback[0x02]), (int) sizeof(ratefallback),
-+ *((u8 *)&ratefallback[0x04]));
-+
-+ /* protect against IRQ */
-+ acx_lock(priv, flags);
-+
-+ /* dump acx111 internal rx descriptor ring buffer */
-+ rxdesc = priv->rxdesc_start;
-+
-+ /* loop over complete receive pool */
-+ if (rxdesc) for (i = 0; i < RX_CNT; i++) {
-+ printk("\ndump internal rxdesc %d:\n"
-+ "mem pos %p\n"
-+ "next 0x%X\n"
-+ "acx mem pointer (dynamic) 0x%X\n"
-+ "CTL (dynamic) 0x%X\n"
-+ "Rate (dynamic) 0x%X\n"
-+ "RxStatus (dynamic) 0x%X\n"
-+ "Mod/Pre (dynamic) 0x%X\n",
-+ i,
-+ rxdesc,
-+ acx2cpu(rxdesc->pNextDesc),
-+ acx2cpu(rxdesc->ACXMemPtr),
-+ rxdesc->Ctl_8,
-+ rxdesc->rate,
-+ rxdesc->error,
-+ rxdesc->SNR);
-+ rxdesc++;
-+ }
-+
-+ /* dump host rx descriptor ring buffer */
-+
-+ rxhostdesc = priv->rxhostdesc_start;
-+
-+ /* loop over complete receive pool */
-+ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
-+ printk("\ndump host rxdesc %d:\n"
-+ "mem pos %p\n"
-+ "buffer mem pos 0x%X\n"
-+ "buffer mem offset 0x%X\n"
-+ "CTL 0x%X\n"
-+ "Length 0x%X\n"
-+ "next 0x%X\n"
-+ "Status 0x%X\n",
-+ i,
-+ rxhostdesc,
-+ acx2cpu(rxhostdesc->data_phy),
-+ rxhostdesc->data_offset,
-+ le16_to_cpu(rxhostdesc->Ctl_16),
-+ le16_to_cpu(rxhostdesc->length),
-+ acx2cpu(rxhostdesc->desc_phy_next),
-+ rxhostdesc->Status);
-+ rxhostdesc++;
-+ }
-+
-+ /* dump acx111 internal tx descriptor ring buffer */
-+ txdesc = priv->txdesc_start;
-+
-+ /* loop over complete transmit pool */
-+ if (txdesc) for (i = 0; i < TX_CNT; i++) {
-+ printk("\ndump internal txdesc %d:\n"
-+ "size 0x%X\n"
-+ "mem pos %p\n"
-+ "next 0x%X\n"
-+ "acx mem pointer (dynamic) 0x%X\n"
-+ "host mem pointer (dynamic) 0x%X\n"
-+ "length (dynamic) 0x%X\n"
-+ "CTL (dynamic) 0x%X\n"
-+ "CTL2 (dynamic) 0x%X\n"
-+ "Status (dynamic) 0x%X\n"
-+ "Rate (dynamic) 0x%X\n",
-+ i,
-+ (int) sizeof(struct txdesc),
-+ txdesc,
-+ acx2cpu(txdesc->pNextDesc),
-+ acx2cpu(txdesc->AcxMemPtr),
-+ acx2cpu(txdesc->HostMemPtr),
-+ le16_to_cpu(txdesc->total_length),
-+ txdesc->Ctl_8,
-+ txdesc->Ctl2_8, txdesc->error,
-+ txdesc->u.r1.rate);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+
-+ /* dump host tx descriptor ring buffer */
-+
-+ txhostdesc = priv->txhostdesc_start;
-+
-+ /* loop over complete host send pool */
-+ if (txhostdesc) for (i = 0; i < TX_CNT * 2; i++) {
-+ printk("\ndump host txdesc %d:\n"
-+ "mem pos %p\n"
-+ "buffer mem pos 0x%X\n"
-+ "buffer mem offset 0x%X\n"
-+ "CTL 0x%X\n"
-+ "Length 0x%X\n"
-+ "next 0x%X\n"
-+ "Status 0x%X\n",
-+ i,
-+ txhostdesc,
-+ acx2cpu(txhostdesc->data_phy),
-+ txhostdesc->data_offset,
-+ le16_to_cpu(txhostdesc->Ctl_16),
-+ le16_to_cpu(txhostdesc->length),
-+ acx2cpu(txhostdesc->desc_phy_next),
-+ le32_to_cpu(txhostdesc->Status));
-+ txhostdesc++;
-+ }
-+
-+ /* acx_write_reg16(priv, 0xb4, 0x4); */
-+
-+ acx_unlock(priv, flags);
-+end_ok:
-+
-+ acx_sem_unlock(priv);
-+#endif /* ACX_DEBUG */
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acx100pci_ioctl_set_phy_amp_bias(
-+ struct net_device *dev,
-+ struct iw_request_info *info,
-+ struct iw_param *vwrq,
-+ char *extra)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ u16 gpio_old;
-+
-+ if (!IS_ACX100(priv)) {
-+ /* WARNING!!!
-+ * Removing this check *might* damage
-+ * hardware, since we're tweaking GPIOs here after all!!!
-+ * You've been warned...
-+ * WARNING!!! */
-+ printk("acx: sorry, setting bias level for non-acx100 "
-+ "is not supported yet\n");
-+ return OK;
-+ }
-+
-+ if (*extra > 7) {
-+ printk("acx: invalid bias parameter, range is 0-7\n");
-+ return -EINVAL;
-+ }
-+
-+ acx_sem_lock(priv);
-+
-+ /* Need to lock accesses to [IO_ACX_GPIO_OUT]:
-+ * IRQ handler uses it to update LED */
-+ acx_lock(priv, flags);
-+ gpio_old = acx_read_reg16(priv, IO_ACX_GPIO_OUT);
-+ acx_write_reg16(priv, IO_ACX_GPIO_OUT, (gpio_old & 0xf8ff) | ((u16)*extra << 8));
-+ acx_unlock(priv, flags);
-+
-+ acxlog(L_DEBUG, "gpio_old: 0x%04X\n", gpio_old);
-+ printk("%s: PHY power amplifier bias: old:%d, new:%d\n",
-+ dev->name,
-+ (gpio_old & 0x0700) >> 8, (unsigned char)*extra);
-+
-+ acx_sem_unlock(priv);
-+
-+ return OK;
-+}
-+
-+
-+/***************************************************************
-+** acxpci_l_alloc_tx
-+** Actually returns a txdesc_t* ptr
-+*/
-+tx_t*
-+acxpci_l_alloc_tx(wlandevice_t* priv)
-+{
-+ struct txdesc *txdesc;
-+ u8 ctl8;
-+
-+ FN_ENTER;
-+
-+ txdesc = get_txdesc(priv, priv->tx_head);
-+ ctl8 = txdesc->Ctl_8;
-+ if (unlikely(DESC_CTL_HOSTOWN != (ctl8 & DESC_CTL_DONE))) {
-+ /* whoops, descr at current index is not free, so probably
-+ * ring buffer already full */
-+ /* FIXME: this causes a deadlock situation (endless
-+ * loop) in case the current descriptor remains busy,
-+ * so handle it a bit better in the future!! */
-+ printk("acx: BUG: tx_head->Ctl8=0x%02X, (0x%02X & "
-+ "0x"DESC_CTL_DONE_STR") != 0x"DESC_CTL_HOSTOWN_STR
-+ ": failed to find free tx descr\n",
-+ ctl8, ctl8);
-+ txdesc = NULL;
-+ goto end;
-+ }
-+
-+ priv->tx_free--;
-+ acxlog(L_BUFT, "tx: got desc %u, %u remain\n",
-+ priv->tx_head, priv->tx_free);
-+
-+/*
-+ * This comment is probably not entirely correct, needs further discussion
-+ * (restored commented-out code below to fix Tx ring buffer overflow,
-+ * since it's much better to have a slightly less efficiently used ring
-+ * buffer rather than one which easily overflows):
-+ *
-+ * This doesn't do anything other than limit our maximum number of
-+ * buffers used at a single time (we might as well just declare
-+ * TX_STOP_QUEUE less descriptors when we open up.) We should just let it
-+ * slide here, and back off TX_STOP_QUEUE in acx_l_clean_tx_desc, when given the
-+ * opportunity to let the queue start back up.
-+ */
-+ if (priv->tx_free < TX_STOP_QUEUE) {
-+ acxlog(L_BUF, "stop queue (%u tx desc left)\n",
-+ priv->tx_free);
-+ acx_stop_queue(priv->netdev, NULL);
-+ }
-+
-+ /* returning current descriptor, so advance to next free one */
-+ priv->tx_head = (priv->tx_head + 1) % TX_CNT;
-+end:
-+ FN_EXIT0;
-+
-+ return (tx_t*)txdesc;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+void*
-+acxpci_l_get_txbuf(wlandevice_t *priv, tx_t* tx_opaque)
-+{
-+ return acx_get_txhostdesc(priv, (txdesc_t*)tx_opaque)->data;
-+}
-+
-+
-+/***********************************************************************
-+** acxpci_l_tx_data
-+**
-+** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
-+** Can be called from acx_i_start_xmit (data frames from net core).
-+*/
-+void
-+acxpci_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int len)
-+{
-+ txdesc_t *txdesc = (txdesc_t*)tx_opaque;
-+ txhostdesc_t *hostdesc1, *hostdesc2;
-+ client_t *clt;
-+ u8 Ctl_8, Ctl2_8;
-+
-+ FN_ENTER;
-+
-+ /* fw doesn't tx such packets anyhow */
-+ if (len < WLAN_HDR_A3_LEN)
-+ goto end;
-+
-+ hostdesc1 = acx_get_txhostdesc(priv, txdesc);
-+ hostdesc2 = hostdesc1 + 1;
-+
-+ /* modify flag status in separate variable to be able to write it back
-+ * in one big swoop later (also in order to have less device memory
-+ * accesses) */
-+ Ctl_8 = txdesc->Ctl_8;
-+ Ctl2_8 = txdesc->Ctl2_8;
-+
-+ /* DON'T simply set Ctl field to 0 here globally,
-+ * it needs to maintain a consistent flag status (those are state flags!!),
-+ * otherwise it may lead to severe disruption. Only set or reset particular
-+ * flags at the exact moment this is needed...
-+ * FIXME: what about Ctl2? Equally problematic? */
-+
-+ /* let chip do RTS/CTS handshaking before sending
-+ * in case packet size exceeds threshold */
-+ if (len > priv->rts_threshold)
-+ SET_BIT(Ctl2_8, DESC_CTL2_RTS);
-+ else
-+ CLEAR_BIT(Ctl2_8, DESC_CTL2_RTS);
-+
-+#ifdef DEBUG_WEP
-+ if (priv->wep_enabled)
-+ SET_BIT(Ctl2_8, DESC_CTL2_WEP);
-+ else
-+ CLEAR_BIT(Ctl2_8, DESC_CTL2_WEP);
-+#endif
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_3_AP:
-+ clt = acx_l_sta_list_get(priv, ((wlan_hdr_t*)hostdesc1->data)->a1);
-+ break;
-+ case ACX_MODE_2_STA:
-+ clt = priv->ap_client;
-+ break;
-+#if 0
-+/* testing was done on acx111: */
-+ case ACX_MODE_MONITOR:
-+ SET_BIT(Ctl2_8, 0
-+/* sends CTS to self before packet */
-+ + DESC_CTL2_SEQ /* don't increase sequence field */
-+/* not working (looks like good fcs is still added) */
-+ + DESC_CTL2_FCS /* don't add the FCS */
-+/* not tested */
-+ + DESC_CTL2_MORE_FRAG
-+/* not tested */
-+ + DESC_CTL2_RETRY /* don't increase retry field */
-+/* not tested */
-+ + DESC_CTL2_POWER /* don't increase power mgmt. field */
-+/* no effect */
-+ + DESC_CTL2_WEP /* encrypt this frame */
-+/* not tested */
-+ + DESC_CTL2_DUR /* don't increase duration field */
-+ );
-+ /* fallthrough */
-+#endif
-+ default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
-+ clt = NULL;
-+ break;
-+ }
-+
-+ if (unlikely(clt && !clt->rate_cur)) {
-+ printk("acx: driver bug! bad ratemask\n");
-+ goto end;
-+ }
-+
-+ /* used in tx cleanup routine for auto rate and accounting: */
-+ acx_put_txc(priv, txdesc, clt);
-+
-+ txdesc->total_length = cpu_to_le16(len);
-+ hostdesc2->length = cpu_to_le16(len - WLAN_HDR_A3_LEN);
-+ if (IS_ACX111(priv)) {
-+ u16 rate_cur = clt ? clt->rate_cur : priv->rate_bcast;
-+ /* note that if !txdesc->do_auto, txrate->cur
-+ ** has only one nonzero bit */
-+ txdesc->u.r2.rate111 = cpu_to_le16(
-+ rate_cur
-+ /* WARNING: I was never able to make it work with prism54 AP.
-+ ** It was falling down to 1Mbit where shortpre is not applicable,
-+ ** and not working at all at "5,11 basic rates only" setting.
-+ ** I even didn't see tx packets in radio packet capture.
-+ ** Disabled for now --vda */
-+ /*| ((clt->shortpre && clt->cur!=RATE111_1) ? RATE111_SHORTPRE : 0) */
-+ );
-+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
-+ /* should add this to rate111 above as necessary */
-+ | (clt->pbcc511 ? RATE111_PBCC511 : 0)
-+#endif
-+ hostdesc1->length = cpu_to_le16(len);
-+ } else { /* ACX100 */
-+ u8 rate_100 = clt ? clt->rate_100 : priv->rate_bcast100;
-+ txdesc->u.r1.rate = rate_100;
-+#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
-+ if (clt->pbcc511) {
-+ if (n == RATE100_5 || n == RATE100_11)
-+ n |= RATE100_PBCC511;
-+ }
-+
-+ if (clt->shortpre && (clt->cur != RATE111_1))
-+ SET_BIT(Ctl_8, DESC_CTL_SHORT_PREAMBLE); /* set Short Preamble */
-+#endif
-+ /* set autodma and reclaim and 1st mpdu */
-+ SET_BIT(Ctl_8, DESC_CTL_AUTODMA | DESC_CTL_RECLAIM | DESC_CTL_FIRSTFRAG);
-+ hostdesc1->length = cpu_to_le16(WLAN_HDR_A3_LEN);
-+ }
-+ /* don't need to clean ack/rts statistics here, already
-+ * done on descr cleanup */
-+
-+ /* clears Ctl DESC_CTL_HOSTOWN bit, thus telling that the descriptors
-+ * are now owned by the acx100; do this as LAST operation */
-+ CLEAR_BIT(Ctl_8, DESC_CTL_HOSTOWN);
-+ /* flush writes before we release hostdesc to the adapter here */
-+ wmb();
-+ CLEAR_BIT(hostdesc1->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+ CLEAR_BIT(hostdesc2->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+
-+ /* write back modified flags */
-+ txdesc->Ctl2_8 = Ctl2_8;
-+ txdesc->Ctl_8 = Ctl_8;
-+
-+ /* unused: txdesc->tx_time = cpu_to_le32(jiffies); */
-+//TODO: should it be a mmiowb() instead? we are protecting against race with write[bwl]()
-+ /* flush writes before we tell the adapter that it's its turn now */
-+ wmb();
-+ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_TXPRC);
-+ acx_write_flush(priv);
-+
-+ /* log the packet content AFTER sending it,
-+ * in order to not delay sending any further than absolutely needed
-+ * Do separate logs for acx100/111 to have human-readable rates */
-+ if (unlikely(acx_debug & (L_XFER|L_DATA))) {
-+ u16 fc = ((wlan_hdr_t*)hostdesc1->data)->fc;
-+ if (IS_ACX111(priv))
-+ printk("tx: pkt (%s): len %d "
-+ "rate %04X%s status %u\n",
-+ acx_get_packet_type_string(le16_to_cpu(fc)), len,
-+ le16_to_cpu(txdesc->u.r2.rate111),
-+ (le16_to_cpu(txdesc->u.r2.rate111) & RATE111_SHORTPRE) ? "(SPr)" : "",
-+ priv->status);
-+ else
-+ printk("tx: pkt (%s): len %d rate %03u%s status %u\n",
-+ acx_get_packet_type_string(fc), len,
-+ txdesc->u.r1.rate,
-+ (Ctl_8 & DESC_CTL_SHORT_PREAMBLE) ? "(SPr)" : "",
-+ priv->status);
-+
-+ if (acx_debug & L_DATA) {
-+ printk("tx: 802.11 [%d]: ", len);
-+ acx_dump_bytes(hostdesc1->data, len);
-+ }
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static void
-+acx_l_handle_tx_error(wlandevice_t *priv, u8 error, unsigned int finger)
-+{
-+ const char *err = "unknown error";
-+
-+ /* hmm, should we handle this as a mask
-+ * of *several* bits?
-+ * For now I think only caring about
-+ * individual bits is ok... */
-+ switch (error) {
-+ case 0x01:
-+ err = "no Tx due to error in other fragment";
-+ priv->wstats.discard.fragment++;
-+ break;
-+ case 0x02:
-+ err = "Tx aborted";
-+ priv->stats.tx_aborted_errors++;
-+ break;
-+ case 0x04:
-+ err = "Tx desc wrong parameters";
-+ priv->wstats.discard.misc++;
-+ break;
-+ case 0x08:
-+ err = "WEP key not found";
-+ priv->wstats.discard.misc++;
-+ break;
-+ case 0x10:
-+ err = "MSDU lifetime timeout? - try changing "
-+ "'iwconfig retry lifetime XXX'";
-+ priv->wstats.discard.misc++;
-+ break;
-+ case 0x20:
-+ err = "excessive Tx retries due to either distance "
-+ "too high or unable to Tx or Tx frame error - "
-+ "try changing 'iwconfig txpower XXX' or "
-+ "'sens'itivity or 'retry'";
-+ priv->wstats.discard.retries++;
-+ /* FIXME: set (GETSET_TX|GETSET_RX) here
-+ * (this seems to recalib radio on ACX100)
-+ * after some more jiffies passed??
-+ * But OTOH Tx error 0x20 also seems to occur on
-+ * overheating, so I'm not sure whether we
-+ * actually want that, since people maybe won't notice
-+ * then that their hardware is slowly getting
-+ * cooked...
-+ * Or is it still a safe long distance from utter
-+ * radio non-functionality despite many radio
-+ * recalibs
-+ * to final destructive overheating of the hardware?
-+ * In this case we really should do recalib here...
-+ * I guess the only way to find out is to do a
-+ * potentially fatal self-experiment :-\
-+ * Or maybe only recalib in case we're using Tx
-+ * rate auto (on errors switching to lower speed
-+ * --> less heat?) or 802.11 power save mode? */
-+
-+ /* ok, just do it.
-+ * ENABLE_TX|ENABLE_RX helps, so even do
-+ * DISABLE_TX and DISABLE_RX in order to perhaps
-+ * have more impact. */
-+ if (++priv->retry_errors_msg_ratelimit % 4 == 0) {
-+ if (priv->retry_errors_msg_ratelimit <= 20)
-+ printk("%s: several excessive Tx "
-+ "retry errors occurred, attempting "
-+ "to recalibrate radio. Radio "
-+ "drift might be caused by increasing "
-+ "card temperature, please check the card "
-+ "before it's too late!\n",
-+ priv->netdev->name);
-+ if (priv->retry_errors_msg_ratelimit == 20)
-+ printk("disabling above "
-+ "notification message\n");
-+
-+ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
-+ }
-+ break;
-+ case 0x40:
-+ err = "Tx buffer overflow";
-+ priv->stats.tx_fifo_errors++;
-+ break;
-+ case 0x80:
-+ err = "DMA error";
-+ priv->wstats.discard.misc++;
-+ break;
-+ }
-+ priv->stats.tx_errors++;
-+ if (priv->stats.tx_errors <= 20)
-+ printk("%s: tx error 0x%02X, buf %02u! (%s)\n",
-+ priv->netdev->name, error, finger, err);
-+ else
-+ printk("%s: tx error 0x%02X, buf %02u!\n",
-+ priv->netdev->name, error, finger);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+/* Theory of operation:
-+** client->rate_cap is a bitmask of rates client is capable of.
-+** client->rate_cfg is a bitmask of allowed (configured) rates.
-+** It is set as a result of iwconfig rate N [auto]
-+** or iwpriv set_rates "N,N,N N,N,N" commands.
-+** It can be fixed (e.g. 0x0080 == 18Mbit only),
-+** auto (0x00ff == 18Mbit or any lower value),
-+** and code handles any bitmask (0x1081 == try 54Mbit,18Mbit,1Mbit _only_).
-+**
-+** client->rate_cur is a value for rate111 field in tx descriptor.
-+** It is always set to txrate_cfg sans zero or more most significant
-+** bits. This routine handles selection of new rate_cur value depending on
-+** outcome of last tx event.
-+**
-+** client->rate_100 is a precalculated rate value for acx100
-+** (we can do without it, but will need to calculate it on each tx).
-+**
-+** You cannot configure mixed usage of 5.5 and/or 11Mbit rate
-+** with PBCC and CCK modulation. Either both at CCK or both at PBCC.
-+** In theory you can implement it, but so far it is considered not worth doing.
-+**
-+** 22Mbit, of course, is PBCC always. */
-+
-+/* maps acx100 tx descr rate field to acx111 one */
-+static u16
-+rate100to111(u8 r)
-+{
-+ switch (r) {
-+ case RATE100_1: return RATE111_1;
-+ case RATE100_2: return RATE111_2;
-+ case RATE100_5:
-+ case (RATE100_5 | RATE100_PBCC511): return RATE111_5;
-+ case RATE100_11:
-+ case (RATE100_11 | RATE100_PBCC511): return RATE111_11;
-+ case RATE100_22: return RATE111_22;
-+ default:
-+ printk("acx: unexpected acx100 txrate: %u! "
-+ "Please report\n", r);
-+ return RATE111_2;
-+ }
-+}
-+
-+
-+static void
-+acx_l_handle_txrate_auto(wlandevice_t *priv, struct client *txc,
-+ unsigned int idx, u8 rate100, u16 rate111, u8 error)
-+{
-+ u16 sent_rate;
-+ u16 cur = txc->rate_cur;
-+ int slower_rate_was_used;
-+
-+ /* FIXME: need to implement some kind of rate success memory
-+ * which stores the success percentage per rate, to be taken
-+ * into account when considering allowing a new rate, since it
-+ * doesn't really help to stupidly count fallback/stepup,
-+ * since one invalid rate will spoil the party anyway
-+ * (such as 22M in case of 11M-only peers) */
-+
-+ /* vda: hmm. current code will do this:
-+ ** 1. send packets at 11 Mbit, stepup++
-+ ** 2. will try to send at 22Mbit. hardware will see no ACK,
-+ ** retries at 11Mbit, success. code notes that used rate
-+ ** is lower. stepup = 0, fallback++
-+ ** 3. repeat step 2 fallback_count times. Fall back to
-+ ** 11Mbit. go to step 1.
-+ ** If stepup_count is large (say, 16) and fallback_count
-+ ** is small (3), this wouldn't be too bad wrt throughput */
-+
-+ /* do some preparations, i.e. calculate the one rate that was
-+ * used to send this packet */
-+ if (IS_ACX111(priv)) {
-+ sent_rate = 1 << highest_bit(rate111 & RATE111_ALL);
-+ } else {
-+ sent_rate = rate100to111(rate100);
-+ }
-+ /* sent_rate has only one bit set now, corresponding to tx rate
-+ * which was used by hardware to tx this particular packet */
-+
-+ /* now do the actual auto rate management */
-+ acxlog(L_DEBUG, "tx: %sclient=%p/"MACSTR" used=%04X cur=%04X cfg=%04X "
-+ "__=%u/%u ^^=%u/%u\n",
-+ (txc->ignore_count > 0) ? "[IGN] " : "",
-+ txc, MAC(txc->address), sent_rate, cur, txc->rate_cfg,
-+ txc->fallback_count, priv->fallback_threshold,
-+ txc->stepup_count, priv->stepup_threshold
-+ );
-+
-+ /* we need to ignore old packets already in the tx queue since
-+ * they use older rate bytes configured before our last rate change,
-+ * otherwise our mechanism will get confused by interpreting old data.
-+ * Do it here only, in order to have the logging above */
-+ if (txc->ignore_count) {
-+ txc->ignore_count--;
-+ return;
-+ }
-+
-+ /* true only if the only nonzero bit in sent_rate is
-+ ** less significant than highest nonzero bit in cur */
-+ slower_rate_was_used = ( cur > ((sent_rate<<1)-1) );
-+
-+ if (slower_rate_was_used || (error & 0x30)) {
-+ txc->stepup_count = 0;
-+ if (++txc->fallback_count <= priv->fallback_threshold)
-+ return;
-+ txc->fallback_count = 0;
-+
-+ /* clear highest 1 bit in cur */
-+ sent_rate = RATE111_54;
-+ while (!(cur & sent_rate)) sent_rate >>= 1;
-+ CLEAR_BIT(cur, sent_rate);
-+
-+ if (cur) { /* we can't disable all rates! */
-+ acxlog(L_XFER, "tx: falling back to ratemask %04X\n", cur);
-+ txc->rate_cur = cur;
-+ txc->ignore_count = TX_CNT - priv->tx_free;
-+ }
-+ } else if (!slower_rate_was_used) {
-+ txc->fallback_count = 0;
-+ if (++txc->stepup_count <= priv->stepup_threshold)
-+ return;
-+ txc->stepup_count = 0;
-+
-+ /* sanitize. Sort of not needed, but I dont trust hw that much...
-+ ** what if it can report bogus tx rates sometimes? */
-+ while (!(cur & sent_rate)) sent_rate >>= 1;
-+ /* try to find a higher sent_rate that isn't yet in our
-+ * current set, but is an allowed cfg */
-+ while (1) {
-+ sent_rate <<= 1;
-+ if (sent_rate > txc->rate_cfg)
-+ /* no higher rates allowed by config */
-+ return;
-+ if (!(cur & sent_rate) && (txc->rate_cfg & sent_rate))
-+ /* found */
-+ break;
-+ /* not found, try higher one */
-+ }
-+ SET_BIT(cur, sent_rate);
-+ acxlog(L_XFER, "tx: stepping up to ratemask %04X\n", cur);
-+ txc->rate_cur = cur;
-+ /* FIXME: totally bogus - we could be sending to many peers at once... */
-+ txc->ignore_count = TX_CNT - priv->tx_free;
-+ }
-+
-+ /* calculate acx100 style rate byte if needed */
-+ if (IS_ACX100(priv)) {
-+ txc->rate_100 = bitpos2rate100[highest_bit(cur)];
-+ }
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_log_txbuffer
-+*----------------------------------------------------------------*/
-+#if !ACX_DEBUG
-+static inline void acx_l_log_txbuffer(const wlandevice_t *priv) {}
-+#else
-+static void
-+acx_l_log_txbuffer(wlandevice_t *priv)
-+{
-+ txdesc_t *txdesc;
-+ int i;
-+
-+ /* no FN_ENTER here, we don't want that */
-+ /* no locks here, since it's entirely non-critical code */
-+ txdesc = priv->txdesc_start;
-+ if (!txdesc) return;
-+ for (i = 0; i < TX_CNT; i++) {
-+ if ((txdesc->Ctl_8 & DESC_CTL_DONE) == DESC_CTL_DONE)
-+ printk("tx: buf %d done\n", i);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+}
-+#endif
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_clean_tx_desc
-+*
-+* This function resets the txdescs' status when the ACX100
-+* signals the TX done IRQ (txdescs have been processed), starting with
-+* the pool index of the descriptor which we would use next,
-+* in order to make sure that we can be as fast as possible
-+* in filling new txdescs.
-+* Oops, now we have our own index, so everytime we get called we know
-+* where the next packet to be cleaned is.
-+* Hmm, still need to loop through the whole ring buffer now,
-+* since we lost sync for some reason when ping flooding or so...
-+* (somehow we don't get the IRQ for acx_l_clean_tx_desc any more when
-+* too many packets are being sent!)
-+* FIXME: currently we only process one packet, but this gets out of
-+* sync for some reason when ping flooding, so we need to loop,
-+* but the previous smart loop implementation causes the ping latency
-+* to rise dramatically (~3000 ms), at least on CardBus PheeNet WL-0022.
-+* Dunno what to do :-\
-+*----------------------------------------------------------------*/
-+unsigned int
-+acx_l_clean_tx_desc(wlandevice_t *priv)
-+{
-+ txdesc_t *txdesc;
-+ struct client *txc;
-+ int finger;
-+ int num_cleaned;
-+ int to_process;
-+ u16 r111;
-+ u8 error, ack_failures, rts_failures, rts_ok, r100;
-+
-+ FN_ENTER;
-+
-+ if (unlikely(acx_debug & L_DEBUG))
-+ acx_l_log_txbuffer(priv);
-+
-+ acxlog(L_BUFT, "tx: cleaning up bufs from %u\n", priv->tx_tail);
-+
-+ finger = priv->tx_tail;
-+ num_cleaned = 0;
-+ to_process = TX_CNT;
-+ do {
-+ txdesc = get_txdesc(priv, finger);
-+
-+ /* abort if txdesc is not marked as "Tx finished" and "owned" */
-+ if ((txdesc->Ctl_8 & DESC_CTL_DONE) != DESC_CTL_DONE) {
-+ /* we do need to have at least one cleaned,
-+ * otherwise we wouldn't get called in the first place
-+ */
-+ if (num_cleaned)
-+ break;
-+ }
-+
-+ /* remember descr values... */
-+ error = txdesc->error;
-+ ack_failures = txdesc->ack_failures;
-+ rts_failures = txdesc->rts_failures;
-+ rts_ok = txdesc->rts_ok;
-+ r100 = txdesc->u.r1.rate;
-+ r111 = txdesc->u.r2.rate111;
-+
-+#if WIRELESS_EXT > 13 /* wireless_send_event() and IWEVTXDROP are WE13 */
-+ /* need to check for certain error conditions before we
-+ * clean the descriptor: we still need valid descr data here */
-+ if (unlikely(0x30 & error)) {
-+ /* only send IWEVTXDROP in case of retry or lifetime exceeded;
-+ * all other errors mean we screwed up locally */
-+ union iwreq_data wrqu;
-+ wlan_hdr_t *hdr;
-+ txhostdesc_t *hostdesc;
-+
-+ hostdesc = acx_get_txhostdesc(priv, txdesc);
-+ hdr = (wlan_hdr_t *)hostdesc->data;
-+ MAC_COPY(wrqu.addr.sa_data, hdr->a1);
-+ wireless_send_event(priv->netdev, IWEVTXDROP, &wrqu, NULL);
-+ }
-+#endif
-+ /* ...and free the descr */
-+ txdesc->error = 0;
-+ txdesc->ack_failures = 0;
-+ txdesc->rts_failures = 0;
-+ txdesc->rts_ok = 0;
-+ /* signal host owning it LAST, since ACX already knows that this
-+ * descriptor is finished since it set Ctl_8 accordingly:
-+ * if _OWN is set at the beginning instead, our own get_tx
-+ * might choose a Tx desc that isn't fully cleared
-+ * (in case of bad locking). */
-+ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
-+ priv->tx_free++;
-+ num_cleaned++;
-+
-+ if ((priv->tx_free >= TX_START_QUEUE)
-+ && (priv->status == ACX_STATUS_4_ASSOCIATED)
-+ && (acx_queue_stopped(priv->netdev))
-+ ) {
-+ acxlog(L_BUF, "tx: wake queue (avail. Tx desc %u)\n",
-+ priv->tx_free);
-+ acx_wake_queue(priv->netdev, NULL);
-+ }
-+
-+ /* do error checking, rate handling and logging
-+ * AFTER having done the work, it's faster */
-+
-+ /* do rate handling */
-+ txc = acx_get_txc(priv, txdesc);
-+ if (txc && priv->rate_auto) {
-+ acx_l_handle_txrate_auto(priv, txc, finger, r100, r111, error);
-+ }
-+
-+ if (unlikely(error))
-+ acx_l_handle_tx_error(priv, error, finger);
-+
-+ if (IS_ACX111(priv))
-+ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u r111=%04X\n",
-+ finger, ack_failures, rts_failures, rts_ok, r111);
-+ else
-+ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u rate=%u\n",
-+ finger, ack_failures, rts_failures, rts_ok, r100);
-+
-+ /* update pointer for descr to be cleaned next */
-+ finger = (finger + 1) % TX_CNT;
-+ } while (--to_process);
-+
-+ /* remember last position */
-+ priv->tx_tail = finger;
-+/* end: */
-+ FN_EXIT1(num_cleaned);
-+ return num_cleaned;
-+}
-+
-+/* clean *all* Tx descriptors, and regardless of their previous state.
-+ * Used for brute-force reset handling. */
-+void
-+acx_l_clean_tx_desc_emergency(wlandevice_t *priv)
-+{
-+ txdesc_t *txdesc;
-+ unsigned int i;
-+
-+ FN_ENTER;
-+
-+ for (i = 0; i < TX_CNT; i++) {
-+ txdesc = get_txdesc(priv, i);
-+
-+ /* free it */
-+ txdesc->ack_failures = 0;
-+ txdesc->rts_failures = 0;
-+ txdesc->rts_ok = 0;
-+ txdesc->error = 0;
-+ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
-+ }
-+
-+ priv->tx_free = TX_CNT;
-+
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_l_log_rxbuffer
-+*
-+* Called from IRQ context only
-+*----------------------------------------------------------------*/
-+#if !ACX_DEBUG
-+static inline void acx_l_log_rxbuffer(const wlandevice_t *priv) {}
-+#else
-+static void
-+acx_l_log_rxbuffer(const wlandevice_t *priv)
-+{
-+ const struct rxhostdesc *rxhostdesc;
-+ int i;
-+
-+ /* no FN_ENTER here, we don't want that */
-+
-+ rxhostdesc = priv->rxhostdesc_start;
-+ if (!rxhostdesc) return;
-+ for (i = 0; i < RX_CNT; i++) {
-+ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
-+ printk("rx: buf %d full\n", i);
-+ rxhostdesc++;
-+ }
-+}
-+#endif
-+
-+
-+/***************************************************************
-+** acx_l_process_rx_desc
-+**
-+** Called directly and only from the IRQ handler
-+*/
-+void
-+acx_l_process_rx_desc(wlandevice_t *priv)
-+{
-+ rxhostdesc_t *hostdesc;
-+ /* unsigned int curr_idx; */
-+ unsigned int count = 0;
-+
-+ FN_ENTER;
-+
-+ if (unlikely(acx_debug & L_BUFR)) {
-+ acx_l_log_rxbuffer(priv);
-+ }
-+
-+ /* First, have a loop to determine the first descriptor that's
-+ * full, just in case there's a mismatch between our current
-+ * rx_tail and the full descriptor we're supposed to handle. */
-+ while (1) {
-+ /* curr_idx = priv->rx_tail; */
-+ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
-+ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
-+ if ((hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && (hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) {
-+ /* found it! */
-+ break;
-+ }
-+ count++;
-+ if (unlikely(count > RX_CNT)) {
-+ /* hmm, no luck: all descriptors empty, bail out */
-+ goto end;
-+ }
-+ }
-+
-+ /* now process descriptors, starting with the first we figured out */
-+ while (1) {
-+ acxlog(L_BUFR, "rx: tail=%u Ctl_16=%04X Status=%08X\n",
-+ priv->rx_tail, hostdesc->Ctl_16, hostdesc->Status);
-+
-+ acx_l_process_rxbuf(priv, hostdesc->data);
-+
-+ hostdesc->Status = 0;
-+ /* flush all writes before adapter sees CTL_HOSTOWN change */
-+ wmb();
-+ /* Host no longer owns this, needs to be LAST */
-+ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+
-+ /* ok, descriptor is handled, now check the next descriptor */
-+ /* curr_idx = priv->rx_tail; */
-+ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
-+
-+ /* if next descriptor is empty, then bail out */
-+ /* FIXME: is this check really entirely correct?? */
-+ /*
-+//FIXME: inconsistent with check in prev while() loop
-+ if (!(hostdesc->Ctl & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && !(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) */
-+ if (!(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
-+ break;
-+
-+ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_s_create_tx_host_desc_queue
-+*----------------------------------------------------------------*/
-+static inline void*
-+acx_alloc_coherent(struct pci_dev *hwdev, size_t size,
-+ dma_addr_t *dma_handle, int flag)
-+{
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 53)
-+ return dma_alloc_coherent(hwdev == NULL ? NULL : &hwdev->dev,
-+ size, dma_handle, flag);
-+#else
-+#warning Using old PCI-specific DMA allocation, may fail with out-of-mem!
-+#warning Upgrade kernel if it does...
-+ return pci_alloc_consistent(hwdev, size, dma_handle);
-+#endif
-+}
-+
-+static void*
-+allocate(wlandevice_t *priv, size_t size, dma_addr_t *phy, const char *msg)
-+{
-+ void *ptr = acx_alloc_coherent(priv->pdev, size, phy, GFP_KERNEL);
-+ if (ptr) {
-+ acxlog(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n",
-+ msg, (int)size, ptr, (unsigned long long)*phy);
-+ memset(ptr, 0, size);
-+ return ptr;
-+ }
-+ printk(KERN_ERR "acx: %s allocation FAILED (%d bytes)\n",
-+ msg, (int)size);
-+ return NULL;
-+}
-+
-+static int
-+acx_s_create_tx_host_desc_queue(wlandevice_t *priv)
-+{
-+ txhostdesc_t *hostdesc;
-+ u8 *txbuf;
-+ dma_addr_t hostdesc_phy;
-+ dma_addr_t txbuf_phy;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* allocate TX buffer */
-+ priv->txbuf_area_size = TX_CNT * WLAN_A4FR_MAXLEN_WEP_FCS;
-+ priv->txbuf_start = allocate(priv, priv->txbuf_area_size,
-+ &priv->txbuf_startphy, "txbuf_start");
-+ if (!priv->txbuf_start)
-+ goto fail;
-+
-+ /* allocate the TX host descriptor queue pool */
-+ priv->txhostdesc_area_size = TX_CNT * 2*sizeof(txhostdesc_t);
-+ priv->txhostdesc_start = allocate(priv, priv->txhostdesc_area_size,
-+ &priv->txhostdesc_startphy, "txhostdesc_start");
-+ if (!priv->txhostdesc_start)
-+ goto fail;
-+ /* check for proper alignment of TX host descriptor pool */
-+ if ((long) priv->txhostdesc_start & 3) {
-+ printk("acx: driver bug: dma alloc returns unaligned address\n");
-+ goto fail;
-+ }
-+
-+/* Each tx frame buffer is accessed by hardware via
-+** txdesc -> txhostdesc(s) -> framebuffer(s)
-+** We use only one txhostdesc per txdesc, but it looks like
-+** acx111 is buggy: it accesses second txhostdesc
-+** (via hostdesc.desc_phy_next field) even if
-+** txdesc->length == hostdesc->length and thus
-+** entire packet was placed into first txhostdesc.
-+** Due to this bug acx111 hangs unless second txhostdesc
-+** has hostdesc.length = 3 (or larger)
-+** Storing NULL into hostdesc.desc_phy_next
-+** doesn't seem to help.
-+*/
-+/* It is not known whether we need to have 'extra' second
-+** txhostdescs for acx100. Maybe it is acx111-only bug.
-+*/
-+ hostdesc = priv->txhostdesc_start;
-+ hostdesc_phy = priv->txhostdesc_startphy;
-+ txbuf = priv->txbuf_start;
-+ txbuf_phy = priv->txbuf_startphy;
-+
-+#if 0
-+/* Works for xterasys xn2522g, does not for WG311v2 !!? */
-+ for (i = 0; i < TX_CNT*2; i++) {
-+ hostdesc_phy += sizeof(txhostdesc_t);
-+ if (!(i & 1)) {
-+ hostdesc->data_phy = cpu2acx(txbuf_phy);
-+ /* hostdesc->data_offset = ... */
-+ /* hostdesc->reserved = ... */
-+ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
-+ /* hostdesc->length = ... */
-+ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
-+ hostdesc->pNext = ptr2acx(NULL);
-+ /* hostdesc->Status = ... */
-+ /* below: non-hardware fields */
-+ hostdesc->data = txbuf;
-+
-+ txbuf += WLAN_A4FR_MAXLEN_WEP_FCS;
-+ txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS;
-+ } else {
-+ /* hostdesc->data_phy = ... */
-+ /* hostdesc->data_offset = ... */
-+ /* hostdesc->reserved = ... */
-+ /* hostdesc->Ctl_16 = ... */
-+ hostdesc->length = 3; /* bug workaround */
-+ /* hostdesc->desc_phy_next = ... */
-+ /* hostdesc->pNext = ... */
-+ /* hostdesc->Status = ... */
-+ /* below: non-hardware fields */
-+ /* hostdesc->data = ... */
-+ }
-+ hostdesc++;
-+ }
-+#endif
-+ for (i = 0; i < TX_CNT*2; i++) {
-+ hostdesc_phy += sizeof(txhostdesc_t);
-+ if (!(i & 1)) {
-+ hostdesc->data_phy = cpu2acx(txbuf_phy);
-+ /* done by memset(0): hostdesc->data_offset = 0; */
-+ /* hostdesc->reserved = ... */
-+ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
-+ /* hostdesc->length = ... */
-+ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
-+ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
-+ /* hostdesc->Status = ... */
-+ /* below: non-hardware fields */
-+ hostdesc->data = txbuf;
-+
-+ txbuf += WLAN_HDR_A3_LEN;
-+ txbuf_phy += WLAN_HDR_A3_LEN;
-+ } else {
-+ hostdesc->data_phy = cpu2acx(txbuf_phy);
-+ /* done by memset(0): hostdesc->data_offset = 0; */
-+ /* hostdesc->reserved = ... */
-+ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
-+ /* hostdesc->length = ...; */
-+ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
-+ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
-+ /* hostdesc->Status = ... */
-+ /* below: non-hardware fields */
-+ hostdesc->data = txbuf;
-+
-+ txbuf += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
-+ txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
-+ }
-+ hostdesc++;
-+ }
-+ hostdesc--;
-+ hostdesc->desc_phy_next = cpu2acx(priv->txhostdesc_startphy);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+fail:
-+ printk("acx: create_tx_host_desc_queue FAILED\n");
-+ /* dealloc will be done by free function on error case */
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/***************************************************************
-+** acx_s_create_rx_host_desc_queue
-+*/
-+/* the whole size of a data buffer (header plus data body)
-+ * plus 32 bytes safety offset at the end */
-+#define RX_BUFFER_SIZE (sizeof(rxbuffer_t) + 32)
-+
-+static int
-+acx_s_create_rx_host_desc_queue(wlandevice_t *priv)
-+{
-+ rxhostdesc_t *hostdesc;
-+ rxbuffer_t *rxbuf;
-+ dma_addr_t hostdesc_phy;
-+ dma_addr_t rxbuf_phy;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* allocate the RX host descriptor queue pool */
-+ priv->rxhostdesc_area_size = RX_CNT * sizeof(rxhostdesc_t);
-+ priv->rxhostdesc_start = allocate(priv, priv->rxhostdesc_area_size,
-+ &priv->rxhostdesc_startphy, "rxhostdesc_start");
-+ if (!priv->rxhostdesc_start)
-+ goto fail;
-+ /* check for proper alignment of RX host descriptor pool */
-+ if ((long) priv->rxhostdesc_start & 3) {
-+ printk("acx: driver bug: dma alloc returns unaligned address\n");
-+ goto fail;
-+ }
-+
-+ /* allocate Rx buffer pool which will be used by the acx
-+ * to store the whole content of the received frames in it */
-+ priv->rxbuf_area_size = RX_CNT * RX_BUFFER_SIZE;
-+ priv->rxbuf_start = allocate(priv, priv->rxbuf_area_size,
-+ &priv->rxbuf_startphy, "rxbuf_start");
-+ if (!priv->rxbuf_start)
-+ goto fail;
-+
-+ rxbuf = priv->rxbuf_start;
-+ rxbuf_phy = priv->rxbuf_startphy;
-+ hostdesc = priv->rxhostdesc_start;
-+ hostdesc_phy = priv->rxhostdesc_startphy;
-+
-+ /* don't make any popular C programming pointer arithmetic mistakes
-+ * here, otherwise I'll kill you...
-+ * (and don't dare asking me why I'm warning you about that...) */
-+ for (i = 0; i < RX_CNT; i++) {
-+ hostdesc->data = rxbuf;
-+ hostdesc->data_phy = cpu2acx(rxbuf_phy);
-+ hostdesc->length = cpu_to_le16(RX_BUFFER_SIZE);
-+ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
-+ rxbuf++;
-+ rxbuf_phy += sizeof(rxbuffer_t);
-+ hostdesc_phy += sizeof(rxhostdesc_t);
-+ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
-+ hostdesc++;
-+ }
-+ hostdesc--;
-+ hostdesc->desc_phy_next = cpu2acx(priv->rxhostdesc_startphy);
-+ FN_EXIT1(OK);
-+ return OK;
-+fail:
-+ printk("acx: create_rx_host_desc_queue FAILED\n");
-+ /* dealloc will be done by free function on error case */
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/***************************************************************
-+** acx_s_create_hostdesc_queues
-+*/
-+int
-+acx_s_create_hostdesc_queues(wlandevice_t *priv)
-+{
-+ int result;
-+ result = acx_s_create_tx_host_desc_queue(priv);
-+ if (OK != result) return result;
-+ result = acx_s_create_rx_host_desc_queue(priv);
-+ return result;
-+}
-+
-+
-+/***************************************************************
-+** acx_create_tx_desc_queue
-+*/
-+static void
-+acx_create_tx_desc_queue(wlandevice_t *priv, u32 tx_queue_start)
-+{
-+ txdesc_t *txdesc;
-+ txhostdesc_t *hostdesc;
-+ dma_addr_t hostmemptr;
-+ u32 mem_offs;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ priv->txdesc_size = sizeof(txdesc_t);
-+
-+ if (IS_ACX111(priv)) {
-+ /* the acx111 txdesc is 4 bytes larger */
-+ priv->txdesc_size = sizeof(txdesc_t) + 4;
-+ }
-+
-+ priv->txdesc_start = (txdesc_t *) (priv->iobase2 + tx_queue_start);
-+
-+ acxlog(L_DEBUG, "priv->iobase2=%p\n"
-+ "tx_queue_start=%08X\n"
-+ "priv->txdesc_start=%p\n",
-+ priv->iobase2,
-+ tx_queue_start,
-+ priv->txdesc_start);
-+
-+ priv->tx_free = TX_CNT;
-+ /* done by memset: priv->tx_head = 0; */
-+ /* done by memset: priv->tx_tail = 0; */
-+ txdesc = priv->txdesc_start;
-+ mem_offs = tx_queue_start;
-+ hostmemptr = priv->txhostdesc_startphy;
-+ hostdesc = priv->txhostdesc_start;
-+
-+ if (IS_ACX111(priv)) {
-+ /* ACX111 has a preinitialized Tx buffer! */
-+ /* loop over whole send pool */
-+ /* FIXME: do we have to do the hostmemptr stuff here?? */
-+ for (i = 0; i < TX_CNT; i++) {
-+ txdesc->HostMemPtr = ptr2acx(hostmemptr);
-+ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
-+ /* reserve two (hdr desc and payload desc) */
-+ hostdesc += 2;
-+ hostmemptr += 2 * sizeof(txhostdesc_t);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+ } else {
-+ /* ACX100 Tx buffer needs to be initialized by us */
-+ /* clear whole send pool. sizeof is safe here (we are acx100) */
-+ memset(priv->txdesc_start, 0, TX_CNT * sizeof(txdesc_t));
-+
-+ /* loop over whole send pool */
-+ for (i = 0; i < TX_CNT; i++) {
-+ acxlog(L_DEBUG, "configure card tx descriptor: 0x%p, "
-+ "size: 0x%X\n", txdesc, priv->txdesc_size);
-+
-+ /* pointer to hostdesc memory */
-+ /* FIXME: type-incorrect assignment, might cause trouble
-+ * in some cases */
-+ txdesc->HostMemPtr = ptr2acx(hostmemptr);
-+ /* initialise ctl */
-+ txdesc->Ctl_8 = DESC_CTL_INIT;
-+ txdesc->Ctl2_8 = 0;
-+ /* point to next txdesc */
-+ txdesc->pNextDesc = cpu2acx(mem_offs + priv->txdesc_size);
-+ /* reserve two (hdr desc and payload desc) */
-+ hostdesc += 2;
-+ hostmemptr += 2 * sizeof(txhostdesc_t);
-+ /* go to the next one */
-+ mem_offs += priv->txdesc_size;
-+ /* ++ is safe here (we are acx100) */
-+ txdesc++;
-+ }
-+ /* go back to the last one */
-+ txdesc--;
-+ /* and point to the first making it a ring buffer */
-+ txdesc->pNextDesc = cpu2acx(tx_queue_start);
-+ }
-+ FN_EXIT0;
-+}
-+
-+
-+/***************************************************************
-+** acx_create_rx_desc_queue
-+*/
-+static void
-+acx_create_rx_desc_queue(wlandevice_t *priv, u32 rx_queue_start)
-+{
-+ rxdesc_t *rxdesc;
-+ u32 mem_offs;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* done by memset: priv->rx_tail = 0; */
-+
-+ /* ACX111 doesn't need any further config: preconfigures itself.
-+ * Simply print ring buffer for debugging */
-+ if (IS_ACX111(priv)) {
-+ /* rxdesc_start already set here */
-+
-+ priv->rxdesc_start = (rxdesc_t *) ((u8 *)priv->iobase2 + rx_queue_start);
-+
-+ rxdesc = priv->rxdesc_start;
-+ for (i = 0; i < RX_CNT; i++) {
-+ acxlog(L_DEBUG, "rx descriptor %d @ 0x%p\n", i, rxdesc);
-+ rxdesc = priv->rxdesc_start = (rxdesc_t *)
-+ (priv->iobase2 + acx2cpu(rxdesc->pNextDesc));
-+ }
-+ } else {
-+ /* we didn't pre-calculate rxdesc_start in case of ACX100 */
-+ /* rxdesc_start should be right AFTER Tx pool */
-+ priv->rxdesc_start = (rxdesc_t *)
-+ ((u8 *) priv->txdesc_start + (TX_CNT * sizeof(txdesc_t)));
-+ /* NB: sizeof(txdesc_t) above is valid because we know
-+ ** we are in if(acx100) block. Beware of cut-n-pasting elsewhere!
-+ ** acx111's txdesc is larger! */
-+
-+ memset(priv->rxdesc_start, 0, RX_CNT * sizeof(rxdesc_t));
-+
-+ /* loop over whole receive pool */
-+ rxdesc = priv->rxdesc_start;
-+ mem_offs = rx_queue_start;
-+ for (i = 0; i < RX_CNT; i++) {
-+ acxlog(L_DEBUG, "rx descriptor @ 0x%p\n", rxdesc);
-+ rxdesc->Ctl_8 = DESC_CTL_RECLAIM | DESC_CTL_AUTODMA;
-+ /* point to next rxdesc */
-+ rxdesc->pNextDesc = cpu2acx(mem_offs + sizeof(rxdesc_t));
-+ /* go to the next one */
-+ mem_offs += sizeof(rxdesc_t);
-+ rxdesc++;
-+ }
-+ /* go to the last one */
-+ rxdesc--;
-+
-+ /* and point to the first making it a ring buffer */
-+ rxdesc->pNextDesc = cpu2acx(rx_queue_start);
-+ }
-+ FN_EXIT0;
-+}
-+
-+
-+/***************************************************************
-+** acx_create_desc_queues
-+*/
-+void
-+acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start)
-+{
-+ acx_create_tx_desc_queue(priv, tx_queue_start);
-+ acx_create_rx_desc_queue(priv, rx_queue_start);
-+}
-+
-+
-+/***************************************************************
-+** acxpci_s_proc_diag_output
-+*/
-+char*
-+acxpci_s_proc_diag_output(char *p, wlandevice_t *priv)
-+{
-+ const char *rtl, *thd, *ttl;
-+ rxhostdesc_t *rxhostdesc;
-+ txdesc_t *txdesc;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ p += sprintf(p, "** Rx buf **\n");
-+ rxhostdesc = priv->rxhostdesc_start;
-+ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
-+ rtl = (i == priv->rx_tail) ? " [tail]" : "";
-+ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
-+ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)) )
-+ p += sprintf(p, "%02u FULL%s\n", i, rtl);
-+ else
-+ p += sprintf(p, "%02u empty%s\n", i, rtl);
-+ rxhostdesc++;
-+ }
-+ p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", priv->tx_free,
-+ acx_queue_stopped(priv->netdev) ? "STOPPED" : "running");
-+ txdesc = priv->txdesc_start;
-+ if (txdesc) for (i = 0; i < TX_CNT; i++) {
-+ thd = (i == priv->tx_head) ? " [head]" : "";
-+ ttl = (i == priv->tx_tail) ? " [tail]" : "";
-+ if (txdesc->Ctl_8 & DESC_CTL_ACXDONE)
-+ p += sprintf(p, "%02u DONE (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
-+ else
-+ if (!(txdesc->Ctl_8 & DESC_CTL_HOSTOWN))
-+ p += sprintf(p, "%02u TxWait (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
-+ else
-+ p += sprintf(p, "%02u empty (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
-+ txdesc = move_txdesc(priv, txdesc, 1);
-+ }
-+ p += sprintf(p,
-+ "\n"
-+ "** PCI data **\n"
-+ "txbuf_start %p, txbuf_area_size %u, txbuf_startphy %08llx\n"
-+ "txdesc_size %u, txdesc_start %p\n"
-+ "txhostdesc_start %p, txhostdesc_area_size %u, txhostdesc_startphy %08llx\n"
-+ "rxdesc_start %p\n"
-+ "rxhostdesc_start %p, rxhostdesc_area_size %u, rxhostdesc_startphy %08llx\n"
-+ "rxbuf_start %p, rxbuf_area_size %u, rxbuf_startphy %08llx\n",
-+ priv->txbuf_start, priv->txbuf_area_size, (u64)priv->txbuf_startphy,
-+ priv->txdesc_size, priv->txdesc_start,
-+ priv->txhostdesc_start, priv->txhostdesc_area_size, (u64)priv->txhostdesc_startphy,
-+ priv->rxdesc_start,
-+ priv->rxhostdesc_start, priv->rxhostdesc_area_size, (u64)priv->rxhostdesc_startphy,
-+ priv->rxbuf_start, priv->rxbuf_area_size, (u64)priv->rxbuf_startphy);
-+
-+ FN_EXIT0;
-+ return p;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acx_proc_eeprom_output(char *buf, wlandevice_t *priv)
-+{
-+ char *p = buf;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ for (i = 0; i < 0x400; i++) {
-+ acx_read_eeprom_offset(priv, i, p++);
-+ }
-+
-+ FN_EXIT1(p - buf);
-+ return p - buf;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+void
-+acx_set_interrupt_mask(wlandevice_t *priv)
-+{
-+ if (IS_ACX111(priv)) {
-+ priv->irq_mask = (u16) ~(0
-+ /* | HOST_INT_RX_DATA */
-+ | HOST_INT_TX_COMPLETE
-+ /* | HOST_INT_TX_XFER */
-+ | HOST_INT_RX_COMPLETE
-+ /* | HOST_INT_DTIM */
-+ /* | HOST_INT_BEACON */
-+ /* | HOST_INT_TIMER */
-+ /* | HOST_INT_KEY_NOT_FOUND */
-+ | HOST_INT_IV_ICV_FAILURE
-+ | HOST_INT_CMD_COMPLETE
-+ | HOST_INT_INFO
-+ /* | HOST_INT_OVERFLOW */
-+ /* | HOST_INT_PROCESS_ERROR */
-+ | HOST_INT_SCAN_COMPLETE
-+ | HOST_INT_FCS_THRESHOLD
-+ /* | HOST_INT_UNKNOWN */
-+ );
-+ priv->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */
-+ } else {
-+ priv->irq_mask = (u16) ~(0
-+ /* | HOST_INT_RX_DATA */
-+ | HOST_INT_TX_COMPLETE
-+ /* | HOST_INT_TX_XFER */
-+ | HOST_INT_RX_COMPLETE
-+ /* | HOST_INT_DTIM */
-+ /* | HOST_INT_BEACON */
-+ /* | HOST_INT_TIMER */
-+ /* | HOST_INT_KEY_NOT_FOUND */
-+ /* | HOST_INT_IV_ICV_FAILURE */
-+ | HOST_INT_CMD_COMPLETE
-+ | HOST_INT_INFO
-+ /* | HOST_INT_OVERFLOW */
-+ /* | HOST_INT_PROCESS_ERROR */
-+ | HOST_INT_SCAN_COMPLETE
-+ /* | HOST_INT_FCS_THRESHOLD */
-+ /* | HOST_INT_UNKNOWN */
-+ );
-+ priv->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */
-+ }
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
-+{
-+ /* since it can be assumed that at least the Maxim radio has a
-+ * maximum power output of 20dBm and since it also can be
-+ * assumed that these values drive the DAC responsible for
-+ * setting the linear Tx level, I'd guess that these values
-+ * should be the corresponding linear values for a dBm value,
-+ * in other words: calculate the values from that formula:
-+ * Y [dBm] = 10 * log (X [mW])
-+ * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
-+ * and you're done...
-+ * Hopefully that's ok, but you never know if we're actually
-+ * right... (especially since Windows XP doesn't seem to show
-+ * actual Tx dBm values :-P) */
-+
-+ /* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the
-+ * values are EXACTLY mW!!! Not sure about RFMD and others,
-+ * though... */
-+ static const u8 dbm2val_maxim[21] = {
-+ 63, 63, 63, 62,
-+ 61, 61, 60, 60,
-+ 59, 58, 57, 55,
-+ 53, 50, 47, 43,
-+ 38, 31, 23, 13,
-+ 0
-+ };
-+ static const u8 dbm2val_rfmd[21] = {
-+ 0, 0, 0, 1,
-+ 2, 2, 3, 3,
-+ 4, 5, 6, 8,
-+ 10, 13, 16, 20,
-+ 25, 32, 41, 50,
-+ 63
-+ };
-+ const u8 *table;
-+
-+ switch (priv->radio_type) {
-+ case RADIO_MAXIM_0D:
-+ table = &dbm2val_maxim[0];
-+ break;
-+ case RADIO_RFMD_11:
-+ case RADIO_RALINK_15:
-+ table = &dbm2val_rfmd[0];
-+ break;
-+ default:
-+ printk("%s: unknown/unsupported radio type, "
-+ "cannot modify tx power level yet!\n",
-+ priv->netdev->name);
-+ return NOT_OK;
-+ }
-+ printk("%s: changing radio power level to %u dBm (%u)\n",
-+ priv->netdev->name, level_dbm, table[level_dbm]);
-+ acxpci_s_write_phy_reg(priv, 0x11, table[level_dbm]);
-+ return OK;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_init_module
-+*
-+* Module initialization routine, called once at module load time.
-+*
-+* Returns:
-+* 0 - success
-+* ~0 - failure, module is unloaded.
-+*
-+* Call context:
-+* process thread (insmod or modprobe)
-+----------------------------------------------------------------*/
-+int __init
-+acxpci_e_init_module(void)
-+{
-+ int res;
-+
-+ FN_ENTER;
-+
-+#if (ACX_IO_WIDTH==32)
-+ printk("acx: compiled to use 32bit I/O access. "
-+ "I/O timing issues might occur, such as "
-+ "non-working firmware upload. Report them\n");
-+#else
-+ printk("acx: compiled to use 16bit I/O access only "
-+ "(compatibility mode)\n");
-+#endif
-+
-+#ifdef __LITTLE_ENDIAN
-+ acxlog(L_INIT, "running on a little-endian CPU\n");
-+#else
-+ acxlog(L_INIT, "running on a BIG-ENDIAN CPU\n");
-+#endif
-+ acxlog(L_INIT, "PCI module " WLAN_RELEASE " initialized, "
-+ "waiting for cards to probe...\n");
-+
-+ res = pci_module_init(&acx_pci_drv_id);
-+ FN_EXIT1(res);
-+ return res;
-+}
-+
-+
-+/*----------------------------------------------------------------
-+* acx_e_cleanup_module
-+*
-+* Called at module unload time. This is our last chance to
-+* clean up after ourselves.
-+*
-+* Call context:
-+* process thread
-+----------------------------------------------------------------*/
-+void __exit
-+acxpci_e_cleanup_module(void)
-+{
-+ struct net_device *dev;
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ /* Since the whole module is about to be unloaded,
-+ * we recursively shutdown all cards we handled instead
-+ * of doing it in remove_pci() (which will be activated by us
-+ * via pci_unregister_driver at the end).
-+ * remove_pci() might just get called after a card eject,
-+ * that's why hardware operations have to be done here instead
-+ * when the hardware is available. */
-+
-+ down(&root_acx_dev_sem);
-+
-+ dev = root_acx_dev.newest;
-+ while (dev != NULL) {
-+ /* doh, netdev_priv() doesn't have const! */
-+ wlandevice_t *priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ /* disable both Tx and Rx to shut radio down properly */
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0);
-+
-+#ifdef REDUNDANT
-+ /* put the eCPU to sleep to save power
-+ * Halting is not possible currently,
-+ * since not supported by all firmware versions */
-+ acx_s_issue_cmd(priv, ACX100_CMD_SLEEP, NULL, 0);
-+#endif
-+ acx_lock(priv, flags);
-+
-+ /* disable power LED to save power :-) */
-+ acxlog(L_INIT, "switching off power LED to save power :-)\n");
-+ acx_l_power_led(priv, 0);
-+
-+ /* stop our eCPU */
-+ if (IS_ACX111(priv)) {
-+ /* FIXME: does this actually keep halting the eCPU?
-+ * I don't think so...
-+ */
-+ acx_l_reset_mac(priv);
-+ } else {
-+ u16 temp;
-+
-+ /* halt eCPU */
-+ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
-+ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
-+ acx_write_flush(priv);
-+ }
-+
-+ acx_unlock(priv, flags);
-+
-+ acx_sem_unlock(priv);
-+
-+ dev = priv->prev_nd;
-+ }
-+
-+ up(&root_acx_dev_sem);
-+
-+ /* now let the PCI layer recursively remove
-+ * all PCI related things (acx_e_remove_pci()) */
-+ pci_unregister_driver(&acx_pci_drv_id);
-+
-+ FN_EXIT0;
-+}
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/setrate.c bt_kernel/drivers/net/wireless/tiacx/setrate.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/setrate.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/setrate.c 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,213 @@
-+/* TODO: stop #including, move into wireless.c
-+ * until then, keep in sync copies in prism54/ and acx/ dirs
-+ * code+data size: less than 1k */
-+
-+enum {
-+ DOT11_RATE_1,
-+ DOT11_RATE_2,
-+ DOT11_RATE_5,
-+ DOT11_RATE_11,
-+ DOT11_RATE_22,
-+ DOT11_RATE_33,
-+ DOT11_RATE_6,
-+ DOT11_RATE_9,
-+ DOT11_RATE_12,
-+ DOT11_RATE_18,
-+ DOT11_RATE_24,
-+ DOT11_RATE_36,
-+ DOT11_RATE_48,
-+ DOT11_RATE_54
-+};
-+enum {
-+ DOT11_MOD_DBPSK,
-+ DOT11_MOD_DQPSK,
-+ DOT11_MOD_CCK,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_CCKOFDM,
-+ DOT11_MOD_PBCC
-+};
-+static const u8 ratelist[] = { 1,2,5,11,22,33,6,9,12,18,24,36,48,54 };
-+static const u8 dot11ratebyte[] = { 1*2,2*2,11,11*2,22*2,33*2,6*2,9*2,12*2,18*2,24*2,36*2,48*2,54*2 };
-+static const u8 default_modulation[] = {
-+ DOT11_MOD_DBPSK,
-+ DOT11_MOD_DQPSK,
-+ DOT11_MOD_CCK,
-+ DOT11_MOD_CCK,
-+ DOT11_MOD_PBCC,
-+ DOT11_MOD_PBCC,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_OFDM,
-+ DOT11_MOD_OFDM
-+};
-+
-+static /* TODO: remove 'static' when moved to wireless.c */
-+int
-+rate_mbit2enum(int n) {
-+ int i=0;
-+ while(i<sizeof(ratelist)) {
-+ if(n==ratelist[i]) return i;
-+ i++;
-+ }
-+ return -EINVAL;
-+}
-+
-+static int
-+get_modulation(int r_enum, char suffix) {
-+ if(suffix==',' || suffix==' ' || suffix=='\0') {
-+ /* could shorten default_mod by 8 bytes:
-+ if(r_enum>=DOT11_RATE_6) return DOT11_MOD_OFDM; */
-+ return default_modulation[r_enum];
-+ }
-+ if(suffix=='c') {
-+ if(r_enum<DOT11_RATE_5 || r_enum>DOT11_RATE_11) return -EINVAL;
-+ return DOT11_MOD_CCK;
-+ }
-+ if(suffix=='p') {
-+ if(r_enum<DOT11_RATE_5 || r_enum>DOT11_RATE_33) return -EINVAL;
-+ return DOT11_MOD_PBCC;
-+ }
-+ if(suffix=='o') {
-+ if(r_enum<DOT11_RATE_6) return -EINVAL;
-+ return DOT11_MOD_OFDM;
-+ }
-+ if(suffix=='d') {
-+ if(r_enum<DOT11_RATE_6) return -EINVAL;
-+ return DOT11_MOD_CCKOFDM;
-+ }
-+ return -EINVAL;
-+}
-+
-+#ifdef UNUSED
-+static int
-+fill_ratevector(const char **pstr, u8 *vector, int size,
-+ int (*supported)(int mbit, int mod, void *opaque), void *opaque, int or_mask)
-+{
-+ unsigned long rate_mbit;
-+ int rate_enum,mod;
-+ const char *str = *pstr;
-+ char c;
-+
-+ do {
-+ rate_mbit = simple_strtoul(str, (char**)&str, 10);
-+ if(rate_mbit>INT_MAX) return -EINVAL;
-+
-+ rate_enum = rate_mbit2enum(rate_mbit);
-+ if(rate_enum<0) return rate_enum;
-+
-+ c = *str;
-+ mod = get_modulation(rate_enum, c);
-+ if(mod<0) return mod;
-+
-+ if(c>='a' && c<='z') c = *++str;
-+ if(c!=',' && c!=' ' && c!='\0') return -EINVAL;
-+
-+ if(supported) {
-+ int r = supported(rate_mbit, mod, opaque);
-+ if(r) return r;
-+ }
-+
-+ *vector++ = dot11ratebyte[rate_enum] | or_mask;
-+
-+ size--;
-+ str++;
-+ } while(size>0 && c==',');
-+
-+ if(size<1) return -E2BIG;
-+ *vector=0; /* TODO: sort, remove dups? */
-+
-+ *pstr = str-1;
-+ return 0;
-+}
-+
-+static /* TODO: remove 'static' when moved to wireless.c */
-+int
-+fill_ratevectors(const char *str, u8 *brate, u8 *orate, int size,
-+ int (*supported)(int mbit, int mod, void *opaque), void *opaque)
-+{
-+ int r;
-+
-+ r = fill_ratevector(&str, brate, size, supported, opaque, 0x80);
-+ if(r) return r;
-+
-+ orate[0] = 0;
-+ if(*str==' ') {
-+ str++;
-+ r = fill_ratevector(&str, orate, size, supported, opaque, 0);
-+ if(r) return r;
-+ /* TODO: sanitize, e.g. remove/error on rates already in basic rate set? */
-+ }
-+ if(*str)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+#endif
-+
-+/* TODO: use u64 masks? */
-+
-+static int
-+fill_ratemask(const char **pstr, u32* mask,
-+ int (*supported)(int mbit, int mod,void *opaque),
-+ u32 (*gen_mask)(int mbit, int mod,void *opaque),
-+ void *opaque)
-+{
-+ unsigned long rate_mbit;
-+ int rate_enum,mod;
-+ u32 m = 0;
-+ const char *str = *pstr;
-+ char c;
-+
-+ do {
-+ rate_mbit = simple_strtoul(str, (char**)&str, 10);
-+ if(rate_mbit>INT_MAX) return -EINVAL;
-+
-+ rate_enum = rate_mbit2enum(rate_mbit);
-+ if(rate_enum<0) return rate_enum;
-+
-+ c = *str;
-+ mod = get_modulation(rate_enum, c);
-+ if(mod<0) return mod;
-+
-+ if(c>='a' && c<='z') c = *++str;
-+ if(c!=',' && c!=' ' && c!='\0') return -EINVAL;
-+
-+ if(supported) {
-+ int r = supported(rate_mbit, mod, opaque);
-+ if(r) return r;
-+ }
-+
-+ m |= gen_mask(rate_mbit, mod, opaque);
-+ str++;
-+ } while(c==',');
-+
-+ *pstr = str-1;
-+ *mask |= m;
-+ return 0;
-+}
-+
-+static /* TODO: remove 'static' when moved to wireless.c */
-+int
-+fill_ratemasks(const char *str, u32 *bmask, u32 *omask,
-+ int (*supported)(int mbit, int mod,void *opaque),
-+ u32 (*gen_mask)(int mbit, int mod,void *opaque),
-+ void *opaque)
-+{
-+ int r;
-+
-+ r = fill_ratemask(&str, bmask, supported, gen_mask, opaque);
-+ if(r) return r;
-+
-+ if(*str==' ') {
-+ str++;
-+ r = fill_ratemask(&str, omask, supported, gen_mask, opaque);
-+ if(r) return r;
-+ }
-+ if(*str)
-+ return -EINVAL;
-+ return 0;
-+}
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/usb.c bt_kernel/drivers/net/wireless/tiacx/usb.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/usb.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/usb.c 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,1700 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+/***********************************************************************
-+** USB support for TI ACX100 based devices. Many parts are taken from
-+** the PCI driver.
-+**
-+** Authors:
-+** Martin Wawro <martin.wawro AT uni-dortmund.de>
-+** Andreas Mohr <andi AT lisas.de>
-+**
-+** Issues:
-+** - Note that this driver relies on a native little-endian byteformat
-+** at some points
-+**
-+** LOCKING
-+** callback functions called by USB core are running in interrupt context
-+** and thus have names with _i_.
-+*/
-+#define ACX_USB 1
-+
-+#include <linux/version.h>
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-+#include <linux/moduleparam.h>
-+#endif
-+#include <linux/kernel.h>
-+#include <linux/usb.h>
-+#include <linux/netdevice.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/etherdevice.h>
-+#include <linux/wireless.h>
-+#if WIRELESS_EXT >= 13
-+#include <net/iw_handler.h>
-+#endif
-+
-+#include "acx.h"
-+
-+/* number of endpoints of an interface */
-+#define NUM_EP(intf) (intf)->altsetting[0].desc.bNumEndpoints
-+#define EP(intf, nr) (intf)->altsetting[0].endpoint[(nr)].desc
-+#define GET_DEV(udev) usb_get_dev((udev))
-+#define PUT_DEV(udev) usb_put_dev((udev))
-+#define SET_NETDEV_OWNER(ndev, owner) /* not needed anymore ??? */
-+
-+#define QUEUE_BULK 0
-+#define ZERO_PACKET URB_ZERO_PACKET
-+
-+static inline int
-+submit_urb(struct urb *urb, int mem_flags)
-+{
-+ return usb_submit_urb(urb, mem_flags);
-+}
-+static inline struct urb*
-+alloc_urb(int iso_pk, int mem_flags)
-+{
-+ return usb_alloc_urb(iso_pk, mem_flags);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+#define ACX100_VENDOR_ID 0x2001
-+#define ACX100_PRODUCT_ID_UNBOOTED 0x3B01
-+#define ACX100_PRODUCT_ID_BOOTED 0x3B00
-+
-+/* RX-Timeout: NONE (request waits forever) */
-+#define ACX100_USB_RX_TIMEOUT (0)
-+
-+#define ACX100_USB_TX_TIMEOUT (4*HZ)
-+
-+#define USB_CTRL_HARD_TIMEOUT 5500 /* steps in ms */
-+
-+
-+/***********************************************************************
-+** Prototypes
-+*/
-+static int acx100usb_e_probe(struct usb_interface *, const struct usb_device_id *);
-+static void acx100usb_e_disconnect(struct usb_interface *);
-+static void acx100usb_i_complete_tx(struct urb *, struct pt_regs *);
-+static void acx100usb_i_complete_rx(struct urb *, struct pt_regs *);
-+static int acx100usb_e_open(struct net_device *);
-+static int acx100usb_e_close(struct net_device *);
-+static void acx100usb_i_set_rx_mode(struct net_device *);
-+static int acx100usb_e_init_network_device(struct net_device *);
-+static int acx100usb_boot(struct usb_device *);
-+
-+static struct net_device_stats * acx_e_get_stats(struct net_device *);
-+static struct iw_statistics *acx_e_get_wireless_stats(struct net_device *);
-+
-+static void acx100usb_l_poll_rx(wlandevice_t *, int number);
-+
-+static void acx100usb_i_tx_timeout(struct net_device *);
-+
-+/* static void dump_device(struct usb_device *); */
-+/* static void dump_device_descriptor(struct usb_device_descriptor *); */
-+/* static void dump_config_descriptor(struct usb_config_descriptor *); */
-+
-+/***********************************************************************
-+** Module Data
-+*/
-+#define TXBUFSIZE sizeof(usb_txbuffer_t)
-+//// Bogus! We CANNOT pretend that rxbuffer_t is larger than it is.
-+/* make it a multiply of 64 */
-+/* #define RXBUFSIZE ((sizeof(rxbuffer_t)+63) & ~63) */
-+#define RXBUFSIZE sizeof(rxbuffer_t)
-+
-+static const struct usb_device_id
-+acx100usb_ids[] = {
-+ { USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_BOOTED) },
-+ { USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_UNBOOTED) },
-+ {}
-+};
-+
-+
-+/* USB driver data structure as required by the kernel's USB core */
-+static struct usb_driver
-+acx100usb_driver = {
-+ .name = "acx_usb",
-+ .owner = THIS_MODULE,
-+ .probe = acx100usb_e_probe,
-+ .disconnect = acx100usb_e_disconnect,
-+ .id_table = acx100usb_ids
-+};
-+
-+
-+/***********************************************************************
-+** USB helper
-+**
-+** ldd3 ch13 says:
-+** When the function is usb_kill_urb, the urb lifecycle is stopped. This
-+** function is usually used when the device is disconnected from the system,
-+** in the disconnect callback. For some drivers, the usb_unlink_urb function
-+** should be used to tell the USB core to stop an urb. This function does not
-+** wait for the urb to be fully stopped before returning to the caller.
-+** This is useful for stoppingthe urb while in an interrupt handler or when
-+** a spinlock is held, as waiting for a urb to fully stop requires the ability
-+** for the USB core to put the calling process to sleep. This function requires
-+** that the URB_ASYNC_UNLINK flag value be set in the urb that is being asked
-+** to be stopped in order to work properly.
-+**
-+** URB_ASYNC_UNLINK is osolete, usb_unlink_urb will always be
-+** asynchronuos while usb_kill_urb is synchronuos and should be called
-+** directly. -> drivers/usb/core/urb.c
-+**
-+** In light of this, timeout is just for paranoid reasons...
-+*/
-+static void
-+acx_unlink_and_free_urb(struct urb* urb)
-+{
-+ if (!urb)
-+ return;
-+
-+ if (urb->status == -EINPROGRESS) {
-+ int timeout = 10;
-+
-+ usb_unlink_urb(urb);
-+ while (--timeout && urb->status == -EINPROGRESS) {
-+ mdelay(1);
-+ }
-+ /* if (!timeout) then what?? */
-+ }
-+
-+ /* just a refcounted kfree, safe undef lock */
-+ usb_free_urb(urb);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+#if ACX_DEBUG
-+static char*
-+acx100usb_pstatus(int val)
-+{
-+ static char status[20];
-+
-+ if (val < 0)
-+ sprintf(status, "errno %d", -val);
-+ else
-+ sprintf(status, "length %d", val);
-+
-+ return status;
-+}
-+#endif /* ACX_DEBUG */
-+
-+
-+/***********************************************************************
-+** EEPROM and PHY read/write helpers
-+*/
-+/***********************************************************************
-+** acxusb_s_read_phy_reg
-+*/
-+int
-+acxusb_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
-+{
-+ mem_read_write_t mem;
-+
-+ FN_ENTER;
-+
-+ mem.addr = cpu_to_le16(reg);
-+ mem.type = cpu_to_le16(0x82);
-+ mem.len = cpu_to_le32(4);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_MEM_READ, &mem, sizeof(mem) - 4);
-+ *charbuf = mem.data;
-+ acxlog(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+int
-+acxusb_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
-+{
-+ mem_read_write_t mem;
-+
-+ FN_ENTER;
-+
-+ mem.addr = cpu_to_le16(reg);
-+ mem.type = cpu_to_le16(0x82);
-+ mem.len = cpu_to_le32(4);
-+ mem.data = value;
-+//FIXME: maybe sizeof() - 4?
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_MEM_WRITE, &mem, sizeof(mem));
-+ acxlog(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg);
-+
-+ FN_EXIT1(OK);
-+ return OK;
-+}
-+
-+
-+/***********************************************************************
-+** acx_s_issue_cmd_timeo
-+** Excecutes a command in the command mailbox
-+**
-+** buffer = a pointer to the data.
-+** The data must not include 4 byte command header
-+*/
-+
-+/* TODO: ideally we shall always know how much we need
-+** and this shall be 0 */
-+#define BOGUS_SAFETY_PADDING 0x40
-+
-+#undef FUNC
-+#define FUNC "issue_cmd"
-+
-+#if !ACX_DEBUG
-+int
-+acxusb_s_issue_cmd_timeo(
-+ wlandevice_t *priv,
-+ unsigned cmd,
-+ void *buffer,
-+ unsigned buflen,
-+ unsigned timeout)
-+{
-+#else
-+int
-+acxusb_s_issue_cmd_timeo_debug(
-+ wlandevice_t *priv,
-+ unsigned cmd,
-+ void *buffer,
-+ unsigned buflen,
-+ unsigned timeout,
-+ const char* cmdstr)
-+{
-+#endif
-+ /* USB ignores timeout param */
-+
-+ struct usb_device *usbdev;
-+ struct {
-+ u16 cmd ACX_PACKED;
-+ u16 status ACX_PACKED;
-+ u8 data[1] ACX_PACKED;
-+ } *loc;
-+ const char *devname;
-+ int acklen, blocklen, inpipe, outpipe;
-+ int cmd_status;
-+ int result;
-+
-+ FN_ENTER;
-+
-+ devname = priv->netdev->name;
-+ if (!devname || !devname[0])
-+ devname = "acx";
-+
-+ acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,type:0x%04X)\n",
-+ cmdstr, buflen,
-+ buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
-+
-+ loc = kmalloc(buflen + 4 + BOGUS_SAFETY_PADDING, GFP_KERNEL);
-+ if (!loc) {
-+ printk("%s: "FUNC"(): no memory for data buffer\n", devname);
-+ goto bad;
-+ }
-+
-+ /* get context from wlandevice */
-+ usbdev = priv->usbdev;
-+
-+ /* check which kind of command was issued */
-+ loc->cmd = cpu_to_le16(cmd);
-+ loc->status = 0;
-+
-+/* NB: buflen == frmlen + 4
-+**
-+** Interrogate: write 8 bytes: (cmd,status,rid,frmlen), then
-+** read (cmd,status,rid,frmlen,data[frmlen]) back
-+**
-+** Configure: write (cmd,status,rid,frmlen,data[frmlen])
-+**
-+** Possibly bogus special handling of ACX1xx_IE_SCAN_STATUS removed
-+*/
-+
-+ /* now write the parameters of the command if needed */
-+ acklen = buflen + 4 + BOGUS_SAFETY_PADDING;
-+ blocklen = buflen;
-+ if (buffer && buflen) {
-+ /* if it's an INTERROGATE command, just pass the length
-+ * of parameters to read, as data */
-+ if (cmd == ACX1xx_CMD_INTERROGATE) {
-+ blocklen = 4;
-+ acklen = buflen + 4;
-+ }
-+ memcpy(loc->data, buffer, blocklen);
-+ }
-+ blocklen += 4; /* account for cmd,status */
-+
-+ /* obtain the I/O pipes */
-+ outpipe = usb_sndctrlpipe(usbdev, 0);
-+ inpipe = usb_rcvctrlpipe(usbdev, 0);
-+ acxlog(L_CTL, "ctrl inpipe=0x%X outpipe=0x%X\n", inpipe, outpipe);
-+ acxlog(L_CTL, "sending USB control msg (out) (blocklen=%d)\n", blocklen);
-+ if (acx_debug & L_DATA)
-+ acx_dump_bytes(loc, blocklen);
-+
-+ result = usb_control_msg(usbdev, outpipe,
-+ ACX_USB_REQ_CMD, /* request */
-+ USB_TYPE_VENDOR|USB_DIR_OUT, /* requesttype */
-+ 0, /* value */
-+ 0, /* index */
-+ loc, /* dataptr */
-+ blocklen, /* size */
-+ USB_CTRL_HARD_TIMEOUT /* timeout in ms */
-+ );
-+ acxlog(L_CTL, "wrote %d bytes\n", result);
-+ if (result < 0) {
-+ goto bad;
-+ }
-+
-+ /* check for device acknowledge */
-+ acxlog(L_CTL, "sending USB control msg (in) (acklen=%d)\n", acklen);
-+ loc->status = 0; /* delete old status flag -> set to IDLE */
-+//shall we zero out the rest?
-+ result = usb_control_msg(usbdev, inpipe,
-+ ACX_USB_REQ_CMD, /* request */
-+ USB_TYPE_VENDOR|USB_DIR_IN, /* requesttype */
-+ 0, /* value */
-+ 0, /* index */
-+ loc, /* dataptr */
-+ acklen, /* size */
-+ USB_CTRL_HARD_TIMEOUT /* timeout in ms */
-+ );
-+ if (result < 0) {
-+ printk("%s: "FUNC"(): USB read error %d\n", devname, result);
-+ goto bad;
-+ }
-+ if (acx_debug & L_CTL) {
-+ printk("read %d bytes: ", result);
-+ acx_dump_bytes(loc, result);
-+ }
-+
-+//check for result==buflen+4? Was seen:
-+//interrogate(type:ACX100_IE_DOT11_ED_THRESHOLD,len:4)
-+//issue_cmd(cmd:ACX1xx_CMD_INTERROGATE,buflen:8,type:4111)
-+//ctrl inpipe=0x80000280 outpipe=0x80000200
-+//sending USB control msg (out) (blocklen=8)
-+//01 00 00 00 0F 10 04 00
-+//wrote 8 bytes
-+//sending USB control msg (in) (acklen=12) sizeof(loc->data
-+//read 4 bytes <==== MUST BE 12!!
-+
-+ cmd_status = le16_to_cpu(loc->status);
-+ if (cmd_status != 1) {
-+ printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s)\n",
-+ devname, cmd_status, acx_cmd_status_str(cmd_status));
-+ /* TODO: goto bad; ? */
-+ }
-+ if ((cmd == ACX1xx_CMD_INTERROGATE) && buffer && buflen) {
-+ memcpy(buffer, loc->data, buflen);
-+ acxlog(L_CTL, "response frame: cmd=0x%04X status=%d\n",
-+ le16_to_cpu(loc->cmd),
-+ cmd_status);
-+ }
-+ kfree(loc);
-+ FN_EXIT1(OK);
-+ return OK;
-+bad:
-+ kfree(loc);
-+ /* Give enough info so that callers can avoid
-+ ** printing their own diagnostic messages */
-+#if ACX_DEBUG
-+ printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
-+#else
-+ printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
-+#endif
-+ dump_stack();
-+ FN_EXIT1(NOT_OK);
-+ return NOT_OK;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_e_probe()
-+**
-+** Inputs:
-+** dev -> Pointer to usb_device structure that may or may not be claimed
-+** ifNum -> Interface number
-+** devID -> Device ID (vendor and product specific stuff)
-+************************************************************************
-+** Returns:
-+** (void *) Pointer to (custom) driver context or NULL if we are not interested
-+** or unable to handle the offered device.
-+**
-+** Description:
-+** This function is invoked by the kernel's USB core whenever a new device is
-+** attached to the system or the module is loaded. It is presented a usb_device
-+** structure from which information regarding the device is obtained and evaluated.
-+** In case this driver is able to handle one of the offered devices, it returns
-+** a non-null pointer to a driver context and thereby claims the device.
-+*/
-+static void
-+acx_netdev_init(struct net_device *dev) {}
-+
-+static int
-+acx100usb_e_probe(struct usb_interface *intf, const struct usb_device_id *devID)
-+{
-+ struct usb_device *usbdev = interface_to_usbdev(intf);
-+ wlandevice_t *priv = NULL;
-+ struct net_device *dev = NULL;
-+ struct usb_config_descriptor *config;
-+ struct usb_endpoint_descriptor *epdesc;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
-+ struct usb_host_endpoint *ep;
-+#endif
-+ struct usb_interface_descriptor *ifdesc;
-+ const char* msg;
-+ int numconfigs, numfaces, numep;
-+ int result = OK;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* First check if this is the "unbooted" hardware */
-+ if ((usbdev->descriptor.idVendor == ACX100_VENDOR_ID)
-+ && (usbdev->descriptor.idProduct == ACX100_PRODUCT_ID_UNBOOTED)) {
-+ /* Boot the device (i.e. upload the firmware) */
-+ acx100usb_boot(usbdev);
-+
-+ /* OK, we are done with booting. Normally, the
-+ ** ID for the unbooted device should disappear
-+ ** and it will not need a driver anyway...so
-+ ** return a NULL
-+ */
-+ acxlog(L_INIT, "finished booting, returning from probe()\n");
-+ result = OK; /* success */
-+ goto end;
-+ }
-+
-+ if ((usbdev->descriptor.idVendor != ACX100_VENDOR_ID)
-+ || (usbdev->descriptor.idProduct != ACX100_PRODUCT_ID_BOOTED)) {
-+ goto end_nodev;
-+ }
-+
-+ /* Ok, so it's our device and it is already booted */
-+
-+ /* Allocate memory for a network device */
-+ dev = alloc_netdev(sizeof(wlandevice_t), "wlan%d", acx_netdev_init);
-+ /* (NB: memsets to 0 entire area) */
-+ if (!dev) {
-+ msg = "acx: no memory for netdev\n";
-+ goto end_nomem;
-+ }
-+ dev->init = (void *)&acx100usb_e_init_network_device;
-+
-+ /* Setup private driver context */
-+ priv = netdev_priv(dev);
-+ priv->netdev = dev;
-+ priv->dev_type = DEVTYPE_USB;
-+ priv->chip_type = CHIPTYPE_ACX100;
-+ /* FIXME: should be read from register (via firmware) using standard ACX code */
-+ priv->radio_type = RADIO_MAXIM_0D;
-+ priv->usbdev = usbdev;
-+
-+ spin_lock_init(&priv->lock); /* initial state: unlocked */
-+ sema_init(&priv->sem, 1); /* initial state: 1 (upped) */
-+
-+ /* Initialize the device context and also check
-+ ** if this is really the hardware we know about.
-+ ** If not sure, at least notify the user that he
-+ ** may be in trouble...
-+ */
-+ numconfigs = (int)usbdev->descriptor.bNumConfigurations;
-+ if (numconfigs != 1)
-+ printk("acx: number of configurations is %d, "
-+ "this driver only knows how to handle 1, "
-+ "be prepared for surprises\n", numconfigs);
-+
-+ config = &usbdev->config->desc;
-+ numfaces = config->bNumInterfaces;
-+ if (numfaces != 1)
-+ printk("acx: number of interfaces is %d, "
-+ "this driver only knows how to handle 1, "
-+ "be prepared for surprises\n", numfaces);
-+
-+ ifdesc = &intf->altsetting->desc;
-+ numep = ifdesc->bNumEndpoints;
-+ acxlog(L_DEBUG, "# of endpoints: %d\n", numep);
-+
-+ /* obtain information about the endpoint
-+ ** addresses, begin with some default values
-+ */
-+ priv->bulkoutep = 1;
-+ priv->bulkinep = 1;
-+ for (i = 0; i < numep; i++) {
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
-+ ep = usbdev->ep_in[i];
-+ if (!ep)
-+ continue;
-+ epdesc = &ep->desc;
-+#else
-+ epdesc = usb_epnum_to_ep_desc(usbdev, i);
-+ if (!epdesc)
-+ continue;
-+#endif
-+ if (epdesc->bmAttributes & USB_ENDPOINT_XFER_BULK) {
-+ if (epdesc->bEndpointAddress & 0x80)
-+ priv->bulkinep = epdesc->bEndpointAddress & 0xF;
-+ else
-+ priv->bulkoutep = epdesc->bEndpointAddress & 0xF;
-+ }
-+ }
-+ acxlog(L_DEBUG, "bulkout ep: 0x%X\n", priv->bulkoutep);
-+ acxlog(L_DEBUG, "bulkin ep: 0x%X\n", priv->bulkinep);
-+
-+ /* Set the packet-size equivalent to the buffer size */
-+ /* already done by memset: priv->rxtruncsize = 0; */
-+ acxlog(L_DEBUG, "TXBUFSIZE=%d RXBUFSIZE=%d\n",
-+ (int) TXBUFSIZE, (int) RXBUFSIZE);
-+
-+ priv->tx_free = ACX100_USB_NUM_BULK_URBS;
-+ /* already done by memset:
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ priv->usb_tx[i].busy = 0;
-+ }
-+ */
-+
-+ /* Setup URBs for bulk-in/out messages */
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ priv->bulkrx_urbs[i] = alloc_urb(0, GFP_KERNEL);
-+ if (!priv->bulkrx_urbs[i]) {
-+ msg = "acx: no memory for input URB\n";
-+ goto end_nomem;
-+ }
-+ priv->bulkrx_urbs[i]->status = 0;
-+
-+ priv->usb_tx[i].urb = alloc_urb(0, GFP_KERNEL);
-+ if (!priv->usb_tx[i].urb) {
-+ msg = "acx: no memory for output URB\n";
-+ goto end_nomem;
-+ }
-+ priv->usb_tx[i].urb->status = 0;
-+
-+ priv->usb_tx[i].priv = priv;
-+ }
-+
-+ usb_set_intfdata(intf, priv);
-+ SET_NETDEV_DEV(dev, &intf->dev);
-+
-+ /* Register the network device */
-+ acxlog(L_INIT, "registering network device\n");
-+ result = register_netdev(dev);
-+ if (result != 0) {
-+ msg = "acx: failed to register network device "
-+ "for USB WLAN (errcode=%d)\n";
-+ goto end_nomem;
-+ }
-+#ifdef CONFIG_PROC_FS
-+ if (OK != acx_proc_register_entries(dev)) {
-+ printk("acx: /proc registration failed\n");
-+ }
-+#endif
-+
-+ printk("acx: USB module " WLAN_RELEASE " loaded successfully\n");
-+
-+#if CMD_DISCOVERY
-+ great_inquisitor(priv);
-+#endif
-+
-+ /* Everything went OK, we are happy now */
-+ result = OK;
-+ goto end;
-+
-+end_nomem:
-+ printk(msg, result);
-+
-+ if (dev) {
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ usb_free_urb(priv->bulkrx_urbs[i]);
-+ usb_free_urb(priv->usb_tx[i].urb);
-+ }
-+ free_netdev(dev);
-+ }
-+ result = -ENOMEM;
-+ goto end;
-+
-+end_nodev:
-+
-+ /* no device we could handle, return error. */
-+ result = -EIO;
-+
-+end:
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_e_disconnect():
-+** Inputs:
-+** dev -> Pointer to usb_device structure handled by this module
-+** devContext -> Pointer to own device context (acx100usb_context)
-+************************************************************************
-+** Description:
-+** This function is invoked whenever the user pulls the plug from the USB
-+** device or the module is removed from the kernel. In these cases, the
-+** network devices have to be taken down and all allocated memory has
-+** to be freed.
-+*/
-+static void
-+acx100usb_e_disconnect(struct usb_interface *intf)
-+{
-+ wlandevice_t *priv = usb_get_intfdata(intf);
-+ unsigned long flags;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ /* No WLAN device...no sense */
-+ if (!priv)
-+ goto end;
-+
-+ /*
-+ * We get the sem *after* FLUSH to avoid a deadlock.
-+ * See pci.c:acx_s_down() for deails.
-+ */
-+ FLUSH_SCHEDULED_WORK();
-+ acx_sem_lock(priv);
-+
-+ acx_lock(priv, flags);
-+
-+ /* I wonder if above is enough to prevent tx/rx callbacks
-+ ** to start queue again? Like this:
-+ ** complete_rx -> acx_l_process_rxbuf -> associated -> acx_start_queue()
-+ ** Oh well... */
-+
-+ /* This device exists no more. */
-+ usb_set_intfdata(intf, NULL);
-+
-+ /* stop the transmit queue */
-+ if (priv->netdev) {
-+ acx_stop_queue(priv->netdev, "on USB disconnect");
-+#ifdef CONFIG_PROC_FS
-+ acx_proc_unregister_entries(priv->netdev);
-+#endif
-+ }
-+
-+ /* now abort pending URBs and free them */
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ acx_unlink_and_free_urb(priv->bulkrx_urbs[i]);
-+ acx_unlink_and_free_urb(priv->usb_tx[i].urb);
-+ }
-+
-+ acx_unlock(priv, flags);
-+ acx_sem_unlock(priv);
-+
-+ /* Unregister the network devices */
-+ if (priv->netdev) {
-+ unregister_netdev(priv->netdev);
-+ free_netdev(priv->netdev);
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_boot():
-+** Inputs:
-+** usbdev -> Pointer to kernel's usb_device structure
-+** endpoint -> Address of the endpoint for control transfers
-+************************************************************************
-+** Returns:
-+** (int) Errorcode or 0 on success
-+**
-+** Description:
-+** This function triggers the loading of the firmware image from harddisk
-+** and then uploads the firmware to the USB device. After uploading the
-+** firmware and transmitting the checksum, the device resets and appears
-+** as a new device on the USB bus (the device we can finally deal with)
-+*/
-+static int
-+acx100usb_boot(struct usb_device *usbdev)
-+{
-+ static const char filename[] = "tiacx100usb";
-+
-+ char *firmware = NULL;
-+ char *usbbuf;
-+ unsigned int offset;
-+ unsigned int len, inpipe, outpipe;
-+ u32 checksum;
-+ u32 size;
-+ int result;
-+
-+ FN_ENTER;
-+
-+ usbbuf = kmalloc(ACX100_USB_RWMEM_MAXLEN, GFP_KERNEL);
-+ if (!usbbuf) {
-+ printk(KERN_ERR "acx: no memory for USB transfer buffer ("
-+ STRING(ACX100_USB_RWMEM_MAXLEN)" bytes)\n");
-+ result = -ENOMEM;
-+ goto end;
-+ }
-+ firmware = (char *)acx_s_read_fw(&usbdev->dev, filename, &size);
-+ if (!firmware) {
-+ result = -EIO;
-+ goto end;
-+ }
-+ acxlog(L_INIT, "firmware size: %d bytes\n", size);
-+
-+ /* Obtain the I/O pipes */
-+ outpipe = usb_sndctrlpipe(usbdev, 0);
-+ inpipe = usb_rcvctrlpipe(usbdev, 0);
-+
-+ /* now upload the firmware, slice the data into blocks */
-+ offset = 8;
-+ while (offset < size) {
-+ len = size - offset;
-+ if (len >= ACX100_USB_RWMEM_MAXLEN) {
-+ len = ACX100_USB_RWMEM_MAXLEN;
-+ }
-+ acxlog(L_INIT, "uploading firmware (%d bytes, offset=%d)\n",
-+ len, offset);
-+ result = 0;
-+ memcpy(usbbuf, firmware + offset, len);
-+ result = usb_control_msg(usbdev, outpipe,
-+ ACX_USB_REQ_UPLOAD_FW,
-+ USB_TYPE_VENDOR|USB_DIR_OUT,
-+ size - 8, /* value */
-+ 0, /* index */
-+ usbbuf, /* dataptr */
-+ len, /* size */
-+ 3000 /* timeout in ms */
-+ );
-+ offset += len;
-+ if (result < 0) {
-+#if ACX_DEBUG
-+ printk(KERN_ERR "acx: error %d (%s) during upload "
-+ "of firmware, aborting\n", result,
-+ acx100usb_pstatus(result));
-+#else
-+ printk(KERN_ERR "acx: error %d during upload "
-+ "of firmware, aborting\n", result);
-+#endif
-+ goto end;
-+ }
-+ }
-+
-+ /* finally, send the checksum and reboot the device */
-+ checksum = le32_to_cpu(*(u32 *)firmware);
-+ /* is this triggers the reboot? */
-+ result = usb_control_msg(usbdev, outpipe,
-+ ACX_USB_REQ_UPLOAD_FW,
-+ USB_TYPE_VENDOR|USB_DIR_OUT,
-+ checksum & 0xffff, /* value */
-+ checksum >> 16, /* index */
-+ NULL, /* dataptr */
-+ 0, /* size */
-+ 3000 /* timeout in ms */
-+ );
-+ if (result < 0) {
-+ printk(KERN_ERR "acx: error %d during tx of checksum, "
-+ "aborting\n", result);
-+ goto end;
-+ }
-+ result = usb_control_msg(usbdev, inpipe,
-+ ACX_USB_REQ_ACK_CS,
-+ USB_TYPE_VENDOR|USB_DIR_IN,
-+ checksum & 0xffff, /* value */
-+ checksum >> 16, /* index */
-+ usbbuf, /* dataptr */
-+ 8, /* size */
-+ 3000 /* timeout in ms */
-+ );
-+ if (result < 0) {
-+ printk(KERN_ERR "acx: error %d during ACK of checksum, "
-+ "aborting\n", result);
-+ goto end;
-+ }
-+ if (*usbbuf != 0x10) {
-+ kfree(usbbuf);
-+ printk(KERN_ERR "acx: invalid checksum?\n");
-+ result = -EINVAL;
-+ goto end;
-+ }
-+ result = 0;
-+end:
-+ vfree(firmware);
-+ kfree(usbbuf);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_e_init_network_device():
-+** Inputs:
-+** dev -> Pointer to network device
-+************************************************************************
-+** Description:
-+** Basic setup of a network device for use with the WLAN device.
-+*/
-+static int
-+acx100usb_e_init_network_device(struct net_device *dev)
-+{
-+ wlandevice_t *priv;
-+ int result = 0;
-+
-+ FN_ENTER;
-+
-+ /* Setup the device and stop the queue */
-+ ether_setup(dev);
-+ acx_stop_queue(dev, "on init");
-+
-+ priv = netdev_priv(dev);
-+
-+ acx_sem_lock(priv);
-+
-+ /* put the ACX100 out of sleep mode */
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
-+
-+ /* Register the callbacks for the network device functions */
-+ dev->open = &acx100usb_e_open;
-+ dev->stop = &acx100usb_e_close;
-+ dev->hard_start_xmit = (void *)&acx_i_start_xmit;
-+ dev->get_stats = (void *)&acx_e_get_stats;
-+ dev->get_wireless_stats = (void *)&acx_e_get_wireless_stats;
-+#if WIRELESS_EXT >= 13
-+ dev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
-+#else
-+ dev->do_ioctl = (void *)&acx_e_ioctl_old;
-+#endif
-+ dev->set_multicast_list = (void *)&acx100usb_i_set_rx_mode;
-+#ifdef HAVE_TX_TIMEOUT
-+ dev->tx_timeout = &acx100usb_i_tx_timeout;
-+ dev->watchdog_timeo = 4 * HZ;
-+#endif
-+ result = acx_s_init_mac(dev);
-+ if (OK != result)
-+ goto end;
-+ result = acx_s_set_defaults(priv);
-+ if (OK != result) {
-+ printk("%s: acx_set_defaults FAILED\n", dev->name);
-+ goto end;
-+ }
-+
-+ SET_MODULE_OWNER(dev);
-+end:
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT1(result);
-+ return result;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_e_open
-+** This function is called when the user sets up the network interface.
-+** It initializes a management timer, sets up the USB card and starts
-+** the network tx queue and USB receive.
-+*/
-+static int
-+acx100usb_e_open(struct net_device *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ acx_sem_lock(priv);
-+
-+ /* put the ACX100 out of sleep mode */
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
-+
-+ acx_init_task_scheduler(priv);
-+
-+ init_timer(&priv->mgmt_timer);
-+ priv->mgmt_timer.function = acx_i_timer;
-+ priv->mgmt_timer.data = (unsigned long)priv;
-+
-+ /* set ifup to 1, since acx_start needs it */
-+ SET_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-+ acx_s_start(priv);
-+
-+ acx_start_queue(dev, "on open");
-+
-+ acx_lock(priv, flags);
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ acx100usb_l_poll_rx(priv, i);
-+ }
-+ acx_unlock(priv, flags);
-+
-+ WLAN_MOD_INC_USE_COUNT;
-+
-+ acx_sem_unlock(priv);
-+
-+ FN_EXIT0;
-+ return 0;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_l_poll_rx
-+** This function initiates a bulk-in USB transfer (in case the interface
-+** is up).
-+*/
-+static void
-+acx100usb_l_poll_rx(wlandevice_t *priv, int number)
-+{
-+ struct usb_device *usbdev;
-+ rxbuffer_t *inbuf;
-+ acx_usb_bulk_context_t *rxcon;
-+ struct urb *rxurb;
-+ int errcode;
-+ unsigned int inpipe;
-+
-+ FN_ENTER;
-+
-+ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
-+ goto end;
-+ }
-+
-+ rxcon = &priv->rxcons[number];
-+ inbuf = &priv->bulkins[number];
-+ rxurb = priv->bulkrx_urbs[number];
-+ usbdev = priv->usbdev;
-+
-+ rxcon->device = priv;
-+ rxcon->number = number;
-+ inpipe = usb_rcvbulkpipe(usbdev, priv->bulkinep);
-+ if (rxurb->status == -EINPROGRESS) {
-+ printk(KERN_ERR "acx: error, rx triggered while rx urb in progress\n");
-+ /* FIXME: this is nasty, receive is being cancelled by this code
-+ * on the other hand, this should not happen anyway...
-+ */
-+ usb_unlink_urb(rxurb);
-+ }
-+ rxurb->actual_length = 0;
-+ usb_fill_bulk_urb(rxurb, usbdev, inpipe,
-+ inbuf, /* dataptr */
-+ RXBUFSIZE, /* size */
-+ acx100usb_i_complete_rx, /* handler */
-+ rxcon /* handler param */
-+ );
-+ rxurb->transfer_flags = QUEUE_BULK;
-+
-+ /* ATOMIC: we may be called from complete_rx() usb callback */
-+ errcode = submit_urb(rxurb, GFP_ATOMIC);
-+ /* FIXME: evaluate the error code! */
-+ acxlog(L_USBRXTX, "SUBMIT RX (%d) inpipe=0x%X size=%d errcode=%d\n",
-+ number, inpipe, (int) RXBUFSIZE, errcode);
-+
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_i_complete_rx():
-+** Inputs:
-+** urb -> Pointer to USB request block
-+** regs -> Pointer to register-buffer for syscalls (see asm/ptrace.h)
-+************************************************************************
-+** Description:
-+** This function is invoked by USB subsystem whenever a bulk receive
-+** request returns.
-+** The received data is then committed to the network stack and the next
-+** USB receive is triggered.
-+*/
-+static void
-+acx100usb_i_complete_rx(struct urb *urb, struct pt_regs *regs)
-+{
-+ wlandevice_t *priv;
-+ rxbuffer_t *ptr;
-+ rxbuffer_t *inbuf;
-+ unsigned long flags;
-+ int size, number, remsize, packetsize;
-+
-+ FN_ENTER;
-+
-+ if (!urb->context) {
-+ printk(KERN_ERR "acx: error, urb context was NULL\n");
-+ goto end; /* at least try to prevent the worst */
-+ }
-+
-+ priv = ((acx_usb_bulk_context_t *)urb->context)->device;
-+
-+ acx_lock(priv, flags);
-+
-+ /* TODO: we maybe need to check whether urb was unlinked
-+ ** (happens on disconnect and close, see there). How? */
-+
-+ number = ((acx_usb_bulk_context_t *)urb->context)->number;
-+ size = urb->actual_length;
-+ remsize = size;
-+
-+ acxlog(L_USBRXTX, "RETURN RX (%d) status=%d size=%d\n",
-+ number, urb->status, size);
-+
-+ inbuf = &priv->bulkins[number];
-+ ptr = inbuf;
-+
-+ /* check if the transfer was aborted */
-+ switch (urb->status) {
-+ case 0: /* No error */
-+ break;
-+ case -EOVERFLOW:
-+ printk(KERN_ERR "acx: error in rx, data overrun -> emergency stop\n");
-+ /* LOCKING BUG! acx100usb_e_close(priv->netdev); */
-+ goto end_unlock;
-+ case -ECONNRESET:
-+ goto do_poll_rx;
-+ default:
-+ priv->stats.rx_errors++;
-+ printk("acx: rx error (urb status=%d)\n", urb->status);
-+ goto do_poll_rx;
-+ }
-+
-+ if (!size)
-+ printk("acx: warning, encountered zerolength rx packet\n");
-+
-+ if (urb->transfer_buffer != inbuf)
-+ goto do_poll_rx;
-+
-+ /* check if previous frame was truncated
-+ ** FIXME: this code can only handle truncation
-+ ** of consecutive packets!
-+ */
-+ if (priv->rxtruncsize) {
-+ int tail_size;
-+
-+ ptr = &priv->rxtruncbuf;
-+ packetsize = RXBUF_BYTES_RCVD(ptr) + RXBUF_HDRSIZE;
-+ if (acx_debug & L_USBRXTX) {
-+ printk("handling truncated frame (truncsize=%d size=%d "
-+ "packetsize(from trunc)=%d)\n",
-+ priv->rxtruncsize, size, packetsize);
-+ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
-+ acx_dump_bytes(inbuf, RXBUF_HDRSIZE);
-+ }
-+
-+ /* bytes needed for rxtruncbuf completion: */
-+ tail_size = packetsize - priv->rxtruncsize;
-+
-+ if (size < tail_size) {
-+ /* there is not enough data to complete this packet,
-+ ** simply append the stuff to the truncation buffer
-+ */
-+ memcpy(((char *)ptr) + priv->rxtruncsize, inbuf, size);
-+ priv->rxtruncsize += size;
-+ remsize = 0;
-+ } else {
-+ /* ok, this data completes the previously
-+ ** truncated packet. copy it into a descriptor
-+ ** and give it to the rest of the stack */
-+
-+ /* append tail to previously truncated part
-+ ** NB: priv->rxtruncbuf (pointed to by ptr) can't
-+ ** overflow because this is already checked before
-+ ** truncation buffer was filled. See below,
-+ ** "if (packetsize > sizeof(rxbuffer_t))..." code */
-+ memcpy(((char *)ptr) + priv->rxtruncsize, inbuf, tail_size);
-+
-+ if (acx_debug & L_USBRXTX) {
-+ printk("full trailing packet + 12 bytes:\n");
-+ acx_dump_bytes(inbuf, tail_size + RXBUF_HDRSIZE);
-+ }
-+ acx_l_process_rxbuf(priv, ptr);
-+ priv->rxtruncsize = 0;
-+ ptr = (rxbuffer_t *) (((char *)inbuf) + tail_size);
-+ remsize -= tail_size;
-+ }
-+ acxlog(L_USBRXTX, "post-merge size=%d remsize=%d\n",
-+ size, remsize);
-+ }
-+
-+ /* size = USB data block size
-+ ** remsize = unprocessed USB bytes left
-+ ** ptr = current pos in USB data block
-+ */
-+ while (remsize) {
-+ if (remsize < RXBUF_HDRSIZE) {
-+ printk("acx: truncated rx header (%d bytes)!\n",
-+ remsize);
-+ break;
-+ }
-+ packetsize = RXBUF_BYTES_RCVD(ptr) + RXBUF_HDRSIZE;
-+ acxlog(L_USBRXTX, "packet with packetsize=%d\n", packetsize);
-+ if (packetsize > sizeof(rxbuffer_t)) {
-+ printk("acx: packet exceeds max wlan "
-+ "frame size (%d > %d). size=%d\n",
-+ packetsize, (int) sizeof(rxbuffer_t), size);
-+ /* FIXME: put some real error-handling in here! */
-+ break;
-+ }
-+
-+ /* skip null packets (does this really happen?!) */
-+ if (packetsize == RXBUF_HDRSIZE) {
-+ remsize -= RXBUF_HDRSIZE;
-+ if (acx_debug & L_USBRXTX) {
-+ printk("acx: null packet, new remsize=%d. "
-+ "header follows:\n", remsize);
-+ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
-+ }
-+ ptr = (rxbuffer_t *)(((char *)ptr) + RXBUF_HDRSIZE);
-+ continue;
-+ }
-+
-+ if (packetsize > remsize) {
-+ /* frame truncation handling */
-+ if (acx_debug & L_USBRXTX) {
-+ printk("need to truncate packet, "
-+ "packetsize=%d remsize=%d "
-+ "size=%d\n",
-+ packetsize, remsize, size);
-+ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
-+ }
-+ memcpy(&priv->rxtruncbuf, ptr, remsize);
-+ priv->rxtruncsize = remsize;
-+ break;
-+ } else { /* packetsize <= remsize */
-+ /* now handle the received data */
-+ acx_l_process_rxbuf(priv, ptr);
-+
-+ ptr = (rxbuffer_t *)(((char *)ptr) + packetsize);
-+ remsize -= packetsize;
-+ if ((acx_debug & L_USBRXTX) && remsize) {
-+ printk("more than one packet in buffer, "
-+ "second packet hdr follows\n");
-+ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
-+ }
-+ }
-+ }
-+
-+do_poll_rx:
-+ /* look for the next rx */
-+ if (priv->dev_state_mask & ACX_STATE_IFACE_UP) {
-+ /* receive of frame completed, now look for the next one */
-+ acx100usb_l_poll_rx(priv, number);
-+ }
-+
-+end_unlock:
-+ acx_unlock(priv, flags);
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_i_complete_tx():
-+** Inputs:
-+** urb -> Pointer to USB request block
-+** regs -> Pointer to register-buffer for syscalls (see asm/ptrace.h)
-+************************************************************************
-+** Description:
-+** This function is invoked upon termination of a USB transfer. As the
-+** USB device is only capable of sending a limited amount of bytes per
-+** transfer to the bulk-out endpoint, this routine checks if there are
-+** more bytes to send and triggers subsequent transfers. In case the
-+** transfer size exactly matches the maximum bulk-out size, it triggers
-+** a transfer of a null-frame, telling the card that this is it. Upon
-+** completion of a frame, it checks whether the Tx ringbuffer contains
-+** more data to send and invokes the Tx routines if this is the case.
-+** If there are no more occupied Tx descriptors, the Tx Mutex is unlocked
-+** and the network queue is switched back to life again.
-+**
-+** FIXME: unlike PCI code, we do not analyze tx rate used, retries, etc...
-+** Thus we have no automatic rate control in USB!
-+*/
-+static void
-+acx100usb_i_complete_tx(struct urb *urb, struct pt_regs *regs)
-+{
-+ wlandevice_t *priv;
-+ usb_tx_t *tx;
-+ unsigned long flags;
-+
-+ FN_ENTER;
-+
-+ if (!urb->context) {
-+ printk(KERN_ERR "acx: error, NULL context in tx completion callback\n");
-+ /* FIXME: real error-handling code must go here! */
-+ goto end;
-+ }
-+
-+ tx = (usb_tx_t *)urb->context;
-+ priv = tx->priv;
-+
-+ acx_lock(priv, flags);
-+
-+ /* TODO: we maybe need to check whether urb was unlinked
-+ ** (happens on disconnect and close, see there). How? */
-+
-+ acxlog(L_USBRXTX, "RETURN TX (%p): status=%d size=%d\n",
-+ tx, urb->status, urb->actual_length);
-+
-+ /* handle USB transfer errors */
-+ switch (urb->status) {
-+ case 0: /* No error */
-+ break;
-+ case -ECONNRESET:
-+ break;
-+ /* FIXME: real error-handling code here please */
-+ default:
-+ printk(KERN_ERR "acx: tx error, urb status=%d\n", urb->status);
-+ /* FIXME: real error-handling code here please */
-+ }
-+
-+ /* free the URB and check for more data */
-+ priv->tx_free++;
-+ tx->busy = 0;
-+
-+/* end_unlock: */
-+ acx_unlock(priv, flags);
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+** acx100usb_e_close():
-+**
-+** This function stops the network functionality of the interface (invoked
-+** when the user calls ifconfig <wlan> down). The tx queue is halted and
-+** the device is marked as down. In case there were any pending USB bulk
-+** transfers, these are unlinked (asynchronously). The module in-use count
-+** is also decreased in this function.
-+*/
-+static int
-+acx100usb_e_close(struct net_device *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ int i;
-+
-+ FN_ENTER;
-+
-+#if WE_STILL_DONT_CARE_ABOUT_IT
-+ /* Transmit a disassociate frame */
-+ lock
-+ acx_l_transmit_disassoc(priv, &client);
-+ unlock
-+#endif
-+
-+ /*
-+ * We get the sem *after* FLUSH to avoid a deadlock.
-+ * See pci.c:acx_s_down() for deails.
-+ */
-+ FLUSH_SCHEDULED_WORK();
-+ acx_sem_lock(priv);
-+
-+ /* stop the transmit queue, mark the device as DOWN */
-+ acx_lock(priv, flags);
-+ acx_stop_queue(dev, "on iface stop");
-+ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
-+
-+ /* I wonder if above is enough to prevent tx/rx callbacks
-+ ** to start queue again? Like this:
-+ ** complete_rx -> acx_l_process_rxbuf -> associated -> acx_start_queue()
-+ ** Oh well... */
-+
-+ /* stop pending rx/tx urb transfers */
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ acx_unlink_and_free_urb(priv->bulkrx_urbs[i]);
-+ acx_unlink_and_free_urb(priv->usb_tx[i].urb);
-+ }
-+ acx_unlock(priv, flags);
-+
-+ /* disable rx and tx */
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0);
-+
-+ /* power down the device */
-+ acx_s_issue_cmd(priv, ACX1xx_CMD_SLEEP, NULL, 0);
-+
-+ acx_sem_unlock(priv);
-+
-+ /* decrease module-in-use count (if necessary) */
-+
-+ WLAN_MOD_DEC_USE_COUNT;
-+
-+ FN_EXIT0;
-+ return 0;
-+}
-+
-+
-+/***************************************************************
-+** acxusb_l_alloc_tx
-+** Actually returns a usb_tx_t* ptr
-+*/
-+tx_t*
-+acxusb_l_alloc_tx(wlandevice_t* priv)
-+{
-+ int i;
-+ usb_tx_t *tx = NULL;
-+
-+ FN_ENTER;
-+
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ if (!priv->usb_tx[i].busy) {
-+ tx = &priv->usb_tx[i];
-+ tx->busy = 1;
-+ break;
-+ }
-+ }
-+ if (i >= ACX100_USB_NUM_BULK_URBS) {
-+ printk("acx: tx buffers full\n");
-+ }
-+
-+ FN_EXIT0;
-+
-+ return (tx_t*)tx;
-+}
-+
-+
-+/***************************************************************
-+*/
-+void*
-+acxusb_l_get_txbuf(wlandevice_t *priv, tx_t* tx_opaque)
-+{
-+ usb_tx_t* tx = (usb_tx_t*)tx_opaque;
-+ return &tx->bulkout.data;
-+}
-+
-+
-+/***************************************************************
-+** acxusb_l_tx_data
-+**
-+** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
-+** Can be called from acx_i_start_xmit (data frames from net core).
-+*/
-+void
-+acxusb_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int wlanpkt_len)
-+{
-+ struct usb_device *usbdev;
-+ struct urb* txurb;
-+ usb_tx_t* tx;
-+ usb_txbuffer_t* txbuf;
-+ client_t *clt;
-+ wlan_hdr_t* whdr;
-+ unsigned int outpipe;
-+ int ucode;
-+ u8 rate100;
-+
-+ FN_ENTER;
-+
-+ tx = ((usb_tx_t *)tx_opaque);
-+ txurb = tx->urb;
-+ txbuf = &tx->bulkout;
-+ whdr = (wlan_hdr_t *)txbuf->data;
-+
-+ priv->tx_free--;
-+ acxlog(L_DEBUG, "using buf#%d free=%d len=%d\n",
-+ (int)(tx - priv->usb_tx),
-+ priv->tx_free, wlanpkt_len);
-+
-+ switch (priv->mode) {
-+ case ACX_MODE_0_ADHOC:
-+ case ACX_MODE_3_AP:
-+ clt = acx_l_sta_list_get(priv, whdr->a1);
-+ break;
-+ case ACX_MODE_2_STA:
-+ clt = priv->ap_client;
-+ break;
-+ default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
-+ clt = NULL;
-+ break;
-+ }
-+
-+ if (unlikely(clt && !clt->rate_cur)) {
-+ printk("acx: driver bug! bad ratemask\n");
-+ goto end;
-+ }
-+
-+ /* used in tx cleanup routine for auto rate and accounting: */
-+//TODO: currently unused - fix that
-+ tx->txc = clt;
-+
-+ rate100 = clt ? clt->rate_100 : priv->rate_bcast100;
-+
-+ /* fill the USB transfer header */
-+ txbuf->desc = cpu_to_le16(USB_TXBUF_TXDESC);
-+ txbuf->MPDUlen = cpu_to_le16(wlanpkt_len);
-+ txbuf->ctrl1 = 0;
-+ txbuf->ctrl2 = 0;
-+ txbuf->hostData = cpu_to_le32(wlanpkt_len | (rate100 << 24));
-+ if (1 == priv->preamble_cur)
-+ SET_BIT(txbuf->ctrl1, DESC_CTL_SHORT_PREAMBLE);
-+ SET_BIT(txbuf->ctrl1, DESC_CTL_FIRSTFRAG);
-+ txbuf->txRate = rate100;
-+ txbuf->index = 1;
-+ txbuf->dataLength = cpu_to_le16(wlanpkt_len);
-+
-+ if ( (WF_FC_FTYPEi & whdr->fc) == WF_FTYPE_DATAi )
-+ SET_BIT(txbuf->hostData, cpu_to_le32(USB_TXBUF_HD_ISDATA));
-+ if (mac_is_directed(whdr->a1))
-+ SET_BIT(txbuf->hostData, cpu_to_le32(USB_TXBUF_HD_DIRECTED));
-+ else if (mac_is_bcast(whdr->a1))
-+ SET_BIT(txbuf->hostData, cpu_to_le32(USB_TXBUF_HD_BROADCAST));
-+
-+ if (acx_debug & L_DATA) {
-+ printk("dump of bulk out urb:\n");
-+ acx_dump_bytes(txbuf, wlanpkt_len + USB_TXBUF_HDRSIZE);
-+ }
-+
-+ if (txurb->status == -EINPROGRESS) {
-+ printk("acx: trying to submit tx urb while already in progress\n");
-+ }
-+
-+ /* now schedule the USB transfer */
-+ usbdev = priv->usbdev;
-+ outpipe = usb_sndbulkpipe(usbdev, priv->bulkoutep);
-+//can be removed, please try & test:
-+ tx->priv = priv;
-+
-+ usb_fill_bulk_urb(txurb, usbdev, outpipe,
-+ txbuf, /* dataptr */
-+ wlanpkt_len + USB_TXBUF_HDRSIZE, /* size */
-+ acx100usb_i_complete_tx, /* handler */
-+ tx /* handler param */
-+ );
-+
-+ txurb->transfer_flags = QUEUE_BULK|ZERO_PACKET;
-+ ucode = submit_urb(txurb, GFP_ATOMIC);
-+ acxlog(L_USBRXTX, "SUBMIT TX (%p): outpipe=0x%X buf=%p txsize=%d "
-+ "errcode=%d\n", tx, outpipe, txbuf,
-+ wlanpkt_len + USB_TXBUF_HDRSIZE, ucode);
-+
-+ if (ucode) {
-+ printk(KERN_ERR "acx: submit_urb() error=%d txsize=%d\n",
-+ ucode, wlanpkt_len + USB_TXBUF_HDRSIZE);
-+
-+ /* on error, just mark the frame as done and update
-+ ** the statistics
-+ */
-+ priv->stats.tx_errors++;
-+ tx->busy = 0;
-+ priv->tx_free++;
-+ }
-+end:
-+ FN_EXIT0;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static struct net_device_stats*
-+acx_e_get_stats(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ return &priv->stats;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static struct iw_statistics*
-+acx_e_get_wireless_stats(netdevice_t *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ FN_ENTER;
-+ FN_EXIT0;
-+ return &priv->wstats;
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static void
-+acx100usb_i_set_rx_mode(struct net_device *dev)
-+{
-+}
-+
-+
-+/***********************************************************************
-+*/
-+#ifdef HAVE_TX_TIMEOUT
-+static void
-+acx100usb_i_tx_timeout(struct net_device *dev)
-+{
-+ wlandevice_t *priv = netdev_priv(dev);
-+ unsigned long flags;
-+ int i;
-+
-+ FN_ENTER;
-+
-+ acx_lock(priv, flags);
-+ /* unlink the URBs */
-+ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
-+ if (priv->usb_tx[i].urb->status == -EINPROGRESS)
-+ usb_unlink_urb(priv->usb_tx[i].urb);
-+ }
-+ /* TODO: stats update */
-+ acx_unlock(priv, flags);
-+
-+ FN_EXIT0;
-+}
-+#endif
-+
-+
-+/***********************************************************************
-+** init_module():
-+**
-+** This function is invoked upon loading of the kernel module.
-+** It registers itself at the kernel's USB subsystem.
-+**
-+** Returns: Errorcode on failure, 0 on success
-+*/
-+int __init
-+acxusb_e_init_module(void)
-+{
-+ acxlog(L_INIT, "USB module " WLAN_RELEASE " initialized, "
-+ "probing for devices...\n");
-+ return usb_register(&acx100usb_driver);
-+}
-+
-+
-+
-+/***********************************************************************
-+** cleanup_module():
-+**
-+** This function is invoked as last step of the module unloading. It simply
-+** deregisters this module at the kernel's USB subsystem.
-+*/
-+void __exit
-+acxusb_e_cleanup_module()
-+{
-+ usb_deregister(&acx100usb_driver);
-+}
-+
-+
-+/***********************************************************************
-+** DEBUG STUFF
-+*/
-+#if ACX_DEBUG
-+
-+#ifdef UNUSED
-+static void
-+dump_device(struct usb_device *usbdev)
-+{
-+ int i;
-+ struct usb_config_descriptor *cd;
-+
-+ printk("acx device dump:\n");
-+ printk(" devnum: %d\n", usbdev->devnum);
-+ printk(" speed: %d\n", usbdev->speed);
-+ printk(" tt: 0x%X\n", (unsigned int)(usbdev->tt));
-+ printk(" ttport: %d\n", (unsigned int)(usbdev->ttport));
-+ printk(" toggle[0]: 0x%X toggle[1]: 0x%X\n", (unsigned int)(usbdev->toggle[0]), (unsigned int)(usbdev->toggle[1]));
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
-+ /* halted removed in 2.6.9-rc1 */
-+ /* DOH, Canbreak... err... Mandrake decided to do their very own very
-+ * special version "2.6.8.1" which already includes this change, so we
-+ * need to blacklist that version already (i.e. 2.6.8) */
-+ printk(" halted[0]: 0x%X halted[1]: 0x%X\n", usbdev->halted[0], usbdev->halted[1]);
-+#endif
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
-+ /* This saw a change after 2.6.10 */
-+ printk(" ep_in wMaxPacketSize: ");
-+ for (i = 0; i < 16; ++i)
-+ printk("%d ", usbdev->ep_in[i]->desc.wMaxPacketSize);
-+ printk("\n");
-+ printk(" ep_out wMaxPacketSize: ");
-+ for (i = 0; i < 15; ++i)
-+ printk("%d ", usbdev->ep_out[i]->desc.wMaxPacketSize);
-+ printk("\n");
-+#else
-+ printk(" epmaxpacketin: ");
-+ for (i = 0; i < 16; i++)
-+ printk("%d ", usbdev->epmaxpacketin[i]);
-+ printk("\n");
-+ printk(" epmaxpacketout: ");
-+ for (i = 0; i < 16; i++)
-+ printk("%d ", usbdev->epmaxpacketout[i]);
-+ printk("\n");
-+#endif
-+ printk(" parent: 0x%X\n", (unsigned int)usbdev->parent);
-+ printk(" bus: 0x%X\n", (unsigned int)usbdev->bus);
-+#if NO_DATATYPE
-+ printk(" configs: ");
-+ for (i = 0; i < usbdev->descriptor.bNumConfigurations; i++)
-+ printk("0x%X ", usbdev->config[i]);
-+ printk("\n");
-+#endif
-+ printk(" actconfig: %p\n", usbdev->actconfig);
-+ dump_device_descriptor(&usbdev->descriptor);
-+
-+ cd = &usbdev->config->desc;
-+ dump_config_descriptor(cd);
-+}
-+
-+
-+/***********************************************************************
-+*/
-+static void
-+dump_config_descriptor(struct usb_config_descriptor *cd)
-+{
-+ printk("Configuration Descriptor:\n");
-+ if (!cd) {
-+ printk("NULL\n");
-+ return;
-+ }
-+ printk(" bLength: %d (0x%X)\n", cd->bLength, cd->bLength);
-+ printk(" bDescriptorType: %d (0x%X)\n", cd->bDescriptorType, cd->bDescriptorType);
-+ printk(" bNumInterfaces: %d (0x%X)\n", cd->bNumInterfaces, cd->bNumInterfaces);
-+ printk(" bConfigurationValue: %d (0x%X)\n", cd->bConfigurationValue, cd->bConfigurationValue);
-+ printk(" iConfiguration: %d (0x%X)\n", cd->iConfiguration, cd->iConfiguration);
-+ printk(" bmAttributes: %d (0x%X)\n", cd->bmAttributes, cd->bmAttributes);
-+ /* printk(" MaxPower: %d (0x%X)\n", cd->bMaxPower, cd->bMaxPower); */
-+}
-+
-+
-+static void
-+dump_device_descriptor(struct usb_device_descriptor *dd)
-+{
-+ printk("Device Descriptor:\n");
-+ if (!dd) {
-+ printk("NULL\n");
-+ return;
-+ }
-+ printk(" bLength: %d (0x%X)\n", dd->bLength, dd->bLength);
-+ printk(" bDescriptortype: %d (0x%X)\n", dd->bDescriptorType, dd->bDescriptorType);
-+ printk(" bcdUSB: %d (0x%X)\n", dd->bcdUSB, dd->bcdUSB);
-+ printk(" bDeviceClass: %d (0x%X)\n", dd->bDeviceClass, dd->bDeviceClass);
-+ printk(" bDeviceSubClass: %d (0x%X)\n", dd->bDeviceSubClass, dd->bDeviceSubClass);
-+ printk(" bDeviceProtocol: %d (0x%X)\n", dd->bDeviceProtocol, dd->bDeviceProtocol);
-+ printk(" bMaxPacketSize0: %d (0x%X)\n", dd->bMaxPacketSize0, dd->bMaxPacketSize0);
-+ printk(" idVendor: %d (0x%X)\n", dd->idVendor, dd->idVendor);
-+ printk(" idProduct: %d (0x%X)\n", dd->idProduct, dd->idProduct);
-+ printk(" bcdDevice: %d (0x%X)\n", dd->bcdDevice, dd->bcdDevice);
-+ printk(" iManufacturer: %d (0x%X)\n", dd->iManufacturer, dd->iManufacturer);
-+ printk(" iProduct: %d (0x%X)\n", dd->iProduct, dd->iProduct);
-+ printk(" iSerialNumber: %d (0x%X)\n", dd->iSerialNumber, dd->iSerialNumber);
-+ printk(" bNumConfigurations: %d (0x%X)\n", dd->bNumConfigurations, dd->bNumConfigurations);
-+}
-+#endif /* UNUSED */
-+
-+#endif /* ACX_DEBUG */
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan.c bt_kernel/drivers/net/wireless/tiacx/wlan.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/wlan.c 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,392 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+/***********************************************************************
-+** This code is based on elements which are
-+** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
-+** info@linux-wlan.com
-+** http://www.linux-wlan.com
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#include <linux/types.h>
-+#include <linux/if_arp.h>
-+#include <linux/wireless.h>
-+#if WIRELESS_EXT >= 13
-+#include <net/iw_handler.h>
-+#endif
-+
-+#include "acx.h"
-+
-+
-+/***********************************************************************
-+*/
-+#define LOG_BAD_EID(hdr,len,ie_ptr) acx_log_bad_eid(hdr, len, ((wlan_ie_t*)ie_ptr))
-+
-+#define IE_EID(ie_ptr) (((wlan_ie_t*)(ie_ptr))->eid)
-+#define IE_LEN(ie_ptr) (((wlan_ie_t*)(ie_ptr))->len)
-+#define OFFSET(hdr,off) (WLAN_HDR_A3_DATAP(hdr) + (off))
-+
-+
-+/***********************************************************************
-+** wlan_mgmt_decode_XXX
-+**
-+** Given a complete frame in f->hdr, sets the pointers in f to
-+** the areas that correspond to the parts of the frame.
-+**
-+** Assumptions:
-+** 1) f->len and f->hdr are already set
-+** 2) f->len is the length of the MAC header + data, the FCS
-+** is NOT included
-+** 3) all members except len and hdr are zero
-+** Arguments:
-+** f frame structure
-+**
-+** Returns:
-+** nothing
-+**
-+** Side effects:
-+** frame structure members are pointing at their
-+** respective portions of the frame buffer.
-+*/
-+void
-+wlan_mgmt_decode_beacon(wlan_fr_beacon_t * f)
-+{
-+ u8 *ie_ptr;
-+ u8 *end = (u8*)f->hdr + f->len;
-+
-+ f->type = WLAN_FSTYPE_BEACON;
-+
-+ /*-- Fixed Fields ----*/
-+ f->ts = (u64 *) OFFSET(f->hdr, WLAN_BEACON_OFF_TS);
-+ f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_BCN_INT);
-+ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_CAPINFO);
-+
-+ /*-- Information elements */
-+ ie_ptr = OFFSET(f->hdr, WLAN_BEACON_OFF_SSID);
-+ while (ie_ptr < end) {
-+ switch (IE_EID(ie_ptr)) {
-+ case WLAN_EID_SSID:
-+ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_SUPP_RATES:
-+ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_EXT_RATES:
-+ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_FH_PARMS:
-+ f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_DS_PARMS:
-+ f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_CF_PARMS:
-+ f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_IBSS_PARMS:
-+ f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_TIM:
-+ f->tim = (wlan_ie_tim_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_ERP_INFO:
-+ f->erp = (wlan_ie_erp_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_COUNTRY:
-+ /* was seen: 07 06 47 42 20 01 0D 14 */
-+ case WLAN_EID_NONERP:
-+ /* was seen from WRT54GS with OpenWrt: 2F 01 07 */
-+ case WLAN_EID_GENERIC:
-+ /* WPA: hostap code:
-+ if (pos[1] >= 4 &&
-+ pos[2] == 0x00 && pos[3] == 0x50 &&
-+ pos[4] == 0xf2 && pos[5] == 1) {
-+ wpa = pos;
-+ wpa_len = pos[1] + 2;
-+ }
-+ TI x4 mode: seen DD 04 08 00 28 00
-+ (08 00 28 is TI's OUI)
-+ last byte is probably 0/1 - disabled/enabled
-+ */
-+ case WLAN_EID_RSN:
-+ /* hostap does something with it:
-+ rsn = pos;
-+ rsn_len = pos[1] + 2;
-+ */
-+ break;
-+ default:
-+ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
-+ break;
-+ }
-+ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
-+ }
-+}
-+
-+
-+#ifdef UNUSED
-+void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t * f)
-+{
-+ f->type = WLAN_FSTYPE_ATIM;
-+ /*-- Fixed Fields ----*/
-+ /*-- Information elements */
-+}
-+#endif /* UNUSED */
-+
-+void
-+wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t * f)
-+{
-+ f->type = WLAN_FSTYPE_DISASSOC;
-+
-+ /*-- Fixed Fields ----*/
-+ f->reason = (u16 *) OFFSET(f->hdr, WLAN_DISASSOC_OFF_REASON);
-+
-+ /*-- Information elements */
-+}
-+
-+
-+void
-+wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t * f)
-+{
-+ u8 *ie_ptr;
-+ u8 *end = (u8*)f->hdr + f->len;
-+
-+
-+ f->type = WLAN_FSTYPE_ASSOCREQ;
-+
-+ /*-- Fixed Fields ----*/
-+ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_CAP_INFO);
-+ f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_LISTEN_INT);
-+
-+ /*-- Information elements */
-+ ie_ptr = OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_SSID);
-+ while (ie_ptr < end) {
-+ switch (IE_EID(ie_ptr)) {
-+ case WLAN_EID_SSID:
-+ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_SUPP_RATES:
-+ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_EXT_RATES:
-+ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ default:
-+ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
-+ break;
-+ }
-+ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
-+ }
-+}
-+
-+
-+void
-+wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t * f)
-+{
-+ f->type = WLAN_FSTYPE_ASSOCRESP;
-+
-+ /*-- Fixed Fields ----*/
-+ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_CAP_INFO);
-+ f->status = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_STATUS);
-+ f->aid = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_AID);
-+
-+ /*-- Information elements */
-+ f->supp_rates = (wlan_ie_supp_rates_t *)
-+ OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_SUPP_RATES);
-+}
-+
-+
-+void
-+wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t * f)
-+{
-+ u8 *ie_ptr;
-+ u8 *end = (u8*)f->hdr + f->len;
-+
-+ f->type = WLAN_FSTYPE_REASSOCREQ;
-+
-+ /*-- Fixed Fields ----*/
-+ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CAP_INFO);
-+ f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_LISTEN_INT);
-+ f->curr_ap = (u8 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CURR_AP);
-+
-+ /*-- Information elements */
-+ ie_ptr = OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_SSID);
-+ while (ie_ptr < end) {
-+ switch (IE_EID(ie_ptr)) {
-+ case WLAN_EID_SSID:
-+ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_SUPP_RATES:
-+ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_EXT_RATES:
-+ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ default:
-+ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
-+ break;
-+ }
-+ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
-+ }
-+}
-+
-+
-+void
-+wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t * f)
-+{
-+ f->type = WLAN_FSTYPE_REASSOCRESP;
-+
-+ /*-- Fixed Fields ----*/
-+ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_CAP_INFO);
-+ f->status = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_STATUS);
-+ f->aid = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_AID);
-+
-+ /*-- Information elements */
-+ f->supp_rates = (wlan_ie_supp_rates_t *)
-+ OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_SUPP_RATES);
-+}
-+
-+
-+void
-+wlan_mgmt_decode_probereq(wlan_fr_probereq_t * f)
-+{
-+ u8 *ie_ptr;
-+ u8 *end = (u8*)f->hdr + f->len;
-+
-+ f->type = WLAN_FSTYPE_PROBEREQ;
-+
-+ /*-- Fixed Fields ----*/
-+
-+ /*-- Information elements */
-+ ie_ptr = OFFSET(f->hdr, WLAN_PROBEREQ_OFF_SSID);
-+ while (ie_ptr < end) {
-+ switch (IE_EID(ie_ptr)) {
-+ case WLAN_EID_SSID:
-+ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_SUPP_RATES:
-+ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_EXT_RATES:
-+ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ default:
-+ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
-+ break;
-+ }
-+ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
-+ }
-+}
-+
-+
-+/* TODO: decoding of beacon and proberesp can be merged (similar structure) */
-+void
-+wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t * f)
-+{
-+ u8 *ie_ptr;
-+ u8 *end = (u8*)f->hdr + f->len;
-+
-+ f->type = WLAN_FSTYPE_PROBERESP;
-+
-+ /*-- Fixed Fields ----*/
-+ f->ts = (u64 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_TS);
-+ f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_BCN_INT);
-+ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_CAP_INFO);
-+
-+ /*-- Information elements */
-+ ie_ptr = OFFSET(f->hdr, WLAN_PROBERESP_OFF_SSID);
-+ while (ie_ptr < end) {
-+ switch (IE_EID(ie_ptr)) {
-+ case WLAN_EID_SSID:
-+ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_SUPP_RATES:
-+ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_EXT_RATES:
-+ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_FH_PARMS:
-+ f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_DS_PARMS:
-+ f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_CF_PARMS:
-+ f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr;
-+ break;
-+ case WLAN_EID_IBSS_PARMS:
-+ f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr;
-+ break;
-+ default:
-+ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
-+ break;
-+ }
-+
-+ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
-+ }
-+}
-+
-+
-+void
-+wlan_mgmt_decode_authen(wlan_fr_authen_t * f)
-+{
-+ u8 *ie_ptr;
-+ u8 *end = (u8*)f->hdr + f->len;
-+
-+ f->type = WLAN_FSTYPE_AUTHEN;
-+
-+ /*-- Fixed Fields ----*/
-+ f->auth_alg = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_ALG);
-+ f->auth_seq = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_SEQ);
-+ f->status = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_STATUS);
-+
-+ /*-- Information elements */
-+ ie_ptr = OFFSET(f->hdr, WLAN_AUTHEN_OFF_CHALLENGE);
-+ if ((ie_ptr < end) && (IE_EID(ie_ptr) == WLAN_EID_CHALLENGE)) {
-+ f->challenge = (wlan_ie_challenge_t *) ie_ptr;
-+ }
-+}
-+
-+
-+void
-+wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t * f)
-+{
-+ f->type = WLAN_FSTYPE_DEAUTHEN;
-+
-+ /*-- Fixed Fields ----*/
-+ f->reason = (u16 *) OFFSET(f->hdr, WLAN_DEAUTHEN_OFF_REASON);
-+
-+ /*-- Information elements */
-+}
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan_compat.h bt_kernel/drivers/net/wireless/tiacx/wlan_compat.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan_compat.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/wlan_compat.h 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,297 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+/***********************************************************************
-+** This code is based on elements which are
-+** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
-+** info@linux-wlan.com
-+** http://www.linux-wlan.com
-+*/
-+
-+/*=============================================================*/
-+/*------ Establish Platform Identity --------------------------*/
-+/*=============================================================*/
-+/* Key macros: */
-+/* WLAN_CPU_FAMILY */
-+#define WLAN_Ix86 1
-+#define WLAN_PPC 2
-+#define WLAN_Ix96 3
-+#define WLAN_ARM 4
-+#define WLAN_ALPHA 5
-+#define WLAN_MIPS 6
-+#define WLAN_HPPA 7
-+#define WLAN_SPARC 8
-+#define WLAN_SH 9
-+#define WLAN_x86_64 10
-+/* WLAN_CPU_CORE */
-+#define WLAN_I386CORE 1
-+#define WLAN_PPCCORE 2
-+#define WLAN_I296 3
-+#define WLAN_ARMCORE 4
-+#define WLAN_ALPHACORE 5
-+#define WLAN_MIPSCORE 6
-+#define WLAN_HPPACORE 7
-+/* WLAN_CPU_PART */
-+#define WLAN_I386PART 1
-+#define WLAN_MPC860 2
-+#define WLAN_MPC823 3
-+#define WLAN_I296SA 4
-+#define WLAN_PPCPART 5
-+#define WLAN_ARMPART 6
-+#define WLAN_ALPHAPART 7
-+#define WLAN_MIPSPART 8
-+#define WLAN_HPPAPART 9
-+/* WLAN_SYSARCH */
-+#define WLAN_PCAT 1
-+#define WLAN_MBX 2
-+#define WLAN_RPX 3
-+#define WLAN_LWARCH 4
-+#define WLAN_PMAC 5
-+#define WLAN_SKIFF 6
-+#define WLAN_BITSY 7
-+#define WLAN_ALPHAARCH 7
-+#define WLAN_MIPSARCH 9
-+#define WLAN_HPPAARCH 10
-+/* WLAN_HOSTIF (generally set on the command line, not detected) */
-+#define WLAN_PCMCIA 1
-+#define WLAN_ISA 2
-+#define WLAN_PCI 3
-+#define WLAN_USB 4
-+#define WLAN_PLX 5
-+
-+/* Note: the PLX HOSTIF above refers to some vendors implementations for */
-+/* PCI. It's a PLX chip that is a PCI to PCMCIA adapter, but it */
-+/* isn't a real PCMCIA host interface adapter providing all the */
-+/* card&socket services. */
-+
-+#ifdef __powerpc__
-+#ifndef __ppc__
-+#define __ppc__
-+#endif
-+#endif
-+
-+#if (defined(CONFIG_PPC) || defined(CONFIG_8xx))
-+#ifndef __ppc__
-+#define __ppc__
-+#endif
-+#endif
-+
-+#if defined(__x86_64__)
-+ #define WLAN_CPU_FAMILY WLAN_x86_64
-+ #define WLAN_SYSARCH WLAN_PCAT
-+#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
-+ #define WLAN_CPU_FAMILY WLAN_Ix86
-+ #define WLAN_CPU_CORE WLAN_I386CORE
-+ #define WLAN_CPU_PART WLAN_I386PART
-+ #define WLAN_SYSARCH WLAN_PCAT
-+#elif defined(__ppc__)
-+ #define WLAN_CPU_FAMILY WLAN_PPC
-+ #define WLAN_CPU_CORE WLAN_PPCCORE
-+ #if defined(CONFIG_MBX)
-+ #define WLAN_CPU_PART WLAN_MPC860
-+ #define WLAN_SYSARCH WLAN_MBX
-+ #elif defined(CONFIG_RPXLITE)
-+ #define WLAN_CPU_PART WLAN_MPC823
-+ #define WLAN_SYSARCH WLAN_RPX
-+ #elif defined(CONFIG_RPXCLASSIC)
-+ #define WLAN_CPU_PART WLAN_MPC860
-+ #define WLAN_SYSARCH WLAN_RPX
-+ #else
-+ #define WLAN_CPU_PART WLAN_PPCPART
-+ #define WLAN_SYSARCH WLAN_PMAC
-+ #endif
-+#elif defined(__arm__)
-+ #define WLAN_CPU_FAMILY WLAN_ARM
-+ #define WLAN_CPU_CORE WLAN_ARMCORE
-+ #define WLAN_CPU_PART WLAN_ARM_PART
-+ #define WLAN_SYSARCH WLAN_SKIFF
-+#elif defined(__alpha__)
-+ #define WLAN_CPU_FAMILY WLAN_ALPHA
-+ #define WLAN_CPU_CORE WLAN_ALPHACORE
-+ #define WLAN_CPU_PART WLAN_ALPHAPART
-+ #define WLAN_SYSARCH WLAN_ALPHAARCH
-+#elif defined(__mips__)
-+ #define WLAN_CPU_FAMILY WLAN_MIPS
-+ #define WLAN_CPU_CORE WLAN_MIPSCORE
-+ #define WLAN_CPU_PART WLAN_MIPSPART
-+ #define WLAN_SYSARCH WLAN_MIPSARCH
-+#elif defined(__hppa__)
-+ #define WLAN_CPU_FAMILY WLAN_HPPA
-+ #define WLAN_CPU_CORE WLAN_HPPACORE
-+ #define WLAN_CPU_PART WLAN_HPPAPART
-+ #define WLAN_SYSARCH WLAN_HPPAARCH
-+#elif defined(__sparc__)
-+ #define WLAN_CPU_FAMILY WLAN_SPARC
-+ #define WLAN_SYSARCH WLAN_SPARC
-+#elif defined(__sh__)
-+ #define WLAN_CPU_FAMILY WLAN_SH
-+ #define WLAN_SYSARCH WLAN_SHARCH
-+ #ifndef __LITTLE_ENDIAN__
-+ #define __LITTLE_ENDIAN__
-+ #endif
-+#else
-+ #error "No CPU identified!"
-+#endif
-+
-+/*
-+ Some big endian machines implicitly do all I/O in little endian mode.
-+
-+ In particular:
-+ Linux/PPC on PowerMacs (PCI)
-+ Arm/Intel Xscale (PCI)
-+
-+ This may also affect PLX boards and other BE &| PPC platforms;
-+ as new ones are discovered, add them below.
-+*/
-+
-+#if ((WLAN_SYSARCH == WLAN_SKIFF) || (WLAN_SYSARCH == WLAN_PMAC))
-+#define REVERSE_ENDIAN
-+#endif
-+
-+/*=============================================================*/
-+/*------ Hardware Portability Macros --------------------------*/
-+/*=============================================================*/
-+#if (WLAN_CPU_FAMILY == WLAN_PPC)
-+#define wlan_inw(a) in_be16((unsigned short *)((a)+_IO_BASE))
-+#define wlan_inw_le16_to_cpu(a) inw((a))
-+#define wlan_outw(v,a) out_be16((unsigned short *)((a)+_IO_BASE), (v))
-+#define wlan_outw_cpu_to_le16(v,a) outw((v),(a))
-+#else
-+#define wlan_inw(a) inw((a))
-+#define wlan_inw_le16_to_cpu(a) __cpu_to_le16(inw((a)))
-+#define wlan_outw(v,a) outw((v),(a))
-+#define wlan_outw_cpu_to_le16(v,a) outw(__cpu_to_le16((v)),(a))
-+#endif
-+
-+/*=============================================================*/
-+/*------ Bit settings -----------------------------------------*/
-+/*=============================================================*/
-+#define ieee2host16(n) __le16_to_cpu(n)
-+#define ieee2host32(n) __le32_to_cpu(n)
-+#define host2ieee16(n) __cpu_to_le16(n)
-+#define host2ieee32(n) __cpu_to_le32(n)
-+
-+/* for constants */
-+#ifdef __LITTLE_ENDIAN
-+ #define IEEE16(a,n) a = n, a##i = n,
-+#else
-+ #ifdef __BIG_ENDIAN
-+ /* shifts would produce gcc warnings. Oh well... */
-+ #define IEEE16(a,n) a = n, a##i = ((n&0xff)*256 + ((n&0xff00)/256)),
-+ #else
-+ #error give me endianness or give me death
-+ #endif
-+#endif
-+
-+/*=============================================================*/
-+/*------ Compiler Portability Macros --------------------------*/
-+/*=============================================================*/
-+#define __WLAN_ATTRIB_PACK__ __attribute__ ((packed))
-+#define __WLAN_PRAGMA_PACK1__
-+#define __WLAN_PRAGMA_PACKDFLT__
-+
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38))
-+ typedef struct device netdevice_t;
-+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4))
-+ typedef struct net_device netdevice_t;
-+#else
-+ #undef netdevice_t
-+ typedef struct net_device netdevice_t;
-+#endif
-+
-+#ifdef WIRELESS_EXT
-+#if (WIRELESS_EXT < 13)
-+struct iw_request_info {
-+ __u16 cmd; /* Wireless Extension command */
-+ __u16 flags; /* More to come ;-) */
-+};
-+#endif
-+#endif
-+
-+/* Interrupt handler backwards compatibility stuff */
-+#ifndef IRQ_NONE
-+#define IRQ_NONE
-+#define IRQ_HANDLED
-+typedef void irqreturn_t;
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) /* more or less */
-+#define WLAN_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
-+#define WLAN_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
-+#else
-+#define WLAN_MOD_INC_USE_COUNT
-+#define WLAN_MOD_DEC_USE_COUNT
-+#endif
-+
-+#ifndef ARPHRD_IEEE80211_PRISM
-+#define ARPHRD_IEEE80211_PRISM 802
-+#endif
-+
-+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
-+
-+/*============================================================================*
-+ * Constants *
-+ *============================================================================*/
-+#define WLAN_IEEE_OUI_LEN 3
-+/* unused
-+#define WLAN_ETHHDR_LEN 14
-+#define WLAN_ETHCONV_ENCAP 1
-+#define WLAN_ETHCONV_RFC1042 2
-+#define WLAN_ETHCONV_8021h 3
-+#define WLAN_MIN_ETHFRM_LEN 60
-+#define WLAN_MAX_ETHFRM_LEN 1514
-+*/
-+
-+/*============================================================================*
-+ * Types *
-+ *============================================================================*/
-+
-+/* local ether header type */
-+typedef struct wlan_ethhdr {
-+ u8 daddr[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 saddr[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 type __WLAN_ATTRIB_PACK__;
-+} wlan_ethhdr_t;
-+
-+/* local llc header type */
-+typedef struct wlan_llc {
-+ u8 dsap __WLAN_ATTRIB_PACK__;
-+ u8 ssap __WLAN_ATTRIB_PACK__;
-+ u8 ctl __WLAN_ATTRIB_PACK__;
-+} wlan_llc_t;
-+
-+/* local snap header type */
-+typedef struct wlan_snap {
-+ u8 oui[WLAN_IEEE_OUI_LEN] __WLAN_ATTRIB_PACK__;
-+ u16 type __WLAN_ATTRIB_PACK__;
-+} wlan_snap_t;
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan_hdr.h bt_kernel/drivers/net/wireless/tiacx/wlan_hdr.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan_hdr.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/wlan_hdr.h 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,497 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+/***********************************************************************
-+** This code is based on elements which are
-+** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
-+** info@linux-wlan.com
-+** http://www.linux-wlan.com
-+*/
-+
-+/* mini-doc
-+
-+Here are all 11b/11g/11a rates and modulations:
-+
-+ 11b 11g 11a
-+ --- --- ---
-+ 1 |B |B |
-+ 2 |Q |Q |
-+ 5.5|Cp |C p|
-+ 6 | |Od |O
-+ 9 | |od |o
-+11 |Cp |C p|
-+12 | |Od |O
-+18 | |od |o
-+22 | | p|
-+24 | |Od |O
-+33 | | p|
-+36 | |od |o
-+48 | |od |o
-+54 | |od |o
-+
-+Mandatory:
-+ B - DBPSK (Differential Binary Phase Shift Keying)
-+ Q - DQPSK (Differential Quaternary Phase Shift Keying)
-+ C - CCK (Complementary Code Keying, a form of DSSS
-+ (Direct Sequence Spread Spectrum) modulation)
-+ O - OFDM (Orthogonal Frequency Division Multiplexing)
-+Optional:
-+ o - OFDM
-+ d - CCK-OFDM (also known as DSSS-OFDM)
-+ p - PBCC (Packet Binary Convolutional Coding)
-+
-+The term CCK-OFDM may be used interchangeably with DSSS-OFDM
-+(the IEEE 802.11g-2003 standard uses the latter terminology).
-+In the CCK-OFDM, the PLCP header of the frame uses the CCK form of DSSS,
-+while the PLCP payload (the MAC frame) is modulated using OFDM.
-+
-+Basically, you must use CCK-OFDM if you have mixed 11b/11g environment,
-+or else (pure OFDM) 11b equipment may not realize that AP
-+is sending a packet and start sending its own one.
-+Sadly, looks like acx111 does not support CCK-OFDM, only pure OFDM.
-+
-+Re PBCC: avoid using it. It makes sense only if you have
-+TI "11b+" hardware. You _must_ use PBCC in order to reach 22Mbps on it.
-+
-+Preambles:
-+
-+Long preamble (at 1Mbit rate, takes 144 us):
-+ 16 bytes ones
-+ 2 bytes 0xF3A0 (lsb sent first)
-+PLCP header follows (at 1Mbit also):
-+ 1 byte Signal: speed, in 0.1Mbit units, except for:
-+ 33Mbit: 33 (instead of 330 - doesn't fit in octet)
-+ all CCK-OFDM rates: 30
-+ 1 byte Service
-+ 0,1,4: reserved
-+ 2: 1=locked clock
-+ 3: 1=PBCC
-+ 5: Length Extension (PBCC 22,33Mbit (11g only)) <-
-+ 6: Length Extension (PBCC 22,33Mbit (11g only)) <- BLACK MAGIC HERE
-+ 7: Length Extension <-
-+ 2 bytes Length (time needed to tx this frame)
-+ a) 5.5 Mbit/s CCK
-+ Length = octets*8/5.5, rounded up to integer
-+ b) 11 Mbit/s CCK
-+ Length = octets*8/11, rounded up to integer
-+ Service bit 7:
-+ 0 = rounding took less than 8/11
-+ 1 = rounding took more than or equal to 8/11
-+ c) 5.5 Mbit/s PBCC
-+ Length = (octets+1)*8/5.5, rounded up to integer
-+ d) 11 Mbit/s PBCC
-+ Length = (octets+1)*8/11, rounded up to integer
-+ Service bit 7:
-+ 0 = rounding took less than 8/11
-+ 1 = rounding took more than or equal to 8/11
-+ e) 22 Mbit/s PBCC
-+ Length = (octets+1)*8/22, rounded up to integer
-+ Service bits 6,7:
-+ 00 = rounding took less than 8/22ths
-+ 01 = rounding took 8/22...15/22ths
-+ 10 = rounding took 16/22ths or more.
-+ f) 33 Mbit/s PBCC
-+ Length = (octets+1)*8/33, rounded up to integer
-+ Service bits 5,6,7:
-+ 000 rounding took less than 8/33
-+ 001 rounding took 8/33...15/33
-+ 010 rounding took 16/33...23/33
-+ 011 rounding took 24/33...31/33
-+ 100 rounding took 32/33 or more
-+ 2 bytes CRC
-+
-+PSDU follows (up to 2346 bytes at selected rate)
-+
-+While Signal value alone is not enough to determine rate and modulation,
-+Signal+Service is always sufficient.
-+
-+Short preamble (at 1Mbit rate, takes 72 us):
-+ 7 bytes zeroes
-+ 2 bytes 0x05CF (lsb sent first)
-+PLCP header follows *at 2Mbit/s*. Format is the same as in long preamble.
-+PSDU follows (up to 2346 bytes at selected rate)
-+
-+OFDM preamble is completely different, uses OFDM
-+modulation from the start and thus easily identifiable.
-+Not shown here.
-+*/
-+
-+
-+/***********************************************************************
-+** Constants
-+*/
-+
-+#define WLAN_HDR_A3_LEN 24
-+#define WLAN_HDR_A4_LEN 30
-+/* IV structure:
-+** 3 bytes: Initialization Vector (24 bits)
-+** 1 byte: 0..5: padding, must be 0; 6..7: key selector (0-3)
-+*/
-+#define WLAN_WEP_IV_LEN 4
-+/* 802.11 says 2312 but looks like 2312 is a max size of _WEPed data_ */
-+#define WLAN_DATA_MAXLEN 2304
-+#define WLAN_WEP_ICV_LEN 4
-+#define WLAN_FCS_LEN 4
-+#define WLAN_A3FR_MAXLEN (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN)
-+#define WLAN_A4FR_MAXLEN (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN)
-+#define WLAN_A3FR_MAXLEN_FCS (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN + 4)
-+#define WLAN_A4FR_MAXLEN_FCS (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + 4)
-+#define WLAN_A3FR_MAXLEN_WEP (WLAN_A3FR_MAXLEN + 8)
-+#define WLAN_A4FR_MAXLEN_WEP (WLAN_A4FR_MAXLEN + 8)
-+#define WLAN_A3FR_MAXLEN_WEP_FCS (WLAN_A3FR_MAXLEN_FCS + 8)
-+#define WLAN_A4FR_MAXLEN_WEP_FCS (WLAN_A4FR_MAXLEN_FCS + 8)
-+
-+#define WLAN_BSS_TS_LEN 8
-+#define WLAN_SSID_MAXLEN 32
-+#define WLAN_BEACON_FR_MAXLEN (WLAN_HDR_A3_LEN + 334)
-+#define WLAN_ATIM_FR_MAXLEN (WLAN_HDR_A3_LEN + 0)
-+#define WLAN_DISASSOC_FR_MAXLEN (WLAN_HDR_A3_LEN + 2)
-+#define WLAN_ASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 48)
-+#define WLAN_ASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16)
-+#define WLAN_REASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 54)
-+#define WLAN_REASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16)
-+#define WLAN_PROBEREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 44)
-+#define WLAN_PROBERESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 78)
-+#define WLAN_AUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 261)
-+#define WLAN_DEAUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 2)
-+#define WLAN_CHALLENGE_IE_LEN 130
-+#define WLAN_CHALLENGE_LEN 128
-+#define WLAN_WEP_MAXKEYLEN 13
-+#define WLAN_WEP_NKEYS 4
-+
-+/*--- Frame Control Field -------------------------------------*/
-+/* Frame Types */
-+#define WLAN_FTYPE_MGMT 0x00
-+#define WLAN_FTYPE_CTL 0x01
-+#define WLAN_FTYPE_DATA 0x02
-+
-+/* Frame subtypes */
-+/* Management */
-+#define WLAN_FSTYPE_ASSOCREQ 0x00
-+#define WLAN_FSTYPE_ASSOCRESP 0x01
-+#define WLAN_FSTYPE_REASSOCREQ 0x02
-+#define WLAN_FSTYPE_REASSOCRESP 0x03
-+#define WLAN_FSTYPE_PROBEREQ 0x04
-+#define WLAN_FSTYPE_PROBERESP 0x05
-+#define WLAN_FSTYPE_BEACON 0x08
-+#define WLAN_FSTYPE_ATIM 0x09
-+#define WLAN_FSTYPE_DISASSOC 0x0a
-+#define WLAN_FSTYPE_AUTHEN 0x0b
-+#define WLAN_FSTYPE_DEAUTHEN 0x0c
-+
-+/* Control */
-+#define WLAN_FSTYPE_PSPOLL 0x0a
-+#define WLAN_FSTYPE_RTS 0x0b
-+#define WLAN_FSTYPE_CTS 0x0c
-+#define WLAN_FSTYPE_ACK 0x0d
-+#define WLAN_FSTYPE_CFEND 0x0e
-+#define WLAN_FSTYPE_CFENDCFACK 0x0f
-+
-+/* Data */
-+#define WLAN_FSTYPE_DATAONLY 0x00
-+#define WLAN_FSTYPE_DATA_CFACK 0x01
-+#define WLAN_FSTYPE_DATA_CFPOLL 0x02
-+#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03
-+#define WLAN_FSTYPE_NULL 0x04
-+#define WLAN_FSTYPE_CFACK 0x05
-+#define WLAN_FSTYPE_CFPOLL 0x06
-+#define WLAN_FSTYPE_CFACK_CFPOLL 0x07
-+
-+/*--- FC Constants v. 2.0 ------------------------------------*/
-+/* Each constant is defined twice: WF_CONST is in host */
-+/* byteorder, WF_CONSTi is in ieee byteorder. */
-+/* Usage: */
-+/* printf("the frame subtype is %X", WF_FC_FTYPEi & rx.fc); */
-+/* tx.fc = WF_FTYPE_CTLi | WF_FSTYPE_RTSi; */
-+/*------------------------------------------------------------*/
-+
-+enum {
-+/*--- Frame Control Field -------------------------------------*/
-+/* Protocol version: always 0 for current 802.11 standards */
-+IEEE16(WF_FC_PVER, 0x0003)
-+IEEE16(WF_FC_FTYPE, 0x000c)
-+IEEE16(WF_FC_FSTYPE, 0x00f0)
-+IEEE16(WF_FC_TODS, 0x0100)
-+IEEE16(WF_FC_FROMDS, 0x0200)
-+IEEE16(WF_FC_FROMTODS, 0x0300)
-+IEEE16(WF_FC_MOREFRAG, 0x0400)
-+IEEE16(WF_FC_RETRY, 0x0800)
-+/* Indicates PS mode in which STA will be after successful completion
-+** of current frame exchange sequence. Always 0 for AP frames */
-+IEEE16(WF_FC_PWRMGT, 0x1000)
-+/* What MoreData=1 means:
-+** From AP to STA in PS mode: don't sleep yet, I have more frames for you
-+** From Contention-Free (CF) Pollable STA in response to a CF-Poll:
-+** STA has buffered frames for transmission in response to next CF-Poll
-+** Bcast/mcast frames transmitted from AP:
-+** when additional bcast/mcast frames remain to be transmitted by AP
-+** during this beacon interval
-+** In all other cases MoreData=0 */
-+IEEE16(WF_FC_MOREDATA, 0x2000)
-+IEEE16(WF_FC_ISWEP, 0x4000)
-+IEEE16(WF_FC_ORDER, 0x8000)
-+
-+/* Frame Types */
-+IEEE16(WF_FTYPE_MGMT, 0x00)
-+IEEE16(WF_FTYPE_CTL, 0x04)
-+IEEE16(WF_FTYPE_DATA, 0x08)
-+
-+/* Frame subtypes */
-+/* Management */
-+IEEE16(WF_FSTYPE_ASSOCREQ, 0x00)
-+IEEE16(WF_FSTYPE_ASSOCRESP, 0x10)
-+IEEE16(WF_FSTYPE_REASSOCREQ, 0x20)
-+IEEE16(WF_FSTYPE_REASSOCRESP, 0x30)
-+IEEE16(WF_FSTYPE_PROBEREQ, 0x40)
-+IEEE16(WF_FSTYPE_PROBERESP, 0x50)
-+IEEE16(WF_FSTYPE_BEACON, 0x80)
-+IEEE16(WF_FSTYPE_ATIM, 0x90)
-+IEEE16(WF_FSTYPE_DISASSOC, 0xa0)
-+IEEE16(WF_FSTYPE_AUTHEN, 0xb0)
-+IEEE16(WF_FSTYPE_DEAUTHEN, 0xc0)
-+
-+/* Control */
-+IEEE16(WF_FSTYPE_PSPOLL, 0xa0)
-+IEEE16(WF_FSTYPE_RTS, 0xb0)
-+IEEE16(WF_FSTYPE_CTS, 0xc0)
-+IEEE16(WF_FSTYPE_ACK, 0xd0)
-+IEEE16(WF_FSTYPE_CFEND, 0xe0)
-+IEEE16(WF_FSTYPE_CFENDCFACK, 0xf0)
-+
-+/* Data */
-+IEEE16(WF_FSTYPE_DATAONLY, 0x00)
-+IEEE16(WF_FSTYPE_DATA_CFACK, 0x10)
-+IEEE16(WF_FSTYPE_DATA_CFPOLL, 0x20)
-+IEEE16(WF_FSTYPE_DATA_CFACK_CFPOLL, 0x30)
-+IEEE16(WF_FSTYPE_NULL, 0x40)
-+IEEE16(WF_FSTYPE_CFACK, 0x50)
-+IEEE16(WF_FSTYPE_CFPOLL, 0x60)
-+IEEE16(WF_FSTYPE_CFACK_CFPOLL, 0x70)
-+};
-+
-+
-+/***********************************************************************
-+** Macros
-+*/
-+
-+/*--- Duration Macros ----------------------------------------*/
-+/* Macros to get/set the bitfields of the Duration Field */
-+/* - the duration value is only valid when bit15 is zero */
-+/* - the firmware handles these values, so I'm not going */
-+/* these macros right now. */
-+/*------------------------------------------------------------*/
-+
-+/*--- Sequence Control Macros -------------------------------*/
-+/* Macros to get/set the bitfields of the Sequence Control */
-+/* Field. */
-+/*------------------------------------------------------------*/
-+#define WLAN_GET_SEQ_FRGNUM(n) ((u16)(n) & 0x000f)
-+#define WLAN_GET_SEQ_SEQNUM(n) (((u16)(n) & 0xfff0) >> 4)
-+
-+/*--- Data ptr macro -----------------------------------------*/
-+/* Creates a u8* to the data portion of a frame */
-+/* Assumes you're passing in a ptr to the beginning of the hdr*/
-+/*------------------------------------------------------------*/
-+#define WLAN_HDR_A3_DATAP(p) (((u8*)(p)) + WLAN_HDR_A3_LEN)
-+#define WLAN_HDR_A4_DATAP(p) (((u8*)(p)) + WLAN_HDR_A4_LEN)
-+
-+
-+/***********************************************************************
-+** Types
-+*/
-+
-+/* 802.11 header type
-+**
-+** Note the following:
-+** a1 *always* is receiver's mac or bcast/mcast
-+** a2 *always* is transmitter's mac, if a2 exists
-+** seq: [0:3] frag#, [4:15] seq# - used for dup detection
-+** (dups from retries have same seq#) */
-+typedef struct wlan_hdr {
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 a1[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 a2[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 a3[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+ u8 a4[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} wlan_hdr_t;
-+
-+/* Separate structs for use if frame type is known */
-+typedef struct wlan_hdr_a3 {
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 a1[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 a2[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 a3[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+} wlan_hdr_a3_t;
-+
-+typedef struct wlan_hdr_mgmt {
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+} wlan_hdr_mgmt_t;
-+
-+#ifdef NOT_NEEDED_YET
-+typedef struct { /* ad-hoc peer->peer (to/from DS = 0/0) */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+} ibss;
-+typedef struct { /* ap->sta (to/from DS = 0/1) */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+} fromap;
-+typedef struct { /* sta->ap (to/from DS = 1/0) */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+} toap;
-+typedef struct { /* wds->wds (to/from DS = 1/1), the only 4addr pkt */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} wds;
-+typedef struct { /* all management packets */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u16 seq __WLAN_ATTRIB_PACK__;
-+} mgmt;
-+typedef struct { /* has no body, just a FCS */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} rts;
-+typedef struct { /* has no body, just a FCS */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} cts;
-+typedef struct { /* has no body, just a FCS */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} ack;
-+typedef struct { /* has no body, just a FCS */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ /* NB: this one holds Assoc ID in dur field: */
-+ u16 aid __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} pspoll;
-+typedef struct { /* has no body, just a FCS */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} cfend;
-+typedef struct { /* has no body, just a FCS */
-+ u16 fc __WLAN_ATTRIB_PACK__;
-+ u16 dur __WLAN_ATTRIB_PACK__;
-+ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+} cfendcfack;
-+#endif
-+
-+/* Prism header emulation (monitor mode) */
-+typedef struct wlanitem_u32 {
-+ u32 did __WLAN_ATTRIB_PACK__;
-+ u16 status __WLAN_ATTRIB_PACK__;
-+ u16 len __WLAN_ATTRIB_PACK__;
-+ u32 data __WLAN_ATTRIB_PACK__;
-+} wlanitem_u32_t;
-+#define WLANITEM_STATUS_data_ok 0
-+#define WLANITEM_STATUS_no_value 1
-+#define WLANITEM_STATUS_invalid_itemname 2
-+#define WLANITEM_STATUS_invalid_itemdata 3
-+#define WLANITEM_STATUS_missing_itemdata 4
-+#define WLANITEM_STATUS_incomplete_itemdata 5
-+#define WLANITEM_STATUS_invalid_msg_did 6
-+#define WLANITEM_STATUS_invalid_mib_did 7
-+#define WLANITEM_STATUS_missing_conv_func 8
-+#define WLANITEM_STATUS_string_too_long 9
-+#define WLANITEM_STATUS_data_out_of_range 10
-+#define WLANITEM_STATUS_string_too_short 11
-+#define WLANITEM_STATUS_missing_valid_func 12
-+#define WLANITEM_STATUS_unknown 13
-+#define WLANITEM_STATUS_invalid_did 14
-+#define WLANITEM_STATUS_missing_print_func 15
-+
-+#define WLAN_DEVNAMELEN_MAX 16
-+typedef struct wlansniffrm {
-+ u32 msgcode __WLAN_ATTRIB_PACK__;
-+ u32 msglen __WLAN_ATTRIB_PACK__;
-+ u8 devname[WLAN_DEVNAMELEN_MAX] __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t hosttime __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t mactime __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t channel __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t rssi __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t sq __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t signal __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t noise __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t rate __WLAN_ATTRIB_PACK__;
-+ wlanitem_u32_t istx __WLAN_ATTRIB_PACK__; /* tx? 0:no 1:yes */
-+ wlanitem_u32_t frmlen __WLAN_ATTRIB_PACK__;
-+} wlansniffrm_t;
-+#define WLANSNIFFFRM 0x0041
-+#define WLANSNIFFFRM_hosttime 0x1041
-+#define WLANSNIFFFRM_mactime 0x2041
-+#define WLANSNIFFFRM_channel 0x3041
-+#define WLANSNIFFFRM_rssi 0x4041
-+#define WLANSNIFFFRM_sq 0x5041
-+#define WLANSNIFFFRM_signal 0x6041
-+#define WLANSNIFFFRM_noise 0x7041
-+#define WLANSNIFFFRM_rate 0x8041
-+#define WLANSNIFFFRM_istx 0x9041
-+#define WLANSNIFFFRM_frmlen 0xA041
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan_mgmt.h bt_kernel/drivers/net/wireless/tiacx/wlan_mgmt.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/net/wireless/tiacx/wlan_mgmt.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/net/wireless/tiacx/wlan_mgmt.h 2005-09-28 23:54:23.938287000 +0300
-@@ -0,0 +1,579 @@
-+/***********************************************************************
-+** Copyright (C) 2003 ACX100 Open Source Project
-+**
-+** The contents of this file are subject to the Mozilla Public
-+** License Version 1.1 (the "License"); you may not use this file
-+** except in compliance with the License. You may obtain a copy of
-+** the License at http://www.mozilla.org/MPL/
-+**
-+** Software distributed under the License is distributed on an "AS
-+** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+** implied. See the License for the specific language governing
-+** rights and limitations under the License.
-+**
-+** Alternatively, the contents of this file may be used under the
-+** terms of the GNU Public License version 2 (the "GPL"), in which
-+** case the provisions of the GPL are applicable instead of the
-+** above. If you wish to allow the use of your version of this file
-+** only under the terms of the GPL and not to allow others to use
-+** your version of this file under the MPL, indicate your decision
-+** by deleting the provisions above and replace them with the notice
-+** and other provisions required by the GPL. If you do not delete
-+** the provisions above, a recipient may use your version of this
-+** file under either the MPL or the GPL.
-+** ---------------------------------------------------------------------
-+** Inquiries regarding the ACX100 Open Source Project can be
-+** made directly to:
-+**
-+** acx100-users@lists.sf.net
-+** http://acx100.sf.net
-+** ---------------------------------------------------------------------
-+*/
-+
-+/***********************************************************************
-+** This code is based on elements which are
-+** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
-+** info@linux-wlan.com
-+** http://www.linux-wlan.com
-+*/
-+
-+/***********************************************************************
-+** Constants
-+*/
-+
-+/*-- Information Element IDs --------------------*/
-+#define WLAN_EID_SSID 0
-+#define WLAN_EID_SUPP_RATES 1
-+#define WLAN_EID_FH_PARMS 2
-+#define WLAN_EID_DS_PARMS 3
-+#define WLAN_EID_CF_PARMS 4
-+#define WLAN_EID_TIM 5
-+#define WLAN_EID_IBSS_PARMS 6
-+#define WLAN_EID_COUNTRY 7 /* 802.11d */
-+#define WLAN_EID_FH_HOP_PARMS 8 /* 802.11d */
-+#define WLAN_EID_FH_TABLE 9 /* 802.11d */
-+#define WLAN_EID_REQUEST 10 /* 802.11d */
-+/*-- values 11-15 reserved --*/
-+#define WLAN_EID_CHALLENGE 16
-+/*-- values 17-31 reserved for challenge text extension --*/
-+#define WLAN_EID_ERP_INFO 42
-+#define WLAN_EID_NONERP 47 /* was seen from WRT54GS with OpenWrt */
-+#define WLAN_EID_RSN 48
-+#define WLAN_EID_EXT_RATES 50
-+#define WLAN_EID_GENERIC 221
-+
-+#if 0
-+#define WLAN_EID_PWR_CONSTRAINT 32 /* 11H PowerConstraint */
-+#define WLAN_EID_PWR_CAP 33 /* 11H PowerCapability */
-+#define WLAN_EID_TPC_REQUEST 34 /* 11H TPC Request */
-+#define WLAN_EID_TPC_REPORT 35 /* 11H TPC Report */
-+#define WLAN_EID_SUPP_CHANNELS 36 /* 11H Supported Channels */
-+#define WLAN_EID_CHANNEL_SWITCH 37 /* 11H ChannelSwitch */
-+#define WLAN_EID_MEASURE_REQUEST 38 /* 11H MeasurementRequest */
-+#define WLAN_EID_MEASURE_REPORT 39 /* 11H MeasurementReport */
-+#define WLAN_EID_QUIET_ID 40 /* 11H Quiet */
-+#define WLAN_EID_IBSS_DFS_ID 41 /* 11H IBSS_DFS */
-+#endif
-+
-+/*-- Reason Codes -------------------------------*/
-+#define WLAN_MGMT_REASON_RSVD 0
-+#define WLAN_MGMT_REASON_UNSPEC 1
-+#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID 2
-+#define WLAN_MGMT_REASON_DEAUTH_LEAVING 3
-+#define WLAN_MGMT_REASON_DISASSOC_INACTIVE 4
-+#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY 5
-+#define WLAN_MGMT_REASON_CLASS2_NONAUTH 6
-+#define WLAN_MGMT_REASON_CLASS3_NONASSOC 7
-+#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT 8
-+#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH 9
-+
-+/*-- Status Codes -------------------------------*/
-+#define WLAN_MGMT_STATUS_SUCCESS 0
-+#define WLAN_MGMT_STATUS_UNSPEC_FAILURE 1
-+#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED 10
-+#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC 11
-+#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC 12
-+#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG 13
-+#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ 14
-+#define WLAN_MGMT_STATUS_CHALLENGE_FAIL 15
-+#define WLAN_MGMT_STATUS_AUTH_TIMEOUT 16
-+#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY 17
-+#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES 18
-+/* p80211b additions */
-+#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOSHORT 19
-+#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOPBCC 20
-+#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOAGILITY 21
-+
-+/*-- Auth Algorithm Field ---------------------------*/
-+#define WLAN_AUTH_ALG_OPENSYSTEM 0
-+#define WLAN_AUTH_ALG_SHAREDKEY 1
-+
-+/*-- Management Frame Field Offsets -------------*/
-+/* Note: Not all fields are listed because of variable lengths */
-+/* Note: These offsets are from the start of the frame data */
-+
-+#define WLAN_BEACON_OFF_TS 0
-+#define WLAN_BEACON_OFF_BCN_INT 8
-+#define WLAN_BEACON_OFF_CAPINFO 10
-+#define WLAN_BEACON_OFF_SSID 12
-+
-+#define WLAN_DISASSOC_OFF_REASON 0
-+
-+#define WLAN_ASSOCREQ_OFF_CAP_INFO 0
-+#define WLAN_ASSOCREQ_OFF_LISTEN_INT 2
-+#define WLAN_ASSOCREQ_OFF_SSID 4
-+
-+#define WLAN_ASSOCRESP_OFF_CAP_INFO 0
-+#define WLAN_ASSOCRESP_OFF_STATUS 2
-+#define WLAN_ASSOCRESP_OFF_AID 4
-+#define WLAN_ASSOCRESP_OFF_SUPP_RATES 6
-+
-+#define WLAN_REASSOCREQ_OFF_CAP_INFO 0
-+#define WLAN_REASSOCREQ_OFF_LISTEN_INT 2
-+#define WLAN_REASSOCREQ_OFF_CURR_AP 4
-+#define WLAN_REASSOCREQ_OFF_SSID 10
-+
-+#define WLAN_REASSOCRESP_OFF_CAP_INFO 0
-+#define WLAN_REASSOCRESP_OFF_STATUS 2
-+#define WLAN_REASSOCRESP_OFF_AID 4
-+#define WLAN_REASSOCRESP_OFF_SUPP_RATES 6
-+
-+#define WLAN_PROBEREQ_OFF_SSID 0
-+
-+#define WLAN_PROBERESP_OFF_TS 0
-+#define WLAN_PROBERESP_OFF_BCN_INT 8
-+#define WLAN_PROBERESP_OFF_CAP_INFO 10
-+#define WLAN_PROBERESP_OFF_SSID 12
-+
-+#define WLAN_AUTHEN_OFF_AUTH_ALG 0
-+#define WLAN_AUTHEN_OFF_AUTH_SEQ 2
-+#define WLAN_AUTHEN_OFF_STATUS 4
-+#define WLAN_AUTHEN_OFF_CHALLENGE 6
-+
-+#define WLAN_DEAUTHEN_OFF_REASON 0
-+
-+enum {
-+IEEE16(WF_MGMT_CAP_ESS, 0x0001)
-+IEEE16(WF_MGMT_CAP_IBSS, 0x0002)
-+/* In (re)assoc request frames by STA:
-+** Pollable=0, PollReq=0: STA is not CF-Pollable
-+** 0 1: STA is CF-Pollable, not requesting to be placed on the CF-Polling list
-+** 1 0: STA is CF-Pollable, requesting to be placed on the CF-Polling list
-+** 1 1: STA is CF-Pollable, requesting never to be polled
-+** In beacon, proberesp, (re)assoc resp frames by AP:
-+** 0 0: No point coordinator at AP
-+** 0 1: Point coordinator at AP for delivery only (no polling)
-+** 1 0: Point coordinator at AP for delivery and polling
-+** 1 1: Reserved */
-+IEEE16(WF_MGMT_CAP_CFPOLLABLE, 0x0004)
-+IEEE16(WF_MGMT_CAP_CFPOLLREQ, 0x0008)
-+/* 1=non-WEP data frames are disallowed */
-+IEEE16(WF_MGMT_CAP_PRIVACY, 0x0010)
-+/* In beacon, proberesp, (re)assocresp by AP/AdHoc:
-+** 1=use of shortpre is allowed ("I can receive shortpre") */
-+IEEE16(WF_MGMT_CAP_SHORT, 0x0020)
-+IEEE16(WF_MGMT_CAP_PBCC, 0x0040)
-+IEEE16(WF_MGMT_CAP_AGILITY, 0x0080)
-+/* In (re)assoc request frames by STA:
-+** 1=short slot time implemented and enabled
-+** NB: AP shall use long slot time beginning at the next Beacon after assoc
-+** of STA with this bit set to 0
-+** In beacon, proberesp, (re)assoc resp frames by AP:
-+** currently used slot time value: 0/1 - long/short */
-+IEEE16(WF_MGMT_CAP_SHORTSLOT, 0x0400)
-+/* In (re)assoc request frames by STA: 1=CCK-OFDM is implemented and enabled
-+** In beacon, proberesp, (re)assoc resp frames by AP/AdHoc:
-+** 1=CCK-OFDM is allowed */
-+IEEE16(WF_MGMT_CAP_CCKOFDM, 0x2000)
-+};
-+
-+
-+/***********************************************************************
-+** Types
-+*/
-+
-+/* Information Element types */
-+
-+/* prototype structure, all IEs start with these members */
-+typedef struct wlan_ie {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+} wlan_ie_t;
-+
-+/*-- Service Set Identity (SSID) -----------------*/
-+typedef struct wlan_ie_ssid {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u8 ssid[1] __WLAN_ATTRIB_PACK__; /* may be zero */
-+} wlan_ie_ssid_t;
-+
-+/*-- Supported Rates -----------------------------*/
-+typedef struct wlan_ie_supp_rates {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u8 rates[1] __WLAN_ATTRIB_PACK__; /* had better be at LEAST one! */
-+} wlan_ie_supp_rates_t;
-+
-+/*-- FH Parameter Set ----------------------------*/
-+typedef struct wlan_ie_fh_parms {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u16 dwell __WLAN_ATTRIB_PACK__;
-+ u8 hopset __WLAN_ATTRIB_PACK__;
-+ u8 hoppattern __WLAN_ATTRIB_PACK__;
-+ u8 hopindex __WLAN_ATTRIB_PACK__;
-+} wlan_ie_fh_parms_t;
-+
-+/*-- DS Parameter Set ----------------------------*/
-+typedef struct wlan_ie_ds_parms {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u8 curr_ch __WLAN_ATTRIB_PACK__;
-+} wlan_ie_ds_parms_t;
-+
-+/*-- CF Parameter Set ----------------------------*/
-+typedef struct wlan_ie_cf_parms {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u8 cfp_cnt __WLAN_ATTRIB_PACK__;
-+ u8 cfp_period __WLAN_ATTRIB_PACK__;
-+ u16 cfp_maxdur __WLAN_ATTRIB_PACK__;
-+ u16 cfp_durremaining __WLAN_ATTRIB_PACK__;
-+} wlan_ie_cf_parms_t;
-+
-+/*-- TIM ------------------------------------------*/
-+typedef struct wlan_ie_tim {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u8 dtim_cnt __WLAN_ATTRIB_PACK__;
-+ u8 dtim_period __WLAN_ATTRIB_PACK__;
-+ u8 bitmap_ctl __WLAN_ATTRIB_PACK__;
-+ u8 virt_bm[1] __WLAN_ATTRIB_PACK__;
-+} wlan_ie_tim_t;
-+
-+/*-- IBSS Parameter Set ---------------------------*/
-+typedef struct wlan_ie_ibss_parms {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u16 atim_win __WLAN_ATTRIB_PACK__;
-+} wlan_ie_ibss_parms_t;
-+
-+/*-- Challenge Text ------------------------------*/
-+typedef struct wlan_ie_challenge {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ u8 challenge[1] __WLAN_ATTRIB_PACK__;
-+} wlan_ie_challenge_t;
-+
-+/*-- ERP (42) -------------------------------------*/
-+typedef struct wlan_ie_erp {
-+ u8 eid __WLAN_ATTRIB_PACK__;
-+ u8 len __WLAN_ATTRIB_PACK__;
-+ /* bit 0:Non ERP present
-+ ** 1:Use Protection
-+ ** 2:Barker Preamble mode
-+ ** 3-7:reserved */
-+ u8 erp __WLAN_ATTRIB_PACK__;
-+} wlan_ie_erp_t;
-+
-+/* Types for parsing mgmt frames */
-+
-+/* prototype structure, all mgmt frame types will start with these members */
-+typedef struct wlan_fr_mgmt {
-+ u16 type;
-+ u16 len; /* DOES NOT include FCS */
-+ wlan_hdr_t *hdr;
-+ /* used for target specific data, skb in Linux */
-+ /*-- fixed fields -----------*/
-+ /*-- info elements ----------*/
-+} wlan_fr_mgmt_t;
-+
-+/*-- Beacon ---------------------------------------*/
-+typedef struct wlan_fr_beacon {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u64 *ts;
-+ u16 *bcn_int;
-+ u16 *cap_info;
-+ /*-- info elements ----------*/
-+ wlan_ie_ssid_t *ssid;
-+ wlan_ie_supp_rates_t *supp_rates;
-+ wlan_ie_supp_rates_t *ext_rates;
-+ wlan_ie_fh_parms_t *fh_parms;
-+ wlan_ie_ds_parms_t *ds_parms;
-+ wlan_ie_cf_parms_t *cf_parms;
-+ wlan_ie_ibss_parms_t *ibss_parms;
-+ wlan_ie_tim_t *tim; /* in beacon only, not proberesp */
-+ wlan_ie_erp_t *erp; /* in beacon only, not proberesp */
-+} wlan_fr_beacon_t;
-+#define wlan_fr_proberesp wlan_fr_beacon
-+#define wlan_fr_proberesp_t wlan_fr_beacon_t
-+
-+/*-- IBSS ATIM ------------------------------------*/
-+typedef struct wlan_fr_ibssatim {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ /*-- info elements ----------*/
-+ /* this frame type has a null body */
-+} wlan_fr_ibssatim_t;
-+
-+/*-- Disassociation -------------------------------*/
-+typedef struct wlan_fr_disassoc {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u16 *reason;
-+ /*-- info elements ----------*/
-+} wlan_fr_disassoc_t;
-+
-+/*-- Association Request --------------------------*/
-+typedef struct wlan_fr_assocreq {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u16 *cap_info;
-+ u16 *listen_int;
-+ /*-- info elements ----------*/
-+ wlan_ie_ssid_t *ssid;
-+ wlan_ie_supp_rates_t *supp_rates;
-+ wlan_ie_supp_rates_t *ext_rates;
-+} wlan_fr_assocreq_t;
-+
-+/*-- Association Response -------------------------*/
-+typedef struct wlan_fr_assocresp {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u16 *cap_info;
-+ u16 *status;
-+ u16 *aid;
-+ /*-- info elements ----------*/
-+ wlan_ie_supp_rates_t *supp_rates;
-+ wlan_ie_supp_rates_t *ext_rates;
-+} wlan_fr_assocresp_t;
-+
-+/*-- Reassociation Request ------------------------*/
-+typedef struct wlan_fr_reassocreq {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u16 *cap_info;
-+ u16 *listen_int;
-+ u8 *curr_ap;
-+ /*-- info elements ----------*/
-+ wlan_ie_ssid_t *ssid;
-+ wlan_ie_supp_rates_t *supp_rates;
-+ wlan_ie_supp_rates_t *ext_rates;
-+} wlan_fr_reassocreq_t;
-+
-+/*-- Reassociation Response -----------------------*/
-+typedef struct wlan_fr_reassocresp {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u16 *cap_info;
-+ u16 *status;
-+ u16 *aid;
-+ /*-- info elements ----------*/
-+ wlan_ie_supp_rates_t *supp_rates;
-+ wlan_ie_supp_rates_t *ext_rates;
-+} wlan_fr_reassocresp_t;
-+
-+/*-- Probe Request --------------------------------*/
-+typedef struct wlan_fr_probereq {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ /*-- info elements ----------*/
-+ wlan_ie_ssid_t *ssid;
-+ wlan_ie_supp_rates_t *supp_rates;
-+ wlan_ie_supp_rates_t *ext_rates;
-+} wlan_fr_probereq_t;
-+
-+/*-- Authentication -------------------------------*/
-+typedef struct wlan_fr_authen {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u16 *auth_alg;
-+ u16 *auth_seq;
-+ u16 *status;
-+ /*-- info elements ----------*/
-+ wlan_ie_challenge_t *challenge;
-+} wlan_fr_authen_t;
-+
-+/*-- Deauthenication -----------------------------*/
-+typedef struct wlan_fr_deauthen {
-+ u16 type;
-+ u16 len;
-+ wlan_hdr_t *hdr;
-+ /*-- fixed fields -----------*/
-+ u16 *reason;
-+ /*-- info elements ----------*/
-+} wlan_fr_deauthen_t;
-+
-+/* Types for building mgmt frames */
-+
-+/* Warning. Several types used in below structs are
-+** in fact variable length. Use structs with such fields with caution */
-+typedef struct auth_frame_body {
-+ u16 auth_alg __WLAN_ATTRIB_PACK__;
-+ u16 auth_seq __WLAN_ATTRIB_PACK__;
-+ u16 status __WLAN_ATTRIB_PACK__;
-+ wlan_ie_challenge_t challenge __WLAN_ATTRIB_PACK__;
-+} auth_frame_body_t;
-+
-+typedef struct assocresp_frame_body {
-+ u16 cap_info __WLAN_ATTRIB_PACK__;
-+ u16 status __WLAN_ATTRIB_PACK__;
-+ u16 aid __WLAN_ATTRIB_PACK__;
-+ wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
-+} assocresp_frame_body_t;
-+
-+typedef struct reassocreq_frame_body {
-+ u16 cap_info __WLAN_ATTRIB_PACK__;
-+ u16 listen_int __WLAN_ATTRIB_PACK__;
-+ u8 current_ap[ETH_ALEN] __WLAN_ATTRIB_PACK__;
-+ wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
-+/* access to this one is disabled since ssid_t is variable length: */
-+ /* wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__; */
-+} reassocreq_frame_body_t;
-+
-+typedef struct reassocresp_frame_body {
-+ u16 cap_info __WLAN_ATTRIB_PACK__;
-+ u16 status __WLAN_ATTRIB_PACK__;
-+ u16 aid __WLAN_ATTRIB_PACK__;
-+ wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
-+} reassocresp_frame_body_t;
-+
-+typedef struct deauthen_frame_body {
-+ u16 reason __WLAN_ATTRIB_PACK__;
-+} deauthen_frame_body_t;
-+
-+typedef struct disassoc_frame_body {
-+ u16 reason __WLAN_ATTRIB_PACK__;
-+} disassoc_frame_body_t;
-+
-+typedef struct probereq_frame_body {
-+ wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
-+ wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
-+} probereq_frame_body_t;
-+
-+typedef struct proberesp_frame_body {
-+ u8 timestamp[8] __WLAN_ATTRIB_PACK__;
-+ u16 beacon_int __WLAN_ATTRIB_PACK__;
-+ u16 cap_info __WLAN_ATTRIB_PACK__;
-+ wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
-+/* access to these is disabled since ssid_t is variable length: */
-+ /* wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__; */
-+ /* fhps_t fhps __WLAN_ATTRIB_PACK__; */
-+ /* dsps_t dsps __WLAN_ATTRIB_PACK__; */
-+ /* cfps_t cfps __WLAN_ATTRIB_PACK__; */
-+} proberesp_frame_body_t;
-+
-+
-+/***********************************************************************
-+** Functions
-+*/
-+
-+/* Helpers for parsing mgmt frames */
-+void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t *f);
-+void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t *f);
-+void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t *f);
-+void wlan_mgmt_decode_authen(wlan_fr_authen_t *f);
-+void wlan_mgmt_decode_beacon(wlan_fr_beacon_t *f);
-+void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t *f);
-+void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t *f);
-+void wlan_mgmt_decode_probereq(wlan_fr_probereq_t *f);
-+void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t *f);
-+void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t *f);
-+void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t *f);
-+
-+/* Helpers for building mgmt frames */
-+static inline u8*
-+wlan_fill_ie_ssid(u8 *p, int len, const char *ssid)
-+{
-+ struct wlan_ie_ssid *ie = (void*)p;
-+ ie->eid = WLAN_EID_SSID;
-+ ie->len = len;
-+ memcpy(ie->ssid, ssid, len);
-+ return p + len + 2;
-+}
-+/* This controls whether we create 802.11g 'ext supported rates' IEs
-+** or just create overlong 'supported rates' IEs instead
-+** (non-11g compliant) */
-+#define WE_OBEY_802_11G 1
-+static inline u8*
-+wlan_fill_ie_rates(u8 *p, int len, const u8 *rates)
-+{
-+ struct wlan_ie_supp_rates *ie = (void*)p;
-+#if WE_OBEY_802_11G
-+ if (len > 8 ) len = 8;
-+#endif
-+ /* supported rates (1 to 8 octets) */
-+ ie->eid = WLAN_EID_SUPP_RATES;
-+ ie->len = len;
-+ memcpy(ie->rates, rates, len);
-+ return p + len + 2;
-+}
-+/* This one wouldn't create an IE at all if not needed */
-+static inline u8*
-+wlan_fill_ie_rates_ext(u8 *p, int len, const u8 *rates)
-+{
-+ struct wlan_ie_supp_rates *ie = (void*)p;
-+#if !WE_OBEY_802_11G
-+ return p;
-+#endif
-+ len -= 8;
-+ if (len < 0) return p;
-+ /* ext supported rates */
-+ ie->eid = WLAN_EID_EXT_RATES;
-+ ie->len = len;
-+ memcpy(ie->rates, rates+8, len);
-+ return p + len + 2;
-+}
-+static inline u8*
-+wlan_fill_ie_ds_parms(u8 *p, int channel)
-+{
-+ struct wlan_ie_ds_parms *ie = (void*)p;
-+ ie->eid = WLAN_EID_DS_PARMS;
-+ ie->len = 1;
-+ ie->curr_ch = channel;
-+ return p + sizeof(*ie);
-+}
-+static inline u8*
-+wlan_fill_ie_ibss_parms(u8 *p, int atim_win)
-+{
-+ struct wlan_ie_ibss_parms *ie = (void*)p;
-+ ie->eid = WLAN_EID_IBSS_PARMS;
-+ ie->len = 2;
-+ ie->atim_win = atim_win;
-+ return p + sizeof(*ie);
-+}
-+static inline u8*
-+wlan_fill_ie_tim(u8 *p, int rem, int period, int bcast,
-+ int ofs, int len, const u8 *vbm)
-+{
-+ struct wlan_ie_tim *ie = (void*)p;
-+ ie->eid = WLAN_EID_TIM;
-+ ie->len = len + 3;
-+ ie->dtim_cnt = rem;
-+ ie->dtim_period = period;
-+ ie->bitmap_ctl = ofs | (bcast!=0);
-+ if (vbm)
-+ memcpy(ie->virt_bm, vbm, len); /* min 1 byte */
-+ else
-+ ie->virt_bm[0] = 0;
-+ return p + len + 3 + 2;
-+}
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/pci/.gitignore bt_kernel/drivers/pci/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/pci/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/pci/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,4 +0,0 @@
--classlist.h
--devlist.h
--gen-devlist
--
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/ssi/omap-tsc2101.c bt_kernel/drivers/ssi/omap-tsc2101.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/ssi/omap-tsc2101.c 2005-10-30 17:44:18.415932786 +0200
-+++ bt_kernel/drivers/ssi/omap-tsc2101.c 2005-10-22 03:52:45.687256000 +0300
-@@ -36,10 +36,11 @@
- #include <asm/arch/hardware.h>
- #include <asm/hardware/tsc2101.h>
- #include <asm/arch/gpioexpander.h>
-+#include <asm/arch/gpio.h>
-
- #include "omap-tsc2101.h"
-
--#if CONFIG_ARCH_OMAP16XX
-+#if CONFIG_ARCH_OMAP1
- #include <../drivers/ssi/omap-uwire.h>
- #else
- #error "Unsupported configuration"
-@@ -66,27 +67,28 @@
- if (count++ == 0) {
- int ret = 0;
- /* set the Mux to provide MCLK to TSC2101 */
-- if (machine_is_omap_h3()) {
-+ if (machine_is_omap_h3())
- ret = omap_cfg_reg(V5_1710_MCLK_ON);
-- } else {
-- if (machine_is_omap_h2()) {
-- ret = omap_cfg_reg(R10_1610_MCLK_ON);
-+ else if (machine_is_omap_h2())
-+ ret = omap_cfg_reg(R10_1610_MCLK_ON);
-+ else if (machine_is_h6300 ())
-+ ret = omap_cfg_reg(R10_1510_MCLK_ON);
-+
-+ if (!cpu_is_omap1510 ()) {
-+ /* Get the MCLK */
-+ tsc2101_mclk_ck = clk_get(NULL, "mclk");
-+ if (NULL == tsc2101_mclk_ck) {
-+ printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
-+ ret = -EPERM;
-+ goto done;
- }
-- }
--
-- /* Get the MCLK */
-- tsc2101_mclk_ck = clk_get(NULL, "mclk");
-- if (NULL == tsc2101_mclk_ck) {
-- printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
-- ret = -EPERM;
-- goto done;
-- }
-- if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
-- printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
-- ret = -EPERM;
-- goto done;
-- }
-- clk_enable(tsc2101_mclk_ck);
-+ if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
-+ printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
-+ ret = -EPERM;
-+ goto done;
-+ }
-+ clk_enable(tsc2101_mclk_ck);
-+ } /* if (!cpu_is_omap1510 ()) */
-
- ret = omap_tsc2101_configure();
-
-@@ -116,10 +118,16 @@
- }
- }
-
-- /* Release the MCLK */
-- clk_disable(tsc2101_mclk_ck);
-- clk_put(tsc2101_mclk_ck);
-- tsc2101_mclk_ck = NULL;
-+ if (!cpu_is_omap1510 ()) {
-+ /* Release the MCLK */
-+ clk_disable(tsc2101_mclk_ck);
-+ clk_put(tsc2101_mclk_ck);
-+ tsc2101_mclk_ck = NULL;
-+ }
-+
-+#if defined(CONFIG_MACH_OMAP_H6300)
-+ omap_free_gpio(8);
-+#endif
-
- module_put(THIS_MODULE);
- }
-@@ -150,7 +158,10 @@
- return;
- }
- }
-- if (machine_is_omap_h3()) {
-+ if (machine_is_omap_h3() || machine_is_h6300 ()) {
-+
-+ if (machine_is_h6300 ())
-+ omap_set_gpio_dataout (8, 0);
-
- ret =
- omap_uwire_data_transfer(0, ((page << 11) | (address << 5)),
-@@ -159,6 +170,8 @@
- printk(KERN_ERR
- "uwire-write returned error for address %x\n",
- address);
-+ if (machine_is_h6300 ())
-+ omap_set_gpio_dataout (8, 1);
- return;
- }
- ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0);
-@@ -166,10 +179,14 @@
- printk(KERN_ERR
- "uwire-write returned error for address %x\n",
- address);
-+ if (machine_is_h6300 ())
-+ omap_set_gpio_dataout (8, 1);
- return;
- }
-- }
-
-+ if (machine_is_h6300 ())
-+ omap_set_gpio_dataout (8, 1);
-+ }
- }
-
- void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs)
-@@ -178,9 +195,13 @@
- if (machine_is_omap_h2()) {
- cs = 1;
- }
-- if (machine_is_omap_h3()) {
-+ if (machine_is_omap_h3() || machine_is_h6300 ()) {
- cs = 0;
- }
-+
-+ if (machine_is_h6300 ())
-+ omap_set_gpio_dataout(8, 0);
-+
- (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11)
- | (startaddress << 5)),
- 16, 0, NULL, 1);
-@@ -188,6 +209,9 @@
- omap_uwire_data_transfer(cs, 0, 0, 16, data, 1);
- }
- omap_uwire_data_transfer(cs, 0, 0, 16, data, 0);
-+
-+ if (machine_is_h6300 ())
-+ omap_set_gpio_dataout(8, 1);
- }
-
- u16 omap_tsc2101_read(int page, u8 address)
-@@ -228,9 +252,24 @@
- omap_cfg_reg(N14_1610_UWIRE_CS0);
- omap_uwire_configure_mode(0, uwire_flags);
- }
-+ if (machine_is_h6300()) {
-+ uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
-+ omap_cfg_reg(N14_1510_UWIRE_CS0);
-+ omap_uwire_configure_mode(0, uwire_flags);
-+
-+ omap_request_gpio(8);
-+ omap_set_gpio_dataout(8, 0);
-+ omap_set_gpio_direction (8, 0);
-+ }
-
- /* Configure MCLK enable */
-- omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);
-+ if (cpu_is_omap16xx() || cpu_is_omap1710())
-+ omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);
-+ if (machine_is_h6300()) {
-+ omap_cfg_reg(V19_1510_UWIRE_SCLK);
-+ omap_cfg_reg(W21_1510_UWIRE_SDO);
-+ omap_cfg_reg(U18_1510_UWIRE_SDI);
-+ }
-
- return 0;
- }
-@@ -243,5 +282,5 @@
-
- MODULE_AUTHOR("Texas Instruments");
- MODULE_DESCRIPTION
-- ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
-+ ("Glue audio driver for the TI OMAP1510/1610/OMAP1710 TSC2101 codec.");
- MODULE_LICENSE("GPL");
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/ssi/omap-uwire.c bt_kernel/drivers/ssi/omap-uwire.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/ssi/omap-uwire.c 2005-10-30 17:44:18.435929603 +0200
-+++ bt_kernel/drivers/ssi/omap-uwire.c 2005-08-12 13:46:22.016114000 +0300
-@@ -212,6 +212,10 @@
- omap_cfg_reg(N14_1610_UWIRE_CS0);
- omap_cfg_reg(P15_1610_UWIRE_CS3);
- }
-+ if (machine_is_h6300 ()) {
-+ omap_cfg_reg(N14_1510_UWIRE_CS0);
-+ omap_cfg_reg(P15_1510_UWIRE_CS3);
-+ }
- if (machine_is_omap_perseus2()) {
- /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
- int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/Kconfig bt_kernel/drivers/telephony/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/Kconfig 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/telephony/Kconfig 2005-10-06 02:34:39.057478000 +0300
-@@ -41,7 +41,18 @@
- help
- Say Y here to configure in PCMCIA service support for the Quicknet
- cards manufactured by Quicknet Technologies, Inc. This changes the
-- card initialization code to work with the card manager daemon.
-+ card initialization code to work with the card manager daemon.
-+
-+config GSM_H6300
-+ tristate "H6300 P5186 GSM/GPRS DRIVER"
-+ depends on PHONE && I2C && PCA9535
-+ help
-+ Bluetooth H6300 P5186 gsm/gprs driver.
-+ This driver provides the firmware loading mechanism for the P5185
-+ gsm/gprs hardware in iPAQ h6300.
-+
-+ Say Y here to compile support for P5186 gsm/gprs devices into the
-+ kernel or say M to compile it as module (h6300_gsm).
-
- endmenu
-
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/Makefile bt_kernel/drivers/telephony/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/Makefile 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/telephony/Makefile 2005-10-06 02:34:39.057478000 +0300
-@@ -2,6 +2,7 @@
- # Makefile for drivers/telephony
- #
-
--obj-$(CONFIG_PHONE) += phonedev.o
--obj-$(CONFIG_PHONE_IXJ) += ixj.o
--obj-$(CONFIG_PHONE_IXJ_PCMCIA) += ixj_pcmcia.o
-+obj-$(CONFIG_PHONE) += phonedev.o
-+obj-$(CONFIG_PHONE_IXJ) += ixj.o
-+obj-$(CONFIG_PHONE_IXJ_PCMCIA) += ixj_pcmcia.o
-+obj-$(CONFIG_GSM_H6300) += omap/
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/h6300_gsm_led.c bt_kernel/drivers/telephony/omap/h6300_gsm_led.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/h6300_gsm_led.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/telephony/omap/h6300_gsm_led.c 2005-10-06 02:34:39.057478000 +0300
-@@ -0,0 +1,40 @@
-+/*
-+ * GSM interface driver helper for controlling bluetooth leds available in iPAQ h6300.
-+ *
-+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
-+ *
-+ * 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/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/arch/gpio.h>
-+
-+/*
-+ * Low level access for disabling h6300 gsm led.
-+ *
-+ * TODO: implement for h6300
-+ */
-+void h6300_clear_gsm_led(int led_num)
-+{
-+ printk(KERN_NOTICE "h6300_gsm_led.c h6300_clear_gsm_led() done\n");
-+ //hx4700_set_led(led_num, 0, 16);
-+}
-+EXPORT_SYMBOL(h6300_clear_gsm_led);
-+
-+/*
-+ * Low level access for setting up the gsm led.
-+ *
-+ * TODO: implement for h6300
-+ */
-+void h6300_set_gsm_led(int led_num, int duty_time, int cycle_time)
-+{
-+ printk(KERN_NOTICE "h6300_gsm_led.c h6300_set_gsm_led() done\n");
-+}
-+EXPORT_SYMBOL(h6300_set_gsm_led);
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/h6300_gsm_led.h bt_kernel/drivers/telephony/omap/h6300_gsm_led.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/h6300_gsm_led.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/telephony/omap/h6300_gsm_led.h 2005-10-06 02:34:39.057478000 +0300
-@@ -0,0 +1,10 @@
-+#ifndef H6300_GSM_LED_H_
-+#define H6300_GSM_LED_H_
-+
-+#define INDEX_GSM_LED 1
-+
-+void h6300_clear_gsm_led(int led_num);
-+void h6300_set_gsm_led(int led_num, int duty_time, int cycle_time);
-+
-+
-+#endif /*H6300_GSM_LED_H_*/
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/h6300_gsm_p5186.c bt_kernel/drivers/telephony/omap/h6300_gsm_p5186.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/h6300_gsm_p5186.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/telephony/omap/h6300_gsm_p5186.c 2005-10-20 20:57:07.074687000 +0300
-@@ -0,0 +1,171 @@
-+/*
-+ * Wavecom P5186 GPRS and GSM module driver for iPAQ h6300.
-+ *
-+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
-+ *
-+ * 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/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/arch/gpio.h>
-+
-+#include <asm/arch/pca9535.h>
-+#include <asm/arch/h6300_uart_info.h>
-+#include "h6300_gsm_led.h"
-+
-+static void
-+h6300_gsm_configure(struct uart_omap_port *up, int enable)
-+{
-+ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_configure() started, enable = %d\n", enable);
-+
-+ // printk( KERN_NOTICE "h6300 configure bluetooth: %d\n", enable );
-+ if (enable == 0) {
-+ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_OFF); // turn off gpio
-+ mdelay(5);
-+ h6300_clear_gsm_led(INDEX_GSM_LED);
-+ }
-+ else if (enable == 1) {
-+ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_ON); // turn on gpio
-+ mdelay(5);
-+ }
-+ else if (enable == 2) {
-+ h6300_set_gsm_led(INDEX_GSM_LED, 16, 16);
-+ }
-+ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_configure() done\n");
-+}
-+
-+static void
-+h6300_gsm_set_txrx(struct uart_omap_port *up, int txrx)
-+{
-+ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_set_txrx(), txrx = %d done\n", txrx);
-+ /* do nothing */
-+}
-+
-+static int
-+h6300_gsm_get_txrx(struct uart_omap_port *up)
-+{
-+ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_get_txrx() done\n");
-+ /* do nothing */
-+ return 0;
-+}
-+
-+static int
-+h6300_gsm_probe(struct device *dev)
-+{
-+ int ii;
-+ int curVal;
-+
-+ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
-+/*
-+ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_probe() started\n");
-+ for (ii = 0; ii < 8; ii++)
-+ {
-+ curVal = pca9535_gpio_read(ii);
-+ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
-+ }
-+ for (ii = 10; ii < 18; ii++)
-+ {
-+ curVal = pca9535_gpio_read(ii);
-+ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
-+ }
-+ printk(KERN_NOTICE "\nfirst check done\n");
-+*/
-+ pca9535_gpio_direction(GPIO_I2C_GPRS_RESET, GPIO_DIR_OUTPUT); // set gpio direction to be output
-+ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_ON); // turn on gpio
-+ mdelay(200);
-+
-+ pca9535_gpio_direction(GPIO_I2C_MIC_OP_EN, GPIO_DIR_OUTPUT); // set gpio direction to be output
-+ pca9535_gpio_write(GPIO_I2C_MIC_OP_EN, GPIO_VALUE_ON); // turn on gpio
-+ mdelay(200);
-+
-+ pca9535_gpio_direction(GPIO_I2C_SPK_OP_PD, GPIO_DIR_OUTPUT); // set gpio direction to be output
-+ pca9535_gpio_write(GPIO_I2C_SPK_OP_PD, GPIO_VALUE_ON); // pd = pulldown?, normal off = on
-+
-+ mdelay(200);
-+
-+ //pca9535_gpio_direction(
-+ /* configure bluetooth UART */
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_RXD_MD);
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_TXD_MD);
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_CTS_MD);
-+ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_RTS_MD);
-+
-+ funcs->configure = h6300_gsm_configure;
-+ funcs->set_txrx = h6300_gsm_set_txrx;
-+ funcs->get_txrx = h6300_gsm_get_txrx;
-+
-+ /* Make sure the LED is off */
-+ h6300_clear_gsm_led(INDEX_GSM_LED);
-+/*
-+ for (ii = 0; ii < 8; ii++)
-+ {
-+ curVal = pca9535_gpio_read(ii);
-+ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
-+ }
-+ for (ii = 10; ii < 18; ii++)
-+ {
-+ curVal = pca9535_gpio_read(ii);
-+ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
-+ }
-+*/
-+ printk(KERN_NOTICE "\nh6300_gsm_p5186.c h6300_gsm_probe() done\n");
-+
-+ return 0;
-+}
-+
-+static int
-+h6300_gsm_remove(struct device *dev)
-+{
-+ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
-+
-+ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_remove() started\n");
-+
-+ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, 0); // turn off gpio
-+
-+ funcs->configure = NULL;
-+ funcs->set_txrx = NULL;
-+ funcs->get_txrx = NULL;
-+
-+ /* Make sure the LED is off */
-+ h6300_clear_gsm_led(INDEX_GSM_LED);
-+
-+ printk(KERN_NOTICE "h6300_gsm_p5186.c, h6300_gsm_remove() done\n");
-+
-+ return 0;
-+}
-+
-+static struct device_driver gsm_driver = {
-+ .name = "h6300_gsm",
-+ .bus = &platform_bus_type,
-+ .probe = h6300_gsm_probe,
-+ .remove = h6300_gsm_remove,
-+};
-+
-+static int __init
-+h6300_gsm_init(void)
-+{
-+ printk(KERN_NOTICE "h6300 GSM Driver init()\n");
-+ return driver_register(&gsm_driver);
-+}
-+
-+static void __exit
-+h6300_gsm_exit(void)
-+{
-+ printk(KERN_NOTICE "h6300 GSM Driver exit()\n");
-+ driver_unregister(&gsm_driver);
-+}
-+
-+module_init(h6300_gsm_init);
-+module_exit(h6300_gsm_exit);
-+
-+MODULE_AUTHOR("Mika Laitio, <lamikr@cc.jyu.fi>");
-+MODULE_DESCRIPTION("iPAQ h6300 Wavecom P5186 GPRS and GSM module driver.");
-+MODULE_LICENSE("GPL");
-+
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/Makefile bt_kernel/drivers/telephony/omap/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/telephony/omap/Makefile 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/telephony/omap/Makefile 2005-10-06 02:34:39.057478000 +0300
-@@ -0,0 +1,6 @@
-+#
-+# Makefile for the Linux iPAQ H6300 BRF6100 Bluetooth device drivers.
-+#
-+
-+h6300_gsm-objs := h6300_gsm_led.o h6300_gsm_p5186.o
-+obj-$(CONFIG_GSM_H6300) += h6300_gsm.o
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/usb/gadget/omap_udc.c bt_kernel/drivers/usb/gadget/omap_udc.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/usb/gadget/omap_udc.c 2005-10-30 17:44:18.495920054 +0200
-+++ bt_kernel/drivers/usb/gadget/omap_udc.c 2005-10-30 16:32:39.609796000 +0200
-@@ -622,17 +622,24 @@
- || (cpu_is_omap15xx() && length < ep->maxpacket)) {
- txdma_ctrl = UDC_TXN_EOT | length;
- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-- length, 1, sync_mode);
-+ length, 1, sync_mode, 0, 0);
- } else {
- length = min(length / ep->maxpacket,
- (unsigned) UDC_TXN_TSC + 1);
- txdma_ctrl = length;
-- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
-- ep->ep.maxpacket >> 1, length, sync_mode);
-+ if (machine_is_h6300())
-+ omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-+ ep->ep.maxpacket, length, sync_mode,
-+ 0, 0);
-+ else
-+ omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
-+ ep->ep.maxpacket >> 1, length, sync_mode,
-+ 0, 0);
- length *= ep->maxpacket;
- }
- omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
-- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
-+ OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
-+ 0, 0);
-
- omap_start_dma(ep->lch);
- ep->dma_counter = dma_csac(ep->lch);
-@@ -675,11 +682,19 @@
- packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
- packets = min(packets, (unsigned)UDC_RXN_TC + 1);
- req->dma_bytes = packets * ep->ep.maxpacket;
-- omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
-- ep->ep.maxpacket >> 1, packets,
-- OMAP_DMA_SYNC_ELEMENT);
-+ if (machine_is_h6300())
-+ omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-+ ep->ep.maxpacket, packets,
-+ OMAP_DMA_SYNC_ELEMENT,
-+ 0, 0);
-+ else
-+ omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
-+ ep->ep.maxpacket >> 1, packets,
-+ OMAP_DMA_SYNC_ELEMENT,
-+ 0, 0);
- omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
-- OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
-+ OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
-+ 0, 0);
- ep->dma_counter = DMA_DEST_LAST(ep->lch);
-
- UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
-@@ -822,7 +837,8 @@
- omap_set_dma_dest_params(ep->lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
-- (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
-+ (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
-+ 0, 0);
- }
- } else {
- status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
-@@ -833,7 +849,8 @@
- omap_set_dma_src_params(ep->lch,
- OMAP_DMA_PORT_TIPB,
- OMAP_DMA_AMODE_CONSTANT,
-- (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
-+ (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
-+ 0, 0);
- /* EMIFF */
- omap_set_dma_dest_burst_mode(ep->lch,
- OMAP_DMA_DATA_BURST_4);
-@@ -2103,7 +2120,7 @@
- /* boards that don't have VBUS sensing can't autogate 48MHz;
- * can't enter deep sleep while a gadget driver is active.
- */
-- if (machine_is_omap_innovator() || machine_is_omap_osk())
-+ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_h6300())
- omap_vbus_session(&udc->gadget, 1);
-
- done:
-@@ -2121,7 +2138,7 @@
- if (!driver || driver != udc->driver)
- return -EINVAL;
-
-- if (machine_is_omap_innovator() || machine_is_omap_osk())
-+ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_h6300())
- omap_vbus_session(&udc->gadget, 0);
-
- if (udc->transceiver)
-@@ -2729,7 +2746,7 @@
- hmc = HMC_1510;
- type = "(unknown)";
-
-- if (machine_is_omap_innovator()) {
-+ if (machine_is_omap_innovator() || machine_is_h6300()) {
- /* just set up software VBUS detect, and then
- * later rig it so we always report VBUS.
- * FIXME without really sensing VBUS, we can't
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/logo/.gitignore bt_kernel/drivers/video/logo/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/logo/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/drivers/video/logo/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,7 +0,0 @@
--#
--# Generated files
--#
--*_mono.c
--*_vga16.c
--*_clut224.c
--*_gray256.c
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/lcd_h6300.c bt_kernel/drivers/video/omap/lcd_h6300.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/lcd_h6300.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/video/omap/lcd_h6300.c 2005-10-30 16:32:39.609796000 +0200
-@@ -0,0 +1,107 @@
-+/*
-+ * File: drivers/video/omap_new/lcd-h6300.c
-+ *
-+ * LCD panel support for the TI OMAP1510 Innovator board
-+ *
-+ * Copyright (C) 2004 Nokia Corporation
-+ * Author: Imre Deak <imre.deak@nokia.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#include <linux/module.h>
-+#include <asm/io.h>
-+
-+#include <asm/hardware/clock.h>
-+#include <asm/arch/omapfb.h>
-+
-+/* #define OMAPFB_DBG 1 */
-+
-+#include "debug.h"
-+
-+//static struct clk *h6300_lcd_ck;
-+
-+static int h6300_panel_init(struct omapfb_device *fbdev)
-+{
-+ DBGENTER(1);
-+/*
-+ if ((h6300_lcd_ck = clk_get (NULL, "lcd_ck")) == NULL) {
-+ printk(KERN_ERR "Unable to get the clock LCD_CK!!!\n");
-+ return -EPERM;
-+ } clk_enable (h6300_lcd_ck);
-+*/
-+ DBGLEAVE(1);
-+ printk(KERN_INFO "lcd_h6300.c: h6300_panel_init() done\n");
-+ return 0;
-+}
-+
-+static void h6300_panel_cleanup(void)
-+{
-+ DBGENTER(1);
-+/*
-+ if (h6300_lcd_ck) {
-+ clk_disable (h6300_lcd_ck);
-+ clk_put (h6300_lcd_ck);
-+ h6300_lcd_ck = NULL;
-+ }
-+*/
-+ DBGLEAVE(1);
-+ printk(KERN_INFO "lcd_h6300.c: h6300_panel_cleanup() done\n");
-+}
-+
-+static int h6300_panel_enable(void)
-+{
-+ DBGENTER(1);
-+ DBGLEAVE(1);
-+ printk(KERN_INFO "lcd_h6300.c: h6300_panel_enable() done\n");
-+ return 0;
-+}
-+
-+static void h6300_panel_disable(void)
-+{
-+ DBGENTER(1);
-+ DBGLEAVE(1);
-+ printk(KERN_INFO "lcd_h6300.c: h6300_panel_disable() done\n");
-+}
-+
-+static unsigned long h6300_panel_get_caps(void)
-+{
-+ printk(KERN_INFO "lcd_h6300.c: h6300_panel_get_caps() called\n");
-+ return 0;
-+}
-+
-+struct lcd_panel h6300_panel = {
-+ .name = "h6300",
-+ .config = OMAP_LCDC_PANEL_TFT,
-+
-+ .bpp = 16,
-+ .data_lines = 16,
-+ .x_res = 240,
-+ .y_res = 320,
-+ .pixel_clock = 21000,
-+ .hsw = 12,
-+ .hfp = 10,
-+ .hbp = 10,
-+ .vsw = 3,
-+ .vfp = 10,
-+ .vbp = 3,
-+ .pcd = 0,
-+
-+ .init = h6300_panel_init,
-+ .cleanup = h6300_panel_cleanup,
-+ .enable = h6300_panel_enable,
-+ .disable = h6300_panel_disable,
-+ .get_caps = h6300_panel_get_caps,
-+};
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/Makefile bt_kernel/drivers/video/omap/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/Makefile 2005-10-30 17:44:18.730882654 +0200
-+++ bt_kernel/drivers/video/omap/Makefile 2005-10-22 03:52:45.687256000 +0300
-@@ -21,6 +21,7 @@
- objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
- objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
- objs-y$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o
-+objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_H6300) += lcd_h6300.o
-
- omapfb-objs := $(objs-yy)
-
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/omapfb.h bt_kernel/drivers/video/omap/omapfb.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/omapfb.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/drivers/video/omap/omapfb.h 2005-08-12 13:46:22.016114000 +0300
-@@ -0,0 +1,325 @@
-+/*
-+ * File: drivers/video/omap_new/omapfb.c
-+ *
-+ * Framebuffer driver for TI OMAP boards
-+ *
-+ * Copyright (C) 2004 Nokia Corporation
-+ * Author: Imre Deak <imre.deak@nokia.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+
-+#ifndef __OMAPFB_H
-+#define __OMAPFB_H
-+
-+/* IOCTL commands. */
-+
-+#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
-+#define OMAP_IOR(num, dtype) _IOR('O', num, dtype)
-+#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype)
-+#define OMAP_IO(num) _IO('O', num)
-+
-+#define OMAPFB_FILLRECT OMAP_IOW(0, struct fb_fillrect)
-+#define OMAPFB_COPYAREA OMAP_IOW(1, struct fb_copyarea)
-+#define OMAPFB_IMAGEBLIT OMAP_IOW(2, struct fb_image)
-+
-+#define OMAPFB_TRANSPARENT_BLIT OMAP_IOW(30, struct fb_image)
-+#define OMAPFB_MIRROR OMAP_IOW(31, int)
-+#define OMAPFB_SCALE OMAP_IOW(32, struct fb_scale)
-+#define OMAPFB_SELECT_VIS_FRAME OMAP_IOW(33, int)
-+#define OMAPFB_SELECT_SRC_FRAME OMAP_IOW(34, int)
-+#define OMAPFB_SELECT_DST_FRAME OMAP_IOW(35, int)
-+#define OMAPFB_GET_FRAME_OFFSET OMAP_IOWR(36, struct fb_frame_offset)
-+#define OMAPFB_SYNC_GFX OMAP_IO(37)
-+#define OMAPFB_VSYNC OMAP_IO(38)
-+#define OMAPFB_LATE_ACTIVATE OMAP_IO(39)
-+#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, enum fb_update_mode)
-+#define OMAPFB_UPDATE_WINDOW OMAP_IOW(41, struct fb_update_window)
-+#define OMAPFB_GET_CAPS OMAP_IOR(42, unsigned long)
-+#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, enum fb_update_mode)
-+#define OMAPFB_GET_GFX_STATUS OMAP_IOR(44, unsigned long)
-+
-+#define FBCAPS_GENERIC_MASK 0x00000fff
-+#define FBCAPS_LCDC_MASK 0x00fff000
-+#define FBCAPS_PANEL_MASK 0xff000000
-+
-+#define FBCAPS_MANUAL_UPDATE 0x00001000
-+#define FBCAPS_SET_BACKLIGHT 0x01000000
-+
-+enum omapfb_gfx_status {
-+ OMAPFB_GFX_STATUS_OK = 0,
-+ OMAPFB_GFX_STATUS_CHANGED
-+};
-+
-+#define OMAPFB_UPDATE_FAILED 0x01
-+#define OMAPFB_FILLRECT_FAILED 0x02
-+#define OMAPFB_COPYAREA_FAILED 0x04
-+#define OMAPFB_IMGBLIT_FAILED 0x08
-+
-+struct fb_copyarea_ext {
-+ __u32 dx;
-+ __u32 dy;
-+ __u32 width;
-+ __u32 height;
-+ __u32 sx;
-+ __u32 sy;
-+ __u32 trans_color;
-+ __u32 rev_dir;
-+};
-+
-+struct fb_scale {
-+ unsigned int xscale, yscale;
-+};
-+
-+struct fb_frame_offset {
-+ unsigned int idx;
-+ unsigned long offset;
-+};
-+
-+struct fb_update_window {
-+ unsigned int x, y;
-+ unsigned int width, height;
-+};
-+
-+enum fb_update_mode {
-+ FB_UPDATE_DISABLED = 0,
-+ FB_AUTO_UPDATE,
-+ FB_MANUAL_UPDATE
-+};
-+
-+#ifdef __KERNEL__
-+
-+#include <linux/completion.h>
-+#include <linux/interrupt.h>
-+#include <linux/fb.h>
-+
-+#define OMAPFB_DEVICE "omapfb"
-+#define OMAPFB_DRIVER "omapfb"
-+
-+#define PRNERR(fmt, args...) printk(KERN_ERR OMAPFB_DRIVER ": " fmt, ## args)
-+
-+#define GFX_FIFO_SIZE 2
-+
-+#define LCD_PANEL_TFT 0x01
-+
-+#define OMAP_LCDC_INV_VSYNC 0x01
-+#define OMAP_LCDC_INV_HSYNC 0x02
-+#define OMAP_LCDC_INV_PIX_CLOCK 0x04
-+#define OMAP_LCDC_INV_OUTPUT_EN 0x08
-+#define OMAP_LCDC_HSVS_RISING_EDGE 0x10
-+#define OMAP_LCDC_HSVS_OPPOSITE 0x20
-+
-+struct lcdc_video_mode {
-+ u16 x_res, y_res;
-+ u32 pixel_clock; /* In kHz */
-+ int bpp;
-+ u8 hsw; /* Horizontal synchronization pulse width */
-+ u8 hfp; /* Horizontal front porch */
-+ u8 hbp; /* Horizontal back porch */
-+ u8 vsw; /* Vertical synchronization pulse width */
-+ u8 vfp; /* Vertical front porch */
-+ u8 vbp; /* Vertical back porch */
-+ u8 acb; /* ac-bias pin frequency */
-+ u8 pcd; /* Pixel clock divider (this will change) */
-+ u8 flags;
-+};
-+
-+struct lcd_panel {
-+ const char *name;
-+ int config;
-+ int signals;
-+ struct lcdc_video_mode *video_mode;
-+
-+ int (*init) (struct lcd_panel *panel);
-+ void (*cleanup) (struct lcd_panel *panel);
-+ int (*enable) (struct lcd_panel *panel);
-+ void (*disable) (struct lcd_panel *panel);
-+ unsigned long (*get_caps)(struct lcd_panel *panel);
-+ int (*set_bklight_level)(struct lcd_panel *panel,
-+ unsigned int level);
-+ unsigned int (*get_bklight_level)(struct lcd_panel *panel);
-+ unsigned int (*get_bklight_max) (struct lcd_panel *panel);
-+};
-+
-+struct omapfb_device;
-+
-+struct lcd_ctrl {
-+ const char *name;
-+ void *data;
-+ int (*init) (struct omapfb_device *fbdev);
-+ void (*cleanup) (struct omapfb_device *fbdev);
-+ void (*get_mem_layout) (struct omapfb_device *fbdev,
-+ unsigned long *size,
-+ unsigned long *fb_org);
-+ unsigned long (*get_caps) (struct omapfb_device *fbdev);
-+ int (*set_update_mode)(struct omapfb_device *fbdev,
-+ enum fb_update_mode mode);
-+ enum fb_update_mode (*get_update_mode)(struct omapfb_device *fbdev);
-+ int (*update_window) (struct omapfb_device *fbdev,
-+ struct fb_update_window *win);
-+ void (*suspend) (struct omapfb_device *fbdev);
-+ void (*resume) (struct omapfb_device *fbdev);
-+ void (*change_mode) (struct omapfb_device *fbdev);
-+};
-+
-+enum omapfb_state {
-+ OMAPFB_DISABLED = 0,
-+ OMAPFB_SUSPENDED= 99,
-+ OMAPFB_ACTIVE = 100
-+};
-+
-+struct gfx_lchannel {
-+ int lch_num;
-+ struct gfx_lchannel *next, *prev;
-+};
-+
-+struct gfx_dma {
-+ spinlock_t spinlock;
-+
-+ struct completion sync_complete; /* Signalled when the
-+ fifo gets empty */
-+ volatile int done; /* Indicates the
-+ end of a DMA chain
-+ transfer */
-+ struct gfx_lchannel fifo[GFX_FIFO_SIZE];
-+ struct gfx_lchannel *f_head, *f_tail; /* Process and insert
-+ points on the
-+ fifo */
-+ struct gfx_lchannel *f_chain_end; /* Points to the new
-+ chain end */
-+ struct semaphore f_free; /* # of free lch-s */
-+ int f_run; /* # of active lch-s */
-+ int f_wait; /* # of lch-s
-+ waiting */
-+ struct tasklet_struct dequeue_tasklet; /* Processes new DMA
-+ chain transfers on
-+ the fifo */
-+};
-+
-+#define OMAPFB_RQUEUE_SIZE 20
-+
-+struct omapfb_fillrect_params
-+{
-+ struct fb_info *fbi;
-+ struct fb_fillrect rect;
-+};
-+
-+struct omapfb_copyarea_params
-+{
-+ struct fb_info *fbi;
-+ struct fb_copyarea_ext area;
-+};
-+
-+struct omapfb_update_window_params
-+{
-+ struct fb_info *fbi;
-+ struct fb_update_window win;
-+};
-+
-+struct omapfb_imageblit_params
-+{
-+ struct fb_info *fbi;
-+ struct fb_image image;
-+ int flags;
-+};
-+
-+union req_params
-+{
-+ /* All possible requests are to be listed here */
-+ struct omapfb_fillrect_params fillrect;
-+ struct omapfb_copyarea_params copyarea;
-+ struct omapfb_update_window_params update_window;
-+ struct omapfb_imageblit_params imageblit;
-+};
-+
-+struct omapfb_request
-+{
-+ struct list_head entry;
-+ int (*function)(void *par);
-+ union req_params par;
-+};
-+
-+struct omapfb_rqueue
-+{
-+ spinlock_t lock;
-+ struct list_head free_list;
-+ struct list_head pending_list;
-+ struct completion rqueue_empty;
-+ struct semaphore free_sema;
-+ struct omapfb_request req_pool[OMAPFB_RQUEUE_SIZE];
-+ struct work_struct work;
-+ unsigned long status;
-+};
-+
-+struct omapfb_device {
-+ int state;
-+ int ext_lcdc; /* Using external
-+ LCD controller */
-+ void *lcddma_base; /* MPU virtual
-+ address */
-+ dma_addr_t lcddma_handle; /* Bus physical
-+ address */
-+ unsigned long lcddma_mem_size;
-+ unsigned long palette_org; /* Palette offset into
-+ lcddma_base/handle */
-+ unsigned long frame0_org, frame1_org; /* Frame offsets for
-+ back and front
-+ frame buffers into
-+ lcddma_base/handle */
-+ unsigned long vis_frame_org; /* Offset of visible
-+ frame buffer.
-+ = frame0/1_org */
-+ unsigned long src_frame_org; /* Offset of source
-+ frame for drawing
-+ operations.
-+ = frame0/1_org */
-+ unsigned long dst_frame_org; /* Offset of dest
-+ frame for drawing
-+ operations.
-+ = frame0/1_org */
-+ unsigned long view_org; /* View offset into
-+ lcddma_base/handle+
-+ vis_frame_org.
-+ Used for panning */
-+ unsigned long palette_size;
-+ int xscale, yscale, mirror; /* transformations.
-+ rotate is stored in
-+ fb_info->var */
-+
-+ u32 pseudo_palette[17];
-+
-+ struct gfx_dma gfx; /* Accelerator */
-+ struct omapfb_rqueue rqueue;
-+ struct lcd_panel *panel; /* LCD panel */
-+ struct lcd_ctrl *ctrl; /* LCD controller */
-+
-+ struct fb_info *fb_info; /* Linux fbdev
-+ framework data */
-+ struct device *dev;
-+};
-+
-+extern struct lcd_panel h3_panel;
-+extern struct lcd_panel h2_panel;
-+extern struct lcd_panel p2_panel;
-+extern struct lcd_panel osk_panel;
-+extern struct lcd_panel innovator1610_panel;
-+extern struct lcd_panel innovator1510_panel;
-+extern struct lcd_panel h6300_panel;
-+
-+extern struct lcd_ctrl omapfb_lcdc_ctrl;
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* __OMAPFB_H */
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/omapfb_main.c bt_kernel/drivers/video/omap/omapfb_main.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/drivers/video/omap/omapfb_main.c 2005-10-30 17:44:18.967844936 +0200
-+++ bt_kernel/drivers/video/omap/omapfb_main.c 2005-10-24 19:16:46.600530000 +0300
-@@ -89,6 +89,7 @@
- extern struct lcd_panel innovator1610_panel;
- extern struct lcd_panel innovator1510_panel;
- extern struct lcd_panel lph8923_panel;
-+extern struct lcd_panel h6300_panel;
-
- static struct lcd_panel *panels[] = {
- #ifdef CONFIG_MACH_OMAP_H2
-@@ -109,6 +110,9 @@
- #ifdef CONFIG_MACH_OMAP_PALMTE
- &palmte_panel,
- #endif
-+#ifdef CONFIG_MACH_OMAP_H6300
-+ &h6300_panel,
-+#endif
-
- #ifdef CONFIG_MACH_OMAP_INNOVATOR
-
-@@ -260,18 +264,40 @@
- u_int blue, u_int transp, int update_hw_pal)
- {
- struct omapfb_device *fbdev = (struct omapfb_device *)info->par;
-- u16 pal;
- int r = 0;
-
-- if (regno < 16) {
-- pal = ((red >> 11) << 11) | ((green >> 10) << 5) | (blue >> 11);
-- ((u32 *)(info->pseudo_palette))[regno] = pal;
-- }
-+ switch (fbdev->color_mode) {
-+ case OMAPFB_COLOR_YUV422:
-+ case OMAPFB_COLOR_YUV420:
-+ r = -EINVAL;
-+ break;
-+ case OMAPFB_COLOR_CLUT_8BPP:
-+ case OMAPFB_COLOR_CLUT_4BPP:
-+ case OMAPFB_COLOR_CLUT_2BPP:
-+ case OMAPFB_COLOR_CLUT_1BPP:
-+ if (fbdev->ctrl->setcolreg)
-+ r = fbdev->ctrl->setcolreg(regno, red, green, blue,
-+ transp, update_hw_pal);
-+ /* Fallthrough */
-+ case OMAPFB_COLOR_RGB565:
-+ if (r != 0)
-+ break;
-
-- if (fbdev->ctrl->setcolreg)
-- r = fbdev->ctrl->setcolreg(regno, red, green, blue, transp,
-- update_hw_pal);
-+ if (regno < 0) {
-+ r = -EINVAL;
-+ break;
-+ }
-
-+ if (regno < 16) {
-+ u16 pal;
-+ pal = ((red >> 11) << 11) | ((green >> 10) << 5) |
-+ (blue >> 11);
-+ ((u32 *)(info->pseudo_palette))[regno] = pal;
-+ }
-+ break;
-+ default:
-+ BUG();
-+ }
- return r;
- }
-
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/.gitignore bt_kernel/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,30 +0,0 @@
--#
--# NOTE! Don't add files that are generated in specific
--# subdirectories here. Add them in the ".gitignore" file
--# in that subdirectory instead.
--#
--# Normal rules
--#
--.*
--*.o
--*.a
--*.s
--*.ko
--*.mod.c
--
--#
--# Top-level generic files
--#
--vmlinux*
--System.map
--Module.symvers
--
--#
--# Generated include files
--#
--include/asm
--include/config
--include/linux/autoconf.h
--include/linux/compile.h
--include/linux/version.h
--
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/board-h6300.h bt_kernel/include/asm-arm/arch-omap/board-h6300.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/board-h6300.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/board-h6300.h 2005-08-12 13:46:22.016114000 +0300
-@@ -0,0 +1,40 @@
-+/*
-+ * linux/include/asm-arm/arch-omap/board-innovator.h
-+ *
-+ * Copyright (C) 2001 RidgeRun, 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+#ifndef __ASM_ARCH_H6300_H
-+#define __ASM_ARCH_H6300_H
-+
-+#ifndef OMAP_SDRAM_DEVICE
-+#define OMAP_SDRAM_DEVICE D256M_1X16_4B
-+#endif
-+
-+#define OMAP1510P1_IMIF_PRI_VALUE 0x00
-+#define OMAP1510P1_EMIFS_PRI_VALUE 0x00
-+#define OMAP1510P1_EMIFF_PRI_VALUE 0x00
-+
-+#define NR_FPGA_IRQS 24
-+#define NR_IRQS IH_BOARD_BASE + NR_FPGA_IRQS
-+
-+#endif /* __ASM_ARCH_H6300_H */
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/cpu.h bt_kernel/include/asm-arm/arch-omap/cpu.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/cpu.h 2005-10-30 17:44:19.208806581 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/cpu.h 2005-10-30 16:32:39.609796000 +0200
-@@ -215,4 +215,9 @@
- # define cpu_is_omap2420() 1
- #endif
-
-+/* Macros to detect if we have OMAP1 or OMAP2 */
-+#define cpu_class_is_omap1() (cpu_is_omap730() || cpu_is_omap15xx() || \
-+ cpu_is_omap16xx())
-+#define cpu_class_is_omap2() cpu_is_omap24xx()
-+
- #endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/dma.h bt_kernel/include/asm-arm/arch-omap/dma.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/dma.h 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/include/asm-arm/arch-omap/dma.h 2005-10-30 16:32:39.609796000 +0200
-@@ -217,19 +217,22 @@
- extern void omap_stop_dma(int lch);
- extern void omap_set_dma_transfer_params(int lch, int data_type,
- int elem_count, int frame_count,
-- int sync_mode);
-+ int sync_mode,
-+ int dma_trigger, int src_or_dst_synch);
- extern void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode,
- u32 color);
-
- extern void omap_set_dma_src_params(int lch, int src_port, int src_amode,
-- unsigned long src_start);
-+ unsigned long src_start,
-+ int src_ei, int src_fi);
- extern void omap_set_dma_src_index(int lch, int eidx, int fidx);
- extern void omap_set_dma_src_data_pack(int lch, int enable);
- extern void omap_set_dma_src_burst_mode(int lch,
- enum omap_dma_burst_mode burst_mode);
-
- extern void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
-- unsigned long dest_start);
-+ unsigned long dest_start,
-+ int dst_ei, int dst_fi);
- extern void omap_set_dma_dest_index(int lch, int eidx, int fidx);
- extern void omap_set_dma_dest_data_pack(int lch, int enable);
- extern void omap_set_dma_dest_burst_mode(int lch,
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/hardware.h bt_kernel/include/asm-arm/arch-omap/hardware.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/hardware.h 2005-10-30 17:44:19.364781754 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/hardware.h 2005-10-22 03:52:45.687256000 +0300
-@@ -290,6 +290,10 @@
- #include "board-innovator.h"
- #endif
-
-+#ifdef CONFIG_MACH_OMAP_H6300
-+#include "board-h6300.h"
-+#endif
-+
- #ifdef CONFIG_MACH_OMAP_H2
- #include "board-h2.h"
- #endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/h6300_uart_info.h bt_kernel/include/asm-arm/arch-omap/h6300_uart_info.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/h6300_uart_info.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/h6300_uart_info.h 2005-10-14 18:55:31.156317000 +0300
-@@ -0,0 +1,33 @@
-+/*
-+ * Support file for calling h6300 uart configuration functions.
-+ * Used at least by h6300_bt driver.
-+ *
-+ * Copyright (c) 2005 SDG Systems, LLC
-+ * 2005-03-29 Todd Blumer Converted basic structure to support hx4700
-+ * 2005-10-03 Mika Laitio (lamikr@cc.jyu.fi) Reorganized for the iPAQ h6300 bt driver.
-+ */
-+
-+#ifndef _H6300_UART_INFO_H
-+#define _H6300_UART_INFO_H
-+
-+#include "omap_serial.h"
-+
-+#define GPIO_BT_PWR_EN 3
-+#define GPIO_N_BT_RST 9
-+
-+#define GPIO_I2C_GPRS_RESET 16
-+#define GPIO_I2C_MIC_OP_EN 10
-+#define GPIO_I2C_SPK_OP_PD 11
-+
-+#define GPIO_VALUE_OFF 0
-+#define GPIO_VALUE_ON 1
-+
-+#define GPIO_DIR_OUTPUT 1
-+
-+struct h6300_uart_funcs {
-+ void (*configure)( struct uart_omap_port *up, int state);
-+ void (*set_txrx)( struct uart_omap_port *up, int txrx);
-+ int (*get_txrx)( struct uart_omap_port *up);
-+};
-+
-+#endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/mux.h bt_kernel/include/asm-arm/arch-omap/mux.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/mux.h 2005-10-30 17:44:19.465765680 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/mux.h 2005-10-14 18:55:31.156317000 +0300
-@@ -316,6 +316,13 @@
- P15_1610_UWIRE_CS3,
- N15_1610_UWIRE_CS1,
-
-+ /* OMAP-1510 uWire */
-+ P15_1510_UWIRE_CS3,
-+ N14_1510_UWIRE_CS0,
-+ V19_1510_UWIRE_SCLK,
-+ W21_1510_UWIRE_SDO,
-+ U18_1510_UWIRE_SDI,
-+
- /* OMAP-1610 Flash */
- L3_1610_FLASH_CS2B_OE,
- M8_1610_FLASH_CS2B_WE,
-@@ -380,6 +387,7 @@
- T20_1610_LOW_PWR,
-
- /* MCLK Settings */
-+ R10_1510_MCLK_ON,
- V5_1710_MCLK_ON,
- V5_1710_MCLK_OFF,
- R10_1610_MCLK_ON,
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/omapfb.h bt_kernel/include/asm-arm/arch-omap/omapfb.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/omapfb.h 2005-10-30 17:44:19.557751038 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/omapfb.h 2005-10-22 03:52:45.687256000 +0300
-@@ -267,6 +267,7 @@
- extern struct lcd_panel osk_panel;
- extern struct lcd_panel innovator1610_panel;
- extern struct lcd_panel innovator1510_panel;
-+extern struct lcd_panel h6300_panel;
-
- #ifdef CONFIG_ARCH_OMAP1
- extern struct lcd_ctrl omap1_lcd_ctrl;
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/omap_serial.h bt_kernel/include/asm-arm/arch-omap/omap_serial.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/omap_serial.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/omap_serial.h 2005-10-04 00:58:34.589442000 +0300
-@@ -0,0 +1,62 @@
-+/*
-+ * Omap/h6300 serial driver private interface.
-+ * Code originates from the pxa-serial.h available in the handheld org drivers
-+ * for iPAQ PXA4700.
-+ *
-+ * Copyright (c) 2005 SDG Systems, LLC
-+ * 2005-03-29 Todd Blumer Converted basic structure to support hx4700
-+ * 2005-10-03 Mika Laitio (lamikr@cc.jyu.fi) Reorganized for the iPAQ h6300 bt driver.
-+ */
-+
-+#ifndef _OMAP_SERIAL_H
-+#define _OMAP_SERIAL_H
-+
-+#define OMAP_SERIAL_TX 1
-+#define OMAP_SERIAL_RX 2
-+
-+#include <linux/tty.h>
-+#include <linux/serial_core.h>
-+
-+struct platform_omap_serial_funcs;
-+
-+struct uart_omap_port {
-+ struct uart_port port;
-+ unsigned char ier;
-+ unsigned char lcr;
-+ unsigned char mcr;
-+ unsigned int lsr_break_flag;
-+ unsigned int cken;
-+ char *name;
-+ struct platform_omap_serial_funcs *pf;
-+};
-+
-+/* A pointer to such a structure can be contained in the platform_data
-+ * field of every PXA UART platform_device. If the field is NULL, the
-+ * serial port works as usual.
-+ *
-+ * For the sake of simplicity/performance no one of the function pointers
-+ * in the structure below can be NULL.
-+ */
-+struct platform_omap_serial_funcs {
-+ /* Platform-specific function to initialize whatever is connected
-+ to this serial port... enable=1 -> enable transceiver,
-+ 0 -> disable transceiver. */
-+ void (*configure) (struct uart_omap_port *up, int enable);
-+ /* Platform-specific function to enable or disable the individual
-+ transmitter/receiver submodules. On transceivers without echo
-+ cancellation (e.g. SIR) transmitter always has priority, e.g.
-+ if both bits are set, only the transmitter is enabled. */
-+ void (*set_txrx) (struct uart_omap_port *up, int txrx);
-+ /* Get the current state of tx/rx (see bitflags above) */
-+ int (*get_txrx) (struct uart_omap_port *up);
-+};
-+
-+/*
-+ * The variables below are located in arch/arm/mach-omap/board_h6300.c
-+ * Machine-specific code may want to put a pointer to a static
-+ * platform_pxa_serial_funcs structure in the dev.platform_data
-+ * field of the respective port device.
-+ */
-+extern struct platform_device btuart_device;
-+
-+#endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/pca9535.h bt_kernel/include/asm-arm/arch-omap/pca9535.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/include/asm-arm/arch-omap/pca9535.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/include/asm-arm/arch-omap/pca9535.h 2005-10-25 03:24:45.525766000 +0300
-@@ -0,0 +1,39 @@
-+#ifndef _PCA9535_H
-+#define _PCA9535_H
-+
-+enum pca9535_gpios {
-+ GPIO0 = 0,
-+ GPIO1 = 1,
-+ GPIO2 = 2,
-+ GPIO3 = 3,
-+ GPIO4 = 4,
-+ GPIO5 = 5,
-+ GPIO6 = 6,
-+ GPIO7 = 7,
-+ GPIO8 = 8,
-+ GPIO9 = 9,
-+ GPIO10 = 10,
-+ GPIO11 = 11,
-+ GPIO12 = 12,
-+ GPIO13 = 13,
-+ GPIO14 = 14,
-+ GPIO15 = 15,
-+ GPIO16 = 16,
-+ GPIO17 = 17
-+};
-+
-+enum gpio_values {
-+ HI = 0,
-+ LOW = 1
-+};
-+
-+enum gpio_direction {
-+ GPIO_INPUT = 0,
-+ GPIO_OUTPUT = 1
-+};
-+
-+extern int pca9535_gpio_read(int gpio);
-+extern int pca9535_gpio_write(int gpio, unsigned char val);
-+extern int pca9535_gpio_direction(int gpio, unsigned char direction);
-+
-+#endif
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/lib/.gitignore bt_kernel/lib/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/lib/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/lib/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,6 +0,0 @@
--#
--# Generated files
--#
--gen_crc32table
--crc32table.h
--
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/Makefile bt_kernel/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/Makefile 2005-10-30 17:44:14.606539141 +0200
-+++ bt_kernel/Makefile 2005-10-22 03:52:45.687256000 +0300
-@@ -11,7 +11,7 @@
- # expect to learn how to build the kernel reading this file.
-
- # Add custom flags here to avoid conflict with updates
--EXTRAVERSION := $(EXTRAVERSION)-omap1
-+EXTRAVERSION := $(EXTRAVERSION)-omap-h6300
-
- # Do not print "Entering directory ..."
- MAKEFLAGS += --no-print-directory
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/basic/.gitignore bt_kernel/scripts/basic/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/basic/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/scripts/basic/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,3 +0,0 @@
--fixdep
--split-include
--docproc
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/.gitignore bt_kernel/scripts/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/scripts/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,4 +0,0 @@
--conmakehash
--kallsyms
--pnmtologo
--
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/kconfig/.gitignore bt_kernel/scripts/kconfig/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/kconfig/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/scripts/kconfig/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,16 +0,0 @@
--#
--# Generated files
--#
--config*
--lex.*.c
--*.tab.c
--*.tab.h
--
--#
--# configuration programs
--#
--conf
--mconf
--qconf
--gconf
--kxgettext
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/mod/.gitignore bt_kernel/scripts/mod/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/scripts/mod/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/scripts/mod/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,4 +0,0 @@
--elfconfig.h
--mk_elfconfig
--modpost
--
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/Kconfig bt_kernel/sound/arm/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/Kconfig 2005-10-30 17:44:20.184651252 +0200
-+++ bt_kernel/sound/arm/Kconfig 2005-10-14 18:55:31.156317000 +0300
-@@ -15,6 +15,13 @@
- To compile this driver as a module, choose M here: the module
- will be called snd-sa11xx-uda1341.
-
-+config SND_OMAP_TSC2101
-+ tristate "OMAP TSC2101 driver (iPaq H63xx)"
-+ depends ARCH_OMAP1
-+ select SND_PCM
-+ help
-+ ALSA driver for TI TSC2101.
-+
- config SND_ARMAACI
- tristate "ARM PrimeCell PL041 AC Link support"
- depends on SND && ARM_AMBA
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/Makefile bt_kernel/sound/arm/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/Makefile 2005-10-30 17:44:20.234643295 +0200
-+++ bt_kernel/sound/arm/Makefile 2005-10-14 18:55:31.156317000 +0300
-@@ -16,3 +16,6 @@
-
- obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-aic23.o
- snd-omap-aic23-objs := omap-aic23.o omap-alsa-dma.o omap-alsa-mixer.o
-+
-+obj-$(CONFIG_SND) += \
-+ omap/
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/Makefile bt_kernel/sound/arm/omap/Makefile
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/Makefile 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/sound/arm/omap/Makefile 2005-08-12 13:46:22.016114000 +0300
-@@ -0,0 +1,8 @@
-+#
-+# Makefile for ALSA
-+#
-+
-+snd-omap-tsc2101-objs := tsc2101_main.o tsc2101_mix.o tsc2101_pcm.o
-+
-+# Toplevel Module Dependency
-+obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-tsc2101.o
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/omap-tsc2101.h bt_kernel/sound/arm/omap/omap-tsc2101.h
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/omap-tsc2101.h 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/sound/arm/omap/omap-tsc2101.h 2005-08-20 00:24:45.622662000 +0300
-@@ -0,0 +1,81 @@
-+/*
-+ * OMAP tsc2101 soundcard
-+ * Copyright (c) by Everett Coleman II <gcc80x86@fuzzyneural.net>
-+ *
-+ * 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 __SOUND_OMAP_TSC2101_H
-+# define __SOUND_OMAP_TSC2101_H 1
-+
-+# include <sound/driver.h>
-+# include <linux/init.h>
-+# include <sound/core.h>
-+# include <sound/initval.h>
-+# include <sound/control.h>
-+# include <sound/pcm.h>
-+# include <asm/arch/dma.h>
-+# include <asm/hardware/tsc2101.h>
-+# include <../drivers/ssi/omap-tsc2101.h>
-+
-+# define TSC2101_AUDIO_CODEC_REGISTERS 2
-+# define OUTPUT_VOLUME_MIN 0
-+# define OUTPUT_VOLUME_MAX 127
-+# define AUDIO_RATE_DEFAULT 44100
-+# define AUDIO_BPS_DEFAULT 16
-+
-+# define AUDIO_DMA_BUF_SIZE (8 * 1024)
-+
-+# define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX
-+# define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX
-+# define AUDIO_MCBSP OMAP_MCBSP1
-+
-+# define DEBUG 1
-+# ifdef DEBUG
-+# define dprintk(x, y...) printk (x, ##y);
-+# else
-+# define dprintk(x, y...) {}
-+# endif /* DEBUG */
-+
-+//# define DUMP_TSC2101_REGISTERS
-+
-+typedef struct audio_stream {
-+ char *id;
-+ int sid;
-+ int dev;
-+ int channel;
-+ spinlock_t lock;
-+ unsigned int offset, period, position;
-+ u8 active;
-+ snd_pcm_substream_t *stream;
-+} audio_stream_t;
-+
-+typedef struct snd_card_tsc2101 {
-+ snd_card_t *card;
-+ snd_pcm_t *pcm;
-+
-+ long samplerate;
-+ audio_stream_t s[2];
-+} snd_card_tsc2101_t;
-+
-+# ifdef DUMP_TSC2101_REGISTERS
-+void dump_tsc2101_reg (void);
-+# endif /* DUMP_TSC2101_REGISTERS */
-+
-+int snd_tsc2101_setup_mix (snd_card_tsc2101_t *);
-+int snd_tsc2101_setup_pcm (snd_card_tsc2101_t *);
-+void snd_tsc2101_disable_pcm (snd_card_tsc2101_t *);
-+
-+#endif /* __SOUND_OMAP_TSC2101_H */
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/tsc2101_main.c bt_kernel/sound/arm/omap/tsc2101_main.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/tsc2101_main.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/sound/arm/omap/tsc2101_main.c 2005-08-12 13:46:22.016114000 +0300
-@@ -0,0 +1,109 @@
-+/*
-+ * OMAP tsc2101 soundcard
-+ * Copyright (c) by Everett Coleman II <gcc80x86@fuzzyneural.net>
-+ *
-+ * 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 <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include "omap-tsc2101.h"
-+
-+#ifdef DUMP_TSC2101_REGISTERS
-+void
-+dump_tsc2101_reg (void) {
-+ int i=0;
-+ printk ("TSC2101 Register DUMP:\n");
-+ for (i=0; i <= 0x27; i++) {
-+ printk ("0x%02x: %04x ", i, omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, i));
-+ if ((i % 4) == 3)
-+ printk ("\n");
-+ } printk ("\n");
-+} /* dump_tsc2101_reg */
-+#endif /* DUMP_TSC2101_REGISTERS */
-+
-+/* Globals
-+ **********/
-+static struct snd_card_tsc2101 *tsc2101=NULL;
-+static char *id=NULL;
-+
-+/* Module init/exit Functions
-+ ****************************/
-+static void
-+snd_tsc2101_free (snd_card_t *card) {
-+ snd_card_tsc2101_t *chip=card->private_data;
-+
-+ tsc2101=0;
-+ card->private_data=0;
-+ kfree (chip);
-+} /* snd_tsc2101_free */
-+
-+static int __init
-+alsa_card_tsc2101_init (void) {
-+ int err=0;
-+ snd_card_t *card;
-+
-+ if (!machine_is_h6300 ())
-+ return -ENODEV;
-+
-+ if ((card=snd_card_new (-1, id, THIS_MODULE, sizeof (snd_card_tsc2101_t))) == 0)
-+ return -ENOMEM;
-+ if ((tsc2101=kcalloc (1, sizeof (*tsc2101), GFP_KERNEL)) == 0)
-+ return -ENOMEM;
-+
-+ card->private_data=(void *)tsc2101;
-+ card->private_free=snd_tsc2101_free;
-+
-+ tsc2101->card=card;
-+ tsc2101->samplerate=AUDIO_RATE_DEFAULT;
-+
-+ if ((err=snd_tsc2101_setup_pcm (tsc2101)) < 0)
-+ goto nodev;
-+ if ((err=snd_tsc2101_setup_mix (tsc2101)) < 0)
-+ goto nodev;
-+
-+ // TODO: PM
-+
-+ strncpy (card->driver, "TSC2101", sizeof (card->driver));
-+ strncpy (card->shortname, "OMAP TSC2101", sizeof (card->shortname));
-+ strncpy (card->longname, "TI OMAP TSC2101 Audio Codec", sizeof (card->longname));
-+
-+ if ((err=snd_card_register (card)) == 0) {
-+ printk (KERN_INFO "TSC2101 audio support initialized\n");
-+ return 0;
-+ }
-+
-+nodev:
-+ snd_tsc2101_disable_pcm (tsc2101);
-+ snd_card_free (card);
-+ return err;
-+} /* alsa_card_tsc2101_init */
-+
-+static void __exit
-+alsa_card_tsc2101_exit (void) {
-+ snd_tsc2101_disable_pcm (tsc2101);
-+ snd_card_free(tsc2101->card);
-+} /* alsa_card_tsc2101_exit */
-+
-+module_init(alsa_card_tsc2101_init)
-+module_exit(alsa_card_tsc2101_exit)
-+
-+MODULE_AUTHOR("Everett Coleman II <gcc80x86@fuzzyneural.net>");
-+MODULE_DESCRIPTION("TI TSC2101 Audio Driver");
-+MODULE_LICENSE("GPL");
-+
-+module_param(id, charp, 0444);
-+MODULE_PARM_DESC(id, "ID string for OMAP TSC2101 soundcard.");
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/tsc2101_mix.c bt_kernel/sound/arm/omap/tsc2101_mix.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/tsc2101_mix.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/sound/arm/omap/tsc2101_mix.c 2005-08-12 13:46:22.016114000 +0300
-@@ -0,0 +1,211 @@
-+/*
-+ * OMAP tsc2101 soundcard
-+ * Copyright (c) by Everett Coleman II <gcc80x86@fuzzyneural.net>
-+ *
-+ * 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 "omap-tsc2101.h"
-+
-+static int
-+__pcm_playback_volume_info (snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
-+ uinfo->type =SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count=2;
-+ uinfo->value.integer.min=OUTPUT_VOLUME_MIN;
-+ uinfo->value.integer.max=OUTPUT_VOLUME_MAX;
-+ return 0;
-+} /* __pcm_playback_volume_info */
-+
-+# define dgc_dalvl_extract(x) ((x & 0x7f00) >> 8)
-+# define dgc_darvl_extract(x) ((x & 0x007f))
-+static int
-+__pcm_playback_volume_get (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_DAC_GAIN_CTRL);
-+ ucontrol->value.integer.value[0]=dgc_dalvl_extract(val); // L
-+ ucontrol->value.integer.value[1]=dgc_darvl_extract(val); // R
-+ return 0;
-+} /* __pcm_playback_volume_get */
-+
-+static int
-+__pcm_playback_volume_put (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_DAC_GAIN_CTRL);
-+ int count=0;
-+ if (dgc_dalvl_extract(val) != ucontrol->value.integer.value[0]) {
-+ val=(val & ~DGC_DALVL(OUTPUT_VOLUME_MAX)) |
-+ DGC_DALVL(ucontrol->value.integer.value[0]);
-+ count++;
-+ } /* L */
-+
-+ if (dgc_darvl_extract(val) != ucontrol->value.integer.value[1]) {
-+ val=(val & ~DGC_DARVL(OUTPUT_VOLUME_MAX)) |
-+ DGC_DARVL((u16)ucontrol->value.integer.value[1]);
-+ count++;
-+ } /* R */
-+
-+ if (count)
-+ omap_tsc2101_write (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_DAC_GAIN_CTRL, val);
-+
-+ return count;
-+} /* __pcm_playback_volume_put */
-+
-+static int
-+__pcm_playback_switch_info (snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
-+ uinfo->type =SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-+ uinfo->count=2;
-+ uinfo->value.integer.min=0;
-+ uinfo->value.integer.max=1;
-+ return 0;
-+} /* __pcm_playback_switch_info */
-+
-+static int
-+__pcm_playback_switch_get (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_DAC_GAIN_CTRL);
-+ ucontrol->value.integer.value[0]=(val & DGC_DALMU) == DGC_DALMU; // L
-+ ucontrol->value.integer.value[1]=(val & DGC_DARMU) == DGC_DARMU; // R
-+ return 0;
-+} /* __pcm_playback_switch_get */
-+
-+static int
-+__pcm_playback_switch_put (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_DAC_GAIN_CTRL);
-+ int count=0;
-+
-+ if (((val & DGC_DALMU) == DGC_DALMU) != ucontrol->value.integer.value[0]) {
-+ val=(val & ~DGC_DALMU) |
-+ (ucontrol->value.integer.value[0] ? DGC_DALMU : 0);
-+ count++;
-+ } /* L */
-+ if (((val & DGC_DARMU) == DGC_DARMU) != ucontrol->value.integer.value[1]) {
-+ val=(val & ~DGC_DARMU) |
-+ (ucontrol->value.integer.value[1] ? DGC_DARMU : 0);
-+ count++;
-+ } /* R */
-+
-+ if (count)
-+ omap_tsc2101_write (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_DAC_GAIN_CTRL, val);
-+ return count;
-+} /* __pcm_playback_switch_put */
-+
-+static int
-+__line_playback_volume_info (snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
-+ uinfo->type =SNDRV_CTL_ELEM_TYPE_INTEGER;
-+ uinfo->count=1;
-+ uinfo->value.integer.min=OUTPUT_VOLUME_MIN;
-+ uinfo->value.integer.max=OUTPUT_VOLUME_MAX;
-+ return 0;
-+} /* __line_playback_volume_info */
-+
-+#define hgc_adpga_hed_extract(x) ((x & 0x7f00) >> 8)
-+static int
-+__line_playback_volume_get (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_HEADSET_GAIN_CTRL);
-+ ucontrol->value.integer.value[0]=hgc_adpga_hed_extract(val);
-+ return 0;
-+} /* __line_playback_volume_get */
-+
-+static int
-+__line_playback_volume_put (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_HEADSET_GAIN_CTRL);
-+ int count=0;
-+ if (hgc_adpga_hed_extract(val) != ucontrol->value.integer.value[0]) {
-+ val=(val & ~HGC_ADPGA_HED(OUTPUT_VOLUME_MAX)) |
-+ HGC_ADPGA_HED((u16)ucontrol->value.integer.value[0]);
-+ count++;
-+ }
-+ if (count)
-+ omap_tsc2101_write (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_HEADSET_GAIN_CTRL, val);
-+ return count;
-+} /* __line_playback_volume_put */
-+
-+static int
-+__line_playback_switch_info (snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) {
-+ uinfo->type =SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-+ uinfo->count=1;
-+ uinfo->value.integer.min=0;
-+ uinfo->value.integer.max=1;
-+ return 0;
-+} /* __line_playback_switch_info */
-+
-+static int
-+__line_playback_switch_get (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_HEADSET_GAIN_CTRL);
-+ ucontrol->value.integer.value[0]=(val & HGC_ADMUT_HED) == HGC_ADMUT_HED;
-+ return 0;
-+} /* __line_playback_switch_get */
-+
-+static int
-+__line_playback_switch_put (snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) {
-+ u16 val=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_HEADSET_GAIN_CTRL);
-+ int count=0;
-+
-+ if (((val & HGC_ADMUT_HED) == HGC_ADMUT_HED) != ucontrol->value.integer.value[0]) {
-+ val=(val & ~HGC_ADMUT_HED) |
-+ (ucontrol->value.integer.value[0] ? HGC_ADMUT_HED : 0);
-+ count++;
-+ }
-+
-+ if (count)
-+ omap_tsc2101_write (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_HEADSET_GAIN_CTRL, val);
-+ return count;
-+} /* __line_playback_switch_put */
-+
-+
-+static snd_kcontrol_new_t tsc2101_control[] __devinitdata={
-+ { .name = "PCM Playback Volume",
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .index = 0,
-+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .info = __pcm_playback_volume_info,
-+ .get = __pcm_playback_volume_get,
-+ .put = __pcm_playback_volume_put,
-+ }, {
-+ .name = "PCM Playback Switch",
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .index = 0,
-+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .info = __pcm_playback_switch_info,
-+ .get = __pcm_playback_switch_get,
-+ .put = __pcm_playback_switch_put,
-+ }, {
-+ .name = "Line Playback Volume",
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .index = 1,
-+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .info = __line_playback_volume_info,
-+ .get = __line_playback_volume_get,
-+ .put = __line_playback_volume_put,
-+ }, {
-+ .name = "Line Playback Switch",
-+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+ .index = 1,
-+ .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+ .info = __line_playback_switch_info,
-+ .get = __line_playback_switch_get,
-+ .put = __line_playback_switch_put,
-+ }
-+};
-+
-+int
-+snd_tsc2101_setup_mix (snd_card_tsc2101_t *tsc2101) {
-+ int i=0, err=0;
-+
-+ if (!tsc2101)
-+ return -EINVAL;
-+ for (i=0; i < ARRAY_SIZE(tsc2101_control); i++)
-+ if ((err=snd_ctl_add (tsc2101->card, snd_ctl_new1 (&tsc2101_control[i], tsc2101->card))) < 0)
-+ return err;
-+ return 0;
-+} /* snd_tsc2101_setup_mix */
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/tsc2101_pcm.c bt_kernel/sound/arm/omap/tsc2101_pcm.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap/tsc2101_pcm.c 1970-01-01 02:00:00.000000000 +0200
-+++ bt_kernel/sound/arm/omap/tsc2101_pcm.c 2005-08-31 01:22:50.289885000 +0300
-@@ -0,0 +1,555 @@
-+/*
-+ * OMAP tsc2101 soundcard
-+ * Copyright (c) by Everett Coleman II <gcc80x86@fuzzyneural.net>
-+ *
-+ * 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 <asm/arch/mcbsp.h>
-+#include <linux/delay.h>
-+#include <asm/arch/gpio.h>
-+#include "omap-tsc2101.h"
-+
-+static snd_pcm_hardware_t pcm_hardware[2] = {
-+ {
-+ .info =
-+ SNDRV_PCM_INFO_INTERLEAVED |
-+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP |
-+ SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_PAUSE |
-+ SNDRV_PCM_INFO_RESUME,
-+ .formats = SNDRV_PCM_FMTBIT_U16_LE,
-+ .rates =
-+ SNDRV_PCM_RATE_8000_44100 |
-+ SNDRV_PCM_RATE_KNOT,
-+ .rate_min = 7350,
-+ .rate_max = 48000,
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .buffer_bytes_max = 128 * 1024,
-+ .period_bytes_min = 64,
-+ .period_bytes_max = AUDIO_DMA_BUF_SIZE,
-+ .periods_min = 2,
-+ .periods_max = 255,
-+ .fifo_size = 0,
-+ }, {
-+ .info =
-+ SNDRV_PCM_INFO_INTERLEAVED |
-+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP |
-+ SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_PAUSE |
-+ SNDRV_PCM_INFO_RESUME,
-+ .formats = SNDRV_PCM_FMTBIT_U16_LE,
-+ .rates =
-+ SNDRV_PCM_RATE_8000_44100 |
-+ SNDRV_PCM_RATE_KNOT,
-+ .rate_min = 7350,
-+ .rate_max = 48000,
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .buffer_bytes_max = 128 * 1024,
-+ .period_bytes_min = 64,
-+ .period_bytes_max = AUDIO_DMA_BUF_SIZE,
-+ .periods_min = 2,
-+ .periods_max = 255,
-+ .fifo_size = 0,
-+ }
-+};
-+
-+static unsigned int rate_list[] = {
-+ 7350, 8000, 8018, 8727,
-+ 8820, 9600, 11025, 12000,
-+ 14700, 16000, 22050, 24000,
-+ 29400, 32000, 44100, 48000
-+};
-+
-+static snd_pcm_hw_constraint_list_t rate_constraint = {
-+ .count = ARRAY_SIZE (rate_list),
-+ .list = rate_list,
-+ .mask = 0,
-+};
-+
-+
-+static int
-+__tsc2101_open (snd_pcm_substream_t *substream) {
-+ snd_pcm_runtime_t *runtime = substream->runtime;
-+ snd_card_tsc2101_t *chip = snd_pcm_substream_chip (substream);
-+ int sid = substream->pstr->stream, err;
-+
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ chip->s[sid].stream = substream;
-+ runtime->hw = pcm_hardware[sid];
-+
-+ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-+ return err;
-+ if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &rate_constraint)) < 0)
-+ return err;
-+
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+ return 0;
-+} /* __tsc2101_open */
-+
-+static int
-+__tsc2101_close (snd_pcm_substream_t *substream) {
-+ snd_card_tsc2101_t *chip = snd_pcm_substream_chip (substream);
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ chip->s[substream->pstr->stream].stream = 0;
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+ return 0;
-+} /* __tsc2101_close */
-+
-+static int
-+__tsc2101_hw_params (snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params) {
-+ dprintk ("[%s> pass\n", __FUNCTION__);
-+ return snd_pcm_lib_malloc_pages (substream, params_buffer_bytes (hw_params));
-+} /* __tsc2101_hw_params */
-+
-+static int
-+__tsc2101_hw_free (snd_pcm_substream_t *substream) {
-+ dprintk ("[%s> pass\n", __FUNCTION__);
-+ return snd_pcm_lib_free_pages (substream);
-+} /* __tsc2101_hw_free */
-+
-+static struct omap_mcbsp_reg_cfg mcbsp_cfg = {
-+// .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
-+// .pcr0 = CLKXP | CLKRP,
-+ .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
-+
-+// .spcr2 = FREE | FRST | GRST | XRST | XINTM(3) | XEMPTY,
-+// .spcr1 = RINTM(3) | RRST | RFULL,
-+ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
-+ .spcr1 = RINTM(3) | RRST,
-+
-+ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
-+ RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
-+ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
-+ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
-+ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
-+ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
-+ .srgr1 = FWID(15),
-+ .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
-+};
-+
-+static int
-+__set_samplerate (snd_card_tsc2101_t *tsc2101, long sample_rate) {
-+ static u8 div_list[] = {
-+ 7, 7, 6, 6,
-+ 5, 5, 4, 4,
-+ 3, 3, 2, 2,
-+ 1, 1, 0, 0
-+ };
-+ int i = 0, clkgdv = 0;
-+ u8 khz = 0;
-+ u16 data = 0;
-+
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ udelay (125);
-+ for (i=rate_constraint.count-1; i >= 0 ; i--)
-+ if (sample_rate >= rate_list[i])
-+ break;
-+ if (i == -1)
-+ i=0;
-+ khz=(i%2) ? 0 : 1;
-+
-+ dprintk ("rate=%u\n", rate_list[i]);
-+
-+ data=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_AUDIO_CTRL_1);
-+ data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
-+ data |= AC1_DACFS(div_list[i])
-+ | AC1_ADCFS(div_list[i]);
-+ omap_tsc2101_write (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_AUDIO_CTRL_1, data);
-+
-+ data=omap_tsc2101_read (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_AUDIO_CTRL_3);
-+ data &= ~(AC3_REFFS | AC3_SLVMS);
-+ data |= (khz) ? AC3_REFFS : 0;
-+ data |= AC3_SLVMS;
-+ omap_tsc2101_write (TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_AUDIO_CTRL_3, data);
-+
-+ if (khz) {
-+ omap_tsc2101_write (
-+ TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_PLL_PROG_1,
-+ PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7));
-+ omap_tsc2101_write (
-+ TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_PLL_PROG_2,
-+ PLL2_D_VAL(0x1490));
-+
-+ } else {
-+ omap_tsc2101_write (
-+ TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_PLL_PROG_1,
-+ PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8));
-+ omap_tsc2101_write (
-+ TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_PLL_PROG_2,
-+ PLL2_D_VAL(0x780));
-+ }
-+
-+ tsc2101->samplerate=rate_list[i];
-+
-+ mcbsp_cfg.srgr1 =
-+ (FWID(AUDIO_BPS_DEFAULT - 1) | CLKGDV(clkgdv));
-+ mcbsp_cfg.srgr2 =
-+ ((GSYNC | CLKSP | FSGM | FPER(AUDIO_BPS_DEFAULT * 2 - 1)));
-+
-+ omap_mcbsp_config(AUDIO_MCBSP, &mcbsp_cfg);
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+ return 0;
-+} /* __set_samplerate */
-+
-+static int
-+__tsc2101_prepare (snd_pcm_substream_t *substream) {
-+ snd_pcm_runtime_t *runtime = substream->runtime;
-+ snd_card_tsc2101_t *chip = snd_pcm_substream_chip (substream);
-+ audio_stream_t *s = &chip->s[substream->pstr->stream];
-+
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ __set_samplerate (chip, runtime->rate);
-+
-+ // set FMT here ????
-+ s->period =0;
-+ s->offset =0;
-+ s->position=0;
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+ return 0;
-+} /* __tsc2101_prepare */
-+
-+# define DCSR_ERROR 0x3
-+# define DCSR_END_BLOCK (1 << 5)
-+# define DCCR_EN (1 << 7)
-+static void
-+tsc2101_playback_callback (int channel, u16 ch_status, void *data) {
-+ audio_stream_t *s=(audio_stream_t *)data;
-+
-+ dprintk ("[%s]\n", __FUNCTION__);
-+
-+ if (ch_status & DCSR_ERROR) {
-+ omap_writew (omap_readw (OMAP_DMA_CCR (channel)) &
-+ ~DCCR_EN, OMAP_DMA_CCR (channel));
-+ printk (KERN_ERR "[%s] DCSR_ERROR!\n", __FUNCTION__);
-+ dprintk ("[%s] x-fail\n", __FUNCTION__);
-+ return;
-+ }
-+
-+ if (!(ch_status & DCSR_END_BLOCK)) {
-+ dprintk ("[%s] y-fail\n", __FUNCTION__);
-+ return;
-+ }
-+
-+ if (s->active) {
-+ unsigned int dma_size;
-+ unsigned int offset;
-+ snd_pcm_runtime_t *runtime;
-+
-+ snd_pcm_period_elapsed (s->stream);
-+
-+ spin_lock (&s->lock);
-+ runtime=s->stream->runtime;
-+
-+ dma_size = frames_to_bytes(runtime, runtime->period_size);
-+ offset = dma_size * s->period;
-+ snd_assert(dma_size <= AUDIO_DMA_BUF_SIZE,);
-+
-+ dprintk ("pb: offset=%08lx size=%u period=%u\n", (unsigned long)(runtime->dma_area + offset), dma_size, s->period);
-+#if 0
-+ omap_set_dma_transfer_params(channel, OMAP_DMA_DATA_TYPES16, 32, dma_size/(2*32), OMAP_DMA_SYNC_ELEMENT);
-+ omap_set_dma_dest_params(channel, OMAP_DMA_PORT_MPUI, OMAP_DMA_AMODE_CONSTANT, (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1));
-+ omap_set_dma_src_params(channel, 0x00, 0x01, (unsigned long)(runtime->dma_area + offset));
-+ omap_start_dma (channel);
-+#else
-+// omap_set_gpio_dataout (2, 1);
-+ omap_set_dma_transfer_params (channel,
-+ OMAP_DMA_DATA_TYPE_S16,
-+ dma_size >> 1, 1,
-+ OMAP_DMA_SYNC_ELEMENT
-+ );
-+ omap_set_dma_dest_params (channel,
-+// OMAP_DMA_PORT_TIPB,
-+ OMAP_DMA_PORT_MPUI,
-+ OMAP_DMA_AMODE_CONSTANT,
-+ (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1)
-+ );
-+ omap_set_dma_src_params (channel,
-+ OMAP_DMA_PORT_EMIFF,
-+ OMAP_DMA_AMODE_POST_INC,
-+ runtime->dma_area + offset
-+ );
-+ omap_start_dma (channel);
-+// omap_set_gpio_dataout (2, 0);
-+#endif
-+
-+ s->period++;
-+ s->period %= runtime->periods;
-+// s->periods++;
-+
-+ s->offset = offset;
-+
-+ spin_unlock (&s->lock);
-+ }
-+
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+} /* tsc2101_playback_callback */
-+
-+static void
-+tsc2101_capture_callback (int channel, u16 ch_status, void *data) {
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ omap_start_dma (channel);
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+} /* tsc2101_capture_callback */
-+
-+static int
-+__tsc2101_trigger (snd_pcm_substream_t *substream, int command) {
-+ snd_card_tsc2101_t *chip = snd_pcm_substream_chip (substream);
-+ audio_stream_t *s = &chip->s[substream->pstr->stream];
-+ int err=0;
-+
-+ dprintk ("[%s]\n", __FUNCTION__);
-+
-+ switch (command) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ dprintk ("[%s] command=start(%d)\n", __FUNCTION__, command);
-+ s->active++;
-+ omap_clear_dma (s->channel);
-+ if (s->sid == SNDRV_PCM_STREAM_PLAYBACK)
-+ tsc2101_playback_callback (s->channel, 32, (void *)s);
-+ else
-+ tsc2101_capture_callback (s->channel, 32, (void *)s);
-+ break;
-+
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ dprintk ("[%s] command=stop(%d)\n", __FUNCTION__, command);
-+ // TODO: be sure that all data has been xfered
-+ s->active--;
-+ spin_lock (&s->lock);
-+ omap_clear_dma (s->channel);
-+ omap_stop_dma (s->channel);
-+ spin_unlock (&s->lock);
-+ break;
-+
-+ case SNDRV_PCM_TRIGGER_SUSPEND:
-+ dprintk ("[%s] command=suspend(%d)\n", __FUNCTION__, command);
-+ case SNDRV_PCM_TRIGGER_RESUME:
-+ dprintk ("[%s] command=resume(%d)\n", __FUNCTION__, command);
-+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+ dprintk ("[%s] command=pause.push(%d)\n", __FUNCTION__, command);
-+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+ dprintk ("[%s] command=pause.release(%d)\n", __FUNCTION__, command);
-+ default:
-+ err = -EINVAL;
-+ break;
-+ } /* switch (command) */
-+
-+ dprintk ("[%s] exit (%d)\n", __FUNCTION__, err);
-+ return err;
-+} /* __tsc2101_trigger */
-+
-+static snd_pcm_uframes_t
-+__tsc2101_pointer (snd_pcm_substream_t *substream) {
-+ snd_card_tsc2101_t *chip = snd_pcm_substream_chip (substream);
-+ snd_pcm_runtime_t *runtime = substream->runtime;
-+ audio_stream_t *s = &chip->s[substream->pstr->stream];
-+ unsigned long flags;
-+ snd_pcm_uframes_t offset;
-+ dma_addr_t ptr;
-+
-+ dprintk ("[%s]\n", __FUNCTION__);
-+
-+ spin_lock_irqsave (&s->lock, flags);
-+ ptr=omap_get_dma_src_pos (s->channel);
-+ dprintk ("xxxx: [%08lx,%08lx] ptr=%08lx:%08lx\n",
-+ (unsigned long)runtime->dma_area,
-+ (unsigned long)runtime->dma_addr,
-+ (unsigned long)ptr,
-+ (unsigned long)runtime->buffer_size);
-+ spin_unlock_irqrestore (&s->lock, flags);
-+
-+ offset=bytes_to_frames (runtime, ptr - runtime->dma_addr);
-+ if ((offset >= runtime->buffer_size) || (offset < 0))
-+ offset=0;
-+ dprintk ("[%s] pass:%lu\n", __FUNCTION__, offset);
-+ return offset;
-+} /* __tsc2101_pointer */
-+
-+static snd_pcm_ops_t playback_ops = {
-+ .open = __tsc2101_open,
-+ .close = __tsc2101_close,
-+ .ioctl = snd_pcm_lib_ioctl,
-+ .hw_params = __tsc2101_hw_params,
-+ .hw_free = __tsc2101_hw_free,
-+ .prepare = __tsc2101_prepare,
-+ .trigger = __tsc2101_trigger,
-+ .pointer = __tsc2101_pointer,
-+};
-+
-+static snd_pcm_ops_t capture_ops = {
-+ .open = __tsc2101_open,
-+ .close = __tsc2101_close,
-+ .ioctl = snd_pcm_lib_ioctl,
-+ .hw_params = __tsc2101_hw_params,
-+ .hw_free = __tsc2101_hw_free,
-+ .prepare = __tsc2101_prepare,
-+ .trigger = __tsc2101_trigger,
-+ .pointer = __tsc2101_pointer,
-+};
-+
-+static void
-+tsc2101_audio_init (snd_card_tsc2101_t *tsc2101) {
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ omap_set_gpio_dataout (2, 0);
-+ omap_set_gpio_direction (2, 0);
-+
-+ /* initialize mcbsp */
-+ omap_mcbsp_request (AUDIO_MCBSP);
-+ omap_mcbsp_stop (AUDIO_MCBSP);
-+
-+ omap_mcbsp_config (AUDIO_MCBSP, &mcbsp_cfg);
-+ omap_mcbsp_start (AUDIO_MCBSP);
-+
-+ omap_tsc2101_enable ();
-+#if 0
-+ omap_tsc2101_write (
-+ TSC2101_AUDIO_CODEC_REGISTERS,
-+ TSC2101_CODEC_POWER_CTRL,
-+ 0x0000);
-+ omap_tsc2101_write (
-+ TSC2101_AUDIO_CODEC_REGISTERS,
-+ TSC2101_AUDIO_CTRL_5,
-+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
-+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
-+ AC5_HDSCPTC);
-+#else
-+#ifdef DUMP_TSC2101_REGISTERS
-+ dump_tsc2101_reg ();
-+#endif /* DUMP_TSC2101_REGISTERS */
-+
-+ omap_tsc2101_write (2, TSC2101_CODEC_POWER_CTRL, 0x0000);
-+
-+ /*Mute Analog Sidetone */
-+ /*Select MIC_INHED input for headset */
-+ /*Cell Phone In not connected */
-+ omap_tsc2101_write (2, TSC2101_MIXER_PGA_CTRL,
-+ MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
-+
-+ /* Set record source */
-+ omap_tsc2101_write (2, TSC2101_MIXER_PGA_CTRL, MPC_MICSEL(0));
-+
-+ /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
-+ /* 1dB AGC hysteresis */
-+ /* MICes bias 2V */
-+ omap_tsc2101_write (2, TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
-+
-+ /* Set codec output volume */
-+ omap_tsc2101_write (2, TSC2101_DAC_GAIN_CTRL, 0x0000);
-+
-+ /* DAC left and right routed to SPK2 */
-+ /* SPK1/2 unmuted */
-+ omap_tsc2101_write (2, TSC2101_AUDIO_CTRL_5,
-+ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
-+ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
-+ AC5_HDSCPTC);
-+
-+ /* OUT8P/N muted, CPOUT muted */
-+
-+ omap_tsc2101_write (2, TSC2101_AUDIO_CTRL_6,
-+ AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
-+ AC6_VGNDSCPTC);
-+
-+ /* Headset/Hook switch detect disabled */
-+ omap_tsc2101_write (2, TSC2101_AUDIO_CTRL_7, 0x0000);
-+
-+ /* mic input volume control */
-+ omap_tsc2101_write(2, TSC2101_HANDSET_GAIN_CTRL, HNGC_ADPGA_HND(25));
-+#endif
-+
-+#ifdef DUMP_TSC2101_REGISTERS
-+ dump_tsc2101_reg ();
-+#endif /* DUMP_TSC2101_REGISTERS */
-+
-+ __set_samplerate (tsc2101, tsc2101->samplerate);
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+} /* tsc2101_audio_init */
-+
-+int
-+snd_tsc2101_setup_pcm (snd_card_tsc2101_t *tsc2101) {
-+ snd_pcm_t *pcm=0;
-+ int err=0;
-+
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ if (!tsc2101)
-+ return -EINVAL;
-+ if ((err=snd_pcm_new (tsc2101->card, "TSC2101 PCM", 0, 1, 1, &pcm)) < 0)
-+ return err;
-+
-+ if ((err=snd_pcm_lib_preallocate_pages_for_all (pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data (GFP_KERNEL), 128, 128*1024)) < 0)
-+ return err;
-+
-+ snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
-+ snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
-+
-+ pcm->private_data=tsc2101;
-+ pcm->info_flags = 0;
-+ strncpy (pcm->name, "TSC2101 PCM", sizeof (pcm->name));
-+
-+ spin_lock_init (&tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].lock);
-+ tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].id = "TSC2101 out";
-+ tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].sid = SNDRV_PCM_STREAM_PLAYBACK;
-+ tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].dev = AUDIO_DMA_TX;
-+ if ((err=omap_request_dma (
-+ tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].dev,
-+ tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].id,
-+ tsc2101_playback_callback,
-+ (void *)&tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK],
-+ &tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].channel)) < 0)
-+ return err;
-+ dprintk ("TX dev=%u channel=%u\n", tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].dev, tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].channel);
-+
-+ spin_lock_init (&tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].lock);
-+ tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].id = "TSC2101 in";
-+ tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].sid = SNDRV_PCM_STREAM_CAPTURE;
-+ tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].dev = AUDIO_DMA_RX;
-+ if ((err=omap_request_dma (
-+ tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].dev,
-+ tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].id,
-+ tsc2101_capture_callback,
-+ (void *)&tsc2101->s[SNDRV_PCM_STREAM_CAPTURE],
-+ &tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].channel)) < 0)
-+ return err;
-+ dprintk ("RX dev=%u channel=%u\n", tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].dev, tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].channel);
-+
-+ tsc2101_audio_init (tsc2101);
-+
-+ tsc2101->pcm=pcm;
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+ return 0;
-+} /* snd_tsc2101_setup_pcm */
-+
-+void
-+snd_tsc2101_disable_pcm (snd_card_tsc2101_t *tsc2101) {
-+ dprintk ("[%s]\n", __FUNCTION__);
-+ omap_stop_dma (tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].channel);
-+ omap_free_dma (tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].channel);
-+ omap_stop_dma (tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].channel);
-+ omap_free_dma (tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].channel);
-+
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(2);
-+
-+ omap_mcbsp_stop (AUDIO_MCBSP);
-+ omap_mcbsp_free (AUDIO_MCBSP);
-+
-+ omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS, TSC2101_CODEC_POWER_CTRL, ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
-+ omap_tsc2101_disable ();
-+ dprintk ("[%s] pass\n", __FUNCTION__);
-+} /* snd_tsc2101_disable_pcm */
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap-alsa-dma.c bt_kernel/sound/arm/omap-alsa-dma.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/arm/omap-alsa-dma.c 2005-10-30 17:44:20.392618150 +0200
-+++ bt_kernel/sound/arm/omap-alsa-dma.c 2005-10-30 16:32:39.609796000 +0200
-@@ -325,9 +325,11 @@
- int cfn = dma_size / (2 * cen);
- FN_IN;
- omap_set_dma_dest_params(channel, 0x05, 0x00,
-- (OMAP1610_MCBSP1_BASE + 0x806));
-- omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr);
-- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);
-+ (OMAP1610_MCBSP1_BASE + 0x806),
-+ 0, 0);
-+ omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
-+ 0, 0);
-+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
- }
-@@ -341,9 +343,10 @@
- int cfn = dma_size / (2 * cen);
- FN_IN;
- omap_set_dma_src_params(channel, 0x05, 0x00,
-- (OMAP1610_MCBSP1_BASE + 0x802));
-- omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr);
-- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);
-+ (OMAP1610_MCBSP1_BASE + 0x802),
-+ 0, 0);
-+ omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
-+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
- }
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/oss/Kconfig bt_kernel/sound/oss/Kconfig
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/oss/Kconfig 2005-10-30 17:44:20.459607487 +0200
-+++ bt_kernel/sound/oss/Kconfig 2005-10-22 03:52:45.687256000 +0300
-@@ -12,7 +12,7 @@
-
- config SOUND_OMAP_TSC2101
- tristate "TSC2101 Stereo Codec"
-- depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 )
-+ depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H6300)
- select OMAP_TSC2101
- select OMAP_UWIRE if ARCH_OMAP
- ---help---
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/oss/omap-audio-dma-intfc.c bt_kernel/sound/oss/omap-audio-dma-intfc.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/oss/omap-audio-dma-intfc.c 2005-10-30 17:44:20.656576134 +0200
-+++ bt_kernel/sound/oss/omap-audio-dma-intfc.c 2005-10-30 16:32:39.609796000 +0200
-@@ -701,9 +701,10 @@
- int cfn = dma_size / (2 * cen);
- FN_IN;
- omap_set_dma_dest_params(channel, 0x05, 0x00,
-- (OMAP1610_MCBSP1_BASE + 0x806));
-- omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr);
-- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);
-+ (OMAP1610_MCBSP1_BASE + 0x806),
-+ 0, 0);
-+ omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
-+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
- }
-@@ -716,9 +717,10 @@
- int cfn = dma_size / (2 * cen);
- FN_IN;
- omap_set_dma_src_params(channel, 0x05, 0x00,
-- (OMAP1610_MCBSP1_BASE + 0x802));
-- omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr);
-- omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);
-+ (OMAP1610_MCBSP1_BASE + 0x802),
-+ 0, 0);
-+ omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
-+ omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
- FN_OUT(0);
- return 0;
- }
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/oss/omap-audio-tsc2101.c bt_kernel/sound/oss/omap-audio-tsc2101.c
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/sound/oss/omap-audio-tsc2101.c 2005-10-30 17:44:20.697569609 +0200
-+++ bt_kernel/sound/oss/omap-audio-tsc2101.c 2005-10-22 03:52:45.687256000 +0300
-@@ -48,7 +48,7 @@
- #include "omap-audio.h"
- #include "omap-audio-dma-intfc.h"
- #include <asm/arch/mcbsp.h>
--#if CONFIG_ARCH_OMAP16XX
-+#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_MACH_OMAP_H6300)
- #include <../drivers/ssi/omap-uwire.h>
- #include <asm/arch/dsp_common.h>
- #else
-@@ -72,6 +72,8 @@
-
- #if CONFIG_ARCH_OMAP16XX
- #define PLATFORM_NAME "OMAP16XX"
-+#elif CONFIG_MACH_OMAP_H6300
-+#define PLATFORM_NAME "OMAP15XX"
- #endif
-
- #if CONFIG_ARCH_OMAP16XX
-@@ -90,7 +92,7 @@
- #define LEAVE_CS 0x80
-
- /* Select the McBSP For Audio */
--#if CONFIG_ARCH_OMAP16XX
-+#if defined (CONFIG_ARCH_OMAP16XX) || defined(CONFIG_MACH_OMAP_H6300)
- #define AUDIO_MCBSP OMAP_MCBSP1
- #else
- #error "UnSupported Configuration"
-@@ -124,7 +126,7 @@
- /*********** Debug Macros ********/
- /* To Generate a rather shrill tone -test the entire path */
- //#define TONE_GEN
--/* To Generate a tone for each keyclick - test the tsc,spi paths*/
-+///* To Generate a tone for each keyclick - test the tsc,spi paths*/
- //#define TEST_KEYCLICK
- /* To dump the tsc registers for debug */
- //#define TSC_DUMP_REGISTERS
-@@ -215,6 +217,17 @@
- };
-
- static struct omap_mcbsp_reg_cfg initial_config = {
-+#ifdef CONFIG_MACH_OMAP_H6300
-+ .spcr2 = 0x0005,
-+ .spcr1 = 0x0005,
-+ .rcr2 = 0x8041,
-+ .rcr1 = 0x8041,
-+ .xcr2 = 0x00a1,
-+ .xcr1 = 0x00a1,
-+ .srgr2 = 0xb000,
-+ .srgr1 = 0xb000,
-+ .pcr0 = 0x0081,
-+#else
- .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
- .spcr1 = RINTM(3) | RRST,
- .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
-@@ -238,6 +251,7 @@
- #endif /* tsc Master defs */
-
- #endif /* platform specific inits */
-+#endif /* CONFIG_MACH_OMAP_H6300 */
- };
-
- /***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
-diff -Naur /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/usr/.gitignore bt_kernel/usr/.gitignore
---- /home/lamikr/own/h6340/kernel/linux-2.6.14-rc5/usr/.gitignore 2005-10-20 09:23:05.000000000 +0300
-+++ bt_kernel/usr/.gitignore 1970-01-01 02:00:00.000000000 +0200
-@@ -1,7 +0,0 @@
--#
--# Generated files
--#
--gen_init_cpio
--initramfs_data.cpio
--initramfs_data.cpio.gz
--initramfs_list
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14.1-omap1-h6300
+# Wed Nov 23 00:43:00 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+CONFIG_ARCH_OMAP15XX=y
+# CONFIG_ARCH_OMAP16XX is not set
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+CONFIG_MACH_OMAP_H6300=y
+# CONFIG_MACH_VOICEBLUE is not set
+# CONFIG_MACH_NETSTAR is not set
+# CONFIG_MACH_OMAP_PALMTE is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+CONFIG_OMAP_ARM_168MHZ=y
+CONFIG_OMAP_ARM_150MHZ=y
+CONFIG_OMAP_ARM_120MHZ=y
+CONFIG_OMAP_ARM_60MHZ=y
+CONFIG_OMAP_ARM_30MHZ=y
+CONFIG_OMAP_DSP=y
+CONFIG_OMAP_DSP_MBCMD_VERBOSE=y
+CONFIG_OMAP_DSP_TASK_MULTIOPEN=y
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM925T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+
+#
+# PC-card bridges
+#
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=tty0 root=/dev/nfs nfsroot=192.168.2.1:/opt/h6300/rootfs,rsize=8192,wsize=8192 ip=192.168.2.2:192.168.2.1:192.168.2.1:255.0.0.0:ipaq:"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_NWFPE_XP=y
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_APM=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+# CONFIG_NETFILTER_NETLINK is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_PPTP is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+# CONFIG_IP_NF_MATCH_MARK is not set
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_LENGTH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_TCPMSS is not set
+# CONFIG_IP_NF_MATCH_HELPER is not set
+# CONFIG_IP_NF_MATCH_STATE is not set
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_PHYSDEV is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_DCCP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+# CONFIG_IP_NF_MATCH_CONNMARK is not set
+# CONFIG_IP_NF_MATCH_CONNBYTES is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+# CONFIG_IP_NF_MATCH_STRING is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_TARGET_NFQUEUE is not set
+# CONFIG_IP_NF_NAT is not set
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_TARGET_TOS is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+# CONFIG_IP_NF_TARGET_MARK is not set
+# CONFIG_IP_NF_TARGET_CLASSIFY is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_TARGET_CONNMARK is not set
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_LIMIT is not set
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+# CONFIG_IP6_NF_MATCH_MARK is not set
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+# CONFIG_IP6_NF_MATCH_PHYSDEV is not set
+CONFIG_IP6_NF_FILTER=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+# CONFIG_IP6_NF_TARGET_NFQUEUE is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_MARK is not set
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+# CONFIG_BRIDGE_EBT_BROUTE is not set
+# CONFIG_BRIDGE_EBT_T_FILTER is not set
+# CONFIG_BRIDGE_EBT_T_NAT is not set
+# CONFIG_BRIDGE_EBT_802_3 is not set
+# CONFIG_BRIDGE_EBT_AMONG is not set
+# CONFIG_BRIDGE_EBT_ARP is not set
+# CONFIG_BRIDGE_EBT_IP is not set
+# CONFIG_BRIDGE_EBT_LIMIT is not set
+# CONFIG_BRIDGE_EBT_MARK is not set
+# CONFIG_BRIDGE_EBT_PKTTYPE is not set
+# CONFIG_BRIDGE_EBT_STP is not set
+# CONFIG_BRIDGE_EBT_VLAN is not set
+# CONFIG_BRIDGE_EBT_ARPREPLY is not set
+# CONFIG_BRIDGE_EBT_DNAT is not set
+# CONFIG_BRIDGE_EBT_MARK_T is not set
+# CONFIG_BRIDGE_EBT_REDIRECT is not set
+# CONFIG_BRIDGE_EBT_SNAT is not set
+# CONFIG_BRIDGE_EBT_LOG is not set
+# CONFIG_BRIDGE_EBT_ULOG is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM 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_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+CONFIG_OMAP1610_IR=m
+CONFIG_SMC_IRCC_FIR=m
+# CONFIG_ALI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+# CONFIG_BT_SCO is not set
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_BCSP_TXCRC is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_H6300=m
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=m
+CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=1
+CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+CONFIG_MTD_ABSENT=m
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x4000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PCMCIA is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_SLRAM=m
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLKMTD=m
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+CONFIG_MTD_DOC2000=m
+CONFIG_MTD_DOC2001=m
+CONFIG_MTD_DOC2001PLUS=m
+CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
+CONFIG_MTD_DOCPROBE_ADVANCED=y
+CONFIG_MTD_DOCPROBE_ADDRESS=0x0000
+CONFIG_MTD_DOCPROBE_HIGH=y
+CONFIG_MTD_DOCPROBE_55AA=y
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_TOTO is not set
+CONFIG_MTD_NAND_IDS=m
+CONFIG_MTD_NAND_DISKONCHIP=m
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
+CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x0
+# CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH is not set
+CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# 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=16384
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+CONFIG_STRIP=y
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+CONFIG_ATMEL=y
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_HOSTAP is not set
+CONFIG_NET_WIRELESS=y
+CONFIG_ACX=m
+# CONFIG_ACX_USB is not set
+CONFIG_ACX_CFI=y
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPPOE=y
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=m
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_SERIAL=y
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+CONFIG_TOUCHSCREEN_OMAP=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=y
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_NVRAM=y
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_PARPORT_LIGHT=m
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=m
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+CONFIG_PCA9535=m
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_TPS65010 is not set
+CONFIG_SENSORS_TLV320AIC23=m
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_INTERNAL=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+CONFIG_FB_OMAP_DMA_TUNE=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+CONFIG_LOGO_LINUX_VGA16=y
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+
+#
+# Telephony Support
+#
+CONFIG_PHONE=m
+# CONFIG_PHONE_IXJ is not set
+CONFIG_GSM_H6300=m
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+CONFIG_SND_OMAP_TSC2101=m
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# PCMCIA devices
+#
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+CONFIG_SOUND_OMAP=m
+CONFIG_SOUND_OMAP_TSC2101=m
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+CONFIG_USB_ACM=y
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+CONFIG_USB_SERIAL_VISOR=y
+CONFIG_USB_SERIAL_IPAQ=y
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BROKEN_RFD=y
+CONFIG_MMC_BULKTRANSFER=y
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_WBSD is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+CONFIG_OMAP_TSC2101=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=4
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION 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_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+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
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_REED_SOLOMON=m
+CONFIG_REED_SOLOMON_DEC16=y
--- /dev/null
+diff -Naur linux-2.6.14-omap2/arch/arm/configs/omap_h6300_defconfig linux-h6300-omap2-2.6.14.3/arch/arm/configs/omap_h6300_defconfig
+--- linux-2.6.14-omap2/arch/arm/configs/omap_h6300_defconfig 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/arch/arm/configs/omap_h6300_defconfig 2005-11-11 04:13:42.000000000 +0200
+@@ -0,0 +1,1538 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.14-omap1-h6300
++# Thu Nov 10 05:21:43 2005
++#
++CONFIG_ARM=y
++CONFIG_MMU=y
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_CLEAN_COMPILE is not set
++CONFIG_BROKEN=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++
++#
++# General setup
++#
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_SYSCTL=y
++# CONFIG_AUDIT is not set
++CONFIG_HOTPLUG=y
++CONFIG_KOBJECT_UEVENT=y
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_EMBEDDED=y
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SHMEM=y
++CONFIG_CC_ALIGN_FUNCTIONS=0
++CONFIG_CC_ALIGN_LABELS=0
++CONFIG_CC_ALIGN_LOOPS=0
++CONFIG_CC_ALIGN_JUMPS=0
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++CONFIG_OBSOLETE_MODPARM=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_IOP3XX is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++CONFIG_ARCH_OMAP=y
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_IMX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_AAEC2000 is not set
++
++#
++# TI OMAP Implementations
++#
++CONFIG_ARCH_OMAP1=y
++# CONFIG_ARCH_OMAP2 is not set
++
++#
++# OMAP Feature Selections
++#
++# CONFIG_OMAP_RESET_CLOCKS is not set
++# CONFIG_OMAP_BOOT_TAG is not set
++CONFIG_OMAP_MUX=y
++# CONFIG_OMAP_MUX_DEBUG is not set
++CONFIG_OMAP_MUX_WARNINGS=y
++CONFIG_OMAP_MPU_TIMER=y
++# CONFIG_OMAP_32K_TIMER is not set
++CONFIG_OMAP_LL_DEBUG_UART1=y
++# CONFIG_OMAP_LL_DEBUG_UART2 is not set
++# CONFIG_OMAP_LL_DEBUG_UART3 is not set
++CONFIG_OMAP_SERIAL_WAKE=y
++
++#
++# OMAP Core Type
++#
++# CONFIG_ARCH_OMAP730 is not set
++CONFIG_ARCH_OMAP15XX=y
++# CONFIG_ARCH_OMAP16XX is not set
++
++#
++# OMAP Board Type
++#
++# CONFIG_MACH_OMAP_INNOVATOR is not set
++CONFIG_MACH_OMAP_H6300=y
++# CONFIG_MACH_VOICEBLUE is not set
++# CONFIG_MACH_NETSTAR is not set
++# CONFIG_MACH_OMAP_PALMTE is not set
++# CONFIG_MACH_OMAP_GENERIC is not set
++
++#
++# OMAP CPU Speed
++#
++# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
++CONFIG_OMAP_ARM_168MHZ=y
++CONFIG_OMAP_ARM_150MHZ=y
++CONFIG_OMAP_ARM_120MHZ=y
++CONFIG_OMAP_ARM_60MHZ=y
++CONFIG_OMAP_ARM_30MHZ=y
++CONFIG_OMAP_DSP=y
++CONFIG_OMAP_DSP_MBCMD_VERBOSE=y
++CONFIG_OMAP_DSP_TASK_MULTIOPEN=y
++CONFIG_OMAP_DSP_FBEXPORT=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_ARM925T=y
++CONFIG_CPU_32v4=y
++CONFIG_CPU_ABRT_EV4T=y
++CONFIG_CPU_CACHE_V4WT=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++
++#
++# Processor Features
++#
++CONFIG_ARM_THUMB=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++CONFIG_CPU_DCACHE_WRITETHROUGH=y
++
++#
++# Bus support
++#
++CONFIG_ISA_DMA_API=y
++
++#
++# PCCARD (PCMCIA/CardBus) support
++#
++CONFIG_PCCARD=m
++# CONFIG_PCMCIA_DEBUG is not set
++CONFIG_PCMCIA=m
++CONFIG_PCMCIA_LOAD_CIS=y
++CONFIG_PCMCIA_IOCTL=y
++
++#
++# PC-card bridges
++#
++
++#
++# Kernel Features
++#
++# CONFIG_SMP is not set
++# CONFIG_PREEMPT is not set
++# CONFIG_NO_IDLE_HZ is not set
++# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++# CONFIG_SPARSEMEM_STATIC is not set
++CONFIG_LEDS=y
++CONFIG_LEDS_TIMER=y
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=tty0 root=/dev/nfs nfsroot=192.168.2.1:/opt/h6300/rootfs,rsize=8192,wsize=8192 ip=192.168.2.2:192.168.2.1:192.168.2.1:255.0.0.0:ipaq:"
++# CONFIG_XIP_KERNEL is not set
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++CONFIG_CPU_FREQ_DEBUG=y
++CONFIG_CPU_FREQ_STAT=y
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++CONFIG_FPE_NWFPE_XP=y
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_MISC=y
++# CONFIG_ARTHUR is not set
++
++#
++# Power management options
++#
++CONFIG_PM=y
++CONFIG_APM=y
++
++#
++# Networking
++#
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++CONFIG_XFRM_USER=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++CONFIG_SYN_COOKIES=y
++CONFIG_INET_AH=m
++CONFIG_INET_ESP=m
++CONFIG_INET_IPCOMP=m
++CONFIG_INET_TUNNEL=m
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_BIC=y
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++CONFIG_IPV6=y
++CONFIG_IPV6_PRIVACY=y
++CONFIG_INET6_AH=m
++CONFIG_INET6_ESP=m
++CONFIG_INET6_IPCOMP=m
++CONFIG_INET6_TUNNEL=m
++CONFIG_IPV6_TUNNEL=m
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_BRIDGE_NETFILTER=y
++# CONFIG_NETFILTER_NETLINK is not set
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_IP_NF_CONNTRACK=m
++CONFIG_IP_NF_CT_ACCT=y
++CONFIG_IP_NF_CONNTRACK_MARK=y
++# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
++CONFIG_IP_NF_CT_PROTO_SCTP=m
++CONFIG_IP_NF_FTP=m
++CONFIG_IP_NF_IRC=m
++# CONFIG_IP_NF_NETBIOS_NS is not set
++CONFIG_IP_NF_TFTP=m
++# CONFIG_IP_NF_AMANDA is not set
++# CONFIG_IP_NF_PPTP is not set
++CONFIG_IP_NF_QUEUE=m
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_MATCH_LIMIT=m
++CONFIG_IP_NF_MATCH_IPRANGE=m
++CONFIG_IP_NF_MATCH_MAC=m
++CONFIG_IP_NF_MATCH_PKTTYPE=m
++# CONFIG_IP_NF_MATCH_MARK is not set
++# CONFIG_IP_NF_MATCH_MULTIPORT is not set
++# CONFIG_IP_NF_MATCH_TOS is not set
++# CONFIG_IP_NF_MATCH_RECENT is not set
++# CONFIG_IP_NF_MATCH_ECN is not set
++# CONFIG_IP_NF_MATCH_DSCP is not set
++# CONFIG_IP_NF_MATCH_AH_ESP is not set
++# CONFIG_IP_NF_MATCH_LENGTH is not set
++# CONFIG_IP_NF_MATCH_TTL is not set
++# CONFIG_IP_NF_MATCH_TCPMSS is not set
++# CONFIG_IP_NF_MATCH_HELPER is not set
++# CONFIG_IP_NF_MATCH_STATE is not set
++# CONFIG_IP_NF_MATCH_CONNTRACK is not set
++# CONFIG_IP_NF_MATCH_OWNER is not set
++# CONFIG_IP_NF_MATCH_PHYSDEV is not set
++# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
++# CONFIG_IP_NF_MATCH_REALM is not set
++# CONFIG_IP_NF_MATCH_SCTP is not set
++# CONFIG_IP_NF_MATCH_DCCP is not set
++# CONFIG_IP_NF_MATCH_COMMENT is not set
++# CONFIG_IP_NF_MATCH_CONNMARK is not set
++# CONFIG_IP_NF_MATCH_CONNBYTES is not set
++# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
++# CONFIG_IP_NF_MATCH_STRING is not set
++# CONFIG_IP_NF_FILTER is not set
++# CONFIG_IP_NF_TARGET_LOG is not set
++# CONFIG_IP_NF_TARGET_ULOG is not set
++# CONFIG_IP_NF_TARGET_TCPMSS is not set
++# CONFIG_IP_NF_TARGET_NFQUEUE is not set
++# CONFIG_IP_NF_NAT is not set
++CONFIG_IP_NF_MANGLE=m
++# CONFIG_IP_NF_TARGET_TOS is not set
++# CONFIG_IP_NF_TARGET_ECN is not set
++# CONFIG_IP_NF_TARGET_DSCP is not set
++# CONFIG_IP_NF_TARGET_MARK is not set
++# CONFIG_IP_NF_TARGET_CLASSIFY is not set
++# CONFIG_IP_NF_TARGET_TTL is not set
++# CONFIG_IP_NF_TARGET_CONNMARK is not set
++# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
++# CONFIG_IP_NF_RAW is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++
++#
++# IPv6: Netfilter Configuration (EXPERIMENTAL)
++#
++CONFIG_IP6_NF_QUEUE=m
++CONFIG_IP6_NF_IPTABLES=m
++# CONFIG_IP6_NF_MATCH_LIMIT is not set
++CONFIG_IP6_NF_MATCH_MAC=m
++CONFIG_IP6_NF_MATCH_RT=m
++# CONFIG_IP6_NF_MATCH_OPTS is not set
++# CONFIG_IP6_NF_MATCH_FRAG is not set
++# CONFIG_IP6_NF_MATCH_HL is not set
++# CONFIG_IP6_NF_MATCH_MULTIPORT is not set
++# CONFIG_IP6_NF_MATCH_OWNER is not set
++# CONFIG_IP6_NF_MATCH_MARK is not set
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++# CONFIG_IP6_NF_MATCH_AHESP is not set
++# CONFIG_IP6_NF_MATCH_LENGTH is not set
++# CONFIG_IP6_NF_MATCH_EUI64 is not set
++# CONFIG_IP6_NF_MATCH_PHYSDEV is not set
++CONFIG_IP6_NF_FILTER=m
++# CONFIG_IP6_NF_TARGET_LOG is not set
++# CONFIG_IP6_NF_TARGET_REJECT is not set
++# CONFIG_IP6_NF_TARGET_NFQUEUE is not set
++CONFIG_IP6_NF_MANGLE=m
++# CONFIG_IP6_NF_TARGET_MARK is not set
++# CONFIG_IP6_NF_TARGET_HL is not set
++CONFIG_IP6_NF_RAW=m
++
++#
++# Bridge: Netfilter Configuration
++#
++CONFIG_BRIDGE_NF_EBTABLES=m
++# CONFIG_BRIDGE_EBT_BROUTE is not set
++# CONFIG_BRIDGE_EBT_T_FILTER is not set
++# CONFIG_BRIDGE_EBT_T_NAT is not set
++# CONFIG_BRIDGE_EBT_802_3 is not set
++# CONFIG_BRIDGE_EBT_AMONG is not set
++# CONFIG_BRIDGE_EBT_ARP is not set
++# CONFIG_BRIDGE_EBT_IP is not set
++# CONFIG_BRIDGE_EBT_LIMIT is not set
++# CONFIG_BRIDGE_EBT_MARK is not set
++# CONFIG_BRIDGE_EBT_PKTTYPE is not set
++# CONFIG_BRIDGE_EBT_STP is not set
++# CONFIG_BRIDGE_EBT_VLAN is not set
++# CONFIG_BRIDGE_EBT_ARPREPLY is not set
++# CONFIG_BRIDGE_EBT_DNAT is not set
++# CONFIG_BRIDGE_EBT_MARK_T is not set
++# CONFIG_BRIDGE_EBT_REDIRECT is not set
++# CONFIG_BRIDGE_EBT_SNAT is not set
++# CONFIG_BRIDGE_EBT_LOG is not set
++# CONFIG_BRIDGE_EBT_ULOG is not set
++
++#
++# DCCP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_DCCP is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++# CONFIG_ATM 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_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_NET_CLS_ROUTE is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++CONFIG_IRDA=m
++
++#
++# IrDA protocols
++#
++CONFIG_IRLAN=m
++CONFIG_IRNET=m
++CONFIG_IRCOMM=m
++CONFIG_IRDA_ULTRA=y
++
++#
++# IrDA options
++#
++CONFIG_IRDA_CACHE_LAST_LSAP=y
++CONFIG_IRDA_FAST_RR=y
++# CONFIG_IRDA_DEBUG is not set
++
++#
++# Infrared-port device drivers
++#
++
++#
++# SIR device drivers
++#
++# CONFIG_IRTTY_SIR is not set
++
++#
++# Dongle support
++#
++
++#
++# Old SIR device drivers
++#
++# CONFIG_IRPORT_SIR is not set
++
++#
++# Old Serial dongle support
++#
++
++#
++# FIR device drivers
++#
++# CONFIG_USB_IRDA is not set
++# CONFIG_SIGMATEL_FIR is not set
++# CONFIG_NSC_FIR is not set
++# CONFIG_WINBOND_FIR is not set
++CONFIG_OMAP1610_IR=m
++CONFIG_SMC_IRCC_FIR=m
++# CONFIG_ALI_FIR is not set
++# CONFIG_VIA_FIR is not set
++CONFIG_BT=m
++CONFIG_BT_L2CAP=m
++# CONFIG_BT_SCO is not set
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=m
++
++#
++# Bluetooth device drivers
++#
++# CONFIG_BT_HCIUSB is not set
++CONFIG_BT_HCIUART=m
++CONFIG_BT_HCIUART_H4=y
++CONFIG_BT_HCIUART_BCSP=y
++# CONFIG_BT_HCIUART_BCSP_TXCRC is not set
++# CONFIG_BT_HCIBCM203X is not set
++# CONFIG_BT_HCIBPA10X is not set
++# CONFIG_BT_HCIBFUSB is not set
++# CONFIG_BT_HCIDTL1 is not set
++# CONFIG_BT_HCIBT3C is not set
++# CONFIG_BT_HCIBLUECARD is not set
++# CONFIG_BT_HCIBTUART is not set
++CONFIG_BT_HCIVHCI=m
++CONFIG_BT_H6300=m
++# CONFIG_IEEE80211 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++# CONFIG_DEBUG_DRIVER is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_CONCAT=y
++CONFIG_MTD_PARTITIONS=y
++CONFIG_MTD_REDBOOT_PARTS=y
++CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
++# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
++# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=m
++CONFIG_MTD_JEDECPROBE=m
++CONFIG_MTD_GEN_PROBE=m
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_GEOMETRY is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_OTP is not set
++CONFIG_MTD_CFI_INTELEXT=m
++CONFIG_MTD_CFI_AMDSTD=m
++CONFIG_MTD_CFI_AMDSTD_RETRY=1
++CONFIG_MTD_CFI_STAA=m
++CONFIG_MTD_CFI_UTIL=m
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++CONFIG_MTD_ABSENT=m
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_XIP is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++CONFIG_MTD_PHYSMAP=m
++CONFIG_MTD_PHYSMAP_START=0x8000000
++CONFIG_MTD_PHYSMAP_LEN=0x4000000
++CONFIG_MTD_PHYSMAP_BANKWIDTH=2
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_OMAP_NOR is not set
++# CONFIG_MTD_PCMCIA is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++CONFIG_MTD_SLRAM=m
++CONFIG_MTD_PHRAM=m
++CONFIG_MTD_MTDRAM=m
++CONFIG_MTDRAM_TOTAL_SIZE=4096
++CONFIG_MTDRAM_ERASE_SIZE=128
++CONFIG_MTD_BLKMTD=m
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++CONFIG_MTD_DOC2000=m
++CONFIG_MTD_DOC2001=m
++CONFIG_MTD_DOC2001PLUS=m
++CONFIG_MTD_DOCPROBE=m
++CONFIG_MTD_DOCECC=m
++CONFIG_MTD_DOCPROBE_ADVANCED=y
++CONFIG_MTD_DOCPROBE_ADDRESS=0x0000
++CONFIG_MTD_DOCPROBE_HIGH=y
++CONFIG_MTD_DOCPROBE_55AA=y
++
++#
++# NAND Flash Device Drivers
++#
++CONFIG_MTD_NAND=m
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_TOTO is not set
++CONFIG_MTD_NAND_IDS=m
++CONFIG_MTD_NAND_DISKONCHIP=m
++CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y
++CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x0
++# CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH is not set
++CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y
++# CONFIG_MTD_NAND_NANDSIM is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play support
++#
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_CRYPTOLOOP=m
++# 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=16384
++CONFIG_BLK_DEV_INITRD=y
++# CONFIG_CDROM_PKTCDVD is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_ATA_OVER_ETH is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++
++#
++# PHY device support
++#
++# CONFIG_PHYLIB is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++CONFIG_SMC91X=y
++# CONFIG_DM9000 is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++
++#
++# Ethernet (10000 Mbit)
++#
++
++#
++# Token Ring devices
++#
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++
++#
++# Obsolete Wireless cards support (pre-802.11)
++#
++CONFIG_STRIP=y
++# CONFIG_PCMCIA_WAVELAN is not set
++# CONFIG_PCMCIA_NETWAVE is not set
++
++#
++# Wireless 802.11 Frequency Hopping cards support
++#
++# CONFIG_PCMCIA_RAYCS is not set
++
++#
++# Wireless 802.11b ISA/PCI cards support
++#
++# CONFIG_AIRO is not set
++# CONFIG_HERMES is not set
++CONFIG_ATMEL=y
++
++#
++# Wireless 802.11b Pcmcia/Cardbus cards support
++#
++# CONFIG_AIRO_CS is not set
++# CONFIG_PCMCIA_ATMEL is not set
++# CONFIG_PCMCIA_WL3501 is not set
++# CONFIG_HOSTAP is not set
++CONFIG_NET_WIRELESS=y
++CONFIG_ACX=m
++# CONFIG_ACX_USB is not set
++CONFIG_ACX_CFI=y
++
++#
++# PCMCIA network device support
++#
++# CONFIG_NET_PCMCIA is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++CONFIG_PPP=y
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPP_FILTER=y
++CONFIG_PPP_ASYNC=y
++CONFIG_PPP_SYNC_TTY=y
++CONFIG_PPP_DEFLATE=y
++CONFIG_PPP_BSDCOMP=y
++CONFIG_PPPOE=y
++# CONFIG_SLIP is not set
++# CONFIG_SHAPER is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_TSDEV=y
++CONFIG_INPUT_TSDEV_SCREEN_X=240
++CONFIG_INPUT_TSDEV_SCREEN_Y=320
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++CONFIG_KEYBOARD_OMAP=m
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++CONFIG_MOUSE_SERIAL=y
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_INPUT_JOYSTICK is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++CONFIG_TOUCHSCREEN_OMAP=m
++CONFIG_INPUT_MISC=y
++CONFIG_INPUT_UINPUT=m
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++CONFIG_SERIO_LIBPS2=y
++CONFIG_SERIO_RAW=y
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_CS is not set
++CONFIG_SERIAL_8250_NR_UARTS=4
++# CONFIG_SERIAL_8250_EXTENDED is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_UNIX98_PTYS=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=256
++
++#
++# IPMI
++#
++# CONFIG_IPMI_HANDLER is not set
++
++#
++# Watchdog Cards
++#
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_NOWAYOUT=y
++
++#
++# Watchdog Device Drivers
++#
++CONFIG_SOFT_WATCHDOG=m
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_NVRAM=y
++# CONFIG_RTC is not set
++CONFIG_OMAP_RTC=y
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++
++#
++# PCMCIA character devices
++#
++# CONFIG_SYNCLINK_CS is not set
++# CONFIG_RAW_DRIVER is not set
++
++#
++# TPM devices
++#
++
++#
++# I2C support
++#
++CONFIG_I2C=m
++CONFIG_I2C_CHARDEV=m
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=m
++CONFIG_I2C_ALGOPCF=m
++CONFIG_I2C_ALGOPCA=m
++
++#
++# I2C Hardware Bus support
++#
++CONFIG_I2C_PARPORT_LIGHT=m
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_PCA_ISA is not set
++CONFIG_I2C_OMAP=m
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++CONFIG_PCA9535=m
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_RTC8564 is not set
++# CONFIG_TPS65010 is not set
++CONFIG_SENSORS_TLV320AIC23=m
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++
++#
++# Hardware Monitoring support
++#
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ASB100 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_FSCHER is not set
++# CONFIG_SENSORS_FSCPOS is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM75 is not set
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Misc devices
++#
++
++#
++# Multimedia Capabilities Port drivers
++#
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Digital Video Broadcasting Devices
++#
++# CONFIG_DVB is not set
++
++#
++# Graphics support
++#
++CONFIG_FB=y
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++CONFIG_FB_SOFT_CURSOR=y
++# CONFIG_FB_MACMODES is not set
++CONFIG_FB_MODE_HELPERS=y
++# CONFIG_FB_TILEBLITTING is not set
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_OMAP=y
++CONFIG_FB_OMAP_LCDC_INTERNAL=y
++# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
++CONFIG_FB_OMAP_DMA_TUNE=y
++# CONFIG_FB_VIRTUAL is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_FONTS=y
++# CONFIG_FONT_8x8 is not set
++# CONFIG_FONT_8x16 is not set
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_7x14 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++# CONFIG_FONT_ACORN_8x8 is not set
++CONFIG_FONT_MINI_4x6=y
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_10x18 is not set
++
++#
++# Logo configuration
++#
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++CONFIG_LOGO_LINUX_VGA16=y
++# CONFIG_LOGO_LINUX_CLUT224 is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++CONFIG_BACKLIGHT_DEVICE=y
++CONFIG_LCD_CLASS_DEVICE=y
++CONFIG_LCD_DEVICE=y
++
++#
++# Telephony Support
++#
++CONFIG_PHONE=m
++# CONFIG_PHONE_IXJ is not set
++CONFIG_GSM_H6300=m
++
++#
++# Sound
++#
++CONFIG_SOUND=m
++
++#
++# Advanced Linux Sound Architecture
++#
++# CONFIG_SND is not set
++
++#
++# Open Sound System
++#
++CONFIG_SOUND_PRIME=m
++CONFIG_SOUND_OMAP=m
++CONFIG_SOUND_OMAP_TSC2101=m
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_TVMIXER is not set
++# CONFIG_SOUND_AD1980 is not set
++
++#
++# USB support
++#
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB=y
++CONFIG_USB_DEBUG=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_BANDWIDTH is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_SUSPEND is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
++
++#
++# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
++#
++CONFIG_USB_ACM=y
++# CONFIG_USB_PRINTER is not set
++
++#
++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
++#
++# CONFIG_USB_STORAGE is not set
++
++#
++# USB Input Devices
++#
++# CONFIG_USB_HID is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_ACECAD is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++# CONFIG_USB_MTOUCH is not set
++# CONFIG_USB_ITMTOUCH is not set
++# CONFIG_USB_EGALAX is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++
++#
++# USB Multimedia devices
++#
++# CONFIG_USB_DABUSB is not set
++
++#
++# Video4Linux support is needed for USB Multimedia device support
++#
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++CONFIG_USB_USBNET=y
++CONFIG_USB_NET_AX8817X=y
++CONFIG_USB_NET_CDCETHER=y
++# CONFIG_USB_NET_GL620A is not set
++CONFIG_USB_NET_NET1080=y
++# CONFIG_USB_NET_PLUSB is not set
++# CONFIG_USB_NET_RNDIS_HOST is not set
++# CONFIG_USB_NET_CDC_SUBSET is not set
++CONFIG_USB_NET_ZAURUS=y
++# CONFIG_USB_ZD1201 is not set
++CONFIG_USB_MON=y
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++CONFIG_USB_SERIAL=y
++CONFIG_USB_SERIAL_CONSOLE=y
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRPRIME is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++CONFIG_USB_SERIAL_VISOR=y
++CONFIG_USB_SERIAL_IPAQ=y
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGETKIT is not set
++# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TEST is not set
++
++#
++# USB DSL modem support
++#
++
++#
++# USB Gadget Support
++#
++CONFIG_USB_GADGET=y
++CONFIG_USB_GADGET_DEBUG_FILES=y
++CONFIG_USB_GADGET_SELECTED=y
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_PXA2XX is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++CONFIG_USB_GADGET_OMAP=y
++CONFIG_USB_OMAP=y
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++# CONFIG_USB_GADGET_DUALSPEED is not set
++# CONFIG_USB_ZERO is not set
++CONFIG_USB_ETH=y
++# CONFIG_USB_ETH_RNDIS is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FILE_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
++
++#
++# MMC/SD Card support
++#
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_BROKEN_RFD=y
++CONFIG_MMC_BULKTRANSFER=y
++CONFIG_MMC_OMAP=y
++# CONFIG_MMC_WBSD is not set
++
++#
++# Synchronous Serial Interfaces (SSI)
++#
++CONFIG_OMAP_UWIRE=y
++CONFIG_OMAP_TSC2101=y
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++# CONFIG_EXT2_FS_XIP is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++# CONFIG_XFS_FS is not set
++# CONFIG_MINIX_FS is not set
++CONFIG_ROMFS_FS=y
++CONFIG_INOTIFY=y
++# CONFIG_QUOTA is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_AUTOFS_FS is not set
++CONFIG_AUTOFS4_FS=y
++# CONFIG_FUSE_FS is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=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_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++# CONFIG_RELAYFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS_FS=y
++CONFIG_JFFS_FS_VERBOSE=0
++CONFIG_JFFS_PROC_FS=y
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=4
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++CONFIG_JFFS2_COMPRESSION_OPTIONS=y
++CONFIG_JFFS2_ZLIB=y
++CONFIG_JFFS2_RTIME=y
++CONFIG_JFFS2_RUBIN=y
++# CONFIG_JFFS2_CMODE_NONE is not set
++CONFIG_JFFS2_CMODE_PRIORITY=y
++# CONFIG_JFFS2_CMODE_SIZE is not set
++CONFIG_CRAMFS=y
++# CONFIG_VXFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++
++#
++# Network File Systems
++#
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++CONFIG_NFS_V4=y
++# CONFIG_NFS_DIRECTIO is not set
++# CONFIG_NFSD is not set
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++# CONFIG_9P_FS is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION 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_EFI_PARTITION is not set
++
++#
++# Native Language Support
++#
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="utf8"
++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
++
++#
++# Profiling support
++#
++# CONFIG_PROFILING is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_LOG_BUF_SHIFT=17
++CONFIG_DETECT_SOFTLOCKUP=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_FS is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++
++#
++# Cryptographic options
++#
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++CONFIG_CRYPTO_SHA1=y
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_DEFLATE=m
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Hardware crypto devices
++#
++
++#
++# Library routines
++#
++CONFIG_CRC_CCITT=y
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++CONFIG_LIBCRC32C=y
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_REED_SOLOMON=m
++CONFIG_REED_SOLOMON_DEC16=y
+diff -Naur linux-2.6.14-omap2/arch/arm/Kconfig linux-h6300-omap2-2.6.14.3/arch/arm/Kconfig
+--- linux-2.6.14-omap2/arch/arm/Kconfig 2005-12-02 01:53:31.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/arch/arm/Kconfig 2005-10-14 18:55:31.000000000 +0300
+@@ -725,6 +725,8 @@
+
+ source "drivers/video/Kconfig"
+
++source "drivers/telephony/Kconfig"
++
+ source "sound/Kconfig"
+
+ source "drivers/usb/Kconfig"
+diff -Naur linux-2.6.14-omap2/arch/arm/mach-omap1/board-h6300.c linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/board-h6300.c
+--- linux-2.6.14-omap2/arch/arm/mach-omap1/board-h6300.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/board-h6300.c 2005-10-22 03:52:45.000000000 +0300
+@@ -0,0 +1,317 @@
++/*
++ * Modified from board-h6300.c
++ *
++ * Code for generic OMAP board. Should work on many OMAP systems where
++ * the device drivers take care of all the necessary hardware initialization.
++ * Do not put any board specific code to this file; create a new machine
++ * type if you need custom low-level initializations.
++ *
++ * 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/device.h>
++#include <linux/delay.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++#include <asm/mach/map.h>
++
++#include <asm/arch/gpio.h>
++
++#include <asm/arch/tc.h>
++#include <asm/arch/usb.h>
++
++#include <asm/arch/common.h>
++
++#include <asm/arch/h6300_uart_info.h>
++
++/*
++ * Bluetooth - Relies on h6300_bt module,
++ * so make the calls indirectly through pointers. Requires that the
++ * h6300_bt bluetooth module be loaded before any attempt to use
++ * bluetooth (obviously).
++ */
++
++static struct h6300_uart_funcs bt_funcs;
++static struct h6300_uart_funcs gsm_funcs;
++
++static void
++h6300_bt_configure(struct uart_omap_port *up, int enable)
++{
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_configure() started\n");
++ if (bt_funcs.configure != NULL)
++ bt_funcs.configure(up, enable);
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_configure() done\n");
++}
++
++static void
++h6300_bt_set_txrx(struct uart_omap_port *up, int txrx)
++{
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx() started\n");
++ if (bt_funcs.set_txrx != NULL)
++ {
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx(), bt_funcs.set_txrx != NULL\n");
++ bt_funcs.set_txrx(up, txrx);
++ }
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_set_txrx() done\n");
++}
++
++static int
++h6300_bt_get_txrx(struct uart_omap_port *up)
++{
++ int retVal;
++
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx() started\n");
++ if (bt_funcs.get_txrx != NULL)
++ {
++ retVal = bt_funcs.get_txrx(up);
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx(), bt_funcs.get_trx != null, done, retVal %d\n", retVal);
++ return retVal;
++ }
++ else
++ {
++ printk(KERN_NOTICE "board-h6300.c, h6300_bt_get_txrx() done, returning 0\n");
++ return 0;
++ }
++}
++
++static struct platform_omap_serial_funcs h6300_omap_bt_funcs = {
++ .configure = h6300_bt_configure,
++ .set_txrx = h6300_bt_set_txrx,
++ .get_txrx = h6300_bt_get_txrx,
++};
++
++struct platform_device btuart_device = {
++ .name = "h6300_bt",
++ .id = 1,
++};
++EXPORT_SYMBOL(btuart_device);
++
++static void
++h6300_gsm_configure(struct uart_omap_port *up, int enable)
++{
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_configure() started\n");
++ if (gsm_funcs.configure != NULL)
++ gsm_funcs.configure(up, enable);
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_configure() done\n");
++}
++
++static void
++h6300_gsm_set_txrx(struct uart_omap_port *up, int txrx)
++{
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx() started\n");
++ if (bt_funcs.set_txrx != NULL)
++ {
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx(), bt_funcs.set_txrx != NULL\n");
++ gsm_funcs.set_txrx(up, txrx);
++ }
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_set_txrx() done\n");
++}
++
++static int
++h6300_gsm_get_txrx(struct uart_omap_port *up)
++{
++ int retVal;
++
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx() started\n");
++ if (bt_funcs.get_txrx != NULL)
++ {
++ retVal = gsm_funcs.get_txrx(up);
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx(), bt_funcs.get_trx != null, done, retVal %d\n", retVal);
++ return retVal;
++ }
++ else
++ {
++ printk(KERN_NOTICE "board-h6300.c, h6300_gsm_get_txrx() done, returning 0\n");
++ return 0;
++ }
++}
++
++static struct platform_omap_serial_funcs h6300_omap_gsm_funcs = {
++ .configure = h6300_gsm_configure,
++ .set_txrx = h6300_gsm_set_txrx,
++ .get_txrx = h6300_gsm_get_txrx,
++};
++
++struct platform_device gsmuart_device = {
++ .name = "h6300_gsm",
++ .id = 1,
++};
++EXPORT_SYMBOL(gsmuart_device);
++
++#if 0
++static struct mtd_partition h6300_partitions[] = {
++ /* bootloader (U-Boot, etc) in first sector */
++ {
++ .name = "bootloader",
++ .offset = 0,
++ .size = SZ_128K,
++ .mask_flags = MTD_WRITEABLE, /* force read-only */
++ },
++ /* bootloader params in the next sector */
++ {
++ .name = "params",
++ .offset = MTDPART_OFS_APPEND,
++ .size = SZ_128K,
++ .mask_flags = 0,
++ },
++ /* kernel */
++ {
++ .name = "kernel",
++ .offset = MTDPART_OFS_APPEND,
++ .size = SZ_2M,
++ .mask_flags = 0
++ },
++ /* rest of flash1 is a file system */
++ {
++ .name = "rootfs",
++ .offset = MTDPART_OFS_APPEND,
++ .size = SZ_16M - SZ_2M - 2 * SZ_128K,
++ .mask_flags = 0
++ },
++ /* file system */
++ {
++ .name = "filesystem",
++ .offset = MTDPART_OFS_APPEND,
++ .size = MTDPART_SIZ_FULL,
++ .mask_flags = 0
++ }
++};
++
++static struct flash_platform_data h6300_flash_data = {
++ .map_name = "cfi_probe",
++ .width = 2,
++ .parts = h6300_partitions,
++ .nr_parts = ARRAY_SIZE(h6300_partitions),
++};
++
++static struct resource h6300_flash_resource = {
++ .start = OMAP_CS0_PHYS,
++ .end = OMAP_CS0_PHYS + SZ_32M - 1,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct platform_device h6300_flash_device = {
++ .name = "omapflash",
++ .id = 0,
++ .dev = {
++ .platform_data = &h6300_flash_data,
++ },
++ .num_resources = 1,
++ .resource = &h6300_flash_resource,
++};
++#endif
++
++static struct resource h6300_wlan_resource[] = {
++ [0] = {
++ .start = OMAP_CS1_PHYS,
++ .end = OMAP_CS1_PHYS + SZ_32M -1,
++ .flags = IORESOURCE_MEM,
++ },
++
++ [1] = {
++ .start = OMAP_GPIO_IRQ(11),
++ .end = OMAP_GPIO_IRQ(11),
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device h6300_wlan_device = {
++ .name = "tnetw1100b",
++ .id = 0,
++ .num_resources = 2,
++ .resource = h6300_wlan_resource,
++};
++
++static struct platform_device *h6300_devices[] __initdata = {
++ &btuart_device,
++ &gsmuart_device,
++ &h6300_wlan_device,
++ //&h6300_flash_device,
++};
++
++static void __init h6300_init_irq(void)
++{
++ omap_init_irq();
++ omap_gpio_init();
++
++ omap_request_gpio (2);
++ omap_set_gpio_direction (2, 0);
++ omap_set_gpio_dataout (2, 1);
++}
++
++/* assume no Mini-AB port */
++
++static struct omap_usb_config h6300_usb_config __initdata = {
++ .hmc_mode = 0,
++ .register_dev = 1,
++ .pins[0] = 0,
++};
++
++static struct omap_lcd_config h6300_lcd_config __initdata = {
++ .panel_name = "h6300",
++ .ctrl_name = "internal",
++};
++
++static struct omap_mmc_config h6300_mmc_config __initdata = {
++ .mmc [0] = {
++ .enabled = 1,
++ .wire4 = 1,
++ .wp_pin = OMAP_GPIO_IRQ(13),
++ .power_pin = -1, /* FPGA F3 UIO42 */
++ .switch_pin = -1, /* FPGA F4 UIO43 */
++ },
++};
++
++static struct omap_uart_config h6300_uart_config __initdata = {
++ .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
++};
++
++static struct omap_board_config_kernel h6300_config[] = {
++ { OMAP_TAG_USB, &h6300_usb_config },
++ { OMAP_TAG_MMC, &h6300_mmc_config },
++ { OMAP_TAG_UART, &h6300_uart_config },
++ { OMAP_TAG_LCD, &h6300_lcd_config },
++};
++
++static void __init h6300_init(void)
++{
++ int ret;
++
++ ret = platform_add_devices(h6300_devices, ARRAY_SIZE(h6300_devices));
++ if (ret)
++ {
++ printk(KERN_WARNING "Unable to add h6300 platform devices like bluetooth");
++ }
++ omap_board_config = h6300_config;
++ omap_board_config_size = ARRAY_SIZE(h6300_config);
++ omap_serial_init();
++}
++
++static void __init h6300_map_io(void)
++{
++ omap_map_common_io();
++
++ btuart_device.dev.platform_data = &h6300_omap_bt_funcs;
++ gsmuart_device.dev.platform_data = &h6300_omap_gsm_funcs;
++}
++
++MACHINE_START(H6300, "HP iPAQ H6300")
++ /* MAINTAINER("Everett Coleman II <gcc80x86@fuzzyneural.net>") */
++ .phys_ram = 0x10000000,
++ .phys_io = 0xfff00000,
++ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
++ .boot_params = 0x10000100,
++ .map_io = h6300_map_io,
++ .init_irq = h6300_init_irq,
++ .init_machine = h6300_init,
++ .timer = &omap_timer,
++MACHINE_END
+diff -Naur linux-2.6.14-omap2/arch/arm/mach-omap1/Kconfig linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/Kconfig
+--- linux-2.6.14-omap2/arch/arm/mach-omap1/Kconfig 2005-12-02 01:53:31.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/Kconfig 2005-10-22 03:52:45.000000000 +0300
+@@ -26,6 +26,12 @@
+ TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
+ have such a board.
+
++config MACH_OMAP_H6300
++ bool "HP IPaq H6300"
++ depends on ARCH_OMAP1 && ARCH_OMAP15XX
++ help
++ HP IPaq H6300 series.
++
+ config MACH_OMAP_H2
+ bool "TI H2 Support"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+diff -Naur linux-2.6.14-omap2/arch/arm/mach-omap1/Makefile linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/Makefile
+--- linux-2.6.14-omap2/arch/arm/mach-omap1/Makefile 2005-12-02 01:53:31.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/Makefile 2005-10-22 03:52:45.000000000 +0300
+@@ -15,7 +15,8 @@
+ obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
+ obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
+ obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
+-obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
++obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
++obj-$(CONFIG_MACH_OMAP_H6300) += board-h6300.o
+
+ ifeq ($(CONFIG_ARCH_OMAP15XX),y)
+ # Innovator-1510 FPGA
+diff -Naur linux-2.6.14-omap2/arch/arm/mach-omap1/mux.c linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/mux.c
+--- linux-2.6.14-omap2/arch/arm/mach-omap1/mux.c 2005-12-02 01:53:32.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/arch/arm/mach-omap1/mux.c 2005-11-11 04:13:42.000000000 +0200
+@@ -196,6 +196,13 @@
+ MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1)
+ MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1)
+
++/* OMAP-1510 uWire */
++MUX_CFG("P15_1510_UWIRE_CS3", 8, 12, 1, NA, 0, 0, NA, 0, 1)
++MUX_CFG("N14_1510_UWIRE_CS0", 8, 9, 1, NA, 0, 0, NA, 0, 1)
++MUX_CFG("V19_1510_UWIRE_SCLK", 8, 6, 0, NA, 0, 0, NA, 0, 1)
++MUX_CFG("W21_1510_UWIRE_SDO", 8, 3, 0, NA, 0, 0, NA, 0, 1)
++MUX_CFG("U18_1510_UWIRE_SDI", 8, 0, 0, 1, 18, 0, NA, 0, 1)
++
+ /* OMAP-1610 Flash */
+ MUX_CFG("L3_1610_FLASH_CS2B_OE",10, 6, 1, NA, 0, 0, NA, 0, 1)
+ MUX_CFG("M8_1610_FLASH_CS2B_WE",10, 3, 1, NA, 0, 0, NA, 0, 1)
+@@ -258,6 +265,7 @@
+ MUX_CFG("T20_1610_LOW_PWR", 7, 12, 1, NA, 0, 0, NA, 0, 0)
+
+ /* MCLK Settings */
++MUX_CFG("R10_1510_MCLK_ON", B, 18, 0, 2, 22, 1, NA, 1, 1)
+ MUX_CFG("V5_1710_MCLK_ON", B, 15, 0, NA, 0, 0, NA, 0, 0)
+ MUX_CFG("V5_1710_MCLK_OFF", B, 15, 6, NA, 0, 0, NA, 0, 0)
+ MUX_CFG("R10_1610_MCLK_ON", B, 18, 0, NA, 22, 0, NA, 1, 0)
+diff -Naur linux-2.6.14-omap2/arch/arm/plat-omap/dma.c linux-h6300-omap2-2.6.14.3/arch/arm/plat-omap/dma.c
+--- linux-2.6.14-omap2/arch/arm/plat-omap/dma.c 2005-12-02 01:53:32.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/arch/arm/plat-omap/dma.c 2005-11-11 04:13:42.000000000 +0200
+@@ -30,6 +30,7 @@
+ #include <asm/hardware.h>
+ #include <asm/dma.h>
+ #include <asm/io.h>
++#include <asm/mach-types.h>
+
+ #include <asm/arch/tc.h>
+
+@@ -1086,6 +1087,10 @@
+ }
+
+ if (omap_dma_in_1510_mode()) {
++ u16 l = omap_readw(OMAP1510_DMA_LCD_CTRL);
++ l &= ~(1 << 6);
++ omap_writew (l, OMAP1510_DMA_LCD_CTRL);
++
+ omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
+ omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
+ omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
+diff -Naur linux-2.6.14-omap2/arch/arm/tools/mach-types linux-h6300-omap2-2.6.14.3/arch/arm/tools/mach-types
+--- linux-2.6.14-omap2/arch/arm/tools/mach-types 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/arch/arm/tools/mach-types 2005-10-22 03:52:45.000000000 +0300
+@@ -576,7 +576,7 @@
+ s3c2460 MACH_S3C2460 S3C2460 560
+ pdm MACH_PDM PDM 561
+ h4700 MACH_H4700 H4700 562
+-h6300 MACH_H6300 H6300 563
++h6300 MACH_OMAP_H6300 H6300 563
+ rz1700 MACH_RZ1700 RZ1700 564
+ a716 MACH_A716 A716 565
+ estk2440a MACH_ESTK2440A ESTK2440A 566
+diff -Naur linux-2.6.14-omap2/arch/i386/kernel/cpu/mtrr/main.c linux-h6300-omap2-2.6.14.3/arch/i386/kernel/cpu/mtrr/main.c
+--- linux-2.6.14-omap2/arch/i386/kernel/cpu/mtrr/main.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/arch/i386/kernel/cpu/mtrr/main.c 2005-12-02 01:34:34.000000000 +0200
+@@ -626,6 +626,14 @@
+ if (cpuid_eax(0x80000000) >= 0x80000008) {
+ u32 phys_addr;
+ phys_addr = cpuid_eax(0x80000008) & 0xff;
++ /* CPUID workaround for Intel 0F33/0F34 CPU */
++ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
++ boot_cpu_data.x86 == 0xF &&
++ boot_cpu_data.x86_model == 0x3 &&
++ (boot_cpu_data.x86_mask == 0x3 ||
++ boot_cpu_data.x86_mask == 0x4))
++ phys_addr = 36;
++
+ size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
+ size_and_mask = ~size_or_mask & 0xfff00000;
+ } else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR &&
+diff -Naur linux-2.6.14-omap2/arch/ppc64/Kconfig linux-h6300-omap2-2.6.14.3/arch/ppc64/Kconfig
+--- linux-2.6.14-omap2/arch/ppc64/Kconfig 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/arch/ppc64/Kconfig 2005-12-02 01:34:35.000000000 +0200
+@@ -234,6 +234,10 @@
+ This option enables hardware multithreading on RS64 cpus.
+ pSeries systems p620 and p660 have such a cpu type.
+
++config NUMA
++ bool "NUMA support"
++ default y if DISCONTIGMEM || SPARSEMEM
++
+ config ARCH_SELECT_MEMORY_MODEL
+ def_bool y
+
+@@ -249,9 +253,6 @@
+ def_bool y
+ depends on ARCH_DISCONTIGMEM_ENABLE
+
+-config ARCH_FLATMEM_ENABLE
+- def_bool y
+-
+ config ARCH_SPARSEMEM_ENABLE
+ def_bool y
+ depends on ARCH_DISCONTIGMEM_ENABLE
+@@ -274,10 +275,6 @@
+ def_bool y
+ depends on NEED_MULTIPLE_NODES
+
+-config NUMA
+- bool "NUMA support"
+- default y if DISCONTIGMEM || SPARSEMEM
+-
+ config SCHED_SMT
+ bool "SMT (Hyperthreading) scheduler support"
+ depends on SMP
+diff -Naur linux-2.6.14-omap2/arch/s390/appldata/appldata_base.c linux-h6300-omap2-2.6.14.3/arch/s390/appldata/appldata_base.c
+--- linux-2.6.14-omap2/arch/s390/appldata/appldata_base.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/arch/s390/appldata/appldata_base.c 2005-11-23 01:44:02.000000000 +0200
+@@ -592,12 +592,15 @@
+ */
+ void appldata_unregister_ops(struct appldata_ops *ops)
+ {
++ void *table;
+ spin_lock(&appldata_ops_lock);
+- unregister_sysctl_table(ops->sysctl_header);
+ list_del(&ops->list);
+- kfree(ops->ctl_table);
++ /* at that point any incoming access will fail */
++ table = ops->ctl_table;
+ ops->ctl_table = NULL;
+ spin_unlock(&appldata_ops_lock);
++ unregister_sysctl_table(ops->sysctl_header);
++ kfree(table);
+ P_INFO("%s-ops unregistered!\n", ops->name);
+ }
+ /********************** module-ops management <END> **************************/
+diff -Naur linux-2.6.14-omap2/arch/x86_64/kernel/setup.c linux-h6300-omap2-2.6.14.3/arch/x86_64/kernel/setup.c
+--- linux-2.6.14-omap2/arch/x86_64/kernel/setup.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/arch/x86_64/kernel/setup.c 2005-12-02 01:34:35.000000000 +0200
+@@ -993,6 +993,11 @@
+ unsigned eax = cpuid_eax(0x80000008);
+ c->x86_virt_bits = (eax >> 8) & 0xff;
+ c->x86_phys_bits = eax & 0xff;
++ /* CPUID workaround for Intel 0F34 CPU */
++ if (c->x86_vendor == X86_VENDOR_INTEL &&
++ c->x86 == 0xF && c->x86_model == 0x3 &&
++ c->x86_mask == 0x4)
++ c->x86_phys_bits = 36;
+ }
+
+ if (c->x86 == 15)
+diff -Naur linux-2.6.14-omap2/drivers/block/cfq-iosched.c linux-h6300-omap2-2.6.14.3/drivers/block/cfq-iosched.c
+--- linux-2.6.14-omap2/drivers/block/cfq-iosched.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/block/cfq-iosched.c 2005-11-23 01:44:02.000000000 +0200
+@@ -2260,10 +2260,8 @@
+ if (!atomic_dec_and_test(&cfqd->ref))
+ return;
+
+- blk_put_queue(q);
+-
+ cfq_shutdown_timer_wq(cfqd);
+- q->elevator->elevator_data = NULL;
++ blk_put_queue(q);
+
+ mempool_destroy(cfqd->crq_pool);
+ kfree(cfqd->crq_hash);
+diff -Naur linux-2.6.14-omap2/drivers/block/pktcdvd.c linux-h6300-omap2-2.6.14.3/drivers/block/pktcdvd.c
+--- linux-2.6.14-omap2/drivers/block/pktcdvd.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/block/pktcdvd.c 2005-12-02 01:34:35.000000000 +0200
+@@ -1191,7 +1191,7 @@
+ struct packet_data *pkt;
+ int i;
+
+- for (i = 0; i <= PACKET_NUM_STATES; i++)
++ for (i = 0; i < PACKET_NUM_STATES; i++)
+ states[i] = 0;
+
+ spin_lock(&pd->cdrw.active_list_lock);
+diff -Naur linux-2.6.14-omap2/drivers/bluetooth/Kconfig linux-h6300-omap2-2.6.14.3/drivers/bluetooth/Kconfig
+--- linux-2.6.14-omap2/drivers/bluetooth/Kconfig 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/bluetooth/Kconfig 2005-10-04 00:58:34.000000000 +0300
+@@ -163,6 +163,16 @@
+
+ Say Y here to compile support for virtual HCI devices into the
+ kernel or say M to compile it as module (hci_vhci).
++
++config BT_H6300
++ tristate "H6300 BRF6100 BT DRIVER"
++ help
++ Bluetooth H6300 BRF6100 driver.
++ This driver provides the firmware loading mechanism for the BRF6100
++ bt hardware in iPAQ h6300.
++
++ Say Y here to compile support for BRF6100 BT devices into the
++ kernel or say M to compile it as module (h6300_BT).
+
+ endmenu
+
+diff -Naur linux-2.6.14-omap2/drivers/bluetooth/Makefile linux-h6300-omap2-2.6.14.3/drivers/bluetooth/Makefile
+--- linux-2.6.14-omap2/drivers/bluetooth/Makefile 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/bluetooth/Makefile 2005-09-28 01:04:13.000000000 +0300
+@@ -10,10 +10,11 @@
+ obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o
+ obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
+ obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
+-obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
++obj-$(CONFIG_BT_HCIBLUECARD)+= bluecard_cs.o
+ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
++obj-$(CONFIG_BT_H6300) += omap/
+
+-hci_uart-y := hci_ldisc.o
++hci_uart-y := hci_ldisc.o
+ hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
+ hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
+-hci_uart-objs := $(hci_uart-y)
++hci_uart-objs := $(hci_uart-y)
+diff -Naur linux-2.6.14-omap2/drivers/bluetooth/omap/h6300_bt_brf6100.c linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/h6300_bt_brf6100.c
+--- linux-2.6.14-omap2/drivers/bluetooth/omap/h6300_bt_brf6100.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/h6300_bt_brf6100.c 2005-12-02 00:45:30.000000000 +0200
+@@ -0,0 +1,153 @@
++/*
++ * Bluetooth interface driver for TI BRF6100 on h6300
++ *
++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
++ * Ideas taken from the brf6150 bt driver made by Todd Blumer for the pxa hx4700.
++ *
++ * 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/kernel.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++
++#include <asm/hardware.h>
++#include <asm/arch/gpio.h>
++
++#include <asm/arch/h6300_uart_info.h>
++#include "h6300_bt_led.h"
++
++static void
++h6300_bt_configure(struct uart_omap_port *up, int enable)
++{
++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_configure() started, enable = %d\n", enable);
++
++ // printk( KERN_NOTICE "h6300 configure bluetooth: %d\n", enable );
++ if (enable == 0) {
++ omap_set_gpio_dataout(GPIO_N_BT_RST, 1); // turn off gpio, note 1 == off for negative gpios
++ mdelay(5);
++ h6300_clear_led(INDEX_BT_LED);
++ }
++ else if (enable == 1) {
++ omap_set_gpio_dataout(GPIO_N_BT_RST, 1); // turn on gpio, note 0 == on for negative gpios
++ mdelay(5);
++ }
++ else if (enable == 2) {
++ /*
++ * BRF6150's RTS goes low when firmware is ready
++ * so check for CTS=1 (nCTS=0 -> CTS=1). Typical 150ms
++ */
++/*
++ int tries = 0;
++ do
++ {
++ mdelay(10);
++ }
++ while ((BTMSR & MSR_CTS) == 0 && tries++ < 50);
++*/
++ h6300_set_led(INDEX_BT_LED, 16, 16);
++ }
++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_configure() done\n");
++}
++
++static void
++h6300_bt_set_txrx(struct uart_omap_port *up, int txrx)
++{
++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_set_txrx(), txrx = %d done\n", txrx);
++ /* do nothing */
++}
++
++static int
++h6300_bt_get_txrx(struct uart_omap_port *up)
++{
++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_get_txrx() done\n");
++ /* do nothing */
++ return 0;
++}
++
++static int
++h6300_bt_probe(struct device *dev)
++{
++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
++
++ omap_request_gpio(GPIO_BT_PWR_EN); // ask bt_power_en gpio, remember to release in remove_function
++ omap_set_gpio_direction(GPIO_BT_PWR_EN, 1); // set gpio direction to be output
++ omap_set_gpio_dataout(GPIO_BT_PWR_EN, 1); // turn on gpio
++
++ mdelay(200);
++
++ omap_request_gpio(GPIO_N_BT_RST); // ask bt_reset gpio, remember to release in remove_function
++ omap_set_gpio_direction(GPIO_N_BT_RST, 1); // set gpio direction to be output
++ omap_set_gpio_dataout(GPIO_N_BT_RST, 0); // turn on gpio, note 0 == on for negative gpios
++
++ /* configure bluetooth UART */
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_RXD_MD);
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_TXD_MD);
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_CTS_MD);
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_RTS_MD);
++
++ funcs->configure = h6300_bt_configure;
++ funcs->set_txrx = h6300_bt_set_txrx;
++ funcs->get_txrx = h6300_bt_get_txrx;
++
++ /* Make sure the LED is off */
++ h6300_clear_led(INDEX_BT_LED);
++
++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_probe() done\n");
++
++ return 0;
++}
++
++static int
++h6300_bt_remove(struct device *dev)
++{
++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
++
++ printk(KERN_NOTICE "h6300_bt_brf6100.c h6300_bt_remove() started\n");
++
++ omap_free_gpio(GPIO_BT_PWR_EN);
++ omap_free_gpio(GPIO_N_BT_RST);
++
++ funcs->configure = NULL;
++ funcs->set_txrx = NULL;
++ funcs->get_txrx = NULL;
++
++ /* Make sure the LED is off */
++ h6300_clear_led(INDEX_BT_LED);
++
++ printk(KERN_NOTICE "h6300_bt_brf6100.c, h6300_bt_remove() done\n");
++
++ return 0;
++}
++
++static struct device_driver bt_driver = {
++ .name = "h6300_bt",
++ .bus = &platform_bus_type,
++ .probe = h6300_bt_probe,
++ .remove = h6300_bt_remove,
++};
++
++static int __init
++h6300_bt_init(void)
++{
++ printk(KERN_NOTICE "h6300 Bluetooth Driver init()\n");
++ return driver_register(&bt_driver);
++}
++
++static void __exit
++h6300_bt_exit(void)
++{
++ printk(KERN_NOTICE "h6300 Bluetooth Driver exit()\n");
++ driver_unregister(&bt_driver);
++}
++
++module_init(h6300_bt_init);
++module_exit(h6300_bt_exit);
++
++MODULE_AUTHOR("Mika Laitio, <lamikr@cc.jyu.fi>");
++MODULE_DESCRIPTION("iPAQ h6300 BRF6100 Bluetooth driver.");
++MODULE_LICENSE("GPL");
++
+diff -Naur linux-2.6.14-omap2/drivers/bluetooth/omap/h6300_bt_led.c linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/h6300_bt_led.c
+--- linux-2.6.14-omap2/drivers/bluetooth/omap/h6300_bt_led.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/h6300_bt_led.c 2005-10-06 02:34:39.000000000 +0300
+@@ -0,0 +1,41 @@
++/*
++ * Bluetooth interface driver helper for controlling bluetooth leds available in iPAQ h6300.
++ *
++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
++ * Ideas from the brf6150 bt driver made by Todd Blumer for the pxa hx4700.
++ *
++ * 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/kernel.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++
++#include <asm/hardware.h>
++#include <asm/arch/gpio.h>
++
++/*
++ * Low level access for disabling h6300 bt led.
++ *
++ * TODO: implement for h6300
++ */
++void h6300_clear_led(int led_num)
++{
++ printk(KERN_NOTICE "h6300_bt_led.c h6300_clear_led() done\n");
++ //hx4700_set_led(led_num, 0, 16);
++}
++EXPORT_SYMBOL(h6300_clear_led);
++
++/*
++ * Low level access for setting up the bt led.
++ *
++ * TODO: implement for h6300
++ */
++void h6300_set_led(int led_num, int duty_time, int cycle_time)
++{
++ printk(KERN_NOTICE "h6300_bt_led.c h6300_set_led() done\n");
++}
++EXPORT_SYMBOL(h6300_set_led);
+diff -Naur linux-2.6.14-omap2/drivers/bluetooth/omap/h6300_bt_led.h linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/h6300_bt_led.h
+--- linux-2.6.14-omap2/drivers/bluetooth/omap/h6300_bt_led.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/h6300_bt_led.h 2005-10-06 02:34:39.000000000 +0300
+@@ -0,0 +1,9 @@
++#ifndef H6300_BT_LED_H_
++#define H6300_BT_LED_H_
++
++#define INDEX_BT_LED 2
++
++void h6300_clear_led(int led_num);
++void h6300_set_led(int led_num, int duty_time, int cycle_time);
++
++#endif /*H6300_BT_LED_H_*/
+diff -Naur linux-2.6.14-omap2/drivers/bluetooth/omap/Makefile linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/Makefile
+--- linux-2.6.14-omap2/drivers/bluetooth/omap/Makefile 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/bluetooth/omap/Makefile 2005-10-06 02:34:39.000000000 +0300
+@@ -0,0 +1,6 @@
++#
++# Makefile for the Linux iPAQ H6300 BRF6100 Bluetooth device drivers.
++#
++
++h6300_bt-objs := h6300_bt_led.o h6300_bt_brf6100.o
++obj-$(CONFIG_BT_H6300) += h6300_bt.o
+diff -Naur linux-2.6.14-omap2/drivers/char/rtc.c linux-h6300-omap2-2.6.14.3/drivers/char/rtc.c
+--- linux-2.6.14-omap2/drivers/char/rtc.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/char/rtc.c 2005-12-02 01:34:35.000000000 +0200
+@@ -149,8 +149,22 @@
+ #ifdef RTC_IRQ
+ static void rtc_dropped_irq(unsigned long data);
+
+-static void set_rtc_irq_bit(unsigned char bit);
+-static void mask_rtc_irq_bit(unsigned char bit);
++static void set_rtc_irq_bit_locked(unsigned char bit);
++static void mask_rtc_irq_bit_locked(unsigned char bit);
++
++static inline void set_rtc_irq_bit(unsigned char bit)
++{
++ spin_lock_irq(&rtc_lock);
++ set_rtc_irq_bit_locked(bit);
++ spin_unlock_irq(&rtc_lock);
++}
++
++static void mask_rtc_irq_bit(unsigned char bit)
++{
++ spin_lock_irq(&rtc_lock);
++ mask_rtc_irq_bit_locked(bit);
++ spin_unlock_irq(&rtc_lock);
++}
+ #endif
+
+ static int rtc_proc_open(struct inode *inode, struct file *file);
+@@ -401,18 +415,19 @@
+ }
+ case RTC_PIE_OFF: /* Mask periodic int. enab. bit */
+ {
+- mask_rtc_irq_bit(RTC_PIE);
++ unsigned long flags; /* can be called from isr via rtc_control() */
++ spin_lock_irqsave (&rtc_lock, flags);
++ mask_rtc_irq_bit_locked(RTC_PIE);
+ if (rtc_status & RTC_TIMER_ON) {
+- spin_lock_irq (&rtc_lock);
+ rtc_status &= ~RTC_TIMER_ON;
+ del_timer(&rtc_irq_timer);
+- spin_unlock_irq (&rtc_lock);
+ }
++ spin_unlock_irqrestore (&rtc_lock, flags);
+ return 0;
+ }
+ case RTC_PIE_ON: /* Allow periodic ints */
+ {
+-
++ unsigned long flags; /* can be called from isr via rtc_control() */
+ /*
+ * We don't really want Joe User enabling more
+ * than 64Hz of interrupts on a multi-user machine.
+@@ -421,14 +436,14 @@
+ (!capable(CAP_SYS_RESOURCE)))
+ return -EACCES;
+
++ spin_lock_irqsave (&rtc_lock, flags);
+ if (!(rtc_status & RTC_TIMER_ON)) {
+- spin_lock_irq (&rtc_lock);
+ rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
+ add_timer(&rtc_irq_timer);
+ rtc_status |= RTC_TIMER_ON;
+- spin_unlock_irq (&rtc_lock);
+ }
+- set_rtc_irq_bit(RTC_PIE);
++ set_rtc_irq_bit_locked(RTC_PIE);
++ spin_unlock_irqrestore (&rtc_lock, flags);
+ return 0;
+ }
+ case RTC_UIE_OFF: /* Mask ints from RTC updates. */
+@@ -609,6 +624,7 @@
+ {
+ int tmp = 0;
+ unsigned char val;
++ unsigned long flags; /* can be called from isr via rtc_control() */
+
+ /*
+ * The max we can do is 8192Hz.
+@@ -631,9 +647,9 @@
+ if (arg != (1<<tmp))
+ return -EINVAL;
+
+- spin_lock_irq(&rtc_lock);
++ spin_lock_irqsave(&rtc_lock, flags);
+ if (hpet_set_periodic_freq(arg)) {
+- spin_unlock_irq(&rtc_lock);
++ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+ }
+ rtc_freq = arg;
+@@ -641,7 +657,7 @@
+ val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
+ val |= (16 - tmp);
+ CMOS_WRITE(val, RTC_FREQ_SELECT);
+- spin_unlock_irq(&rtc_lock);
++ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+ }
+ #endif
+@@ -844,12 +860,15 @@
+ #ifndef RTC_IRQ
+ return -EIO;
+ #else
+- spin_lock_irq(&rtc_task_lock);
++ unsigned long flags;
++ if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
++ return -EINVAL;
++ spin_lock_irqsave(&rtc_task_lock, flags);
+ if (rtc_callback != task) {
+- spin_unlock_irq(&rtc_task_lock);
++ spin_unlock_irqrestore(&rtc_task_lock, flags);
+ return -ENXIO;
+ }
+- spin_unlock_irq(&rtc_task_lock);
++ spin_unlock_irqrestore(&rtc_task_lock, flags);
+ return rtc_do_ioctl(cmd, arg, 1);
+ #endif
+ }
+@@ -1306,40 +1325,32 @@
+ * meddles with the interrupt enable/disable bits.
+ */
+
+-static void mask_rtc_irq_bit(unsigned char bit)
++static void mask_rtc_irq_bit_locked(unsigned char bit)
+ {
+ unsigned char val;
+
+- spin_lock_irq(&rtc_lock);
+- if (hpet_mask_rtc_irq_bit(bit)) {
+- spin_unlock_irq(&rtc_lock);
++ if (hpet_mask_rtc_irq_bit(bit))
+ return;
+- }
+ val = CMOS_READ(RTC_CONTROL);
+ val &= ~bit;
+ CMOS_WRITE(val, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+
+ rtc_irq_data = 0;
+- spin_unlock_irq(&rtc_lock);
+ }
+
+-static void set_rtc_irq_bit(unsigned char bit)
++static void set_rtc_irq_bit_locked(unsigned char bit)
+ {
+ unsigned char val;
+
+- spin_lock_irq(&rtc_lock);
+- if (hpet_set_rtc_irq_bit(bit)) {
+- spin_unlock_irq(&rtc_lock);
++ if (hpet_set_rtc_irq_bit(bit))
+ return;
+- }
+ val = CMOS_READ(RTC_CONTROL);
+ val |= bit;
+ CMOS_WRITE(val, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+
+ rtc_irq_data = 0;
+- spin_unlock_irq(&rtc_lock);
+ }
+ #endif
+
+diff -Naur linux-2.6.14-omap2/drivers/hwmon/it87.c linux-h6300-omap2-2.6.14.3/drivers/hwmon/it87.c
+--- linux-2.6.14-omap2/drivers/hwmon/it87.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/hwmon/it87.c 2005-12-02 01:34:35.000000000 +0200
+@@ -522,8 +522,15 @@
+ struct i2c_client *client = to_i2c_client(dev);
+ struct it87_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
++ u8 reg = it87_read_value(client, IT87_REG_FAN_DIV);
+
+ down(&data->update_lock);
++ switch (nr) {
++ case 0: data->fan_div[nr] = reg & 0x07; break;
++ case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
++ case 2: data->fan_div[nr] = (reg & 0x40) ? 3 : 1; break;
++ }
++
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ up(&data->update_lock);
+diff -Naur linux-2.6.14-omap2/drivers/hwmon/lm78.c linux-h6300-omap2-2.6.14.3/drivers/hwmon/lm78.c
+--- linux-2.6.14-omap2/drivers/hwmon/lm78.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/hwmon/lm78.c 2005-12-02 01:34:35.000000000 +0200
+@@ -451,7 +451,7 @@
+ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct lm78_data *data = lm78_update_device(dev);
+- return sprintf(buf, "%d\n", vid_from_reg(82, data->vid));
++ return sprintf(buf, "%d\n", vid_from_reg(data->vid, 82));
+ }
+ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+diff -Naur linux-2.6.14-omap2/drivers/hwmon/w83627hf.c linux-h6300-omap2-2.6.14.3/drivers/hwmon/w83627hf.c
+--- linux-2.6.14-omap2/drivers/hwmon/w83627hf.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/hwmon/w83627hf.c 2005-12-02 01:34:35.000000000 +0200
+@@ -454,7 +454,9 @@
+ (w83627thf == data->type || w83637hf == data->type))
+
+ /* use VRM9 calculation */
+- data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488);
++ data->in_min[0] =
++ SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
++ 255);
+ else
+ /* use VRM8 (standard) calculation */
+ data->in_min[0] = IN_TO_REG(val);
+@@ -479,7 +481,9 @@
+ (w83627thf == data->type || w83637hf == data->type))
+
+ /* use VRM9 calculation */
+- data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488);
++ data->in_max[0] =
++ SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
++ 255);
+ else
+ /* use VRM8 (standard) calculation */
+ data->in_max[0] = IN_TO_REG(val);
+diff -Naur linux-2.6.14-omap2/drivers/i2c/busses/i2c-omap.c linux-h6300-omap2-2.6.14.3/drivers/i2c/busses/i2c-omap.c
+--- linux-2.6.14-omap2/drivers/i2c/busses/i2c-omap.c 2005-12-02 01:53:32.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/i2c/busses/i2c-omap.c 2005-10-20 20:53:33.000000000 +0300
+@@ -124,10 +124,10 @@
+ /* I2C System Configuration Register (OMAP_I2C_SYSC): */
+ #define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
+
++#undef I2C_OMAP_DEBUG
+ /* ------- debugging ---------------------------------------------------*/
+
+-#define I2C_OMAP_DEBUG
+-#ifdef I2c_OMAP_DEBUG
++#ifdef I2C_OMAP_DEBUG
+ static int i2c_debug;
+
+ module_param(i2c_debug, int, 0);
+diff -Naur linux-2.6.14-omap2/drivers/i2c/chips/Kconfig linux-h6300-omap2-2.6.14.3/drivers/i2c/chips/Kconfig
+--- linux-2.6.14-omap2/drivers/i2c/chips/Kconfig 2005-12-02 01:53:32.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/i2c/chips/Kconfig 2005-10-14 18:55:31.000000000 +0300
+@@ -56,6 +56,16 @@
+ This driver can also be built as a module. If so, the module
+ will be called pca9539.
+
++config PCA9535
++ tristate "Philips PCA9535 16-bit I/O port"
++ depends on I2C
++ help
++ If you say yes here you get support for the Philips PCA9535
++ 16-bit I/O port.
++
++ This driver can also be built as a module. If so, the module
++ will be called pca9539.
++
+ config SENSORS_PCF8591
+ tristate "Philips PCF8591"
+ depends on I2C && EXPERIMENTAL
+diff -Naur linux-2.6.14-omap2/drivers/i2c/chips/Makefile linux-h6300-omap2-2.6.14.3/drivers/i2c/chips/Makefile
+--- linux-2.6.14-omap2/drivers/i2c/chips/Makefile 2005-12-02 01:53:32.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/i2c/chips/Makefile 2005-10-14 18:55:31.000000000 +0300
+@@ -16,6 +16,7 @@
+ obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o
+ obj-$(CONFIG_GPIOEXPANDER_OMAP) += gpio_expander_omap.o
+ obj-$(CONFIG_MENELAUS) += menelaus.o
++obj-$(CONFIG_PCA9535) += pca9535.o
+
+ ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
+ EXTRA_CFLAGS += -DDEBUG
+diff -Naur linux-2.6.14-omap2/drivers/i2c/chips/pca9535.c linux-h6300-omap2-2.6.14.3/drivers/i2c/chips/pca9535.c
+--- linux-2.6.14-omap2/drivers/i2c/chips/pca9535.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/i2c/chips/pca9535.c 2005-10-25 22:23:21.000000000 +0300
+@@ -0,0 +1,414 @@
++/*
++ Driver for Philips PCA9535 16-bit low power I/O port with interrupt
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++ Copyright (C) 2005 Husam Senussi
++ Framework based on Pawel Kolodziejski's pca9535 driver in
++ handheld.org's 2.6.13 kernel. Driver updated by Mika Laitio.
++*/
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/hwmon.h>
++#include <linux/err.h>
++
++#include <asm/arch/pca9535.h>
++#include <linux/delay.h>
++
++#include <linux/interrupt.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/hardware.h>
++
++EXPORT_SYMBOL(pca9535_gpio_read);
++EXPORT_SYMBOL(pca9535_gpio_write);
++EXPORT_SYMBOL(pca9535_gpio_direction);
++
++static int pca9535_attach_adapter(struct i2c_adapter *adapter);
++static int pca9535_detach_client(struct i2c_client *client);
++static int pca9535_attach(struct i2c_adapter *adapter, int address, int zero_or_minus_one);
++static u32 pca9535_read_reg(struct i2c_client *client, u8 regaddr);
++static void pca9535_write_reg(struct i2c_client *client, u8 regaddr, u16 param);
++
++enum pca9535_cmd
++{
++ PCA9535_INPUT_0 = 0,
++ PCA9535_INPUT_1 = 1,
++ PCA9535_OUTPUT_0 = 2,
++ PCA9535_OUTPUT_1 = 3,
++ PCA9535_INVERT_0 = 4,
++ PCA9535_INVERT_1 = 5,
++ PCA9535_DIRECTION_0 = 6,
++ PCA9535_DIRECTION_1 = 7,
++};
++
++struct pca9535_data {
++ struct semaphore lock;
++ struct i2c_client client;
++};
++
++static struct i2c_driver pca9535_driver = {
++ .owner = THIS_MODULE,
++ .name = "pca9535",
++ .flags = I2C_DF_NOTIFY,
++ .attach_adapter = pca9535_attach_adapter,
++ .detach_client = pca9535_detach_client,
++};
++
++static struct i2c_client *pca9535_i2c_client = NULL;
++static struct pca9535_data pca9535_inited;
++
++static unsigned short normal_i2c[] = { 0x20, I2C_CLIENT_END };
++
++#define DRIVER_VERSION "20 OCT 2005"
++#define DRIVER_NAME "PCA9535"
++
++/*
++ * sysfs callback function.
++ */
++static ssize_t pca9535_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
++ struct i2c_client *client = to_i2c_client(dev);
++ return sprintf(buf, "%02X\n", (pca9535_read_reg(client, psa->index) >> 8));
++}
++
++/*
++ * sysfs callback function.
++ */
++static ssize_t pca9535_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned long val = simple_strtoul(buf, NULL, 0);
++ unsigned long old = pca9535_read_reg(client, psa->index);
++
++ if (val > 0xff)
++ return -EINVAL;
++
++ val = (old & 0xff) | (val << 8);
++ pca9535_write_reg(client, psa->index, val);
++ return count;
++}
++
++#define PCA9535_ENTRY_RO(name, cmd_idx) \
++ static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9535_show, NULL, cmd_idx)
++
++#define PCA9535_ENTRY_RW(name, cmd_idx) \
++ static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9535_show, \
++ pca9535_store, cmd_idx)
++
++PCA9535_ENTRY_RO(input0, PCA9535_INPUT_0);
++PCA9535_ENTRY_RO(input1, PCA9535_INPUT_1);
++PCA9535_ENTRY_RW(output0, PCA9535_OUTPUT_0);
++PCA9535_ENTRY_RW(output1, PCA9535_OUTPUT_1);
++PCA9535_ENTRY_RW(invert0, PCA9535_INVERT_0);
++PCA9535_ENTRY_RW(invert1, PCA9535_INVERT_1);
++PCA9535_ENTRY_RW(direction0, PCA9535_DIRECTION_0);
++PCA9535_ENTRY_RW(direction1, PCA9535_DIRECTION_1);
++
++static struct attribute *pca9535_attributes[] = {
++ &sensor_dev_attr_input0.dev_attr.attr,
++ &sensor_dev_attr_input1.dev_attr.attr,
++ &sensor_dev_attr_output0.dev_attr.attr,
++ &sensor_dev_attr_output1.dev_attr.attr,
++ &sensor_dev_attr_invert0.dev_attr.attr,
++ &sensor_dev_attr_invert1.dev_attr.attr,
++ &sensor_dev_attr_direction0.dev_attr.attr,
++ &sensor_dev_attr_direction1.dev_attr.attr,
++ NULL
++};
++
++static struct attribute_group pca9535_defattr_group = {
++ .attrs = pca9535_attributes,
++};
++//End of sysfs management code.
++
++I2C_CLIENT_INSMOD;
++
++u32 pca9535_read_input(void)
++{
++ return pca9535_read_reg(pca9535_i2c_client, 0);
++}
++EXPORT_SYMBOL(pca9535_read_input);
++
++void pca9535_write_output(u16 param)
++{
++ pca9535_write_reg(pca9535_i2c_client, 2, param);
++}
++EXPORT_SYMBOL(pca9535_write_output);
++
++void pca9535_set_dir(u16 param)
++{
++ pca9535_write_reg(pca9535_i2c_client, 6, param);
++}
++EXPORT_SYMBOL(pca9535_set_dir);
++
++static int pca9535_attach_adapter(struct i2c_adapter *adapter)
++{
++ return i2c_probe(adapter, &addr_data, pca9535_attach);
++}
++
++static int pca9535_attach(struct i2c_adapter *adapter, int address, int zero_or_minus_one)
++{
++ struct i2c_client *new_client;
++ int err = 0;
++
++ printk("pca9535_attach() started\n");
++ new_client = &(pca9535_inited.client);
++ i2c_set_clientdata(new_client, 0);
++ new_client->addr = address;
++ new_client->adapter = adapter;
++ new_client->driver = &pca9535_driver;
++ new_client->flags = I2C_CLIENT_ALLOW_USE;
++ strcpy(new_client->name, DRIVER_NAME);
++
++ if ((err = i2c_attach_client(new_client)))
++ goto exit_free;
++
++ pca9535_i2c_client = new_client;
++
++ init_MUTEX(&pca9535_inited.lock);
++ i2c_set_clientdata(pca9535_i2c_client, &pca9535_inited);
++
++ sysfs_create_group(&pca9535_i2c_client->dev.kobj, &pca9535_defattr_group);
++
++ printk("pca9535_attach() ok\n");
++ return 0;
++
++exit_free:
++ printk("pca9535_attach() failed, error code = %d\n", err);
++ return err;
++}
++
++static int pca9535_detach_client(struct i2c_client *client)
++{
++ int err;
++
++ if ((err = i2c_detach_client(client))) {
++ dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
++ return err;
++ }
++ pca9535_i2c_client = NULL;
++
++ return 0;
++}
++
++static int __init pca9535_init(void)
++{
++ return i2c_add_driver(&pca9535_driver);
++}
++
++static void __exit pca9535_exit(void)
++{
++ i2c_del_driver(&pca9535_driver);
++}
++
++/*
++ * Reads the value of GPIO available via I2C.
++ */
++int pca9535_gpio_read(int gpio){
++ unsigned char reg = 0;
++ unsigned long val = 0;
++
++ printk("9535_gpio_read() called\n");
++ if(!pca9535_i2c_client)
++ return -ENODEV;
++
++ if(gpio < GPIO0 || gpio > GPIO17)
++ return -EINVAL;
++
++ if(gpio >= GPIO0 && gpio <= GPIO7){
++ reg = PCA9535_INPUT_0;
++ gpio -= GPIO0;
++ }else if(gpio >= GPIO8 && gpio <= GPIO17){
++ reg = PCA9535_INPUT_1;
++ gpio -= GPIO8;
++ }
++
++ down(&pca9535_inited.lock);
++
++ // Read the existing values first
++ val = pca9535_read_reg(pca9535_i2c_client, reg) >> 8;
++ val = (val >> gpio) & 0x01;
++
++ up(&pca9535_inited.lock);
++
++ return val;
++}
++
++/*
++ * Set the value of I2C GPIO.
++ */
++int pca9535_gpio_write(int gpio, unsigned char value){
++ unsigned char in_reg = 0;
++ unsigned char out_reg = 0;
++ unsigned long val = 0;
++ unsigned long old = 0;
++ int ret = 0;
++
++ if(!pca9535_i2c_client)
++ return -ENODEV;
++
++ if(gpio < GPIO0 || gpio > GPIO17)
++ return -EINVAL;
++
++ if(gpio >= GPIO0 && gpio <= GPIO7){
++ in_reg = PCA9535_INPUT_0;
++ out_reg = PCA9535_OUTPUT_0;
++ gpio -= GPIO0;
++ }else if(gpio >= GPIO8 && gpio <= GPIO17){
++ in_reg = PCA9535_INPUT_1;
++ out_reg = PCA9535_OUTPUT_1;
++ gpio -= GPIO8;
++ }
++
++ down(&pca9535_inited.lock);
++
++ // Read the existing values first
++ val = pca9535_read_reg(pca9535_i2c_client, in_reg);
++ old = val >> 8;
++
++ switch(value){
++ case LOW:
++ old |= (1 << gpio);
++ break;
++ case HI:
++ old &= ~(1 << gpio);
++ break;
++ default:
++ ret = -EINVAL;
++ goto error;
++ }
++
++ val = (val & 0xff) | (old << 8);
++
++ // write the values back to the register
++ pca9535_write_reg(pca9535_i2c_client, out_reg, val);
++error:
++
++ up(&pca9535_inited.lock);
++ return ret;
++}
++
++/*
++ * Set the direction of I2C GPIO.
++ */
++int pca9535_gpio_direction(int gpio, unsigned char direction){
++ unsigned char reg = 0;
++ unsigned long val = 0;
++ unsigned long old = 0;
++ int ret = 0;
++
++ if(!pca9535_i2c_client)
++ return -ENODEV;
++
++ if(gpio < GPIO0 || gpio > GPIO17)
++ return -EINVAL;
++
++ if(gpio >= GPIO0 && gpio <= GPIO7){
++ reg = PCA9535_DIRECTION_0;
++ gpio -= GPIO0;
++ }else if(gpio >= GPIO8 && gpio <= GPIO17){
++ reg = PCA9535_DIRECTION_1;
++ gpio -= GPIO8;
++ }
++
++ down(&pca9535_inited.lock);
++
++ // Read the existing values first
++ old = pca9535_read_reg(pca9535_i2c_client, reg);
++ val = old >> 8;
++
++ switch(direction){
++ case GPIO_INPUT:
++ val |= (1 << gpio);
++ break;
++ case GPIO_OUTPUT:
++ val &= ~(1 << gpio);
++ break;
++ default:
++ ret = -EINVAL;
++ goto error;
++ }
++
++ val = (old & 0xff) | (val << 8);
++
++ // write the values back to the register
++ pca9535_write_reg(pca9535_i2c_client, reg, val);
++error:
++
++ up(&pca9535_inited.lock);
++ return ret;
++}
++
++static u32 pca9535_read_reg(struct i2c_client *client, u8 regaddr)
++{
++ char buffer[3];
++ int r;
++ u32 data;
++
++ buffer[0] = regaddr;
++ buffer[1] = 0;
++ buffer[2] = 0;
++
++ r = i2c_master_send(client, buffer, 1);
++ if (r != 1) {
++ printk(KERN_ERR "pca9535: read failed, status %d\n", r);
++ return 0xffffffff;
++ }
++
++ r = i2c_master_recv(client, buffer, 3);
++ if (r != 3) {
++ printk(KERN_ERR "pca9535: read failed, status %d\n", r);
++ return 0xffffffff;
++ }
++
++ data = buffer[1];
++ data |= buffer[2] << 8;
++ //printk(KERN_ERR "%s: reading %x in %x\n", __FUNCTION__, data, regaddr);
++
++ return data;
++}
++
++static void pca9535_write_reg(struct i2c_client *client, u8 regaddr, u16 data)
++{
++ char buffer[3];
++ int r;
++
++ //printk(KERN_ERR "%s: writing %x in %x\n", __FUNCTION__, data, regaddr);
++ buffer[0] = regaddr;
++ buffer[1] = data >> 8;
++ buffer[2] = data & 0xff;
++
++ r = i2c_master_send(client, buffer, 3);
++ if (r != 3) {
++ printk(KERN_ERR "pca9535: write failed, status %d\n", r);
++ }
++}
++
++MODULE_AUTHOR("Husam Senussi <husamsenussi@gmail.com>");
++MODULE_DESCRIPTION("PCA9535 driver");
++MODULE_LICENSE("GPL");
++
++module_init(pca9535_init);
++module_exit(pca9535_exit);
+diff -Naur linux-2.6.14-omap2/drivers/input/keyboard/omap-keypad.c linux-h6300-omap2-2.6.14.3/drivers/input/keyboard/omap-keypad.c
+--- linux-2.6.14-omap2/drivers/input/keyboard/omap-keypad.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/input/keyboard/omap-keypad.c 2005-11-04 03:06:04.000000000 +0200
+@@ -5,10 +5,11 @@
+ *
+ * Copyright (C) 2003 Nokia Corporation
+ * Written by Timo Teräs <ext-timo.teras@nokia.com>
++ * iPAQ h6300 key and joypad support added by Mika Laitio. (2005)
+ *
+ * Added support for H2 & H3 Keypad
+ * Copyright (C) 2004 Texas Instruments
+- *
++ *
+ * 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
+@@ -40,6 +41,7 @@
+ #include <asm/arch/mux.h>
+
+ #undef NEW_BOARD_LEARNING_MODE
++//#define NEW_BOARD_LEARNING_MODE 1
+
+ static void omap_kp_tasklet(unsigned long);
+ static void omap_kp_timer(unsigned long);
+@@ -48,6 +50,8 @@
+ static unsigned char keypad_state[8];
+ static unsigned int keypad_irq = INT_KEYBOARD;
+
++static int prevJoypadKeycodePressEmulated;
++
+ static struct timer_list kp_timer;
+ DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
+
+@@ -165,6 +169,47 @@
+ 0
+ };
+
++#define _h6300_KEY_CALENDAR 67 // xmodmap 75 aka F9
++#define _H6300_KEY_TELEPHONE 68 // xmodmap 76 aka F10
++#define _H6300_KEY_HOMEPAGE 87 // xmodmap 87 aka Num_Lock
++#define _H6300_KEY_MAIL 88 // xmodmap 88 aka Scroll_Lock
++
++/*
++ * Following 5 keypad events are not really sent to userspace.
++ * Instead if the good combination of them is sent, then that is send.
++ * (up, right, down, left, enter)
++ */
++#define _H6300_JOYPAD_UP_RIGHT 1 // 00001
++#define _H6300_JOYPAD_DOWN_RIGHT 2 // 00010
++#define _h6300_JOYPAD_DOWN_LEFT 4 // 00100
++#define _h6300_JOYPAD_UP_LEFT 8 // 01000
++#define _H6300_JOYPAD_KEY_OK 16 // 10000
++
++static int h6300_keymap[] = {
++ KEY(2, 0, _h6300_KEY_CALENDAR), // address button in the bottom left
++ KEY(2, 3, _H6300_KEY_TELEPHONE), // start call button in the bottom
++ KEY(3, 1, _H6300_KEY_HOMEPAGE), // stop call button in the bottom
++ KEY(3, 4, _H6300_KEY_MAIL), // messaging button in the bottom right
++
++ KEY(0, 0, KEY_VOLUMEUP), // volume up button in the right side
++ KEY(0, 1, KEY_VOLUMEDOWN), // volume down button in the right side
++ KEY(3, 2, KEY_RECORD), // record button in the left side
++
++ KEY(1, 0, _h6300_JOYPAD_UP_LEFT),
++ KEY(1, 1, _h6300_JOYPAD_DOWN_LEFT),
++ KEY(1, 2, _H6300_JOYPAD_KEY_OK),
++ KEY(1, 3, _H6300_JOYPAD_DOWN_RIGHT),
++ KEY(1, 4, _H6300_JOYPAD_UP_RIGHT),
++
++ KEY(5, 0, KEY_RIGHT),
++ KEY(5, 1, KEY_DOWN),
++ KEY(5, 2, KEY_LEFT),
++ KEY(5, 3, KEY_UP),
++ KEY(5, 4, KEY_ENTER),
++
++ 0
++};
++
+ static int *keymap;
+
+ static irqreturn_t omap_kp_interrupt(int irq, void *dev_id,
+@@ -191,7 +236,8 @@
+ for (col = 0; col < 8; col++) {
+ omap_writew(~(1 << col) & 0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+
+- if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3()) {
++ if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3() || machine_is_h6300()) {
++ // makes keyboard act a little bit slower
+ udelay(9);
+ } else {
+ udelay(4);
+@@ -214,26 +260,34 @@
+ return -1;
+ }
+
++int is_key_down(unsigned char new_state[],
++ int col,
++ int row)
++{
++ return (new_state[col] & (1 << row)) ? 1 : 0;
++}
++
+ static void omap_kp_tasklet(unsigned long data)
+ {
+ unsigned char new_state[8], changed, key_down = 0;
+ int col, row;
+ int spurious = 0;
++ int report_key, report_col, report_row, joypad_checked; // joypad specific variables
+
+ /* check for any changes */
+ omap_kp_scan_keypad(new_state);
+-
+ /* check for changes and print those */
++ joypad_checked = 0;
+ for (col = 0; col < 8; col++) {
+ changed = new_state[col] ^ keypad_state[col];
+ key_down |= new_state[col];
+ if (changed == 0)
+ continue;
+-
++
+ for (row = 0; row < 8; row++) {
+ int key;
+ if (!(changed & (1 << row)))
+- continue;
++ continue;
+ #ifdef NEW_BOARD_LEARNING_MODE
+ printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col, row, (new_state[col] & (1 << row)) ? "pressed" : "released");
+ #else
+@@ -245,9 +299,173 @@
+ spurious = 1;
+ continue;
+ }
+-
+- input_report_key(&omap_kp_dev, key,
+- new_state[col] & (1 << row));
++ if (machine_is_h6300() &&
++ ((col == 1) || (col == 5)))
++ {
++ if (col == 5)
++ {
++ continue;
++ }
++ if ((joypad_checked == 0) &&
++ ((key == _H6300_JOYPAD_KEY_OK) ||
++ (key == _h6300_JOYPAD_UP_LEFT) ||
++ (key == _H6300_JOYPAD_UP_RIGHT) ||
++ (key == _H6300_JOYPAD_DOWN_RIGHT) ||
++ (key == _h6300_JOYPAD_DOWN_LEFT)))
++ {
++ if (is_key_down(new_state, col, row))
++ {
++ /*
++ * only enter pressed
++ * 1 0 0 _H6300_JOYPAD_KEY_OK 0 0
++ * --> 100100 == 36
++ */
++ if (new_state[1] == 36)
++ {
++ joypad_checked = 1;
++ prevJoypadKeycodePressEmulated = KEY_ENTER;
++ new_state[5] = 48; //110000
++ report_key = prevJoypadKeycodePressEmulated;
++ report_col = 5;
++ report_row = 4;
++ input_report_key(&omap_kp_dev,
++ report_key,
++ new_state[report_col] & (1 << report_row));
++ }
++ /*
++ * enter, up_left and up_right sensors pressed.
++ * 1 _H6300_JOYPAD_UP_RIGHT 0 _H6300_JOYPAD_KEY_OK 0 _h6300_JOYPAD_UP_LEFT
++ * --> 110101 == 53
++ * OR
++ * 1 KEY_UP_RIGHT 0 0 0 _h6300_JOYPAD_UP_LEFT
++ * --> 110001 == 42
++ * --> move to up
++ */
++ else if ((new_state[1] == 53) ||
++ (new_state[1] == 49))
++ {
++ joypad_checked = 1;
++ prevJoypadKeycodePressEmulated = KEY_UP;
++ new_state[5] = 40; //101000
++ report_key = prevJoypadKeycodePressEmulated;
++ report_col = 5;
++ report_row = 3;
++ input_report_key(&omap_kp_dev,
++ report_key,
++ new_state[report_col] & (1 << report_row));
++ }
++ /*
++ * enter, down_left and down_right sensors pressed
++ * --> 101110 == 46
++ * OR
++ * down_left and down_right
++ * -->101010 == 42
++ * --> move to down
++ */
++ else if ((new_state[1] == 46) ||
++ (new_state[1] == 42))
++ {
++ joypad_checked = 1;
++ prevJoypadKeycodePressEmulated = KEY_DOWN;
++ new_state[5] = 34; //100010
++ report_key = prevJoypadKeycodePressEmulated;
++ report_col = 5;
++ report_row = 1;
++ input_report_key(&omap_kp_dev,
++ report_key,
++ new_state[report_col] & (1 << report_row));
++ }
++ /*
++ * enter, up_right and down_right sensors pressed
++ * --> 111100 == 60
++ * or
++ * down_right and up_right
++ * --> 111000 == 56
++ * --> move to right
++ */
++ else if ((new_state[1] == 60) ||
++ (new_state[1] == 56))
++ {
++ joypad_checked = 1;
++ prevJoypadKeycodePressEmulated = KEY_RIGHT;
++ new_state[5] = 33; //100001
++ report_key = prevJoypadKeycodePressEmulated;
++ report_col = 5;
++ report_row = 0;
++ input_report_key(&omap_kp_dev,
++ report_key,
++ new_state[report_col] & (1 << report_row));
++ }
++ /*
++ * enter, up_left and down_left sensors pressed
++ * --> 100111 == 39
++ * or up_left and down_left
++ * --> 100011 == 35
++ * --> move to left
++ */
++ else if ((new_state[1] == 39) ||
++ (new_state[1] == 35))
++ {
++ joypad_checked = 1;
++ prevJoypadKeycodePressEmulated = KEY_LEFT;
++ new_state[5] = 36; //100100
++ report_key = prevJoypadKeycodePressEmulated;
++ report_col = 5;
++ report_row = 2;
++ input_report_key(&omap_kp_dev,
++ report_key,
++ new_state[report_col] & (1 << report_row));
++ }
++ else
++ {
++ //printk("missed new_state = %d\n", new_state[1]);
++ }
++ }
++ else
++ {
++ if (prevJoypadKeycodePressEmulated != 0)
++ {
++ // report key up event
++ joypad_checked = 1;
++ new_state[5] = 32; //100000
++ report_key = prevJoypadKeycodePressEmulated;
++ report_col = 5;
++ switch(prevJoypadKeycodePressEmulated)
++ {
++ case KEY_RIGHT:
++ report_row = 0;
++ break;
++ case KEY_DOWN:
++ report_row = 1;
++ break;
++ case KEY_LEFT:
++ report_row = 2;
++ break;
++ case KEY_UP:
++ report_row = 3;
++ break;
++ case KEY_ENTER:
++ report_row = 4;
++ break;
++ default:
++ printk(KERN_WARNING "Unknown iPAQ h6300 column 1 key = %d released. This should newer happen!\n",
++ key);
++ report_row = 0;
++ }
++ input_report_key(&omap_kp_dev,
++ report_key,
++ new_state[report_col] & (1 << report_row));
++ prevJoypadKeycodePressEmulated = 0;
++ }
++ }
++ }
++ }
++ else
++ {
++ input_report_key(&omap_kp_dev,
++ key,
++ new_state[col] & (1 << row));
++ }
+ #endif
+ }
+ }
+@@ -285,7 +503,12 @@
+ } else if (machine_is_omap_perseus2()) {
+ keymap = p2_keymap;
+ keypad_irq = INT_730_MPUIO_KEYPAD;
++ } else if (machine_is_h6300()) {
++ keymap = h6300_keymap;
++ // set keyboard to send repeated key events if key is hold down
++ set_bit(EV_REP, omap_kp_dev.evbit);
+ } else {
++ printk("omap_keypad.c, keyMap = test_keymap\n");
+ keymap = test_keymap;
+ }
+
+@@ -305,7 +528,7 @@
+ omap_kp_dev.name = "omap-keypad";
+ input_register_device(&omap_kp_dev);
+
+- if (machine_is_omap_h2() || machine_is_omap_h3()) {
++ if (machine_is_omap_h2() || machine_is_omap_h3() || machine_is_h6300()) {
+ omap_cfg_reg(F18_1610_KBC0);
+ omap_cfg_reg(D20_1610_KBC1);
+ omap_cfg_reg(D19_1610_KBC2);
+@@ -335,6 +558,7 @@
+
+ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
+ }
++ prevJoypadKeycodePressEmulated = 0;
+
+ /* scan current status and enable interrupt */
+ omap_kp_scan_keypad(keypad_state);
+diff -Naur linux-2.6.14-omap2/drivers/input/touchscreen/omap/Makefile linux-h6300-omap2-2.6.14.3/drivers/input/touchscreen/omap/Makefile
+--- linux-2.6.14-omap2/drivers/input/touchscreen/omap/Makefile 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/input/touchscreen/omap/Makefile 2005-10-22 03:52:45.000000000 +0300
+@@ -8,5 +8,6 @@
+ objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o
+ objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += ts_inn1510.o
+ objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += ts_osk.o
++objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_H6300) += ts_hx.o
+
+ omapts-objs := omap_ts.o $(objs-yy)
+diff -Naur linux-2.6.14-omap2/drivers/input/touchscreen/omap/omap_ts.c linux-h6300-omap2-2.6.14.3/drivers/input/touchscreen/omap/omap_ts.c
+--- linux-2.6.14-omap2/drivers/input/touchscreen/omap/omap_ts.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/input/touchscreen/omap/omap_ts.c 2005-10-22 03:52:45.000000000 +0300
+@@ -46,7 +46,7 @@
+ #define OMAP_TS_NAME "omap_ts"
+
+ static struct ts_device *__initdata ts_devs[] = {
+-#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
++#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) || defined(CONFIG_MACH_OMAP_H6300)
+ &hx_ts,
+ #endif
+ #ifdef CONFIG_MACH_OMAP_OSK
+diff -Naur linux-2.6.14-omap2/drivers/input/touchscreen/omap/ts_hx.c linux-h6300-omap2-2.6.14.3/drivers/input/touchscreen/omap/ts_hx.c
+--- linux-2.6.14-omap2/drivers/input/touchscreen/omap/ts_hx.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/input/touchscreen/omap/ts_hx.c 2005-09-28 02:45:59.000000000 +0300
+@@ -33,6 +33,7 @@
+ #include <asm/arch/mux.h>
+ #include <asm/arch/hardware.h>
+ #include <asm/hardware/tsc2101.h>
++#include <linux/delay.h>
+
+ #include "../drivers/ssi/omap-tsc2101.h"
+ #include "omap_ts.h"
+@@ -88,14 +89,19 @@
+ } else if (machine_is_omap_h3()) {
+ gpio = H3_GPIO_NUM;
+ omap_cfg_reg(W19_1610_GPIO48);
++ } else if (machine_is_h6300 ()) {
++ gpio = 2;
++ omap_cfg_reg(M14_1510_GPIO2);
+ } else
+ return -ENODEV;
+
+ ts->irq = OMAP_GPIO_IRQ(gpio);
+- if (omap_request_gpio(gpio) != 0) {
+- printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n");
+- return -EINVAL;
+- };
++ if (!machine_is_h6300 ()){
++ if (omap_request_gpio(gpio) != 0) {
++ printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n");
++ return -EINVAL;
++ };
++ }
+
+ omap_set_gpio_direction(gpio, 1);
+ set_irq_type(ts->irq, IRQT_FALLING);
+@@ -180,5 +186,7 @@
+ omap_free_gpio(H2_GPIO_NUM);
+ else if (machine_is_omap_h3())
+ omap_free_gpio(H3_GPIO_NUM);
++ else if (machine_is_h6300())
++ omap_free_gpio(2);
+ }
+ #endif
+diff -Naur linux-2.6.14-omap2/drivers/isdn/hardware/eicon/os_4bri.c linux-h6300-omap2-2.6.14.3/drivers/isdn/hardware/eicon/os_4bri.c
+--- linux-2.6.14-omap2/drivers/isdn/hardware/eicon/os_4bri.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/isdn/hardware/eicon/os_4bri.c 2005-12-02 01:34:35.000000000 +0200
+@@ -16,6 +16,7 @@
+ #include "diva_pci.h"
+ #include "mi_pc.h"
+ #include "dsrv4bri.h"
++#include "helpers.h"
+
+ static void *diva_xdiLoadFileFile = NULL;
+ static dword diva_xdiLoadFileLength = 0;
+@@ -815,7 +816,7 @@
+ return (ret);
+ }
+
+-void *xdiLoadFile(char *FileName, unsigned long *FileLength,
++void *xdiLoadFile(char *FileName, dword *FileLength,
+ unsigned long lim)
+ {
+ void *ret = diva_xdiLoadFileFile;
+diff -Naur linux-2.6.14-omap2/drivers/mmc/mmc.c linux-h6300-omap2-2.6.14.3/drivers/mmc/mmc.c
+--- linux-2.6.14-omap2/drivers/mmc/mmc.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/mmc/mmc.c 2005-11-05 00:46:08.000000000 +0200
+@@ -495,6 +495,7 @@
+
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
++ case 4: /* MMC v4 */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+diff -Naur linux-2.6.14-omap2/drivers/net/wan/hdlc_cisco.c linux-h6300-omap2-2.6.14.3/drivers/net/wan/hdlc_cisco.c
+--- linux-2.6.14-omap2/drivers/net/wan/hdlc_cisco.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wan/hdlc_cisco.c 2005-12-02 01:34:35.000000000 +0200
+@@ -192,7 +192,9 @@
+ "uptime %ud%uh%um%us)\n",
+ dev->name, days, hrs,
+ min, sec);
++#if 0
+ netif_carrier_on(dev);
++#endif
+ hdlc->state.cisco.up = 1;
+ }
+ }
+@@ -225,7 +227,9 @@
+ hdlc->state.cisco.settings.timeout * HZ)) {
+ hdlc->state.cisco.up = 0;
+ printk(KERN_INFO "%s: Link down\n", dev->name);
++#if 0
+ netif_carrier_off(dev);
++#endif
+ }
+
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
+@@ -261,8 +265,10 @@
+ {
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ del_timer_sync(&hdlc->state.cisco.timer);
++#if 0
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
++#endif
+ hdlc->state.cisco.up = 0;
+ hdlc->state.cisco.request_sent = 0;
+ }
+diff -Naur linux-2.6.14-omap2/drivers/net/wan/hdlc_fr.c linux-h6300-omap2-2.6.14.3/drivers/net/wan/hdlc_fr.c
+--- linux-2.6.14-omap2/drivers/net/wan/hdlc_fr.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wan/hdlc_fr.c 2005-12-02 01:34:35.000000000 +0200
+@@ -545,8 +545,10 @@
+
+ hdlc->state.fr.reliable = reliable;
+ if (reliable) {
++#if 0
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
++#endif
+
+ hdlc->state.fr.n391cnt = 0; /* Request full status */
+ hdlc->state.fr.dce_changed = 1;
+@@ -560,8 +562,10 @@
+ }
+ }
+ } else {
++#if 0
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
++#endif
+
+ while (pvc) { /* Deactivate all PVCs */
+ pvc_carrier(0, pvc);
+diff -Naur linux-2.6.14-omap2/drivers/net/wan/hdlc_generic.c linux-h6300-omap2-2.6.14.3/drivers/net/wan/hdlc_generic.c
+--- linux-2.6.14-omap2/drivers/net/wan/hdlc_generic.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wan/hdlc_generic.c 2005-12-02 01:34:35.000000000 +0200
+@@ -79,11 +79,13 @@
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ if (hdlc->proto.start)
+ return hdlc->proto.start(dev);
++#if 0
+ #ifdef DEBUG_LINK
+ if (netif_carrier_ok(dev))
+ printk(KERN_ERR "hdlc_set_carrier_on(): already on\n");
+ #endif
+ netif_carrier_on(dev);
++#endif
+ }
+
+
+@@ -94,11 +96,13 @@
+ if (hdlc->proto.stop)
+ return hdlc->proto.stop(dev);
+
++#if 0
+ #ifdef DEBUG_LINK
+ if (!netif_carrier_ok(dev))
+ printk(KERN_ERR "hdlc_set_carrier_off(): already off\n");
+ #endif
+ netif_carrier_off(dev);
++#endif
+ }
+
+
+@@ -294,8 +298,10 @@
+ if (result != 0)
+ return -EIO;
+
++#if 0
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev); /* no carrier until DCD goes up */
++#endif
+
+ return 0;
+ }
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/airo.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/airo.c
+--- linux-2.6.14-omap2/drivers/net/wireless/airo.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/airo.c 2005-11-23 01:44:02.000000000 +0200
+@@ -46,6 +46,8 @@
+ #include <linux/pci.h>
+ #include <asm/uaccess.h>
+
++#include "airo.h"
++
+ #ifdef CONFIG_PCI
+ static struct pci_device_id card_ids[] = {
+ { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/airo_cs.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/airo_cs.c
+--- linux-2.6.14-omap2/drivers/net/wireless/airo_cs.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/airo_cs.c 2005-11-23 01:44:02.000000000 +0200
+@@ -42,6 +42,8 @@
+ #include <asm/io.h>
+ #include <asm/system.h>
+
++#include "airo.h"
++
+ /*
+ All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If
+ you do not define PCMCIA_DEBUG at all, all the debug code will be
+@@ -78,10 +80,6 @@
+ event handler.
+ */
+
+-struct net_device *init_airo_card( int, int, int, struct device * );
+-void stop_airo_card( struct net_device *, int );
+-int reset_airo_card( struct net_device * );
+-
+ static void airo_config(dev_link_t *link);
+ static void airo_release(dev_link_t *link);
+ static int airo_event(event_t event, int priority,
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/airo.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/airo.h
+--- linux-2.6.14-omap2/drivers/net/wireless/airo.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/airo.h 2005-11-23 01:44:02.000000000 +0200
+@@ -0,0 +1,9 @@
++#ifndef _AIRO_H_
++#define _AIRO_H_
++
++struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia,
++ struct device *dmdev);
++int reset_airo_card(struct net_device *dev);
++void stop_airo_card(struct net_device *dev, int freeres);
++
++#endif /* _AIRO_H_ */
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/Kconfig linux-h6300-omap2-2.6.14.3/drivers/net/wireless/Kconfig
+--- linux-2.6.14-omap2/drivers/net/wireless/Kconfig 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/Kconfig 2005-10-22 03:52:45.000000000 +0300
+@@ -483,5 +483,7 @@
+ depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA)
+ default y
+
++source "drivers/net/wireless/tiacx/Kconfig"
++
+ endmenu
+
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/Makefile linux-h6300-omap2-2.6.14.3/drivers/net/wireless/Makefile
+--- linux-2.6.14-omap2/drivers/net/wireless/Makefile 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/Makefile 2005-10-14 18:55:31.000000000 +0300
+@@ -39,3 +39,4 @@
+ # 16-bit wireless PCMCIA client drivers
+ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
+ obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
++obj-$(CONFIG_ACX) += tiacx/
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/prism54/islpci_eth.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/prism54/islpci_eth.c
+--- linux-2.6.14-omap2/drivers/net/wireless/prism54/islpci_eth.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/prism54/islpci_eth.c 2005-11-23 01:44:02.000000000 +0200
+@@ -97,12 +97,6 @@
+ /* lock the driver code */
+ spin_lock_irqsave(&priv->slock, flags);
+
+- /* determine the amount of fragments needed to store the frame */
+-
+- frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+- if (init_wds)
+- frame_size += 6;
+-
+ /* check whether the destination queue has enough fragments for the frame */
+ curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);
+ if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) {
+@@ -213,6 +207,7 @@
+ /* store the skb address for future freeing */
+ priv->data_low_tx[index] = skb;
+ /* set the proper fragment start address and size information */
++ frame_size = skb->len;
+ fragment->size = cpu_to_le16(frame_size);
+ fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */
+ fragment->address = cpu_to_le32(pci_map_address);
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx_config.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx_config.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx_config.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx_config.h 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,44 @@
++/* temporary hack until proper Kconfig integration */
++#define CONFIG_ACX_PCI 1
++#define CONFIG_ACX_USB 1
++
++#define WLAN_RELEASE "v0.3.10"
++
++/* set to 0 if you don't want any debugging code to be compiled in */
++/* set to 1 if you want some debugging */
++/* set to 2 if you want extensive debug log */
++#define ACX_DEBUG 2
++
++/* assume 32bit I/O width
++ * (16bit is also compatible with Compact Flash) */
++#define ACX_IO_WIDTH 16
++
++/* Set this to 1 if you want monitor mode to use
++ * phy header. Currently it is not useful anyway since we
++ * don't know what useful info (if any) is in phy header.
++ * If you want faster/smaller code, say 0 here */
++#define WANT_PHY_HDR 0
++
++/* whether to do Tx descriptor cleanup in softirq (i.e. not in IRQ
++ * handler) or not. Note that doing it later does slightly increase
++ * system load, so still do that stuff in the IRQ handler for now,
++ * even if that probably means worse latency */
++#define TX_CLEANUP_IN_SOFTIRQ 0
++
++/* set to 1 if you want to have 1 driver per card instead of 1 single driver
++ * managing all cards (of a particular bus type) in your system
++ * Useful e.g. if you need to reinitialize single cards from time to time
++ * LINUX 2.4.X ONLY!! (pci_for_each_dev()) Feel free to implement 2.6.x
++ * compatibility... */
++#define SEPARATE_DRIVER_INSTANCES 0
++
++/* Locking: */
++/* very talkative */
++#define PARANOID_LOCKING 1
++/* normal (use when bug-free) */
++/* #define DO_LOCKING 1 */
++/* else locking is disabled! */
++
++/* 0 - normal mode */
++/* 1 - development/debug: probe for IEs on modprobe */
++#define CMD_DISCOVERY 0
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx_func.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx_func.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx_func.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx_func.h 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,660 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++
++/***********************************************************************
++** LOGGING
++**
++** - Avoid SHOUTING needlessly. Avoid excessive verbosity.
++** Gradually remove messages which are old debugging aids.
++**
++** - Use printk() for messages which are to be always logged.
++** Supply either 'acx:' or '<devname>:' prefix so that user
++** can figure out who's speaking among other kernel chatter.
++** acx: is for general issues (e.g. "acx: no firmware image!")
++** while <devname>: is related to a particular device
++** (think about multi-card setup). Double check that message
++** is not confusing to the average user.
++**
++** - use printk KERN_xxx level only if message is not a WARNING
++** but is INFO, ERR etc.
++**
++** - Use printk_ratelimited() for messages which may flood
++** (e.g. "rx DUP pkt!").
++**
++** - Use acxlog() for messages which may be omitted (and they
++** _will_ be omitted in non-debug builds). Note that
++** message levels may be disabled at compile-time selectively,
++** thus select them wisely. Example: L_DEBUG is the lowest
++** (most likely to be compiled out) -> use for less important stuff.
++**
++** - Do not print important stuff with acxlog(), or else people
++** will never build non-debug driver.
++**
++** Style:
++** hex: capital letters, zero filled (e.g. 0x02AC)
++** str: dont start from capitals, no trailing periods ("tx: queue is stopped")
++*/
++#if ACX_DEBUG > 1
++
++void log_fn_enter(const char *funcname);
++void log_fn_exit(const char *funcname);
++void log_fn_exit_v(const char *funcname, int v);
++
++#define FN_ENTER \
++ do { \
++ if (unlikely(acx_debug & L_FUNC)) { \
++ log_fn_enter(__func__); \
++ } \
++ } while (0)
++
++#define FN_EXIT1(v) \
++ do { \
++ if (unlikely(acx_debug & L_FUNC)) { \
++ log_fn_exit_v(__func__, v); \
++ } \
++ } while (0)
++#define FN_EXIT0 \
++ do { \
++ if (unlikely(acx_debug & L_FUNC)) { \
++ log_fn_exit(__func__); \
++ } \
++ } while (0)
++
++#else
++
++#define FN_ENTER
++#define FN_EXIT1(v)
++#define FN_EXIT0
++
++#endif /* ACX_DEBUG > 1 */
++
++
++#if ACX_DEBUG
++
++#define acxlog(chan, args...) \
++ do { \
++ if (acx_debug & (chan)) \
++ printk(args); \
++ } while (0)
++#define printk_ratelimited(args...) printk(args)
++
++#else /* Non-debug build: */
++
++#define acxlog(chan, args...)
++/* Standard way of log flood prevention */
++#define printk_ratelimited(args...) \
++do { \
++ if (printk_ratelimit()) \
++ printk(args); \
++} while (0)
++
++#endif /* ACX_DEBUG */
++
++void acx_print_mac(const char *head, const u8 *mac, const char *tail);
++
++/* Optimized out to nothing in non-debug build */
++static inline void
++acxlog_mac(int level, const char *head, const u8 *mac, const char *tail)
++{
++ if (acx_debug & level) {
++ acx_print_mac(head, mac, tail);
++ }
++}
++
++
++/***********************************************************************
++** MAC address helpers
++*/
++static inline void
++MAC_COPY(u8 *mac, const u8 *src)
++{
++ *(u32*)mac = *(u32*)src;
++ ((u16*)mac)[2] = ((u16*)src)[2];
++ /* kernel's memcpy will do the same: memcpy(dst, src, ETH_ALEN); */
++}
++
++static inline void
++MAC_FILL(u8 *mac, u8 val)
++{
++ memset(mac, val, ETH_ALEN);
++}
++
++static inline void
++MAC_BCAST(u8 *mac)
++{
++ ((u16*)mac)[2] = *(u32*)mac = -1;
++}
++
++static inline void
++MAC_ZERO(u8 *mac)
++{
++ ((u16*)mac)[2] = *(u32*)mac = 0;
++}
++
++static inline int
++mac_is_equal(const u8 *a, const u8 *b)
++{
++ /* can't beat this */
++ return memcmp(a, b, ETH_ALEN) == 0;
++}
++
++static inline int
++mac_is_bcast(const u8 *mac)
++{
++ /* AND together 4 first bytes with sign-entended 2 last bytes
++ ** Only bcast address gives 0xffffffff. +1 gives 0 */
++ return ( *(s32*)mac & ((s16*)mac)[2] ) + 1 == 0;
++}
++
++static inline int
++mac_is_zero(const u8 *mac)
++{
++ return ( *(u32*)mac | ((u16*)mac)[2] ) == 0;
++}
++
++static inline int
++mac_is_directed(const u8 *mac)
++{
++ return (mac[0] & 1)==0;
++}
++
++static inline int
++mac_is_mcast(const u8 *mac)
++{
++ return (mac[0] & 1) && !mac_is_bcast(mac);
++}
++
++#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
++#define MAC(bytevector) \
++ ((unsigned char *)bytevector)[0], \
++ ((unsigned char *)bytevector)[1], \
++ ((unsigned char *)bytevector)[2], \
++ ((unsigned char *)bytevector)[3], \
++ ((unsigned char *)bytevector)[4], \
++ ((unsigned char *)bytevector)[5]
++
++
++/***********************************************************************
++** Random helpers
++*/
++#define TO_STRING(x) #x
++#define STRING(x) TO_STRING(x)
++
++#define CLEAR_BIT(val, mask) ((val) &= ~(mask))
++#define SET_BIT(val, mask) ((val) |= (mask))
++
++/* undefined if v==0 */
++static inline unsigned int
++lowest_bit(u16 v)
++{
++ unsigned int n = 0;
++ while (!(v & 0xf)) { v>>=4; n+=4; }
++ while (!(v & 1)) { v>>=1; n++; }
++ return n;
++}
++
++/* undefined if v==0 */
++static inline unsigned int
++highest_bit(u16 v)
++{
++ unsigned int n = 0;
++ while (v>0xf) { v>>=4; n+=4; }
++ while (v>1) { v>>=1; n++; }
++ return n;
++}
++
++/* undefined if v==0 */
++static inline int
++has_only_one_bit(u16 v)
++{
++ return ((v-1) ^ v) >= v;
++}
++
++
++/***********************************************************************
++** LOCKING
++** We have priv->sem and priv->lock.
++**
++** We employ following naming convention in order to get locking right:
++**
++** acx_e_xxxx - external entry points called from process context.
++** It is okay to sleep. priv->sem is to be taken on entry.
++** acx_i_xxxx - external entry points possibly called from atomic context.
++** Sleeping is not allowed (and thus down(sem) is not legal!)
++** acx_s_xxxx - potentially sleeping functions. Do not ever call under lock!
++** acx_l_xxxx - functions which expect lock to be already taken.
++** rest - non-sleeping functions which do not require locking
++** but may be run inder lock
++**
++** Theory of operation:
++**
++** All process-context entry points (_e_ functions) take sem
++** immediately. IRQ handler and other 'atomic-context' entry points
++** (_i_ functions) take lock immediately on entry, but dont take sem
++** because that might sleep.
++**
++** Thus *all* code is either protected by sem or lock, or both.
++**
++** Code which must not run concurrently with IRQ takes lock.
++** Such code is marked with _l_.
++**
++** This results in the following rules of thumb useful in code review:
++**
++** + If a function calls _s_ fn, it must be an _s_ itself.
++** + You can call _l_ fn only (a) from another _l_ fn
++** or (b) from _s_, _e_ or _i_ fn by taking lock, calling _l_,
++** and dropping lock.
++** + All IRQ code runs under lock.
++** + Any _s_ fn is running under sem.
++** + Code under sem can race only with IRQ code.
++** + Code under sem+lock cannot race with anything.
++*/
++
++/* These functions *must* be inline or they will break horribly on SPARC, due
++ * to its weird semantics for save/restore flags */
++
++#if defined(PARANOID_LOCKING) /* Lock debugging */
++
++void acx_lock_debug(wlandevice_t *priv, const char* where);
++void acx_unlock_debug(wlandevice_t *priv, const char* where);
++void acx_down_debug(wlandevice_t *priv, const char* where);
++void acx_up_debug(wlandevice_t *priv, const char* where);
++void acx_lock_unhold(void);
++void acx_sem_unhold(void);
++
++static inline void
++acx_lock_helper(wlandevice_t *priv, unsigned long *fp, const char* where)
++{
++ acx_lock_debug(priv, where);
++ spin_lock_irqsave(&priv->lock, *fp);
++}
++static inline void
++acx_unlock_helper(wlandevice_t *priv, unsigned long *fp, const char* where)
++{
++ acx_unlock_debug(priv, where);
++ spin_unlock_irqrestore(&priv->lock, *fp);
++}
++static inline void
++acx_down_helper(wlandevice_t *priv, const char* where)
++{
++ acx_down_debug(priv, where);
++}
++static inline void
++acx_up_helper(wlandevice_t *priv, const char* where)
++{
++ acx_up_debug(priv, where);
++}
++#define acx_lock(priv, flags) acx_lock_helper(priv, &(flags), __FILE__ ":" STRING(__LINE__))
++#define acx_unlock(priv, flags) acx_unlock_helper(priv, &(flags), __FILE__ ":" STRING(__LINE__))
++#define acx_sem_lock(priv) acx_down_helper(priv, __FILE__ ":" STRING(__LINE__))
++#define acx_sem_unlock(priv) acx_up_helper(priv, __FILE__ ":" STRING(__LINE__))
++
++#elif defined(DO_LOCKING)
++
++#define acx_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
++#define acx_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
++#define acx_sem_lock(priv) down(&priv->sem)
++#define acx_sem_unlock(priv) up(&priv->sem)
++#define acx_lock_unhold() ((void)0)
++#define acx_sem_unhold() ((void)0)
++
++#else /* no locking! :( */
++
++#define acx_lock(priv, flags) ((void)0)
++#define acx_unlock(priv, flags) ((void)0)
++#define acx_sem_lock(priv) ((void)0)
++#define acx_sem_unlock(priv) ((void)0)
++#define acx_lock_unhold() ((void)0)
++#define acx_sem_unhold() ((void)0)
++
++#endif
++
++
++/***********************************************************************
++*/
++
++/* Can race with rx path (which is not protected by sem):
++** rx -> process_[re]assocresp() -> set_status(ASSOCIATED) -> wake_queue()
++** Can race with tx_complete IRQ:
++** IRQ -> acx_l_clean_tx_desc -> acx_wake_queue
++** Review carefully all callsites */
++static inline void
++acx_stop_queue(netdevice_t *dev, const char *msg)
++{
++ if(netif_queue_stopped(dev))
++ return;
++
++ netif_stop_queue(dev);
++ if (msg)
++ acxlog(L_BUFT, "tx: stop queue %s\n", msg);
++}
++
++static inline int
++acx_queue_stopped(netdevice_t *dev)
++{
++ return netif_queue_stopped(dev);
++}
++
++static inline void
++acx_start_queue(netdevice_t *dev, const char *msg)
++{
++ netif_start_queue(dev);
++ if (msg)
++ acxlog(L_BUFT, "tx: start queue %s\n", msg);
++}
++
++static inline void
++acx_wake_queue(netdevice_t *dev, const char *msg)
++{
++ netif_wake_queue(dev);
++ if (msg)
++ acxlog(L_BUFT, "tx: wake queue %s\n", msg);
++}
++
++static inline void
++acx_carrier_off(netdevice_t *dev, const char *msg)
++{
++ netif_carrier_off(dev);
++ if (msg)
++ acxlog(L_BUFT, "tx: carrier off %s\n", msg);
++}
++
++static inline void
++acx_carrier_on(netdevice_t *dev, const char *msg)
++{
++ netif_carrier_on(dev);
++ if (msg)
++ acxlog(L_BUFT, "tx: carrier on %s\n", msg);
++}
++
++/* This function does not need locking UNLESS you call it
++** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
++** wake queue. This can race with stop_queue elsewhere. */
++void acx_set_status(wlandevice_t *priv, u16 status);
++
++
++/***********************************************************************
++** Communication with firmware
++*/
++#define CMD_TIMEOUT_MS(n) (n)
++#define ACX_CMD_TIMEOUT_DEFAULT CMD_TIMEOUT_MS(50)
++
++#if ACX_DEBUG
++
++/* We want to log cmd names */
++int acxpci_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
++int acxusb_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr);
++static inline int
++acx_s_issue_cmd_timeo_debug(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout, const char* cmdstr)
++{
++#if defined(CONFIG_ACX_CFI)
++ return acxpci_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
++#else
++ if (IS_PCI(priv))
++ return acxpci_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
++ return acxusb_s_issue_cmd_timeo_debug(priv, cmd, param, len, timeout, cmdstr);
++#endif
++}
++#define acx_s_issue_cmd(priv,cmd,param,len) \
++ acx_s_issue_cmd_timeo_debug(priv,cmd,param,len,ACX_CMD_TIMEOUT_DEFAULT,#cmd)
++#define acx_s_issue_cmd_timeo(priv,cmd,param,len,timeo) \
++ acx_s_issue_cmd_timeo_debug(priv,cmd,param,len,timeo,#cmd)
++int acx_s_configure_debug(wlandevice_t *priv, void *pdr, int type, const char* str);
++#define acx_s_configure(priv,pdr,type) \
++ acx_s_configure_debug(priv,pdr,type,#type)
++int acx_s_interrogate_debug(wlandevice_t *priv, void *pdr, int type, const char* str);
++#define acx_s_interrogate(priv,pdr,type) \
++ acx_s_interrogate_debug(priv,pdr,type,#type)
++
++#else
++
++int acxpci_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout);
++int acxusb_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout);
++static inline int
++acx_s_issue_cmd_timeo(wlandevice_t *priv, unsigned cmd, void *param, unsigned len, unsigned timeout)
++{
++ if (IS_PCI(priv))
++ return acxpci_s_issue_cmd_timeo(priv, cmd, param, len, timeout);
++ return acxusb_s_issue_cmd_timeo(priv, cmd, param, len, timeout);
++}
++static inline int
++acx_s_issue_cmd(wlandevice_t *priv, unsigned cmd, void *param, unsigned len)
++{
++ if (IS_PCI(priv))
++ return acxpci_s_issue_cmd_timeo(priv, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
++ return acxusb_s_issue_cmd_timeo(priv, cmd, param, len, ACX_CMD_TIMEOUT_DEFAULT);
++}
++int acx_s_configure(wlandevice_t *priv, void *pdr, int type);
++int acx_s_interrogate(wlandevice_t *priv, void *pdr, int type);
++
++#endif
++
++void acx_s_cmd_start_scan(wlandevice_t *priv);
++
++
++/***********************************************************************
++** Ioctls
++*/
++int
++acx111pci_ioctl_info(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra);
++int
++acx100pci_ioctl_set_phy_amp_bias(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra);
++
++
++/***********************************************************************
++** Unsorted yet :)
++*/
++int acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf);
++int acxusb_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf);
++static inline int
++acx_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
++{
++#if defined(CONFIG_ACX_CFI)
++ return acxpci_s_read_phy_reg(priv, reg, charbuf);
++#else
++ if (IS_PCI(priv))
++ return acxpci_s_read_phy_reg(priv, reg, charbuf);
++ return acxusb_s_read_phy_reg(priv, reg, charbuf);
++#endif
++}
++
++int acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value);
++int acxusb_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value);
++static inline int
++acx_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
++{
++#if defined(CONFIG_ACX_CFI)
++ return acxpci_s_write_phy_reg(priv, reg, value);
++#else
++ if (IS_PCI(priv))
++ return acxpci_s_write_phy_reg(priv, reg, value);
++ return acxusb_s_write_phy_reg(priv, reg, value);
++#endif
++}
++
++void acx_s_msleep(int ms);
++int acx_s_init_mac(netdevice_t *dev);
++void acx_set_reg_domain(wlandevice_t *priv, unsigned char reg_dom_id);
++void acx_set_timer(wlandevice_t *priv, int timeout_us);
++void acx_update_capabilities(wlandevice_t *priv);
++int acx_read_eeprom_offset(wlandevice_t *priv, u32 addr, u8 *charbuf);
++void acx_s_start(wlandevice_t *priv);
++#if USE_FW_LOADER_26
++firmware_image_t *acx_s_read_fw(struct device *dev, const char *file, u32 *size);
++#else
++firmware_image_t *acx_s_read_fw(const char *file, u32 *size);
++#define acx_s_read_fw(dev, file, size) acx_s_read_fw(file, size)
++#endif
++void acx_s_initialize_rx_config(wlandevice_t *priv);
++void acx_s_update_card_settings(wlandevice_t *priv, int get_all, int set_all);
++void acx_init_task_scheduler(wlandevice_t *priv);
++void acx_schedule_after_interrupt_task(wlandevice_t *priv, unsigned int set_flag);
++int acx_s_upload_radio(wlandevice_t *priv);
++void acx_read_configoption(wlandevice_t *priv);
++int acx_proc_register_entries(const struct net_device *dev);
++int acx_proc_unregister_entries(const struct net_device *dev);
++void acx_l_update_ratevector(wlandevice_t *priv);
++
++int acx_e_ioctl_old(netdevice_t *dev, struct ifreq *ifr, int cmd);
++
++client_t *acx_l_sta_list_get(wlandevice_t *priv, const u8 *address);
++void acx_l_sta_list_del(wlandevice_t *priv, client_t *clt);
++
++int acx_l_transmit_disassoc(wlandevice_t *priv, client_t *clt);
++void acx_i_timer(unsigned long a);
++int acx_s_complete_scan(wlandevice_t *priv);
++
++static inline wlan_hdr_t*
++acx_get_wlan_hdr(wlandevice_t *priv, const rxbuffer_t *rxbuf)
++{
++ if (!(priv->rx_config_1 & RX_CFG1_INCLUDE_PHY_HDR))
++ return (wlan_hdr_t*)&rxbuf->hdr_a3;
++
++ /* take into account phy header in front of packet */
++ if (IS_ACX111(priv))
++ return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 8);
++
++ return (wlan_hdr_t*)((u8*)&rxbuf->hdr_a3 + 4);
++}
++
++struct sk_buff *acx_rxbuf_to_ether(struct wlandevice *priv, rxbuffer_t *rxbuf);
++
++void acx_l_power_led(wlandevice_t *priv, int enable);
++
++unsigned int acx_l_clean_tx_desc(wlandevice_t *priv);
++void acx_l_clean_tx_desc_emergency(wlandevice_t *priv);
++
++u8 acx_signal_determine_quality(u8 signal, u8 noise);
++
++void acx_l_process_rxbuf(wlandevice_t *priv, rxbuffer_t *rxbuf);
++void acx_l_process_rx_desc(wlandevice_t *priv);
++
++tx_t* acxpci_l_alloc_tx(wlandevice_t *priv);
++tx_t* acxusb_l_alloc_tx(wlandevice_t *priv);
++static inline tx_t*
++acx_l_alloc_tx(wlandevice_t *priv)
++{
++#if defined(CONFIG_ACX_CFI)
++ return acxpci_l_alloc_tx(priv);
++#else
++ if (IS_PCI(priv))
++ return acxpci_l_alloc_tx(priv);
++ return acxusb_l_alloc_tx(priv);
++#endif
++}
++
++void* acxpci_l_get_txbuf(wlandevice_t *priv, tx_t *tx_opaque);
++void* acxusb_l_get_txbuf(wlandevice_t *priv, tx_t *tx_opaque);
++static inline void*
++acx_l_get_txbuf(wlandevice_t *priv, tx_t *tx_opaque)
++{
++#if defined(CONFIG_ACX_CFI)
++ return acxpci_l_get_txbuf(priv, tx_opaque);
++#else
++ if (IS_PCI(priv))
++ return acxpci_l_get_txbuf(priv, tx_opaque);
++ return acxusb_l_get_txbuf(priv, tx_opaque);
++#endif
++}
++
++void acxpci_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len);
++void acxusb_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len);
++static inline void
++acx_l_tx_data(wlandevice_t *priv, tx_t *tx_opaque, int len)
++{
++#if defined(CONFIG_ACX_CFI)
++ acxpci_l_tx_data(priv, tx_opaque, len);
++#else
++ if (IS_PCI(priv))
++ acxpci_l_tx_data(priv, tx_opaque, len);
++ else
++ acxusb_l_tx_data(priv, tx_opaque, len);
++#endif
++}
++
++void acx_dump_bytes(const void *, int);
++void acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr);
++
++u8 acx_rate111to100(u16);
++
++void acx100usb_l_tx_data(wlandevice_t *priv, struct txdesc *desc);
++int acx_s_set_defaults(wlandevice_t *priv);
++void acx_init_mboxes(wlandevice_t *priv);
++
++int acx_l_ether_to_txbuf(wlandevice_t *priv, void *txbuf, const struct sk_buff *skb);
++
++#if !ACX_DEBUG
++static inline const char* acx_get_packet_type_string(u16 fc) { return ""; }
++#else
++const char* acx_get_packet_type_string(u16 fc);
++#endif
++const char* acx_cmd_status_str(unsigned int state);
++
++int acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev);
++void acx_free_desc_queues(wlandevice_t *priv);
++
++int acx_s_create_hostdesc_queues(wlandevice_t *priv);
++void acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start);
++
++int acx100_s_init_wep(wlandevice_t *priv);
++int acx100_s_init_packet_templates(wlandevice_t *priv);
++int acx111_s_init_packet_templates(wlandevice_t *priv);
++
++void great_inquisitor(wlandevice_t *priv);
++
++char* acxpci_s_proc_diag_output(char *p, wlandevice_t *priv);
++int acx_proc_eeprom_output(char *p, wlandevice_t *priv);
++void acx_set_interrupt_mask(wlandevice_t *priv);
++int acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm);
++
++#if defined(CONFIG_ACX_CFI)
++int __init acxcfi_e_init_module(void);
++#else
++int __init acxpci_e_init_module(void);
++int __init acxusb_e_init_module(void);
++#endif
++
++#if defined(CONFIG_ACX_CFI)
++void __exit acxcfi_e_cleanup_module(void);
++#else
++void __exit acxpci_e_cleanup_module(void);
++void __exit acxusb_e_cleanup_module(void);
++#endif
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx.h 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,6 @@
++#include "acx_config.h"
++#include "wlan_compat.h"
++#include "wlan_hdr.h"
++#include "wlan_mgmt.h"
++#include "acx_struct.h"
++#include "acx_func.h"
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx_struct.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx_struct.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/acx_struct.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/acx_struct.h 2005-10-29 22:02:44.000000000 +0300
+@@ -0,0 +1,1966 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++/***********************************************************************
++** Forward declarations of types
++*/
++typedef struct tx tx_t;
++typedef struct wlandevice wlandevice_t;
++typedef struct client client_t;
++typedef struct rxdesc rxdesc_t;
++typedef struct txdesc txdesc_t;
++typedef struct rxhostdesc rxhostdesc_t;
++typedef struct txhostdesc txhostdesc_t;
++
++
++/***********************************************************************
++** Debug / log functionality
++*/
++enum {
++ L_LOCK = (ACX_DEBUG>1)*0x0001, /* locking debug log */
++ L_INIT = (ACX_DEBUG>0)*0x0002, /* special card initialization logging */
++ L_IRQ = (ACX_DEBUG>0)*0x0004, /* interrupt stuff */
++ L_ASSOC = (ACX_DEBUG>0)*0x0008, /* assocation (network join) and station log */
++ L_FUNC = (ACX_DEBUG>1)*0x0020, /* logging of function enter / leave */
++ L_XFER = (ACX_DEBUG>1)*0x0080, /* logging of transfers and mgmt */
++ L_DATA = (ACX_DEBUG>1)*0x0100, /* logging of transfer data */
++ L_DEBUG = (ACX_DEBUG>1)*0x0200, /* log of debug info */
++ L_IOCTL = (ACX_DEBUG>0)*0x0400, /* log ioctl calls */
++ L_CTL = (ACX_DEBUG>1)*0x0800, /* log of low-level ctl commands */
++ L_BUFR = (ACX_DEBUG>1)*0x1000, /* debug rx buffer mgmt (ring buffer etc.) */
++ L_XFER_BEACON = (ACX_DEBUG>1)*0x2000, /* also log beacon packets */
++ L_BUFT = (ACX_DEBUG>1)*0x4000, /* debug tx buffer mgmt (ring buffer etc.) */
++ L_USBRXTX = (ACX_DEBUG>0)*0x8000, /* debug USB rx/tx operations */
++ L_BUF = L_BUFR + L_BUFT,
++ L_ANY = 0xffff
++};
++
++#if ACX_DEBUG
++extern unsigned int acx_debug;
++#else
++enum { acx_debug = 0 };
++#endif
++
++
++/*============================================================================*
++ * Random helpers *
++ *============================================================================*/
++#define ACX_PACKED __WLAN_ATTRIB_PACK__
++
++#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
++
++/* Use worker_queues for 2.5/2.6 Kernels and queue tasks for 2.4 Kernels
++ (used for the 'bottom half' of the interrupt routine) */
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
++#include <linux/workqueue.h>
++/* #define NEWER_KERNELS_ONLY 1 */
++#define USE_WORKER_TASKS
++#define WORK_STRUCT struct work_struct
++#define SCHEDULE_WORK schedule_work
++#define FLUSH_SCHEDULED_WORK flush_scheduled_work
++
++#else
++#include <linux/tqueue.h>
++#define USE_QUEUE_TASKS
++#define WORK_STRUCT struct tq_struct
++#define SCHEDULE_WORK schedule_task
++#define INIT_WORK(work, func, ndev) \
++ do { \
++ (work)->routine = (func); \
++ (work)->data = (ndev); \
++ } while (0)
++#define FLUSH_SCHEDULED_WORK flush_scheduled_tasks
++
++#endif
++
++
++/*============================================================================*
++ * Constants *
++ *============================================================================*/
++#define OK 0
++#define NOT_OK 1
++
++/* The supported chip models */
++#define CHIPTYPE_ACX100 1
++#define CHIPTYPE_ACX111 2
++
++#define IS_ACX100(priv) ((priv)->chip_type == CHIPTYPE_ACX100)
++#define IS_ACX111(priv) ((priv)->chip_type == CHIPTYPE_ACX111)
++
++/* Supported interfaces */
++#define DEVTYPE_PCI 0
++#define DEVTYPE_USB 1
++
++#if defined(CONFIG_ACX_PCI)
++ #if !defined(CONFIG_ACX_USB)
++ #define IS_PCI(priv) 1
++ #else
++ #define IS_PCI(priv) ((priv)->dev_type == DEVTYPE_PCI)
++ #endif
++#else
++ #define IS_PCI(priv) 0
++#endif
++
++#if defined(CONFIG_ACX_USB)
++ #if !defined(CONFIG_ACX_PCI)
++ #define IS_USB(priv) 1
++ #else
++ #define IS_USB(priv) ((priv)->dev_type == DEVTYPE_USB)
++ #endif
++#else
++ #define IS_USB(priv) 0
++#endif
++
++/* Driver defaults */
++#define DEFAULT_DTIM_INTERVAL 10
++/* used to be 2048, but FreeBSD driver changed it to 4096 to work properly
++** in noisy wlans */
++#define DEFAULT_MSDU_LIFETIME 4096
++#define DEFAULT_RTS_THRESHOLD 2312 /* max. size: disable RTS mechanism */
++#define DEFAULT_BEACON_INTERVAL 100
++
++#define ACX100_BAP_DATALEN_MAX 4096
++#define ACX100_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */
++#define ACX100_RIDDATA_MAXLEN ACX100_RID_GUESSING_MAXLEN
++
++/* Support Constants */
++/* Radio type names, found in Win98 driver's TIACXLN.INF */
++#define RADIO_MAXIM_0D 0x0d
++#define RADIO_RFMD_11 0x11
++#define RADIO_RALINK_15 0x15
++/* used in ACX111 cards (WG311v2, WL-121, ...): */
++#define RADIO_RADIA_16 0x16
++/* most likely *sometimes* used in ACX111 cards: */
++#define RADIO_UNKNOWN_17 0x17
++/* FwRad19.bin was found in a Safecom driver; must be an ACX111 radio: */
++#define RADIO_UNKNOWN_19 0x19
++
++/* Controller Commands */
++/* can be found in table cmdTable in firmware "Rev. 1.5.0" (FW150) */
++#define ACX1xx_CMD_RESET 0x00
++#define ACX1xx_CMD_INTERROGATE 0x01
++#define ACX1xx_CMD_CONFIGURE 0x02
++#define ACX1xx_CMD_ENABLE_RX 0x03
++#define ACX1xx_CMD_ENABLE_TX 0x04
++#define ACX1xx_CMD_DISABLE_RX 0x05
++#define ACX1xx_CMD_DISABLE_TX 0x06
++#define ACX1xx_CMD_FLUSH_QUEUE 0x07
++#define ACX1xx_CMD_SCAN 0x08
++#define ACX1xx_CMD_STOP_SCAN 0x09
++#define ACX1xx_CMD_CONFIG_TIM 0x0a
++#define ACX1xx_CMD_JOIN 0x0b
++#define ACX1xx_CMD_WEP_MGMT 0x0c
++#ifdef OLD_FIRMWARE_VERSIONS
++#define ACX100_CMD_HALT 0x0e /* mapped to unknownCMD in FW150 */
++#else
++#define ACX1xx_CMD_MEM_READ 0x0d
++#define ACX1xx_CMD_MEM_WRITE 0x0e
++#endif
++#define ACX1xx_CMD_SLEEP 0x0f
++#define ACX1xx_CMD_WAKE 0x10
++#define ACX1xx_CMD_UNKNOWN_11 0x11 /* mapped to unknownCMD in FW150 */
++#define ACX100_CMD_INIT_MEMORY 0x12
++#define ACX1xx_CMD_CONFIG_BEACON 0x13
++#define ACX1xx_CMD_CONFIG_PROBE_RESPONSE 0x14
++#define ACX1xx_CMD_CONFIG_NULL_DATA 0x15
++#define ACX1xx_CMD_CONFIG_PROBE_REQUEST 0x16
++#define ACX1xx_CMD_TEST 0x17
++#define ACX1xx_CMD_RADIOINIT 0x18
++#define ACX111_CMD_RADIOCALIB 0x19
++
++/* 'After Interrupt' Commands */
++#define ACX_AFTER_IRQ_CMD_STOP_SCAN 0x01
++#define ACX_AFTER_IRQ_CMD_ASSOCIATE 0x02
++#define ACX_AFTER_IRQ_CMD_RADIO_RECALIB 0x04
++#define ACX_AFTER_IRQ_UPDATE_CARD_CFG 0x08
++#define ACX_AFTER_IRQ_TX_CLEANUP 0x10
++#define ACX_AFTER_IRQ_COMPLETE_SCAN 0x20
++#define ACX_AFTER_IRQ_RESTART_SCAN 0x40
++
++/***********************************************************************
++** Tx/Rx buffer sizes and watermarks
++*/
++/* BTW, this will alloc and use DMAable buffers of
++** WLAN_A4FR_MAXLEN_WEP_FCS * (RX_CNT + TX_CNT) bytes
++** RX/TX_CNT=32 -> ~150k DMA buffers
++** RX/TX_CNT=16 -> ~75k DMA buffers
++*/
++#define RX_CNT 32
++#define TX_CNT 32
++
++/* we clean up txdescs when we have N free txdesc: */
++#define TX_START_CLEAN (TX_CNT - (TX_CNT/4))
++#define TX_EMERG_CLEAN 2
++/* we stop queue if we have less than N free txbufs: */
++#define TX_STOP_QUEUE 3
++/* we start queue if we have more than N free txbufs: */
++#define TX_START_QUEUE 6
++
++/***********************************************************************
++** Interrogate/Configure cmd constants
++**
++** NB: length includes JUST the data part of the IE
++** (does not include size of the (type,len) pair)
++**
++** TODO: seems that acx100, acx100usb, acx111 have some differences,
++** fix code with regard to this!
++*/
++
++#define DEF_IE(name, val, len) enum { ACX##name=val, ACX##name##_LEN=len }
++
++/* Information Elements: Network Parameters, Static Configuration Entities */
++/* these are handled by real_cfgtable in firmware "Rev 1.5.0" (FW150) */
++DEF_IE(1xx_IE_UNKNOWN_00 ,0x0000, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(100_IE_ACX_TIMER ,0x0001, 0x10);
++DEF_IE(1xx_IE_POWER_MGMT ,0x0002, 0x06);
++DEF_IE(1xx_IE_QUEUE_CONFIG ,0x0003, 0x1c);
++DEF_IE(100_IE_BLOCK_SIZE ,0x0004, 0x02);
++DEF_IE(1xx_IE_MEMORY_CONFIG_OPTIONS ,0x0005, 0x14);
++DEF_IE(1xx_IE_RATE_FALLBACK ,0x0006, 0x01);
++DEF_IE(100_IE_WEP_OPTIONS ,0x0007, 0x03);
++DEF_IE(111_IE_RADIO_BAND ,0x0007, -1);
++DEF_IE(1xx_IE_MEMORY_MAP ,0x0008, 0x28); /* huh? */
++DEF_IE(100_IE_SSID ,0x0008, 0x20); /* huh? */
++DEF_IE(1xx_IE_SCAN_STATUS ,0x0009, 0x04); /* mapped to cfgInvalid in FW150 */
++DEF_IE(1xx_IE_ASSOC_ID ,0x000a, 0x02);
++DEF_IE(1xx_IE_UNKNOWN_0B ,0x000b, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(100_IE_UNKNOWN_0C ,0x000c, -1); /* very small implementation in FW150! */
++DEF_IE(111_IE_CONFIG_OPTIONS ,0x000c, 0x14c);
++DEF_IE(1xx_IE_FWREV ,0x000d, 0x18);
++DEF_IE(1xx_IE_FCS_ERROR_COUNT ,0x000e, 0x04);
++DEF_IE(1xx_IE_MEDIUM_USAGE ,0x000f, 0x08);
++DEF_IE(1xx_IE_RXCONFIG ,0x0010, 0x04);
++DEF_IE(100_IE_UNKNOWN_11 ,0x0011, -1); /* NONBINARY: large implementation in FW150! link quality readings or so? */
++DEF_IE(111_IE_QUEUE_THRESH ,0x0011, -1);
++DEF_IE(100_IE_UNKNOWN_12 ,0x0012, -1); /* NONBINARY: VERY large implementation in FW150!! */
++DEF_IE(111_IE_BSS_POWER_SAVE ,0x0012, -1);
++DEF_IE(1xx_IE_FIRMWARE_STATISTICS ,0x0013, 0x9c);
++DEF_IE(1xx_IE_FEATURE_CONFIG ,0x0015, 0x08);
++DEF_IE(111_IE_KEY_CHOOSE ,0x0016, 0x04); /* for rekeying. really len=4?? */
++DEF_IE(1xx_IE_DOT11_STATION_ID ,0x1001, 0x06);
++DEF_IE(100_IE_DOT11_UNKNOWN_1002 ,0x1002, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(111_IE_DOT11_FRAG_THRESH ,0x1002, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(100_IE_DOT11_BEACON_PERIOD ,0x1003, 0x02); /* mapped to cfgInvalid in FW150 */
++DEF_IE(1xx_IE_DOT11_DTIM_PERIOD ,0x1004, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(1xx_IE_DOT11_SHORT_RETRY_LIMIT ,0x1005, 0x01);
++DEF_IE(1xx_IE_DOT11_LONG_RETRY_LIMIT ,0x1006, 0x01);
++DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE ,0x1007, 0x20); /* configure default keys */
++DEF_IE(1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME ,0x1008, 0x04);
++DEF_IE(1xx_IE_DOT11_GROUP_ADDR ,0x1009, -1);
++DEF_IE(1xx_IE_DOT11_CURRENT_REG_DOMAIN ,0x100a, 0x02);
++//It's harmless to have larger struct. Use USB case always.
++////#ifdef ACX_PCI
++////DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA ,0x100b, 0x01);
++////#else
++DEF_IE(1xx_IE_DOT11_CURRENT_ANTENNA ,0x100b, 0x02);
++////#endif
++DEF_IE(1xx_IE_DOT11_UNKNOWN_100C ,0x100c, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(1xx_IE_DOT11_TX_POWER_LEVEL ,0x100d, 0x01);
++////#ifdef ACX_PCI
++////DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE ,0x100e, 0x01);
++////#else
++DEF_IE(1xx_IE_DOT11_CURRENT_CCA_MODE ,0x100e, 0x02);
++////#endif
++//USB doesn't return anything - len==0?!
++DEF_IE(100_IE_DOT11_ED_THRESHOLD ,0x100f, 0x04);
++DEF_IE(1xx_IE_DOT11_WEP_DEFAULT_KEY_SET ,0x1010, 0x01); /* set default key ID */
++DEF_IE(100_IE_DOT11_UNKNOWN_1011 ,0x1011, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(100_IE_DOT11_UNKNOWN_1012 ,0x1012, -1); /* mapped to cfgInvalid in FW150 */
++DEF_IE(100_IE_DOT11_UNKNOWN_1013 ,0x1013, -1); /* mapped to cfgInvalid in FW150 */
++
++#if 0
++/* Experimentally obtained on acx100, fw 1.9.8.b
++** -1 means that fw returned 'invalid IE'
++** 0200 FC00 nnnn... are test read contents: u16 type, u16 len, data
++** (AA are poison bytes marking bytes not written by fw)
++**
++** Looks like acx100 fw does not update len field (thus len=256-4=FC here)
++** A number of IEs seem to trash type,len fields
++** IEs marked 'huge' return gobs of data (no poison bytes remain)
++*/
++DEF_IE(100_IE_INVAL_00, 0x0000, -1);
++DEF_IE(100_IE_INVAL_01, 0x0001, -1); /* IE_ACX_TIMER, len=16 on older fw */
++DEF_IE(100_IE_POWER_MGMT, 0x0002, 4); /* 0200FC00 00040000 AAAAAAAA */
++DEF_IE(100_IE_QUEUE_CONFIG, 0x0003, 28); /* 0300FC00 48060000 9CAD0000 0101AAAA DCB00000 E4B00000 9CAA0000 00AAAAAA */
++DEF_IE(100_IE_BLOCK_SIZE, 0x0004, 2); /* 0400FC00 0001AAAA AAAAAAAA AAAAAAAA */
++/* write only: */
++DEF_IE(100_IE_MEMORY_CONFIG_OPTIONS, 0x0005, 20);
++DEF_IE(100_IE_RATE_FALLBACK, 0x0006, 1); /* 0600FC00 00AAAAAA AAAAAAAA AAAAAAAA */
++/* write only: */
++DEF_IE(100_IE_WEP_OPTIONS, 0x0007, 3);
++DEF_IE(100_IE_MEMORY_MAP, 0x0008, 40); /* huge: 0800FC00 30000000 6CA20000 70A20000... */
++/* gives INVAL on read: */
++DEF_IE(100_IE_SCAN_STATUS, 0x0009, -1);
++DEF_IE(100_IE_ASSOC_ID, 0x000a, 2); /* huge: 0A00FC00 00000000 01040800 00000000... */
++DEF_IE(100_IE_INVAL_0B, 0x000b, -1);
++/* 'command rejected': */
++DEF_IE(100_IE_CONFIG_OPTIONS, 0x000c, -3);
++DEF_IE(100_IE_FWREV, 0x000d, 24); /* 0D00FC00 52657620 312E392E 382E6200 AAAAAAAA AAAAAAAA 05050201 AAAAAAAA */
++DEF_IE(100_IE_FCS_ERROR_COUNT, 0x000e, 4);
++DEF_IE(100_IE_MEDIUM_USAGE, 0x000f, 8); /* E41F0000 2D780300 FCC91300 AAAAAAAA */
++DEF_IE(100_IE_RXCONFIG, 0x0010, 4); /* 1000FC00 00280000 AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_QUEUE_THRESH, 0x0011, 12); /* 1100FC00 AAAAAAAA 00000000 00000000 */
++DEF_IE(100_IE_BSS_POWER_SAVE, 0x0012, 1); /* 1200FC00 00AAAAAA AAAAAAAA AAAAAAAA */
++/* read only, variable len */
++DEF_IE(100_IE_FIRMWARE_STATISTICS, 0x0013, 256); /* 0000AC00 00000000 ... */
++DEF_IE(100_IE_INT_CONFIG, 0x0014, 20); /* 00000000 00000000 00000000 00000000 5D74D105 00000000 AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_FEATURE_CONFIG, 0x0015, 8); /* 1500FC00 16000000 AAAAAAAA AAAAAAAA */
++/* returns 'invalid MAC': */
++DEF_IE(100_IE_KEY_CHOOSE, 0x0016, -4);
++DEF_IE(100_IE_INVAL_17, 0x0017, -1);
++DEF_IE(100_IE_UNKNOWN_18, 0x0018, 0); /* null len?! 1800FC00 AAAAAAAA AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_UNKNOWN_19, 0x0019, 256); /* huge: 1900FC00 9C1F00EA FEFFFFEA FEFFFFEA... */
++DEF_IE(100_IE_INVAL_1A, 0x001A, -1);
++
++DEF_IE(100_IE_DOT11_INVAL_1000, 0x1000, -1);
++DEF_IE(100_IE_DOT11_STATION_ID, 0x1001, 6); /* huge: 0110FC00 58B10E2F 03000000 00000000... */
++DEF_IE(100_IE_DOT11_INVAL_1002, 0x1002, -1);
++DEF_IE(100_IE_DOT11_INVAL_1003, 0x1003, -1);
++DEF_IE(100_IE_DOT11_INVAL_1004, 0x1004, -1);
++DEF_IE(100_IE_DOT11_SHORT_RETRY_LIMIT, 0x1005, 1);
++DEF_IE(100_IE_DOT11_LONG_RETRY_LIMIT, 0x1006, 1);
++/* write only: */
++DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_WRITE, 0x1007, 32);
++DEF_IE(100_IE_DOT11_MAX_XMIT_MSDU_LIFETIME, 0x1008, 4); /* huge: 0810FC00 00020000 F4010000 00000000... */
++/* undoc but returns something */
++DEF_IE(100_IE_DOT11_GROUP_ADDR, 0x1009, 12); /* huge: 0910FC00 00000000 00000000 00000000... */
++DEF_IE(100_IE_DOT11_CURRENT_REG_DOMAIN, 0x100a, 1); /* 0A10FC00 30AAAAAA AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_DOT11_CURRENT_ANTENNA, 0x100b, 1); /* 0B10FC00 8FAAAAAA AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_DOT11_INVAL_100C, 0x100c, -1);
++DEF_IE(100_IE_DOT11_TX_POWER_LEVEL, 0x100d, 2); /* 00000000 0100AAAA AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_DOT11_CURRENT_CCA_MODE, 0x100e, 1); /* 0E10FC00 0DAAAAAA AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_DOT11_ED_THRESHOLD, 0x100f, 4); /* 0F10FC00 70000000 AAAAAAAA AAAAAAAA */
++/* set default key ID */
++DEF_IE(100_IE_DOT11_WEP_DEFAULT_KEY_SET, 0x1010, 1); /* 1010FC00 00AAAAAA AAAAAAAA AAAAAAAA */
++DEF_IE(100_IE_DOT11_INVAL_1011, 0x1011, -1);
++DEF_IE(100_IE_DOT11_INVAL_1012, 0x1012, -1);
++DEF_IE(100_IE_DOT11_INVAL_1013, 0x1013, -1);
++DEF_IE(100_IE_DOT11_UNKNOWN_1014, 0x1014, 256); /* huge */
++DEF_IE(100_IE_DOT11_UNKNOWN_1015, 0x1015, 256); /* huge */
++DEF_IE(100_IE_DOT11_UNKNOWN_1016, 0x1016, 256); /* huge */
++DEF_IE(100_IE_DOT11_UNKNOWN_1017, 0x1017, 256); /* huge */
++DEF_IE(100_IE_DOT11_UNKNOWN_1018, 0x1018, 256); /* huge */
++DEF_IE(100_IE_DOT11_UNKNOWN_1019, 0x1019, 256); /* huge */
++#endif
++
++#if 0
++/* Experimentally obtained on PCI acx111 Xterasys XN-2522g, fw 1.2.1.34
++** -1 means that fw returned 'invalid IE'
++** 0400 0800 nnnn... are test read contents: u16 type, u16 len, data
++** (AA are poison bytes marking bytes not written by fw)
++**
++** Looks like acx111 fw reports real len!
++*/
++DEF_IE(111_IE_INVAL_00, 0x0000, -1);
++DEF_IE(111_IE_INVAL_01, 0x0001, -1);
++DEF_IE(111_IE_POWER_MGMT, 0x0002, 12);
++/* write only, variable len: 12 + rxqueue_cnt*8 + txqueue_cnt*4: */
++DEF_IE(111_IE_MEMORY_CONFIG, 0x0003, 24);
++DEF_IE(111_IE_BLOCK_SIZE, 0x0004, 8); /* 04000800 AA00AAAA AAAAAAAA */
++/* variable len: 8 + rxqueue_cnt*8 + txqueue_cnt*8: */
++DEF_IE(111_IE_QUEUE_HEAD, 0x0005, 24);
++DEF_IE(111_IE_RATE_FALLBACK, 0x0006, 1);
++/* acx100 name:WEP_OPTIONS */
++/* said to have len:1 (not true, actually returns 12 bytes): */
++DEF_IE(111_IE_RADIO_BAND, 0x0007, 12); /* 07000C00 AAAA1F00 FF03AAAA AAAAAAAA */
++DEF_IE(111_IE_MEMORY_MAP, 0x0008, 48);
++/* said to have len:4, but gives INVAL on read: */
++DEF_IE(111_IE_SCAN_STATUS, 0x0009, -1);
++DEF_IE(111_IE_ASSOC_ID, 0x000a, 2);
++/* write only, len is not known: */
++DEF_IE(111_IE_UNKNOWN_0B, 0x000b, 0);
++/* read only, variable len. I see 67 byte reads: */
++DEF_IE(111_IE_CONFIG_OPTIONS, 0x000c, 67); /* 0C004300 01160500 ... */
++DEF_IE(111_IE_FWREV, 0x000d, 24);
++DEF_IE(111_IE_FCS_ERROR_COUNT, 0x000e, 4);
++DEF_IE(111_IE_MEDIUM_USAGE, 0x000f, 8);
++DEF_IE(111_IE_RXCONFIG, 0x0010, 4);
++DEF_IE(111_IE_QUEUE_THRESH, 0x0011, 12);
++DEF_IE(111_IE_BSS_POWER_SAVE, 0x0012, 1);
++/* read only, variable len. I see 240 byte reads: */
++DEF_IE(111_IE_FIRMWARE_STATISTICS, 0x0013, 240); /* 1300F000 00000000 ... */
++/* said to have len=17. looks like fw pads it to 20: */
++DEF_IE(111_IE_INT_CONFIG, 0x0014, 20); /* 14001400 00000000 00000000 00000000 00000000 00000000 */
++DEF_IE(111_IE_FEATURE_CONFIG, 0x0015, 8);
++/* said to be name:KEY_INDICATOR, len:4, but gives INVAL on read: */
++DEF_IE(111_IE_KEY_CHOOSE, 0x0016, -1);
++/* said to have len:4, but in fact returns 8: */
++DEF_IE(111_IE_MAX_USB_XFR, 0x0017, 8); /* 17000800 00014000 00000000 */
++DEF_IE(111_IE_INVAL_18, 0x0018, -1);
++DEF_IE(111_IE_INVAL_19, 0x0019, -1);
++/* undoc but returns something: */
++/* huh, fw indicates len=20 but uses 4 more bytes in buffer??? */
++DEF_IE(111_IE_UNKNOWN_1A, 0x001A, 20); /* 1A001400 AA00AAAA 0000020F FF030000 00020000 00000007 04000000 */
++
++DEF_IE(111_IE_DOT11_INVAL_1000, 0x1000, -1);
++DEF_IE(111_IE_DOT11_STATION_ID, 0x1001, 6);
++DEF_IE(111_IE_DOT11_FRAG_THRESH, 0x1002, 2);
++/* acx100 only? gives INVAL on read: */
++DEF_IE(111_IE_DOT11_BEACON_PERIOD, 0x1003, -1);
++/* said to be MAX_RECV_MSDU_LIFETIME: */
++DEF_IE(111_IE_DOT11_DTIM_PERIOD, 0x1004, 4);
++DEF_IE(111_IE_DOT11_SHORT_RETRY_LIMIT, 0x1005, 1);
++DEF_IE(111_IE_DOT11_LONG_RETRY_LIMIT, 0x1006, 1);
++/* acx100 only? gives INVAL on read: */
++DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_WRITE, 0x1007, -1);
++DEF_IE(111_IE_DOT11_MAX_XMIT_MSDU_LIFETIME, 0x1008, 4);
++/* undoc but returns something. maybe it's 2 multicast MACs to listen to? */
++DEF_IE(111_IE_DOT11_GROUP_ADDR, 0x1009, 12); /* 09100C00 00000000 00000000 00000000 */
++DEF_IE(111_IE_DOT11_CURRENT_REG_DOMAIN, 0x100a, 1);
++DEF_IE(111_IE_DOT11_CURRENT_ANTENNA, 0x100b, 2);
++DEF_IE(111_IE_DOT11_INVAL_100C, 0x100c, -1);
++DEF_IE(111_IE_DOT11_TX_POWER_LEVEL, 0x100d, 1);
++/* said to have len=1 but gives INVAL on read: */
++DEF_IE(111_IE_DOT11_CURRENT_CCA_MODE, 0x100e, -1);
++/* said to have len=4 but gives INVAL on read: */
++DEF_IE(111_IE_DOT11_ED_THRESHOLD, 0x100f, -1);
++/* set default key ID. write only: */
++DEF_IE(111_IE_DOT11_WEP_DEFAULT_KEY_SET, 0x1010, 1);
++/* undoc but returns something: */
++DEF_IE(111_IE_DOT11_UNKNOWN_1011, 0x1011, 1); /* 11100100 20 */
++DEF_IE(111_IE_DOT11_INVAL_1012, 0x1012, -1);
++DEF_IE(111_IE_DOT11_INVAL_1013, 0x1013, -1);
++#endif
++
++
++/*============================================================================*
++ * Information Frames Structures *
++ *============================================================================*/
++
++/* Used in beacon frames and the like */
++#define DOT11RATEBYTE_1 (1*2)
++#define DOT11RATEBYTE_2 (2*2)
++#define DOT11RATEBYTE_5_5 (5*2+1)
++#define DOT11RATEBYTE_11 (11*2)
++#define DOT11RATEBYTE_22 (22*2)
++#define DOT11RATEBYTE_6_G (6*2)
++#define DOT11RATEBYTE_9_G (9*2)
++#define DOT11RATEBYTE_12_G (12*2)
++#define DOT11RATEBYTE_18_G (18*2)
++#define DOT11RATEBYTE_24_G (24*2)
++#define DOT11RATEBYTE_36_G (36*2)
++#define DOT11RATEBYTE_48_G (48*2)
++#define DOT11RATEBYTE_54_G (54*2)
++#define DOT11RATEBYTE_BASIC 0x80 /* flags rates included in basic rate set */
++
++
++/***********************************************************************
++** rxbuffer_t
++**
++** This is the format of rx data returned by acx
++*/
++
++/* I've hoped it's a 802.11 PHY header, but no...
++ * so far, I've seen on acx111:
++ * 0000 3a00 0000 0000 IBBS Beacons
++ * 0000 3c00 0000 0000 ESS Beacons
++ * 0000 2700 0000 0000 Probe requests
++ * --vda
++ */
++typedef struct phy_hdr {
++ u8 unknown[4] ACX_PACKED;
++ u8 acx111_unknown[4] ACX_PACKED;
++} phy_hdr_t;
++
++/* seems to be a bit similar to hfa384x_rx_frame.
++ * These fields are still not quite obvious, though.
++ * Some seem to have different meanings... */
++
++#define RXBUF_HDRSIZE 12
++#define PHY_HDR(rxbuf) ((phy_hdr_t*)&rxbuf->hdr_a3)
++#define RXBUF_BYTES_RCVD(rxbuf) (le16_to_cpu(rxbuf->mac_cnt_rcvd) & 0xfff)
++#define RXBUF_BYTES_USED(rxbuf) \
++ ((le16_to_cpu(rxbuf->mac_cnt_rcvd) & 0xfff) + RXBUF_HDRSIZE)
++/*
++mac_cnt_rcvd:
++ 12 bits: length of frame from control field to last byte of FCS
++ 4 bits: reserved
++
++mac_cnt_mblks:
++ 6 bits: number of memory block used to store frame in adapter memory
++ 1 bit: Traffic Indicator bit in TIM of received Beacon was set
++
++mac_status: 1 byte (bitmap):
++ 7 Matching BSSID
++ 6 Matching SSID
++ 5 BDCST Address 1 field is a broadcast
++ 4 VBM received beacon frame has more than one set bit (?!)
++ 3 TIM Set bit representing this station is set in TIM of received beacon
++ 2 GROUP Address 1 is a multicast
++ 1 ADDR1 Address 1 matches our MAC
++ 0 FCSGD FSC is good
++
++phy_stat_baseband: 1 byte (bitmap):
++ 7 Preamble frame had a long preamble
++ 6 PLCP Error CRC16 error in PLCP header
++ 5 Unsup_Mod unsupported modulation
++ 4 Selected Antenna antenna 1 was used to receive this frame
++ 3 PBCC/CCK frame used: 1=PBCC, 0=CCK modulation
++ 2 OFDM frame used OFDM modulation
++ 1 TI Protection protection frame was detected
++ 0 Reserved
++
++phy_plcp_signal: 1 byte:
++ Receive PLCP Signal field from the Baseband Processor
++
++phy_level: 1 byte:
++ receive AGC gain level (can be used to measure receive signal strength)
++
++phy_snr: 1 byte:
++ estimated noise power of equalized receive signal
++ at input of FEC decoder (can be used to measure receive signal quality)
++
++time: 4 bytes:
++ timestamp sampled from either the Access Manager TSF counter
++ or free-running microsecond counter when the MAC receives
++ first byte of PLCP header.
++*/
++
++typedef struct rxbuffer {
++ u16 mac_cnt_rcvd ACX_PACKED; /* only 12 bits are len! (0xfff) */
++ u8 mac_cnt_mblks ACX_PACKED;
++ u8 mac_status ACX_PACKED;
++ u8 phy_stat_baseband ACX_PACKED; /* bit 0x80: used LNA (Low-Noise Amplifier) */
++ u8 phy_plcp_signal ACX_PACKED;
++ u8 phy_level ACX_PACKED; /* PHY stat */
++ u8 phy_snr ACX_PACKED; /* PHY stat */
++ u32 time ACX_PACKED; /* timestamp upon MAC rcv first byte */
++/* 4-byte (acx100) or 8-byte (acx111) phy header will be here
++** if RX_CFG1_INCLUDE_PHY_HDR is in effect:
++** phy_hdr_t phy */
++ wlan_hdr_a3_t hdr_a3 ACX_PACKED;
++ /* maximally sized data part of wlan packet */
++ u8 data_a3[WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN] ACX_PACKED;
++ /* can add hdr/data_a4 if needed */
++} rxbuffer_t;
++
++
++/*--- Firmware statistics ----------------------------------------------------*/
++typedef struct fw_stats {
++ u32 val0x0 ACX_PACKED; /* hdr; */
++ u32 tx_desc_of ACX_PACKED;
++ u32 rx_oom ACX_PACKED;
++ u32 rx_hdr_of ACX_PACKED;
++ u32 rx_hdr_use_next ACX_PACKED;
++ u32 rx_dropped_frame ACX_PACKED;
++ u32 rx_frame_ptr_err ACX_PACKED;
++ u32 rx_xfr_hint_trig ACX_PACKED;
++
++ u32 rx_dma_req ACX_PACKED;
++ u32 rx_dma_err ACX_PACKED;
++ u32 tx_dma_req ACX_PACKED;
++ u32 tx_dma_err ACX_PACKED;
++
++ u32 cmd_cplt ACX_PACKED;
++ u32 fiq ACX_PACKED;
++ u32 rx_hdrs ACX_PACKED;
++ u32 rx_cmplt ACX_PACKED;
++ u32 rx_mem_of ACX_PACKED;
++ u32 rx_rdys ACX_PACKED;
++ u32 irqs ACX_PACKED;
++ u32 acx_trans_procs ACX_PACKED;
++ u32 decrypt_done ACX_PACKED;
++ u32 dma_0_done ACX_PACKED;
++ u32 dma_1_done ACX_PACKED;
++ u32 tx_exch_complet ACX_PACKED;
++ u32 commands ACX_PACKED;
++ u32 acx_rx_procs ACX_PACKED;
++ u32 hw_pm_mode_changes ACX_PACKED;
++ u32 host_acks ACX_PACKED;
++ u32 pci_pm ACX_PACKED;
++ u32 acm_wakeups ACX_PACKED;
++
++ u32 wep_key_count ACX_PACKED;
++ u32 wep_default_key_count ACX_PACKED;
++ u32 dot11_def_key_mib ACX_PACKED;
++ u32 wep_key_not_found ACX_PACKED;
++ u32 wep_decrypt_fail ACX_PACKED;
++} fw_stats_t;
++
++/* Firmware version struct */
++
++typedef struct fw_ver {
++ u16 cmd ACX_PACKED;
++ u16 size ACX_PACKED;
++ char fw_id[20] ACX_PACKED;
++ u32 hw_id ACX_PACKED;
++} fw_ver_t;
++
++#define FW_ID_SIZE 20
++
++
++/*--- WEP stuff --------------------------------------------------------------*/
++#define DOT11_MAX_DEFAULT_WEP_KEYS 4
++
++/* non-firmware struct, no packing necessary */
++typedef struct wep_key {
++ size_t size; /* most often used member first */
++ u8 index;
++ u8 key[29];
++ u16 strange_filler;
++} wep_key_t; /* size = 264 bytes (33*8) */
++/* FIXME: We don't have size 264! Or is there 2 bytes beyond the key
++ * (strange_filler)? */
++
++/* non-firmware struct, no packing necessary */
++typedef struct key_struct {
++ u8 addr[ETH_ALEN]; /* 0x00 */
++ u16 filler1; /* 0x06 */
++ u32 filler2; /* 0x08 */
++ u32 index; /* 0x0c */
++ u16 len; /* 0x10 */
++ u8 key[29]; /* 0x12; is this long enough??? */
++} key_struct_t; /* size = 276. FIXME: where is the remaining space?? */
++
++
++/*--- Client (peer) info -----------------------------------------------------*/
++/* priv->sta_list[] is used for:
++** accumulating and processing of scan results
++** keeping client info in AP mode
++** keeping AP info in STA mode (AP is the only one 'client')
++** keeping peer info in ad-hoc mode
++** non-firmware struct --> no packing necessary */
++enum {
++ CLIENT_EMPTY_SLOT_0 = 0,
++ CLIENT_EXIST_1 = 1,
++ CLIENT_AUTHENTICATED_2 = 2,
++ CLIENT_ASSOCIATED_3 = 3,
++ CLIENT_JOIN_CANDIDATE = 4
++};
++struct client {
++ struct client* next;
++ unsigned long mtime; /* last time we heard it, in jiffies */
++ size_t essid_len; /* length of ESSID (without '\0') */
++ u32 sir; /* Standard IR */
++ u32 snr; /* Signal to Noise Ratio */
++ u16 aid; /* association ID */
++ u16 seq; /* from client's auth req */
++ u16 auth_alg; /* from client's auth req */
++ u16 cap_info; /* from client's assoc req */
++ u16 rate_cap; /* what client supports (all rates) */
++ u16 rate_bas; /* what client supports (basic rates) */
++ u16 rate_cfg; /* what is allowed (by iwconfig etc) */
++ u16 rate_cur; /* currently used rate mask */
++ u8 rate_100; /* currently used rate byte (acx100 only) */
++ u8 used; /* misnamed, more like 'status' */
++ u8 address[ETH_ALEN];
++ u8 bssid[ETH_ALEN]; /* ad-hoc hosts can have bssid != mac */
++ u8 channel;
++ u8 auth_step;
++ u8 ignore_count;
++ u8 fallback_count;
++ u8 stepup_count;
++ char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID and trailing '\0' */
++/* FIXME: this one is too damn big */
++ char challenge_text[WLAN_CHALLENGE_LEN];
++};
++
++
++/*============================================================================*
++ * Hardware structures *
++ *============================================================================*/
++
++/* An opaque typesafe helper type
++ *
++ * Some hardware fields are actually pointers,
++ * but they have to remain u32, since using ptr instead
++ * (8 bytes on 64bit systems!) would disrupt the fixed descriptor
++ * format the acx firmware expects in the non-user area.
++ * Since we cannot cram an 8 byte ptr into 4 bytes, we need to
++ * enforce that pointed to data remains in low memory
++ * (address value needs to fit in 4 bytes) on 64bit systems.
++ *
++ * This is easy to get wrong, thus we are using a small struct
++ * and special macros to access it. Macros will check for
++ * attempts to overflow an acx_ptr with value > 0xffffffff.
++ *
++ * Attempts to use acx_ptr without macros result in compile-time errors */
++
++typedef struct {
++ u32 v ACX_PACKED;
++} acx_ptr;
++
++#if ACX_DEBUG
++#define CHECK32(n) BUG_ON(sizeof(n)>4 && (long)(n)>0xffffff00)
++#else
++#define CHECK32(n) ((void)0)
++#endif
++
++/* acx_ptr <-> integer conversion */
++#define cpu2acx(n) ({ CHECK32(n); ((acx_ptr){ .v = cpu_to_le32(n) }); })
++#define acx2cpu(a) (le32_to_cpu(a.v))
++
++/* acx_ptr <-> pointer conversion */
++#define ptr2acx(p) ({ CHECK32(p); ((acx_ptr){ .v = cpu_to_le32((u32)(long)(p)) }); })
++#define acx2ptr(a) ((void*)le32_to_cpu(a.v))
++
++/* Values for rate field (acx100 only) */
++#define RATE100_1 10
++#define RATE100_2 20
++#define RATE100_5 55
++#define RATE100_11 110
++#define RATE100_22 220
++/* This bit denotes use of PBCC:
++** (PBCC encoding is usable with 11 and 22 Mbps speeds only) */
++#define RATE100_PBCC511 0x80
++
++/* Bit values for rate111 field */
++#define RATE111_1 0x0001 /* DBPSK */
++#define RATE111_2 0x0002 /* DQPSK */
++#define RATE111_5 0x0004 /* CCK or PBCC */
++#define RATE111_6 0x0008 /* CCK-OFDM or OFDM */
++#define RATE111_9 0x0010 /* CCK-OFDM or OFDM */
++#define RATE111_11 0x0020 /* CCK or PBCC */
++#define RATE111_12 0x0040 /* CCK-OFDM or OFDM */
++#define RATE111_18 0x0080 /* CCK-OFDM or OFDM */
++#define RATE111_22 0x0100 /* PBCC */
++#define RATE111_24 0x0200 /* CCK-OFDM or OFDM */
++#define RATE111_36 0x0400 /* CCK-OFDM or OFDM */
++#define RATE111_48 0x0800 /* CCK-OFDM or OFDM */
++#define RATE111_54 0x1000 /* CCK-OFDM or OFDM */
++#define RATE111_RESERVED 0x2000
++#define RATE111_PBCC511 0x4000 /* PBCC mod at 5.5 or 11Mbit (else CCK) */
++#define RATE111_SHORTPRE 0x8000 /* short preamble */
++/* Special 'try everything' value */
++#define RATE111_ALL 0x1fff
++/* These bits denote acx100 compatible settings */
++#define RATE111_ACX100_COMPAT 0x0127
++/* These bits denote 802.11b compatible settings */
++#define RATE111_80211B_COMPAT 0x0027
++
++/* Descriptor Ctl field bits
++ * init value is 0x8e, "idle" value is 0x82 (in idle tx descs)
++ */
++#define DESC_CTL_SHORT_PREAMBLE 0x01 /* preamble type: 0 = long; 1 = short */
++#define DESC_CTL_FIRSTFRAG 0x02 /* this is the 1st frag of the frame */
++#define DESC_CTL_AUTODMA 0x04
++#define DESC_CTL_RECLAIM 0x08 /* ready to reuse */
++#define DESC_CTL_HOSTDONE 0x20 /* host has finished processing */
++#define DESC_CTL_ACXDONE 0x40 /* acx has finished processing */
++/* host owns the desc [has to be released last, AFTER modifying all other desc fields!] */
++#define DESC_CTL_HOSTOWN 0x80
++
++#define DESC_CTL_INIT (DESC_CTL_HOSTOWN | DESC_CTL_RECLAIM | \
++ DESC_CTL_AUTODMA | DESC_CTL_FIRSTFRAG)
++#define DESC_CTL_DONE (DESC_CTL_ACXDONE | DESC_CTL_HOSTOWN)
++
++#define DESC_CTL_HOSTOWN_STR "80"
++#define DESC_CTL_DONE_STR "C0"
++/* Descriptor Status field
++ */
++#define DESC_STATUS_FULL (1 << 31)
++
++/* NB: some bits may be interesting for Monitor mode tx (aka Raw tx): */
++#define DESC_CTL2_SEQ 0x01 /* don't increase sequence field */
++#define DESC_CTL2_FCS 0x02 /* don't add the FCS */
++#define DESC_CTL2_MORE_FRAG 0x04
++#define DESC_CTL2_RETRY 0x08 /* don't increase retry field */
++#define DESC_CTL2_POWER 0x10 /* don't increase power mgmt. field */
++#define DESC_CTL2_RTS 0x20 /* do RTS/CTS magic before sending */
++#define DESC_CTL2_WEP 0x40 /* encrypt this frame */
++#define DESC_CTL2_DUR 0x80 /* don't increase duration field */
++
++/***************************************************************
++** PCI structures
++*/
++/* IRQ Constants
++** (outside of "#ifdef PCI" because USB (mis)uses HOST_INT_SCAN_COMPLETE) */
++#define HOST_INT_RX_DATA 0x0001
++#define HOST_INT_TX_COMPLETE 0x0002
++#define HOST_INT_TX_XFER 0x0004
++#define HOST_INT_RX_COMPLETE 0x0008
++#define HOST_INT_DTIM 0x0010
++#define HOST_INT_BEACON 0x0020
++#define HOST_INT_TIMER 0x0040
++#define HOST_INT_KEY_NOT_FOUND 0x0080
++#define HOST_INT_IV_ICV_FAILURE 0x0100
++#define HOST_INT_CMD_COMPLETE 0x0200
++#define HOST_INT_INFO 0x0400
++#define HOST_INT_OVERFLOW 0x0800
++#define HOST_INT_PROCESS_ERROR 0x1000
++#define HOST_INT_SCAN_COMPLETE 0x2000
++#define HOST_INT_FCS_THRESHOLD 0x4000
++#define HOST_INT_UNKNOWN 0x8000
++
++/* Outside of "#ifdef PCI" because USB needs to know sizeof()
++** of txdesc and rxdesc: */
++struct txdesc {
++ acx_ptr pNextDesc ACX_PACKED; /* pointer to next txdesc */
++ acx_ptr HostMemPtr ACX_PACKED; /* 0x04 */
++ acx_ptr AcxMemPtr ACX_PACKED; /* 0x08 */
++ u32 tx_time ACX_PACKED; /* 0x0c */
++ u16 total_length ACX_PACKED; /* 0x10 */
++ u16 Reserved ACX_PACKED; /* 0x12 */
++
++/* The following 16 bytes do not change when acx100 owns the descriptor */
++/* BUG: fw clears last byte of this area which is supposedly reserved
++** for driver use. amd64 blew up. We dare not use it now */
++ u32 dummy[4] ACX_PACKED;
++
++ u8 Ctl_8 ACX_PACKED; /* 0x24, 8bit value */
++ u8 Ctl2_8 ACX_PACKED; /* 0x25, 8bit value */
++ u8 error ACX_PACKED; /* 0x26 */
++ u8 ack_failures ACX_PACKED; /* 0x27 */
++ u8 rts_failures ACX_PACKED; /* 0x28 */
++ u8 rts_ok ACX_PACKED; /* 0x29 */
++ union {
++ struct {
++ u8 rate ACX_PACKED; /* 0x2a */
++ u8 queue_ctrl ACX_PACKED; /* 0x2b */
++ } r1 ACX_PACKED;
++ struct {
++ u16 rate111 ACX_PACKED; /* 0x2a */
++ } r2 ACX_PACKED;
++ } u ACX_PACKED;
++ u32 queue_info ACX_PACKED; /* 0x2c (acx100, reserved on acx111) */
++}; /* size : 48 = 0x30 */
++/* NB: acx111 txdesc structure is 4 byte larger */
++/* All these 4 extra bytes are reserved. tx alloc code takes them into account */
++
++struct rxdesc {
++ acx_ptr pNextDesc ACX_PACKED; /* 0x00 */
++ acx_ptr HostMemPtr ACX_PACKED; /* 0x04 */
++ acx_ptr ACXMemPtr ACX_PACKED; /* 0x08 */
++ u32 rx_time ACX_PACKED; /* 0x0c */
++ u16 total_length ACX_PACKED; /* 0x10 */
++ u16 WEP_length ACX_PACKED; /* 0x12 */
++ u32 WEP_ofs ACX_PACKED; /* 0x14 */
++
++/* the following 16 bytes do not change when acx100 owns the descriptor */
++ u8 driverWorkspace[16] ACX_PACKED; /* 0x18 */
++
++ u8 Ctl_8 ACX_PACKED;
++ u8 rate ACX_PACKED;
++ u8 error ACX_PACKED;
++ u8 SNR ACX_PACKED; /* Signal-to-Noise Ratio */
++ u8 RxLevel ACX_PACKED;
++ u8 queue_ctrl ACX_PACKED;
++ u16 unknown ACX_PACKED;
++ u32 unknown2 ACX_PACKED;
++}; /* size 52 = 0x34 */
++
++#ifdef ACX_PCI
++
++/* Register I/O offsets */
++#define ACX100_EEPROM_ID_OFFSET 0x380
++
++/* please add further ACX hardware register definitions only when
++ it turns out you need them in the driver, and please try to use
++ firmware functionality instead, since using direct I/O access instead
++ of letting the firmware do it might confuse the firmware's state
++ machine */
++
++/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION
++** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */
++enum {
++ IO_ACX_SOFT_RESET = 0,
++
++ IO_ACX_HW_SLAVE_REG_ADDR,
++ IO_ACX_HW_SLAVE_REG_DATA,
++ IO_ACX_HW_SLAVE_REG_CTRL,
++
++ IO_ACX_SLV_MEM_ADDR,
++ IO_ACX_SLV_MEM_DATA,
++ IO_ACX_SLV_MEM_CTL,
++ IO_ACX_SLV_END_CTL,
++ IO_ACX_CHIPID,
++
++ IO_ACX_FEMR, /* Function Event Mask */
++
++ IO_ACX_INT_TRIG,
++ IO_ACX_IRQ_MASK,
++ IO_ACX_IRQ_STATUS_NON_DES,
++ IO_ACX_IRQ_STATUS_CLEAR, /* CLEAR = clear on read */
++ IO_ACX_IRQ_ACK,
++ IO_ACX_HINT_TRIG,
++
++ IO_ACX_ENABLE,
++
++ IO_ACX_EEPROM_CTL,
++ IO_ACX_EEPROM_ADDR,
++ IO_ACX_EEPROM_DATA,
++ IO_ACX_EEPROM_CFG,
++
++ IO_ACX_PHY_ADDR,
++ IO_ACX_PHY_DATA,
++ IO_ACX_PHY_CTL,
++
++ IO_ACX_GPIO_OE,
++
++ IO_ACX_GPIO_IN,
++ IO_ACX_GPIO_OUT,
++ IO_ACX_GPIO_PD,
++ IO_ACX_GPIO_CFG,
++
++ IO_ACX_CMD_MAILBOX_OFFS,
++ IO_ACX_INFO_MAILBOX_OFFS,
++ IO_ACX_EEPROM_INFORMATION,
++
++ IO_ACX_EE_START,
++ IO_ACX_SOR_CFG,
++ IO_ACX_ECPU_CTRL,
++
++ IO_ACX_HI_CTRL,
++ IO_ACX_LPWR_MGR,
++
++ IO_ACX_PCI_ARB_CFG,
++};
++/* ***** ABSOLUTELY ALWAYS KEEP OFFSETS IN SYNC WITH THE INITIALIZATION
++** OF THE I/O ARRAYS!!!! (grep for '^IO_ACX') ***** */
++
++/* Values for IO_ACX_INT_TRIG register: */
++/* inform hw that rxdesc in queue needs processing */
++#define INT_TRIG_RXPRC 0x08
++/* inform hw that txdesc in queue needs processing */
++#define INT_TRIG_TXPRC 0x04
++/* ack that we received info from info mailbox */
++#define INT_TRIG_INFOACK 0x02
++/* inform hw that we have filled command mailbox */
++#define INT_TRIG_CMD 0x01
++
++struct txhostdesc {
++ acx_ptr data_phy ACX_PACKED; /* 0x00 [u8 *] */
++ u16 data_offset ACX_PACKED; /* 0x04 */
++ u16 reserved ACX_PACKED; /* 0x06 */
++ u16 Ctl_16 ACX_PACKED; /* 16bit value, endianness!! */
++ u16 length ACX_PACKED; /* 0x0a */
++ acx_ptr desc_phy_next ACX_PACKED; /* 0x0c [txhostdesc *] */
++ acx_ptr pNext ACX_PACKED; /* 0x10 [txhostdesc *] */
++ u32 Status ACX_PACKED; /* 0x14, unused on Tx */
++/* From here on you can use this area as you want (variable length, too!) */
++ u8 *data ACX_PACKED;
++};
++
++struct rxhostdesc {
++ acx_ptr data_phy ACX_PACKED; /* 0x00 [rxbuffer_t *] */
++ u16 data_offset ACX_PACKED; /* 0x04 */
++ u16 reserved ACX_PACKED; /* 0x06 */
++ u16 Ctl_16 ACX_PACKED; /* 0x08; 16bit value, endianness!! */
++ u16 length ACX_PACKED; /* 0x0a */
++ acx_ptr desc_phy_next ACX_PACKED; /* 0x0c [rxhostdesc_t *] */
++ acx_ptr pNext ACX_PACKED; /* 0x10 [rxhostdesc_t *] */
++ u32 Status ACX_PACKED; /* 0x14 */
++/* From here on you can use this area as you want (variable length, too!) */
++ rxbuffer_t *data ACX_PACKED;
++};
++
++#endif /* ACX_PCI */
++
++/***************************************************************
++** USB structures and constants
++*/
++#ifdef ACX_USB
++
++/* Buffer size for fw upload */
++#define ACX100_USB_RWMEM_MAXLEN 2048
++
++/* Should be sent to the ctrlout endpoint */
++#define ACX100_USB_ENBULKIN 6
++
++/* The number of bulk URBs to use */
++#define ACX100_USB_NUM_BULK_URBS 8
++
++/* Should be sent to the bulkout endpoint */
++#define ACX_USB_REQ_UPLOAD_FW 0x10
++#define ACX_USB_REQ_ACK_CS 0x11
++#define ACX_USB_REQ_CMD 0x12
++
++/* Used for usb_txbuffer.desc field */
++#define USB_TXBUF_TXDESC 0xA
++/* Used for usb_txbuffer.hostData field */
++#define USB_TXBUF_HD_ISDATA 0x10000
++#define USB_TXBUF_HD_DIRECTED 0x20000
++#define USB_TXBUF_HD_BROADCAST 0x40000
++/* Size of header (everything up to data[]) */
++#define USB_TXBUF_HDRSIZE 14
++typedef struct usb_txbuffer {
++ u16 desc ACX_PACKED;
++ u16 MPDUlen ACX_PACKED;
++ u8 index ACX_PACKED;
++ u8 txRate ACX_PACKED;
++ u32 hostData ACX_PACKED;
++ u8 ctrl1 ACX_PACKED;
++ u8 ctrl2 ACX_PACKED;
++ u16 dataLength ACX_PACKED;
++ /* wlan packet content is placed here: */
++ u8 data[WLAN_A4FR_MAXLEN_WEP_FCS] ACX_PACKED;
++} usb_txbuffer_t;
++
++typedef struct {
++ void *device;
++ int number;
++} acx_usb_bulk_context_t;
++
++typedef struct usb_tx {
++ unsigned busy:1;
++ struct urb *urb;
++ wlandevice_t *priv;
++ client_t *txc;
++ /* actual USB bulk output data block is here: */
++ usb_txbuffer_t bulkout;
++} usb_tx_t;
++
++#endif /* ACX_USB */
++
++
++/*============================================================================*
++ * Main acx per-device data structure (netdev_priv(dev)) *
++ *============================================================================*/
++#define ACX_STATE_FW_LOADED 0x01
++#define ACX_STATE_IFACE_UP 0x02
++
++/* MAC mode (BSS type) defines
++ * Note that they shouldn't be redefined, since they are also used
++ * during communication with firmware */
++#define ACX_MODE_0_ADHOC 0
++#define ACX_MODE_1_UNUSED 1
++#define ACX_MODE_2_STA 2
++#define ACX_MODE_3_AP 3
++/* These are our own inventions. Sending these to firmware
++** makes it stop emitting beacons, which is exactly what we want
++** for these modes */
++#define ACX_MODE_MONITOR 0xfe
++#define ACX_MODE_OFF 0xff
++/* 'Submode': identifies exact status of ADHOC/STA host */
++#define ACX_STATUS_0_STOPPED 0
++#define ACX_STATUS_1_SCANNING 1
++#define ACX_STATUS_2_WAIT_AUTH 2
++#define ACX_STATUS_3_AUTHENTICATED 3
++#define ACX_STATUS_4_ASSOCIATED 4
++
++/* FIXME: this should be named something like struct acx_priv (typedef'd to
++ * acx_priv_t) */
++
++/* non-firmware struct, no packing necessary */
++struct wlandevice {
++ /*** Device chain ***/
++ struct wlandevice *next; /* link for list of devices */
++
++ /*** Linux network device ***/
++ struct net_device *netdev; /* pointer to linux netdevice */
++ struct net_device *prev_nd; /* FIXME: We should not chain via our
++ * private struct wlandevice _and_
++ * the struct net_device. */
++ /*** Device statistics ***/
++ struct net_device_stats stats; /* net device statistics */
++#ifdef WIRELESS_EXT
++ struct iw_statistics wstats; /* wireless statistics */
++#endif
++ /*** Power managment ***/
++ struct pm_dev *pm; /* PM crap */
++
++ /*** Management timer ***/
++ struct timer_list mgmt_timer;
++
++ /*** Locking ***/
++ struct semaphore sem;
++ spinlock_t lock;
++#if defined(PARANOID_LOCKING) /* Lock debugging */
++ const char *last_sem;
++ const char *last_lock;
++ unsigned long sem_time;
++ unsigned long lock_time;
++#endif
++
++ /*** Hardware identification ***/
++ const char *chip_name;
++ u8 dev_type;
++ u8 chip_type;
++ u8 form_factor;
++ u8 radio_type;
++ u8 eeprom_version;
++
++ /*** Firmware identification ***/
++ char firmware_version[FW_ID_SIZE+1];
++ u32 firmware_numver;
++ u32 firmware_id;
++
++ /*** Device state ***/
++ u16 dev_state_mask;
++ u8 led_power; /* power LED status */
++ u32 get_mask; /* mask of settings to fetch from the card */
++ u32 set_mask; /* mask of settings to write to the card */
++
++ /* Barely used in USB case */
++ u16 irq_status;
++
++ u8 after_interrupt_jobs; /* mini job list for doing actions after an interrupt occurred */
++ WORK_STRUCT after_interrupt_task; /* our task for after interrupt actions */
++
++ /*** scanning ***/
++ u16 scan_count; /* number of times to do channel scan */
++ u8 scan_mode; /* 0 == active, 1 == passive, 2 == background */
++ u8 scan_rate;
++ u16 scan_duration;
++ u16 scan_probe_delay;
++#if WIRELESS_EXT > 15
++ struct iw_spy_data spy_data; /* FIXME: needs to be implemented! */
++#endif
++
++ /*** Wireless network settings ***/
++ /* copy of the device address (ifconfig hw ether) that we actually use
++ ** for 802.11; copied over from the network device's MAC address
++ ** (ifconfig) when it makes sense only */
++ u8 dev_addr[MAX_ADDR_LEN];
++ u8 bssid[ETH_ALEN]; /* the BSSID after having joined */
++ u8 ap[ETH_ALEN]; /* The AP we want, FF:FF:FF:FF:FF:FF is any */
++ u16 aid; /* The Association ID sent from the AP / last used AID if we're an AP */
++ u16 mode; /* mode from iwconfig */
++ u16 status; /* 802.11 association status */
++ u8 essid_active; /* specific ESSID active, or select any? */
++ u8 essid_len; /* to avoid dozens of strlen() */
++ /* INCLUDES \0 termination for easy printf - but many places
++ ** simply want the string data memcpy'd plus a length indicator!
++ ** Keep that in mind... */
++ char essid[IW_ESSID_MAX_SIZE+1];
++ /* essid we are going to use for association, in case of "essid 'any'"
++ ** and in case of hidden ESSID (use configured ESSID then) */
++ char essid_for_assoc[IW_ESSID_MAX_SIZE+1];
++ char nick[IW_ESSID_MAX_SIZE+1]; /* see essid! */
++ u8 channel;
++ u8 reg_dom_id; /* reg domain setting */
++ u16 reg_dom_chanmask;
++ u16 auth_or_assoc_retries;
++ u16 scan_retries;
++ unsigned long scan_start; /* YES, jiffies is defined as "unsigned long" */
++
++ /* stations known to us (if we're an ap) */
++ client_t sta_list[32]; /* tab is larger than list, so that */
++ client_t *sta_hash_tab[64]; /* hash collisions are not likely */
++ client_t *ap_client; /* this one is our AP (STA mode only) */
++
++ unsigned long dup_msg_expiry;
++ int dup_count;
++ int nondup_count;
++ u16 last_seq_ctrl; /* duplicate packet detection */
++
++ /* 802.11 power save mode */
++ u8 ps_wakeup_cfg;
++ u8 ps_listen_interval;
++ u8 ps_options;
++ u8 ps_hangover_period;
++ u16 ps_enhanced_transition_time;
++
++ /*** PHY settings ***/
++ u8 fallback_threshold;
++ u8 stepup_threshold;
++ u16 rate_basic;
++ u16 rate_oper;
++ u16 rate_bcast;
++ u16 rate_bcast100;
++ u8 rate_auto; /* false if "iwconfig rate N" (WITHOUT 'auto'!) */
++ u8 preamble_mode; /* 0 == Long Preamble, 1 == Short, 2 == Auto */
++ u8 preamble_cur;
++
++ u8 tx_disabled;
++ u8 tx_level_dbm;
++ /* u8 tx_level_val; */
++ /* u8 tx_level_auto; whether to do automatic power adjustment */
++
++ unsigned long recalib_time_last_success;
++ unsigned long recalib_time_last_attempt;
++ int recalib_failure_count;
++ int recalib_msg_ratelimit;
++ int retry_errors_msg_ratelimit;
++
++ unsigned long brange_time_last_state_change; /* time the power LED was last changed */
++ u8 brange_last_state; /* last state of the LED */
++ u8 brange_max_quality; /* maximum quality that equates to full speed */
++
++ u8 sensitivity;
++ u8 antenna; /* antenna settings */
++ u8 ed_threshold; /* energy detect threshold */
++ u8 cca; /* clear channel assessment */
++
++ u16 rts_threshold;
++ u32 short_retry;
++ u32 long_retry;
++ u16 msdu_lifetime;
++ u16 listen_interval; /* given in units of beacon interval */
++ u32 beacon_interval;
++
++ u16 capabilities;
++ u8 capab_short;
++ u8 capab_pbcc;
++ u8 capab_agility;
++ u8 rate_supported_len;
++ u8 rate_supported[13];
++
++ /*** Encryption settings (WEP) ***/
++ u32 auth_alg; /* used in transmit_authen1 */
++ u8 wep_enabled;
++ u8 wep_restricted;
++ u8 wep_current_index;
++ wep_key_t wep_keys[DOT11_MAX_DEFAULT_WEP_KEYS]; /* the default WEP keys */
++ key_struct_t wep_key_struct[10];
++
++ /*** Card Rx/Tx management ***/
++ u16 rx_config_1;
++ u16 rx_config_2;
++ u16 memblocksize;
++ u32 tx_free;
++
++ /*** Unknown ***/
++ u8 dtim_interval;
++
++/*** PCI/USB/... must be last or else hw agnostic code breaks horribly ***/
++ /* hack to let common code compile. FIXME */
++ dma_addr_t rxhostdesc_startphy;
++
++ /*** PCI stuff ***/
++#ifdef ACX_PCI
++ /* pointers to tx buffers, tx host descriptors (in host memory)
++ ** and tx descrs in device memory */
++ u8 *txbuf_start;
++ txhostdesc_t *txhostdesc_start;
++ txdesc_t *txdesc_start; /* points to PCI-mapped memory */
++ /* same for rx */
++ rxbuffer_t *rxbuf_start;
++ rxhostdesc_t *rxhostdesc_start;
++ rxdesc_t *rxdesc_start;
++ /* physical addresses of above host memory areas */
++ dma_addr_t rxbuf_startphy;
++ /* dma_addr_t rxhostdesc_startphy; */
++ dma_addr_t txbuf_startphy;
++ dma_addr_t txhostdesc_startphy;
++ /* sizes of above host memory areas */
++ unsigned int txbuf_area_size;
++ unsigned int txhostdesc_area_size;
++ unsigned int rxbuf_area_size;
++ unsigned int rxhostdesc_area_size;
++
++ unsigned int txdesc_size; /* size per tx descr; ACX111 = ACX100 + 4 */
++ unsigned int tx_head; /* current ring buffer pool member index */
++ unsigned int tx_tail;
++ unsigned int rx_tail;
++
++ client_t *txc[TX_CNT];
++
++ u8 need_radio_fw;
++ u8 irqs_active; /* whether irq sending is activated */
++
++ const u16 *io; /* points to ACX100 or ACX111 I/O register address set */
++
++#if defined(CONFIG_ACX_CFI)
++ struct device *dev;
++#else
++ struct pci_dev *pdev;
++#endif
++
++ unsigned long membase;
++ unsigned long membase2;
++ void *iobase;
++ void *iobase2;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
++ /* 2.6.9-rc3-mm2 (2.6.9-bk4, too) introduced a shorter API version,
++ then it made its way into 2.6.10 */
++ u32 pci_state[16]; /* saved PCI state for suspend/resume */
++#endif
++ u16 irq_mask; /* interrupt types to mask out (not wanted) with many IRQs activated */
++ u16 irq_mask_off; /* interrupt types to mask out (not wanted) with IRQs off */
++ unsigned int irq_loops_this_jiffy;
++ unsigned long irq_last_jiffies;
++
++ /* command interface */
++ void *cmd_area; /* points to PCI mapped memory */
++ void *info_area; /* points to PCI mapped memory */
++ u16 cmd_type;
++ u16 cmd_status;
++ u16 info_type;
++ u16 info_status;
++#endif
++
++ /*** USB stuff ***/
++#ifdef ACX_USB
++ struct usb_device *usbdev;
++
++ rxbuffer_t rxtruncbuf;
++ /* TODO: convert (bulkins,bulkrx_urbs,rxcons) triple into
++ ** struct usb_rx (see struct usb_tx for an example) */
++ rxbuffer_t bulkins[ACX100_USB_NUM_BULK_URBS];
++ struct urb *bulkrx_urbs[ACX100_USB_NUM_BULK_URBS];
++ /* Used by rx urb completion handler in order to find
++ ** corresponding priv/index pair */
++ acx_usb_bulk_context_t rxcons[ACX100_USB_NUM_BULK_URBS];
++ usb_tx_t usb_tx[ACX100_USB_NUM_BULK_URBS];
++
++ int bulkinep; /* bulk-in endpoint */
++ int bulkoutep; /* bulk-out endpoint */
++ int rxtruncsize;
++#endif
++
++};
++
++/* For use with ACX1xx_IE_RXCONFIG */
++/* bit description
++ * 13 include additional header (length etc.) *required*
++ * struct is defined in 'struct rxbuffer'
++ * is this bit acx100 only? does acx111 always put the header,
++ * and bit setting is irrelevant? --vda
++ * 10 receive frames only with SSID used in last join cmd
++ * 9 discard broadcast
++ * 8 receive packets for multicast address 1
++ * 7 receive packets for multicast address 0
++ * 6 discard all multicast packets
++ * 5 discard frames from foreign BSSID
++ * 4 discard frames with foreign destination MAC address
++ * 3 promiscuous mode (receive ALL frames, disable filter)
++ * 2 include FCS
++ * 1 include phy header
++ * 0 ???
++ */
++#define RX_CFG1_INCLUDE_RXBUF_HDR 0x2000 /* ACX100 only */
++#define RX_CFG1_FILTER_SSID 0x0400
++#define RX_CFG1_FILTER_BCAST 0x0200
++#define RX_CFG1_RCV_MC_ADDR1 0x0100
++#define RX_CFG1_RCV_MC_ADDR0 0x0080
++#define RX_CFG1_FILTER_ALL_MULTI 0x0040
++#define RX_CFG1_FILTER_BSSID 0x0020
++#define RX_CFG1_FILTER_MAC 0x0010
++#define RX_CFG1_RCV_PROMISCUOUS 0x0008
++#define RX_CFG1_INCLUDE_FCS 0x0004
++#define RX_CFG1_INCLUDE_PHY_HDR (WANT_PHY_HDR ? 0x0002 : 0)
++/* bit description
++ * 11 receive association requests etc.
++ * 10 receive authentication frames
++ * 9 receive beacon frames
++ * 8 receive contention free packets
++ * 7 receive control frames
++ * 6 receive data frames
++ * 5 receive broken frames
++ * 4 receive management frames
++ * 3 receive probe requests
++ * 2 receive probe responses
++ * 1 receive RTS/CTS/ACK frames
++ * 0 receive other
++ */
++#define RX_CFG2_RCV_ASSOC_REQ 0x0800
++#define RX_CFG2_RCV_AUTH_FRAMES 0x0400
++#define RX_CFG2_RCV_BEACON_FRAMES 0x0200
++#define RX_CFG2_RCV_CONTENTION_FREE 0x0100
++#define RX_CFG2_RCV_CTRL_FRAMES 0x0080
++#define RX_CFG2_RCV_DATA_FRAMES 0x0040
++#define RX_CFG2_RCV_BROKEN_FRAMES 0x0020
++#define RX_CFG2_RCV_MGMT_FRAMES 0x0010
++#define RX_CFG2_RCV_PROBE_REQ 0x0008
++#define RX_CFG2_RCV_PROBE_RESP 0x0004
++#define RX_CFG2_RCV_ACK_FRAMES 0x0002
++#define RX_CFG2_RCV_OTHER 0x0001
++
++/* For use with ACX1xx_IE_FEATURE_CONFIG */
++#define FEATURE1_80MHZ_CLOCK 0x00000040L
++#define FEATURE1_4X 0x00000020L
++#define FEATURE1_LOW_RX 0x00000008L
++#define FEATURE1_EXTRA_LOW_RX 0x00000001L
++
++#define FEATURE2_SNIFFER 0x00000080L
++#define FEATURE2_NO_TXCRYPT 0x00000001L
++
++/*-- get and set mask values --*/
++#define GETSET_LED_POWER 0x00000001L
++#define GETSET_STATION_ID 0x00000002L
++#define SET_TEMPLATES 0x00000004L
++#define SET_STA_LIST 0x00000008L
++#define GETSET_TX 0x00000010L
++#define GETSET_RX 0x00000020L
++#define SET_RXCONFIG 0x00000040L
++#define GETSET_ANTENNA 0x00000080L
++#define GETSET_SENSITIVITY 0x00000100L
++#define GETSET_TXPOWER 0x00000200L
++#define GETSET_ED_THRESH 0x00000400L
++#define GETSET_CCA 0x00000800L
++#define GETSET_POWER_80211 0x00001000L
++#define GETSET_RETRY 0x00002000L
++#define GETSET_REG_DOMAIN 0x00004000L
++#define GETSET_CHANNEL 0x00008000L
++/* Used when ESSID changes etc and we need to scan for AP anew */
++#define GETSET_RESCAN 0x00010000L
++#define GETSET_MODE 0x00020000L
++#define GETSET_WEP 0x00040000L
++#define SET_WEP_OPTIONS 0x00080000L
++#define SET_MSDU_LIFETIME 0x00100000L
++#define SET_RATE_FALLBACK 0x00200000L
++#define GETSET_ALL 0x80000000L
++
++
++/*============================================================================*
++ * Firmware loading *
++ *============================================================================*/
++/* Doh, 2.4.x also has CONFIG_FW_LOADER_MODULE
++ * (but doesn't have the new device model yet which we require!)
++ * FIXME: exact version that introduced new device handling? */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
++#define USE_FW_LOADER_26 1
++#define USE_FW_LOADER_LEGACY 0
++#else
++#define USE_FW_LOADER_26 0
++#define USE_FW_LOADER_LEGACY 1
++#endif
++#endif
++
++#if USE_FW_LOADER_26
++#include <linux/firmware.h> /* request_firmware() */
++#include <linux/pci.h> /* struct pci_device */
++#endif
++
++
++/***********************************************************************
++*/
++typedef struct acx100_ie_memblocksize {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u16 size ACX_PACKED;
++} acx100_ie_memblocksize_t;
++
++typedef struct acx100_ie_queueconfig {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u32 AreaSize ACX_PACKED;
++ u32 RxQueueStart ACX_PACKED;
++ u8 QueueOptions ACX_PACKED;
++ u8 NumTxQueues ACX_PACKED;
++ u8 NumRxDesc ACX_PACKED; /* for USB only */
++ u8 pad1 ACX_PACKED;
++ u32 QueueEnd ACX_PACKED;
++ u32 HostQueueEnd ACX_PACKED; /* QueueEnd2 */
++ u32 TxQueueStart ACX_PACKED;
++ u8 TxQueuePri ACX_PACKED;
++ u8 NumTxDesc ACX_PACKED;
++ u16 pad2 ACX_PACKED;
++} acx100_ie_queueconfig_t;
++
++typedef struct acx111_ie_queueconfig {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u32 tx_memory_block_address ACX_PACKED;
++ u32 rx_memory_block_address ACX_PACKED;
++ u32 rx1_queue_address ACX_PACKED;
++ u32 reserved1 ACX_PACKED;
++ u32 tx1_queue_address ACX_PACKED;
++ u8 tx1_attributes ACX_PACKED;
++ u16 reserved2 ACX_PACKED;
++ u8 reserved3 ACX_PACKED;
++} acx111_ie_queueconfig_t;
++
++typedef struct acx100_ie_memconfigoption {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u32 DMA_config ACX_PACKED;
++ acx_ptr pRxHostDesc ACX_PACKED;
++ u32 rx_mem ACX_PACKED;
++ u32 tx_mem ACX_PACKED;
++ u16 RxBlockNum ACX_PACKED;
++ u16 TxBlockNum ACX_PACKED;
++} acx100_ie_memconfigoption_t;
++
++typedef struct acx111_ie_memoryconfig {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u16 no_of_stations ACX_PACKED;
++ u16 memory_block_size ACX_PACKED;
++ u8 tx_rx_memory_block_allocation ACX_PACKED;
++ u8 count_rx_queues ACX_PACKED;
++ u8 count_tx_queues ACX_PACKED;
++ u8 options ACX_PACKED;
++ u8 fragmentation ACX_PACKED;
++ u16 reserved1 ACX_PACKED;
++ u8 reserved2 ACX_PACKED;
++
++ /* start of rx1 block */
++ u8 rx_queue1_count_descs ACX_PACKED;
++ u8 rx_queue1_reserved1 ACX_PACKED;
++ u8 rx_queue1_type ACX_PACKED; /* must be set to 7 */
++ u8 rx_queue1_prio ACX_PACKED; /* must be set to 0 */
++ acx_ptr rx_queue1_host_rx_start ACX_PACKED;
++ /* end of rx1 block */
++
++ /* start of tx1 block */
++ u8 tx_queue1_count_descs ACX_PACKED;
++ u8 tx_queue1_reserved1 ACX_PACKED;
++ u8 tx_queue1_reserved2 ACX_PACKED;
++ u8 tx_queue1_attributes ACX_PACKED;
++ /* end of tx1 block */
++} acx111_ie_memoryconfig_t;
++
++typedef struct acx_ie_memmap {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u32 CodeStart ACX_PACKED;
++ u32 CodeEnd ACX_PACKED;
++ u32 WEPCacheStart ACX_PACKED;
++ u32 WEPCacheEnd ACX_PACKED;
++ u32 PacketTemplateStart ACX_PACKED;
++ u32 PacketTemplateEnd ACX_PACKED;
++ u32 QueueStart ACX_PACKED;
++ u32 QueueEnd ACX_PACKED;
++ u32 PoolStart ACX_PACKED;
++ u32 PoolEnd ACX_PACKED;
++} acx_ie_memmap_t;
++
++typedef struct acx111_ie_feature_config {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u32 feature_options ACX_PACKED;
++ u32 data_flow_options ACX_PACKED;
++} acx111_ie_feature_config_t;
++
++typedef struct acx111_ie_tx_level {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u8 level ACX_PACKED;
++} acx111_ie_tx_level_t;
++
++#define PS_CFG_ENABLE 0x80
++#define PS_CFG_PENDING 0x40 /* status flag when entering PS */
++#define PS_CFG_WAKEUP_MODE_MASK 0x07
++#define PS_CFG_WAKEUP_BY_HOST 0x03
++#define PS_CFG_WAKEUP_EACH_ITVL 0x02
++#define PS_CFG_WAKEUP_ON_DTIM 0x01
++#define PS_CFG_WAKEUP_ALL_BEAC 0x00
++
++/* Enhanced PS mode: sleep until Rx Beacon w/ the STA's AID bit set
++** in the TIM; newer firmwares only(?) */
++#define PS_OPT_ENA_ENHANCED_PS 0x04
++#define PS_OPT_STILL_RCV_BCASTS 0x01
++
++typedef struct acx100_ie_powermgmt {
++ u32 type ACX_PACKED;
++ u32 len ACX_PACKED;
++ u8 wakeup_cfg ACX_PACKED;
++ u8 listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
++ u8 options ACX_PACKED;
++ u8 hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
++ u16 enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
++} acx100_ie_powermgmt_t;
++
++typedef struct acx111_ie_powermgmt {
++ u32 type ACX_PACKED;
++ u32 len ACX_PACKED;
++ u8 wakeup_cfg ACX_PACKED;
++ u8 listen_interval ACX_PACKED; /* for EACH_ITVL: wake up every "beacon units" interval */
++ u8 options ACX_PACKED;
++ u8 hangover_period ACX_PACKED; /* remaining wake time after Tx MPDU w/ PS bit, in values of 1/1024 seconds */
++ u32 beaconRxTime ACX_PACKED;
++ u32 enhanced_ps_transition_time ACX_PACKED; /* rem. wake time for Enh. PS */
++} acx111_ie_powermgmt_t;
++
++
++/***********************************************************************
++** Commands and template structures
++*/
++
++/*
++** SCAN command structure
++**
++** even though acx100 scan rates match RATE100 constants,
++** acx111 ones do not match! Therefore we do not use RATE100 #defines */
++#define ACX_SCAN_RATE_1 10
++#define ACX_SCAN_RATE_2 20
++#define ACX_SCAN_RATE_5 55
++#define ACX_SCAN_RATE_11 110
++#define ACX_SCAN_RATE_22 220
++#define ACX_SCAN_OPT_ACTIVE 0x00 /* a bit mask */
++#define ACX_SCAN_OPT_PASSIVE 0x01
++/* Background scan: we go into Power Save mode (by transmitting
++** NULL data frame to AP with the power mgmt bit set), do the scan,
++** and then exit Power Save mode. A plus is that AP buffers frames
++** for us while we do background scan. Thus we avoid frame losses.
++** Background scan can be active or passive, just like normal one */
++#define ACX_SCAN_OPT_BACKGROUND 0x02
++typedef struct acx100_scan {
++ u16 count ACX_PACKED; /* number of scans to do, 0xffff == continuous */
++ u16 start_chan ACX_PACKED;
++ u16 flags ACX_PACKED; /* channel list mask; 0x8000 == all channels? */
++ u8 max_rate ACX_PACKED; /* max. probe rate */
++ u8 options ACX_PACKED; /* bit mask, see defines above */
++ u16 chan_duration ACX_PACKED;
++ u16 max_probe_delay ACX_PACKED;
++} acx100_scan_t; /* length 0xc */
++
++#define ACX111_SCAN_RATE_6 0x0B
++#define ACX111_SCAN_RATE_9 0x0F
++#define ACX111_SCAN_RATE_12 0x0A
++#define ACX111_SCAN_RATE_18 0x0E
++#define ACX111_SCAN_RATE_24 0x09
++#define ACX111_SCAN_RATE_36 0x0D
++#define ACX111_SCAN_RATE_48 0x08
++#define ACX111_SCAN_RATE_54 0x0C
++#define ACX111_SCAN_OPT_5GHZ 0x04 /* else 2.4GHZ */
++#define ACX111_SCAN_MOD_SHORTPRE 0x01 /* you can combine SHORTPRE and PBCC */
++#define ACX111_SCAN_MOD_PBCC 0x80
++#define ACX111_SCAN_MOD_OFDM 0x40
++typedef struct acx111_scan {
++ u16 count ACX_PACKED; /* number of scans to do */
++ u8 channel_list_select ACX_PACKED; /* 0: scan all channels, 1: from chan_list only */
++ u16 reserved1 ACX_PACKED;
++ u8 reserved2 ACX_PACKED;
++ u8 rate ACX_PACKED; /* rate for probe requests (if active scan) */
++ u8 options ACX_PACKED; /* bit mask, see defines above */
++ u16 chan_duration ACX_PACKED; /* min time to wait for reply on one channel (in TU) */
++ /* (active scan only) (802.11 section 11.1.3.2.2) */
++ u16 max_probe_delay ACX_PACKED; /* max time to wait for reply on one channel (active scan) */
++ /* time to listen on a channel (passive scan) */
++ u8 modulation ACX_PACKED;
++ u8 channel_list[26] ACX_PACKED; /* bits 7:0 first byte: channels 8:1 */
++ /* bits 7:0 second byte: channels 16:9 */
++ /* 26 bytes is enough to cover 802.11a */
++} acx111_scan_t;
++
++
++/*
++** Radio calibration command structure
++*/
++typedef struct acx111_cmd_radiocalib {
++/* 0x80000000 == automatic calibration by firmware, according to interval;
++ * bits 0..3: select calibration methods to go through:
++ * calib based on DC, AfeDC, Tx mismatch, Tx equilization */
++ u32 methods ACX_PACKED;
++ u32 interval ACX_PACKED;
++} acx111_cmd_radiocalib_t;
++
++
++/*
++** Packet template structures
++**
++** Packet templates store contents of Beacon, Probe response, Probe request,
++** Null data frame, and TIM data frame. Firmware automatically transmits
++** contents of template at appropriate time:
++** - Beacon: when configured as AP or Ad-hoc
++** - Probe response: when configured as AP or Ad-hoc, whenever
++** a Probe request frame is received
++** - Probe request: when host issues SCAN command (active)
++** - Null data frame: when entering 802.11 power save mode
++** - TIM data: at the end of Beacon frames (if no TIM template
++** is configured, then transmits default TIM)
++** NB:
++** - size field must be set to size of actual template
++** (NOT sizeof(struct) - templates are variable in length),
++** size field is not itself counted.
++** - members flagged with an asterisk must be initialized with host,
++** rest must be zero filled.
++** - variable length fields shown only in comments */
++typedef struct acx_template_tim {
++ u16 size ACX_PACKED;
++ u8 tim_eid ACX_PACKED; /* 00 1 TIM IE ID * */
++ u8 len ACX_PACKED; /* 01 1 Length * */
++ u8 dtim_cnt ACX_PACKED; /* 02 1 DTIM Count */
++ u8 dtim_period ACX_PACKED; /* 03 1 DTIM Period */
++ u8 bitmap_ctrl ACX_PACKED; /* 04 1 Bitmap Control * (except bit0) */
++ /* 05 n Partial Virtual Bitmap * */
++ u8 variable[0x100 - 1-1-1-1-1] ACX_PACKED;
++} acx_template_tim_t;
++
++typedef struct acx100_template_probereq {
++ u16 size ACX_PACKED;
++ u16 fc ACX_PACKED; /* 00 2 fc */
++ u16 dur ACX_PACKED; /* 02 2 Duration */
++ u8 da[6] ACX_PACKED; /* 04 6 Destination Address * */
++ u8 sa[6] ACX_PACKED; /* 0A 6 Source Address * */
++ u8 bssid[6] ACX_PACKED; /* 10 6 BSSID * */
++ u16 seq ACX_PACKED; /* 16 2 Sequence Control */
++ u8 timestamp[8] ACX_PACKED;/* 18 8 Timestamp */
++ u16 beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */
++ u16 cap ACX_PACKED; /* 22 2 Capability Information * */
++ /* 24 n SSID * */
++ /* nn n Supported Rates * */
++ u8 variable[0x44 - 2-2-6-6-6-2-8-2-2] ACX_PACKED;
++} acx100_template_probereq_t;
++
++typedef struct acx111_template_probereq {
++ u16 size ACX_PACKED;
++ u16 fc ACX_PACKED; /* 00 2 fc * */
++ u16 dur ACX_PACKED; /* 02 2 Duration */
++ u8 da[6] ACX_PACKED; /* 04 6 Destination Address * */
++ u8 sa[6] ACX_PACKED; /* 0A 6 Source Address * */
++ u8 bssid[6] ACX_PACKED; /* 10 6 BSSID * */
++ u16 seq ACX_PACKED; /* 16 2 Sequence Control */
++ /* 18 n SSID * */
++ /* nn n Supported Rates * */
++ u8 variable[0x44 - 2-2-6-6-6-2] ACX_PACKED;
++} acx111_template_probereq_t;
++
++typedef struct acx_template_proberesp {
++ u16 size ACX_PACKED;
++ u16 fc ACX_PACKED; /* 00 2 fc * (bits [15:12] and [10:8] per 802.11 section 7.1.3.1) */
++ u16 dur ACX_PACKED; /* 02 2 Duration */
++ u8 da[6] ACX_PACKED; /* 04 6 Destination Address */
++ u8 sa[6] ACX_PACKED; /* 0A 6 Source Address */
++ u8 bssid[6] ACX_PACKED; /* 10 6 BSSID */
++ u16 seq ACX_PACKED; /* 16 2 Sequence Control */
++ u8 timestamp[8] ACX_PACKED;/* 18 8 Timestamp */
++ u16 beacon_interval ACX_PACKED; /* 20 2 Beacon Interval * */
++ u16 cap ACX_PACKED; /* 22 2 Capability Information * */
++ /* 24 n SSID * */
++ /* nn n Supported Rates * */
++ /* nn 1 DS Parameter Set * */
++ u8 variable[0x54 - 2-2-6-6-6-2-8-2-2] ACX_PACKED;
++} acx_template_proberesp_t;
++#define acx_template_beacon_t acx_template_proberesp_t
++#define acx_template_beacon acx_template_proberesp
++
++typedef struct acx_template_nullframe {
++ u16 size ACX_PACKED;
++ struct wlan_hdr_a3 hdr ACX_PACKED;
++} acx_template_nullframe_t;
++
++
++/*
++** JOIN command structure
++**
++** as opposed to acx100, acx111 dtim interval is AFTER rates_basic111.
++** NOTE: took me about an hour to get !@#$%^& packing right --> struct packing is eeeeevil... */
++typedef struct acx_joinbss {
++ u8 bssid[ETH_ALEN] ACX_PACKED;
++ u16 beacon_interval ACX_PACKED;
++ union {
++ struct {
++ u8 dtim_interval ACX_PACKED;
++ u8 rates_basic ACX_PACKED;
++ u8 rates_supported ACX_PACKED;
++ } acx100 ACX_PACKED;
++ struct {
++ u16 rates_basic ACX_PACKED;
++ u8 dtim_interval ACX_PACKED;
++ } acx111 ACX_PACKED;
++ } u ACX_PACKED;
++ u8 genfrm_txrate ACX_PACKED; /* generated frame (bcn, proberesp, RTS, PSpoll) tx rate */
++ u8 genfrm_mod_pre ACX_PACKED; /* generated frame modulation/preamble:
++ ** bit7: PBCC, bit6: OFDM (else CCK/DQPSK/DBPSK)
++ ** bit5: short pre */
++ u8 macmode ACX_PACKED; /* BSS Type, must be one of ACX_MODE_xxx */
++ u8 channel ACX_PACKED;
++ u8 essid_len ACX_PACKED;
++ char essid[IW_ESSID_MAX_SIZE] ACX_PACKED;
++} acx_joinbss_t;
++
++#define JOINBSS_RATES_1 0x01
++#define JOINBSS_RATES_2 0x02
++#define JOINBSS_RATES_5 0x04
++#define JOINBSS_RATES_11 0x08
++#define JOINBSS_RATES_22 0x10
++
++/* Looks like missing bits are used to indicate 11g rates!
++** (it follows from the fact that constants below match 1:1 to RATE111_nn)
++** This was actually seen! Look at that Assoc Request sent by acx111,
++** it _does_ contain 11g rates in basic set:
++01:30:20.070772 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1
++01:30:20.074425 Authentication (Open System)-1: Succesful
++01:30:20.076539 Authentication (Open System)-2:
++01:30:20.076620 Acknowledgment
++01:30:20.088546 Assoc Request (xxx) [1.0* 2.0* 5.5* 6.0* 9.0* 11.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit]
++01:30:20.122413 Assoc Response AID(1) :: Succesful
++01:30:20.122679 Acknowledgment
++01:30:20.173204 Beacon (xxx) [1.0* 2.0* 5.5* 11.0* 6.0* 9.0* 12.0* 18.0* 24.0* 36.0* 48.0* 54.0* Mbit] ESS CH: 1
++*/
++#define JOINBSS_RATES_BASIC111_1 0x0001
++#define JOINBSS_RATES_BASIC111_2 0x0002
++#define JOINBSS_RATES_BASIC111_5 0x0004
++#define JOINBSS_RATES_BASIC111_11 0x0020
++#define JOINBSS_RATES_BASIC111_22 0x0100
++
++
++/***********************************************************************
++*/
++typedef struct mem_read_write {
++ u16 addr ACX_PACKED;
++ u16 type ACX_PACKED; /* 0x0 int. RAM / 0xffff MAC reg. / 0x81 PHY RAM / 0x82 PHY reg. */
++ u32 len ACX_PACKED;
++ u32 data ACX_PACKED;
++} mem_read_write_t;
++
++typedef struct firmware_image {
++ u32 chksum ACX_PACKED;
++ u32 size ACX_PACKED;
++ u8 data[1] ACX_PACKED; /* the byte array of the actual firmware... */
++} firmware_image_t;
++
++typedef struct acx_cmd_radioinit {
++ u32 offset ACX_PACKED;
++ u32 len ACX_PACKED;
++} acx_cmd_radioinit_t;
++
++typedef struct acx100_ie_wep_options {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u16 NumKeys ACX_PACKED; /* max # of keys */
++ u8 WEPOption ACX_PACKED; /* 0 == decrypt default key only, 1 == override decrypt */
++ u8 Pad ACX_PACKED; /* used only for acx111 */
++} acx100_ie_wep_options_t;
++
++typedef struct ie_dot11WEPDefaultKey {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u8 action ACX_PACKED;
++ u8 keySize ACX_PACKED;
++ u8 defaultKeyNum ACX_PACKED;
++ u8 key[29] ACX_PACKED; /* check this! was Key[19]. */
++} ie_dot11WEPDefaultKey_t;
++
++typedef struct acx111WEPDefaultKey {
++ u8 MacAddr[ETH_ALEN] ACX_PACKED;
++ u16 action ACX_PACKED; /* NOTE: this is a u16, NOT a u8!! */
++ u16 reserved ACX_PACKED;
++ u8 keySize ACX_PACKED;
++ u8 type ACX_PACKED;
++ u8 index ACX_PACKED;
++ u8 defaultKeyNum ACX_PACKED;
++ u8 counter[6] ACX_PACKED;
++ u8 key[32] ACX_PACKED; /* up to 32 bytes (for TKIP!) */
++} acx111WEPDefaultKey_t;
++
++typedef struct ie_dot11WEPDefaultKeyID {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u8 KeyID ACX_PACKED;
++} ie_dot11WEPDefaultKeyID_t;
++
++typedef struct acx100_cmd_wep_mgmt {
++ u8 MacAddr[ETH_ALEN] ACX_PACKED;
++ u16 Action ACX_PACKED;
++ u16 KeySize ACX_PACKED;
++ u8 Key[29] ACX_PACKED; /* 29*8 == 232bits == WEP256 */
++} acx100_cmd_wep_mgmt_t;
++
++typedef struct defaultkey {
++ u8 num;
++} defaultkey_t;
++
++typedef struct acx_ie_generic {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ union {
++ /* struct wep wp ACX_PACKED; */
++ /* Association ID IE: just a 16bit value: */
++ u16 aid;
++ /* UNUSED? struct defaultkey dkey ACX_PACKED; */
++ /* generic member for quick implementation of commands */
++ u8 bytes[32] ACX_PACKED;
++ } m ACX_PACKED;
++} acx_ie_generic_t;
++
++/* Config Option structs */
++
++typedef struct co_antennas {
++ u8 type ACX_PACKED;
++ u8 len ACX_PACKED;
++ u8 list[2] ACX_PACKED;
++} co_antennas_t;
++
++typedef struct co_powerlevels {
++ u8 type ACX_PACKED;
++ u8 len ACX_PACKED;
++ u16 list[8] ACX_PACKED;
++} co_powerlevels_t;
++
++typedef struct co_datarates {
++ u8 type ACX_PACKED;
++ u8 len ACX_PACKED;
++ u8 list[8] ACX_PACKED;
++} co_datarates_t;
++
++typedef struct co_domains {
++ u8 type ACX_PACKED;
++ u8 len ACX_PACKED;
++ u8 list[6] ACX_PACKED;
++} co_domains_t;
++
++typedef struct co_product_id {
++ u8 type ACX_PACKED;
++ u8 len ACX_PACKED;
++ u8 list[128] ACX_PACKED;
++} co_product_id_t;
++
++typedef struct co_manuf_id {
++ u8 type ACX_PACKED;
++ u8 len ACX_PACKED;
++ u8 list[128] ACX_PACKED;
++} co_manuf_t;
++
++typedef struct co_fixed {
++ u8 type ACX_PACKED;
++ u8 len ACX_PACKED;
++ char NVSv[8] ACX_PACKED;
++ u8 MAC[6] ACX_PACKED;
++ u16 probe_delay ACX_PACKED;
++ u32 eof_memory ACX_PACKED;
++ u8 dot11CCAModes ACX_PACKED;
++ u8 dot11Diversity ACX_PACKED;
++ u8 dot11ShortPreambleOption ACX_PACKED;
++ u8 dot11PBCCOption ACX_PACKED;
++ u8 dot11ChannelAgility ACX_PACKED;
++ u8 dot11PhyType ACX_PACKED;
++/* u8 dot11TempType ACX_PACKED;
++ u8 num_var ACX_PACKED; seems to be erased */
++} co_fixed_t;
++
++
++typedef struct acx111_ie_configoption {
++ co_fixed_t configoption_fixed ACX_PACKED;
++ co_antennas_t antennas ACX_PACKED;
++ co_powerlevels_t power_levels ACX_PACKED;
++ co_datarates_t data_rates ACX_PACKED;
++ co_domains_t domains ACX_PACKED;
++ co_product_id_t product_id ACX_PACKED;
++ co_manuf_t manufacturer ACX_PACKED;
++} acx111_ie_configoption_t;
++
++
++/***********************************************************************
++*/
++#define CHECK_SIZEOF(type,size) { \
++ extern void BUG_bad_size_for_##type(void); \
++ if (sizeof(type)!=(size)) BUG_bad_size_for_##type(); \
++}
++
++static inline void
++acx_struct_size_check(void)
++{
++ //CHECK_SIZEOF(txdesc_t, 0x30);
++ CHECK_SIZEOF(acx100_ie_memconfigoption_t, 24);
++ CHECK_SIZEOF(acx100_ie_queueconfig_t, 0x20);
++ //CHECK_SIZEOF(acx_joinbss_t, 0x30);
++}
++
++
++/*============================================================================*
++ * Global data *
++ *============================================================================*/
++extern const u8 bitpos2ratebyte[];
++extern const u8 bitpos2rate100[];
++
++extern const u8 reg_domain_ids[];
++extern const u8 reg_domain_ids_len;
++
++extern const struct iw_handler_def acx_ioctl_handler_def;
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/cfi.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/cfi.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/cfi.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/cfi.c 2005-10-29 22:02:44.000000000 +0300
+@@ -0,0 +1,4779 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++#define ACX_PCI 1
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
++#include <linux/moduleparam.h>
++#endif
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/if_arp.h>
++#include <linux/rtnetlink.h>
++#include <linux/wireless.h>
++#if WIRELESS_EXT >= 13
++#include <net/iw_handler.h>
++#endif
++#include <linux/device.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ioport.h>
++#include <linux/pm.h>
++#include <linux/vmalloc.h>
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/arch/tc.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/pca9535.h>
++
++#include "acx.h"
++
++#define CARDNAME "tnetw1100b"
++
++/*================================================================*/
++/* Local Constants */
++#define PCI_TYPE (PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
++#define PCI_ACX100_REGION1 0x01
++#define PCI_ACX100_REGION1_SIZE 0x1000 /* Memory size - 4K bytes */
++#define PCI_ACX100_REGION2 0x02
++#define PCI_ACX100_REGION2_SIZE 0x10000 /* Memory size - 64K bytes */
++
++#define PCI_ACX111_REGION1 0x00
++#define PCI_ACX111_REGION1_SIZE 0x2000 /* Memory size - 8K bytes */
++#define PCI_ACX111_REGION2 0x01
++#define PCI_ACX111_REGION2_SIZE 0x20000 /* Memory size - 128K bytes */
++
++/* Texas Instruments Vendor ID */
++#define PCI_VENDOR_ID_TI 0x104c
++
++/* ACX100 22Mb/s WLAN controller */
++#define PCI_DEVICE_ID_TI_TNETW1100A 0x8400
++#define PCI_DEVICE_ID_TI_TNETW1100B 0x8401
++
++/* ACX111 54Mb/s WLAN controller */
++#define PCI_DEVICE_ID_TI_TNETW1130 0x9066
++
++/* PCI Class & Sub-Class code, Network-'Other controller' */
++#define PCI_CLASS_NETWORK_OTHERS 0x280
++
++#define CARD_EEPROM_ID_SIZE 6
++#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* a la orinoco.c */
++
++
++/***********************************************************************
++*/
++static void acx_l_disable_irq(wlandevice_t *priv);
++static void acx_l_enable_irq(wlandevice_t *priv);
++static int acx_drv_probe(struct device *dev);
++static int acx_remove(struct device *dev);
++
++static inline void test(wlandevice_t *priv);
++
++#ifdef CONFIG_PM
++static int acx_suspend(struct device *dev, pm_message_t state, u32 level);
++static int acx_resume(struct device *dev, u32 level);
++#endif
++
++static void acx_i_tx_timeout(netdevice_t *dev);
++static struct net_device_stats *acx_e_get_stats(netdevice_t *dev);
++static struct iw_statistics *acx_e_get_wireless_stats(netdevice_t *dev);
++
++static irqreturn_t acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static void acx_i_set_multicast_list(netdevice_t *dev);
++
++static int acx_e_open(netdevice_t *dev);
++static int acx_e_close(netdevice_t *dev);
++static void acx_s_up(netdevice_t *dev);
++static void acx_s_down(netdevice_t *dev);
++
++
++/***********************************************************************
++** Register access
++*/
++
++/* Pick one */
++/* #define INLINE_IO static */
++#define INLINE_IO static inline
++
++INLINE_IO u32
++acx_read_reg32(wlandevice_t *priv, unsigned int offset)
++{
++#if ACX_IO_WIDTH == 32
++ return readl((u8 *)priv->iobase + priv->io[offset]);
++#else
++ return readw((u8 *)priv->iobase + priv->io[offset])
++ + (readw((u8 *)priv->iobase + priv->io[offset] + 2) << 16);
++#endif
++}
++
++INLINE_IO u16
++acx_read_reg16(wlandevice_t *priv, unsigned int offset)
++{
++ return readw((u8 *)priv->iobase + priv->io[offset]);
++}
++
++INLINE_IO u8
++acx_read_reg8(wlandevice_t *priv, unsigned int offset)
++{
++ return readb((u8 *)priv->iobase + priv->io[offset]);
++}
++
++INLINE_IO void
++acx_write_reg32(wlandevice_t *priv, unsigned int offset, u32 val)
++{
++#if ACX_IO_WIDTH == 32
++ writel(val, (u8 *)priv->iobase + priv->io[offset]);
++#else
++ writew(val & 0xffff, (u8 *)priv->iobase + priv->io[offset]);
++ writew(val >> 16, (u8 *)priv->iobase + priv->io[offset] + 2);
++#endif
++}
++
++INLINE_IO void
++acx_write_reg16(wlandevice_t *priv, unsigned int offset, u16 val)
++{
++ writew(val, (u8 *)priv->iobase + priv->io[offset]);
++}
++
++INLINE_IO void
++acx_write_reg8(wlandevice_t *priv, unsigned int offset, u8 val)
++{
++ writeb(val, (u8 *)priv->iobase + priv->io[offset]);
++}
++
++/* Handle PCI posting properly:
++ * Make sure that writes reach the adapter in case they require to be executed
++ * *before* the next write, by reading a random (and safely accessible) register.
++ * This call has to be made if there is no read following (which would flush the data
++ * to the adapter), yet the written data has to reach the adapter immediately. */
++INLINE_IO void
++acx_write_flush(wlandevice_t *priv)
++{
++ /* readb(priv->iobase + priv->io[IO_ACX_INFO_MAILBOX_OFFS]); */
++ /* faster version (accesses the first register, IO_ACX_SOFT_RESET,
++ * which should also be safe): */
++ readb(priv->iobase);
++}
++
++
++INLINE_IO void acx_mailbox_fill(wlandevice_t *priv, unsigned int offset, unsigned char val, int len){
++ unsigned int addr = offset;
++ unsigned int buff = 0;
++
++ // Fill the buffer
++ memset((void *) &buff, val, len);
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x00010000);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, addr);
++
++ while(len >= 4){
++ // Write data
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,buff);
++ acx_write_flush(priv);
++
++ addr += 4;
++ len -= 4;
++ }
++
++ if(len > 0) {
++ val = 0;
++ memset((void *) &buff, val , len);
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,buff);
++ acx_write_flush(priv);
++ }
++}
++
++
++INLINE_IO void acx_mailbox_write(wlandevice_t *priv, unsigned int offset, void *cmd, int len){
++ unsigned char *buff = (unsigned char *) cmd;
++ unsigned int addr = offset;
++ unsigned int val = 0;
++
++ if(!cmd){
++ return;
++ }
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x00010000);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, addr);
++
++ while(len >= 4){
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,*((unsigned int *) buff));
++ acx_write_flush(priv);
++
++ buff += 4;
++ addr += 4;
++ len -= 4;
++ }
++
++ if(len > 0) {
++ val = 0;
++ memcpy((void *) &val, (void *) buff, len);
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA,val);
++ acx_write_flush(priv);
++ }
++}
++
++INLINE_IO void acx_mailbox_read(wlandevice_t *priv, unsigned int offset, void *data, int len){
++ unsigned char *buff = (unsigned char *) data;
++ unsigned int addr = offset;
++ unsigned int value = 0;
++
++ if(!data){
++ return;
++ }
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x00010000);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, addr);
++
++ while(len >= 4){
++ *buff = 0;
++ *((unsigned int *) buff) = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++
++ buff += 4;
++ addr += 4;
++ len -= 4;
++ }
++
++ if(len > 0){
++ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++ memcpy((void *) buff, (void *) &value, len);
++ }
++}
++
++/***********************************************************************
++*/
++static const char name_acx100[] = "ACX100";
++static const char name_tnetw1100a[] = "TNETW1100A";
++static const char name_tnetw1100b[] = "TNETW1100B";
++
++static const char name_acx111[] = "ACX111";
++static const char name_tnetw1130[] = "TNETW1130";
++
++struct device_driver acx_driver = {
++ .name = CARDNAME,
++ .bus = &platform_bus_type,
++ .probe = acx_drv_probe,
++ .remove = acx_remove,
++#ifdef CONFIG_PM
++ .suspend = acx_suspend,
++ .resume = acx_resume
++#endif
++};
++
++typedef struct acx_device {
++ netdevice_t *newest;
++} acx_device_t;
++
++/* if this driver was only about PCI devices, then we probably wouldn't
++ * need this linked list.
++ * But if we want to register ALL kinds of devices in one global list,
++ * then we need it and need to maintain it properly. */
++static struct acx_device root_acx_dev = {
++ .newest = NULL,
++};
++DECLARE_MUTEX(root_acx_dev_sem);
++
++
++/***********************************************************************
++*/
++static inline txdesc_t*
++get_txdesc(wlandevice_t* priv, int index)
++{
++ return (txdesc_t*) (((u8*)priv->txdesc_start) + index * priv->txdesc_size);
++}
++
++static inline txdesc_t*
++move_txdesc(wlandevice_t* priv, txdesc_t* txdesc, int inc)
++{
++ return (txdesc_t*) (((u8*)txdesc) + inc * priv->txdesc_size);
++}
++
++static txhostdesc_t*
++acx_get_txhostdesc(wlandevice_t* priv, txdesc_t* txdesc)
++{
++ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
++ if (ACX_DEBUG && (index % priv->txdesc_size)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ index /= priv->txdesc_size;
++ if (ACX_DEBUG && (index >= TX_CNT)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ return &priv->txhostdesc_start[index*2];
++}
++
++static client_t*
++acx_get_txc(wlandevice_t* priv, txdesc_t* txdesc)
++{
++ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
++ if (ACX_DEBUG && (index % priv->txdesc_size)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ index /= priv->txdesc_size;
++ if (ACX_DEBUG && (index >= TX_CNT)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ return priv->txc[index];
++}
++
++static void
++acx_put_txc(wlandevice_t* priv, txdesc_t* txdesc, client_t* c)
++{
++ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
++ if (ACX_DEBUG && (index % priv->txdesc_size)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return;
++ }
++ index /= priv->txdesc_size;
++ if (ACX_DEBUG && (index >= TX_CNT)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return;
++ }
++ priv->txc[index] = c;
++}
++
++/***********************************************************************
++** EEPROM and PHY read/write helpers
++*/
++/***********************************************************************
++** acx_read_eeprom_offset
++**
++** Function called to read an octet in the EEPROM.
++**
++** This function is used by acx_probe_pci to check if the
++** connected card is a legal one or not.
++**
++** Arguments:
++** priv ptr to wlandevice structure
++** addr address to read in the EEPROM
++** charbuf ptr to a char. This is where the read octet
++** will be stored
++**
++** Returns:
++** zero (0) - failed
++** one (1) - success
++**
++** NOT ADAPTED FOR ACX111!!
++*/
++int
++acx_read_eeprom_offset(wlandevice_t *priv, u32 addr, u8 *charbuf)
++{
++ int result = NOT_OK;
++ int count;
++
++ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
++ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
++
++ count = 0xffff;
++ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
++ /* scheduling away instead of CPU burning loop
++ * doesn't seem to work here at all:
++ * awful delay, sometimes also failure.
++ * Doesn't matter anyway (only small delay). */
++ if (unlikely(!--count)) {
++ printk("%s: timeout waiting for EEPROM read\n",
++ priv->netdev->name);
++ goto fail;
++ }
++ }
++
++ *charbuf = acx_read_reg8(priv, IO_ACX_EEPROM_DATA);
++ acxlog(L_DEBUG, "EEPROM at 0x%04X = 0x%02X\n", addr, *charbuf);
++ result = OK;
++
++fail:
++ return result;
++}
++
++
++/***********************************************************************
++** Dummy EEPROM read? why?!
++*/
++static int
++acx_read_eeprom_area(wlandevice_t *priv)
++{
++ int offs;
++ u8 tmp[0x3b];
++
++ for (offs = 0x8c; offs < 0xb9; offs++) {
++ acx_read_eeprom_offset(priv, offs, &tmp[offs - 0x8c]);
++ }
++ return OK;
++}
++
++
++/***********************************************************************
++** We don't lock hw accesses here since we never r/w eeprom in IRQ
++** Note: this function sleeps only because of GFP_KERNEL alloc
++*/
++#ifdef UNUSED
++int
++acx_s_write_eeprom_offset(wlandevice_t *priv, u32 addr, u32 len, const u8 *charbuf)
++{
++ u8 *data_verify = NULL;
++ unsigned long flags;
++ int count, i;
++ int result = NOT_OK;
++ u16 gpio_orig;
++
++ printk("acx: WARNING! I would write to EEPROM now. "
++ "Since I really DON'T want to unless you know "
++ "what you're doing (THIS CODE WILL PROBABLY "
++ "NOT WORK YET!), I will abort that now. And "
++ "definitely make sure to make a "
++ "/proc/driver/acx_wlan0_eeprom backup copy first!!! "
++ "(the EEPROM content includes the PCI config header!! "
++ "If you kill important stuff, then you WILL "
++ "get in trouble and people DID get in trouble already)\n");
++ return OK;
++
++ FN_ENTER;
++
++ data_verify = kmalloc(len, GFP_KERNEL);
++ if (!data_verify) {
++ goto end;
++ }
++
++ /* first we need to enable the OE (EEPROM Output Enable) GPIO line
++ * to be able to write to the EEPROM.
++ * NOTE: an EEPROM writing success has been reported,
++ * but you probably have to modify GPIO_OUT, too,
++ * and you probably need to activate a different GPIO
++ * line instead! */
++ gpio_orig = acx_read_reg16(priv, IO_ACX_GPIO_OE);
++ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig & ~1);
++ acx_write_flush(priv);
++
++ /* ok, now start writing the data out */
++ for (i = 0; i < len; i++) {
++ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
++ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
++ acx_write_reg32(priv, IO_ACX_EEPROM_DATA, *(charbuf + i));
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 1);
++
++ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
++ if (unlikely(++count > 0xffff)) {
++ printk("WARNING, DANGER!!! "
++ "Timeout waiting for EEPROM write\n");
++ goto end;
++ }
++ }
++ }
++
++ /* disable EEPROM writing */
++ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig);
++ acx_write_flush(priv);
++
++ /* now start a verification run */
++ count = 0xffff;
++ for (i = 0; i < len; i++) {
++ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
++ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
++
++ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
++ if (unlikely(!--count)) {
++ printk("timeout waiting for EEPROM read\n");
++ goto end;
++ }
++ }
++
++ data_verify[i] = acx_read_reg16(priv, IO_ACX_EEPROM_DATA);
++ }
++
++ if (0 == memcmp(charbuf, data_verify, len))
++ result = OK; /* read data matches, success */
++
++end:
++ kfree(data_verify);
++ FN_EXIT1(result);
++ return result;
++}
++#endif /* UNUSED */
++
++
++/***********************************************************************
++** acxpci_s_read_phy_reg
++**
++** Messing with rx/tx disabling and enabling here
++** (acx_write_reg32(priv, IO_ACX_ENABLE, 0b000000xx)) kills traffic
++*/
++int
++acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
++{
++ int result = NOT_OK;
++ int count;
++
++ FN_ENTER;
++
++ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_PHY_CTL, 2);
++
++ count = 0xffff;
++ while (acx_read_reg32(priv, IO_ACX_PHY_CTL)) {
++ /* scheduling away instead of CPU burning loop
++ * doesn't seem to work here at all:
++ * awful delay, sometimes also failure.
++ * Doesn't matter anyway (only small delay). */
++ if (unlikely(!--count)) {
++ printk("%s: timeout waiting for phy read\n",
++ priv->netdev->name);
++ *charbuf = 0;
++ goto fail;
++ }
++ }
++
++ acxlog(L_DEBUG, "count was %u\n", count);
++ *charbuf = acx_read_reg8(priv, IO_ACX_PHY_DATA);
++
++ acxlog(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg);
++ result = OK;
++ goto fail; /* silence compiler warning */
++fail:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++int
++acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
++{
++ FN_ENTER;
++
++ /* FIXME: we didn't use 32bit access here since mprusko said that
++ * it results in distorted sensitivity on his card (huh!?!?
++ * doesn't happen with my setup...)
++ * But with the access reordering and flushing it
++ * shouldn't happen any more...
++ * FIXME: which radio is in the problematic card? My working one
++ * is 0x11 */
++ acx_write_reg32(priv, IO_ACX_PHY_DATA, value);
++ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_PHY_CTL, 1);
++ acx_write_flush(priv);
++ acxlog(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg);
++
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++#define NO_AUTO_INCREMENT 1
++
++/***********************************************************************
++** acx_s_write_fw
++**
++** Write the firmware image into the card.
++**
++** Arguments:
++** priv wlan device structure
++** apfw_image firmware image.
++**
++** Returns:
++** 1 firmware image corrupted
++** 0 success
++*/
++static int
++acx_s_write_fw(wlandevice_t *priv, const firmware_image_t *apfw_image, u32 offset)
++{
++ int len, size;
++ u32 sum, v32;
++ /* we skip the first four bytes which contain the control sum */
++ const u8 *image = (u8*)apfw_image + 4;
++
++ /* start the image checksum by adding the image size value */
++ sum = image[0]+image[1]+image[2]+image[3];
++ image += 4;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
++
++#if NO_AUTO_INCREMENT
++ acxlog(L_INIT, "not using auto increment for firmware loading\n");
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
++#else
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
++ acx_write_flush(priv);
++#endif
++
++ len = 0;
++ size = le32_to_cpu(apfw_image->size) & (~3);
++
++ while (likely(len < size)) {
++ v32 = be32_to_cpu(*(u32*)image);
++ sum += image[0]+image[1]+image[2]+image[3];
++ image += 4;
++ len += 4;
++
++#if NO_AUTO_INCREMENT
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
++ acx_write_flush(priv);
++#endif
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, v32);
++ }
++
++ acxlog(L_DEBUG, "%s: firmware written\n", __func__);
++
++ /* compare our checksum with the stored image checksum */
++ return (sum != le32_to_cpu(apfw_image->chksum));
++}
++
++
++/***********************************************************************
++** acx_s_validate_fw
++**
++** Compare the firmware image given with
++** the firmware image written into the card.
++**
++** Arguments:
++** priv wlan device structure
++** apfw_image firmware image.
++**
++** Returns:
++** NOT_OK firmware image corrupted or not correctly written
++** OK success
++*/
++static int
++acx_s_validate_fw(wlandevice_t *priv, const firmware_image_t *apfw_image,
++ u32 offset)
++{
++ u32 v32, w32, sum;
++ int len, size;
++ int result = OK;
++ /* we skip the first four bytes which contain the control sum */
++ const u8 *image = (u8*)apfw_image + 4;
++
++ /* start the image checksum by adding the image size value */
++ sum = image[0]+image[1]+image[2]+image[3];
++ image += 4;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
++
++#if NO_AUTO_INCREMENT
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
++#else
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
++#endif
++
++ len = 0;
++ size = le32_to_cpu(apfw_image->size) & (~3);
++
++ while (likely(len < size)) {
++ v32 = be32_to_cpu(*(u32*)image);
++ image += 4;
++ len += 4;
++
++#if NO_AUTO_INCREMENT
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
++#endif
++ w32 = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++
++ if (unlikely(w32 != v32)) {
++ printk("acx: FATAL: firmware upload: "
++ "data parts at offset %d don't match (0x%08X vs. 0x%08X)! "
++ "I/O timing issues or defective memory, with DWL-xx0+? "
++ "ACX_IO_WIDTH=16 may help. Please report\n",
++ len, v32, w32);
++ result = NOT_OK;
++ break;
++ }
++
++ sum += (u8)w32 + (u8)(w32>>8) + (u8)(w32>>16) + (u8)(w32>>24);
++ }
++
++ /* sum control verification */
++ if (result != NOT_OK) {
++ if (sum != le32_to_cpu(apfw_image->chksum)) {
++ printk("acx: FATAL: firmware upload: "
++ "checksums don't match!\n");
++ result = NOT_OK;
++ }
++ }
++
++ return result;
++}
++
++
++/***********************************************************************
++** acx_s_upload_fw
++**
++** Arguments:
++** wlandevice: private device that contains card device
++** Returns:
++** NOT_OK: failed
++** OK: success
++** Call context:
++** acx_reset_dev
++*/
++static int
++acx_s_upload_fw(wlandevice_t *priv)
++{
++ firmware_image_t *apfw_image = NULL;
++ int res = NOT_OK;
++ int try;
++ u32 size;
++ char filename[sizeof("tiacx1NNcNN")];
++
++ FN_ENTER;
++
++ /* Try combined, then main image */
++ priv->need_radio_fw = 0;
++ sprintf(filename, "tiacx1%02dc%02X",
++ IS_ACX111(priv)*11, priv->radio_type);
++
++ apfw_image = acx_s_read_fw(priv->dev, filename, &size);
++ if (!apfw_image) {
++ priv->need_radio_fw = 1;
++ filename[sizeof("tiacx1NN")-1] = '\0';
++ apfw_image = acx_s_read_fw(priv->dev, filename, &size);
++ if (!apfw_image) {
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++ }
++ }
++
++ for (try = 1; try <= 5; try++) {
++ res = acx_s_write_fw(priv, apfw_image, 0);
++ acxlog(L_DEBUG|L_INIT, "acx_write_fw (main/combined):%d\n", res);
++ if (OK == res) {
++ res = acx_s_validate_fw(priv, apfw_image, 0);
++ acxlog(L_DEBUG|L_INIT, "acx_validate_fw "
++ "(main/combined):%d\n", res);
++ }
++
++ if (OK == res) {
++ SET_BIT(priv->dev_state_mask, ACX_STATE_FW_LOADED);
++ break;
++ }
++ printk("acx: firmware upload attempt #%d FAILED, "
++ "retrying...\n", try);
++ acx_s_msleep(1000); /* better wait for a while... */
++ }
++
++ vfree((void *) apfw_image);
++
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/***********************************************************************
++** acx_s_upload_radio
++**
++** Uploads the appropriate radio module firmware
++** into the card.
++*/
++int
++acx_s_upload_radio(wlandevice_t *priv)
++{
++ acx_ie_memmap_t mm;
++ firmware_image_t *radio_image = NULL;
++ acx_cmd_radioinit_t radioinit;
++ int res = NOT_OK;
++ int try;
++ u32 offset;
++ u32 size;
++ char filename[sizeof("tiacx1NNrNN")];
++
++ if (!priv->need_radio_fw) return OK;
++
++ FN_ENTER;
++
++ acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
++ offset = le32_to_cpu(mm.CodeEnd);
++
++ sprintf(filename, "tiacx1%02dr%02X",
++ IS_ACX111(priv)*11,
++ priv->radio_type);
++ radio_image = acx_s_read_fw(priv->dev, filename, &size);
++ if (!radio_image) {
++ printk("acx: can't load radio module '%s'\n", filename);
++ goto fail;
++ }
++
++ acx_s_issue_cmd(priv, ACX1xx_CMD_SLEEP, NULL, 0);
++
++ for (try = 1; try <= 5; try++) {
++ res = acx_s_write_fw(priv, radio_image, offset);
++ acxlog(L_DEBUG|L_INIT, "acx_write_fw (radio): %d\n", res);
++ if (OK == res) {
++ res = acx_s_validate_fw(priv, radio_image, offset);
++ acxlog(L_DEBUG|L_INIT, "acx_validate_fw (radio): %d\n", res);
++ }
++
++ if (OK == res)
++ break;
++ printk("acx: radio firmware upload attempt #%d FAILED, "
++ "retrying...\n", try);
++ acx_s_msleep(1000); /* better wait for a while... */
++ }
++
++ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
++ radioinit.offset = cpu_to_le32(offset);
++ /* no endian conversion needed, remains in card CPU area: */
++ radioinit.len = radio_image->size;
++
++ vfree(radio_image);
++
++ if (OK != res)
++ goto fail;
++
++ /* will take a moment so let's have a big timeout */
++ acx_s_issue_cmd_timeo(priv, ACX1xx_CMD_RADIOINIT,
++ &radioinit, sizeof(radioinit), CMD_TIMEOUT_MS(1000));
++
++ res = acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
++fail:
++ FN_EXIT1(res);
++ return res;
++}
++
++void write_reg(wlandevice_t *priv, int reg, u32 value){
++ acx_write_reg32(priv,IO_ACX_HW_SLAVE_REG_ADDR,priv->io[reg]);
++ acx_write_reg16(priv,IO_ACX_HW_SLAVE_REG_DATA,value);
++}
++
++u32 read_reg(wlandevice_t *priv, int reg){
++ u32 value;
++
++ acx_write_reg32(priv,IO_ACX_HW_SLAVE_REG_ADDR,reg);
++ value = acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_DATA);
++
++ return value;
++}
++
++
++/***********************************************************************
++** acx_l_reset_mac
++**
++** Arguments:
++** wlandevice: private device that contains card device
++** Side effects:
++** MAC will be reset
++** Call context:
++** acx_reset_dev
++** Comment:
++** resets onboard acx100 MAC
++**
++** Requires lock to be taken
++*/
++static void
++acx_l_reset_mac(wlandevice_t *priv)
++{
++ u16 temp;
++
++ FN_ENTER;
++
++ /* Pocket PC driver setting this register
++ * with 2.
++ */
++ acx_write_reg16(priv,IO_ACX_PCI_ARB_CFG,0x2);
++
++ msleep(300);
++
++ /* halt eCPU */
++ acxlog(L_DEBUG, "%s: Halt eCPU ...\n", __func__);
++ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
++ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
++ acx_write_flush(priv);
++
++ test(priv);
++
++ /* now do soft reset of eCPU */
++ temp = acx_read_reg16(priv, IO_ACX_SOFT_RESET) | 0x1;
++ acxlog(L_DEBUG, "%s: enable soft reset...\n", __func__);
++ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp);
++ acx_write_flush(priv);
++
++ test(priv);
++
++ /* now reset bit again */
++ acxlog(L_DEBUG, "%s: disable soft reset and go to init mode...\n", __func__);
++ /* deassert eCPU reset */
++ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp & ~0x1);
++
++ /* now start a burst read from initial flash EEPROM */
++ temp = acx_read_reg16(priv, IO_ACX_EE_START) | 0x1;
++ acx_write_reg16(priv, IO_ACX_EE_START, temp);
++ acx_write_flush(priv);
++
++ test(priv);
++
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx_s_verify_init
++*/
++static int
++acx_s_verify_init(wlandevice_t *priv)
++{
++ int result = NOT_OK;
++ int timer;
++
++ FN_ENTER;
++
++ for (timer = 40; timer > 0; timer--) {
++ u16 irqstat = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
++ if (irqstat & HOST_INT_FCS_THRESHOLD) {
++ result = OK;
++ acx_write_reg16(priv, IO_ACX_IRQ_ACK, HOST_INT_FCS_THRESHOLD);
++ break;
++ }
++ /* HZ / 50 resulted in 24 schedules for ACX100 on my machine,
++ * so better schedule away longer for greater efficiency,
++ * decrease loop count */
++ acx_s_msleep(50);
++ }
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++
++/***********************************************************************
++** A few low-level helpers
++**
++** Note: these functions are not protected by lock
++** and thus are never allowed to be called from IRQ.
++** Also they must not race with fw upload which uses same hw regs
++*/
++
++/***********************************************************************
++** acx_read_info_status
++*/
++/* Info mailbox format:
++2 bytes: type
++2 bytes: status
++more bytes may follow
++ docs say about status:
++ 0x0000 info available (set by hw)
++ 0x0001 information received (must be set by host)
++ 0x1000 info available, mailbox overflowed (messages lost) (set by hw)
++ but in practice we've seen:
++ 0x9000 when we did not set status to 0x0001 on prev message
++ 0x1001 when we did set it
++ 0x0000 was never seen
++ conclusion: this is really a bitfield:
++ 0x1000 is 'info available' bit
++ 'mailbox overflowed' bit is 0x8000, not 0x1000
++ value of 0x0000 probably means that there is no message at all
++ P.S. I dunno how in hell hw is supposed to notice that messages are lost -
++ it does NOT clear bit 0x0001, and this bit will probably stay forever set
++ after we set it once. Let's hope this will be fixed in firmware someday
++*/
++static void
++acx_read_info_status(wlandevice_t *priv)
++{
++ u32 value;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1);
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
++ acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS));
++
++ /* make sure we only read the data once all cfg registers are written: */
++ acx_write_flush(priv);
++ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++
++ priv->info_type = (u16)value;
++ priv->info_status = (value >> 16);
++
++ /* inform hw that we have read this info message */
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, priv->info_type | 0x00010000);
++ acx_write_flush(priv);
++ /* now bother hw to notice it: */
++ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_INFOACK);
++ acx_write_flush(priv);
++
++ acxlog(L_CTL, "info_type 0x%04X, info_status 0x%04X\n",
++ priv->info_type, priv->info_status);
++}
++
++
++/***********************************************************************
++** acx_write_cmd_type_or_status
++*/
++static void
++acx_write_cmd_type_or_status(wlandevice_t *priv, u32 val)
++{
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
++ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
++
++ /* make sure we only write the data once all config registers are written */
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, val);
++ acx_write_flush(priv);
++}
++static inline void
++acx_write_cmd_type(wlandevice_t *priv, u32 val)
++{
++ acx_write_cmd_type_or_status(priv, val);
++}
++static inline void
++acx_write_cmd_status(wlandevice_t *priv, u32 val)
++{
++ acx_write_cmd_type_or_status(priv, val<<16);
++}
++
++
++/***********************************************************************
++** acx_read_cmd_status
++*/
++static void
++acx_read_cmd_status(wlandevice_t *priv)
++{
++ u32 value;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
++ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
++
++ /* make sure we only read the data once all config registers are written */
++ acx_write_flush(priv);
++ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++
++ priv->cmd_type = (u16)value;
++ priv->cmd_status = (value >> 16);
++
++ acxlog(L_CTL, "cmd_type 0x%04X, cmd_status 0x%04X [%s]\n",
++ priv->cmd_type, priv->cmd_status,
++ acx_cmd_status_str(priv->cmd_status));
++}
++
++/***********************************************************************
++** acx_s_reset_dev
++**
++** Arguments:
++** netdevice that contains the wlandevice priv variable
++** Returns:
++** NOT_OK on fail
++** OK on success
++** Side effects:
++** device is hard reset
++** Call context:
++** acx_probe_pci
++** Comment:
++** This resets the acx100 device using low level hardware calls
++** as well as uploads and verifies the firmware to the card
++*/
++static int
++acx_s_reset_dev(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ const char* msg = "";
++ unsigned long flags;
++ int result = NOT_OK;
++ u16 hardware_info;
++ u16 ecpu_ctrl;
++
++ FN_ENTER;
++
++ /* we're doing a reset, so hardware is unavailable */
++
++ /* reset the device to make sure the eCPU is stopped
++ * to upload the firmware correctly */
++
++ acx_lock(priv, flags);
++
++ acx_l_reset_mac(priv);
++
++ ecpu_ctrl = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) & 1;
++ if (!ecpu_ctrl) {
++ msg = "eCPU is already running. ";
++ goto fail_unlock;
++ }
++
++#ifdef WE_DONT_NEED_THAT_DO_WE
++ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 2) {
++ /* eCPU most likely means "embedded CPU" */
++ msg = "eCPU did not start after boot from flash. ";
++ goto fail_unlock;
++ }
++
++ /* check sense on reset flags */
++ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 0x10) {
++ printk("%s: eCPU did not start after boot (SOR), "
++ "is this fatal?\n", dev->name);
++ }
++#endif
++ /* scan, if any, is stopped now, setting corresponding IRQ bit */
++ priv->irq_status |= HOST_INT_SCAN_COMPLETE;
++
++ acx_unlock(priv, flags);
++
++ /* without this delay acx100 may fail to report hardware_info
++ ** (see below). Most probably eCPU runs some init code */
++ acx_s_msleep(10);
++
++ /* Need to know radio type before fw load */
++ hardware_info = acx_read_reg16(priv, IO_ACX_EEPROM_INFORMATION);
++ priv->form_factor = hardware_info & 0xff;
++ priv->radio_type = hardware_info >> 8;
++
++ /* load the firmware */
++ if (OK != acx_s_upload_fw(priv)){
++ printk("Failed to load firmware\n");
++ goto fail;
++ }
++
++ acx_s_msleep(10);
++
++ /* now start eCPU by clearing bit */
++ acxlog(L_DEBUG, "booted eCPU up and waiting for completion...\n");
++ //acx_write_reg16(priv, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1);
++ write_reg(priv, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1);
++
++ /* wait for eCPU bootup */
++ if (OK != acx_s_verify_init(priv)) {
++ msg = "timeout waiting for eCPU. ";
++ goto fail;
++ }
++
++ acxlog(L_DEBUG, "eCPU has woken up, card is ready to be configured\n");
++
++ if (IS_ACX111(priv)) {
++ acxlog(L_DEBUG, "cleaning up cmd mailbox access area\n");
++ acx_write_cmd_status(priv, 0);
++ acx_read_cmd_status(priv);
++ if (priv->cmd_status) {
++ msg = "error cleaning cmd mailbox area. ";
++ goto fail;
++ }
++ }
++
++ /* TODO what is this one doing ?? adapt for acx111 */
++ if ((OK != acx_read_eeprom_area(priv)) && IS_ACX100(priv)) {
++ /* does "CIS" mean "Card Information Structure"?
++ * If so, then this would be a PCMCIA message...
++ */
++ msg = "CIS error. ";
++ goto fail;
++ }
++
++ result = OK;
++ FN_EXIT1(result);
++ return result;
++
++/* Finish error message. Indicate which function failed */
++fail_unlock:
++ acx_unlock(priv, flags);
++fail:
++ printk("acx: %sreset_dev() FAILED\n", msg);
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx_init_mboxes
++*/
++void
++acx_init_mboxes(wlandevice_t *priv)
++{
++ u32 cmd_offs, info_offs;
++
++ FN_ENTER;
++
++ cmd_offs = acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS);
++ info_offs = acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS);
++ priv->cmd_area = (u8 *) cmd_offs + 0x4;
++ priv->info_area = (u8 *) info_offs + 0x4;
++ acxlog(L_DEBUG, "iobase2=%p\n"
++ "cmd_mbox_offset=%X cmd_area=%p\n"
++ "info_mbox_offset=%X info_area=%p\n",
++ priv->iobase2,
++ cmd_offs, priv->cmd_area,
++ info_offs, priv->info_area);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_issue_cmd_timeo
++* Excecutes a command in the command mailbox
++*
++* Arguments:
++* *pcmdparam = an pointer to the data. The data mustn't include
++* the 4 byte command header!
++*
++* NB: we do _not_ take lock inside, so be sure to not touch anything
++* which may interfere with IRQ handler operation
++*
++* TODO: busy wait is a bit silly, so:
++* 1) stop doing many iters - go to sleep after first
++* 2) go to waitqueue based approach: wait, not poll!
++*----------------------------------------------------------------*/
++#undef FUNC
++#define FUNC "issue_cmd"
++
++#if !ACX_DEBUG
++int
++acxpci_s_issue_cmd_timeo(
++ wlandevice_t *priv,
++ unsigned int cmd,
++ void *buffer,
++ unsigned buflen,
++ unsigned timeout)
++{
++#else
++int
++acxpci_s_issue_cmd_timeo_debug(
++ wlandevice_t *priv,
++ unsigned cmd,
++ void *buffer,
++ unsigned buflen,
++ unsigned timeout,
++ const char* cmdstr)
++{
++ unsigned long start = jiffies;
++#endif
++ const char *devname;
++ unsigned counter;
++ u16 irqtype;
++ u16 cmd_status;
++
++ FN_ENTER;
++
++ devname = priv->netdev->name;
++ if (!devname || !devname[0])
++ devname = "acx";
++
++ acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,timeout:%ums,type:0x%04X)\n",
++ cmdstr, buflen, timeout,
++ buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
++
++ if (!(priv->dev_state_mask & ACX_STATE_FW_LOADED)) {
++ printk("%s: "FUNC"(): firmware is not loaded yet, "
++ "cannot execute commands!\n", devname);
++ goto bad;
++ }
++
++ if ((acx_debug & L_DEBUG) && (cmd != ACX1xx_CMD_INTERROGATE)) {
++ printk("input pdr (len=%u):\n", buflen);
++ acx_dump_bytes(buffer, buflen);
++ }
++
++ /* wait for firmware to become idle for our command submission */
++ counter = 199; /* in ms */
++ do {
++ acx_read_cmd_status(priv);
++ /* Test for IDLE state */
++ if (!priv->cmd_status)
++ break;
++ if (counter % 10 == 0) {
++ /* we waited 10 iterations, no luck. Sleep 10 ms */
++ acx_s_msleep(10);
++ }
++ } while (--counter);
++
++ if (!counter) {
++ /* the card doesn't get idle, we're in trouble */
++ printk("%s: "FUNC"(): cmd_status is not IDLE: 0x%04X!=0\n",
++ devname, priv->cmd_status);
++ goto bad;
++ } else if (counter < 190) { /* if waited >10ms... */
++ acxlog(L_CTL|L_DEBUG, FUNC"(): waited for IDLE %dms. "
++ "Please report\n", 199 - counter);
++ }
++
++ /* now write the parameters of the command if needed */
++ if (buffer && buflen) {
++ /* if it's an INTERROGATE command, just pass the length
++ * of parameters to read, as data */
++#if CMD_DISCOVERY
++ if (cmd == ACX1xx_CMD_INTERROGATE)
++ acx_mailbox_fill(priv, (unsigned int) priv->cmd_area, 0xAA, buflen);
++#endif
++ acx_mailbox_write(priv,
++ (unsigned int) priv->cmd_area,
++ buffer, (cmd == ACX1xx_CMD_INTERROGATE) ? 4 : buflen);
++ }
++
++ /* now write the actual command type */
++ priv->cmd_type = cmd;
++ acx_write_cmd_type(priv, cmd);
++ /* execute command */
++ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_CMD);
++ acx_write_flush(priv);
++
++ /* wait for firmware to process command */
++
++ /* Ensure nonzero and not too large timeout.
++ ** Also converts e.g. 100->99, 200->199
++ ** which is nice but not essential */
++ timeout = (timeout-1) | 1;
++ if (unlikely(timeout > 1199))
++ timeout = 1199;
++ /* clear CMD_COMPLETE bit. can be set only by IRQ handler: */
++ priv->irq_status &= ~HOST_INT_CMD_COMPLETE;
++
++ /* we schedule away sometimes (timeout can be large) */
++ counter = timeout;
++ do {
++ if (!priv->irqs_active) { /* IRQ disabled: poll */
++ irqtype = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
++ if (irqtype & HOST_INT_CMD_COMPLETE) {
++ acx_write_reg16(priv, IO_ACX_IRQ_ACK,
++ HOST_INT_CMD_COMPLETE);
++ break;
++ }
++ } else { /* Wait when IRQ will set the bit */
++ irqtype = priv->irq_status;
++ if (irqtype & HOST_INT_CMD_COMPLETE)
++ break;
++ }
++
++ if (counter % 10 == 0) {
++ /* we waited 10 iterations, no luck. Sleep 10 ms */
++ acx_s_msleep(10);
++ }
++ } while (--counter);
++
++ /* save state for debugging */
++ acx_read_cmd_status(priv);
++ cmd_status = priv->cmd_status;
++
++ /* put the card in IDLE state */
++ priv->cmd_status = 0;
++ acx_write_cmd_status(priv, 0);
++
++ if (!counter) { /* timed out! */
++ printk("%s: "FUNC"(): timed out %s for CMD_COMPLETE. "
++ "irq bits:0x%04X irq_status:0x%04X timeout:%dms "
++ "cmd_status:%d (%s)\n",
++ devname, (priv->irqs_active) ? "waiting" : "polling",
++ irqtype, priv->irq_status, timeout,
++ cmd_status, acx_cmd_status_str(cmd_status));
++ goto bad;
++ } else if (timeout - counter > 30) { /* if waited >30ms... */
++ acxlog(L_CTL|L_DEBUG, FUNC"(): %s for CMD_COMPLETE %dms. "
++ "count:%d. Please report\n",
++ (priv->irqs_active) ? "waited" : "polled",
++ timeout - counter, counter);
++ }
++
++ if (1 != cmd_status) { /* it is not a 'Success' */
++ printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s). "
++ "Took %dms of %d\n",
++ devname, cmd_status, acx_cmd_status_str(cmd_status),
++ timeout - counter, timeout);
++ /* zero out result buffer */
++ if (buffer && buflen)
++ memset(buffer, 0, buflen);
++ goto bad;
++ }
++
++ /* read in result parameters if needed */
++ if (buffer && buflen && (cmd == ACX1xx_CMD_INTERROGATE)) {
++ //memcpy(buffer, priv->cmd_area, buflen);
++ acx_mailbox_read(priv, (unsigned int) priv->cmd_area, buffer, buflen);
++ if (acx_debug & L_DEBUG) {
++ printk("output buffer (len=%u): ", buflen);
++ acx_dump_bytes(buffer, buflen);
++ }
++ }
++/* ok: */
++ acxlog(L_CTL, FUNC"(%s): took %ld jiffies to complete\n",
++ cmdstr, jiffies - start);
++ FN_EXIT1(OK);
++ return OK;
++
++bad:
++ /* Give enough info so that callers can avoid
++ ** printing their own diagnostic messages */
++#if ACX_DEBUG
++ printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
++#else
++ printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
++#endif
++ dump_stack();
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_get_firmware_version
++*----------------------------------------------------------------*/
++static void
++acx_s_get_firmware_version(wlandevice_t *priv)
++{
++ fw_ver_t fw;
++ u8 hexarr[4] = { 0, 0, 0, 0 };
++ int hexidx = 0, val = 0;
++ const char *num;
++ char c;
++
++ FN_ENTER;
++
++ acx_s_interrogate(priv, &fw, ACX1xx_IE_FWREV);
++ memcpy(priv->firmware_version, fw.fw_id, FW_ID_SIZE);
++ priv->firmware_version[FW_ID_SIZE] = '\0';
++ acxlog(L_DEBUG, "fw_ver: fw_id='%s' hw_id=%08X\n",
++ priv->firmware_version, fw.hw_id);
++
++ if (strncmp(fw.fw_id, "Rev ", 4) != 0) {
++ printk("acx: strange firmware version string "
++ "'%s', please report\n", priv->firmware_version);
++ priv->firmware_numver = 0x01090407; /* assume 1.9.4.7 */
++ } else {
++ num = &fw.fw_id[4];
++ while (1) {
++ c = *num++;
++ if ((c == '.') || (c == '\0')) {
++ hexarr[hexidx++] = val;
++ if ((hexidx > 3) || (c == '\0')) /* end? */
++ break;
++ val = 0;
++ continue;
++ }
++ if ((c >= '0') && (c <= '9'))
++ c -= '0';
++ else
++ c = c - 'a' + (char)10;
++ val = val*16 + c;
++ }
++
++ priv->firmware_numver = (u32)(
++ (hexarr[0] << 24) + (hexarr[1] << 16)
++ + (hexarr[2] << 8) + hexarr[3]);
++ acxlog(L_DEBUG, "firmware_numver 0x%08X\n", priv->firmware_numver);
++ }
++ if (IS_ACX111(priv)) {
++ if (priv->firmware_numver == 0x00010011) {
++ /* This one does not survive floodpinging */
++ printk("acx: firmware '%s' is known to be buggy, "
++ "please upgrade\n", priv->firmware_version);
++ }
++ if (priv->firmware_numver == 0x02030131) {
++ /* With this one, all rx packets look mangled
++ ** Most probably we simply do not know how to use it
++ ** properly */
++ printk("acx: firmware '%s' does not work well "
++ "with this driver\n", priv->firmware_version);
++ }
++ }
++
++ priv->firmware_id = le32_to_cpu(fw.hw_id);
++
++ /* we're able to find out more detailed chip names now */
++ switch (priv->firmware_id & 0xffff0000) {
++ case 0x01010000:
++ case 0x01020000:
++ priv->chip_name = name_tnetw1100a;
++ break;
++ case 0x01030000:
++ priv->chip_name = name_tnetw1100b;
++ break;
++ case 0x03000000:
++ case 0x03010000:
++ priv->chip_name = name_tnetw1130;
++ break;
++ default:
++ printk("acx: unknown chip ID 0x%08X, "
++ "please report\n", priv->firmware_id);
++ break;
++ }
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_display_hardware_details
++*
++* Arguments:
++* priv: ptr to wlandevice that contains all the details
++* displayed by this function
++* Call context:
++* acx_probe_pci
++* Comment:
++* This function will display strings to the system log according
++* to device form_factor and radio type. It will needed to be
++*----------------------------------------------------------------*/
++static void
++acx_display_hardware_details(wlandevice_t *priv)
++{
++ const char *radio_str, *form_str;
++
++ FN_ENTER;
++
++ switch (priv->radio_type) {
++ case RADIO_MAXIM_0D:
++ /* hmm, the DWL-650+ seems to have two variants,
++ * according to a windows driver changelog comment:
++ * RFMD and Maxim. */
++ radio_str = "Maxim";
++ break;
++ case RADIO_RFMD_11:
++ radio_str = "RFMD";
++ break;
++ case RADIO_RALINK_15:
++ radio_str = "Ralink";
++ break;
++ case RADIO_RADIA_16:
++ radio_str = "Radia";
++ break;
++ case RADIO_UNKNOWN_17:
++ /* TI seems to have a radio which is
++ * additionally 802.11a capable, too */
++ radio_str = "802.11a/b/g radio?! Please report";
++ break;
++ case RADIO_UNKNOWN_19:
++ radio_str = "A radio used by Safecom cards?! Please report";
++ break;
++ default:
++ radio_str = "UNKNOWN, please report the radio type name!";
++ break;
++ }
++
++ switch (priv->form_factor) {
++ case 0x00:
++ form_str = "unspecified";
++ break;
++ case 0x01:
++ form_str = "(mini-)PCI / CardBus";
++ break;
++ case 0x02:
++ form_str = "USB";
++ break;
++ case 0x03:
++ form_str = "Compact Flash";
++ break;
++ default:
++ form_str = "UNKNOWN, Please report";
++ break;
++ }
++
++ printk("acx: form factor 0x%02X (%s), "
++ "radio type 0x%02X (%s), EEPROM version 0x%02X, "
++ "uploaded firmware '%s' (0x%08X)\n",
++ priv->form_factor, form_str, priv->radio_type, radio_str,
++ priv->eeprom_version, priv->firmware_version,
++ priv->firmware_id);
++
++ FN_EXIT0;
++}
++
++/***********************************************************************
++*/
++#ifdef NONESSENTIAL_FEATURES
++typedef struct device_id {
++ unsigned char id[6];
++ char *descr;
++ char *type;
++} device_id_t;
++
++static const device_id_t
++device_ids[] =
++{
++ {
++ {'G', 'l', 'o', 'b', 'a', 'l'},
++ NULL,
++ NULL,
++ },
++ {
++ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
++ "uninitialized",
++ "SpeedStream SS1021 or Gigafast WF721-AEX"
++ },
++ {
++ {0x80, 0x81, 0x82, 0x83, 0x84, 0x85},
++ "non-standard",
++ "DrayTek Vigor 520"
++ },
++ {
++ {'?', '?', '?', '?', '?', '?'},
++ "non-standard",
++ "Level One WPC-0200"
++ },
++ {
++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
++ "empty",
++ "DWL-650+ variant"
++ }
++};
++
++static void
++acx_show_card_eeprom_id(wlandevice_t *priv)
++{
++ unsigned char buffer[CARD_EEPROM_ID_SIZE];
++ int i;
++
++ memset(&buffer, 0, CARD_EEPROM_ID_SIZE);
++ /* use direct EEPROM access */
++ for (i = 0; i < CARD_EEPROM_ID_SIZE; i++) {
++ if (OK != acx_read_eeprom_offset(priv,
++ ACX100_EEPROM_ID_OFFSET + i,
++ &buffer[i]))
++ {
++ printk("acx: reading EEPROM FAILED\n");
++ break;
++ }
++ }
++
++ for (i = 0; i < VEC_SIZE(device_ids); i++) {
++ if (!memcmp(&buffer, device_ids[i].id, CARD_EEPROM_ID_SIZE)) {
++ if (device_ids[i].descr) {
++ printk("acx: EEPROM card ID string check "
++ "found %s card ID: is this %s?\n",
++ device_ids[i].descr, device_ids[i].type);
++ }
++ break;
++ }
++ }
++ if (i == VEC_SIZE(device_ids)) {
++ printk("acx: EEPROM card ID string check found "
++ "unknown card: expected 'Global', got '%.*s\'. "
++ "Please report\n", CARD_EEPROM_ID_SIZE, buffer);
++ }
++}
++#endif /* NONESSENTIAL_FEATURES */
++
++
++/***********************************************************************
++*/
++static void
++acx_s_device_chain_add(struct net_device *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ down(&root_acx_dev_sem);
++ priv->prev_nd = root_acx_dev.newest;
++ root_acx_dev.newest = dev;
++ priv->netdev = dev;
++ up(&root_acx_dev_sem);
++}
++
++static void
++acx_s_device_chain_remove(struct net_device *dev)
++{
++ struct net_device *querydev;
++ struct net_device *olderdev;
++ struct net_device *newerdev;
++
++ down(&root_acx_dev_sem);
++ querydev = root_acx_dev.newest;
++ newerdev = NULL;
++ while (querydev) {
++ olderdev = ((wlandevice_t*)netdev_priv(querydev))->prev_nd;
++ if (0 == strcmp(querydev->name, dev->name)) {
++ if (!newerdev) {
++ /* if we were at the beginning of the
++ * list, then it's the list head that
++ * we need to update to point at the
++ * next older device */
++ root_acx_dev.newest = olderdev;
++ } else {
++ /* it's the device that is newer than us
++ * that we need to update to point at
++ * the device older than us */
++ ((wlandevice_t*)netdev_priv(newerdev))->
++ prev_nd = olderdev;
++ }
++ break;
++ }
++ /* "newerdev" is actually the device of the old iteration,
++ * but since the list starts (root_acx_dev.newest)
++ * with the newest devices,
++ * it's newer than the ones following.
++ * Oh the joys of iterating from newest to oldest :-\ */
++ newerdev = querydev;
++
++ /* keep checking old devices for matches until we hit the end
++ * of the list */
++ querydev = olderdev;
++ }
++ up(&root_acx_dev_sem);
++}
++
++
++/***********************************************************************
++** acx_free_desc_queues
++**
++** Releases the queues that have been allocated, the
++** others have been initialised to NULL so this
++** function can be used if only part of the queues were allocated.
++*/
++static inline void
++acx_free_coherent(struct pci_dev *hwdev, size_t size,
++ void *vaddr, dma_addr_t dma_handle)
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 53)
++ dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev,
++ size, vaddr, dma_handle);
++#else
++ pci_free_consistent(hwdev, size, vaddr, dma_handle);
++#endif
++}
++
++void
++acx_free_desc_queues(wlandevice_t *priv)
++{
++#define ACX_FREE_QUEUE(size, ptr, phyaddr) \
++ if (ptr) { \
++ acx_free_coherent(0, size, ptr, phyaddr); \
++ ptr = NULL; \
++ size = 0; \
++ }
++
++ FN_ENTER;
++
++ ACX_FREE_QUEUE(priv->txhostdesc_area_size, priv->txhostdesc_start, priv->txhostdesc_startphy);
++ ACX_FREE_QUEUE(priv->txbuf_area_size, priv->txbuf_start, priv->txbuf_startphy);
++
++ priv->txdesc_start = NULL;
++
++ ACX_FREE_QUEUE(priv->rxhostdesc_area_size, priv->rxhostdesc_start, priv->rxhostdesc_startphy);
++ ACX_FREE_QUEUE(priv->rxbuf_area_size, priv->rxbuf_start, priv->rxbuf_startphy);
++
++ priv->rxdesc_start = NULL;
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_delete_dma_regions
++*----------------------------------------------------------------*/
++static void
++acx_s_delete_dma_regions(wlandevice_t *priv)
++{
++ unsigned long flags;
++
++ FN_ENTER;
++ /* disable radio Tx/Rx. Shouldn't we use the firmware commands
++ * here instead? Or are we that much down the road that it's no
++ * longer possible here? */
++ acx_write_reg16(priv, IO_ACX_ENABLE, 0);
++
++ acx_s_msleep(100);
++
++ acx_lock(priv, flags);
++ acx_free_desc_queues(priv);
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_probe_pci
++*
++* Probe routine called when a PCI device w/ matching ID is found.
++* Here's the sequence:
++* - Allocate the PCI resources.
++* - Read the PCMCIA attribute memory to make sure we have a WLAN card
++* - Reset the MAC
++* - Initialize the dev and wlan data
++* - Initialize the MAC
++*
++* Arguments:
++* pdev ptr to pci device structure containing info about
++* pci configuration.
++* id ptr to the device id entry that matched this device.
++*
++* Returns:
++* zero - success
++* negative - failed
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++static const u16
++IO_ACX100[] =
++{
++ 0x0000, /* IO_ACX_SOFT_RESET */
++
++ 0x0004, /* IO_ACX_HW_SLAVE_REG_ADDR */
++ 0x0008, /* IO_ACX_HW_SLAVE_REG_DATA */
++ 0x000c, /* IO_ACX_HW_SLAVE_REG_REG_CTRL */
++
++ 0x0014, /* IO_ACX_SLV_MEM_ADDR */
++ 0x0018, /* IO_ACX_SLV_MEM_DATA */
++ 0x001c, /* IO_ACX_SLV_MEM_CTL */
++ 0x0020, /* IO_ACX_SLV_END_CTL */
++ 0x0024, /* IO_ACX_CHIPID */
++
++ 0x0034, /* IO_ACX_FEMR */
++
++ 0x007c, /* IO_ACX_INT_TRIG */
++ 0x0098, /* IO_ACX_IRQ_MASK */
++ 0x00a4, /* IO_ACX_IRQ_STATUS_NON_DES */
++ 0x00a8, /* IO_ACX_IRQ_STATUS_CLEAR */
++ 0x00ac, /* IO_ACX_IRQ_ACK */
++ 0x00b0, /* IO_ACX_HINT_TRIG */
++
++ 0x0104, /* IO_ACX_ENABLE */
++
++ 0x0250, /* IO_ACX_EEPROM_CTL */
++ 0x0254, /* IO_ACX_EEPROM_ADDR */
++ 0x0258, /* IO_ACX_EEPROM_DATA */
++ 0x025c, /* IO_ACX_EEPROM_CFG */
++
++ 0x0268, /* IO_ACX_PHY_ADDR */
++ 0x026c, /* IO_ACX_PHY_DATA */
++ 0x0270, /* IO_ACX_PHY_CTL */
++
++ 0x0290, /* IO_ACX_GPIO_OE */
++
++ 0x0294, /* IO_ACX_GPIO_IN */
++ 0x0298, /* IO_ACX_GPIO_OUT */
++ 0x029c, /* IO_ACX_GPIO_PD */
++ 0x02a0, /* IO_ACX_GPIO_CFG */
++
++ 0x02a4, /* IO_ACX_CMD_MAILBOX_OFFS */
++ 0x02a8, /* IO_ACX_INFO_MAILBOX_OFFS */
++ 0x02ac, /* IO_ACX_EEPROM_INFORMATION */
++
++ 0x02d0, /* IO_ACX_EE_START */
++ 0x02d4, /* IO_ACX_SOR_CFG */
++ 0x02d8, /* IO_ACX_ECPU_CTRL */
++
++ 0x0804, /* IO_ACX_HI_CTL */
++ 0x0808, /* IO_ACX_LPWR_MGN */
++
++ 0x010c, /* IO_ACX_PCI_ARB_CFG */
++
++};
++
++static void
++acx_netdev_init(struct net_device *dev) {}
++
++//FIXME: do the same for USB
++static int
++acx_change_mtu(struct net_device *dev, int mtu)
++{
++ enum {
++ MIN_MTU = 256,
++ MAX_MTU = WLAN_DATA_MAXLEN - (ETH_HLEN)
++ };
++
++ if (mtu < MIN_MTU || mtu > MAX_MTU)
++ return -EINVAL;
++
++ dev->mtu = mtu;
++ return 0;
++}
++
++
++static int acx_enable(struct platform_device *pdev){
++ unsigned long flags;
++
++ /* We need to disabe the interrupt
++ * around reset.
++ */
++ local_irq_save(flags);
++
++ /* Now lets turn on and
++ * reset the device.
++ */
++ pca9535_gpio_write(GPIO6, LOW);
++ pca9535_gpio_write(GPIO12, LOW);
++
++ /* TODO: someother configuration needs
++ * to be done here.
++ */
++
++ // Now we can enable interrupt.
++ local_irq_restore(flags);
++
++
++ return 0;
++}
++
++static inline void test(wlandevice_t *priv) {
++ printk("===============================\n");
++ printk("Reset : %04x\n",acx_read_reg16(priv, IO_ACX_SOFT_RESET));
++ printk("eCPU CTL: %04x\n",acx_read_reg16(priv, IO_ACX_ECPU_CTRL));
++ printk("SOR CFG : %08x\n",acx_read_reg32(priv, IO_ACX_SOR_CFG));
++ printk("EE START: %08x\n",acx_read_reg32(priv, IO_ACX_EE_START));
++ printk("HI CTRL : %08x\n",acx_read_reg32(priv, IO_ACX_HI_CTRL));
++// printk("Info : %08x\n",acx_read_reg32(priv, IO_ACX_EEPROM_INFORMATION));
++ printk("GPIO OE : %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_OE));
++ printk("GPIO OUT: %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_OUT));
++ printk("GPIO IN : %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_IN));
++ printk("GPIO PD : %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_PD));
++ printk("GPIO CFG: %04x\n",acx_read_reg16(priv, IO_ACX_GPIO_CFG));
++ printk("Chip ID : %08x\n",acx_read_reg32(priv, IO_ACX_CHIPID));
++
++/*
++ printk("HW CTRL : %08x\n",acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_CTRL));
++ printk("HW ADDR : %08x\n",acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_ADDR));
++ printk("HW DATA : %08x\n",acx_read_reg32(priv,IO_ACX_HW_SLAVE_REG_DATA));
++*/
++
++ msleep(50);
++
++ printk("==============================\n");
++}
++
++static int __init acx_probe(struct net_device *ndev, void __iomem *addr, struct resource *res){
++ wlandevice_t *priv = netdev_priv(ndev);
++ int ret = 0;
++
++ ether_setup(ndev);
++
++ /* now that device init was successful, fill remaining fields... */
++ ndev->open = &acx_e_open;
++ ndev->stop = &acx_e_close;
++ ndev->hard_start_xmit = &acx_i_start_xmit;
++ ndev->get_stats = &acx_e_get_stats;
++ ndev->get_wireless_stats = &acx_e_get_wireless_stats;
++#if WIRELESS_EXT >= 13
++ ndev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
++#else
++ ndev->do_ioctl = &acx_e_ioctl_old;
++#endif
++ ndev->set_multicast_list = &acx_i_set_multicast_list;
++ ndev->tx_timeout = &acx_i_tx_timeout;
++ ndev->change_mtu = &acx_change_mtu;
++ ndev->watchdog_timeo = 4 * HZ;
++
++ spin_lock_init(&priv->lock); /* initial state: unlocked */
++ /* We do not start with downed sem: we want PARANOID_LOCKING to work */
++ sema_init(&priv->sem, 1); /* initial state: 1 (upped) */
++
++ priv->iobase = (unsigned char *) addr;
++ priv->iobase2 = 0;
++ priv->membase = res->start;
++ priv->chip_type = CHIPTYPE_ACX100;
++ priv->chip_name = name_acx100;
++ priv->io = IO_ACX100;
++ priv->mgmt_timer.function = (void (*)(unsigned long))0x0000dead;
++ spin_lock_init(&priv->lock);
++
++ test(priv);
++
++#ifdef NONESSENTIAL_FEATURES
++ acx_show_card_eeprom_id(priv);
++#endif /* NONESSENTIAL_FEATURES */
++
++ /* now we have our device, so make sure the kernel doesn't try
++ * to send packets even though we're not associated to a network yet */
++ acx_stop_queue(ndev, "after setup");
++
++ /* register new dev in linked list */
++ acx_s_device_chain_add(ndev);
++
++ if((ret = acx_s_reset_dev(ndev)) != OK){
++ /* Failed to reset device */
++ ret = -EIO;
++ goto reset_fail;
++ }
++
++ /* ok, basic setup is finished, now start initialising the card */
++#if 0
++ hardware_info = acx_read_reg16(priv, IO_ACX_EEPROM_INFORMATION);
++ priv->form_factor = (u8)(hardware_info & 0xff);
++ priv->radio_type = (u8)(hardware_info >> 8 & 0xff);
++#endif
++
++ if (OK != acx_read_eeprom_offset(priv, 0x05, &priv->eeprom_version)) {
++ ret = -EIO;
++ goto fail_read_eeprom_version;
++ }
++
++ if (OK != acx_s_init_mac(ndev)) {
++ acxlog(L_DEBUG | L_INIT,
++ "Danger Will Robinson, MAC did not come back\n");
++ ret = -EIO;
++ goto fail_init_mac;
++ }
++
++ if (OK != acx_s_set_defaults(priv)) {
++ printk("acx: set_defaults() FAILED\n");
++ goto fail_set_defaults;
++ }
++
++ /* needs to be after acx_init_mac() due to necessary init stuff */
++ acx_s_get_firmware_version(priv);
++
++ acx_display_hardware_details(priv);
++
++ /* ...and register the card, AFTER everything else has been set up,
++ * since otherwise an ioctl could step on our feet due to
++ * firmware operations happening in parallel or uninitialized data */
++ ret = register_netdev(ndev);
++ if (OK != ret) {
++ printk(KERN_ERR
++ "%s: Register net device of %s FAILED: %d\n",
++ __func__, ndev->name, ret);
++ ret = -EIO;
++ goto fail_register_netdev;
++ }
++ acx_carrier_off(ndev, "on probe");
++
++#ifdef CONFIG_PROC_FS
++ if (OK != acx_proc_register_entries(ndev)) {
++ ret = -EIO;
++ goto fail_proc_register_entries;
++ }
++#endif
++
++#if CMD_DISCOVERY
++ great_inquisitor(priv);
++#endif
++
++
++ return 0;
++
++#ifdef CONFIG_PROC_FS
++fail_proc_register_entries:
++#endif
++
++ if (priv->dev_state_mask & ACX_STATE_IFACE_UP)
++ acx_s_down(ndev);
++ unregister_netdev(ndev);
++
++fail_register_netdev:
++ acx_s_delete_dma_regions(priv);
++fail_set_defaults:
++fail_init_mac:
++fail_read_eeprom_version:
++reset_fail:
++ acx_s_device_chain_remove(ndev);
++
++ return ret;
++}
++
++static void dumpRegs(char *msg, unsigned char *base) {
++ u32 val = 0;
++ u16 addr = 0;
++
++ printk("============= [ %s ] ===============\n",msg);
++
++ for(addr = 0; addr <= 0x0be0; addr+=4){
++ if(addr >= 0x0710 && addr <= 0x0740){
++ val = 0;
++ printk("Reg[%04x] : %08x\n",addr, val);
++ msleep(50);
++ continue;
++ }
++
++ val = readw((u8 *) base + addr) + (readw((u8 *) base + addr + 2) << 16);
++
++ printk("Reg[%04x] : %08x\n",addr, val);
++ msleep(50);
++ }
++
++ printk("=====================================\n");
++}
++
++
++static int __init acx_drv_probe(struct device *dev){
++ struct platform_device *pdev = to_platform_device(dev);
++ struct net_device *ndev = NULL;
++ struct resource *res = NULL;
++ unsigned int __iomem *addr = NULL;
++ wlandevice_t *priv = NULL;
++ int ret;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ printk(KERN_ERR "Device not found\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++
++ if (!request_mem_region(res->start, SZ_32M, CARDNAME)) {
++ printk(KERN_ERR "Device busy\n");
++ ret = -EBUSY;
++ goto out;
++ }
++
++ // Create new ethernet device
++ ndev = alloc_netdev(sizeof(wlandevice_t), "wlan%d", acx_netdev_init);
++ if (!ndev) {
++ printk("%s: could not allocate device.\n", CARDNAME);
++ ret = -ENOMEM;
++ goto out_release_io;
++ }
++ SET_MODULE_OWNER(ndev);
++ SET_NETDEV_DEV(ndev, dev);
++
++ // Get driver private data
++ priv = netdev_priv(ndev);
++
++ // Cleanup the private area
++ memset((void *) priv, 0, sizeof(wlandevice_t));
++
++ ndev->dma = (unsigned char)-1;
++ ndev->irq = platform_get_irq(pdev, 0);
++ priv->dev = dev;
++
++ // Enable device
++ acx_enable(pdev);
++
++ /* Create IOMEM port so we
++ * can use to to read and write
++ * from card registers.
++ */
++ if(!(addr = ioremap(res->start, SZ_32M))){
++ printk(KERN_ERR "Failed to map ioport\n");
++ ret = -ENOMEM;
++ goto free_device;
++ }
++
++ dev_set_drvdata(dev, ndev);
++
++ //dumpRegs("After",addr);
++
++
++ if((ret = acx_probe(ndev, addr,res))){
++ /* Something wrong we couldn't
++ * talke to the device.
++ */
++ printk(KERN_ERR "Failed to probe ACX\n");
++ goto out_iounmap;
++ }
++
++ printk("acx "WLAN_RELEASE": net device %s, driver compiled "
++ "against wireless extensions %d and Linux %s\n",
++ ndev->name, WIRELESS_EXT, UTS_RELEASE);
++
++ return 0;
++
++out_iounmap:
++ dev_set_drvdata(dev, NULL);
++ iounmap(addr);
++free_device:
++ free_netdev(ndev);
++out_release_io:
++ release_mem_region(res->start, SZ_32M);
++out:
++ return ret;
++}
++
++static int acx_remove(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct net_device *ndev = (dev? dev_get_drvdata(dev) : NULL);
++ wlandevice_t *priv = (ndev? (wlandevice_t *) netdev_priv(ndev) : NULL);
++ struct resource *res = NULL;
++
++ if(!ndev){
++ printk(KERN_ERR "Invalid network device structure\n");
++ return 0;
++ }
++
++ dev_set_drvdata(dev, NULL);
++ unregister_netdev(ndev);
++
++#if 0
++ free_irq(ndev->irq, ndev);
++#endif
++
++ iounmap(priv->iobase);
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(res->start, SZ_32M);
++
++ free_netdev(ndev);
++
++ return 0;
++}
++
++/***********************************************************************
++*/
++#ifdef CONFIG_PM
++static int if_was_up = 0; /* FIXME: HACK, do it correctly sometime instead */
++static int
++acx_suspend(struct device *dev, pm_message_t state, u32 level)
++{
++#if 0
++ struct net_device *ndev = pci_get_drvdata(pdev);
++ wlandevice_t *priv = netdev_priv(dev);
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ printk("acx: experimental suspend handler called for %p\n", priv);
++ if (netif_device_present(ndev)) {
++ if_was_up = 1;
++ acx_s_down(ndev);
++ }
++ else
++ if_was_up = 0;
++
++ netif_device_detach(ndev); /* This one cannot sleep */
++ acx_s_delete_dma_regions(priv);
++
++ acx_sem_unlock(priv);
++
++ FN_EXIT0;
++#endif
++ return OK;
++}
++
++static int
++acx_resume(struct device *dev, u32 level)
++{
++#if 0
++ struct platform_device *pdev = to_platform_device(dev);
++ struct net_device *ndev;
++ wlandevice_t *priv;
++
++ printk(KERN_WARNING "rsm: resume\n");
++ ndev = dev_get_drvdata(dev);
++ printk(KERN_WARNING "rsm: got dev\n");
++
++ if (!netif_running(ndev))
++ return 0;
++
++ priv = netdev_priv(ndev);
++
++ acx_sem_lock(priv);
++
++ printk(KERN_WARNING "rsm: got priv\n");
++ FN_ENTER;
++ printk("acx: experimental resume handler called for %p!\n", priv);
++ // TODO
++ acxlog(L_DEBUG, "rsm: power state set\n");
++
++ acxlog(L_DEBUG, "rsm: PCI state restored\n");
++ acx_s_reset_dev(ndev);
++ acxlog(L_DEBUG, "rsm: device reset done\n");
++
++ if (OK != acx_s_init_mac(ndev)) {
++ printk("rsm: init_mac FAILED\n");
++ goto fail;
++ }
++ acxlog(L_DEBUG, "rsm: init MAC done\n");
++
++ if (1 == if_was_up)
++ acx_s_up(ndev);
++ acxlog(L_DEBUG, "rsm: acx up\n");
++
++ /* now even reload all card parameters as they were before suspend,
++ * and possibly be back in the network again already :-)
++ * FIXME: should this be done in that scheduled task instead?? */
++ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
++ acx_s_update_card_settings(priv, 0, 1);
++ acxlog(L_DEBUG, "rsm: settings updated\n");
++ netif_device_attach(ndev);
++ acxlog(L_DEBUG, "rsm: device attached\n");
++fail: /* we need to return OK here anyway, right? */
++ acx_sem_unlock(priv);
++ FN_EXIT0;
++#endif
++ return OK;
++}
++#endif /* CONFIG_PM */
++
++
++/*----------------------------------------------------------------
++* acx_s_up
++*
++* Side effects:
++* - Enables on-card interrupt requests
++* - calls acx_start
++* Call context:
++* - process thread
++* Comment:
++* This function is called by acx_open (when ifconfig sets the
++* device as up).
++*----------------------------------------------------------------*/
++static void
++acx_s_up(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++ acx_l_enable_irq(priv);
++ acx_unlock(priv, flags);
++
++ /* acx fw < 1.9.3.e has a hardware timer, and older drivers
++ ** used to use it. But we don't do that anymore, our OS
++ ** has reliable software timers */
++ init_timer(&priv->mgmt_timer);
++ priv->mgmt_timer.function = acx_i_timer;
++ priv->mgmt_timer.data = (unsigned long)priv;
++
++ /* Need to set ACX_STATE_IFACE_UP first, or else
++ ** timer won't be started by acx_set_status() */
++ SET_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ /* actual scan cmd will happen in start() */
++ acx_set_status(priv, ACX_STATUS_1_SCANNING); break;
++ case ACX_MODE_3_AP:
++ case ACX_MODE_MONITOR:
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED); break;
++ }
++
++ acx_s_start(priv);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_down
++*
++* Side effects:
++* - disables on-card interrupt request
++* Call context:
++* process thread
++* Comment:
++* this disables the netdevice
++*----------------------------------------------------------------*/
++static void
++acx_s_down(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++
++ FN_ENTER;
++
++ /* Disable IRQs first, so that IRQs cannot race with us */
++ acx_lock(priv, flags);
++ acx_l_disable_irq(priv);
++ acx_unlock(priv, flags);
++
++ /* we really don't want to have an asynchronous tasklet disturb us
++ ** after something vital for its job has been shut down, so
++ ** end all remaining work now.
++ **
++ ** NB: carrier_off (done by set_status below) would lead to
++ ** not yet fully understood deadlock in FLUSH_SCHEDULED_WORK().
++ ** That's why we do FLUSH first.
++ **
++ ** NB2: we have a bad locking bug here: FLUSH_SCHEDULED_WORK()
++ ** waits for acx_e_after_interrupt_task to complete if it is running
++ ** on another CPU, but acx_e_after_interrupt_task
++ ** will sleep on sem forever, because it is taken by us!
++ ** Work around that by temporary sem unlock.
++ ** This will fail miserably if we'll be hit by concurrent
++ ** iwconfig or something in between. TODO! */
++ acx_sem_unlock(priv);
++ FLUSH_SCHEDULED_WORK();
++ acx_sem_lock(priv);
++
++ /* This is possible:
++ ** FLUSH_SCHEDULED_WORK -> acx_e_after_interrupt_task ->
++ ** -> set_status(ASSOCIATED) -> wake_queue()
++ ** That's why we stop queue _after_ FLUSH_SCHEDULED_WORK
++ ** lock/unlock is just paranoia, maybe not needed */
++ acx_lock(priv, flags);
++ acx_stop_queue(dev, "during close");
++ acx_set_status(priv, ACX_STATUS_0_STOPPED);
++ acx_unlock(priv, flags);
++
++ /* kernel/timer.c says it's illegal to del_timer_sync()
++ ** a timer which restarts itself. We guarantee this cannot
++ ** ever happen because acx_i_timer() never does this if
++ ** status is ACX_STATUS_0_STOPPED */
++ del_timer_sync(&priv->mgmt_timer);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_open
++*
++* WLAN device open method. Called from p80211netdev when kernel
++* device open (start) method is called in response to the
++* SIOCSIFFLAGS ioctl changing the flags bit IFF_UP
++* from clear to set.
++*
++* Returns:
++* 0 success
++* >0 f/w reported error
++* <0 driver reported error
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++static int
++acx_e_open(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result = OK;
++
++ FN_ENTER;
++
++ acxlog(L_INIT, "module count++\n");
++ WLAN_MOD_INC_USE_COUNT;
++
++ acx_sem_lock(priv);
++
++ acx_init_task_scheduler(priv);
++
++ /* request shared IRQ handler */
++ if (request_irq(dev->irq, acx_i_interrupt, SA_SHIRQ, dev->name, dev)) {
++ printk("%s: request_irq FAILED\n", dev->name);
++ result = -EAGAIN;
++ goto done;
++ }
++ acxlog(L_DEBUG|L_IRQ, "request_irq %d successful\n", dev->irq);
++
++ /* ifup device */
++ acx_s_up(dev);
++
++ /* We don't currently have to do anything else.
++ * The setup of the MAC should be subsequently completed via
++ * the mlme commands.
++ * Higher layers know we're ready from dev->start==1 and
++ * dev->tbusy==0. Our rx path knows to pass up received/
++ * frames because of dev->flags&IFF_UP is true.
++ */
++done:
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_close
++*
++* WLAN device close method. Called from network core when kernel
++* device close method is called in response to the
++* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
++* from set to clear.
++* (i.e. called for "ifconfig DEV down")
++*
++* Returns:
++* 0 success
++* >0 f/w reported error
++* <0 driver reported error
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++static int
++acx_e_close(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ /* ifdown device */
++ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
++ if (netif_device_present(dev)) {
++ acx_s_down(dev);
++ }
++
++ /* disable all IRQs, release shared IRQ handler */
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
++ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
++ free_irq(dev->irq, dev);
++
++ /* We currently don't have to do anything else.
++ * Higher layers know we're not ready from dev->start==0 and
++ * dev->tbusy==1. Our rx path knows to not pass up received
++ * frames because of dev->flags&IFF_UP is false.
++ */
++ acxlog(L_INIT, "module count--\n");
++ WLAN_MOD_DEC_USE_COUNT;
++
++ acx_sem_unlock(priv);
++
++ acxlog(L_INIT, "closed device\n");
++ FN_EXIT0;
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_i_tx_timeout
++*
++* Called from network core. Must not sleep!
++*----------------------------------------------------------------*/
++static void
++acx_i_tx_timeout(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ unsigned int tx_num_cleaned;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++
++ /* clean processed tx descs, they may have been completely full */
++ tx_num_cleaned = acx_l_clean_tx_desc(priv);
++
++ /* nothing cleaned, yet (almost) no free buffers available?
++ * --> clean all tx descs, no matter which status!!
++ * Note that I strongly suspect that doing emergency cleaning
++ * may confuse the firmware. This is a last ditch effort to get
++ * ANYTHING to work again...
++ *
++ * TODO: it's best to simply reset & reinit hw from scratch...
++ */
++ if ((priv->tx_free <= TX_EMERG_CLEAN) && (tx_num_cleaned == 0)) {
++ printk("%s: FAILED to free any of the many full tx buffers. "
++ "Switching to emergency freeing. "
++ "Please report!\n", dev->name);
++ acx_l_clean_tx_desc_emergency(priv);
++ }
++
++ if (acx_queue_stopped(dev) && (ACX_STATUS_4_ASSOCIATED == priv->status))
++ acx_wake_queue(dev, "after tx timeout");
++
++ /* stall may have happened due to radio drift, so recalib radio */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
++
++ /* do unimportant work last */
++ printk("%s: tx timeout!\n", dev->name);
++ priv->stats.tx_errors++;
++
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_get_stats
++*----------------------------------------------------------------*/
++static struct net_device_stats*
++acx_e_get_stats(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ return &priv->stats;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_get_wireless_stats
++*----------------------------------------------------------------*/
++static struct iw_statistics*
++acx_e_get_wireless_stats(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ return &priv->wstats;
++}
++
++
++/*----------------------------------------------------------------
++* acx_i_set_multicast_list
++* FIXME: most likely needs refinement
++*----------------------------------------------------------------*/
++static void
++acx_i_set_multicast_list(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++
++ /* firmwares don't have allmulti capability,
++ * so just use promiscuous mode instead in this case. */
++ if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
++ SET_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
++ CLEAR_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
++ SET_BIT(priv->set_mask, SET_RXCONFIG);
++ /* let kernel know in case *we* needed to set promiscuous */
++ dev->flags |= (IFF_PROMISC|IFF_ALLMULTI);
++ } else {
++ CLEAR_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
++ SET_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
++ SET_BIT(priv->set_mask, SET_RXCONFIG);
++ dev->flags &= ~(IFF_PROMISC|IFF_ALLMULTI);
++ }
++
++ /* cannot update card settings directly here, atomic context */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
++
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++
++static void
++acx_l_update_link_quality_led(wlandevice_t *priv)
++{
++ int qual;
++
++ qual = acx_signal_determine_quality(priv->wstats.qual.level, priv->wstats.qual.noise);
++ if (qual > priv->brange_max_quality)
++ qual = priv->brange_max_quality;
++
++ if (time_after(jiffies, priv->brange_time_last_state_change +
++ (HZ/2 - HZ/2 * (unsigned long) qual/priv->brange_max_quality ) )) {
++ acx_l_power_led(priv, (priv->brange_last_state == 0));
++ priv->brange_last_state ^= 1; /* toggle */
++ priv->brange_time_last_state_change = jiffies;
++ }
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_enable_irq
++*----------------------------------------------------------------*/
++static void
++acx_l_enable_irq(wlandevice_t *priv)
++{
++ FN_ENTER;
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask);
++ acx_write_reg16(priv, IO_ACX_FEMR, 0x8000);
++ priv->irqs_active = 1;
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_disable_irq
++*----------------------------------------------------------------*/
++static void
++acx_l_disable_irq(wlandevice_t *priv)
++{
++ FN_ENTER;
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask_off);
++ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
++ priv->irqs_active = 0;
++ FN_EXIT0;
++}
++
++/* scan is complete. all frames now on the receive queue are valid */
++#define INFO_SCAN_COMPLETE 0x0001
++#define INFO_WEP_KEY_NOT_FOUND 0x0002
++/* hw has been reset as the result of a watchdog timer timeout */
++#define INFO_WATCH_DOG_RESET 0x0003
++/* failed to send out NULL frame from PS mode notification to AP */
++/* recommended action: try entering 802.11 PS mode again */
++#define INFO_PS_FAIL 0x0004
++/* encryption/decryption process on a packet failed */
++#define INFO_IV_ICV_FAILURE 0x0005
++
++static void
++acx_l_handle_info_irq(wlandevice_t *priv)
++{
++#if ACX_DEBUG
++ static const char * const info_type_msg[] = {
++ "(unknown)",
++ "scan complete",
++ "WEP key not found",
++ "internal watchdog reset was done",
++ "failed to send powersave (NULL frame) notification to AP",
++ "encrypt/decrypt on a packet has failed",
++ "TKIP tx keys disabled",
++ "TKIP rx keys disabled",
++ "TKIP rx: key ID not found",
++ "???",
++ "???",
++ "???",
++ "???",
++ "???",
++ "???",
++ "???",
++ "TKIP IV value exceeds thresh"
++ };
++#endif
++ acx_read_info_status(priv);
++ acxlog(L_IRQ, "got Info IRQ: status 0x%04X type 0x%04X: %s\n",
++ priv->info_status, priv->info_type,
++ info_type_msg[(priv->info_type >= VEC_SIZE(info_type_msg)) ?
++ 0 : priv->info_type]
++ );
++}
++
++
++/*----------------------------------------------------------------
++* acx_i_interrupt
++*
++* IRQ handler (atomic context, must not sleep, blah, blah)
++*----------------------------------------------------------------*/
++static void
++acx_log_unusual_irq(u16 irqtype) {
++ /*
++ if (!printk_ratelimit())
++ return;
++ */
++
++ printk("acx: got");
++ if (irqtype & HOST_INT_RX_DATA) {
++ printk(" Rx_Data");
++ }
++ /* HOST_INT_TX_COMPLETE */
++ if (irqtype & HOST_INT_TX_XFER) {
++ printk(" Tx_Xfer");
++ }
++ /* HOST_INT_RX_COMPLETE */
++ if (irqtype & HOST_INT_DTIM) {
++ printk(" DTIM");
++ }
++ if (irqtype & HOST_INT_BEACON) {
++ printk(" Beacon");
++ }
++ if (irqtype & HOST_INT_TIMER) {
++ acxlog(L_IRQ, " Timer");
++ }
++ if (irqtype & HOST_INT_KEY_NOT_FOUND) {
++ printk(" Key_Not_Found");
++ }
++ if (irqtype & HOST_INT_IV_ICV_FAILURE) {
++ printk(" IV_ICV_Failure");
++ }
++ /* HOST_INT_CMD_COMPLETE */
++ /* HOST_INT_INFO */
++ if (irqtype & HOST_INT_OVERFLOW) {
++ printk(" Overflow");
++ }
++ if (irqtype & HOST_INT_PROCESS_ERROR) {
++ printk(" Process_Error");
++ }
++ /* HOST_INT_SCAN_COMPLETE */
++ if (irqtype & HOST_INT_FCS_THRESHOLD) {
++ printk(" FCS_Threshold");
++ }
++ if (irqtype & HOST_INT_UNKNOWN) {
++ printk(" Unknown");
++ }
++ printk(" IRQ(s)\n");
++}
++
++static irqreturn_t
++acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ wlandevice_t *priv;
++ unsigned long flags;
++ unsigned int irqcount = MAX_IRQLOOPS_PER_JIFFY;
++ u16 irqtype, unmasked;
++
++ priv = (wlandevice_t *) (((netdevice_t *) dev_id)->priv);
++
++ /* LOCKING: can just spin_lock() since IRQs are disabled anyway.
++ * I am paranoid */
++ acx_lock(priv, flags);
++
++ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
++ if (unlikely(0xffff == unmasked)) {
++ /* 0xffff value hints at missing hardware,
++ * so don't do anything.
++ * FIXME: that's not very clean - maybe we are able to
++ * establish a flag which definitely tells us that some
++ * hardware is absent and which we could check here?
++ * Hmm, but other drivers do the very same thing... */
++ acxlog(L_IRQ, "IRQ type:FFFF - device removed? IRQ_NONE\n");
++ goto none;
++ }
++
++ /* We will check only "interesting" IRQ types */
++ irqtype = unmasked & ~priv->irq_mask;
++ if (!irqtype) {
++ /* We are on a shared IRQ line and it wasn't our IRQ */
++ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X - all are masked, IRQ_NONE\n",
++ unmasked, priv->irq_mask);
++ goto none;
++ }
++
++ /* Done here because IRQ_NONEs taking three lines of log
++ ** drive me crazy */
++ FN_ENTER;
++
++#define IRQ_ITERATE 1
++#if IRQ_ITERATE
++if (jiffies != priv->irq_last_jiffies) {
++ priv->irq_loops_this_jiffy = 0;
++ priv->irq_last_jiffies = jiffies;
++}
++
++/* safety condition; we'll normally abort loop below
++ * in case no IRQ type occurred */
++while (--irqcount) {
++#endif
++ /* ACK all IRQs asap */
++ acx_write_reg16(priv, IO_ACX_IRQ_ACK, 0xffff);
++
++ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X, type & ~mask:%04X\n",
++ unmasked, priv->irq_mask, irqtype);
++
++ /* Handle most important IRQ types first */
++ if (irqtype & HOST_INT_RX_COMPLETE) {
++ acxlog(L_IRQ, "got Rx_Complete IRQ\n");
++ acx_l_process_rx_desc(priv);
++ }
++ if (irqtype & HOST_INT_TX_COMPLETE) {
++ acxlog(L_IRQ, "got Tx_Complete IRQ\n");
++ /* don't clean up on each Tx complete, wait a bit
++ * unless we're going towards full, in which case
++ * we do it immediately, too (otherwise we might lockup
++ * with a full Tx buffer if we go into
++ * acx_l_clean_tx_desc() at a time when we won't wakeup
++ * the net queue in there for some reason...) */
++ if (priv->tx_free <= TX_START_CLEAN) {
++#if TX_CLEANUP_IN_SOFTIRQ
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_TX_CLEANUP);
++#else
++ acx_l_clean_tx_desc(priv);
++#endif
++ }
++ }
++
++ /* Less frequent ones */
++ if (irqtype & (0
++ | HOST_INT_CMD_COMPLETE
++ | HOST_INT_INFO
++ | HOST_INT_SCAN_COMPLETE
++ )) {
++ if (irqtype & HOST_INT_CMD_COMPLETE) {
++ acxlog(L_IRQ, "got Command_Complete IRQ\n");
++ /* save the state for the running issue_cmd() */
++ SET_BIT(priv->irq_status, HOST_INT_CMD_COMPLETE);
++ }
++ if (irqtype & HOST_INT_INFO) {
++ acx_l_handle_info_irq(priv);
++ }
++ if (irqtype & HOST_INT_SCAN_COMPLETE) {
++ acxlog(L_IRQ, "got Scan_Complete IRQ\n");
++ /* need to do that in process context */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_COMPLETE_SCAN);
++ /* remember that fw is not scanning anymore */
++ SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
++ }
++ }
++
++ /* These we just log, but either they happen rarely
++ * or we keep them masked out */
++ if (irqtype & (0
++ | HOST_INT_RX_DATA
++ /* | HOST_INT_TX_COMPLETE */
++ | HOST_INT_TX_XFER
++ /* | HOST_INT_RX_COMPLETE */
++ | HOST_INT_DTIM
++ | HOST_INT_BEACON
++ | HOST_INT_TIMER
++ | HOST_INT_KEY_NOT_FOUND
++ | HOST_INT_IV_ICV_FAILURE
++ /* | HOST_INT_CMD_COMPLETE */
++ /* | HOST_INT_INFO */
++ | HOST_INT_OVERFLOW
++ | HOST_INT_PROCESS_ERROR
++ /* | HOST_INT_SCAN_COMPLETE */
++ | HOST_INT_FCS_THRESHOLD
++ | HOST_INT_UNKNOWN
++ )) {
++ acx_log_unusual_irq(irqtype);
++ }
++
++#if IRQ_ITERATE
++ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
++ irqtype = unmasked & ~priv->irq_mask;
++ /* Bail out if no new IRQ bits or if all are masked out */
++ if (!irqtype)
++ break;
++
++ if (unlikely(++priv->irq_loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY)) {
++ printk(KERN_ERR "acx: too many interrupts per jiffy!\n");
++ /* Looks like card floods us with IRQs! Try to stop that */
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
++ /* This will short-circuit all future attempts to handle IRQ.
++ * We cant do much more... */
++ priv->irq_mask = 0;
++ break;
++ }
++}
++#endif
++ /* Routine to perform blink with range */
++ if (unlikely(priv->led_power == 2))
++ acx_l_update_link_quality_led(priv);
++
++/* handled: */
++ /* acx_write_flush(priv); - not needed, last op was read anyway */
++ acx_unlock(priv, flags);
++ FN_EXIT0;
++ return IRQ_HANDLED;
++
++none:
++ acx_unlock(priv, flags);
++ return IRQ_NONE;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_power_led
++*----------------------------------------------------------------*/
++void
++acx_l_power_led(wlandevice_t *priv, int enable)
++{
++ u16 gpio_pled = IS_ACX111(priv) ? 0x0040 : 0x0800;
++
++ /* A hack. Not moving message rate limiting to priv->xxx
++ * (it's only a debug message after all) */
++ static int rate_limit = 0;
++
++ if (rate_limit++ < 3)
++ acxlog(L_IOCTL, "Please report in case toggling the power "
++ "LED doesn't work for your card!\n");
++ if (enable)
++ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
++ acx_read_reg16(priv, IO_ACX_GPIO_OUT) & ~gpio_pled);
++ else
++ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
++ acx_read_reg16(priv, IO_ACX_GPIO_OUT) | gpio_pled);
++}
++
++
++/***********************************************************************
++** Ioctls
++*/
++
++/***********************************************************************
++*/
++int
++acx111pci_ioctl_info(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++#if ACX_DEBUG
++ wlandevice_t *priv = netdev_priv(dev);
++ rxdesc_t *rxdesc;
++ txdesc_t *txdesc;
++ rxhostdesc_t *rxhostdesc;
++ txhostdesc_t *txhostdesc;
++ struct acx111_ie_memoryconfig memconf;
++ struct acx111_ie_queueconfig queueconf;
++ unsigned long flags;
++ int i;
++ char memmap[0x34];
++ char rxconfig[0x8];
++ char fcserror[0x8];
++ char ratefallback[0x5];
++
++ if ( !(acx_debug & (L_IOCTL|L_DEBUG)) )
++ return OK;
++ /* using printk() since we checked debug flag already */
++
++ acx_sem_lock(priv);
++
++ if (!IS_ACX111(priv)) {
++ printk("acx111-specific function called "
++ "with non-acx111 chip, aborting\n");
++ goto end_ok;
++ }
++
++ /* get Acx111 Memory Configuration */
++ memset(&memconf, 0, sizeof(memconf));
++ /* BTW, fails with 12 (Write only) error code.
++ ** Retained for easy testing of issue_cmd error handling :) */
++ acx_s_interrogate(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG);
++
++ /* get Acx111 Queue Configuration */
++ memset(&queueconf, 0, sizeof(queueconf));
++ acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
++
++ /* get Acx111 Memory Map */
++ memset(memmap, 0, sizeof(memmap));
++ acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP);
++
++ /* get Acx111 Rx Config */
++ memset(rxconfig, 0, sizeof(rxconfig));
++ acx_s_interrogate(priv, &rxconfig, ACX1xx_IE_RXCONFIG);
++
++ /* get Acx111 fcs error count */
++ memset(fcserror, 0, sizeof(fcserror));
++ acx_s_interrogate(priv, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT);
++
++ /* get Acx111 rate fallback */
++ memset(ratefallback, 0, sizeof(ratefallback));
++ acx_s_interrogate(priv, &ratefallback, ACX1xx_IE_RATE_FALLBACK);
++
++ /* force occurrence of a beacon interrupt */
++ /* TODO: comment why is this necessary */
++ acx_write_reg16(priv, IO_ACX_HINT_TRIG, HOST_INT_BEACON);
++
++ /* dump Acx111 Mem Configuration */
++ printk("dump mem config:\n"
++ "data read: %d, struct size: %d\n"
++ "Number of stations: %1X\n"
++ "Memory block size: %1X\n"
++ "tx/rx memory block allocation: %1X\n"
++ "count rx: %X / tx: %X queues\n"
++ "options %1X\n"
++ "fragmentation %1X\n"
++ "Rx Queue 1 Count Descriptors: %X\n"
++ "Rx Queue 1 Host Memory Start: %X\n"
++ "Tx Queue 1 Count Descriptors: %X\n"
++ "Tx Queue 1 Attributes: %X\n",
++ memconf.len, (int) sizeof(memconf),
++ memconf.no_of_stations,
++ memconf.memory_block_size,
++ memconf.tx_rx_memory_block_allocation,
++ memconf.count_rx_queues, memconf.count_tx_queues,
++ memconf.options,
++ memconf.fragmentation,
++ memconf.rx_queue1_count_descs,
++ acx2cpu(memconf.rx_queue1_host_rx_start),
++ memconf.tx_queue1_count_descs,
++ memconf.tx_queue1_attributes);
++
++ /* dump Acx111 Queue Configuration */
++ printk("dump queue head:\n"
++ "data read: %d, struct size: %d\n"
++ "tx_memory_block_address (from card): %X\n"
++ "rx_memory_block_address (from card): %X\n"
++ "rx1_queue address (from card): %X\n"
++ "tx1_queue address (from card): %X\n"
++ "tx1_queue attributes (from card): %X\n",
++ queueconf.len, (int) sizeof(queueconf),
++ queueconf.tx_memory_block_address,
++ queueconf.rx_memory_block_address,
++ queueconf.rx1_queue_address,
++ queueconf.tx1_queue_address,
++ queueconf.tx1_attributes);
++
++ /* dump Acx111 Mem Map */
++ printk("dump mem map:\n"
++ "data read: %d, struct size: %d\n"
++ "Code start: %X\n"
++ "Code end: %X\n"
++ "WEP default key start: %X\n"
++ "WEP default key end: %X\n"
++ "STA table start: %X\n"
++ "STA table end: %X\n"
++ "Packet template start: %X\n"
++ "Packet template end: %X\n"
++ "Queue memory start: %X\n"
++ "Queue memory end: %X\n"
++ "Packet memory pool start: %X\n"
++ "Packet memory pool end: %X\n"
++ "iobase: %p\n"
++ "iobase2: %p\n",
++ *((u16 *)&memmap[0x02]), (int) sizeof(memmap),
++ *((u32 *)&memmap[0x04]),
++ *((u32 *)&memmap[0x08]),
++ *((u32 *)&memmap[0x0C]),
++ *((u32 *)&memmap[0x10]),
++ *((u32 *)&memmap[0x14]),
++ *((u32 *)&memmap[0x18]),
++ *((u32 *)&memmap[0x1C]),
++ *((u32 *)&memmap[0x20]),
++ *((u32 *)&memmap[0x24]),
++ *((u32 *)&memmap[0x28]),
++ *((u32 *)&memmap[0x2C]),
++ *((u32 *)&memmap[0x30]),
++ priv->iobase,
++ priv->iobase2);
++
++ /* dump Acx111 Rx Config */
++ printk("dump rx config:\n"
++ "data read: %d, struct size: %d\n"
++ "rx config: %X\n"
++ "rx filter config: %X\n",
++ *((u16 *)&rxconfig[0x02]), (int) sizeof(rxconfig),
++ *((u16 *)&rxconfig[0x04]),
++ *((u16 *)&rxconfig[0x06]));
++
++ /* dump Acx111 fcs error */
++ printk("dump fcserror:\n"
++ "data read: %d, struct size: %d\n"
++ "fcserrors: %X\n",
++ *((u16 *)&fcserror[0x02]), (int) sizeof(fcserror),
++ *((u32 *)&fcserror[0x04]));
++
++ /* dump Acx111 rate fallback */
++ printk("dump rate fallback:\n"
++ "data read: %d, struct size: %d\n"
++ "ratefallback: %X\n",
++ *((u16 *)&ratefallback[0x02]), (int) sizeof(ratefallback),
++ *((u8 *)&ratefallback[0x04]));
++
++ /* protect against IRQ */
++ acx_lock(priv, flags);
++
++ /* dump acx111 internal rx descriptor ring buffer */
++ rxdesc = priv->rxdesc_start;
++
++ /* loop over complete receive pool */
++ if (rxdesc) for (i = 0; i < RX_CNT; i++) {
++ printk("\ndump internal rxdesc %d:\n"
++ "mem pos %p\n"
++ "next 0x%X\n"
++ "acx mem pointer (dynamic) 0x%X\n"
++ "CTL (dynamic) 0x%X\n"
++ "Rate (dynamic) 0x%X\n"
++ "RxStatus (dynamic) 0x%X\n"
++ "Mod/Pre (dynamic) 0x%X\n",
++ i,
++ rxdesc,
++ acx2cpu(rxdesc->pNextDesc),
++ acx2cpu(rxdesc->ACXMemPtr),
++ rxdesc->Ctl_8,
++ rxdesc->rate,
++ rxdesc->error,
++ rxdesc->SNR);
++ rxdesc++;
++ }
++
++ /* dump host rx descriptor ring buffer */
++
++ rxhostdesc = priv->rxhostdesc_start;
++
++ /* loop over complete receive pool */
++ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
++ printk("\ndump host rxdesc %d:\n"
++ "mem pos %p\n"
++ "buffer mem pos 0x%X\n"
++ "buffer mem offset 0x%X\n"
++ "CTL 0x%X\n"
++ "Length 0x%X\n"
++ "next 0x%X\n"
++ "Status 0x%X\n",
++ i,
++ rxhostdesc,
++ acx2cpu(rxhostdesc->data_phy),
++ rxhostdesc->data_offset,
++ le16_to_cpu(rxhostdesc->Ctl_16),
++ le16_to_cpu(rxhostdesc->length),
++ acx2cpu(rxhostdesc->desc_phy_next),
++ rxhostdesc->Status);
++ rxhostdesc++;
++ }
++
++ /* dump acx111 internal tx descriptor ring buffer */
++ txdesc = priv->txdesc_start;
++
++ /* loop over complete transmit pool */
++ if (txdesc) for (i = 0; i < TX_CNT; i++) {
++ printk("\ndump internal txdesc %d:\n"
++ "size 0x%X\n"
++ "mem pos %p\n"
++ "next 0x%X\n"
++ "acx mem pointer (dynamic) 0x%X\n"
++ "host mem pointer (dynamic) 0x%X\n"
++ "length (dynamic) 0x%X\n"
++ "CTL (dynamic) 0x%X\n"
++ "CTL2 (dynamic) 0x%X\n"
++ "Status (dynamic) 0x%X\n"
++ "Rate (dynamic) 0x%X\n",
++ i,
++ (int) sizeof(struct txdesc),
++ txdesc,
++ acx2cpu(txdesc->pNextDesc),
++ acx2cpu(txdesc->AcxMemPtr),
++ acx2cpu(txdesc->HostMemPtr),
++ le16_to_cpu(txdesc->total_length),
++ txdesc->Ctl_8,
++ txdesc->Ctl2_8, txdesc->error,
++ txdesc->u.r1.rate);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++
++ /* dump host tx descriptor ring buffer */
++
++ txhostdesc = priv->txhostdesc_start;
++
++ /* loop over complete host send pool */
++ if (txhostdesc) for (i = 0; i < TX_CNT * 2; i++) {
++ printk("\ndump host txdesc %d:\n"
++ "mem pos %p\n"
++ "buffer mem pos 0x%X\n"
++ "buffer mem offset 0x%X\n"
++ "CTL 0x%X\n"
++ "Length 0x%X\n"
++ "next 0x%X\n"
++ "Status 0x%X\n",
++ i,
++ txhostdesc,
++ acx2cpu(txhostdesc->data_phy),
++ txhostdesc->data_offset,
++ le16_to_cpu(txhostdesc->Ctl_16),
++ le16_to_cpu(txhostdesc->length),
++ acx2cpu(txhostdesc->desc_phy_next),
++ le32_to_cpu(txhostdesc->Status));
++ txhostdesc++;
++ }
++
++ /* acx_write_reg16(priv, 0xb4, 0x4); */
++
++ acx_unlock(priv, flags);
++end_ok:
++
++ acx_sem_unlock(priv);
++#endif /* ACX_DEBUG */
++ return OK;
++}
++
++
++/***********************************************************************
++*/
++int
++acx100pci_ioctl_set_phy_amp_bias(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ u16 gpio_old;
++
++ if (!IS_ACX100(priv)) {
++ /* WARNING!!!
++ * Removing this check *might* damage
++ * hardware, since we're tweaking GPIOs here after all!!!
++ * You've been warned...
++ * WARNING!!! */
++ printk("acx: sorry, setting bias level for non-acx100 "
++ "is not supported yet\n");
++ return OK;
++ }
++
++ if (*extra > 7) {
++ printk("acx: invalid bias parameter, range is 0-7\n");
++ return -EINVAL;
++ }
++
++ acx_sem_lock(priv);
++
++ /* Need to lock accesses to [IO_ACX_GPIO_OUT]:
++ * IRQ handler uses it to update LED */
++ acx_lock(priv, flags);
++ gpio_old = acx_read_reg16(priv, IO_ACX_GPIO_OUT);
++ acx_write_reg16(priv, IO_ACX_GPIO_OUT, (gpio_old & 0xf8ff) | ((u16)*extra << 8));
++ acx_unlock(priv, flags);
++
++ acxlog(L_DEBUG, "gpio_old: 0x%04X\n", gpio_old);
++ printk("%s: PHY power amplifier bias: old:%d, new:%d\n",
++ dev->name,
++ (gpio_old & 0x0700) >> 8, (unsigned char)*extra);
++
++ acx_sem_unlock(priv);
++
++ return OK;
++}
++
++
++/***************************************************************
++** acxpci_l_alloc_tx
++** Actually returns a txdesc_t* ptr
++*/
++tx_t*
++acxpci_l_alloc_tx(wlandevice_t* priv)
++{
++ struct txdesc *txdesc;
++ u8 ctl8;
++
++ FN_ENTER;
++
++ txdesc = get_txdesc(priv, priv->tx_head);
++ ctl8 = txdesc->Ctl_8;
++ if (unlikely(DESC_CTL_HOSTOWN != (ctl8 & DESC_CTL_DONE))) {
++ /* whoops, descr at current index is not free, so probably
++ * ring buffer already full */
++ /* FIXME: this causes a deadlock situation (endless
++ * loop) in case the current descriptor remains busy,
++ * so handle it a bit better in the future!! */
++ printk("acx: BUG: tx_head->Ctl8=0x%02X, (0x%02X & "
++ "0x"DESC_CTL_DONE_STR") != 0x"DESC_CTL_HOSTOWN_STR
++ ": failed to find free tx descr\n",
++ ctl8, ctl8);
++ txdesc = NULL;
++ goto end;
++ }
++
++ priv->tx_free--;
++ acxlog(L_BUFT, "tx: got desc %u, %u remain\n",
++ priv->tx_head, priv->tx_free);
++
++/*
++ * This comment is probably not entirely correct, needs further discussion
++ * (restored commented-out code below to fix Tx ring buffer overflow,
++ * since it's much better to have a slightly less efficiently used ring
++ * buffer rather than one which easily overflows):
++ *
++ * This doesn't do anything other than limit our maximum number of
++ * buffers used at a single time (we might as well just declare
++ * TX_STOP_QUEUE less descriptors when we open up.) We should just let it
++ * slide here, and back off TX_STOP_QUEUE in acx_l_clean_tx_desc, when given the
++ * opportunity to let the queue start back up.
++ */
++ if (priv->tx_free < TX_STOP_QUEUE) {
++ acxlog(L_BUF, "stop queue (%u tx desc left)\n",
++ priv->tx_free);
++ acx_stop_queue(priv->netdev, NULL);
++ }
++
++ /* returning current descriptor, so advance to next free one */
++ priv->tx_head = (priv->tx_head + 1) % TX_CNT;
++end:
++ FN_EXIT0;
++
++ return (tx_t*)txdesc;
++}
++
++
++/***********************************************************************
++*/
++void*
++acxpci_l_get_txbuf(wlandevice_t *priv, tx_t* tx_opaque)
++{
++ return acx_get_txhostdesc(priv, (txdesc_t*)tx_opaque)->data;
++}
++
++
++/***********************************************************************
++** acxpci_l_tx_data
++**
++** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
++** Can be called from acx_i_start_xmit (data frames from net core).
++*/
++void
++acxpci_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int len)
++{
++ txdesc_t *txdesc = (txdesc_t*)tx_opaque;
++ txhostdesc_t *hostdesc1, *hostdesc2;
++ client_t *clt;
++ u8 Ctl_8, Ctl2_8;
++
++ FN_ENTER;
++
++ /* fw doesn't tx such packets anyhow */
++ if (len < WLAN_HDR_A3_LEN)
++ goto end;
++
++ hostdesc1 = acx_get_txhostdesc(priv, txdesc);
++ hostdesc2 = hostdesc1 + 1;
++
++ /* modify flag status in separate variable to be able to write it back
++ * in one big swoop later (also in order to have less device memory
++ * accesses) */
++ Ctl_8 = txdesc->Ctl_8;
++ Ctl2_8 = txdesc->Ctl2_8;
++
++ /* DON'T simply set Ctl field to 0 here globally,
++ * it needs to maintain a consistent flag status (those are state flags!!),
++ * otherwise it may lead to severe disruption. Only set or reset particular
++ * flags at the exact moment this is needed...
++ * FIXME: what about Ctl2? Equally problematic? */
++
++ /* let chip do RTS/CTS handshaking before sending
++ * in case packet size exceeds threshold */
++ if (len > priv->rts_threshold)
++ SET_BIT(Ctl2_8, DESC_CTL2_RTS);
++ else
++ CLEAR_BIT(Ctl2_8, DESC_CTL2_RTS);
++
++#ifdef DEBUG_WEP
++ if (priv->wep_enabled)
++ SET_BIT(Ctl2_8, DESC_CTL2_WEP);
++ else
++ CLEAR_BIT(Ctl2_8, DESC_CTL2_WEP);
++#endif
++
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_3_AP:
++ clt = acx_l_sta_list_get(priv, ((wlan_hdr_t*)hostdesc1->data)->a1);
++ break;
++ case ACX_MODE_2_STA:
++ clt = priv->ap_client;
++ break;
++#if 0
++/* testing was done on acx111: */
++ case ACX_MODE_MONITOR:
++ SET_BIT(Ctl2_8, 0
++/* sends CTS to self before packet */
++ + DESC_CTL2_SEQ /* don't increase sequence field */
++/* not working (looks like good fcs is still added) */
++ + DESC_CTL2_FCS /* don't add the FCS */
++/* not tested */
++ + DESC_CTL2_MORE_FRAG
++/* not tested */
++ + DESC_CTL2_RETRY /* don't increase retry field */
++/* not tested */
++ + DESC_CTL2_POWER /* don't increase power mgmt. field */
++/* no effect */
++ + DESC_CTL2_WEP /* encrypt this frame */
++/* not tested */
++ + DESC_CTL2_DUR /* don't increase duration field */
++ );
++ /* fallthrough */
++#endif
++ default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
++ clt = NULL;
++ break;
++ }
++
++ if (unlikely(clt && !clt->rate_cur)) {
++ printk("acx: driver bug! bad ratemask\n");
++ goto end;
++ }
++
++ /* used in tx cleanup routine for auto rate and accounting: */
++ acx_put_txc(priv, txdesc, clt);
++
++ txdesc->total_length = cpu_to_le16(len);
++ hostdesc2->length = cpu_to_le16(len - WLAN_HDR_A3_LEN);
++ if (IS_ACX111(priv)) {
++ u16 rate_cur = clt ? clt->rate_cur : priv->rate_bcast;
++ /* note that if !txdesc->do_auto, txrate->cur
++ ** has only one nonzero bit */
++ txdesc->u.r2.rate111 = cpu_to_le16(
++ rate_cur
++ /* WARNING: I was never able to make it work with prism54 AP.
++ ** It was falling down to 1Mbit where shortpre is not applicable,
++ ** and not working at all at "5,11 basic rates only" setting.
++ ** I even didn't see tx packets in radio packet capture.
++ ** Disabled for now --vda */
++ /*| ((clt->shortpre && clt->cur!=RATE111_1) ? RATE111_SHORTPRE : 0) */
++ );
++#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
++ /* should add this to rate111 above as necessary */
++ | (clt->pbcc511 ? RATE111_PBCC511 : 0)
++#endif
++ hostdesc1->length = cpu_to_le16(len);
++ } else { /* ACX100 */
++ u8 rate_100 = clt ? clt->rate_100 : priv->rate_bcast100;
++ txdesc->u.r1.rate = rate_100;
++#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
++ if (clt->pbcc511) {
++ if (n == RATE100_5 || n == RATE100_11)
++ n |= RATE100_PBCC511;
++ }
++
++ if (clt->shortpre && (clt->cur != RATE111_1))
++ SET_BIT(Ctl_8, DESC_CTL_SHORT_PREAMBLE); /* set Short Preamble */
++#endif
++ /* set autodma and reclaim and 1st mpdu */
++ SET_BIT(Ctl_8, DESC_CTL_AUTODMA | DESC_CTL_RECLAIM | DESC_CTL_FIRSTFRAG);
++ hostdesc1->length = cpu_to_le16(WLAN_HDR_A3_LEN);
++ }
++ /* don't need to clean ack/rts statistics here, already
++ * done on descr cleanup */
++
++ /* clears Ctl DESC_CTL_HOSTOWN bit, thus telling that the descriptors
++ * are now owned by the acx100; do this as LAST operation */
++ CLEAR_BIT(Ctl_8, DESC_CTL_HOSTOWN);
++ /* flush writes before we release hostdesc to the adapter here */
++ wmb();
++ CLEAR_BIT(hostdesc1->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++ CLEAR_BIT(hostdesc2->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++
++ /* write back modified flags */
++ txdesc->Ctl2_8 = Ctl2_8;
++ txdesc->Ctl_8 = Ctl_8;
++
++ /* unused: txdesc->tx_time = cpu_to_le32(jiffies); */
++//TODO: should it be a mmiowb() instead? we are protecting against race with write[bwl]()
++ /* flush writes before we tell the adapter that it's its turn now */
++ wmb();
++ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_TXPRC);
++ acx_write_flush(priv);
++
++ /* log the packet content AFTER sending it,
++ * in order to not delay sending any further than absolutely needed
++ * Do separate logs for acx100/111 to have human-readable rates */
++ if (unlikely(acx_debug & (L_XFER|L_DATA))) {
++ u16 fc = ((wlan_hdr_t*)hostdesc1->data)->fc;
++ if (IS_ACX111(priv))
++ printk("tx: pkt (%s): len %d "
++ "rate %04X%s status %u\n",
++ acx_get_packet_type_string(le16_to_cpu(fc)), len,
++ le16_to_cpu(txdesc->u.r2.rate111),
++ (le16_to_cpu(txdesc->u.r2.rate111) & RATE111_SHORTPRE) ? "(SPr)" : "",
++ priv->status);
++ else
++ printk("tx: pkt (%s): len %d rate %03u%s status %u\n",
++ acx_get_packet_type_string(fc), len,
++ txdesc->u.r1.rate,
++ (Ctl_8 & DESC_CTL_SHORT_PREAMBLE) ? "(SPr)" : "",
++ priv->status);
++
++ if (acx_debug & L_DATA) {
++ printk("tx: 802.11 [%d]: ", len);
++ acx_dump_bytes(hostdesc1->data, len);
++ }
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++*/
++static void
++acx_l_handle_tx_error(wlandevice_t *priv, u8 error, unsigned int finger)
++{
++ const char *err = "unknown error";
++
++ /* hmm, should we handle this as a mask
++ * of *several* bits?
++ * For now I think only caring about
++ * individual bits is ok... */
++ switch (error) {
++ case 0x01:
++ err = "no Tx due to error in other fragment";
++ priv->wstats.discard.fragment++;
++ break;
++ case 0x02:
++ err = "Tx aborted";
++ priv->stats.tx_aborted_errors++;
++ break;
++ case 0x04:
++ err = "Tx desc wrong parameters";
++ priv->wstats.discard.misc++;
++ break;
++ case 0x08:
++ err = "WEP key not found";
++ priv->wstats.discard.misc++;
++ break;
++ case 0x10:
++ err = "MSDU lifetime timeout? - try changing "
++ "'iwconfig retry lifetime XXX'";
++ priv->wstats.discard.misc++;
++ break;
++ case 0x20:
++ err = "excessive Tx retries due to either distance "
++ "too high or unable to Tx or Tx frame error - "
++ "try changing 'iwconfig txpower XXX' or "
++ "'sens'itivity or 'retry'";
++ priv->wstats.discard.retries++;
++ /* FIXME: set (GETSET_TX|GETSET_RX) here
++ * (this seems to recalib radio on ACX100)
++ * after some more jiffies passed??
++ * But OTOH Tx error 0x20 also seems to occur on
++ * overheating, so I'm not sure whether we
++ * actually want that, since people maybe won't notice
++ * then that their hardware is slowly getting
++ * cooked...
++ * Or is it still a safe long distance from utter
++ * radio non-functionality despite many radio
++ * recalibs
++ * to final destructive overheating of the hardware?
++ * In this case we really should do recalib here...
++ * I guess the only way to find out is to do a
++ * potentially fatal self-experiment :-\
++ * Or maybe only recalib in case we're using Tx
++ * rate auto (on errors switching to lower speed
++ * --> less heat?) or 802.11 power save mode? */
++
++ /* ok, just do it.
++ * ENABLE_TX|ENABLE_RX helps, so even do
++ * DISABLE_TX and DISABLE_RX in order to perhaps
++ * have more impact. */
++ if (++priv->retry_errors_msg_ratelimit % 4 == 0) {
++ if (priv->retry_errors_msg_ratelimit <= 20)
++ printk("%s: several excessive Tx "
++ "retry errors occurred, attempting "
++ "to recalibrate radio. Radio "
++ "drift might be caused by increasing "
++ "card temperature, please check the card "
++ "before it's too late!\n",
++ priv->netdev->name);
++ if (priv->retry_errors_msg_ratelimit == 20)
++ printk("disabling above "
++ "notification message\n");
++
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
++ }
++ break;
++ case 0x40:
++ err = "Tx buffer overflow";
++ priv->stats.tx_fifo_errors++;
++ break;
++ case 0x80:
++ err = "DMA error";
++ priv->wstats.discard.misc++;
++ break;
++ }
++ priv->stats.tx_errors++;
++ if (priv->stats.tx_errors <= 20)
++ printk("%s: tx error 0x%02X, buf %02u! (%s)\n",
++ priv->netdev->name, error, finger, err);
++ else
++ printk("%s: tx error 0x%02X, buf %02u!\n",
++ priv->netdev->name, error, finger);
++}
++
++
++/***********************************************************************
++*/
++/* Theory of operation:
++** client->rate_cap is a bitmask of rates client is capable of.
++** client->rate_cfg is a bitmask of allowed (configured) rates.
++** It is set as a result of iwconfig rate N [auto]
++** or iwpriv set_rates "N,N,N N,N,N" commands.
++** It can be fixed (e.g. 0x0080 == 18Mbit only),
++** auto (0x00ff == 18Mbit or any lower value),
++** and code handles any bitmask (0x1081 == try 54Mbit,18Mbit,1Mbit _only_).
++**
++** client->rate_cur is a value for rate111 field in tx descriptor.
++** It is always set to txrate_cfg sans zero or more most significant
++** bits. This routine handles selection of new rate_cur value depending on
++** outcome of last tx event.
++**
++** client->rate_100 is a precalculated rate value for acx100
++** (we can do without it, but will need to calculate it on each tx).
++**
++** You cannot configure mixed usage of 5.5 and/or 11Mbit rate
++** with PBCC and CCK modulation. Either both at CCK or both at PBCC.
++** In theory you can implement it, but so far it is considered not worth doing.
++**
++** 22Mbit, of course, is PBCC always. */
++
++/* maps acx100 tx descr rate field to acx111 one */
++static u16
++rate100to111(u8 r)
++{
++ switch (r) {
++ case RATE100_1: return RATE111_1;
++ case RATE100_2: return RATE111_2;
++ case RATE100_5:
++ case (RATE100_5 | RATE100_PBCC511): return RATE111_5;
++ case RATE100_11:
++ case (RATE100_11 | RATE100_PBCC511): return RATE111_11;
++ case RATE100_22: return RATE111_22;
++ default:
++ printk("acx: unexpected acx100 txrate: %u! "
++ "Please report\n", r);
++ return RATE111_2;
++ }
++}
++
++
++static void
++acx_l_handle_txrate_auto(wlandevice_t *priv, struct client *txc,
++ unsigned int idx, u8 rate100, u16 rate111, u8 error)
++{
++ u16 sent_rate;
++ u16 cur = txc->rate_cur;
++ int slower_rate_was_used;
++
++ /* FIXME: need to implement some kind of rate success memory
++ * which stores the success percentage per rate, to be taken
++ * into account when considering allowing a new rate, since it
++ * doesn't really help to stupidly count fallback/stepup,
++ * since one invalid rate will spoil the party anyway
++ * (such as 22M in case of 11M-only peers) */
++
++ /* vda: hmm. current code will do this:
++ ** 1. send packets at 11 Mbit, stepup++
++ ** 2. will try to send at 22Mbit. hardware will see no ACK,
++ ** retries at 11Mbit, success. code notes that used rate
++ ** is lower. stepup = 0, fallback++
++ ** 3. repeat step 2 fallback_count times. Fall back to
++ ** 11Mbit. go to step 1.
++ ** If stepup_count is large (say, 16) and fallback_count
++ ** is small (3), this wouldn't be too bad wrt throughput */
++
++ /* do some preparations, i.e. calculate the one rate that was
++ * used to send this packet */
++ if (IS_ACX111(priv)) {
++ sent_rate = 1 << highest_bit(rate111 & RATE111_ALL);
++ } else {
++ sent_rate = rate100to111(rate100);
++ }
++ /* sent_rate has only one bit set now, corresponding to tx rate
++ * which was used by hardware to tx this particular packet */
++
++ /* now do the actual auto rate management */
++ acxlog(L_DEBUG, "tx: %sclient=%p/"MACSTR" used=%04X cur=%04X cfg=%04X "
++ "__=%u/%u ^^=%u/%u\n",
++ (txc->ignore_count > 0) ? "[IGN] " : "",
++ txc, MAC(txc->address), sent_rate, cur, txc->rate_cfg,
++ txc->fallback_count, priv->fallback_threshold,
++ txc->stepup_count, priv->stepup_threshold
++ );
++
++ /* we need to ignore old packets already in the tx queue since
++ * they use older rate bytes configured before our last rate change,
++ * otherwise our mechanism will get confused by interpreting old data.
++ * Do it here only, in order to have the logging above */
++ if (txc->ignore_count) {
++ txc->ignore_count--;
++ return;
++ }
++
++ /* true only if the only nonzero bit in sent_rate is
++ ** less significant than highest nonzero bit in cur */
++ slower_rate_was_used = ( cur > ((sent_rate<<1)-1) );
++
++ if (slower_rate_was_used || (error & 0x30)) {
++ txc->stepup_count = 0;
++ if (++txc->fallback_count <= priv->fallback_threshold)
++ return;
++ txc->fallback_count = 0;
++
++ /* clear highest 1 bit in cur */
++ sent_rate = RATE111_54;
++ while (!(cur & sent_rate)) sent_rate >>= 1;
++ CLEAR_BIT(cur, sent_rate);
++
++ if (cur) { /* we can't disable all rates! */
++ acxlog(L_XFER, "tx: falling back to ratemask %04X\n", cur);
++ txc->rate_cur = cur;
++ txc->ignore_count = TX_CNT - priv->tx_free;
++ }
++ } else if (!slower_rate_was_used) {
++ txc->fallback_count = 0;
++ if (++txc->stepup_count <= priv->stepup_threshold)
++ return;
++ txc->stepup_count = 0;
++
++ /* sanitize. Sort of not needed, but I dont trust hw that much...
++ ** what if it can report bogus tx rates sometimes? */
++ while (!(cur & sent_rate)) sent_rate >>= 1;
++ /* try to find a higher sent_rate that isn't yet in our
++ * current set, but is an allowed cfg */
++ while (1) {
++ sent_rate <<= 1;
++ if (sent_rate > txc->rate_cfg)
++ /* no higher rates allowed by config */
++ return;
++ if (!(cur & sent_rate) && (txc->rate_cfg & sent_rate))
++ /* found */
++ break;
++ /* not found, try higher one */
++ }
++ SET_BIT(cur, sent_rate);
++ acxlog(L_XFER, "tx: stepping up to ratemask %04X\n", cur);
++ txc->rate_cur = cur;
++ /* FIXME: totally bogus - we could be sending to many peers at once... */
++ txc->ignore_count = TX_CNT - priv->tx_free;
++ }
++
++ /* calculate acx100 style rate byte if needed */
++ if (IS_ACX100(priv)) {
++ txc->rate_100 = bitpos2rate100[highest_bit(cur)];
++ }
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_log_txbuffer
++*----------------------------------------------------------------*/
++#if !ACX_DEBUG
++static inline void acx_l_log_txbuffer(const wlandevice_t *priv) {}
++#else
++static void
++acx_l_log_txbuffer(wlandevice_t *priv)
++{
++ txdesc_t *txdesc;
++ int i;
++
++ /* no FN_ENTER here, we don't want that */
++ /* no locks here, since it's entirely non-critical code */
++ txdesc = priv->txdesc_start;
++ if (!txdesc) return;
++ for (i = 0; i < TX_CNT; i++) {
++ if ((txdesc->Ctl_8 & DESC_CTL_DONE) == DESC_CTL_DONE)
++ printk("tx: buf %d done\n", i);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++}
++#endif
++
++
++/*----------------------------------------------------------------
++* acx_l_clean_tx_desc
++*
++* This function resets the txdescs' status when the ACX100
++* signals the TX done IRQ (txdescs have been processed), starting with
++* the pool index of the descriptor which we would use next,
++* in order to make sure that we can be as fast as possible
++* in filling new txdescs.
++* Oops, now we have our own index, so everytime we get called we know
++* where the next packet to be cleaned is.
++* Hmm, still need to loop through the whole ring buffer now,
++* since we lost sync for some reason when ping flooding or so...
++* (somehow we don't get the IRQ for acx_l_clean_tx_desc any more when
++* too many packets are being sent!)
++* FIXME: currently we only process one packet, but this gets out of
++* sync for some reason when ping flooding, so we need to loop,
++* but the previous smart loop implementation causes the ping latency
++* to rise dramatically (~3000 ms), at least on CardBus PheeNet WL-0022.
++* Dunno what to do :-\
++*----------------------------------------------------------------*/
++unsigned int
++acx_l_clean_tx_desc(wlandevice_t *priv)
++{
++ txdesc_t *txdesc;
++ struct client *txc;
++ int finger;
++ int num_cleaned;
++ int to_process;
++ u16 r111;
++ u8 error, ack_failures, rts_failures, rts_ok, r100;
++
++ FN_ENTER;
++
++ if (unlikely(acx_debug & L_DEBUG))
++ acx_l_log_txbuffer(priv);
++
++ acxlog(L_BUFT, "tx: cleaning up bufs from %u\n", priv->tx_tail);
++
++ finger = priv->tx_tail;
++ num_cleaned = 0;
++ to_process = TX_CNT;
++ do {
++ txdesc = get_txdesc(priv, finger);
++
++ /* abort if txdesc is not marked as "Tx finished" and "owned" */
++ if ((txdesc->Ctl_8 & DESC_CTL_DONE) != DESC_CTL_DONE) {
++ /* we do need to have at least one cleaned,
++ * otherwise we wouldn't get called in the first place
++ */
++ if (num_cleaned)
++ break;
++ }
++
++ /* remember descr values... */
++ error = txdesc->error;
++ ack_failures = txdesc->ack_failures;
++ rts_failures = txdesc->rts_failures;
++ rts_ok = txdesc->rts_ok;
++ r100 = txdesc->u.r1.rate;
++ r111 = txdesc->u.r2.rate111;
++
++#if WIRELESS_EXT > 13 /* wireless_send_event() and IWEVTXDROP are WE13 */
++ /* need to check for certain error conditions before we
++ * clean the descriptor: we still need valid descr data here */
++ if (unlikely(0x30 & error)) {
++ /* only send IWEVTXDROP in case of retry or lifetime exceeded;
++ * all other errors mean we screwed up locally */
++ union iwreq_data wrqu;
++ wlan_hdr_t *hdr;
++ txhostdesc_t *hostdesc;
++
++ hostdesc = acx_get_txhostdesc(priv, txdesc);
++ hdr = (wlan_hdr_t *)hostdesc->data;
++ MAC_COPY(wrqu.addr.sa_data, hdr->a1);
++ wireless_send_event(priv->netdev, IWEVTXDROP, &wrqu, NULL);
++ }
++#endif
++ /* ...and free the descr */
++ txdesc->error = 0;
++ txdesc->ack_failures = 0;
++ txdesc->rts_failures = 0;
++ txdesc->rts_ok = 0;
++ /* signal host owning it LAST, since ACX already knows that this
++ * descriptor is finished since it set Ctl_8 accordingly:
++ * if _OWN is set at the beginning instead, our own get_tx
++ * might choose a Tx desc that isn't fully cleared
++ * (in case of bad locking). */
++ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
++ priv->tx_free++;
++ num_cleaned++;
++
++ if ((priv->tx_free >= TX_START_QUEUE)
++ && (priv->status == ACX_STATUS_4_ASSOCIATED)
++ && (acx_queue_stopped(priv->netdev))
++ ) {
++ acxlog(L_BUF, "tx: wake queue (avail. Tx desc %u)\n",
++ priv->tx_free);
++ acx_wake_queue(priv->netdev, NULL);
++ }
++
++ /* do error checking, rate handling and logging
++ * AFTER having done the work, it's faster */
++
++ /* do rate handling */
++ txc = acx_get_txc(priv, txdesc);
++ if (txc && priv->rate_auto) {
++ acx_l_handle_txrate_auto(priv, txc, finger, r100, r111, error);
++ }
++
++ if (unlikely(error))
++ acx_l_handle_tx_error(priv, error, finger);
++
++ if (IS_ACX111(priv))
++ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u r111=%04X\n",
++ finger, ack_failures, rts_failures, rts_ok, r111);
++ else
++ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u rate=%u\n",
++ finger, ack_failures, rts_failures, rts_ok, r100);
++
++ /* update pointer for descr to be cleaned next */
++ finger = (finger + 1) % TX_CNT;
++ } while (--to_process);
++
++ /* remember last position */
++ priv->tx_tail = finger;
++/* end: */
++ FN_EXIT1(num_cleaned);
++ return num_cleaned;
++}
++
++/* clean *all* Tx descriptors, and regardless of their previous state.
++ * Used for brute-force reset handling. */
++void
++acx_l_clean_tx_desc_emergency(wlandevice_t *priv)
++{
++ txdesc_t *txdesc;
++ unsigned int i;
++
++ FN_ENTER;
++
++ for (i = 0; i < TX_CNT; i++) {
++ txdesc = get_txdesc(priv, i);
++
++ /* free it */
++ txdesc->ack_failures = 0;
++ txdesc->rts_failures = 0;
++ txdesc->rts_ok = 0;
++ txdesc->error = 0;
++ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
++ }
++
++ priv->tx_free = TX_CNT;
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_log_rxbuffer
++*
++* Called from IRQ context only
++*----------------------------------------------------------------*/
++#if !ACX_DEBUG
++static inline void acx_l_log_rxbuffer(const wlandevice_t *priv) {}
++#else
++static void
++acx_l_log_rxbuffer(const wlandevice_t *priv)
++{
++ const struct rxhostdesc *rxhostdesc;
++ int i;
++
++ /* no FN_ENTER here, we don't want that */
++
++ rxhostdesc = priv->rxhostdesc_start;
++ if (!rxhostdesc) return;
++ for (i = 0; i < RX_CNT; i++) {
++ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
++ printk("rx: buf %d full\n", i);
++ rxhostdesc++;
++ }
++}
++#endif
++
++
++/***************************************************************
++** acx_l_process_rx_desc
++**
++** Called directly and only from the IRQ handler
++*/
++void
++acx_l_process_rx_desc(wlandevice_t *priv)
++{
++ rxhostdesc_t *hostdesc;
++ /* unsigned int curr_idx; */
++ unsigned int count = 0;
++
++ FN_ENTER;
++
++ if (unlikely(acx_debug & L_BUFR)) {
++ acx_l_log_rxbuffer(priv);
++ }
++
++ /* First, have a loop to determine the first descriptor that's
++ * full, just in case there's a mismatch between our current
++ * rx_tail and the full descriptor we're supposed to handle. */
++ while (1) {
++ /* curr_idx = priv->rx_tail; */
++ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
++ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
++ if ((hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && (hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) {
++ /* found it! */
++ break;
++ }
++ count++;
++ if (unlikely(count > RX_CNT)) {
++ /* hmm, no luck: all descriptors empty, bail out */
++ goto end;
++ }
++ }
++
++ /* now process descriptors, starting with the first we figured out */
++ while (1) {
++ acxlog(L_BUFR, "rx: tail=%u Ctl_16=%04X Status=%08X\n",
++ priv->rx_tail, hostdesc->Ctl_16, hostdesc->Status);
++
++ acx_l_process_rxbuf(priv, hostdesc->data);
++
++ hostdesc->Status = 0;
++ /* flush all writes before adapter sees CTL_HOSTOWN change */
++ wmb();
++ /* Host no longer owns this, needs to be LAST */
++ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++
++ /* ok, descriptor is handled, now check the next descriptor */
++ /* curr_idx = priv->rx_tail; */
++ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
++
++ /* if next descriptor is empty, then bail out */
++ /* FIXME: is this check really entirely correct?? */
++ /*
++//FIXME: inconsistent with check in prev while() loop
++ if (!(hostdesc->Ctl & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && !(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) */
++ if (!(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
++ break;
++
++ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_create_tx_host_desc_queue
++*----------------------------------------------------------------*/
++static inline void*
++acx_alloc_coherent(struct device *dev, size_t size,
++ dma_addr_t *dma_handle, int flag)
++{
++ printk("Size : %ld\n",size);
++ dev->coherent_dma_mask = 0xffffffff;
++ return dma_alloc_coherent(dev, size, dma_handle, flag);
++}
++
++static void*
++allocate(wlandevice_t *priv, size_t size, dma_addr_t *phy, const char *msg)
++{
++ void *ptr = acx_alloc_coherent(priv->dev, size, phy, GFP_KERNEL);
++ if (ptr) {
++ acxlog(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n",
++ msg, (int)size, ptr, (unsigned long long)*phy);
++ memset(ptr, 0, size);
++ return ptr;
++ }
++ printk(KERN_ERR "acx: %s allocation FAILED (%d bytes)\n",
++ msg, (int)size);
++ return NULL;
++}
++
++static int
++acx_s_create_tx_host_desc_queue(wlandevice_t *priv)
++{
++ txhostdesc_t *hostdesc;
++ u8 *txbuf;
++ dma_addr_t hostdesc_phy;
++ dma_addr_t txbuf_phy;
++ int i;
++
++ FN_ENTER;
++
++ /* allocate TX buffer */
++ priv->txbuf_area_size = TX_CNT * WLAN_A4FR_MAXLEN_WEP_FCS;
++ priv->txbuf_start = allocate(priv, priv->txbuf_area_size,
++ &priv->txbuf_startphy, "txbuf_start");
++ if (!priv->txbuf_start)
++ goto fail;
++
++ /* allocate the TX host descriptor queue pool */
++ priv->txhostdesc_area_size = TX_CNT * 2*sizeof(txhostdesc_t);
++ priv->txhostdesc_start = allocate(priv, priv->txhostdesc_area_size,
++ &priv->txhostdesc_startphy, "txhostdesc_start");
++ if (!priv->txhostdesc_start)
++ goto fail;
++ /* check for proper alignment of TX host descriptor pool */
++ if ((long) priv->txhostdesc_start & 3) {
++ printk("acx: driver bug: dma alloc returns unaligned address\n");
++ goto fail;
++ }
++
++/* Each tx frame buffer is accessed by hardware via
++** txdesc -> txhostdesc(s) -> framebuffer(s)
++** We use only one txhostdesc per txdesc, but it looks like
++** acx111 is buggy: it accesses second txhostdesc
++** (via hostdesc.desc_phy_next field) even if
++** txdesc->length == hostdesc->length and thus
++** entire packet was placed into first txhostdesc.
++** Due to this bug acx111 hangs unless second txhostdesc
++** has hostdesc.length = 3 (or larger)
++** Storing NULL into hostdesc.desc_phy_next
++** doesn't seem to help.
++*/
++/* It is not known whether we need to have 'extra' second
++** txhostdescs for acx100. Maybe it is acx111-only bug.
++*/
++ hostdesc = priv->txhostdesc_start;
++ hostdesc_phy = priv->txhostdesc_startphy;
++ txbuf = priv->txbuf_start;
++ txbuf_phy = priv->txbuf_startphy;
++
++ for (i = 0; i < TX_CNT*2; i++) {
++ hostdesc_phy += sizeof(txhostdesc_t);
++ if (!(i & 1)) {
++ hostdesc->data_phy = cpu2acx(txbuf_phy);
++ /* done by memset(0): hostdesc->data_offset = 0; */
++ /* hostdesc->reserved = ... */
++ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
++ /* hostdesc->length = ... */
++ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
++ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
++ /* hostdesc->Status = ... */
++ /* below: non-hardware fields */
++ hostdesc->data = txbuf;
++
++ txbuf += WLAN_HDR_A3_LEN;
++ txbuf_phy += WLAN_HDR_A3_LEN;
++ } else {
++ hostdesc->data_phy = cpu2acx(txbuf_phy);
++ /* done by memset(0): hostdesc->data_offset = 0; */
++ /* hostdesc->reserved = ... */
++ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
++ /* hostdesc->length = ...; */
++ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
++ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
++ /* hostdesc->Status = ... */
++ /* below: non-hardware fields */
++ hostdesc->data = txbuf;
++
++ txbuf += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
++ txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
++ }
++ hostdesc++;
++ }
++ hostdesc--;
++ hostdesc->desc_phy_next = cpu2acx(priv->txhostdesc_startphy);
++
++ FN_EXIT1(OK);
++ return OK;
++fail:
++ printk("acx: create_tx_host_desc_queue FAILED\n");
++ /* dealloc will be done by free function on error case */
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/***************************************************************
++** acx_s_create_rx_host_desc_queue
++*/
++/* the whole size of a data buffer (header plus data body)
++ * plus 32 bytes safety offset at the end */
++#define RX_BUFFER_SIZE (sizeof(rxbuffer_t) + 32)
++
++static int
++acx_s_create_rx_host_desc_queue(wlandevice_t *priv)
++{
++ rxhostdesc_t *hostdesc;
++ rxbuffer_t *rxbuf;
++ dma_addr_t hostdesc_phy;
++ dma_addr_t rxbuf_phy;
++ int i;
++
++ FN_ENTER;
++
++ /* allocate the RX host descriptor queue pool */
++ priv->rxhostdesc_area_size = RX_CNT * sizeof(rxhostdesc_t);
++ priv->rxhostdesc_start = allocate(priv, priv->rxhostdesc_area_size,
++ &priv->rxhostdesc_startphy, "rxhostdesc_start");
++ if (!priv->rxhostdesc_start)
++ goto fail;
++ /* check for proper alignment of RX host descriptor pool */
++ if ((long) priv->rxhostdesc_start & 3) {
++ printk("acx: driver bug: dma alloc returns unaligned address\n");
++ goto fail;
++ }
++
++ /* allocate Rx buffer pool which will be used by the acx
++ * to store the whole content of the received frames in it */
++ priv->rxbuf_area_size = RX_CNT * RX_BUFFER_SIZE;
++ priv->rxbuf_start = allocate(priv, priv->rxbuf_area_size,
++ &priv->rxbuf_startphy, "rxbuf_start");
++ if (!priv->rxbuf_start)
++ goto fail;
++
++ rxbuf = priv->rxbuf_start;
++ rxbuf_phy = priv->rxbuf_startphy;
++ hostdesc = priv->rxhostdesc_start;
++ hostdesc_phy = priv->rxhostdesc_startphy;
++
++ /* don't make any popular C programming pointer arithmetic mistakes
++ * here, otherwise I'll kill you...
++ * (and don't dare asking me why I'm warning you about that...) */
++ for (i = 0; i < RX_CNT; i++) {
++ hostdesc->data = rxbuf;
++ hostdesc->data_phy = cpu2acx(rxbuf_phy);
++ hostdesc->length = cpu_to_le16(RX_BUFFER_SIZE);
++ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++ rxbuf++;
++ rxbuf_phy += sizeof(rxbuffer_t);
++ hostdesc_phy += sizeof(rxhostdesc_t);
++ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
++ hostdesc++;
++ }
++ hostdesc--;
++ hostdesc->desc_phy_next = cpu2acx(priv->rxhostdesc_startphy);
++ FN_EXIT1(OK);
++ return OK;
++fail:
++ printk("acx: create_rx_host_desc_queue FAILED\n");
++ /* dealloc will be done by free function on error case */
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/***************************************************************
++** acx_s_create_hostdesc_queues
++*/
++int
++acx_s_create_hostdesc_queues(wlandevice_t *priv)
++{
++ int result;
++ result = acx_s_create_tx_host_desc_queue(priv);
++ if (OK != result) return result;
++ result = acx_s_create_rx_host_desc_queue(priv);
++ return result;
++}
++
++
++/***************************************************************
++** acx_create_tx_desc_queue
++*/
++static void
++acx_create_tx_desc_queue(wlandevice_t *priv, u32 tx_queue_start)
++{
++ txdesc_t *txdesc;
++ txhostdesc_t *hostdesc;
++ dma_addr_t hostmemptr;
++ u32 mem_offs;
++ int i;
++
++ FN_ENTER;
++
++ priv->txdesc_size = sizeof(txdesc_t);
++
++ if (IS_ACX111(priv)) {
++ /* the acx111 txdesc is 4 bytes larger */
++ priv->txdesc_size = sizeof(txdesc_t) + 4;
++ }
++
++#if 0
++ priv->txdesc_start = (txdesc_t *) (priv->iobase2 + tx_queue_start);
++
++ acxlog(L_DEBUG, "priv->iobase2=%p\n"
++ "tx_queue_start=%08X\n"
++ "priv->txdesc_start=%p\n",
++ priv->iobase2,
++ tx_queue_start,
++ priv->txdesc_start);
++
++ priv->tx_free = TX_CNT;
++#endif
++ /* done by memset: priv->tx_head = 0; */
++ /* done by memset: priv->tx_tail = 0; */
++ txdesc = priv->txdesc_start;
++ mem_offs = tx_queue_start;
++ hostmemptr = priv->txhostdesc_startphy;
++ hostdesc = priv->txhostdesc_start;
++
++#if 0
++ if (IS_ACX111(priv)) {
++ /* ACX111 has a preinitialized Tx buffer! */
++ /* loop over whole send pool */
++ /* FIXME: do we have to do the hostmemptr stuff here?? */
++ for (i = 0; i < TX_CNT; i++) {
++ txdesc->HostMemPtr = ptr2acx(hostmemptr);
++ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
++ /* reserve two (hdr desc and payload desc) */
++ hostdesc += 2;
++ hostmemptr += 2 * sizeof(txhostdesc_t);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++ } else {
++ /* ACX100 Tx buffer needs to be initialized by us */
++ /* clear whole send pool. sizeof is safe here (we are acx100) */
++ memset(priv->txdesc_start, 0, TX_CNT * sizeof(txdesc_t));
++
++ /* loop over whole send pool */
++ for (i = 0; i < TX_CNT; i++) {
++ acxlog(L_DEBUG, "configure card tx descriptor: 0x%p, "
++ "size: 0x%X\n", txdesc, priv->txdesc_size);
++
++ /* pointer to hostdesc memory */
++ /* FIXME: type-incorrect assignment, might cause trouble
++ * in some cases */
++ txdesc->HostMemPtr = ptr2acx(hostmemptr);
++ /* initialise ctl */
++ txdesc->Ctl_8 = DESC_CTL_INIT;
++ txdesc->Ctl2_8 = 0;
++ /* point to next txdesc */
++ txdesc->pNextDesc = cpu2acx(mem_offs + priv->txdesc_size);
++ /* reserve two (hdr desc and payload desc) */
++ hostdesc += 2;
++ hostmemptr += 2 * sizeof(txhostdesc_t);
++ /* go to the next one */
++ mem_offs += priv->txdesc_size;
++ /* ++ is safe here (we are acx100) */
++ txdesc++;
++ }
++ /* go back to the last one */
++ txdesc--;
++ /* and point to the first making it a ring buffer */
++ txdesc->pNextDesc = cpu2acx(tx_queue_start);
++ }
++#endif
++ FN_EXIT0;
++}
++
++
++/***************************************************************
++** acx_create_rx_desc_queue
++*/
++static void
++acx_create_rx_desc_queue(wlandevice_t *priv, u32 rx_queue_start)
++{
++ rxdesc_t *rxdesc;
++ u32 mem_offs;
++ int i;
++
++ FN_ENTER;
++
++ /* done by memset: priv->rx_tail = 0; */
++
++ /* ACX111 doesn't need any further config: preconfigures itself.
++ * Simply print ring buffer for debugging */
++ if (IS_ACX111(priv)) {
++ /* rxdesc_start already set here */
++
++ priv->rxdesc_start = (rxdesc_t *) ((u8 *)priv->iobase2 + rx_queue_start);
++
++ rxdesc = priv->rxdesc_start;
++ for (i = 0; i < RX_CNT; i++) {
++ acxlog(L_DEBUG, "rx descriptor %d @ 0x%p\n", i, rxdesc);
++ rxdesc = priv->rxdesc_start = (rxdesc_t *)
++ (priv->iobase2 + acx2cpu(rxdesc->pNextDesc));
++ }
++ } else {
++ /* we didn't pre-calculate rxdesc_start in case of ACX100 */
++ /* rxdesc_start should be right AFTER Tx pool */
++ priv->rxdesc_start = (rxdesc_t *)
++ ((u8 *) priv->txdesc_start + (TX_CNT * sizeof(txdesc_t)));
++ /* NB: sizeof(txdesc_t) above is valid because we know
++ ** we are in if(acx100) block. Beware of cut-n-pasting elsewhere!
++ ** acx111's txdesc is larger! */
++
++ memset(priv->rxdesc_start, 0, RX_CNT * sizeof(rxdesc_t));
++
++ /* loop over whole receive pool */
++ rxdesc = priv->rxdesc_start;
++ mem_offs = rx_queue_start;
++ for (i = 0; i < RX_CNT; i++) {
++ acxlog(L_DEBUG, "rx descriptor @ 0x%p\n", rxdesc);
++ rxdesc->Ctl_8 = DESC_CTL_RECLAIM | DESC_CTL_AUTODMA;
++ /* point to next rxdesc */
++ rxdesc->pNextDesc = cpu2acx(mem_offs + sizeof(rxdesc_t));
++ /* go to the next one */
++ mem_offs += sizeof(rxdesc_t);
++ rxdesc++;
++ }
++ /* go to the last one */
++ rxdesc--;
++
++ /* and point to the first making it a ring buffer */
++ rxdesc->pNextDesc = cpu2acx(rx_queue_start);
++ }
++ FN_EXIT0;
++}
++
++
++/***************************************************************
++** acx_create_desc_queues
++*/
++void
++acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start)
++{
++ acx_create_tx_desc_queue(priv, tx_queue_start);
++ acx_create_rx_desc_queue(priv, rx_queue_start);
++}
++
++
++/***************************************************************
++** acxpci_s_proc_diag_output
++*/
++char*
++acxpci_s_proc_diag_output(char *p, wlandevice_t *priv)
++{
++ const char *rtl, *thd, *ttl;
++ rxhostdesc_t *rxhostdesc;
++ txdesc_t *txdesc;
++ int i;
++
++ FN_ENTER;
++
++ p += sprintf(p, "** Rx buf **\n");
++ rxhostdesc = priv->rxhostdesc_start;
++ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
++ rtl = (i == priv->rx_tail) ? " [tail]" : "";
++ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)) )
++ p += sprintf(p, "%02u FULL%s\n", i, rtl);
++ else
++ p += sprintf(p, "%02u empty%s\n", i, rtl);
++ rxhostdesc++;
++ }
++ p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", priv->tx_free,
++ acx_queue_stopped(priv->netdev) ? "STOPPED" : "running");
++ txdesc = priv->txdesc_start;
++ if (txdesc) for (i = 0; i < TX_CNT; i++) {
++ thd = (i == priv->tx_head) ? " [head]" : "";
++ ttl = (i == priv->tx_tail) ? " [tail]" : "";
++ if (txdesc->Ctl_8 & DESC_CTL_ACXDONE)
++ p += sprintf(p, "%02u DONE (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
++ else
++ if (!(txdesc->Ctl_8 & DESC_CTL_HOSTOWN))
++ p += sprintf(p, "%02u TxWait (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
++ else
++ p += sprintf(p, "%02u empty (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++ p += sprintf(p,
++ "\n"
++ "** PCI data **\n"
++ "txbuf_start %p, txbuf_area_size %u, txbuf_startphy %08llx\n"
++ "txdesc_size %u, txdesc_start %p\n"
++ "txhostdesc_start %p, txhostdesc_area_size %u, txhostdesc_startphy %08llx\n"
++ "rxdesc_start %p\n"
++ "rxhostdesc_start %p, rxhostdesc_area_size %u, rxhostdesc_startphy %08llx\n"
++ "rxbuf_start %p, rxbuf_area_size %u, rxbuf_startphy %08llx\n",
++ priv->txbuf_start, priv->txbuf_area_size, (u64)priv->txbuf_startphy,
++ priv->txdesc_size, priv->txdesc_start,
++ priv->txhostdesc_start, priv->txhostdesc_area_size, (u64)priv->txhostdesc_startphy,
++ priv->rxdesc_start,
++ priv->rxhostdesc_start, priv->rxhostdesc_area_size, (u64)priv->rxhostdesc_startphy,
++ priv->rxbuf_start, priv->rxbuf_area_size, (u64)priv->rxbuf_startphy);
++
++ FN_EXIT0;
++ return p;
++}
++
++
++/***********************************************************************
++*/
++int
++acx_proc_eeprom_output(char *buf, wlandevice_t *priv)
++{
++ char *p = buf;
++ int i;
++
++ FN_ENTER;
++
++ for (i = 0; i < 0x400; i++) {
++ acx_read_eeprom_offset(priv, i, p++);
++ }
++
++ FN_EXIT1(p - buf);
++ return p - buf;
++}
++
++
++/***********************************************************************
++*/
++void
++acx_set_interrupt_mask(wlandevice_t *priv)
++{
++ if (IS_ACX111(priv)) {
++ priv->irq_mask = (u16) ~(0
++ /* | HOST_INT_RX_DATA */
++ | HOST_INT_TX_COMPLETE
++ /* | HOST_INT_TX_XFER */
++ | HOST_INT_RX_COMPLETE
++ /* | HOST_INT_DTIM */
++ /* | HOST_INT_BEACON */
++ /* | HOST_INT_TIMER */
++ /* | HOST_INT_KEY_NOT_FOUND */
++ | HOST_INT_IV_ICV_FAILURE
++ | HOST_INT_CMD_COMPLETE
++ | HOST_INT_INFO
++ /* | HOST_INT_OVERFLOW */
++ /* | HOST_INT_PROCESS_ERROR */
++ | HOST_INT_SCAN_COMPLETE
++ | HOST_INT_FCS_THRESHOLD
++ /* | HOST_INT_UNKNOWN */
++ );
++ priv->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */
++ } else {
++ priv->irq_mask = (u16) ~(0
++ /* | HOST_INT_RX_DATA */
++ | HOST_INT_TX_COMPLETE
++ /* | HOST_INT_TX_XFER */
++ | HOST_INT_RX_COMPLETE
++ /* | HOST_INT_DTIM */
++ /* | HOST_INT_BEACON */
++ /* | HOST_INT_TIMER */
++ /* | HOST_INT_KEY_NOT_FOUND */
++ /* | HOST_INT_IV_ICV_FAILURE */
++ | HOST_INT_CMD_COMPLETE
++ | HOST_INT_INFO
++ /* | HOST_INT_OVERFLOW */
++ /* | HOST_INT_PROCESS_ERROR */
++ | HOST_INT_SCAN_COMPLETE
++ /* | HOST_INT_FCS_THRESHOLD */
++ /* | HOST_INT_UNKNOWN */
++ );
++ priv->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */
++ }
++}
++
++
++/***********************************************************************
++*/
++int
++acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
++{
++ /* since it can be assumed that at least the Maxim radio has a
++ * maximum power output of 20dBm and since it also can be
++ * assumed that these values drive the DAC responsible for
++ * setting the linear Tx level, I'd guess that these values
++ * should be the corresponding linear values for a dBm value,
++ * in other words: calculate the values from that formula:
++ * Y [dBm] = 10 * log (X [mW])
++ * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
++ * and you're done...
++ * Hopefully that's ok, but you never know if we're actually
++ * right... (especially since Windows XP doesn't seem to show
++ * actual Tx dBm values :-P) */
++
++ /* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the
++ * values are EXACTLY mW!!! Not sure about RFMD and others,
++ * though... */
++ static const u8 dbm2val_maxim[21] = {
++ 63, 63, 63, 62,
++ 61, 61, 60, 60,
++ 59, 58, 57, 55,
++ 53, 50, 47, 43,
++ 38, 31, 23, 13,
++ 0
++ };
++ static const u8 dbm2val_rfmd[21] = {
++ 0, 0, 0, 1,
++ 2, 2, 3, 3,
++ 4, 5, 6, 8,
++ 10, 13, 16, 20,
++ 25, 32, 41, 50,
++ 63
++ };
++ const u8 *table;
++
++ switch (priv->radio_type) {
++ case RADIO_MAXIM_0D:
++ table = &dbm2val_maxim[0];
++ break;
++ case RADIO_RFMD_11:
++ case RADIO_RALINK_15:
++ table = &dbm2val_rfmd[0];
++ break;
++ default:
++ printk("%s: unknown/unsupported radio type, "
++ "cannot modify tx power level yet!\n",
++ priv->netdev->name);
++ return NOT_OK;
++ }
++ printk("%s: changing radio power level to %u dBm (%u)\n",
++ priv->netdev->name, level_dbm, table[level_dbm]);
++ acxpci_s_write_phy_reg(priv, 0x11, table[level_dbm]);
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_init_module
++*
++* Module initialization routine, called once at module load time.
++*
++* Returns:
++* 0 - success
++* ~0 - failure, module is unloaded.
++*
++* Call context:
++* process thread (insmod or modprobe)
++----------------------------------------------------------------*/
++int __init
++acxcfi_e_init_module(void)
++{
++ int res;
++
++ FN_ENTER;
++
++ printk("acx: compiled to use 16bit I/O access only "
++ "(compatibility mode)\n");
++
++ acxlog(L_INIT, "running on a little-endian CPU\n");
++
++ acxlog(L_INIT,
++ "Compact Flash module " WLAN_RELEASE " initialized, "
++ "waiting for cards to probe...\n");
++
++ /*
++ * Now let configure device
++ * GPIOs
++ */
++ pca9535_gpio_direction(GPIO6, GPIO_OUTPUT);
++ pca9535_gpio_direction(GPIO12, GPIO_OUTPUT);
++
++ if ((omap_request_gpio(11)) < 0) {
++ printk("Error requesting gpio 11\n");
++ return -EIO;
++ }
++ omap_set_gpio_direction (11, 1);
++ omap_set_gpio_dataout (11, 1);
++
++ res = driver_register(&acx_driver);
++
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/*----------------------------------------------------------------
++* acx_cleanup_module
++*
++* Called at module unload time. This is our last chance to
++* clean up after ourselves.
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++void __exit
++acxcfi_e_cleanup_module(void)
++{
++ struct net_device *dev;
++ unsigned long flags;
++
++ FN_ENTER;
++
++ /* Since the whole module is about to be unloaded,
++ * we recursively shutdown all cards we handled instead
++ * of doing it in remove_pci() (which will be activated by us
++ * via pci_unregister_driver at the end).
++ * remove_pci() might just get called after a card eject,
++ * that's why hardware operations have to be done here instead
++ * when the hardware is available. */
++
++ down(&root_acx_dev_sem);
++
++ dev = root_acx_dev.newest;
++ while (dev != NULL) {
++ /* doh, netdev_priv() doesn't have const! */
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ /* disable both Tx and Rx to shut radio down properly */
++ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0);
++
++#ifdef REDUNDANT
++ /* put the eCPU to sleep to save power
++ * Halting is not possible currently,
++ * since not supported by all firmware versions */
++ acx_s_issue_cmd(priv, ACX100_CMD_SLEEP, NULL, 0);
++#endif
++ acx_lock(priv, flags);
++
++ /* disable power LED to save power :-) */
++ acxlog(L_INIT, "switching off power LED to save power :-)\n");
++ acx_l_power_led(priv, 0);
++
++ /* stop our eCPU */
++ if (IS_ACX111(priv)) {
++ /* FIXME: does this actually keep halting the eCPU?
++ * I don't think so...
++ */
++ acx_l_reset_mac(priv);
++ } else {
++ u16 temp;
++
++ /* halt eCPU */
++ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
++ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
++ acx_write_flush(priv);
++ }
++
++ acx_unlock(priv, flags);
++
++ acx_sem_unlock(priv);
++
++ dev = priv->prev_nd;
++ }
++
++ up(&root_acx_dev_sem);
++
++ omap_free_gpio(11);
++ driver_unregister(&acx_driver);
++
++ FN_EXIT0;
++}
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/common.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/common.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/common.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/common.c 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,6590 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/proc_fs.h>
++#include <linux/if_arp.h>
++#include <linux/rtnetlink.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/wireless.h>
++#include <linux/pm.h>
++#include <linux/vmalloc.h>
++#include <asm/bug.h>
++#if WIRELESS_EXT >= 13
++#include <net/iw_handler.h>
++#endif /* WE >= 13 */
++
++#include "acx.h"
++
++
++#define rdtscl(a)
++
++/***********************************************************************
++*/
++static client_t *acx_l_sta_list_alloc(wlandevice_t *priv);
++static client_t *acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address);
++
++static int acx_l_process_data_frame_master(wlandevice_t *priv, rxbuffer_t *rxbuf);
++static int acx_l_process_data_frame_client(wlandevice_t *priv, rxbuffer_t *rxbuf);
++/* static int acx_l_process_NULL_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala); */
++static int acx_l_process_mgmt_frame(wlandevice_t *priv, rxbuffer_t *rxbuf);
++static void acx_l_process_disassoc_from_sta(wlandevice_t *priv, const wlan_fr_disassoc_t *req);
++static void acx_l_process_disassoc_from_ap(wlandevice_t *priv, const wlan_fr_disassoc_t *req);
++static void acx_l_process_deauth_from_sta(wlandevice_t *priv, const wlan_fr_deauthen_t *req);
++static void acx_l_process_deauth_from_ap(wlandevice_t *priv, const wlan_fr_deauthen_t *req);
++static int acx_l_process_probe_response(wlandevice_t *priv, wlan_fr_proberesp_t *req, const rxbuffer_t *rxbuf);
++static int acx_l_process_assocresp(wlandevice_t *priv, const wlan_fr_assocresp_t *req);
++static int acx_l_process_reassocresp(wlandevice_t *priv, const wlan_fr_reassocresp_t *req);
++static int acx_l_process_authen(wlandevice_t *priv, const wlan_fr_authen_t *req);
++static int acx_l_transmit_assocresp(wlandevice_t *priv, const wlan_fr_assocreq_t *req);
++static int acx_l_transmit_reassocresp(wlandevice_t *priv, const wlan_fr_reassocreq_t *req);
++static int acx_l_transmit_deauthen(wlandevice_t *priv, const u8 *addr, u16 reason);
++static int acx_l_transmit_authen1(wlandevice_t *priv);
++static int acx_l_transmit_authen2(wlandevice_t *priv, const wlan_fr_authen_t *req, client_t *clt);
++static int acx_l_transmit_authen3(wlandevice_t *priv, const wlan_fr_authen_t *req);
++static int acx_l_transmit_authen4(wlandevice_t *priv, const wlan_fr_authen_t *req);
++static int acx_l_transmit_assoc_req(wlandevice_t *priv);
++
++
++/***********************************************************************
++*/
++#if ACX_DEBUG
++unsigned int acx_debug = L_ASSOC|L_INIT;
++#endif
++#if USE_FW_LOADER_LEGACY
++static char *firmware_dir;
++#endif
++#if SEPARATE_DRIVER_INSTANCES
++static int card;
++#endif
++
++/* introduced earlier than 2.6.10, but takes more memory, so don't use it
++ * if there's no compile warning by kernel */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
++
++#if ACX_DEBUG
++/* parameter is 'debug', corresponding var is acx_debug */
++module_param_named(debug, acx_debug, uint, 0);
++#endif
++#if USE_FW_LOADER_LEGACY
++module_param(firmware_dir, charp, 0);
++#endif
++
++#else
++
++#if ACX_DEBUG
++/* doh, 2.6.x screwed up big time: here the define has its own ";"
++ * ("double ; detected"), yet in 2.4.x it DOESN'T (the sane thing to do),
++ * grrrrr! */
++MODULE_PARM(acx_debug, "i");
++#endif
++#if USE_FW_LOADER_LEGACY
++MODULE_PARM(firmware_dir, "s");
++#endif
++
++#endif
++
++#if ACX_DEBUG
++MODULE_PARM_DESC(debug, "Debug level mask (see L_xxx constants)");
++#endif
++#if USE_FW_LOADER_LEGACY
++MODULE_PARM_DESC(firmware_dir, "Directory to load acx100 firmware files from");
++#endif
++#if SEPARATE_DRIVER_INSTANCES
++MODULE_PARM(card, "i");
++MODULE_PARM_DESC(card, "Associate only with card-th acx100 card from this driver instance");
++#endif
++
++/* Shoundn't be needed now, acx.firmware_dir= should work */
++#if 0 /* USE_FW_LOADER_LEGACY */
++static int __init
++acx_get_firmware_dir(const char *str)
++{
++ /* I've seen other drivers just pass the string pointer,
++ * so hopefully that's safe */
++ firmware_dir = str;
++ return OK;
++}
++__setup("acx_firmware_dir=", acx_get_firmware_dir);
++#endif
++
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("Dual MPL/GPL");
++#endif
++/* USB had this: MODULE_AUTHOR("Martin Wawro <martin.wawro AT uni-dortmund.de>"); */
++MODULE_AUTHOR("ACX100 Open Source Driver development team");
++MODULE_DESCRIPTION("Driver for TI ACX1xx based wireless cards (CardBus/PCI/USB)");
++
++
++/***********************************************************************
++*/
++/* Probably a number of acx's itermediate buffers for USB transfers,
++** not to be confused with number of descriptors in tx/rx rings
++** (which are not directly accessible to host in USB devices) */
++#define USB_RX_CNT 10
++#define USB_TX_CNT 10
++
++
++/***********************************************************************
++*/
++
++/* minutes to wait until next radio recalibration: */
++#define RECALIB_PAUSE 5
++
++const u8 reg_domain_ids[] =
++ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41, 0x51 };
++/* stupid workaround for the fact that in C the size of an external array
++ * cannot be determined from within a second file */
++const u8 reg_domain_ids_len = sizeof(reg_domain_ids);
++static const u16 reg_domain_channel_masks[] =
++ { 0x07ff, 0x07ff, 0x1fff, 0x0600, 0x1e00, 0x2000, 0x3fff, 0x01fc };
++
++
++/***********************************************************************
++** Debugging support
++*/
++#ifdef PARANOID_LOCKING
++static unsigned max_lock_time;
++static unsigned max_sem_time;
++
++void
++acx_lock_unhold() { max_lock_time = 0; }
++void
++acx_sem_unhold() { max_sem_time = 0; }
++
++static inline const char*
++sanitize_str(const char *s)
++{
++ const char* t = strrchr(s, '/');
++ if (t) return t + 1;
++ return s;
++}
++
++void
++acx_lock_debug(wlandevice_t *priv, const char* where)
++{
++ int count = 100*1000*1000;
++ where = sanitize_str(where);
++ while (--count) {
++ if (!spin_is_locked(&priv->lock)) break;
++ cpu_relax();
++ }
++ if (!count) {
++ printk(KERN_EMERG "LOCKUP: already taken at %s!\n", priv->last_lock);
++ BUG();
++ }
++ priv->last_lock = where;
++ rdtscl(priv->lock_time);
++}
++void
++acx_unlock_debug(wlandevice_t *priv, const char* where)
++{
++#ifdef SMP
++ if (!spin_is_locked(&priv->lock)) {
++ where = sanitize_str(where);
++ printk(KERN_EMERG "STRAY UNLOCK at %s!\n", where);
++ BUG();
++ }
++#endif
++ if (acx_debug & L_LOCK) {
++ unsigned diff;
++ rdtscl(diff);
++ diff -= priv->lock_time;
++ if (diff > max_lock_time) {
++ where = sanitize_str(where);
++ printk("max lock hold time %d CPU ticks from %s "
++ "to %s\n", diff, priv->last_lock, where);
++ max_lock_time = diff;
++ }
++ }
++}
++void
++acx_down_debug(wlandevice_t *priv, const char* where)
++{
++ int sem_count;
++ int count = 5000/5;
++ where = sanitize_str(where);
++
++ while (--count) {
++ sem_count = atomic_read(&priv->sem.count);
++ if (sem_count) break;
++ msleep(5);
++ }
++ if (!count) {
++ printk(KERN_EMERG "D STATE at %s! last sem at %s\n",
++ where, priv->last_sem);
++ dump_stack();
++ }
++ priv->last_sem = where;
++ priv->sem_time = jiffies;
++ down(&priv->sem);
++ if (acx_debug & L_LOCK) {
++ printk("%s: sem_down %d -> %d\n",
++ where, sem_count, atomic_read(&priv->sem.count));
++ }
++}
++void
++acx_up_debug(wlandevice_t *priv, const char* where)
++{
++ int sem_count = atomic_read(&priv->sem.count);
++ if (sem_count) {
++ where = sanitize_str(where);
++ printk(KERN_EMERG "STRAY UP at %s! sem.count=%d\n", where, sem_count);
++ dump_stack();
++ }
++ if (acx_debug & L_LOCK) {
++ unsigned diff = jiffies - priv->sem_time;
++ if (diff > max_sem_time) {
++ where = sanitize_str(where);
++ printk("max sem hold time %d jiffies from %s "
++ "to %s\n", diff, priv->last_sem, where);
++ max_sem_time = diff;
++ }
++ }
++ up(&priv->sem);
++ if (acx_debug & L_LOCK) {
++ where = sanitize_str(where);
++ printk("%s: sem_up %d -> %d\n",
++ where, sem_count, atomic_read(&priv->sem.count));
++ }
++}
++#endif /* PARANOID_LOCKING */
++
++
++/***********************************************************************
++*/
++#if ACX_DEBUG > 1
++
++static int acx_debug_func_indent;
++#define DEBUG_TSC 0
++#define FUNC_INDENT_INCREMENT 2
++
++#if DEBUG_TSC
++#define TIMESTAMP(d) unsigned long d; rdtscl(d)
++#else
++#define TIMESTAMP(d) unsigned long d = jiffies
++#endif
++
++static const char
++spaces[] = " " " "; /* Nx10 spaces */
++
++void
++log_fn_enter(const char *funcname)
++{
++ int indent;
++ TIMESTAMP(d);
++
++ indent = acx_debug_func_indent;
++ if (indent >= sizeof(spaces))
++ indent = sizeof(spaces)-1;
++
++ printk("%08ld %s==> %s\n",
++ d % 100000000,
++ spaces + (sizeof(spaces)-1) - indent,
++ funcname
++ );
++
++ acx_debug_func_indent += FUNC_INDENT_INCREMENT;
++}
++void
++log_fn_exit(const char *funcname)
++{
++ int indent;
++ TIMESTAMP(d);
++
++ acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
++
++ indent = acx_debug_func_indent;
++ if (indent >= sizeof(spaces))
++ indent = sizeof(spaces)-1;
++
++ printk("%08ld %s<== %s\n",
++ d % 100000000,
++ spaces + (sizeof(spaces)-1) - indent,
++ funcname
++ );
++}
++void
++log_fn_exit_v(const char *funcname, int v)
++{
++ int indent;
++ TIMESTAMP(d);
++
++ acx_debug_func_indent -= FUNC_INDENT_INCREMENT;
++
++ indent = acx_debug_func_indent;
++ if (indent >= sizeof(spaces))
++ indent = sizeof(spaces)-1;
++
++ printk("%08ld %s<== %s: %08X\n",
++ d % 100000000,
++ spaces + (sizeof(spaces)-1) - indent,
++ funcname,
++ v
++ );
++}
++#endif /* ACX_DEBUG > 1 */
++
++
++/***********************************************************************
++** Basically a msleep with logging
++*/
++void
++acx_s_msleep(int ms)
++{
++ FN_ENTER;
++ msleep(ms);
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** Not inlined: it's larger than it seems
++*/
++void
++acx_print_mac(const char *head, const u8 *mac, const char *tail)
++{
++ printk("%s"MACSTR"%s", head, MAC(mac), tail);
++}
++
++
++/***********************************************************************
++** acx_get_status_name
++*/
++static const char*
++acx_get_status_name(u16 status)
++{
++ static const char * const str[] = {
++ "STOPPED", "SCANNING", "WAIT_AUTH",
++ "AUTHENTICATED", "ASSOCIATED", "INVALID??"
++ };
++ return str[(status < VEC_SIZE(str)) ? status : VEC_SIZE(str)-1];
++}
++
++
++/***********************************************************************
++** acx_get_packet_type_string
++*/
++#if ACX_DEBUG
++const char*
++acx_get_packet_type_string(u16 fc)
++{
++ static const char * const mgmt_arr[] = {
++ "MGMT/AssocReq", "MGMT/AssocResp", "MGMT/ReassocReq",
++ "MGMT/ReassocResp", "MGMT/ProbeReq", "MGMT/ProbeResp",
++ "MGMT/UNKNOWN", "MGMT/UNKNOWN", "MGMT/Beacon", "MGMT/ATIM",
++ "MGMT/Disassoc", "MGMT/Authen", "MGMT/Deauthen"
++ };
++ static const char * const ctl_arr[] = {
++ "CTL/PSPoll", "CTL/RTS", "CTL/CTS", "CTL/Ack", "CTL/CFEnd",
++ "CTL/CFEndCFAck"
++ };
++ static const char * const data_arr[] = {
++ "DATA/DataOnly", "DATA/Data CFAck", "DATA/Data CFPoll",
++ "DATA/Data CFAck/CFPoll", "DATA/Null", "DATA/CFAck",
++ "DATA/CFPoll", "DATA/CFAck/CFPoll"
++ };
++ const char *str = "UNKNOWN";
++ u8 fstype = (WF_FC_FSTYPE & fc) >> 4;
++ u8 ctl;
++
++ switch (WF_FC_FTYPE & fc) {
++ case WF_FTYPE_MGMT:
++ str = "MGMT/UNKNOWN";
++ if (fstype < VEC_SIZE(mgmt_arr))
++ str = mgmt_arr[fstype];
++ break;
++ case WF_FTYPE_CTL:
++ ctl = fstype - 0x0a;
++ str = "CTL/UNKNOWN";
++ if (ctl < VEC_SIZE(ctl_arr))
++ str = ctl_arr[ctl];
++ break;
++ case WF_FTYPE_DATA:
++ str = "DATA/UNKNOWN";
++ if (fstype < VEC_SIZE(data_arr))
++ str = data_arr[fstype];
++ break;
++ }
++ return str;
++}
++#endif
++
++
++/***********************************************************************
++** acx_cmd_status_str
++*/
++const char*
++acx_cmd_status_str(unsigned int state)
++{
++ static const char * const cmd_error_strings[] = {
++ "Idle",
++ "Success",
++ "Unknown Command",
++ "Invalid Information Element",
++ "Channel rejected",
++ "Channel invalid in current regulatory domain",
++ "MAC invalid",
++ "Command rejected (read-only information element)",
++ "Command rejected",
++ "Already asleep",
++ "TX in progress",
++ "Already awake",
++ "Write only",
++ "RX in progress",
++ "Invalid parameter",
++ "Scan in progress",
++ "Failed"
++ };
++ return state < VEC_SIZE(cmd_error_strings) ?
++ cmd_error_strings[state] : "UNKNOWN REASON";
++}
++
++
++/***********************************************************************
++** get_status_string
++*/
++static const char*
++get_status_string(unsigned int status)
++{
++ /* A bit shortened, but hopefully still understandable */
++ static const char * const status_str[] = {
++ /* 0 */ "Successful",
++ /* 1 */ "Unspecified failure",
++ /* 2 */ "reserved",
++ /* 3 */ "reserved",
++ /* 4 */ "reserved",
++ /* 5 */ "reserved",
++ /* 6 */ "reserved",
++ /* 7 */ "reserved",
++ /* 8 */ "reserved",
++ /* 9 */ "reserved",
++ /*10 */ "Cannot support all requested capabilities in Capability Information field",
++ /*11 */ "Reassoc denied (reason outside of 802.11b scope)",
++ /*12 */ "Assoc denied (reason outside of 802.11b scope), maybe MAC filtering by peer?",
++ /*13 */ "Responding station doesnt support specified auth algorithm",
++ /*14 */ "Auth rejected: wrong transaction sequence number",
++ /*15 */ "Auth rejected: challenge failure",
++ /*16 */ "Auth rejected: timeout for next frame in sequence",
++ /*17 */ "Assoc denied: too many STAs on this AP",
++ /*18 */ "Assoc denied: requesting STA doesnt support all data rates in basic set",
++ /*19 */ "Assoc denied: requesting STA doesnt support Short Preamble",
++ /*20 */ "Assoc denied: requesting STA doesnt support PBCC Modulation",
++ /*21 */ "Assoc denied: requesting STA doesnt support Channel Agility"
++ /*22 */ "reserved",
++ /*23 */ "reserved",
++ /*24 */ "reserved",
++ /*25 */ "Assoc denied: requesting STA doesnt support Short Slot Time",
++ /*26 */ "Assoc denied: requesting STA doesnt support DSSS-OFDM"
++ };
++
++ return status_str[status < VEC_SIZE(status_str) ? status : 2];
++}
++
++
++/***********************************************************************
++*/
++void
++acx_log_bad_eid(wlan_hdr_t* hdr, int len, wlan_ie_t* ie_ptr)
++{
++ acxlog(L_ASSOC, "acx: unknown EID %d in mgmt frame at offset %d\n",
++ ie_ptr->eid, (int) ((u8*)ie_ptr - (u8*)hdr));
++ if (acx_debug & (L_DATA|L_ASSOC)) {
++ printk("frame (%s): ",
++ acx_get_packet_type_string(le16_to_cpu(hdr->fc)));
++ acx_dump_bytes(hdr, len);
++ }
++}
++
++
++/***********************************************************************
++*/
++#if ACX_DEBUG
++void
++acx_dump_bytes(const void *data, int num)
++{
++ const u8* ptr = (const u8*)data;
++
++ if (num <= 0) {
++ printk("\n");
++ return;
++ }
++
++ while (num >= 16) {
++ printk( "%02X %02X %02X %02X %02X %02X %02X %02X "
++ "%02X %02X %02X %02X %02X %02X %02X %02X\n",
++ ptr[0], ptr[1], ptr[2], ptr[3],
++ ptr[4], ptr[5], ptr[6], ptr[7],
++ ptr[8], ptr[9], ptr[10], ptr[11],
++ ptr[12], ptr[13], ptr[14], ptr[15]);
++ num -= 16;
++ ptr += 16;
++ }
++ if (num > 0) {
++ while (--num > 0)
++ printk("%02X ", *ptr++);
++ printk("%02X\n", *ptr);
++ }
++}
++#endif
++
++
++/***********************************************************************
++** maps acx111 tx descr rate field to acx100 one
++*/
++const u8
++bitpos2rate100[] = {
++ RATE100_1 ,/* 0 */
++ RATE100_2 ,/* 1 */
++ RATE100_5 ,/* 2 */
++ RATE100_2 ,/* 3, should not happen */
++ RATE100_2 ,/* 4, should not happen */
++ RATE100_11 ,/* 5 */
++ RATE100_2 ,/* 6, should not happen */
++ RATE100_2 ,/* 7, should not happen */
++ RATE100_22 ,/* 8 */
++ RATE100_2 ,/* 9, should not happen */
++ RATE100_2 ,/* 10, should not happen */
++ RATE100_2 ,/* 11, should not happen */
++ RATE100_2 ,/* 12, should not happen */
++ RATE100_2 ,/* 13, should not happen */
++ RATE100_2 ,/* 14, should not happen */
++ RATE100_2 ,/* 15, should not happen */
++};
++
++u8
++acx_rate111to100(u16 r) {
++ return bitpos2rate100[highest_bit(r)];
++}
++
++
++/***********************************************************************
++** Calculate level like the feb 2003 windows driver seems to do
++*/
++static u8
++acx_signal_to_winlevel(u8 rawlevel)
++{
++ /* u8 winlevel = (u8) (0.5 + 0.625 * rawlevel); */
++ u8 winlevel = ((4 + (rawlevel * 5)) / 8);
++
++ if (winlevel > 100)
++ winlevel = 100;
++ return winlevel;
++}
++
++u8
++acx_signal_determine_quality(u8 signal, u8 noise)
++{
++ int qual;
++
++ qual = (((signal - 30) * 100 / 70) + (100 - noise * 4)) / 2;
++
++ if (qual > 100)
++ return 100;
++ if (qual < 0)
++ return 0;
++ return qual;
++}
++
++
++/***********************************************************************
++** Interrogate/configure commands
++*/
++static const u16
++CtlLength[] = {
++ 0,
++ ACX100_IE_ACX_TIMER_LEN,
++ ACX1xx_IE_POWER_MGMT_LEN,
++ ACX1xx_IE_QUEUE_CONFIG_LEN,
++ ACX100_IE_BLOCK_SIZE_LEN,
++ ACX1xx_IE_MEMORY_CONFIG_OPTIONS_LEN,
++ ACX1xx_IE_RATE_FALLBACK_LEN,
++ ACX100_IE_WEP_OPTIONS_LEN,
++ ACX1xx_IE_MEMORY_MAP_LEN, /* ACX1xx_IE_SSID_LEN, */
++ 0,
++ ACX1xx_IE_ASSOC_ID_LEN,
++ 0,
++ ACX111_IE_CONFIG_OPTIONS_LEN,
++ ACX1xx_IE_FWREV_LEN,
++ ACX1xx_IE_FCS_ERROR_COUNT_LEN,
++ ACX1xx_IE_MEDIUM_USAGE_LEN,
++ ACX1xx_IE_RXCONFIG_LEN,
++ 0,
++ 0,
++ ACX1xx_IE_FIRMWARE_STATISTICS_LEN,
++ 0,
++ ACX1xx_IE_FEATURE_CONFIG_LEN,
++ ACX111_IE_KEY_CHOOSE_LEN,
++};
++
++static const u16
++CtlLengthDot11[] = {
++ 0,
++ ACX1xx_IE_DOT11_STATION_ID_LEN,
++ 0,
++ ACX100_IE_DOT11_BEACON_PERIOD_LEN,
++ ACX1xx_IE_DOT11_DTIM_PERIOD_LEN,
++ ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN,
++ ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN,
++ ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE_LEN,
++ ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN,
++ 0,
++ ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN_LEN,
++ ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN,
++ 0,
++ ACX1xx_IE_DOT11_TX_POWER_LEVEL_LEN,
++ ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN,
++ ACX100_IE_DOT11_ED_THRESHOLD_LEN,
++ ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET_LEN,
++ 0,
++ 0,
++ 0,
++};
++
++#undef FUNC
++#define FUNC "configure"
++#if !ACX_DEBUG
++int
++acx_s_configure(wlandevice_t *priv, void *pdr, int type)
++{
++#else
++int
++acx_s_configure_debug(wlandevice_t *priv, void *pdr, int type, const char* typestr)
++{
++#endif
++ u16 len;
++ int res;
++
++ if (type < 0x1000)
++ len = CtlLength[type];
++ else
++ len = CtlLengthDot11[type - 0x1000];
++
++ acxlog(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
++ if (unlikely(!len)) {
++ acxlog(L_DEBUG, "zero-length type %s?!\n", typestr);
++ }
++
++ ((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
++ ((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
++ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIGURE, pdr, len + 4);
++ if (OK != res) {
++#if ACX_DEBUG
++ printk("%s: "FUNC"(type:%s) FAILED\n", priv->netdev->name, typestr);
++#else
++ printk("%s: "FUNC"(type:0x%X) FAILED\n", priv->netdev->name, type);
++#endif
++ /* dump_stack() is already done in issue_cmd() */
++ }
++ return res;
++}
++
++#undef FUNC
++#define FUNC "interrogate"
++#if !ACX_DEBUG
++int
++acx_s_interrogate(wlandevice_t *priv, void *pdr, int type)
++{
++#else
++int
++acx_s_interrogate_debug(wlandevice_t *priv, void *pdr, int type,
++ const char* typestr)
++{
++#endif
++ u16 len;
++ int res;
++
++ if (type < 0x1000)
++ len = CtlLength[type];
++ else
++ len = CtlLengthDot11[type-0x1000];
++ acxlog(L_CTL, FUNC"(type:%s,len:%u)\n", typestr, len);
++
++ printk("Type : %08x, Len : %04x\n",type,len);
++
++ ((acx_ie_generic_t *)pdr)->type = cpu_to_le16(type);
++ ((acx_ie_generic_t *)pdr)->len = cpu_to_le16(len);
++ res = acx_s_issue_cmd(priv, ACX1xx_CMD_INTERROGATE, pdr, len + 4);
++ if (OK != res) {
++#if ACX_DEBUG
++ printk("%s: "FUNC"(type:%s) FAILED\n", priv->netdev->name, typestr);
++#else
++ printk("%s: "FUNC"(type:0x%X) FAILED\n", priv->netdev->name, type);
++#endif
++ /* dump_stack() is already done in issue_cmd() */
++ }
++ return res;
++}
++
++#if CMD_DISCOVERY
++void
++great_inquisitor(wlandevice_t *priv)
++{
++ static struct {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ /* 0x200 was too large here: */
++ u8 data[0x100 - 4] ACX_PACKED;
++ } ie;
++ u16 type;
++
++ FN_ENTER;
++
++ /* 0..0x20, 0x1000..0x1020 */
++ for (type = 0; type <= 0x1020; type++) {
++ if (type == 0x21)
++ type = 0x1000;
++ ie.type = cpu_to_le16(type);
++ ie.len = cpu_to_le16(sizeof(ie) - 4);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_INTERROGATE, &ie, sizeof(ie));
++ }
++ FN_EXIT0;
++}
++#endif
++
++
++#ifdef CONFIG_PROC_FS
++/***********************************************************************
++** /proc files
++*/
++/***********************************************************************
++** acx_l_proc_output
++** Generate content for our /proc entry
++**
++** Arguments:
++** buf is a pointer to write output to
++** priv is the usual pointer to our private struct wlandevice
++** Returns:
++** number of bytes actually written to buf
++** Side effects:
++** none
++*/
++static int
++acx_l_proc_output(char *buf, wlandevice_t *priv)
++{
++ char *p = buf;
++ int i;
++
++ FN_ENTER;
++
++ p += sprintf(p,
++ "acx driver version:\t\t" WLAN_RELEASE "\n"
++ "Wireless extension version:\t" STRING(WIRELESS_EXT) "\n"
++ "chip name:\t\t\t%s (0x%08X)\n"
++ "radio type:\t\t\t0x%02X\n"
++ "form factor:\t\t\t0x%02X\n"
++ "EEPROM version:\t\t\t0x%02X\n"
++ "firmware version:\t\t%s (0x%08X)\n",
++ priv->chip_name, priv->firmware_id,
++ priv->radio_type,
++ priv->form_factor,
++ priv->eeprom_version,
++ priv->firmware_version, priv->firmware_numver);
++
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ struct client *bss = &priv->sta_list[i];
++ if (!bss->used) continue;
++ p += sprintf(p, "BSS %u BSSID "MACSTR" ESSID %s channel %u "
++ "Cap 0x%X SIR %u SNR %u\n",
++ i, MAC(bss->bssid), (char*)bss->essid, bss->channel,
++ bss->cap_info, bss->sir, bss->snr);
++ }
++ p += sprintf(p, "status:\t\t\t%u (%s)\n",
++ priv->status, acx_get_status_name(priv->status));
++
++ FN_EXIT1(p - buf);
++ return p - buf;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_s_proc_diag_output(char *buf, wlandevice_t *priv)
++{
++ char *p = buf;
++ fw_stats_t *fw_stats;
++ unsigned long flags;
++
++ FN_ENTER;
++
++ fw_stats = kmalloc(sizeof(fw_stats_t), GFP_KERNEL);
++ if (!fw_stats) {
++ FN_EXIT1(0);
++ return 0;
++ }
++ memset(fw_stats, 0, sizeof(fw_stats_t));
++
++ acx_lock(priv, flags);
++
++ if (IS_PCI(priv))
++ p = acxpci_s_proc_diag_output(p, priv);
++
++ p += sprintf(p,
++ "\n"
++ "** network status **\n"
++ "dev_state_mask 0x%04X\n"
++ "status %u (%s), "
++ "mode %u, channel %u, "
++ "reg_dom_id 0x%02X, reg_dom_chanmask 0x%04X, ",
++ priv->dev_state_mask,
++ priv->status, acx_get_status_name(priv->status),
++ priv->mode, priv->channel,
++ priv->reg_dom_id, priv->reg_dom_chanmask
++ );
++ p += sprintf(p,
++ "ESSID \"%s\", essid_active %d, essid_len %d, "
++ "essid_for_assoc \"%s\", nick \"%s\"\n"
++ "WEP ena %d, restricted %d, idx %d\n",
++ priv->essid, priv->essid_active, (int)priv->essid_len,
++ priv->essid_for_assoc, priv->nick,
++ priv->wep_enabled, priv->wep_restricted,
++ priv->wep_current_index);
++ p += sprintf(p, "dev_addr "MACSTR"\n", MAC(priv->dev_addr));
++ p += sprintf(p, "bssid "MACSTR"\n", MAC(priv->bssid));
++ p += sprintf(p, "ap_filter "MACSTR"\n", MAC(priv->ap));
++
++ p += sprintf(p,
++ "\n"
++ "** PHY status **\n"
++ "tx_disabled %d, tx_level_dbm %d\n" /* "tx_level_val %d, tx_level_auto %d\n" */
++ "sensitivity %d, antenna 0x%02X, ed_threshold %d, cca %d, preamble_mode %d\n"
++ "rts_threshold %d, short_retry %d, long_retry %d, msdu_lifetime %d, listen_interval %d, beacon_interval %d\n",
++ priv->tx_disabled, priv->tx_level_dbm, /* priv->tx_level_val, priv->tx_level_auto, */
++ priv->sensitivity, priv->antenna, priv->ed_threshold, priv->cca, priv->preamble_mode,
++ priv->rts_threshold, priv->short_retry, priv->long_retry, priv->msdu_lifetime, priv->listen_interval, priv->beacon_interval);
++
++ acx_unlock(priv, flags);
++
++ if (OK != acx_s_interrogate(priv, fw_stats, ACX1xx_IE_FIRMWARE_STATISTICS))
++ p += sprintf(p,
++ "\n"
++ "** Firmware **\n"
++ "QUERY FAILED!!\n");
++ else {
++ p += sprintf(p,
++ "\n"
++ "** Firmware **\n"
++ "version \"%s\"\n"
++ "tx_desc_overfl %u, rx_OutOfMem %u, rx_hdr_overfl %u, rx_hdr_use_next %u\n"
++ "rx_dropped_frame %u, rx_frame_ptr_err %u, rx_xfr_hint_trig %u, rx_dma_req %u\n"
++ "rx_dma_err %u, tx_dma_req %u, tx_dma_err %u, cmd_cplt %u, fiq %u\n"
++ "rx_hdrs %u, rx_cmplt %u, rx_mem_overfl %u, rx_rdys %u, irqs %u\n"
++ "acx_trans_procs %u, decrypt_done %u, dma_0_done %u, dma_1_done %u\n",
++ priv->firmware_version,
++ le32_to_cpu(fw_stats->tx_desc_of),
++ le32_to_cpu(fw_stats->rx_oom),
++ le32_to_cpu(fw_stats->rx_hdr_of),
++ le32_to_cpu(fw_stats->rx_hdr_use_next),
++ le32_to_cpu(fw_stats->rx_dropped_frame),
++ le32_to_cpu(fw_stats->rx_frame_ptr_err),
++ le32_to_cpu(fw_stats->rx_xfr_hint_trig),
++ le32_to_cpu(fw_stats->rx_dma_req),
++ le32_to_cpu(fw_stats->rx_dma_err),
++ le32_to_cpu(fw_stats->tx_dma_req),
++ le32_to_cpu(fw_stats->tx_dma_err),
++ le32_to_cpu(fw_stats->cmd_cplt),
++ le32_to_cpu(fw_stats->fiq),
++ le32_to_cpu(fw_stats->rx_hdrs),
++ le32_to_cpu(fw_stats->rx_cmplt),
++ le32_to_cpu(fw_stats->rx_mem_of),
++ le32_to_cpu(fw_stats->rx_rdys),
++ le32_to_cpu(fw_stats->irqs),
++ le32_to_cpu(fw_stats->acx_trans_procs),
++ le32_to_cpu(fw_stats->decrypt_done),
++ le32_to_cpu(fw_stats->dma_0_done),
++ le32_to_cpu(fw_stats->dma_1_done));
++ p += sprintf(p,
++ "tx_exch_complet %u, commands %u, acx_rx_procs %u\n"
++ "hw_pm_mode_changes %u, host_acks %u, pci_pm %u, acm_wakeups %u\n"
++ "wep_key_count %u, wep_default_key_count %u, dot11_def_key_mib %u\n"
++ "wep_key_not_found %u, wep_decrypt_fail %u\n",
++ le32_to_cpu(fw_stats->tx_exch_complet),
++ le32_to_cpu(fw_stats->commands),
++ le32_to_cpu(fw_stats->acx_rx_procs),
++ le32_to_cpu(fw_stats->hw_pm_mode_changes),
++ le32_to_cpu(fw_stats->host_acks),
++ le32_to_cpu(fw_stats->pci_pm),
++ le32_to_cpu(fw_stats->acm_wakeups),
++ le32_to_cpu(fw_stats->wep_key_count),
++ le32_to_cpu(fw_stats->wep_default_key_count),
++ le32_to_cpu(fw_stats->dot11_def_key_mib),
++ le32_to_cpu(fw_stats->wep_key_not_found),
++ le32_to_cpu(fw_stats->wep_decrypt_fail));
++ }
++
++ kfree(fw_stats);
++
++ FN_EXIT1(p - buf);
++ return p - buf;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_s_proc_phy_output(char *buf, wlandevice_t *priv)
++{
++ char *p = buf;
++ int i;
++
++ FN_ENTER;
++
++ /*
++ if (RADIO_RFMD_11 != priv->radio_type) {
++ printk("sorry, not yet adapted for radio types "
++ "other than RFMD, please verify "
++ "PHY size etc. first!\n");
++ goto end;
++ }
++ */
++
++ /* The PHY area is only 0x80 bytes long; further pages after that
++ * only have some page number registers with altered value,
++ * all other registers remain the same. */
++ for (i = 0; i < 0x80; i++) {
++ acx_s_read_phy_reg(priv, i, p++);
++ }
++
++ FN_EXIT1(p - buf);
++ return p - buf;
++}
++
++
++/***********************************************************************
++** acx_e_read_proc_XXXX
++** Handle our /proc entry
++**
++** Arguments:
++** standard kernel read_proc interface
++** Returns:
++** number of bytes written to buf
++** Side effects:
++** none
++*/
++static int
++acx_e_read_proc(char *buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++ wlandevice_t *priv = (wlandevice_t *)data;
++ unsigned long flags;
++ int length;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++ acx_lock(priv, flags);
++ /* fill buf */
++ length = acx_l_proc_output(buf, priv);
++ acx_unlock(priv, flags);
++ acx_sem_unlock(priv);
++
++ /* housekeeping */
++ if (length <= offset + count)
++ *eof = 1;
++ *start = buf + offset;
++ length -= offset;
++ if (length > count)
++ length = count;
++ if (length < 0)
++ length = 0;
++ FN_EXIT1(length);
++ return length;
++}
++
++static int
++acx_e_read_proc_diag(char *buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++ wlandevice_t *priv = (wlandevice_t *)data;
++ int length;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++ /* fill buf */
++ length = acx_s_proc_diag_output(buf, priv);
++ acx_sem_unlock(priv);
++
++ /* housekeeping */
++ if (length <= offset + count)
++ *eof = 1;
++ *start = buf + offset;
++ length -= offset;
++ if (length > count)
++ length = count;
++ if (length < 0)
++ length = 0;
++ FN_EXIT1(length);
++ return length;
++}
++
++static int
++acx_e_read_proc_eeprom(char *buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++ wlandevice_t *priv = (wlandevice_t *)data;
++ int length;
++
++ FN_ENTER;
++
++ /* fill buf */
++ length = 0;
++ if (IS_PCI(priv)) {
++ acx_sem_lock(priv);
++ length = acx_proc_eeprom_output(buf, priv);
++ acx_sem_unlock(priv);
++ }
++
++ /* housekeeping */
++ if (length <= offset + count)
++ *eof = 1;
++ *start = buf + offset;
++ length -= offset;
++ if (length > count)
++ length = count;
++ if (length < 0)
++ length = 0;
++ FN_EXIT1(length);
++ return length;
++}
++
++static int
++acx_e_read_proc_phy(char *buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++ wlandevice_t *priv = (wlandevice_t *)data;
++ int length;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++ /* fill buf */
++ length = acx_s_proc_phy_output(buf, priv);
++ acx_sem_unlock(priv);
++
++ /* housekeeping */
++ if (length <= offset + count)
++ *eof = 1;
++ *start = buf + offset;
++ length -= offset;
++ if (length > count)
++ length = count;
++ if (length < 0)
++ length = 0;
++ FN_EXIT1(length);
++ return length;
++}
++
++
++/***********************************************************************
++** /proc files registration
++*/
++static const char * const
++proc_files[] = { "", "_diag", "_eeprom", "_phy" };
++
++static read_proc_t * const
++acx_proc_funcs[] = {
++ acx_e_read_proc,
++ acx_e_read_proc_diag,
++ acx_e_read_proc_eeprom,
++ acx_e_read_proc_phy
++};
++
++static int
++manage_proc_entries(const struct net_device *dev, int remove)
++{
++ /* doh, netdev_priv() doesn't have const! */
++ wlandevice_t *priv = netdev_priv((struct net_device *)dev);
++ char procbuf[80];
++ int i;
++
++ for (i = 0; i < 4; i++) {
++ sprintf(procbuf, "driver/acx_%s", dev->name);
++ strcat(procbuf, proc_files[i]);
++ if (!remove) {
++ acxlog(L_INIT, "creating /proc entry %s\n", procbuf);
++ if (!create_proc_read_entry(procbuf, 0, 0, acx_proc_funcs[i], priv))
++ return NOT_OK;
++ } else {
++ acxlog(L_INIT, "removing /proc entry %s\n", procbuf);
++ remove_proc_entry(procbuf, NULL);
++ }
++ }
++ return OK;
++}
++
++int
++acx_proc_register_entries(const struct net_device *dev)
++{
++ return manage_proc_entries(dev, 0);
++}
++
++int
++acx_proc_unregister_entries(const struct net_device *dev)
++{
++ return manage_proc_entries(dev, 1);
++}
++#endif /* CONFIG_PROC_FS */
++
++
++/***********************************************************************
++** acx_cmd_join_bssid
++**
++** Common code for both acx100 and acx111.
++*/
++/* NB: does NOT match RATE100_nn but matches ACX[111]_SCAN_RATE_n */
++static const u8
++bitpos2genframe_txrate[] = {
++ 10, /* 0. 1 Mbit/s */
++ 20, /* 1. 2 Mbit/s */
++ 55, /* 2. 5.5 Mbit/s */
++ 0x0B, /* 3. 6 Mbit/s */
++ 0x0F, /* 4. 9 Mbit/s */
++ 110, /* 5. 11 Mbit/s */
++ 0x0A, /* 6. 12 Mbit/s */
++ 0x0E, /* 7. 18 Mbit/s */
++ 220, /* 8. 22 Mbit/s */
++ 0x09, /* 9. 24 Mbit/s */
++ 0x0D, /* 10. 36 Mbit/s */
++ 0x08, /* 11. 48 Mbit/s */
++ 0x0C, /* 12. 54 Mbit/s */
++ 10, /* 13. 1 Mbit/s, should never happen */
++ 10, /* 14. 1 Mbit/s, should never happen */
++ 10, /* 15. 1 Mbit/s, should never happen */
++};
++
++/* Looks scary, eh?
++** Actually, each one compiled into one AND and one SHIFT,
++** 31 bytes in x86 asm (more if uints are replaced by u16/u8) */
++static unsigned int
++rate111to5bits(unsigned int rate)
++{
++ return (rate & 0x7)
++ | ( (rate & RATE111_11) / (RATE111_11/JOINBSS_RATES_11) )
++ | ( (rate & RATE111_22) / (RATE111_22/JOINBSS_RATES_22) )
++ ;
++}
++
++static void
++acx_s_cmd_join_bssid(wlandevice_t *priv, const u8 *bssid)
++{
++ acx_joinbss_t tmp;
++ int dtim_interval;
++ int i;
++
++ FN_ENTER;
++
++ dtim_interval = (ACX_MODE_0_ADHOC == priv->mode) ?
++ 1 : priv->dtim_interval;
++
++ memset(&tmp, 0, sizeof(tmp));
++
++ for (i = 0; i < ETH_ALEN; i++) {
++ tmp.bssid[i] = bssid[ETH_ALEN-1 - i];
++ }
++
++ tmp.beacon_interval = cpu_to_le16(priv->beacon_interval);
++
++ /* basic rate set. Control frame responses (such as ACK or CTS frames)
++ ** are sent with one of these rates */
++ if (IS_ACX111(priv)) {
++ /* It was experimentally determined that rates_basic
++ ** can take 11g rates as well, not only rates
++ ** defined with JOINBSS_RATES_BASIC111_nnn.
++ ** Just use RATE111_nnn constants... */
++ tmp.u.acx111.dtim_interval = dtim_interval;
++ tmp.u.acx111.rates_basic = cpu_to_le16(priv->rate_basic);
++ acxlog(L_ASSOC, "%s rates_basic %04X, rates_supported %04X\n",
++ __func__, priv->rate_basic, priv->rate_oper);
++ } else {
++ tmp.u.acx100.dtim_interval = dtim_interval;
++ tmp.u.acx100.rates_basic = rate111to5bits(priv->rate_basic);
++ tmp.u.acx100.rates_supported = rate111to5bits(priv->rate_oper);
++ acxlog(L_ASSOC, "%s rates_basic %04X->%02X, "
++ "rates_supported %04X->%02X\n",
++ __func__,
++ priv->rate_basic, tmp.u.acx100.rates_basic,
++ priv->rate_oper, tmp.u.acx100.rates_supported);
++ }
++
++ /* Setting up how Beacon, Probe Response, RTS, and PS-Poll frames
++ ** will be sent (rate/modulation/preamble) */
++ tmp.genfrm_txrate = bitpos2genframe_txrate[lowest_bit(priv->rate_basic)];
++ tmp.genfrm_mod_pre = 0; /* FIXME: was = priv->capab_short (which is always 0); */
++ /* we can use short pre *if* all peers can understand it */
++ /* FIXME #2: we need to correctly set PBCC/OFDM bits here too */
++
++ /* we switch fw to STA mode in MONITOR mode, it seems to be
++ ** the only mode where fw does not emit beacons by itself
++ ** but allows us to send anything (we really want to retain
++ ** ability to tx arbitrary frames in MONITOR mode)
++ */
++ tmp.macmode = (priv->mode != ACX_MODE_MONITOR ? priv->mode : ACX_MODE_2_STA);
++ tmp.channel = priv->channel;
++ tmp.essid_len = priv->essid_len;
++ /* NOTE: the code memcpy'd essid_len + 1 before, which is WRONG! */
++ memcpy(tmp.essid, priv->essid, tmp.essid_len);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_JOIN, &tmp, tmp.essid_len + 0x11);
++
++ acxlog(L_ASSOC|L_DEBUG, "BSS_Type = %u\n", tmp.macmode);
++ acxlog_mac(L_ASSOC|L_DEBUG, "JoinBSSID MAC:", priv->bssid, "\n");
++
++ acx_update_capabilities(priv);
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx_s_cmd_start_scan
++**
++** Issue scan command to the hardware
++*/
++static void
++acx100_s_scan_chan(wlandevice_t *priv)
++{
++ acx100_scan_t s;
++
++ FN_ENTER;
++
++ memset(&s, 0, sizeof(s));
++ s.count = cpu_to_le16(priv->scan_count);
++ s.start_chan = cpu_to_le16(1);
++ s.flags = cpu_to_le16(0x8000);
++ s.max_rate = priv->scan_rate;
++ s.options = priv->scan_mode;
++ s.chan_duration = cpu_to_le16(priv->scan_duration);
++ s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
++
++ acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
++ FN_EXIT0;
++}
++
++static void
++acx111_s_scan_chan(wlandevice_t *priv)
++{
++ acx111_scan_t s;
++
++ FN_ENTER;
++
++ memset(&s, 0, sizeof(s));
++ s.count = cpu_to_le16(priv->scan_count);
++ s.channel_list_select = 0; /* scan every allowed channel */
++ /*s.channel_list_select = 1;*/ /* scan given channels */
++ s.rate = priv->scan_rate;
++ s.options = priv->scan_mode;
++ s.chan_duration = cpu_to_le16(priv->scan_duration);
++ s.max_probe_delay = cpu_to_le16(priv->scan_probe_delay);
++ /*s.modulation = 0x40;*/ /* long preamble? OFDM? -> only for active scan */
++ s.modulation = 0;
++ /*s.channel_list[0] = 6;
++ s.channel_list[1] = 4;*/
++
++ acx_s_issue_cmd(priv, ACX1xx_CMD_SCAN, &s, sizeof(s));
++ FN_EXIT0;
++}
++
++void
++acx_s_cmd_start_scan(wlandevice_t *priv)
++{
++ /* time_before check is 'just in case' thing */
++ if (!(priv->irq_status & HOST_INT_SCAN_COMPLETE)
++ && time_before(jiffies, priv->scan_start + 10*HZ)
++ ) {
++ acxlog(L_INIT, "start_scan: seems like previous scan "
++ "is still running. Not starting anew. Please report\n");
++ return;
++ }
++
++ acxlog(L_INIT, "starting radio scan\n");
++ /* remember that fw is commanded to do scan */
++ priv->scan_start = jiffies;
++ CLEAR_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
++ /* issue it */
++ if (IS_ACX100(priv)) {
++ acx100_s_scan_chan(priv);
++ } else {
++ acx111_s_scan_chan(priv);
++ }
++}
++
++
++/***********************************************************************
++** acx111 feature config
++*/
++static int
++acx111_s_get_feature_config(wlandevice_t *priv,
++ u32 *feature_options, u32 *data_flow_options)
++{
++ struct acx111_ie_feature_config fc;
++
++ if (!IS_ACX111(priv)) {
++ return NOT_OK;
++ }
++
++ memset(&fc, 0, sizeof(fc));
++
++ if (OK != acx_s_interrogate(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
++ return NOT_OK;
++ }
++ acxlog(L_DEBUG,
++ "got Feature option:0x%X, DataFlow option: 0x%X\n",
++ fc.feature_options,
++ fc.data_flow_options);
++
++ if (feature_options)
++ *feature_options = le32_to_cpu(fc.feature_options);
++ if (data_flow_options)
++ *data_flow_options = le32_to_cpu(fc.data_flow_options);
++
++ return OK;
++}
++
++static int
++acx111_s_set_feature_config(wlandevice_t *priv,
++ u32 feature_options, u32 data_flow_options,
++ unsigned int mode /* 0 == remove, 1 == add, 2 == set */)
++{
++ struct acx111_ie_feature_config fc;
++
++ if (!IS_ACX111(priv)) {
++ return NOT_OK;
++ }
++
++ if ((mode < 0) || (mode > 2))
++ return NOT_OK;
++
++ if (mode != 2)
++ /* need to modify old data */
++ acx111_s_get_feature_config(priv, &fc.feature_options, &fc.data_flow_options);
++ else {
++ /* need to set a completely new value */
++ fc.feature_options = 0;
++ fc.data_flow_options = 0;
++ }
++
++ if (mode == 0) { /* remove */
++ CLEAR_BIT(fc.feature_options, cpu_to_le32(feature_options));
++ CLEAR_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
++ } else { /* add or set */
++ SET_BIT(fc.feature_options, cpu_to_le32(feature_options));
++ SET_BIT(fc.data_flow_options, cpu_to_le32(data_flow_options));
++ }
++
++ acxlog(L_DEBUG,
++ "old: feature 0x%08X dataflow 0x%08X. mode: %u\n"
++ "new: feature 0x%08X dataflow 0x%08X\n",
++ feature_options, data_flow_options, mode,
++ le32_to_cpu(fc.feature_options),
++ le32_to_cpu(fc.data_flow_options));
++
++ if (OK != acx_s_configure(priv, &fc, ACX1xx_IE_FEATURE_CONFIG)) {
++ return NOT_OK;
++ }
++
++ return OK;
++}
++
++static inline int
++acx111_s_feature_off(wlandevice_t *priv, u32 f, u32 d)
++{
++ return acx111_s_set_feature_config(priv, f, d, 0);
++}
++static inline int
++acx111_s_feature_on(wlandevice_t *priv, u32 f, u32 d)
++{
++ return acx111_s_set_feature_config(priv, f, d, 1);
++}
++static inline int
++acx111_s_feature_set(wlandevice_t *priv, u32 f, u32 d)
++{
++ return acx111_s_set_feature_config(priv, f, d, 2);
++}
++
++
++/***********************************************************************
++** acx100_s_init_memory_pools
++*/
++static int
++acx100_s_init_memory_pools(wlandevice_t *priv, const acx_ie_memmap_t *mmt)
++{
++ acx100_ie_memblocksize_t MemoryBlockSize;
++ acx100_ie_memconfigoption_t MemoryConfigOption;
++ int TotalMemoryBlocks;
++ int RxBlockNum;
++ int TotalRxBlockSize;
++ int TxBlockNum;
++ int TotalTxBlockSize;
++
++ FN_ENTER;
++
++ /* Let's see if we can follow this:
++ first we select our memory block size (which I think is
++ completely arbitrary) */
++ MemoryBlockSize.size = cpu_to_le16(priv->memblocksize);
++
++ /* Then we alert the card to our decision of block size */
++ if (OK != acx_s_configure(priv, &MemoryBlockSize, ACX100_IE_BLOCK_SIZE)) {
++ goto bad;
++ }
++
++ /* We figure out how many total blocks we can create, using
++ the block size we chose, and the beginning and ending
++ memory pointers, i.e.: end-start/size */
++ TotalMemoryBlocks = (le32_to_cpu(mmt->PoolEnd) - le32_to_cpu(mmt->PoolStart)) / priv->memblocksize;
++
++ acxlog(L_DEBUG, "TotalMemoryBlocks=%u (%u bytes)\n",
++ TotalMemoryBlocks, TotalMemoryBlocks*priv->memblocksize);
++
++ /* MemoryConfigOption.DMA_config bitmask:
++ // access to ACX memory is to be done:
++ 0x00080000 // using PCI conf space?!
++ 0x00040000 // using IO instructions?
++ 0x00000000 // using memory access instructions
++ 0x00020000 // use local memory block linked list (else what?)
++ 0x00010000 // use host indirect descriptors (else host must access ACX memory?)
++ */
++ if (IS_PCI(priv)) {
++ MemoryConfigOption.DMA_config = cpu_to_le32(0x30000);
++ /* Declare start of the Rx host pool */
++ MemoryConfigOption.pRxHostDesc = cpu2acx(priv->rxhostdesc_startphy);
++ acxlog(L_DEBUG, "pRxHostDesc 0x%08X, rxhostdesc_startphy 0x%lX\n",
++ acx2cpu(MemoryConfigOption.pRxHostDesc),
++ (long)priv->rxhostdesc_startphy);
++ } else {
++ MemoryConfigOption.DMA_config = cpu_to_le32(0x20000);
++ }
++
++ /* 50% of the allotment of memory blocks go to tx descriptors */
++ TxBlockNum = TotalMemoryBlocks / 2;
++ MemoryConfigOption.TxBlockNum = cpu_to_le16(TxBlockNum);
++
++ /* and 50% go to the rx descriptors */
++ RxBlockNum = TotalMemoryBlocks - TxBlockNum;
++ MemoryConfigOption.RxBlockNum = cpu_to_le16(RxBlockNum);
++
++ /* size of the tx and rx descriptor queues */
++ TotalTxBlockSize = TxBlockNum * priv->memblocksize;
++ TotalRxBlockSize = RxBlockNum * priv->memblocksize;
++ acxlog(L_DEBUG, "TxBlockNum %u RxBlockNum %u TotalTxBlockSize %u "
++ "TotalTxBlockSize %u\n", TxBlockNum, RxBlockNum,
++ TotalTxBlockSize, TotalRxBlockSize);
++
++
++ /* align the tx descriptor queue to an alignment of 0x20 (32 bytes) */
++ MemoryConfigOption.rx_mem =
++ cpu_to_le32((le32_to_cpu(mmt->PoolStart) + 0x1f) & ~0x1f);
++
++ /* align the rx descriptor queue to units of 0x20
++ * and offset it by the tx descriptor queue */
++ MemoryConfigOption.tx_mem =
++ cpu_to_le32((le32_to_cpu(mmt->PoolStart) + TotalRxBlockSize + 0x1f) & ~0x1f);
++ acxlog(L_DEBUG, "rx_mem %08X rx_mem %08X\n",
++ MemoryConfigOption.tx_mem, MemoryConfigOption.rx_mem);
++
++ /* alert the device to our decision */
++ if (OK != acx_s_configure(priv, &MemoryConfigOption, ACX1xx_IE_MEMORY_CONFIG_OPTIONS)) {
++ goto bad;
++ }
++
++ /* and tell the device to kick it into gear */
++ if (OK != acx_s_issue_cmd(priv, ACX100_CMD_INIT_MEMORY, NULL, 0)) {
++ goto bad;
++ }
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/***********************************************************************
++** acx100_s_create_dma_regions
++**
++** Note that this fn messes up heavily with hardware, but we cannot
++** lock it (we need to sleep). Not a problem since IRQs can't happen
++*/
++static int
++acx100_s_create_dma_regions(wlandevice_t *priv)
++{
++ acx100_ie_queueconfig_t queueconf;
++ acx_ie_memmap_t memmap;
++ int res = NOT_OK;
++ u32 tx_queue_start, rx_queue_start;
++
++ FN_ENTER;
++
++ /* read out the acx100 physical start address for the queues */
++ if (OK != acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
++ goto fail;
++ }
++
++ tx_queue_start = le32_to_cpu(memmap.QueueStart);
++ rx_queue_start = tx_queue_start + TX_CNT * sizeof(txdesc_t);
++
++ acxlog(L_DEBUG, "initializing Queue Indicator\n");
++
++ memset(&queueconf, 0, sizeof(queueconf));
++
++ /* Not needed for PCI, so we can avoid setting them altogether */
++ if (IS_USB(priv)) {
++ queueconf.NumTxDesc = USB_TX_CNT;
++ queueconf.NumRxDesc = USB_RX_CNT;
++ }
++
++ /* calculate size of queues */
++ queueconf.AreaSize = cpu_to_le32(
++ TX_CNT * sizeof(txdesc_t) +
++ RX_CNT * sizeof(rxdesc_t) + 8
++ );
++ queueconf.NumTxQueues = 1; /* number of tx queues */
++ /* sets the beginning of the tx descriptor queue */
++ queueconf.TxQueueStart = memmap.QueueStart;
++ /* done by memset: queueconf.TxQueuePri = 0; */
++ queueconf.RxQueueStart = cpu_to_le32(rx_queue_start);
++ queueconf.QueueOptions = 1; /* auto reset descriptor */
++ /* sets the end of the rx descriptor queue */
++ queueconf.QueueEnd = cpu_to_le32(
++ rx_queue_start + RX_CNT * sizeof(rxdesc_t)
++ );
++ /* sets the beginning of the next queue */
++ queueconf.HostQueueEnd = cpu_to_le32(le32_to_cpu(queueconf.QueueEnd) + 8);
++ if (OK != acx_s_configure(priv, &queueconf, ACX1xx_IE_QUEUE_CONFIG)) {
++ goto fail;
++ }
++
++#if 0
++ if (IS_PCI(priv)) {
++ /* sets the beginning of the rx descriptor queue, after the tx descrs */
++ if (OK != acx_s_create_hostdesc_queues(priv))
++ goto fail;
++ acx_create_desc_queues(priv, tx_queue_start, rx_queue_start);
++ }
++#endif
++
++ if (OK != acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
++ goto fail;
++ }
++
++ memmap.PoolStart = cpu_to_le32(
++ (le32_to_cpu(memmap.QueueEnd) + 4 + 0x1f) & ~0x1f
++ );
++
++ if (OK != acx_s_configure(priv, &memmap, ACX1xx_IE_MEMORY_MAP)) {
++ goto fail;
++ }
++
++ if (OK != acx100_s_init_memory_pools(priv, &memmap)) {
++ goto fail;
++ }
++
++ res = OK;
++ goto end;
++
++fail:
++ acx_s_msleep(1000); /* ? */
++ if (IS_PCI(priv))
++ acx_free_desc_queues(priv);
++end:
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/***********************************************************************
++** acx111_s_create_dma_regions
++**
++** Note that this fn messes up heavily with hardware, but we cannot
++** lock it (we need to sleep). Not a problem since IRQs can't happen
++*/
++#define ACX111_PERCENT(percent) ((percent)/5)
++
++static int
++acx111_s_create_dma_regions(wlandevice_t *priv)
++{
++ struct acx111_ie_memoryconfig memconf;
++ struct acx111_ie_queueconfig queueconf;
++ u32 tx_queue_start, rx_queue_start;
++
++ FN_ENTER;
++
++ /* Calculate memory positions and queue sizes */
++
++ /* Set up our host descriptor pool + data pool */
++ if (IS_PCI(priv)) {
++ if (OK != acx_s_create_hostdesc_queues(priv))
++ goto fail;
++ }
++
++ memset(&memconf, 0, sizeof(memconf));
++ /* the number of STAs (STA contexts) to support
++ ** NB: was set to 1 and everything seemed to work nevertheless... */
++ memconf.no_of_stations = cpu_to_le16(VEC_SIZE(priv->sta_list));
++ /* specify the memory block size. Default is 256 */
++ memconf.memory_block_size = cpu_to_le16(priv->memblocksize);
++ /* let's use 50%/50% for tx/rx (specify percentage, units of 5%) */
++ memconf.tx_rx_memory_block_allocation = ACX111_PERCENT(50);
++ /* set the count of our queues
++ ** NB: struct acx111_ie_memoryconfig shall be modified
++ ** if we ever will switch to more than one rx and/or tx queue */
++ memconf.count_rx_queues = 1;
++ memconf.count_tx_queues = 1;
++ /* 0 == Busmaster Indirect Memory Organization, which is what we want
++ * (using linked host descs with their allocated mem).
++ * 2 == Generic Bus Slave */
++ /* done by memset: memconf.options = 0; */
++ /* let's use 25% for fragmentations and 75% for frame transfers
++ * (specified in units of 5%) */
++ memconf.fragmentation = ACX111_PERCENT(75);
++ /* Rx descriptor queue config */
++ memconf.rx_queue1_count_descs = RX_CNT;
++ memconf.rx_queue1_type = 7; /* must be set to 7 */
++ /* done by memset: memconf.rx_queue1_prio = 0; low prio */
++ if (IS_PCI(priv)) {
++ memconf.rx_queue1_host_rx_start = cpu2acx(priv->rxhostdesc_startphy);
++ }
++ /* Tx descriptor queue config */
++ memconf.tx_queue1_count_descs = TX_CNT;
++ /* done by memset: memconf.tx_queue1_attributes = 0; lowest priority */
++
++ /* NB1: this looks wrong: (memconf,ACX1xx_IE_QUEUE_CONFIG),
++ ** (queueconf,ACX1xx_IE_MEMORY_CONFIG_OPTIONS) look swapped, eh?
++ ** But it is actually correct wrt IE numbers.
++ ** NB2: sizeof(memconf) == 28 == 0x1c but configure(ACX1xx_IE_QUEUE_CONFIG)
++ ** writes 0x20 bytes (because same IE for acx100 uses struct acx100_ie_queueconfig
++ ** which is 4 bytes larger. what a mess. TODO: clean it up) */
++ if (OK != acx_s_configure(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG)) {
++ goto fail;
++ }
++
++ acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
++
++ tx_queue_start = le32_to_cpu(queueconf.tx1_queue_address);
++ rx_queue_start = le32_to_cpu(queueconf.rx1_queue_address);
++
++ acxlog(L_INIT, "dump queue head (from card):\n"
++ "len: %u\n"
++ "tx_memory_block_address: %X\n"
++ "rx_memory_block_address: %X\n"
++ "tx1_queue address: %X\n"
++ "rx1_queue address: %X\n",
++ le16_to_cpu(queueconf.len),
++ le32_to_cpu(queueconf.tx_memory_block_address),
++ le32_to_cpu(queueconf.rx_memory_block_address),
++ tx_queue_start,
++ rx_queue_start);
++
++ if (IS_PCI(priv))
++ acx_create_desc_queues(priv, tx_queue_start, rx_queue_start);
++
++ FN_EXIT1(OK);
++ return OK;
++fail:
++ if (IS_PCI(priv))
++ acx_free_desc_queues(priv);
++
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/***********************************************************************
++** acx_s_set_defaults
++** Called from acx_s_init_mac
++*/
++int
++acx_s_set_defaults(wlandevice_t *priv)
++{
++ unsigned long flags;
++
++ FN_ENTER;
++
++ /* query some settings from the card.
++ * NOTE: for some settings, e.g. CCA and ED (ACX100!), an initial
++ * query is REQUIRED, otherwise the card won't work correctly!! */
++ priv->get_mask = GETSET_ANTENNA|GETSET_SENSITIVITY|GETSET_STATION_ID|GETSET_REG_DOMAIN;
++ /* Only ACX100 supports ED and CCA */
++ if (IS_ACX100(priv))
++ priv->get_mask |= GETSET_CCA|GETSET_ED_THRESH;
++
++ acx_s_update_card_settings(priv, 0, 0);
++
++ acx_lock(priv, flags);
++
++ /* set our global interrupt mask */
++ if (IS_PCI(priv))
++ acx_set_interrupt_mask(priv);
++
++ priv->led_power = 1; /* LED is active on startup */
++ priv->brange_max_quality = 60; /* LED blink max quality is 60 */
++ priv->brange_time_last_state_change = jiffies;
++
++ /* copy the MAC address we just got from the card
++ * into our MAC address used during current 802.11 session */
++ MAC_COPY(priv->dev_addr, priv->netdev->dev_addr);
++ sprintf(priv->essid, "STA%02X%02X%02X",
++ priv->dev_addr[3], priv->dev_addr[4], priv->dev_addr[5]);
++ priv->essid_len = sizeof("STAxxxxxx") - 1; /* make sure to adapt if changed above! */
++ priv->essid_active = 1;
++
++ /* we have a nick field to waste, so why not abuse it
++ * to announce the driver version? ;-) */
++ strncpy(priv->nick, "acx " WLAN_RELEASE, IW_ESSID_MAX_SIZE);
++
++ if (IS_PCI(priv)) {
++ if (IS_ACX111(priv)) {
++ /* Hope this is correct, only tested with domain 0x30 */
++ acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
++ } else if (priv->eeprom_version < 5) {
++ acx_read_eeprom_offset(priv, 0x16F, &priv->reg_dom_id);
++ } else {
++ acx_read_eeprom_offset(priv, 0x171, &priv->reg_dom_id);
++ }
++ }
++
++ priv->channel = 1;
++ /* 0xffff would be better, but then we won't get a "scan complete"
++ * interrupt, so our current infrastructure will fail: */
++ priv->scan_count = 1;
++ priv->scan_mode = ACX_SCAN_OPT_PASSIVE;
++ /* Doesn't work for acx100, do it only for acx111 for now */
++ if (IS_ACX111(priv)) {
++ priv->scan_mode = ACX_SCAN_OPT_ACTIVE;
++ }
++ priv->scan_duration = 100;
++ priv->scan_probe_delay = 200;
++ priv->scan_rate = ACX_SCAN_RATE_1;
++
++ priv->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
++ priv->preamble_mode = 2; /* auto */
++ priv->listen_interval = 100;
++ priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
++ priv->mode = ACX_MODE_2_STA;
++ priv->dtim_interval = DEFAULT_DTIM_INTERVAL;
++
++ priv->msdu_lifetime = DEFAULT_MSDU_LIFETIME;
++ SET_BIT(priv->set_mask, SET_MSDU_LIFETIME);
++
++ priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
++
++ /* use standard default values for retry limits */
++ priv->short_retry = 7; /* max. retries for (short) non-RTS packets */
++ priv->long_retry = 4; /* max. retries for long (RTS) packets */
++ SET_BIT(priv->set_mask, GETSET_RETRY);
++
++ priv->fallback_threshold = 3;
++ priv->stepup_threshold = 10;
++ priv->rate_bcast = RATE111_1;
++ priv->rate_bcast100 = RATE100_1;
++ priv->rate_basic = RATE111_1 | RATE111_2;
++ priv->rate_auto = 1;
++ if (IS_ACX111(priv)) {
++ priv->rate_oper = RATE111_ALL;
++ } else {
++ priv->rate_oper = RATE111_ACX100_COMPAT;
++ }
++
++ /* configure card to do rate fallback when in auto rate mode. */
++ SET_BIT(priv->set_mask, SET_RATE_FALLBACK);
++
++ /* Supported Rates element - the rates here are given in units of
++ * 500 kbit/s, plus 0x80 added. See 802.11-1999.pdf item 7.3.2.2 */
++ acx_l_update_ratevector(priv);
++
++ priv->capab_short = 0;
++ priv->capab_pbcc = 1;
++ priv->capab_agility = 0;
++
++ SET_BIT(priv->set_mask, SET_RXCONFIG);
++
++ /* set some more defaults */
++ if (IS_ACX111(priv)) {
++ /* 30mW (15dBm) is default, at least in my acx111 card: */
++ priv->tx_level_dbm = 15;
++ } else {
++ /* don't use max. level, since it might be dangerous
++ * (e.g. WRT54G people experience
++ * excessive Tx power damage!) */
++ priv->tx_level_dbm = 18;
++ }
++ /* priv->tx_level_auto = 1; */
++ SET_BIT(priv->set_mask, GETSET_TXPOWER);
++
++ if (IS_ACX111(priv)) {
++ /* start with sensitivity level 1 out of 3: */
++ priv->sensitivity = 1;
++ }
++
++ /* better re-init the antenna value we got above */
++ SET_BIT(priv->set_mask, GETSET_ANTENNA);
++
++ priv->ps_wakeup_cfg = 0;
++ priv->ps_listen_interval = 0;
++ priv->ps_options = 0;
++ priv->ps_hangover_period = 0;
++ priv->ps_enhanced_transition_time = 0;
++#ifdef POWER_SAVE_80211
++ SET_BIT(priv->set_mask, GETSET_POWER_80211);
++#endif
++
++ MAC_BCAST(priv->ap);
++
++ acx_unlock(priv, flags);
++ acx_lock_unhold(); // hold time 844814 CPU ticks @2GHz
++
++ acx_s_initialize_rx_config(priv);
++
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++/***********************************************************************
++** FIXME: this should be solved in a general way for all radio types
++** by decoding the radio firmware module,
++** since it probably has some standard structure describing how to
++** set the power level of the radio module which it controls.
++** Or maybe not, since the radio module probably has a function interface
++** instead which then manages Tx level programming :-\
++*/
++static int
++acx111_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
++{
++ struct acx111_ie_tx_level tx_level;
++
++ /* my acx111 card has two power levels in its configoptions (== EEPROM):
++ * 1 (30mW) [15dBm]
++ * 2 (10mW) [10dBm]
++ * For now, just assume all other acx111 cards have the same.
++ * Ideally we would query it here, but we first need a
++ * standard way to query individual configoptions easily. */
++ if (level_dbm <= 12) {
++ tx_level.level = 2; /* 10 dBm */
++ priv->tx_level_dbm = 10;
++ } else {
++ tx_level.level = 1; /* 15 dBm */
++ priv->tx_level_dbm = 15;
++ }
++ if (level_dbm != priv->tx_level_dbm)
++ acxlog(L_INIT, "acx111 firmware has specific "
++ "power levels only: adjusted %d dBm to %d dBm!\n",
++ level_dbm, priv->tx_level_dbm);
++
++ return acx_s_configure(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
++}
++
++static int
++acx_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
++{
++ if (IS_ACX111(priv)) {
++ return acx111_s_set_tx_level(priv, level_dbm);
++ }
++ if (IS_PCI(priv)) {
++ return acx100_s_set_tx_level(priv, level_dbm);
++ }
++ return OK;
++}
++
++
++/***********************************************************************
++*/
++#ifdef UNUSED
++/* Returns the current tx level (ACX111) */
++static u8
++acx111_s_get_tx_level(wlandevice_t *priv)
++{
++ struct acx111_ie_tx_level tx_level;
++
++ tx_level.level = 0;
++ acx_s_interrogate(priv, &tx_level, ACX1xx_IE_DOT11_TX_POWER_LEVEL);
++ return tx_level.level;
++}
++#endif
++
++
++/***********************************************************************
++** acx_s_init_mac
++*/
++int
++acx_s_init_mac(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result = NOT_OK;
++
++ FN_ENTER;
++
++ if (IS_PCI(priv)) {
++ priv->memblocksize = 256; /* 256 is default */
++ acx_init_mboxes(priv);
++ /* try to load radio for both ACX100 and ACX111, since both
++ * chips have at least some firmware versions making use of an
++ * external radio module */
++ acx_s_upload_radio(priv);
++ } else {
++ priv->memblocksize = 128;
++ }
++
++ if (IS_ACX111(priv)) {
++ /* for ACX111, the order is different from ACX100
++ 1. init packet templates
++ 2. create station context and create dma regions
++ 3. init wep default keys
++ */
++ if (OK != acx111_s_init_packet_templates(priv))
++ goto fail;
++
++ if (OK != acx111_s_create_dma_regions(priv)) {
++ printk("%s: acx111_create_dma_regions FAILED\n",
++ dev->name);
++ goto fail;
++ }
++#ifdef DEBUG_WEP
++ /* don't decrypt WEP in firmware */
++ if (OK != acx111_s_feature_on(priv, 0, FEATURE2_SNIFFER))
++ goto fail;
++#endif
++ } else {
++ if (OK != acx100_s_init_wep(priv))
++ goto fail;
++ acxlog(L_DEBUG, "between init_wep and init_packet_templates\n");
++ if (OK != acx100_s_init_packet_templates(priv))
++ goto fail;
++
++ if (OK != acx100_s_create_dma_regions(priv)) {
++ printk("%s: acx100_create_dma_regions FAILED\n",
++ dev->name);
++ goto fail;
++ }
++ }
++
++ MAC_COPY(dev->dev_addr, priv->dev_addr);
++ result = OK;
++
++fail:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_rxmonitor
++* Called from IRQ context only
++*----------------------------------------------------------------*/
++static void
++acx_l_rxmonitor(wlandevice_t *priv, const rxbuffer_t *rxbuf)
++{
++ wlansniffrm_t *msg;
++ struct sk_buff *skb;
++ void *datap;
++ unsigned int skb_len;
++ int payload_offset;
++
++ FN_ENTER;
++
++ /* we are in big luck: the acx100 doesn't modify any of the fields */
++ /* in the 802.11 frame. just pass this packet into the PF_PACKET */
++ /* subsystem. yeah. */
++ payload_offset = ((u8*)acx_get_wlan_hdr(priv, rxbuf) - (u8*)rxbuf);
++ skb_len = RXBUF_BYTES_USED(rxbuf) - payload_offset;
++
++ /* sanity check */
++ if (skb_len > WLAN_A4FR_MAXLEN_WEP) {
++ printk("%s: monitor mode panic: oversized frame!\n",
++ priv->netdev->name);
++ goto end;
++ }
++
++ if (priv->netdev->type == ARPHRD_IEEE80211_PRISM)
++ skb_len += sizeof(*msg);
++
++ /* allocate skb */
++ skb = dev_alloc_skb(skb_len);
++ if (!skb) {
++ printk("%s: no memory for skb (%u bytes)\n",
++ priv->netdev->name, skb_len);
++ goto end;
++ }
++
++ skb_put(skb, skb_len);
++
++ /* when in raw 802.11 mode, just copy frame as-is */
++ if (priv->netdev->type == ARPHRD_IEEE80211)
++ datap = skb->data;
++ else { /* otherwise, emulate prism header */
++ msg = (wlansniffrm_t*)skb->data;
++ datap = msg + 1;
++
++ msg->msgcode = WLANSNIFFFRM;
++ msg->msglen = sizeof(*msg);
++ strncpy(msg->devname, priv->netdev->name, sizeof(msg->devname)-1);
++ msg->devname[sizeof(msg->devname)-1] = '\0';
++
++ msg->hosttime.did = WLANSNIFFFRM_hosttime;
++ msg->hosttime.status = WLANITEM_STATUS_data_ok;
++ msg->hosttime.len = 4;
++ msg->hosttime.data = jiffies;
++
++ msg->mactime.did = WLANSNIFFFRM_mactime;
++ msg->mactime.status = WLANITEM_STATUS_data_ok;
++ msg->mactime.len = 4;
++ msg->mactime.data = rxbuf->time;
++
++ msg->channel.did = WLANSNIFFFRM_channel;
++ msg->channel.status = WLANITEM_STATUS_data_ok;
++ msg->channel.len = 4;
++ msg->channel.data = priv->channel;
++
++ msg->rssi.did = WLANSNIFFFRM_rssi;
++ msg->rssi.status = WLANITEM_STATUS_no_value;
++ msg->rssi.len = 4;
++ msg->rssi.data = 0;
++
++ msg->sq.did = WLANSNIFFFRM_sq;
++ msg->sq.status = WLANITEM_STATUS_no_value;
++ msg->sq.len = 4;
++ msg->sq.data = 0;
++
++ msg->signal.did = WLANSNIFFFRM_signal;
++ msg->signal.status = WLANITEM_STATUS_data_ok;
++ msg->signal.len = 4;
++ msg->signal.data = rxbuf->phy_snr;
++
++ msg->noise.did = WLANSNIFFFRM_noise;
++ msg->noise.status = WLANITEM_STATUS_data_ok;
++ msg->noise.len = 4;
++ msg->noise.data = rxbuf->phy_level;
++
++ msg->rate.did = WLANSNIFFFRM_rate;
++ msg->rate.status = WLANITEM_STATUS_data_ok;
++ msg->rate.len = 4;
++ msg->rate.data = rxbuf->phy_plcp_signal / 5;
++
++ msg->istx.did = WLANSNIFFFRM_istx;
++ msg->istx.status = WLANITEM_STATUS_data_ok;
++ msg->istx.len = 4;
++ msg->istx.data = 0; /* tx=0: it's not a tx packet */
++
++ skb_len -= sizeof(*msg);
++
++ msg->frmlen.did = WLANSNIFFFRM_signal;
++ msg->frmlen.status = WLANITEM_STATUS_data_ok;
++ msg->frmlen.len = 4;
++ msg->frmlen.data = skb_len;
++ }
++
++ memcpy(datap, ((unsigned char*)rxbuf)+payload_offset, skb_len);
++
++ skb->dev = priv->netdev;
++ skb->dev->last_rx = jiffies;
++
++ skb->mac.raw = skb->data;
++ skb->ip_summed = CHECKSUM_NONE;
++ skb->pkt_type = PACKET_OTHERHOST;
++ skb->protocol = htons(ETH_P_80211_RAW);
++ netif_rx(skb);
++
++ priv->stats.rx_packets++;
++ priv->stats.rx_bytes += skb->len;
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx_l_rx_ieee802_11_frame
++**
++** Called from IRQ context only
++*/
++
++/* All these contortions are for saner dup logging
++**
++** We want: (a) to know about excessive dups
++** (b) to not spam kernel log about occasional dups
++**
++** 1/64 threshold was chosen by running "ping -A"
++** It gave "rx: 59 DUPs in 2878 packets" only with 4 parallel
++** "ping -A" streams running. */
++static inline int
++acx_l_handle_dup(wlandevice_t *priv, u16 seq)
++{
++ if (priv->dup_count) {
++ priv->nondup_count++;
++ if (time_after(jiffies, priv->dup_msg_expiry)) {
++ /* Log only if more than 1 dup in 64 packets */
++ if (priv->nondup_count/64 < priv->dup_count) {
++ printk(KERN_INFO "%s: rx: %d DUPs in "
++ "%d packets received in 10 secs\n",
++ priv->netdev->name,
++ priv->dup_count,
++ priv->nondup_count);
++ }
++ priv->dup_count = 0;
++ priv->nondup_count = 0;
++ }
++ }
++ if (unlikely(seq == priv->last_seq_ctrl)) {
++ if (!priv->dup_count++)
++ priv->dup_msg_expiry = jiffies + 10*HZ;
++ priv->stats.rx_errors++;
++ return 1; /* a dup */
++ }
++ priv->last_seq_ctrl = seq;
++ return 0;
++}
++
++static int
++acx_l_rx_ieee802_11_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
++{
++ unsigned int ftype, fstype;
++ const wlan_hdr_t *hdr;
++ int result = NOT_OK;
++
++ FN_ENTER;
++
++ hdr = acx_get_wlan_hdr(priv, rxbuf);
++
++ /* see IEEE 802.11-1999.pdf chapter 7 "MAC frame formats" */
++ if ((hdr->fc & WF_FC_PVERi) != 0) {
++ printk_ratelimited(KERN_INFO "rx: unsupported 802.11 protocol\n");
++ goto end;
++ }
++
++ ftype = hdr->fc & WF_FC_FTYPEi;
++ fstype = hdr->fc & WF_FC_FSTYPEi;
++
++ switch (ftype) {
++ /* check data frames first, for speed */
++ case WF_FTYPE_DATAi:
++ switch (fstype) {
++ case WF_FSTYPE_DATAONLYi:
++ if (acx_l_handle_dup(priv, hdr->seq))
++ break; /* a dup, simply discard it */
++
++ /* TODO:
++ if (WF_FC_FROMTODSi == (hdr->fc & WF_FC_FROMTODSi)) {
++ result = acx_l_process_data_frame_wds(priv, rxbuf);
++ break;
++ }
++ */
++
++ switch (priv->mode) {
++ case ACX_MODE_3_AP:
++ result = acx_l_process_data_frame_master(priv, rxbuf);
++ break;
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ result = acx_l_process_data_frame_client(priv, rxbuf);
++ break;
++ }
++ case WF_FSTYPE_DATA_CFACKi:
++ case WF_FSTYPE_DATA_CFPOLLi:
++ case WF_FSTYPE_DATA_CFACK_CFPOLLi:
++ case WF_FSTYPE_CFPOLLi:
++ case WF_FSTYPE_CFACK_CFPOLLi:
++ /* see above.
++ acx_process_class_frame(priv, rxbuf, 3); */
++ break;
++ case WF_FSTYPE_NULLi:
++ /* acx_l_process_NULL_frame(priv, rxbuf, 3); */
++ break;
++ /* FIXME: same here, see above */
++ case WF_FSTYPE_CFACKi:
++ default:
++ break;
++ }
++ break;
++ case WF_FTYPE_MGMTi:
++ result = acx_l_process_mgmt_frame(priv, rxbuf);
++ break;
++ case WF_FTYPE_CTLi:
++ if (fstype == WF_FSTYPE_PSPOLLi)
++ result = OK;
++ /* this call is irrelevant, since
++ * acx_process_class_frame is a stub, so return
++ * immediately instead.
++ * return acx_process_class_frame(priv, rxbuf, 3); */
++ break;
++ default:
++ break;
++ }
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx_l_process_rxbuf
++**
++** NB: used by USB code also
++*/
++void
++acx_l_process_rxbuf(wlandevice_t *priv, rxbuffer_t *rxbuf)
++{
++ struct wlan_hdr *hdr;
++ unsigned int buf_len;
++ unsigned int qual;
++ u16 fc;
++
++ hdr = acx_get_wlan_hdr(priv, rxbuf);
++ /* length of frame from control field to last byte of FCS */
++ buf_len = RXBUF_BYTES_RCVD(rxbuf);
++ fc = le16_to_cpu(hdr->fc);
++
++ if ( ((WF_FC_FSTYPE & fc) != WF_FSTYPE_BEACON)
++ || (acx_debug & L_XFER_BEACON)
++ ) {
++ acxlog(L_XFER|L_DATA, "rx: %s "
++ "time %u len %u signal %u SNR %u macstat %02X "
++ "phystat %02X phyrate %u status %u\n",
++ acx_get_packet_type_string(fc),
++ le32_to_cpu(rxbuf->time),
++ buf_len,
++ acx_signal_to_winlevel(rxbuf->phy_level),
++ acx_signal_to_winlevel(rxbuf->phy_snr),
++ rxbuf->mac_status,
++ rxbuf->phy_stat_baseband,
++ rxbuf->phy_plcp_signal,
++ priv->status);
++ }
++
++ if (unlikely(acx_debug & L_DATA)) {
++ printk("rx: 802.11 buf[%u]: ", buf_len);
++ acx_dump_bytes(hdr, buf_len);
++ }
++
++ /* FIXME: should check for Rx errors (rxbuf->mac_status?
++ * discard broken packets - but NOT for monitor!)
++ * and update Rx packet statistics here */
++
++ if (unlikely(priv->mode == ACX_MODE_MONITOR)) {
++ acx_l_rxmonitor(priv, rxbuf);
++ } else if (likely(buf_len >= WLAN_HDR_A3_LEN)) {
++ acx_l_rx_ieee802_11_frame(priv, rxbuf);
++ } else {
++ acxlog(L_DEBUG|L_XFER|L_DATA,
++ "rx: NOT receiving packet (%s): "
++ "size too small (%u)\n",
++ acx_get_packet_type_string(fc),
++ buf_len);
++ }
++
++ /* Now check Rx quality level, AFTER processing packet.
++ * I tried to figure out how to map these levels to dBm
++ * values, but for the life of me I really didn't
++ * manage to get it. Either these values are not meant to
++ * be expressed in dBm, or it's some pretty complicated
++ * calculation. */
++
++#ifdef FROM_SCAN_SOURCE_ONLY
++ /* only consider packets originating from the MAC
++ * address of the device that's managing our BSSID.
++ * Disable it for now, since it removes information (levels
++ * from different peers) and slows the Rx path. */
++ if (priv->ap_client
++ && mac_is_equal(hdr->a2, priv->ap_client->address)) {
++#endif
++ priv->wstats.qual.level = acx_signal_to_winlevel(rxbuf->phy_level);
++ priv->wstats.qual.noise = acx_signal_to_winlevel(rxbuf->phy_snr);
++#ifndef OLD_QUALITY
++ qual = acx_signal_determine_quality(priv->wstats.qual.level,
++ priv->wstats.qual.noise);
++#else
++ qual = (priv->wstats.qual.noise <= 100) ?
++ 100 - priv->wstats.qual.noise : 0;
++#endif
++ priv->wstats.qual.qual = qual;
++ priv->wstats.qual.updated = 7; /* all 3 indicators updated */
++#ifdef FROM_SCAN_SOURCE_ONLY
++ }
++#endif
++}
++
++
++/***********************************************************************
++** acx_i_start_xmit
++**
++** Called by network core. Can be called outside of process context.
++*/
++int
++acx_i_start_xmit(struct sk_buff *skb, netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ tx_t *tx;
++ void *txbuf;
++ unsigned long flags;
++ int txresult = NOT_OK;
++ int len;
++
++ FN_ENTER;
++
++ if (unlikely(!skb)) {
++ /* indicate success */
++ txresult = OK;
++ goto end_no_unlock;
++ }
++ if (unlikely(!priv)) {
++ goto end_no_unlock;
++ }
++
++ acx_lock(priv, flags);
++
++ if (unlikely(!(priv->dev_state_mask & ACX_STATE_IFACE_UP))) {
++ goto end;
++ }
++ if (unlikely(priv->mode == ACX_MODE_OFF)) {
++ goto end;
++ }
++ if (unlikely(acx_queue_stopped(dev))) {
++ acxlog(L_DEBUG, "%s: called when queue stopped\n", __func__);
++ goto end;
++ }
++ if (unlikely(ACX_STATUS_4_ASSOCIATED != priv->status)) {
++ acxlog(L_XFER, "trying to xmit, but not associated yet: "
++ "aborting...\n");
++ /* silently drop the packet, since we're not connected yet */
++ txresult = OK;
++ /* ...but indicate an error nevertheless */
++ priv->stats.tx_errors++;
++ goto end;
++ }
++
++ tx = acx_l_alloc_tx(priv);
++ if (unlikely(!tx)) {
++ printk("%s: start_xmit: txdesc ring is full, dropping tx\n",
++ dev->name);
++ txresult = NOT_OK;
++ goto end;
++ }
++
++ txbuf = acx_l_get_txbuf(priv, tx);
++ if (!txbuf) {
++ /* Card was removed */
++ txresult = NOT_OK;
++ goto end;
++ }
++ len = acx_l_ether_to_txbuf(priv, txbuf, skb);
++ if (len < 0) {
++ /* Error in packet conversion */
++ txresult = NOT_OK;
++ goto end;
++ }
++ acx_l_tx_data(priv, tx, len);
++ dev->trans_start = jiffies;
++
++ txresult = OK;
++ priv->stats.tx_packets++;
++ priv->stats.tx_bytes += skb->len;
++
++end:
++ acx_unlock(priv, flags);
++
++end_no_unlock:
++ if ((txresult == OK) && skb)
++ dev_kfree_skb_any(skb);
++
++ FN_EXIT1(txresult);
++ return txresult;
++}
++
++
++/***********************************************************************
++** acx_l_update_ratevector
++**
++** Updates priv->rate_supported[_len] according to rate_{basic,oper}
++*/
++const u8
++bitpos2ratebyte[] = {
++ DOT11RATEBYTE_1,
++ DOT11RATEBYTE_2,
++ DOT11RATEBYTE_5_5,
++ DOT11RATEBYTE_6_G,
++ DOT11RATEBYTE_9_G,
++ DOT11RATEBYTE_11,
++ DOT11RATEBYTE_12_G,
++ DOT11RATEBYTE_18_G,
++ DOT11RATEBYTE_22,
++ DOT11RATEBYTE_24_G,
++ DOT11RATEBYTE_36_G,
++ DOT11RATEBYTE_48_G,
++ DOT11RATEBYTE_54_G,
++};
++
++void
++acx_l_update_ratevector(wlandevice_t *priv)
++{
++ u16 bcfg = priv->rate_basic;
++ u16 ocfg = priv->rate_oper;
++ u8 *supp = priv->rate_supported;
++ const u8 *dot11 = bitpos2ratebyte;
++
++ FN_ENTER;
++
++ while (ocfg) {
++ if (ocfg & 1) {
++ *supp = *dot11;
++ if (bcfg & 1) {
++ *supp |= 0x80;
++ }
++ supp++;
++ }
++ dot11++;
++ ocfg >>= 1;
++ bcfg >>= 1;
++ }
++ priv->rate_supported_len = supp - priv->rate_supported;
++ if (acx_debug & L_ASSOC) {
++ printk("new ratevector: ");
++ acx_dump_bytes(priv->rate_supported, priv->rate_supported_len);
++ }
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_sta_list_init
++*----------------------------------------------------------------*/
++static void
++acx_l_sta_list_init(wlandevice_t *priv)
++{
++ FN_ENTER;
++ memset(priv->sta_hash_tab, 0, sizeof(priv->sta_hash_tab));
++ memset(priv->sta_list, 0, sizeof(priv->sta_list));
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_sta_list_get_from_hash
++*----------------------------------------------------------------*/
++static inline client_t*
++acx_l_sta_list_get_from_hash(wlandevice_t *priv, const u8 *address)
++{
++ return priv->sta_hash_tab[address[5] % VEC_SIZE(priv->sta_hash_tab)];
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_sta_list_get
++*----------------------------------------------------------------*/
++client_t*
++acx_l_sta_list_get(wlandevice_t *priv, const u8 *address)
++{
++ client_t *client;
++ FN_ENTER;
++ client = acx_l_sta_list_get_from_hash(priv, address);
++ while (client) {
++ if (mac_is_equal(address, client->address)) {
++ client->mtime = jiffies;
++ break;
++ }
++ client = client->next;
++ }
++ FN_EXIT0;
++ return client;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_sta_list_del
++*----------------------------------------------------------------*/
++void
++acx_l_sta_list_del(wlandevice_t *priv, client_t *victim)
++{
++ client_t *client, *next;
++
++ client = acx_l_sta_list_get_from_hash(priv, victim->address);
++ next = client;
++ /* tricky. next = client on first iteration only,
++ ** on all other iters next = client->next */
++ while (next) {
++ if (next == victim) {
++ client->next = victim->next;
++ /* Overkill */
++ memset(victim, 0, sizeof(*victim));
++ break;
++ }
++ client = next;
++ next = client->next;
++ }
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_sta_list_alloc
++*
++* Never fails - will evict oldest client if needed
++*----------------------------------------------------------------*/
++static client_t*
++acx_l_sta_list_alloc(wlandevice_t *priv)
++{
++ int i;
++ unsigned long age, oldest_age;
++ client_t *client, *oldest;
++
++ FN_ENTER;
++
++ oldest = &priv->sta_list[0];
++ oldest_age = 0;
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ client = &priv->sta_list[i];
++
++ if (!client->used) {
++ goto found;
++ } else {
++ age = jiffies - client->mtime;
++ if (oldest_age < age) {
++ oldest_age = age;
++ oldest = client;
++ }
++ }
++ }
++ acx_l_sta_list_del(priv, oldest);
++ client = oldest;
++found:
++ memset(client, 0, sizeof(*client));
++ FN_EXIT0;
++ return client;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_sta_list_add
++*
++* Never fails - will evict oldest client if needed
++*----------------------------------------------------------------*/
++/* In case we will reimplement it differently... */
++#define STA_LIST_ADD_CAN_FAIL 0
++
++static client_t*
++acx_l_sta_list_add(wlandevice_t *priv, const u8 *address)
++{
++ client_t *client;
++ int index;
++
++ FN_ENTER;
++
++ client = acx_l_sta_list_alloc(priv);
++
++ client->mtime = jiffies;
++ MAC_COPY(client->address, address);
++ client->used = CLIENT_EXIST_1;
++ client->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
++ client->auth_step = 1;
++ /* give some tentative peer rate values
++ ** (needed because peer may do auth without probing us first,
++ ** thus we'll have no idea of peer's ratevector yet).
++ ** Will be overwritten by scanning or assoc code */
++ client->rate_cap = priv->rate_basic;
++ client->rate_cfg = priv->rate_basic;
++ client->rate_cur = 1 << lowest_bit(priv->rate_basic);
++
++ index = address[5] % VEC_SIZE(priv->sta_hash_tab);
++ client->next = priv->sta_hash_tab[index];
++ priv->sta_hash_tab[index] = client;
++
++ acxlog_mac(L_ASSOC, "sta_list_add: sta=", address, "\n");
++
++ FN_EXIT0;
++ return client;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_sta_list_get_or_add
++*
++* Never fails - will evict oldest client if needed
++*----------------------------------------------------------------*/
++static client_t*
++acx_l_sta_list_get_or_add(wlandevice_t *priv, const u8 *address)
++{
++ client_t *client = acx_l_sta_list_get(priv, address);
++ if (!client)
++ client = acx_l_sta_list_add(priv, address);
++ return client;
++}
++
++
++/***********************************************************************
++** acx_set_status
++**
++** This function is called in many atomic regions, must not sleep
++**
++** This function does not need locking UNLESS you call it
++** as acx_set_status(ACX_STATUS_4_ASSOCIATED), bacause this can
++** wake queue. This can race with stop_queue elsewhere.
++** See acx_stop_queue comment. */
++void
++acx_set_status(wlandevice_t *priv, u16 new_status)
++{
++#define QUEUE_OPEN_AFTER_ASSOC 1 /* this really seems to be needed now */
++ u16 old_status = priv->status;
++
++ FN_ENTER;
++
++ acxlog(L_ASSOC, "%s(%d):%s\n",
++ __func__, new_status, acx_get_status_name(new_status));
++
++#if WIRELESS_EXT > 13 /* wireless_send_event() and SIOCGIWSCAN */
++ /* wireless_send_event never sleeps */
++ if (ACX_STATUS_4_ASSOCIATED == new_status) {
++ union iwreq_data wrqu;
++
++ wrqu.data.length = 0;
++ wrqu.data.flags = 0;
++ wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL);
++
++ wrqu.data.length = 0;
++ wrqu.data.flags = 0;
++ MAC_COPY(wrqu.ap_addr.sa_data, priv->bssid);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
++ } else {
++ union iwreq_data wrqu;
++
++ /* send event with empty BSSID to indicate we're not associated */
++ MAC_ZERO(wrqu.ap_addr.sa_data);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++ wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL);
++ }
++#endif
++
++ priv->status = new_status;
++
++ switch (new_status) {
++ case ACX_STATUS_1_SCANNING:
++ priv->scan_retries = 0;
++ /* 1.0 s initial scan time */
++ acx_set_timer(priv, 1000000);
++ break;
++ case ACX_STATUS_2_WAIT_AUTH:
++ case ACX_STATUS_3_AUTHENTICATED:
++ priv->auth_or_assoc_retries = 0;
++ acx_set_timer(priv, 1500000); /* 1.5 s */
++ break;
++ }
++
++#if QUEUE_OPEN_AFTER_ASSOC
++ if (new_status == ACX_STATUS_4_ASSOCIATED) {
++ if (old_status < ACX_STATUS_4_ASSOCIATED) {
++ /* ah, we're newly associated now,
++ * so let's indicate carrier */
++ acx_carrier_on(priv->netdev, "after association");
++ acx_wake_queue(priv->netdev, "after association");
++ }
++ } else {
++ /* not associated any more, so let's kill carrier */
++ if (old_status >= ACX_STATUS_4_ASSOCIATED) {
++ acx_carrier_off(priv->netdev, "after losing association");
++ acx_stop_queue(priv->netdev, "after losing association");
++ }
++ }
++#endif
++ FN_EXIT0;
++}
++
++
++/*------------------------------------------------------------------------------
++ * acx_i_timer
++ *
++ * Fires up periodically. Used to kick scan/auth/assoc if something goes wrong
++ *----------------------------------------------------------------------------*/
++void
++acx_i_timer(unsigned long address)
++{
++ unsigned long flags;
++ wlandevice_t *priv = (wlandevice_t *)address;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++
++ acxlog(L_DEBUG|L_ASSOC, "%s: priv->status=%d (%s)\n",
++ __func__, priv->status, acx_get_status_name(priv->status));
++
++ switch (priv->status) {
++ case ACX_STATUS_1_SCANNING:
++ /* was set to 0 by set_status() */
++ if (++priv->scan_retries < 7) {
++ acx_set_timer(priv, 1000000);
++ /* used to interrogate for scan status.
++ ** We rely on SCAN_COMPLETE IRQ instead */
++ acxlog(L_ASSOC, "continuing scan (%d sec)\n",
++ priv->scan_retries);
++ } else {
++ acxlog(L_ASSOC, "stopping scan\n");
++ /* send stop_scan cmd when we leave the interrupt context,
++ * and make a decision what to do next (COMPLETE_SCAN) */
++ acx_schedule_after_interrupt_task(priv,
++ ACX_AFTER_IRQ_CMD_STOP_SCAN + ACX_AFTER_IRQ_COMPLETE_SCAN);
++ }
++ break;
++ case ACX_STATUS_2_WAIT_AUTH:
++ /* was set to 0 by set_status() */
++ if (++priv->auth_or_assoc_retries < 10) {
++ acxlog(L_ASSOC, "resend authen1 request (attempt %d)\n",
++ priv->auth_or_assoc_retries + 1);
++ acx_l_transmit_authen1(priv);
++ } else {
++ /* time exceeded: fall back to scanning mode */
++ acxlog(L_ASSOC,
++ "authen1 request reply timeout, giving up\n");
++ /* we are a STA, need to find AP anyhow */
++ acx_set_status(priv, ACX_STATUS_1_SCANNING);
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
++ }
++ /* used to be 1500000, but some other driver uses 2.5s */
++ acx_set_timer(priv, 2500000);
++ break;
++ case ACX_STATUS_3_AUTHENTICATED:
++ /* was set to 0 by set_status() */
++ if (++priv->auth_or_assoc_retries < 10) {
++ acxlog(L_ASSOC, "resend assoc request (attempt %d)\n",
++ priv->auth_or_assoc_retries + 1);
++ acx_l_transmit_assoc_req(priv);
++ } else {
++ /* time exceeded: give up */
++ acxlog(L_ASSOC,
++ "association request reply timeout, giving up\n");
++ /* we are a STA, need to find AP anyhow */
++ acx_set_status(priv, ACX_STATUS_1_SCANNING);
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_RESTART_SCAN);
++ }
++ acx_set_timer(priv, 2500000); /* see above */
++ break;
++ case ACX_STATUS_4_ASSOCIATED:
++ default:
++ break;
++ }
++
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++
++
++/*------------------------------------------------------------------------------
++ * acx_set_timer
++ *
++ * Sets the 802.11 state management timer's timeout.
++ *----------------------------------------------------------------------------*/
++void
++acx_set_timer(wlandevice_t *priv, int timeout_us)
++{
++ FN_ENTER;
++
++ acxlog(L_DEBUG|L_IRQ, "%s(%u ms)\n", __func__, timeout_us/1000);
++ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
++ printk("attempt to set the timer "
++ "when the card interface is not up!\n");
++ goto end;
++ }
++
++ /* first check if the timer was already initialized, THEN modify it */
++ if (priv->mgmt_timer.function) {
++ mod_timer(&priv->mgmt_timer,
++ jiffies + (timeout_us * HZ / 1000000));
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_assocresp
++*
++* We are an AP here
++*----------------------------------------------------------------*/
++static const u8
++dot11ratebyte[] = {
++ DOT11RATEBYTE_1,
++ DOT11RATEBYTE_2,
++ DOT11RATEBYTE_5_5,
++ DOT11RATEBYTE_6_G,
++ DOT11RATEBYTE_9_G,
++ DOT11RATEBYTE_11,
++ DOT11RATEBYTE_12_G,
++ DOT11RATEBYTE_18_G,
++ DOT11RATEBYTE_22,
++ DOT11RATEBYTE_24_G,
++ DOT11RATEBYTE_36_G,
++ DOT11RATEBYTE_48_G,
++ DOT11RATEBYTE_54_G,
++};
++
++static int
++find_pos(const u8 *p, int size, u8 v)
++{
++ int i;
++ for (i = 0; i < size; i++)
++ if (p[i] == v)
++ return i;
++ /* printk a message about strange byte? */
++ return 0;
++}
++
++static void
++add_bits_to_ratemasks(u8* ratevec, int len, u16* brate, u16* orate)
++{
++ while (len--) {
++ int n = 1 << find_pos(dot11ratebyte,
++ sizeof(dot11ratebyte), *ratevec & 0x7f);
++ if (*ratevec & 0x80)
++ *brate |= n;
++ *orate |= n;
++ ratevec++;
++ }
++}
++
++static int
++acx_l_transmit_assocresp(wlandevice_t *priv, const wlan_fr_assocreq_t *req)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct assocresp_frame_body *body;
++ u8 *p;
++ const u8 *da;
++ /* const u8 *sa; */
++ const u8 *bssid;
++ client_t *clt;
++
++ FN_ENTER;
++
++ /* sa = req->hdr->a1; */
++ da = req->hdr->a2;
++ bssid = req->hdr->a3;
++
++ clt = acx_l_sta_list_get(priv, da);
++ if (!clt)
++ goto ok;
++
++ /* Assoc without auth is a big no-no */
++ /* Let's be liberal: if already assoc'ed STA sends assoc req again,
++ ** we won't be rude */
++ if (clt->used != CLIENT_AUTHENTICATED_2
++ && clt->used != CLIENT_ASSOCIATED_3) {
++ acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
++ goto bad;
++ }
++
++ clt->used = CLIENT_ASSOCIATED_3;
++
++ if (clt->aid == 0) {
++ clt->aid = ++priv->aid;
++ }
++ clt->cap_info = ieee2host16(*(req->cap_info));
++ /* We cheat here a bit. We don't really care which rates are flagged
++ ** as basic by the client, so we stuff them in single ratemask */
++ clt->rate_cap = 0;
++ if (req->supp_rates)
++ add_bits_to_ratemasks(req->supp_rates->rates,
++ req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
++ if (req->ext_rates)
++ add_bits_to_ratemasks(req->ext_rates->rates,
++ req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
++ /* We can check that client supports all basic rates,
++ ** and deny assoc if not. But let's be liberal, right? ;) */
++ clt->rate_cfg = clt->rate_cap & priv->rate_oper;
++ if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
++ clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
++ clt->fallback_count = clt->stepup_count = 0;
++ clt->ignore_count = 16;
++
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto bad;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto bad;
++ body = (void*)(head + 1);
++
++ head->fc = WF_FSTYPE_ASSOCRESPi;
++ head->dur = req->hdr->dur;
++ MAC_COPY(head->da, da);
++ /* MAC_COPY(head->sa, sa); */
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, bssid);
++ head->seq = req->hdr->seq;
++
++ body->cap_info = host2ieee16(priv->capabilities);
++ body->status = host2ieee16(0);
++ body->aid = host2ieee16(clt->aid);
++ p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
++ priv->rate_supported);
++ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
++ priv->rate_supported);
++
++ acx_l_tx_data(priv, tx, p - (u8*)head);
++ok:
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_reassocresp
++
++You may be wondering, just like me, what a hell is ReAuth.
++In practice it was seen sent by STA when STA feels like losing connection.
++
++[802.11]
++
++5.4.2.3 Reassociation
++
++Association is sufficient for no-transition message delivery between
++IEEE 802.11 stations. Additional functionality is needed to support
++BSS-transition mobility. The additional required functionality
++is provided by the reassociation service. Reassociation is a DSS.
++The reassociation service is invoked to 'move' a current association
++from one AP to another. This keeps the DS informed of the current
++mapping between AP and STA as the station moves from BSS to BSS within
++an ESS. Reassociation also enables changing association attributes
++of an established association while the STA remains associated with
++the same AP. Reassociation is always initiated by the mobile STA.
++
++5.4.3.1 Authentication
++...
++A STA may be authenticated with many other STAs at any given instant.
++
++5.4.3.1.1 Preauthentication
++
++Because the authentication process could be time-consuming (depending
++on the authentication protocol in use), the authentication service can
++be invoked independently of the association service. Preauthentication
++is typically done by a STA while it is already associated with an AP
++(with which it previously authenticated). IEEE 802.11 does not require
++that STAs preauthenticate with APs. However, authentication is required
++before an association can be established. If the authentication is left
++until reassociation time, this may impact the speed with which a STA can
++reassociate between APs, limiting BSS-transition mobility performance.
++The use of preauthentication takes the authentication service overhead
++out of the time-critical reassociation process.
++
++5.7.3 Reassociation
++
++For a STA to reassociate, the reassociation service causes the following
++message to occur:
++
++ Reassociation request
++
++* Message type: Management
++* Message subtype: Reassociation request
++* Information items:
++ - IEEE address of the STA
++ - IEEE address of the AP with which the STA will reassociate
++ - IEEE address of the AP with which the STA is currently associated
++ - ESSID
++* Direction of message: From STA to 'new' AP
++
++The address of the current AP is included for efficiency. The inclusion
++of the current AP address facilitates MAC reassociation to be independent
++of the DS implementation.
++
++ Reassociation response
++* Message type: Management
++* Message subtype: Reassociation response
++* Information items:
++ - Result of the requested reassociation. (success/failure)
++ - If the reassociation is successful, the response shall include the AID.
++* Direction of message: From AP to STA
++
++7.2.3.6 Reassociation Request frame format
++
++The frame body of a management frame of subtype Reassociation Request
++contains the information shown in Table 9.
++
++Table 9 Reassociation Request frame body
++Order Information
++1 Capability information
++2 Listen interval
++3 Current AP address
++4 SSID
++5 Supported rates
++
++7.2.3.7 Reassociation Response frame format
++
++The frame body of a management frame of subtype Reassociation Response
++contains the information shown in Table 10.
++
++Table 10 Reassociation Response frame body
++Order Information
++1 Capability information
++2 Status code
++3 Association ID (AID)
++4 Supported rates
++
++*----------------------------------------------------------------*/
++static int
++acx_l_transmit_reassocresp(wlandevice_t *priv, const wlan_fr_reassocreq_t *req)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct reassocresp_frame_body *body;
++ u8 *p;
++ const u8 *da;
++ /* const u8 *sa; */
++ const u8 *bssid;
++ client_t *clt;
++
++ FN_ENTER;
++
++ /* sa = req->hdr->a1; */
++ da = req->hdr->a2;
++ bssid = req->hdr->a3;
++
++ /* Must be already authenticated, so it must be in the list */
++ clt = acx_l_sta_list_get(priv, da);
++ if (!clt)
++ goto ok;
++
++ /* Assoc without auth is a big no-no */
++ /* Already assoc'ed STAs sending ReAssoc req are ok per 802.11 */
++ if (clt->used != CLIENT_AUTHENTICATED_2
++ && clt->used != CLIENT_ASSOCIATED_3) {
++ acx_l_transmit_deauthen(priv, da, WLAN_MGMT_REASON_CLASS2_NONAUTH);
++ goto bad;
++ }
++
++ clt->used = CLIENT_ASSOCIATED_3;
++ if (clt->aid == 0) {
++ clt->aid = ++priv->aid;
++ }
++ if (req->cap_info)
++ clt->cap_info = ieee2host16(*(req->cap_info));
++ /* We cheat here a bit. We don't really care which rates are flagged
++ ** as basic by the client, so we stuff them in single ratemask */
++ clt->rate_cap = 0;
++ if (req->supp_rates)
++ add_bits_to_ratemasks(req->supp_rates->rates,
++ req->supp_rates->len, &clt->rate_cap, &clt->rate_cap);
++ if (req->ext_rates)
++ add_bits_to_ratemasks(req->ext_rates->rates,
++ req->ext_rates->len, &clt->rate_cap, &clt->rate_cap);
++ /* We can check that client supports all basic rates,
++ ** and deny assoc if not. But let's be liberal, right? ;) */
++ clt->rate_cfg = clt->rate_cap & priv->rate_oper;
++ if (!clt->rate_cfg) clt->rate_cfg = 1 << lowest_bit(priv->rate_oper);
++ clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
++ clt->fallback_count = clt->stepup_count = 0;
++ clt->ignore_count = 16;
++
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto ok;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto ok;
++ body = (void*)(head + 1);
++
++ head->fc = WF_FSTYPE_REASSOCRESPi;
++ head->dur = req->hdr->dur;
++ MAC_COPY(head->da, da);
++ /* MAC_COPY(head->sa, sa); */
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, bssid);
++ head->seq = req->hdr->seq;
++
++ /* IEs: 1. caps */
++ body->cap_info = host2ieee16(priv->capabilities);
++ /* 2. status code */
++ body->status = host2ieee16(0);
++ /* 3. AID */
++ body->aid = host2ieee16(clt->aid);
++ /* 4. supp rates */
++ p = wlan_fill_ie_rates((u8*)&body->rates, priv->rate_supported_len,
++ priv->rate_supported);
++ /* 5. ext supp rates */
++ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len,
++ priv->rate_supported);
++
++ acx_l_tx_data(priv, tx, p - (u8*)head);
++ok:
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_disassoc_from_sta
++*----------------------------------------------------------------*/
++static void
++acx_l_process_disassoc_from_sta(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
++{
++ const u8 *ta;
++ client_t *clt;
++
++ FN_ENTER;
++
++ ta = req->hdr->a2;
++ clt = acx_l_sta_list_get(priv, ta);
++ if (!clt)
++ goto end;
++
++ if (clt->used != CLIENT_ASSOCIATED_3
++ && clt->used != CLIENT_AUTHENTICATED_2) {
++ /* it's disassociating, but it's
++ ** not even authenticated! Let it know that */
++ acxlog_mac(L_ASSOC|L_XFER, "peer ", ta, "has sent disassoc "
++ "req but it is not even auth'ed! sending deauth\n");
++ acx_l_transmit_deauthen(priv, ta,
++ WLAN_MGMT_REASON_CLASS2_NONAUTH);
++ clt->used = CLIENT_EXIST_1;
++ } else {
++ /* mark it as auth'ed only */
++ clt->used = CLIENT_AUTHENTICATED_2;
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_deauthen_from_sta
++*----------------------------------------------------------------*/
++static void
++acx_l_process_deauth_from_sta(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
++{
++ const wlan_hdr_t *hdr;
++ client_t *client;
++
++ FN_ENTER;
++
++ hdr = req->hdr;
++
++ if (acx_debug & L_ASSOC) {
++ acx_print_mac("DEAUTHEN priv->addr=", priv->dev_addr, " ");
++ acx_print_mac("a1", hdr->a1, " ");
++ acx_print_mac("a2", hdr->a2, " ");
++ acx_print_mac("a3", hdr->a3, " ");
++ acx_print_mac("priv->bssid", priv->bssid, "\n");
++ }
++
++ if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
++ goto end;
++ }
++
++ acxlog_mac(L_DEBUG, "STA ", hdr->a2, " sent us deauthen packet\n");
++
++ client = acx_l_sta_list_get(priv, hdr->a2);
++ if (!client) {
++ goto end;
++ }
++ client->used = CLIENT_EXIST_1;
++end:
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_disassoc_from_ap
++*----------------------------------------------------------------*/
++static void
++acx_l_process_disassoc_from_ap(wlandevice_t *priv, const wlan_fr_disassoc_t *req)
++{
++ FN_ENTER;
++
++ if (!priv->ap_client) {
++ /* Hrm, we aren't assoc'ed yet anyhow... */
++ goto end;
++ }
++ if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
++ acx_l_transmit_deauthen(priv, priv->bssid,
++ WLAN_MGMT_REASON_DEAUTH_LEAVING);
++ /* Start scan anew */
++ SET_BIT(priv->set_mask, GETSET_RESCAN);
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_deauth_from_ap
++*----------------------------------------------------------------*/
++static void
++acx_l_process_deauth_from_ap(wlandevice_t *priv, const wlan_fr_deauthen_t *req)
++{
++ FN_ENTER;
++
++ if (!priv->ap_client) {
++ /* Hrm, we aren't assoc'ed yet anyhow... */
++ goto end;
++ }
++ /* Chk: is ta is verified to be from our AP? */
++ if (mac_is_equal(priv->dev_addr, req->hdr->a1)) {
++ acxlog(L_DEBUG, "AP sent us deauth packet\n");
++ /* not needed: acx_set_status(priv, ACX_STATUS_1_SCANNING) */
++ SET_BIT(priv->set_mask, GETSET_RESCAN);
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/*------------------------------------------------------------------------------
++ * acx_l_rx
++ *
++ * The end of the Rx path. Pulls data from a rxhostdesc into a socket
++ * buffer and feeds it to the network stack via netif_rx().
++ *
++ * Arguments:
++ * rxdesc: the rxhostdesc to pull the data from
++ * priv: the acx100 private struct of the interface
++ *----------------------------------------------------------------------------*/
++static void
++acx_l_rx(wlandevice_t *priv, rxbuffer_t *rxbuf)
++{
++ FN_ENTER;
++ if (likely(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
++ struct sk_buff *skb;
++ skb = acx_rxbuf_to_ether(priv, rxbuf);
++ if (likely(skb)) {
++ netif_rx(skb);
++ priv->netdev->last_rx = jiffies;
++ priv->stats.rx_packets++;
++ priv->stats.rx_bytes += skb->len;
++ }
++ }
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_data_frame_master
++*----------------------------------------------------------------*/
++static int
++acx_l_process_data_frame_master(wlandevice_t *priv, rxbuffer_t *rxbuf)
++{
++ struct wlan_hdr *hdr;
++ struct tx *tx;
++ void *txbuf;
++ int len;
++ int result = NOT_OK;
++
++ FN_ENTER;
++
++ hdr = acx_get_wlan_hdr(priv, rxbuf);
++
++ switch (WF_FC_FROMTODSi & hdr->fc) {
++ case 0:
++ case WF_FC_FROMDSi:
++ acxlog(L_DEBUG, "ap->sta or adhoc->adhoc data frame ignored\n");
++ goto done;
++ case WF_FC_TODSi:
++ break;
++ default: /* WF_FC_FROMTODSi */
++ acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
++ goto done;
++ }
++
++ /* check if it is our BSSID, if not, leave */
++ if (!mac_is_equal(priv->bssid, hdr->a1)) {
++ goto done;
++ }
++
++ if (mac_is_equal(priv->dev_addr, hdr->a3)) {
++ /* this one is for us */
++ acx_l_rx(priv, rxbuf);
++ } else {
++ if (mac_is_bcast(hdr->a3)) {
++ /* this one is bcast, rx it too */
++ acx_l_rx(priv, rxbuf);
++ }
++ tx = acx_l_alloc_tx(priv);
++ if (!tx) {
++ goto fail;
++ }
++ /* repackage, tx, and hope it someday reaches its destination */
++ /* order is important, we do it in-place */
++ MAC_COPY(hdr->a1, hdr->a3);
++ MAC_COPY(hdr->a3, hdr->a2);
++ MAC_COPY(hdr->a2, priv->bssid);
++ /* To_DS = 0, From_DS = 1 */
++ hdr->fc = WF_FC_FROMDSi + WF_FTYPE_DATAi;
++
++ len = RXBUF_BYTES_RCVD(rxbuf);
++ txbuf = acx_l_get_txbuf(priv, tx);
++ if (txbuf) {
++ memcpy(txbuf, &rxbuf->hdr_a3, len);
++ acx_l_tx_data(priv, tx, len);
++ }
++ }
++done:
++ result = OK;
++fail:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_data_frame_client
++*----------------------------------------------------------------*/
++static int
++acx_l_process_data_frame_client(wlandevice_t *priv, rxbuffer_t *rxbuf)
++{
++ const u8 *da, *bssid;
++ const wlan_hdr_t *hdr;
++ netdevice_t *dev = priv->netdev;
++ int result = NOT_OK;
++
++ FN_ENTER;
++
++ if (ACX_STATUS_4_ASSOCIATED != priv->status)
++ goto drop;
++
++ hdr = acx_get_wlan_hdr(priv, rxbuf);
++
++ switch (WF_FC_FROMTODSi & hdr->fc) {
++ case 0:
++ if (priv->mode != ACX_MODE_0_ADHOC) {
++ acxlog(L_DEBUG, "adhoc->adhoc data frame ignored\n");
++ goto drop;
++ }
++ bssid = hdr->a3;
++ break;
++ case WF_FC_FROMDSi:
++ if (priv->mode != ACX_MODE_2_STA) {
++ acxlog(L_DEBUG, "ap->sta data frame ignored\n");
++ goto drop;
++ }
++ bssid = hdr->a2;
++ break;
++ case WF_FC_TODSi:
++ acxlog(L_DEBUG, "sta->ap data frame ignored\n");
++ goto drop;
++ default: /* WF_FC_FROMTODSi: wds->wds */
++ acxlog(L_DEBUG, "wds data frame ignored (todo)\n");
++ goto drop;
++ }
++
++ da = hdr->a1;
++
++ if (unlikely(acx_debug & L_DEBUG)) {
++ acx_print_mac("rx: da=", da, "");
++ acx_print_mac(" bssid=", bssid, "");
++ acx_print_mac(" priv->bssid=", priv->bssid, "");
++ acx_print_mac(" priv->addr=", priv->dev_addr, "\n");
++ }
++
++ /* promiscuous mode --> receive all packets */
++ if (unlikely(dev->flags & IFF_PROMISC))
++ goto process;
++
++ /* FIRST, check if it is our BSSID */
++ if (!mac_is_equal(priv->bssid, bssid)) {
++ /* is not our BSSID, so bail out */
++ goto drop;
++ }
++
++ /* then, check if it is our address */
++ if (mac_is_equal(priv->dev_addr, da)) {
++ goto process;
++ }
++
++ /* then, check if it is broadcast */
++ if (mac_is_bcast(da)) {
++ goto process;
++ }
++
++ if (mac_is_mcast(da)) {
++ /* unconditionally receive all multicasts */
++ if (dev->flags & IFF_ALLMULTI)
++ goto process;
++
++ /* FIXME: check against the list of
++ * multicast addresses that are configured
++ * for the interface (ifconfig) */
++ acxlog(L_XFER, "FIXME: multicast packet, need to check "
++ "against a list of multicast addresses "
++ "(to be created!); accepting packet for now\n");
++ /* for now, just accept it here */
++ goto process;
++ }
++
++ acxlog(L_DEBUG, "rx: foreign packet, dropping\n");
++ goto drop;
++process:
++ /* receive packet */
++ acx_l_rx(priv, rxbuf);
++
++ result = OK;
++drop:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_mgmt_frame
++*
++* Theory of operation: mgmt packet gets parsed (to make it easy
++* to access variable-sized IEs), results stored in 'parsed'.
++* Then we react to the packet.
++* NB: wlan_mgmt_decode_XXX are dev-independent (shoudnt have been named acx_XXX)
++*----------------------------------------------------------------*/
++typedef union parsed_mgmt_req {
++ wlan_fr_mgmt_t mgmt;
++ wlan_fr_assocreq_t assocreq;
++ wlan_fr_reassocreq_t reassocreq;
++ wlan_fr_assocresp_t assocresp;
++ wlan_fr_reassocresp_t reassocresp;
++ wlan_fr_beacon_t beacon;
++ wlan_fr_disassoc_t disassoc;
++ wlan_fr_authen_t authen;
++ wlan_fr_deauthen_t deauthen;
++ wlan_fr_proberesp_t proberesp;
++} parsed_mgmt_req_t;
++
++void BUG_excessive_stack_usage(void);
++
++static int
++acx_l_process_mgmt_frame(wlandevice_t *priv, rxbuffer_t *rxbuf)
++{
++ parsed_mgmt_req_t parsed; /* takes ~100 bytes of stack */
++ wlan_hdr_t *hdr;
++ int adhoc, sta_scan, sta, ap;
++ int len;
++
++ if (sizeof(parsed) > 256)
++ BUG_excessive_stack_usage();
++
++ FN_ENTER;
++
++ hdr = acx_get_wlan_hdr(priv, rxbuf);
++
++ /* Management frames never have these set */
++ if (WF_FC_FROMTODSi & hdr->fc) {
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++ }
++
++ len = RXBUF_BYTES_RCVD(rxbuf);
++ if (WF_FC_ISWEPi & hdr->fc)
++ len -= 0x10;
++
++ adhoc = (priv->mode == ACX_MODE_0_ADHOC);
++ sta_scan = ((priv->mode == ACX_MODE_2_STA)
++ && (priv->status != ACX_STATUS_4_ASSOCIATED));
++ sta = ((priv->mode == ACX_MODE_2_STA)
++ && (priv->status == ACX_STATUS_4_ASSOCIATED));
++ ap = (priv->mode == ACX_MODE_3_AP);
++
++ switch (WF_FC_FSTYPEi & hdr->fc) {
++ /* beacons first, for speed */
++ case WF_FSTYPE_BEACONi:
++ memset(&parsed.beacon, 0, sizeof(parsed.beacon));
++ parsed.beacon.hdr = hdr;
++ parsed.beacon.len = len;
++ if (acx_debug & L_DATA) {
++ printk("beacon len:%d fc:%04X dur:%04X seq:%04X",
++ len, hdr->fc, hdr->dur, hdr->seq);
++ acx_print_mac(" a1:", hdr->a1, "");
++ acx_print_mac(" a2:", hdr->a2, "");
++ acx_print_mac(" a3:", hdr->a3, "\n");
++ }
++ wlan_mgmt_decode_beacon(&parsed.beacon);
++ /* beacon and probe response are very similar, so... */
++ acx_l_process_probe_response(priv, &parsed.beacon, rxbuf);
++ break;
++ case WF_FSTYPE_ASSOCREQi:
++ if (!ap)
++ break;
++ memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
++ parsed.assocreq.hdr = hdr;
++ parsed.assocreq.len = len;
++ wlan_mgmt_decode_assocreq(&parsed.assocreq);
++ if (mac_is_equal(hdr->a1, priv->bssid)
++ && mac_is_equal(hdr->a3, priv->bssid)) {
++ acx_l_transmit_assocresp(priv, &parsed.assocreq);
++ }
++ break;
++ case WF_FSTYPE_REASSOCREQi:
++ if (!ap)
++ break;
++ memset(&parsed.assocreq, 0, sizeof(parsed.assocreq));
++ parsed.assocreq.hdr = hdr;
++ parsed.assocreq.len = len;
++ wlan_mgmt_decode_assocreq(&parsed.assocreq);
++ /* reassocreq and assocreq are equivalent */
++ acx_l_transmit_reassocresp(priv, &parsed.reassocreq);
++ break;
++ case WF_FSTYPE_ASSOCRESPi:
++ if (!sta_scan)
++ break;
++ memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
++ parsed.assocresp.hdr = hdr;
++ parsed.assocresp.len = len;
++ wlan_mgmt_decode_assocresp(&parsed.assocresp);
++ acx_l_process_assocresp(priv, &parsed.assocresp);
++ break;
++ case WF_FSTYPE_REASSOCRESPi:
++ if (!sta_scan)
++ break;
++ memset(&parsed.assocresp, 0, sizeof(parsed.assocresp));
++ parsed.assocresp.hdr = hdr;
++ parsed.assocresp.len = len;
++ wlan_mgmt_decode_assocresp(&parsed.assocresp);
++ acx_l_process_reassocresp(priv, &parsed.reassocresp);
++ break;
++ case WF_FSTYPE_PROBEREQi:
++ if (ap || adhoc) {
++ /* FIXME: since we're supposed to be an AP,
++ ** we need to return a Probe Response packet.
++ ** Currently firmware is doing it for us,
++ ** but firmware is buggy! See comment elsewhere --vda */
++ }
++ break;
++ case WF_FSTYPE_PROBERESPi:
++ memset(&parsed.proberesp, 0, sizeof(parsed.proberesp));
++ parsed.proberesp.hdr = hdr;
++ parsed.proberesp.len = len;
++ wlan_mgmt_decode_proberesp(&parsed.proberesp);
++ acx_l_process_probe_response(priv, &parsed.proberesp, rxbuf);
++ break;
++ case 6:
++ case 7:
++ /* exit */
++ break;
++ case WF_FSTYPE_ATIMi:
++ /* exit */
++ break;
++ case WF_FSTYPE_DISASSOCi:
++ if (!sta && !ap)
++ break;
++ memset(&parsed.disassoc, 0, sizeof(parsed.disassoc));
++ parsed.disassoc.hdr = hdr;
++ parsed.disassoc.len = len;
++ wlan_mgmt_decode_disassoc(&parsed.disassoc);
++ if (sta)
++ acx_l_process_disassoc_from_ap(priv, &parsed.disassoc);
++ else
++ acx_l_process_disassoc_from_sta(priv, &parsed.disassoc);
++ break;
++ case WF_FSTYPE_AUTHENi:
++ if (!sta_scan && !ap)
++ break;
++ memset(&parsed.authen, 0, sizeof(parsed.authen));
++ parsed.authen.hdr = hdr;
++ parsed.authen.len = len;
++ wlan_mgmt_decode_authen(&parsed.authen);
++ acx_l_process_authen(priv, &parsed.authen);
++ break;
++ case WF_FSTYPE_DEAUTHENi:
++ if (!sta && !ap)
++ break;
++ memset(&parsed.deauthen, 0, sizeof(parsed.deauthen));
++ parsed.deauthen.hdr = hdr;
++ parsed.deauthen.len = len;
++ wlan_mgmt_decode_deauthen(&parsed.deauthen);
++ if (sta)
++ acx_l_process_deauth_from_ap(priv, &parsed.deauthen);
++ else
++ acx_l_process_deauth_from_sta(priv, &parsed.deauthen);
++ break;
++ }
++
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++#ifdef UNUSED
++/*----------------------------------------------------------------
++* acx_process_class_frame
++*
++* Called from IRQ context only
++*----------------------------------------------------------------*/
++static int
++acx_process_class_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
++{
++ return OK;
++}
++#endif
++
++
++/*----------------------------------------------------------------
++* acx_l_process_NULL_frame
++*----------------------------------------------------------------*/
++#ifdef BOGUS_ITS_NOT_A_NULL_FRAME_HANDLER_AT_ALL
++static int
++acx_l_process_NULL_frame(wlandevice_t *priv, rxbuffer_t *rxbuf, int vala)
++{
++ const signed char *esi;
++ const u8 *ebx;
++ const wlan_hdr_t *hdr;
++ const client_t *client;
++ int result = NOT_OK;
++
++ hdr = acx_get_wlan_hdr(priv, rxbuf);
++
++ switch (WF_FC_FROMTODSi & hdr->fc) {
++ case 0:
++ esi = hdr->a1;
++ ebx = hdr->a2;
++ break;
++ case WF_FC_FROMDSi:
++ esi = hdr->a1;
++ ebx = hdr->a3;
++ break;
++ case WF_FC_TODSi:
++ esi = hdr->a1;
++ ebx = hdr->a2;
++ break;
++ default: /* WF_FC_FROMTODSi */
++ esi = hdr->a1; /* added by me! --vda */
++ ebx = hdr->a2;
++ }
++
++ if (esi[0x0] < 0) {
++ result = OK;
++ goto done;
++ }
++
++ client = acx_l_sta_list_get(priv, ebx);
++ if (client)
++ result = NOT_OK;
++ else {
++#ifdef IS_IT_BROKEN
++ acxlog(L_DEBUG|L_XFER, "<transmit_deauth 7>\n");
++ acx_l_transmit_deauthen(priv, ebx,
++ WLAN_MGMT_REASON_CLASS2_NONAUTH);
++#else
++ acxlog(L_DEBUG, "received NULL frame from unknown client! "
++ "We really shouldn't send deauthen here, right?\n");
++#endif
++ result = OK;
++ }
++done:
++ return result;
++}
++#endif
++
++
++/*----------------------------------------------------------------
++* acx_l_process_probe_response
++*----------------------------------------------------------------*/
++static int
++acx_l_process_probe_response(wlandevice_t *priv, wlan_fr_proberesp_t *req,
++ const rxbuffer_t *rxbuf)
++{
++ struct client *bss;
++ wlan_hdr_t *hdr;
++
++ FN_ENTER;
++
++ hdr = req->hdr;
++
++ if (mac_is_equal(hdr->a3, priv->dev_addr)) {
++ acxlog(L_ASSOC, "huh, scan found our own MAC!?\n");
++ goto ok; /* just skip this one silently */
++ }
++
++ bss = acx_l_sta_list_get_or_add(priv, hdr->a2);
++
++ /* NB: be careful modifying bss data! It may be one
++ ** of already known clients (like our AP is we are a STA)
++ ** Thus do not blindly modify e.g. current ratemask! */
++
++ if (STA_LIST_ADD_CAN_FAIL && !bss) {
++ /* uh oh, we found more sites/stations than we can handle with
++ * our current setup: pull the emergency brake and stop scanning! */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_STOP_SCAN);
++ /* TODO: a nice comment what below call achieves --vda */
++ acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
++ goto ok;
++ }
++ /* NB: get_or_add already filled bss->address = hdr->a2 */
++ MAC_COPY(bss->bssid, hdr->a3);
++
++ /* copy the ESSID element */
++ if (req->ssid && req->ssid->len <= IW_ESSID_MAX_SIZE) {
++ bss->essid_len = req->ssid->len;
++ memcpy(bss->essid, req->ssid->ssid, req->ssid->len);
++ bss->essid[req->ssid->len] = '\0';
++ } else {
++ /* Either no ESSID IE or oversized one */
++ printk("%s: received packet has bogus ESSID\n",
++ priv->netdev->name);
++ }
++
++ if (req->ds_parms)
++ bss->channel = req->ds_parms->curr_ch;
++ if (req->cap_info)
++ bss->cap_info = ieee2host16(*req->cap_info);
++
++ bss->sir = acx_signal_to_winlevel(rxbuf->phy_level);
++ bss->snr = acx_signal_to_winlevel(rxbuf->phy_snr);
++
++ bss->rate_cap = 0; /* operational mask */
++ bss->rate_bas = 0; /* basic mask */
++ if (req->supp_rates)
++ add_bits_to_ratemasks(req->supp_rates->rates,
++ req->supp_rates->len, &bss->rate_bas, &bss->rate_cap);
++ if (req->ext_rates)
++ add_bits_to_ratemasks(req->ext_rates->rates,
++ req->ext_rates->len, &bss->rate_bas, &bss->rate_cap);
++ /* Fix up any possible bogosity - code elsewhere
++ * is not expecting empty masks */
++ if (!bss->rate_cap)
++ bss->rate_cap = priv->rate_basic;
++ if (!bss->rate_bas)
++ bss->rate_bas = 1 << lowest_bit(bss->rate_cap);
++ if (!bss->rate_cur)
++ bss->rate_cur = 1 << lowest_bit(bss->rate_bas);
++
++ /* People moan about this being too noisy at L_ASSOC */
++ acxlog(L_DEBUG,
++ "found %s: ESSID='%s' ch=%d "
++ "BSSID="MACSTR" caps=0x%04X SIR=%d SNR=%d\n",
++ (bss->cap_info & WF_MGMT_CAP_IBSS) ? "Ad-Hoc peer" : "AP",
++ bss->essid, bss->channel, MAC(bss->bssid), bss->cap_info,
++ bss->sir, bss->snr);
++ok:
++ FN_EXIT0;
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_assocresp
++*----------------------------------------------------------------*/
++static int
++acx_l_process_assocresp(wlandevice_t *priv, const wlan_fr_assocresp_t *req)
++{
++ const wlan_hdr_t *hdr;
++ int res = OK;
++
++ FN_ENTER;
++ hdr = req->hdr;
++
++ if ((ACX_MODE_2_STA == priv->mode)
++ && mac_is_equal(priv->dev_addr, hdr->a1)) {
++ u16 st = ieee2host16(*(req->status));
++ if (WLAN_MGMT_STATUS_SUCCESS == st) {
++ priv->aid = ieee2host16(*(req->aid));
++ /* tell the card we are associated when we are out of interrupt context */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_ASSOCIATE);
++ } else {
++
++ /* TODO: we shall delete peer from sta_list, and try other candidates... */
++
++ printk("%s: association FAILED: peer sent "
++ "response code %d (%s)\n",
++ priv->netdev->name, st, get_status_string(st));
++ res = NOT_OK;
++ }
++ }
++
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_reassocresp
++*----------------------------------------------------------------*/
++static int
++acx_l_process_reassocresp(wlandevice_t *priv, const wlan_fr_reassocresp_t *req)
++{
++ const wlan_hdr_t *hdr;
++ int result = NOT_OK;
++ u16 st;
++
++ FN_ENTER;
++ hdr = req->hdr;
++
++ if (!mac_is_equal(priv->dev_addr, hdr->a1)) {
++ goto end;
++ }
++ st = ieee2host16(*(req->status));
++ if (st == WLAN_MGMT_STATUS_SUCCESS) {
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
++ result = OK;
++ } else {
++ printk("%s: reassociation FAILED: peer sent "
++ "response code %d (%s)\n",
++ priv->netdev->name, st, get_status_string(st));
++ }
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_process_authen
++*
++* Called only in STA_SCAN or AP mode
++*----------------------------------------------------------------*/
++static int
++acx_l_process_authen(wlandevice_t *priv, const wlan_fr_authen_t *req)
++{
++ const wlan_hdr_t *hdr;
++ client_t *clt;
++ wlan_ie_challenge_t *chal;
++ u16 alg, seq, status;
++ int ap, result;
++
++ FN_ENTER;
++
++ hdr = req->hdr;
++
++ if (acx_debug & L_ASSOC) {
++ acx_print_mac("AUTHEN priv->addr=", priv->dev_addr, " ");
++ acx_print_mac("a1=", hdr->a1, " ");
++ acx_print_mac("a2=", hdr->a2, " ");
++ acx_print_mac("a3=", hdr->a3, " ");
++ acx_print_mac("priv->bssid=", priv->bssid, "\n");
++ }
++
++ if (!mac_is_equal(priv->dev_addr, hdr->a1)
++ || !mac_is_equal(priv->bssid, hdr->a3)) {
++ result = OK;
++ goto end;
++ }
++
++ alg = ieee2host16(*(req->auth_alg));
++ seq = ieee2host16(*(req->auth_seq));
++ status = ieee2host16(*(req->status));
++
++ ap = (priv->mode == ACX_MODE_3_AP);
++
++ if (priv->auth_alg <= 1) {
++ if (priv->auth_alg != alg) {
++ acxlog(L_ASSOC, "authentication algorithm mismatch: "
++ "want: %d, req: %d\n", priv->auth_alg, alg);
++ result = NOT_OK;
++ goto end;
++ }
++ }
++ acxlog(L_ASSOC, "algorithm is ok\n");
++
++ if (ap) {
++ clt = acx_l_sta_list_get_or_add(priv, hdr->a2);
++ if (STA_LIST_ADD_CAN_FAIL && !clt) {
++ acxlog(L_ASSOC, "could not allocate room for client\n");
++ result = NOT_OK;
++ goto end;
++ }
++ } else {
++ clt = priv->ap_client;
++ if (!mac_is_equal(clt->address, hdr->a2)) {
++ printk("%s: malformed auth frame from AP?!\n",
++ priv->netdev->name);
++ result = NOT_OK;
++ goto end;
++ }
++ }
++
++ /* now check which step in the authentication sequence we are
++ * currently in, and act accordingly */
++ acxlog(L_ASSOC, "acx_process_authen auth seq step %d\n", seq);
++ switch (seq) {
++ case 1:
++ if (!ap)
++ break;
++ acx_l_transmit_authen2(priv, req, clt);
++ break;
++ case 2:
++ if (ap)
++ break;
++ if (status == WLAN_MGMT_STATUS_SUCCESS) {
++ if (alg == WLAN_AUTH_ALG_OPENSYSTEM) {
++ acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
++ acx_l_transmit_assoc_req(priv);
++ } else
++ if (alg == WLAN_AUTH_ALG_SHAREDKEY) {
++ acx_l_transmit_authen3(priv, req);
++ }
++ } else {
++ printk("%s: auth FAILED: peer sent "
++ "response code %d (%s), "
++ "still waiting for authentication\n",
++ priv->netdev->name,
++ status, get_status_string(status));
++ acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
++ }
++ break;
++ case 3:
++ if (!ap)
++ break;
++ if ((clt->auth_alg != WLAN_AUTH_ALG_SHAREDKEY)
++ || (alg != WLAN_AUTH_ALG_SHAREDKEY)
++ || (clt->auth_step != 2))
++ break;
++ chal = req->challenge;
++ if (!chal
++ || memcmp(chal->challenge, clt->challenge_text, WLAN_CHALLENGE_LEN)
++ || (chal->eid != WLAN_EID_CHALLENGE)
++ || (chal->len != WLAN_CHALLENGE_LEN)
++ )
++ break;
++ acx_l_transmit_authen4(priv, req);
++ MAC_COPY(clt->address, hdr->a2);
++ clt->used = CLIENT_AUTHENTICATED_2;
++ clt->auth_step = 4;
++ clt->seq = ieee2host16(hdr->seq);
++ break;
++ case 4:
++ if (ap)
++ break;
++ /* ok, we're through: we're authenticated. Woohoo!! */
++ acx_set_status(priv, ACX_STATUS_3_AUTHENTICATED);
++ acxlog(L_ASSOC, "Authenticated!\n");
++ /* now that we're authenticated, request association */
++ acx_l_transmit_assoc_req(priv);
++ break;
++ }
++ result = NOT_OK;
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_gen_challenge
++*----------------------------------------------------------------*/
++static void
++acx_gen_challenge(wlan_ie_challenge_t* d)
++{
++ FN_ENTER;
++ d->eid = WLAN_EID_CHALLENGE;
++ d->len = WLAN_CHALLENGE_LEN;
++ get_random_bytes(d->challenge, WLAN_CHALLENGE_LEN);
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_deauthen
++*----------------------------------------------------------------*/
++static int
++acx_l_transmit_deauthen(wlandevice_t *priv, const u8 *addr, u16 reason)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct deauthen_frame_body *body;
++
++ FN_ENTER;
++
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto bad;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto bad;
++ body = (void*)(head + 1);
++
++ head->fc = (WF_FTYPE_MGMTi | WF_FSTYPE_DEAUTHENi);
++ head->dur = 0;
++ MAC_COPY(head->da, addr);
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, priv->bssid);
++ head->seq = 0;
++
++ acxlog(L_DEBUG|L_ASSOC|L_XFER,
++ "sending deauthen to "MACSTR" for %d\n",
++ MAC(addr), reason);
++
++ body->reason = host2ieee16(reason);
++
++ /* body is fixed size here, but beware of cutting-and-pasting this -
++ ** do not use sizeof(*body) for variable sized mgmt packets! */
++ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
++
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_authen1
++*----------------------------------------------------------------*/
++static int
++acx_l_transmit_authen1(wlandevice_t *priv)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct auth_frame_body *body;
++
++ FN_ENTER;
++
++ acxlog(L_ASSOC, "Sending authentication1 request, "
++ "awaiting response!\n");
++
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto bad;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto bad;
++ body = (void*)(head + 1);
++
++ head->fc = WF_FSTYPE_AUTHENi;
++ head->dur = host2ieee16(0x8000);
++ MAC_COPY(head->da, priv->bssid);
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, priv->bssid);
++ head->seq = 0;
++
++ body->auth_alg = host2ieee16(priv->auth_alg);
++ body->auth_seq = host2ieee16(1);
++ body->status = host2ieee16(0);
++
++ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
++
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_authen2
++*----------------------------------------------------------------*/
++static int
++acx_l_transmit_authen2(wlandevice_t *priv, const wlan_fr_authen_t *req,
++ client_t *clt)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct auth_frame_body *body;
++ unsigned int packet_len;
++
++ FN_ENTER;
++
++ if (!clt)
++ goto ok;
++
++ MAC_COPY(clt->address, req->hdr->a2);
++#ifdef UNUSED
++ clt->ps = ((WF_FC_PWRMGTi & req->hdr->fc) != 0);
++#endif
++ clt->auth_alg = ieee2host16(*(req->auth_alg));
++ clt->auth_step = 2;
++ clt->seq = ieee2host16(req->hdr->seq);
++
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto bad;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto bad;
++ body = (void*)(head + 1);
++
++ head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
++ head->dur = req->hdr->dur;
++ MAC_COPY(head->da, req->hdr->a2);
++ /* MAC_COPY(head->sa, req->hdr->a1); */
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, req->hdr->a3);
++ head->seq = req->hdr->seq;
++
++ /* already in IEEE format, no endianness conversion */
++ body->auth_alg = *(req->auth_alg);
++ body->auth_seq = host2ieee16(2);
++ body->status = host2ieee16(0);
++
++ packet_len = WLAN_HDR_A3_LEN + 2 + 2 + 2;
++ if (ieee2host16(*(req->auth_alg)) == WLAN_AUTH_ALG_OPENSYSTEM) {
++ clt->used = CLIENT_AUTHENTICATED_2;
++ } else { /* shared key */
++ acx_gen_challenge(&body->challenge);
++ memcpy(&clt->challenge_text, body->challenge.challenge, WLAN_CHALLENGE_LEN);
++ packet_len += 2 + 2 + 2 + 1+1+WLAN_CHALLENGE_LEN;
++ }
++
++ acxlog_mac(L_ASSOC|L_XFER,
++ "transmit_auth2: BSSID=", head->bssid, "\n");
++
++ acx_l_tx_data(priv, tx, packet_len);
++ok:
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_authen3
++*----------------------------------------------------------------*/
++static int
++acx_l_transmit_authen3(wlandevice_t *priv, const wlan_fr_authen_t *req)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct auth_frame_body *body;
++ unsigned int packet_len;
++
++ FN_ENTER;
++
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto ok;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto ok;
++ body = (void*)(head + 1);
++
++ head->fc = WF_FC_ISWEPi + WF_FSTYPE_AUTHENi;
++ /* FIXME: is this needed?? authen4 does it...
++ head->dur = req->hdr->dur;
++ head->seq = req->hdr->seq;
++ */
++ MAC_COPY(head->da, priv->bssid);
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, priv->bssid);
++
++ /* already in IEEE format, no endianness conversion */
++ body->auth_alg = *(req->auth_alg);
++ body->auth_seq = host2ieee16(3);
++ body->status = host2ieee16(0);
++ memcpy(&body->challenge, req->challenge, req->challenge->len + 2);
++ packet_len = WLAN_HDR_A3_LEN + 8 + req->challenge->len;
++
++ acxlog(L_ASSOC|L_XFER, "transmit_authen3!\n");
++
++ acx_l_tx_data(priv, tx, packet_len);
++ok:
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_authen4
++*----------------------------------------------------------------*/
++static int
++acx_l_transmit_authen4(wlandevice_t *priv, const wlan_fr_authen_t *req)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct auth_frame_body *body;
++
++ FN_ENTER;
++
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto ok;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto ok;
++ body = (void*)(head + 1);
++
++ head->fc = WF_FSTYPE_AUTHENi; /* 0xb0 */
++ head->dur = req->hdr->dur;
++ MAC_COPY(head->da, req->hdr->a2);
++ /* MAC_COPY(head->sa, req->hdr->a1); */
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, req->hdr->a3);
++ head->seq = req->hdr->seq;
++
++ /* already in IEEE format, no endianness conversion */
++ body->auth_alg = *(req->auth_alg);
++ body->auth_seq = host2ieee16(4);
++ body->status = host2ieee16(0);
++
++ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + 2 + 2 + 2);
++ok:
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_assoc_req
++*
++* priv->ap_client is a current candidate AP here
++*----------------------------------------------------------------*/
++static int
++acx_l_transmit_assoc_req(wlandevice_t *priv)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ u8 *body, *p, *prate;
++ unsigned int packet_len;
++ u16 cap;
++
++ FN_ENTER;
++
++ acxlog(L_ASSOC, "sending association request, "
++ "awaiting response. NOT ASSOCIATED YET\n");
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto bad;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto bad;
++ body = (void*)(head + 1);
++
++ head->fc = WF_FSTYPE_ASSOCREQi;
++ head->dur = host2ieee16(0x8000);
++ MAC_COPY(head->da, priv->bssid);
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, priv->bssid);
++ head->seq = 0;
++
++ p = body;
++ /* now start filling the AssocReq frame body */
++
++ /* since this assoc request will most likely only get
++ * sent in the STA to AP case (and not when Ad-Hoc IBSS),
++ * the cap combination indicated here will thus be
++ * WF_MGMT_CAP_ESSi *always* (no IBSS ever)
++ * The specs are more than non-obvious on all that:
++ *
++ * 802.11 7.3.1.4 Capability Information field
++ ** APs set the ESS subfield to 1 and the IBSS subfield to 0 within
++ ** Beacon or Probe Response management frames. STAs within an IBSS
++ ** set the ESS subfield to 0 and the IBSS subfield to 1 in transmitted
++ ** Beacon or Probe Response management frames
++ **
++ ** APs set the Privacy subfield to 1 within transmitted Beacon,
++ ** Probe Response, Association Response, and Reassociation Response
++ ** if WEP is required for all data type frames within the BSS.
++ ** STAs within an IBSS set the Privacy subfield to 1 in Beacon
++ ** or Probe Response management frames if WEP is required
++ ** for all data type frames within the IBSS */
++
++ /* note that returning 0 will be refused by several APs...
++ * (so this indicates that you're probably supposed to
++ * "confirm" the ESS mode) */
++ cap = WF_MGMT_CAP_ESSi;
++
++ /* this one used to be a check on wep_restricted,
++ * but more likely it's wep_enabled instead */
++ if (priv->wep_enabled)
++ SET_BIT(cap, WF_MGMT_CAP_PRIVACYi);
++
++ /* Probably we can just set these always, because our hw is
++ ** capable of shortpre and PBCC --vda */
++ /* only ask for short preamble if the peer station supports it */
++ if (priv->ap_client->cap_info & WF_MGMT_CAP_SHORT)
++ SET_BIT(cap, WF_MGMT_CAP_SHORTi);
++ /* only ask for PBCC support if the peer station supports it */
++ if (priv->ap_client->cap_info & WF_MGMT_CAP_PBCC)
++ SET_BIT(cap, WF_MGMT_CAP_PBCCi);
++
++ /* IEs: 1. caps */
++ *(u16*)p = cap; p += 2;
++ /* 2. listen interval */
++ *(u16*)p = host2ieee16(priv->listen_interval); p += 2;
++ /* 3. ESSID */
++ p = wlan_fill_ie_ssid(p,
++ strlen(priv->essid_for_assoc), priv->essid_for_assoc);
++ /* 4. supp rates */
++ prate = p;
++ p = wlan_fill_ie_rates(p,
++ priv->rate_supported_len, priv->rate_supported);
++ /* 5. ext supp rates */
++ p = wlan_fill_ie_rates_ext(p,
++ priv->rate_supported_len, priv->rate_supported);
++
++ if (acx_debug & L_DEBUG) {
++ printk("association: rates element\n");
++ acx_dump_bytes(prate, p - prate);
++ }
++
++ /* calculate lengths */
++ packet_len = WLAN_HDR_A3_LEN + (p - body);
++
++ acxlog(L_ASSOC, "association: requesting caps 0x%04X, ESSID '%s'\n",
++ cap, priv->essid_for_assoc);
++
++ acx_l_tx_data(priv, tx, packet_len);
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_transmit_disassoc
++*
++* FIXME: looks like incomplete implementation of a helper:
++* acx_l_transmit_disassoc(priv, clt) - kick this client (we're an AP)
++* acx_l_transmit_disassoc(priv, NULL) - leave BSSID (we're a STA)
++*----------------------------------------------------------------*/
++#ifdef BROKEN
++int
++acx_l_transmit_disassoc(wlandevice_t *priv, client_t *clt)
++{
++ struct tx *tx;
++ struct wlan_hdr_mgmt *head;
++ struct disassoc_frame_body *body;
++
++ FN_ENTER;
++/* if (clt != NULL) { */
++ tx = acx_l_alloc_tx(priv);
++ if (!tx)
++ goto bad;
++ head = acx_l_get_txbuf(priv, tx);
++ if (!head)
++ goto bad;
++ body = (void*)(head + 1);
++
++/* clt->used = CLIENT_AUTHENTICATED_2; - not (yet?) associated */
++
++ head->fc = WF_FSTYPE_DISASSOCi;
++ head->dur = 0;
++ /* huh? It muchly depends on whether we're STA or AP...
++ ** sta->ap: da=bssid, sa=own, bssid=bssid
++ ** ap->sta: da=sta, sa=bssid, bssid=bssid. FIXME! */
++ MAC_COPY(head->da, priv->bssid);
++ MAC_COPY(head->sa, priv->dev_addr);
++ MAC_COPY(head->bssid, priv->dev_addr);
++ head->seq = 0;
++
++ /* "Class 3 frame received from nonassociated station." */
++ body->reason = host2ieee16(7);
++
++ /* fixed size struct, ok to sizeof */
++ acx_l_tx_data(priv, tx, WLAN_HDR_A3_LEN + sizeof(*body));
++/* } */
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++#endif
++
++
++/*----------------------------------------------------------------
++* acx_s_complete_scan
++*
++* Called either from after_interrupt_task() if:
++* 1) there was Scan_Complete IRQ, or
++* 2) scanning expired in timer()
++* We need to decide which ESS or IBSS to join.
++* Iterates thru priv->sta_list:
++* if priv->ap is not bcast, will join only specified
++* ESS or IBSS with this bssid
++* checks peers' caps for ESS/IBSS bit
++* checks peers' SSID, allows exact match or hidden SSID
++* If station to join is chosen:
++* points priv->ap_client to the chosen struct client
++* sets priv->essid_for_assoc for future assoc attempt
++* Auth/assoc is not yet performed
++* Returns OK if there is no need to restart scan
++*----------------------------------------------------------------*/
++int
++acx_s_complete_scan(wlandevice_t *priv)
++{
++ struct client *bss;
++ unsigned long flags;
++ u16 needed_cap;
++ int i;
++ int idx_found = -1;
++ int result = OK;
++
++ FN_ENTER;
++
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ needed_cap = WF_MGMT_CAP_IBSS; /* 2, we require Ad-Hoc */
++ break;
++ case ACX_MODE_2_STA:
++ needed_cap = WF_MGMT_CAP_ESS; /* 1, we require Managed */
++ break;
++ default:
++ printk("acx: driver bug: mode=%d in complete_scan()\n", priv->mode);
++ dump_stack();
++ goto end;
++ }
++
++ acx_lock(priv, flags);
++
++ /* TODO: sta_iterator hiding implementation would be nice here... */
++
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ bss = &priv->sta_list[i];
++ if (!bss->used) continue;
++
++ acxlog(L_ASSOC, "Scan Table: SSID='%s' CH=%d SIR=%d SNR=%d\n",
++ bss->essid, bss->channel, bss->sir, bss->snr);
++
++ if (!mac_is_bcast(priv->ap))
++ if (!mac_is_equal(bss->bssid, priv->ap))
++ continue; /* keep looking */
++
++ /* broken peer with no mode flags set? */
++ if (unlikely(!(bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)))) {
++ printk("%s: strange peer "MACSTR" found with "
++ "neither ESS (AP) nor IBSS (Ad-Hoc) "
++ "capability - skipped\n",
++ priv->netdev->name, MAC(bss->address));
++ continue;
++ }
++ acxlog(L_ASSOC, "peer_cap 0x%04X, needed_cap 0x%04X\n",
++ bss->cap_info, needed_cap);
++
++ /* does peer station support what we need? */
++ if ((bss->cap_info & needed_cap) != needed_cap)
++ continue; /* keep looking */
++
++ /* strange peer with NO basic rates?! */
++ if (unlikely(!bss->rate_bas)) {
++ printk("%s: strange peer "MACSTR" with empty rate set "
++ "- skipped\n",
++ priv->netdev->name, MAC(bss->address));
++ continue;
++ }
++
++ /* do we support all basic rates of this peer? */
++ if ((bss->rate_bas & priv->rate_oper) != bss->rate_bas) {
++/* we probably need to have all rates as operational rates,
++ even in case of an 11M-only configuration */
++#ifdef THIS_IS_TROUBLESOME
++ printk("%s: peer "MACSTR": incompatible basic rates "
++ "(AP requests 0x%04X, we have 0x%04X) "
++ "- skipped\n",
++ priv->netdev->name, MAC(bss->address),
++ bss->rate_bas, priv->rate_oper);
++ continue;
++#else
++ printk("%s: peer "MACSTR": incompatible basic rates "
++ "(AP requests 0x%04X, we have 0x%04X). "
++ "Considering anyway...\n",
++ priv->netdev->name, MAC(bss->address),
++ bss->rate_bas, priv->rate_oper);
++#endif
++ }
++
++ if ( !(priv->reg_dom_chanmask & (1<<(bss->channel-1))) ) {
++ printk("%s: warning: peer "MACSTR" is on channel %d "
++ "outside of channel range of current "
++ "regulatory domain - couldn't join "
++ "even if other settings match. "
++ "You might want to adapt your config\n",
++ priv->netdev->name, MAC(bss->address),
++ bss->channel);
++ continue; /* keep looking */
++ }
++
++ if (!priv->essid_active || !strcmp(bss->essid, priv->essid)) {
++ acxlog(L_ASSOC,
++ "found station with matching ESSID! ('%s' "
++ "station, '%s' config)\n",
++ bss->essid,
++ (priv->essid_active) ? priv->essid : "[any]");
++ /* TODO: continue looking for peer with better SNR */
++ bss->used = CLIENT_JOIN_CANDIDATE;
++ idx_found = i;
++
++ /* stop searching if this station is
++ * on the current channel, otherwise
++ * keep looking for an even better match */
++ if (bss->channel == priv->channel)
++ break;
++ } else
++ if (!bss->essid[0]
++ || ((' ' == bss->essid[0]) && !bss->essid[1])
++ ) {
++ /* hmm, station with empty or single-space SSID:
++ * using hidden SSID broadcast?
++ */
++ /* This behaviour is broken: which AP from zillion
++ ** of APs with hidden SSID you'd try?
++ ** We should use Probe requests to get Probe responses
++ ** and check for real SSID (are those never hidden?) */
++ bss->used = CLIENT_JOIN_CANDIDATE;
++ if (idx_found == -1)
++ idx_found = i;
++ acxlog(L_ASSOC, "found station with empty or "
++ "single-space (hidden) SSID, considering "
++ "for assoc attempt\n");
++ /* ...and keep looking for better matches */
++ } else {
++ acxlog(L_ASSOC, "ESSID doesn't match! ('%s' "
++ "station, '%s' config)\n",
++ bss->essid,
++ (priv->essid_active) ? priv->essid : "[any]");
++ }
++ }
++
++ /* TODO: iterate thru join candidates instead */
++ /* TODO: rescan if not associated within some timeout */
++ if (idx_found != -1) {
++ char *essid_src;
++ size_t essid_len;
++
++ bss = &priv->sta_list[idx_found];
++ priv->ap_client = bss;
++
++ if (bss->essid[0] == '\0') {
++ /* if the ESSID of the station we found is empty
++ * (no broadcast), then use user configured ESSID
++ * instead */
++ essid_src = priv->essid;
++ essid_len = priv->essid_len;
++ } else {
++ essid_src = bss->essid;
++ essid_len = strlen(bss->essid);
++ }
++
++ acx_update_capabilities(priv);
++
++ memcpy(priv->essid_for_assoc, essid_src, essid_len);
++ priv->essid_for_assoc[essid_len] = '\0';
++ priv->channel = bss->channel;
++ MAC_COPY(priv->bssid, bss->bssid);
++
++ bss->rate_cfg = (bss->rate_cap & priv->rate_oper);
++ bss->rate_cur = 1 << lowest_bit(bss->rate_cfg);
++ bss->rate_100 = acx_rate111to100(bss->rate_cur);
++
++ acxlog_mac(L_ASSOC,
++ "matching station found: ", priv->bssid, ", joining\n");
++
++ /* TODO: do we need to switch to the peer's channel first? */
++
++ if (ACX_MODE_0_ADHOC == priv->mode) {
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
++ } else {
++ acx_l_transmit_authen1(priv);
++ acx_set_status(priv, ACX_STATUS_2_WAIT_AUTH);
++ }
++ } else { /* idx_found == -1 */
++ /* uh oh, no station found in range */
++ if (ACX_MODE_0_ADHOC == priv->mode) {
++ printk("%s: no matching station found in range, "
++ "generating our own IBSS instead\n",
++ priv->netdev->name);
++ /* we do it hostap way: */
++ MAC_COPY(priv->bssid, priv->dev_addr);
++ priv->bssid[0] |= 0x02; /* 'local assigned addr' bit */
++ /* add IBSS bit to our caps... */
++ acx_update_capabilities(priv);
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
++ /* In order to cmd_join be called below */
++ idx_found = 0;
++ } else {
++ /* we shall scan again, AP can be
++ ** just temporarily powered off */
++ acxlog(L_ASSOC,
++ "no matching station found in range yet\n");
++ acx_set_status(priv, ACX_STATUS_1_SCANNING);
++ result = NOT_OK;
++ }
++ }
++
++ acx_unlock(priv, flags);
++
++ if (idx_found != -1) {
++ if (ACX_MODE_0_ADHOC == priv->mode) {
++ /* need to update channel in beacon template */
++ SET_BIT(priv->set_mask, SET_TEMPLATES);
++ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
++ acx_s_update_card_settings(priv, 0, 0);
++ }
++ /* Inform firmware on our decision to start or join BSS */
++ acx_s_cmd_join_bssid(priv, priv->bssid);
++ }
++
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx_s_read_fw
++**
++** Loads a firmware image
++**
++** Returns:
++** 0 unable to load file
++** pointer to firmware success
++*/
++#if USE_FW_LOADER_26
++firmware_image_t*
++acx_s_read_fw(struct device *dev, const char *file, u32 *size)
++#else
++#undef acx_s_read_fw
++firmware_image_t*
++acx_s_read_fw(const char *file, u32 *size)
++#endif
++{
++ firmware_image_t *res;
++
++#if USE_FW_LOADER_LEGACY
++ mm_segment_t orgfs;
++ unsigned long page;
++ char *buffer;
++ struct file *inf;
++ int retval;
++ int offset;
++ char *filename;
++#endif
++
++#if USE_FW_LOADER_26
++ const struct firmware *fw_entry;
++
++ res = NULL;
++ acxlog(L_DEBUG, "requesting firmware image '%s'\n", file);
++ if (!request_firmware(&fw_entry, file, dev)) {
++ *size = 8;
++ if (fw_entry->size >= 8)
++ *size = 8 + le32_to_cpu(*(u32 *)(fw_entry->data + 4));
++ if (fw_entry->size != *size) {
++ printk("acx: firmware size does not match "
++ "firmware header: %d != %d, "
++ "aborting fw upload\n",
++ (int) fw_entry->size, (int) *size);
++ goto release_ret;
++ }
++ res = vmalloc(*size);
++ if (!res) {
++ printk("acx: no memory for firmware "
++ "(%u bytes)\n", *size);
++ goto release_ret;
++ }
++ memcpy(res, fw_entry->data, fw_entry->size);
++release_ret:
++ release_firmware(fw_entry);
++ return res;
++ }
++ printk("acx: firmware image '%s' was not provided. "
++ "Check your hotplug scripts\n", file);
++#endif
++
++#if USE_FW_LOADER_LEGACY
++ printk("acx: firmware upload via firmware_dir module parameter "
++ "is deprecated. Switch to using hotplug\n");
++
++ res = NULL;
++ orgfs = get_fs(); /* store original fs */
++ set_fs(KERNEL_DS);
++
++ /* Read in whole file then check the size */
++ page = __get_free_page(GFP_KERNEL);
++ if (unlikely(0 == page)) {
++ printk("acx: no memory for firmware upload\n");
++ goto fail;
++ }
++
++ filename = kmalloc(PATH_MAX, GFP_KERNEL);
++ if (unlikely(!filename)) {
++ printk("acx: no memory for firmware upload\n");
++ goto fail;
++ }
++ if (!firmware_dir) {
++ firmware_dir = "/usr/share/acx";
++ acxlog(L_DEBUG, "no firmware directory specified "
++ "via module parameter firmware_dir, "
++ "using default %s\n", firmware_dir);
++ }
++ snprintf(filename, PATH_MAX, "%s/%s", firmware_dir, file);
++ acxlog(L_DEBUG, "reading firmware image '%s'\n", filename);
++
++ buffer = (char*)page;
++
++ /* Note that file must be given as absolute path:
++ * a relative path works on first loading,
++ * but any subsequent firmware loading during card
++ * eject/insert will fail, most likely since the first
++ * module loading happens in user space (and thus
++ * filp_open can figure out the absolute path from a
++ * relative path) whereas the card reinsert processing
++ * probably happens in kernel space where you don't have
++ * a current directory to be able to figure out an
++ * absolute path from a relative path... */
++ inf = filp_open(filename, O_RDONLY, 0);
++ kfree(filename);
++ if (OK != IS_ERR(inf)) {
++ const char *err;
++
++ switch (-PTR_ERR(inf)) {
++ case 2: err = "file not found";
++ break;
++ default:
++ err = "unknown error";
++ break;
++ }
++ printk("acx: error %ld trying to open file '%s': %s\n",
++ -PTR_ERR(inf), file, err);
++ goto fail;
++ }
++
++ if (unlikely((NULL == inf->f_op) || (NULL == inf->f_op->read))) {
++ printk("acx: %s does not have a read method?!\n", file);
++ goto fail_close;
++ }
++
++ offset = 0;
++ do {
++ retval = inf->f_op->read(inf, buffer, PAGE_SIZE, &inf->f_pos);
++
++ if (unlikely(0 > retval)) {
++ printk("acx: error %d reading file '%s'\n",
++ -retval, file);
++ vfree(res);
++ res = NULL;
++ } else if (0 == retval) {
++ if (0 == offset) {
++ printk("acx: firmware image file "
++ "'%s' is empty?!\n", file);
++ }
++ } else if (0 < retval) {
++ /* allocate result buffer here if needed,
++ * since we don't want to waste resources/time
++ * (in case file opening/reading fails)
++ * by doing allocation in front of the loop instead. */
++ if (NULL == res) {
++ *size = 8 + le32_to_cpu(*(u32 *)(4 + buffer));
++
++ res = vmalloc(*size);
++ if (NULL == res) {
++ printk("acx: unable to "
++ "allocate %u bytes for "
++ "firmware module upload\n",
++ *size);
++ goto fail_close;
++ }
++ acxlog(L_DEBUG, "allocated %u bytes "
++ "for firmware module loading\n",
++ *size);
++ }
++ if ((unlikely(offset + retval > *size))) {
++ printk("acx: ERROR: allocation "
++ "was less than firmware image size?!\n");
++ goto fail_close;
++ }
++ memcpy((u8*)res + offset, buffer, retval);
++ offset += retval;
++ }
++ } while (0 < retval);
++
++fail_close:
++ retval = filp_close(inf, NULL);
++
++ if (unlikely(retval)) {
++ printk("acx: error %d closing file '%s'\n", -retval, file);
++ }
++
++ if (unlikely((NULL != res) && (offset != le32_to_cpu(res->size) + 8))) {
++ printk("acx: firmware is reporting a different size "
++ "(0x%08X; 0x%08X was read)\n",
++ le32_to_cpu(res->size) + 8, offset);
++ vfree(res);
++ res = NULL;
++ }
++
++fail:
++ if (page)
++ free_page(page);
++ set_fs(orgfs);
++#endif
++
++ /* checksum will be verified in write_fw, so don't bother here */
++ return res;
++}
++
++
++#ifdef POWER_SAVE_80211
++/*----------------------------------------------------------------
++* acx_s_activate_power_save_mode
++*----------------------------------------------------------------*/
++static void
++acx_s_activate_power_save_mode(wlandevice_t *priv)
++{
++ acx100_ie_powermgmt_t pm;
++
++ FN_ENTER;
++
++ acx_s_interrogate(priv, &pm, ACX1xx_IE_POWER_MGMT);
++ if (pm.wakeup_cfg != 0x81)
++ goto end;
++
++ pm.wakeup_cfg = 0;
++ pm.options = 0;
++ pm.hangover_period = 0;
++ acx_s_configure(priv, &pm, ACX1xx_IE_POWER_MGMT);
++end:
++ FN_EXIT0;
++}
++#endif
++
++
++/***********************************************************************
++** acx_s_set_wepkey
++*/
++static void
++acx100_s_set_wepkey(wlandevice_t *priv)
++{
++ ie_dot11WEPDefaultKey_t dk;
++ int i;
++
++ for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
++ if (priv->wep_keys[i].size != 0) {
++ acxlog(L_INIT, "setting WEP key: %d with "
++ "total size: %d\n", i, (int) priv->wep_keys[i].size);
++ dk.action = 1;
++ dk.keySize = priv->wep_keys[i].size;
++ dk.defaultKeyNum = i;
++ memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
++ acx_s_configure(priv, &dk, ACX100_IE_DOT11_WEP_DEFAULT_KEY_WRITE);
++ }
++ }
++}
++
++static void
++acx111_s_set_wepkey(wlandevice_t *priv)
++{
++ acx111WEPDefaultKey_t dk;
++ int i;
++
++ for (i = 0; i < DOT11_MAX_DEFAULT_WEP_KEYS; i++) {
++ if (priv->wep_keys[i].size != 0) {
++ acxlog(L_INIT, "setting WEP key: %d with "
++ "total size: %d\n", i, (int) priv->wep_keys[i].size);
++ memset(&dk, 0, sizeof(dk));
++ dk.action = cpu_to_le16(1); /* "add key"; yes, that's a 16bit value */
++ dk.keySize = priv->wep_keys[i].size;
++
++ /* are these two lines necessary? */
++ dk.type = 0; /* default WEP key */
++ dk.index = 0; /* ignored when setting default key */
++
++ dk.defaultKeyNum = i;
++ memcpy(dk.key, priv->wep_keys[i].key, dk.keySize);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &dk, sizeof(dk));
++ }
++ }
++}
++
++static void
++acx_s_set_wepkey(wlandevice_t *priv)
++{
++ if (IS_ACX111(priv))
++ acx111_s_set_wepkey(priv);
++ else
++ acx100_s_set_wepkey(priv);
++}
++
++
++/***********************************************************************
++** acx100_s_init_wep
++**
++** FIXME: this should probably be moved into the new card settings
++** management, but since we're also modifying the memory map layout here
++** due to the WEP key space we want, we should take care...
++*/
++int
++acx100_s_init_wep(wlandevice_t *priv)
++{
++/* int i;
++ acx100_cmd_wep_mgmt_t wep_mgmt; size = 37 bytes */
++ acx100_ie_wep_options_t options;
++ ie_dot11WEPDefaultKeyID_t dk;
++ acx_ie_memmap_t pt;
++ int res = NOT_OK;
++
++ FN_ENTER;
++
++ if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
++ goto fail;
++ }
++
++ acxlog(L_DEBUG, "CodeEnd:%X\n", pt.CodeEnd);
++
++ pt.WEPCacheStart = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
++ pt.WEPCacheEnd = cpu_to_le32(le32_to_cpu(pt.CodeEnd) + 0x4);
++
++ if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
++ goto fail;
++ }
++
++ /* let's choose maximum setting: 4 default keys, plus 10 other keys: */
++ options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
++ options.WEPOption = 0x00;
++
++ acxlog(L_ASSOC, "%s: writing WEP options\n", __func__);
++ acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
++
++ acx100_s_set_wepkey(priv);
++
++ if (priv->wep_keys[priv->wep_current_index].size != 0) {
++ acxlog(L_ASSOC, "setting active default WEP key number: %d\n",
++ priv->wep_current_index);
++ dk.KeyID = priv->wep_current_index;
++ acx_s_configure(priv, &dk, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET); /* 0x1010 */
++ }
++ /* FIXME!!! wep_key_struct is filled nowhere! But priv
++ * is initialized to 0, and we don't REALLY need those keys either */
++/* for (i = 0; i < 10; i++) {
++ if (priv->wep_key_struct[i].len != 0) {
++ MAC_COPY(wep_mgmt.MacAddr, priv->wep_key_struct[i].addr);
++ wep_mgmt.KeySize = cpu_to_le16(priv->wep_key_struct[i].len);
++ memcpy(&wep_mgmt.Key, priv->wep_key_struct[i].key, le16_to_cpu(wep_mgmt.KeySize));
++ wep_mgmt.Action = cpu_to_le16(1);
++ acxlog(L_ASSOC, "writing WEP key %d (len %d)\n", i, le16_to_cpu(wep_mgmt.KeySize));
++ if (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_WEP_MGMT, &wep_mgmt, sizeof(wep_mgmt))) {
++ priv->wep_key_struct[i].index = i;
++ }
++ }
++ } */
++
++ /* now retrieve the updated WEPCacheEnd pointer... */
++ if (OK != acx_s_interrogate(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
++ printk("%s: ACX1xx_IE_MEMORY_MAP read #2 FAILED\n",
++ priv->netdev->name);
++ goto fail;
++ }
++ /* ...and tell it to start allocating templates at that location */
++ /* (no endianness conversion needed) */
++ pt.PacketTemplateStart = pt.WEPCacheEnd;
++
++ if (OK != acx_s_configure(priv, &pt, ACX1xx_IE_MEMORY_MAP)) {
++ printk("%s: ACX1xx_IE_MEMORY_MAP write #2 FAILED\n",
++ priv->netdev->name);
++ goto fail;
++ }
++ res = OK;
++
++fail:
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_s_init_max_null_data_template(wlandevice_t *priv)
++{
++ struct acx_template_nullframe b;
++ int result;
++
++ FN_ENTER;
++ memset(&b, 0, sizeof(b));
++ b.size = cpu_to_le16(sizeof(b) - 2);
++ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_NULL_DATA, &b, sizeof(b));
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx_s_init_max_beacon_template
++*/
++static int
++acx_s_init_max_beacon_template(wlandevice_t *priv)
++{
++ struct acx_template_beacon b;
++ int result;
++
++ FN_ENTER;
++ memset(&b, 0, sizeof(b));
++ b.size = cpu_to_le16(sizeof(b) - 2);
++ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &b, sizeof(b));
++
++ FN_EXIT1(result);
++ return result;
++}
++
++/***********************************************************************
++** acx_s_init_max_tim_template
++*/
++static int
++acx_s_init_max_tim_template(wlandevice_t *priv)
++{
++ acx_template_tim_t t;
++
++ memset(&t, 0, sizeof(t));
++ t.size = cpu_to_le16(sizeof(t) - 2);
++ return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
++}
++
++
++/***********************************************************************
++** acx_s_init_max_probe_response_template
++*/
++static int
++acx_s_init_max_probe_response_template(wlandevice_t *priv)
++{
++ struct acx_template_proberesp pr;
++
++ memset(&pr, 0, sizeof(pr));
++ pr.size = cpu_to_le16(sizeof(pr) - 2);
++
++ return acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, sizeof(pr));
++}
++
++
++/***********************************************************************
++** acx_s_init_max_probe_request_template
++*/
++static int
++acx_s_init_max_probe_request_template(wlandevice_t *priv)
++{
++ union {
++ acx100_template_probereq_t p100;
++ acx111_template_probereq_t p111;
++ } pr;
++ int res;
++
++ FN_ENTER;
++ memset(&pr, 0, sizeof(pr));
++ pr.p100.size = cpu_to_le16(sizeof(pr) - 2);
++ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &pr, sizeof(pr));
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/***********************************************************************
++** acx_s_set_tim_template
++**
++** In full blown driver we will regularly update partial virtual bitmap
++** by calling this function
++** (it can be done by irq handler on each DTIM irq or by timer...)
++
++[802.11 7.3.2.6] TIM information element:
++- 1 EID
++- 1 Length
++1 1 DTIM Count
++ indicates how many beacons (including this) appear before next DTIM
++ (0=this one is a DTIM)
++2 1 DTIM Period
++ number of beacons between successive DTIMs
++ (0=reserved, 1=all TIMs are DTIMs, 2=every other, etc)
++3 1 Bitmap Control
++ bit0: Traffic Indicator bit associated with Assoc ID 0 (Bcast AID?)
++ set to 1 in TIM elements with a value of 0 in the DTIM Count field
++ when one or more broadcast or multicast frames are buffered at the AP.
++ bit1-7: Bitmap Offset (logically Bitmap_Offset = Bitmap_Control & 0xFE).
++4 n Partial Virtual Bitmap
++ Visible part of traffic-indication bitmap.
++ Full bitmap consists of 2008 bits (251 octets) such that bit number N
++ (0<=N<=2007) in the bitmap corresponds to bit number (N mod 8)
++ in octet number N/8 where the low-order bit of each octet is bit0,
++ and the high order bit is bit7.
++ Each set bit in virtual bitmap corresponds to traffic buffered by AP
++ for a specific station (with corresponding AID?).
++ Partial Virtual Bitmap shows a part of bitmap which has non-zero.
++ Bitmap Offset is a number of skipped zero octets (see above).
++ 'Missing' octets at the tail are also assumed to be zero.
++ Example: Length=6, Bitmap_Offset=2, Partial_Virtual_Bitmap=55 55 55
++ This means that traffic-indication bitmap is:
++ 00000000 00000000 01010101 01010101 01010101 00000000 00000000...
++ (is bit0 in the map is always 0 and real value is in Bitmap Control bit0?)
++*/
++static int
++acx_s_set_tim_template(wlandevice_t *priv)
++{
++/* For now, configure smallish test bitmap, all zero ("no pending data") */
++ enum { bitmap_size = 5 };
++
++ acx_template_tim_t t;
++ int result;
++
++ FN_ENTER;
++
++ memset(&t, 0, sizeof(t));
++ t.size = 5 + bitmap_size; /* eid+len+count+period+bmap_ctrl + bmap */
++ t.tim_eid = WLAN_EID_TIM;
++ t.len = 3 + bitmap_size; /* count+period+bmap_ctrl + bmap */
++ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_TIM, &t, sizeof(t));
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx_fill_beacon_or_proberesp_template
++**
++** For frame format info, please see 802.11-1999.pdf item 7.2.3.9 and below!!
++**
++** NB: we use the fact that
++** struct acx_template_proberesp and struct acx_template_beacon are the same
++** (well, almost...)
++**
++** [802.11] Beacon's body consist of these IEs:
++** 1 Timestamp
++** 2 Beacon interval
++** 3 Capability information
++** 4 SSID
++** 5 Supported rates (up to 8 rates)
++** 6 FH Parameter Set (frequency-hopping PHYs only)
++** 7 DS Parameter Set (direct sequence PHYs only)
++** 8 CF Parameter Set (only if PCF is supported)
++** 9 IBSS Parameter Set (ad-hoc only)
++**
++** Beacon only:
++** 10 TIM (AP only) (see 802.11 7.3.2.6)
++** 11 Country Information (802.11d)
++** 12 FH Parameters (802.11d)
++** 13 FH Pattern Table (802.11d)
++** ... (?!! did not yet find relevant PDF file... --vda)
++** 19 ERP Information (extended rate PHYs)
++** 20 Extended Supported Rates (if more than 8 rates)
++**
++** Proberesp only:
++** 10 Country information (802.11d)
++** 11 FH Parameters (802.11d)
++** 12 FH Pattern Table (802.11d)
++** 13-n Requested information elements (802.11d)
++** ????
++** 18 ERP Information (extended rate PHYs)
++** 19 Extended Supported Rates (if more than 8 rates)
++*/
++static int
++acx_fill_beacon_or_proberesp_template(wlandevice_t *priv,
++ struct acx_template_beacon *templ,
++ u16 fc /* in host order! */)
++{
++ int len;
++ u8 *p;
++
++ FN_ENTER;
++
++ memset(templ, 0, sizeof(*templ));
++ MAC_BCAST(templ->da);
++ MAC_COPY(templ->sa, priv->dev_addr);
++ MAC_COPY(templ->bssid, priv->bssid);
++
++ templ->beacon_interval = cpu_to_le16(priv->beacon_interval);
++ acx_update_capabilities(priv);
++ templ->cap = cpu_to_le16(priv->capabilities);
++
++ p = templ->variable;
++ p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
++ p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
++ p = wlan_fill_ie_ds_parms(p, priv->channel);
++ /* NB: should go AFTER tim, but acx seem to keep tim last always */
++ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
++
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ /* ATIM window */
++ p = wlan_fill_ie_ibss_parms(p, 0); break;
++ case ACX_MODE_3_AP:
++ /* TIM IE is set up as separate template */
++ break;
++ }
++
++ len = p - (u8*)templ;
++ templ->fc = cpu_to_le16(WF_FTYPE_MGMT | fc);
++ /* - 2: do not count 'u16 size' field */
++ templ->size = cpu_to_le16(len - 2);
++
++ FN_EXIT1(len);
++ return len;
++}
++
++
++/***********************************************************************
++** acx_s_set_beacon_template
++*/
++static int
++acx_s_set_beacon_template(wlandevice_t *priv)
++{
++ struct acx_template_beacon bcn;
++ int len, result;
++
++ FN_ENTER;
++
++ len = acx_fill_beacon_or_proberesp_template(priv, &bcn, WF_FSTYPE_BEACON);
++ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_BEACON, &bcn, len);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx_s_set_probe_response_template
++*/
++static int
++acx_s_set_probe_response_template(wlandevice_t *priv)
++{
++ struct acx_template_proberesp pr;
++ int len, result;
++
++ FN_ENTER;
++
++ len = acx_fill_beacon_or_proberesp_template(priv, &pr, WF_FSTYPE_PROBERESP);
++ result = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_RESPONSE, &pr, len);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx100_s_init_packet_templates()
++**
++** NOTE: order is very important here, to have a correct memory layout!
++** init templates: max Probe Request (station mode), max NULL data,
++** max Beacon, max TIM, max Probe Response.
++*/
++int
++acx100_s_init_packet_templates(wlandevice_t *priv)
++{
++ acx_ie_memmap_t mm;
++ int result = NOT_OK;
++
++ FN_ENTER;
++
++ acxlog(L_DEBUG, "sizeof(memmap)=%d bytes\n", (int)sizeof(mm));
++
++ /* acx100 still do not emit probe requests, thus this call
++ ** is sourt of not needed. But we want it to work someday */
++ if (OK != acx_s_init_max_probe_request_template(priv))
++ goto failed;
++
++#ifdef NOT_WORKING_YET
++ /* FIXME: creating the NULL data template breaks
++ * communication right now, needs further testing.
++ * Also, need to set the template once we're joining a network. */
++ if (OK != acx_s_init_max_null_data_template(priv))
++ goto failed;
++#endif
++
++ if (OK != acx_s_init_max_beacon_template(priv))
++ goto failed;
++
++ if (OK != acx_s_init_max_tim_template(priv))
++ goto failed;
++
++ if (OK != acx_s_init_max_probe_response_template(priv))
++ goto failed;
++
++ if (OK != acx_s_set_tim_template(priv))
++ goto failed;
++
++ if (OK != acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
++ goto failed;
++ }
++
++ mm.QueueStart = cpu_to_le32(le32_to_cpu(mm.PacketTemplateEnd) + 4);
++ if (OK != acx_s_configure(priv, &mm, ACX1xx_IE_MEMORY_MAP)) {
++ goto failed;
++ }
++
++ result = OK;
++ goto success;
++
++failed:
++ acxlog(L_DEBUG|L_INIT,
++ /* "cb=0x%X\n" */
++ "pACXMemoryMap:\n"
++ ".CodeStart=0x%X\n"
++ ".CodeEnd=0x%X\n"
++ ".WEPCacheStart=0x%X\n"
++ ".WEPCacheEnd=0x%X\n"
++ ".PacketTemplateStart=0x%X\n"
++ ".PacketTemplateEnd=0x%X\n",
++ /* len, */
++ le32_to_cpu(mm.CodeStart),
++ le32_to_cpu(mm.CodeEnd),
++ le32_to_cpu(mm.WEPCacheStart),
++ le32_to_cpu(mm.WEPCacheEnd),
++ le32_to_cpu(mm.PacketTemplateStart),
++ le32_to_cpu(mm.PacketTemplateEnd));
++
++success:
++ FN_EXIT1(result);
++ return result;
++}
++
++int
++acx111_s_init_packet_templates(wlandevice_t *priv)
++{
++ int result = NOT_OK;
++
++ FN_ENTER;
++
++ acxlog(L_DEBUG|L_INIT, "initializing max packet templates\n");
++
++ if (OK != acx_s_init_max_probe_request_template(priv))
++ goto failed;
++
++ if (OK != acx_s_init_max_null_data_template(priv))
++ goto failed;
++
++ if (OK != acx_s_init_max_beacon_template(priv))
++ goto failed;
++
++ if (OK != acx_s_init_max_tim_template(priv))
++ goto failed;
++
++ if (OK != acx_s_init_max_probe_response_template(priv))
++ goto failed;
++
++ /* the other templates will be set later (acx_start) */
++ /*
++ if (OK != acx_s_set_tim_template(priv))
++ goto failed;*/
++
++ result = OK;
++ goto success;
++
++failed:
++ printk("%s: acx111_init_packet_templates() FAILED\n", priv->netdev->name);
++
++success:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx100_s_set_probe_request_template(wlandevice_t *priv)
++{
++ struct acx100_template_probereq probereq;
++ char *p;
++ int res;
++ int frame_len;
++
++ FN_ENTER;
++
++ memset(&probereq, 0, sizeof(probereq));
++
++ probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
++ MAC_BCAST(probereq.da);
++ MAC_COPY(probereq.sa, priv->dev_addr);
++ MAC_BCAST(probereq.bssid);
++
++ probereq.beacon_interval = cpu_to_le16(priv->beacon_interval);
++ acx_update_capabilities(priv);
++ probereq.cap = cpu_to_le16(priv->capabilities);
++
++ p = probereq.variable;
++ acxlog(L_ASSOC, "SSID='%s' len=%d\n", priv->essid, priv->essid_len);
++ p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
++ p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
++ /* FIXME: should these be here or AFTER ds_parms? */
++ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
++ /* HUH?? who said it must be here? I've found nothing in 802.11! --vda*/
++ /* p = wlan_fill_ie_ds_parms(p, priv->channel); */
++ frame_len = p - (char*)&probereq;
++ probereq.size = frame_len - 2;
++
++ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
++ FN_EXIT0;
++ return res;
++}
++
++static int
++acx111_s_set_probe_request_template(wlandevice_t *priv)
++{
++ struct acx111_template_probereq probereq;
++ char *p;
++ int res;
++ int frame_len;
++
++ FN_ENTER;
++
++ memset(&probereq, 0, sizeof(probereq));
++
++ probereq.fc = WF_FTYPE_MGMTi | WF_FSTYPE_PROBEREQi;
++ MAC_BCAST(probereq.da);
++ MAC_COPY(probereq.sa, priv->dev_addr);
++ MAC_BCAST(probereq.bssid);
++
++ p = probereq.variable;
++ p = wlan_fill_ie_ssid(p, priv->essid_len, priv->essid);
++ p = wlan_fill_ie_rates(p, priv->rate_supported_len, priv->rate_supported);
++ p = wlan_fill_ie_rates_ext(p, priv->rate_supported_len, priv->rate_supported);
++ frame_len = p - (char*)&probereq;
++ probereq.size = frame_len - 2;
++
++ res = acx_s_issue_cmd(priv, ACX1xx_CMD_CONFIG_PROBE_REQUEST, &probereq, frame_len);
++ FN_EXIT0;
++ return res;
++}
++
++static int
++acx_s_set_probe_request_template(wlandevice_t *priv)
++{
++ if (IS_ACX111(priv)) {
++ return acx111_s_set_probe_request_template(priv);
++ } else {
++ return acx100_s_set_probe_request_template(priv);
++ }
++}
++
++
++/***********************************************************************
++** acx_s_update_card_settings
++**
++** Applies accumulated changes in various priv->xxxx members
++** Called by ioctl commit handler, acx_start, acx_set_defaults,
++** acx_s_after_interrupt_task (if IRQ_CMD_UPDATE_CARD_CFG),
++*/
++static void
++acx111_s_sens_radio_16_17(wlandevice_t *priv)
++{
++ u32 feature1, feature2;
++
++ if ((priv->sensitivity < 1) || (priv->sensitivity > 3)) {
++ printk("%s: invalid sensitivity setting (1..3), "
++ "setting to 1\n", priv->netdev->name);
++ priv->sensitivity = 1;
++ }
++ acx111_s_get_feature_config(priv, &feature1, &feature2);
++ CLEAR_BIT(feature1, FEATURE1_LOW_RX|FEATURE1_EXTRA_LOW_RX);
++ if (priv->sensitivity > 1)
++ SET_BIT(feature1, FEATURE1_LOW_RX);
++ if (priv->sensitivity > 2)
++ SET_BIT(feature1, FEATURE1_EXTRA_LOW_RX);
++ acx111_s_feature_set(priv, feature1, feature2);
++}
++
++void
++acx_s_update_card_settings(wlandevice_t *priv, int get_all, int set_all)
++{
++ unsigned long flags;
++ unsigned int start_scan = 0;
++ int i;
++
++ FN_ENTER;
++
++ if (get_all)
++ SET_BIT(priv->get_mask, GETSET_ALL);
++ if (set_all)
++ SET_BIT(priv->set_mask, GETSET_ALL);
++ /* Why not just set masks to 0xffffffff? We can get rid of GETSET_ALL */
++
++ acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X\n",
++ priv->get_mask, priv->set_mask);
++
++ /* Track dependencies betweed various settings */
++
++ if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_WEP)) {
++ acxlog(L_INIT, "important setting has been changed. "
++ "Need to update packet templates, too\n");
++ SET_BIT(priv->set_mask, SET_TEMPLATES);
++ }
++ if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
++ /* This will actually tune RX/TX to the channel */
++ SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX);
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_3_AP:
++ /* Beacons contain channel# - update them */
++ SET_BIT(priv->set_mask, SET_TEMPLATES);
++ }
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ start_scan = 1;
++ }
++ }
++
++ /* Apply settings */
++
++#ifdef WHY_SHOULD_WE_BOTHER /* imagine we were just powered off */
++ /* send a disassoc request in case it's required */
++ if (priv->set_mask & (GETSET_MODE|GETSET_RESCAN|GETSET_CHANNEL|GETSET_WEP|GETSET_ALL)) {
++ if (ACX_MODE_2_STA == priv->mode) {
++ if (ACX_STATUS_4_ASSOCIATED == priv->status) {
++ acxlog(L_ASSOC, "we were ASSOCIATED - "
++ "sending disassoc request\n");
++ acx_lock(priv, flags);
++ acx_l_transmit_disassoc(priv, NULL);
++ /* FIXME: deauth? */
++ acx_unlock(priv, flags);
++ }
++ /* need to reset some other stuff as well */
++ acxlog(L_DEBUG, "resetting bssid\n");
++ MAC_ZERO(priv->bssid);
++ SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST);
++ /* FIXME: should start scanning */
++ start_scan = 1;
++ }
++ }
++#endif
++
++ if (priv->get_mask & (GETSET_STATION_ID|GETSET_ALL)) {
++ u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
++ const u8 *paddr;
++
++ acx_s_interrogate(priv, stationID, ACX1xx_IE_DOT11_STATION_ID);
++ paddr = &stationID[4];
++ for (i = 0; i < ETH_ALEN; i++) {
++ /* we copy the MAC address (reversed in
++ * the card) to the netdevice's MAC
++ * address, and on ifup it will be
++ * copied into iwpriv->dev_addr */
++ priv->netdev->dev_addr[ETH_ALEN - 1 - i] = paddr[i];
++ }
++ CLEAR_BIT(priv->get_mask, GETSET_STATION_ID);
++ }
++
++ if (priv->get_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
++ if ((RADIO_RFMD_11 == priv->radio_type)
++ || (RADIO_MAXIM_0D == priv->radio_type)
++ || (RADIO_RALINK_15 == priv->radio_type)) {
++ acx_s_read_phy_reg(priv, 0x30, &priv->sensitivity);
++ } else {
++ acxlog(L_INIT, "don't know how to get sensitivity "
++ "for radio type 0x%02X\n", priv->radio_type);
++ priv->sensitivity = 0;
++ }
++ acxlog(L_INIT, "got sensitivity value %u\n", priv->sensitivity);
++
++ CLEAR_BIT(priv->get_mask, GETSET_SENSITIVITY);
++ }
++
++ if (priv->get_mask & (GETSET_ANTENNA|GETSET_ALL)) {
++ u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
++
++ memset(antenna, 0, sizeof(antenna));
++ acx_s_interrogate(priv, antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
++ priv->antenna = antenna[4];
++ acxlog(L_INIT, "got antenna value 0x%02X\n", priv->antenna);
++ CLEAR_BIT(priv->get_mask, GETSET_ANTENNA);
++ }
++
++ if (priv->get_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
++ if (IS_ACX100(priv)) {
++ u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
++
++ memset(ed_threshold, 0, sizeof(ed_threshold));
++ acx_s_interrogate(priv, ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
++ priv->ed_threshold = ed_threshold[4];
++ } else {
++ acxlog(L_INIT, "acx111 doesn't support ED\n");
++ priv->ed_threshold = 0;
++ }
++ acxlog(L_INIT, "got Energy Detect (ED) threshold %u\n", priv->ed_threshold);
++ CLEAR_BIT(priv->get_mask, GETSET_ED_THRESH);
++ }
++
++ if (priv->get_mask & (GETSET_CCA|GETSET_ALL)) {
++ if (IS_ACX100(priv)) {
++ u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
++
++ memset(cca, 0, sizeof(priv->cca));
++ acx_s_interrogate(priv, cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
++ priv->cca = cca[4];
++ } else {
++ acxlog(L_INIT, "acx111 doesn't support CCA\n");
++ priv->cca = 0;
++ }
++ acxlog(L_INIT, "got Channel Clear Assessment (CCA) value %u\n", priv->cca);
++ CLEAR_BIT(priv->get_mask, GETSET_CCA);
++ }
++
++ if (priv->get_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
++ acx_ie_generic_t dom;
++
++ acx_s_interrogate(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
++ priv->reg_dom_id = dom.m.bytes[0];
++ /* FIXME: should also set chanmask somehow */
++ acxlog(L_INIT, "got regulatory domain 0x%02X\n", priv->reg_dom_id);
++ CLEAR_BIT(priv->get_mask, GETSET_REG_DOMAIN);
++ }
++
++ if (priv->set_mask & (GETSET_STATION_ID|GETSET_ALL)) {
++ u8 stationID[4 + ACX1xx_IE_DOT11_STATION_ID_LEN];
++ u8 *paddr;
++
++ paddr = &stationID[4];
++ for (i = 0; i < ETH_ALEN; i++) {
++ /* copy the MAC address we obtained when we noticed
++ * that the ethernet iface's MAC changed
++ * to the card (reversed in
++ * the card!) */
++ paddr[i] = priv->dev_addr[ETH_ALEN - 1 - i];
++ }
++ acx_s_configure(priv, &stationID, ACX1xx_IE_DOT11_STATION_ID);
++ CLEAR_BIT(priv->set_mask, GETSET_STATION_ID);
++ }
++
++ if (priv->set_mask & (SET_TEMPLATES|GETSET_ALL)) {
++ acxlog(L_INIT, "updating packet templates\n");
++ /* Doesn't work for acx100, do it only for acx111 for now */
++ if (IS_ACX111(priv)) {
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ acx_s_set_probe_request_template(priv);
++ }
++ }
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_3_AP:
++ /* FIXME: why only for AP? STA need probe req templates... */
++ acx_s_set_beacon_template(priv);
++ acx_s_set_tim_template(priv);
++ /* BTW acx111 firmware would not send probe responses
++ ** if probe request does not have all basic rates flagged
++ ** by 0x80! Thus firmware does not conform to 802.11,
++ ** it should ignore 0x80 bit in ratevector from STA.
++ ** We can 'fix' it by not using this template and
++ ** sending probe responses by hand. TODO --vda */
++ acx_s_set_probe_response_template(priv);
++ }
++ /* Needed if generated frames are to be emitted at different tx rate now */
++ acxlog(L_IRQ, "redoing cmd_join_bssid() after template cfg\n");
++ acx_s_cmd_join_bssid(priv, priv->bssid);
++ CLEAR_BIT(priv->set_mask, SET_TEMPLATES);
++ }
++ if (priv->set_mask & (SET_STA_LIST|GETSET_ALL)) {
++ acx_lock(priv, flags);
++ acx_l_sta_list_init(priv);
++ CLEAR_BIT(priv->set_mask, SET_STA_LIST);
++ acx_unlock(priv, flags);
++ }
++ if (priv->set_mask & (SET_RATE_FALLBACK|GETSET_ALL)) {
++ u8 rate[4 + ACX1xx_IE_RATE_FALLBACK_LEN];
++
++ /* configure to not do fallbacks when not in auto rate mode */
++ rate[4] = (priv->rate_auto) ? /* priv->txrate_fallback_retries */ 1 : 0;
++ acxlog(L_INIT, "updating Tx fallback to %u retries\n", rate[4]);
++ acx_s_configure(priv, &rate, ACX1xx_IE_RATE_FALLBACK);
++ CLEAR_BIT(priv->set_mask, SET_RATE_FALLBACK);
++ }
++ if (priv->set_mask & (GETSET_TXPOWER|GETSET_ALL)) {
++ acxlog(L_INIT, "updating transmit power: %u dBm\n",
++ priv->tx_level_dbm);
++ acx_s_set_tx_level(priv, priv->tx_level_dbm);
++ CLEAR_BIT(priv->set_mask, GETSET_TXPOWER);
++ }
++
++ if (priv->set_mask & (GETSET_SENSITIVITY|GETSET_ALL)) {
++ acxlog(L_INIT, "updating sensitivity value: %u\n",
++ priv->sensitivity);
++ switch (priv->radio_type) {
++ case RADIO_RFMD_11:
++ case RADIO_MAXIM_0D:
++ case RADIO_RALINK_15:
++ acx_s_write_phy_reg(priv, 0x30, priv->sensitivity);
++ break;
++ case RADIO_RADIA_16:
++ case RADIO_UNKNOWN_17:
++ acx111_s_sens_radio_16_17(priv);
++ break;
++ default:
++ acxlog(L_INIT, "don't know how to modify sensitivity "
++ "for radio type 0x%02X\n", priv->radio_type);
++ }
++ CLEAR_BIT(priv->set_mask, GETSET_SENSITIVITY);
++ }
++
++ if (priv->set_mask & (GETSET_ANTENNA|GETSET_ALL)) {
++ /* antenna */
++ u8 antenna[4 + ACX1xx_IE_DOT11_CURRENT_ANTENNA_LEN];
++
++ memset(antenna, 0, sizeof(antenna));
++ antenna[4] = priv->antenna;
++ acxlog(L_INIT, "updating antenna value: 0x%02X\n",
++ priv->antenna);
++ acx_s_configure(priv, &antenna, ACX1xx_IE_DOT11_CURRENT_ANTENNA);
++ CLEAR_BIT(priv->set_mask, GETSET_ANTENNA);
++ }
++
++ if (priv->set_mask & (GETSET_ED_THRESH|GETSET_ALL)) {
++ /* ed_threshold */
++ acxlog(L_INIT, "updating Energy Detect (ED) threshold: %u\n",
++ priv->ed_threshold);
++ if (IS_ACX100(priv)) {
++ u8 ed_threshold[4 + ACX100_IE_DOT11_ED_THRESHOLD_LEN];
++
++ memset(ed_threshold, 0, sizeof(ed_threshold));
++ ed_threshold[4] = priv->ed_threshold;
++ acx_s_configure(priv, &ed_threshold, ACX100_IE_DOT11_ED_THRESHOLD);
++ }
++ else
++ acxlog(L_INIT, "acx111 doesn't support ED!\n");
++ CLEAR_BIT(priv->set_mask, GETSET_ED_THRESH);
++ }
++
++ if (priv->set_mask & (GETSET_CCA|GETSET_ALL)) {
++ /* CCA value */
++ acxlog(L_INIT, "updating Channel Clear Assessment "
++ "(CCA) value: 0x%02X\n", priv->cca);
++ if (IS_ACX100(priv)) {
++ u8 cca[4 + ACX1xx_IE_DOT11_CURRENT_CCA_MODE_LEN];
++
++ memset(cca, 0, sizeof(cca));
++ cca[4] = priv->cca;
++ acx_s_configure(priv, &cca, ACX1xx_IE_DOT11_CURRENT_CCA_MODE);
++ }
++ else
++ acxlog(L_INIT, "acx111 doesn't support CCA!\n");
++ CLEAR_BIT(priv->set_mask, GETSET_CCA);
++ }
++
++ if (priv->set_mask & (GETSET_LED_POWER|GETSET_ALL)) {
++ /* Enable Tx */
++ acxlog(L_INIT, "updating power LED status: %u\n", priv->led_power);
++
++ acx_lock(priv, flags);
++ if (IS_PCI(priv))
++ acx_l_power_led(priv, priv->led_power);
++ CLEAR_BIT(priv->set_mask, GETSET_LED_POWER);
++ acx_unlock(priv, flags);
++ }
++
++/* this seems to cause Tx lockup after some random time (Tx error 0x20),
++ * so let's disable it for now until further investigation */
++/* Maybe fixed now after locking is fixed. Need to retest */
++#ifdef POWER_SAVE_80211
++ if (priv->set_mask & (GETSET_POWER_80211|GETSET_ALL)) {
++ acx100_ie_powermgmt_t pm;
++
++ /* change 802.11 power save mode settings */
++ acxlog(L_INIT, "updating 802.11 power save mode settings: "
++ "wakeup_cfg 0x%02X, listen interval %u, "
++ "options 0x%02X, hangover period %u, "
++ "enhanced_ps_transition_time %d\n",
++ priv->ps_wakeup_cfg, priv->ps_listen_interval,
++ priv->ps_options, priv->ps_hangover_period,
++ priv->ps_enhanced_transition_time);
++ acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
++ acxlog(L_INIT, "Previous PS mode settings: wakeup_cfg 0x%02X, "
++ "listen interval %u, options 0x%02X, "
++ "hangover period %u, "
++ "enhanced_ps_transition_time %d\n",
++ pm.wakeup_cfg, pm.listen_interval, pm.options,
++ pm.hangover_period, pm.enhanced_ps_transition_time);
++ pm.wakeup_cfg = priv->ps_wakeup_cfg;
++ pm.listen_interval = priv->ps_listen_interval;
++ pm.options = priv->ps_options;
++ pm.hangover_period = priv->ps_hangover_period;
++ pm.enhanced_ps_transition_time = cpu_to_le16(priv->ps_enhanced_transition_time);
++ acx_s_configure(priv, &pm, ACX100_IE_POWER_MGMT);
++ acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
++ acxlog(L_INIT, "wakeup_cfg: 0x%02X\n", pm.wakeup_cfg);
++ acx_s_msleep(40);
++ acx_s_interrogate(priv, &pm, ACX100_IE_POWER_MGMT);
++ acxlog(L_INIT, "power save mode change %s\n",
++ (pm.wakeup_cfg & PS_CFG_PENDING) ? "FAILED" : "was successful");
++ /* FIXME: maybe verify via PS_CFG_PENDING bit here
++ * that power save mode change was successful. */
++ /* FIXME: we shouldn't trigger a scan immediately after
++ * fiddling with power save mode (since the firmware is sending
++ * a NULL frame then). Does this need locking?? */
++ CLEAR_BIT(priv->set_mask, GETSET_POWER_80211);
++ }
++#endif
++
++ if (priv->set_mask & (GETSET_CHANNEL|GETSET_ALL)) {
++ /* channel */
++ acxlog(L_INIT, "updating channel to: %u\n", priv->channel);
++ CLEAR_BIT(priv->set_mask, GETSET_CHANNEL);
++ }
++
++ if (priv->set_mask & (GETSET_TX|GETSET_ALL)) {
++ /* set Tx */
++ acxlog(L_INIT, "updating: %s Tx\n",
++ priv->tx_disabled ? "disable" : "enable");
++ if (priv->tx_disabled)
++ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
++ /* ^ */
++ /* FIXME: this used to be 1, but since we don't transfer a parameter... */
++ else
++ acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1);
++ CLEAR_BIT(priv->set_mask, GETSET_TX);
++ }
++
++ if (priv->set_mask & (GETSET_RX|GETSET_ALL)) {
++ /* Enable Rx */
++ acxlog(L_INIT, "updating: enable Rx on channel: %u\n",
++ priv->channel);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1);
++ CLEAR_BIT(priv->set_mask, GETSET_RX);
++ }
++
++ if (priv->set_mask & (GETSET_RETRY|GETSET_ALL)) {
++ u8 short_retry[4 + ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT_LEN];
++ u8 long_retry[4 + ACX1xx_IE_DOT11_LONG_RETRY_LIMIT_LEN];
++
++ acxlog(L_INIT, "updating short retry limit: %u, long retry limit: %u\n",
++ priv->short_retry, priv->long_retry);
++ short_retry[0x4] = priv->short_retry;
++ long_retry[0x4] = priv->long_retry;
++ acx_s_configure(priv, &short_retry, ACX1xx_IE_DOT11_SHORT_RETRY_LIMIT);
++ acx_s_configure(priv, &long_retry, ACX1xx_IE_DOT11_LONG_RETRY_LIMIT);
++ CLEAR_BIT(priv->set_mask, GETSET_RETRY);
++ }
++
++ if (priv->set_mask & (SET_MSDU_LIFETIME|GETSET_ALL)) {
++ u8 xmt_msdu_lifetime[4 + ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME_LEN];
++
++ acxlog(L_INIT, "updating tx MSDU lifetime: %u\n",
++ priv->msdu_lifetime);
++ *(u32 *)&xmt_msdu_lifetime[4] = cpu_to_le32((u32)priv->msdu_lifetime);
++ acx_s_configure(priv, &xmt_msdu_lifetime, ACX1xx_IE_DOT11_MAX_XMIT_MSDU_LIFETIME);
++ CLEAR_BIT(priv->set_mask, SET_MSDU_LIFETIME);
++ }
++
++ if (priv->set_mask & (GETSET_REG_DOMAIN|GETSET_ALL)) {
++ /* reg_domain */
++ acx_ie_generic_t dom;
++ unsigned mask;
++
++ acxlog(L_INIT, "updating regulatory domain: 0x%02X\n",
++ priv->reg_dom_id);
++ for (i = 0; i < sizeof(reg_domain_ids); i++)
++ if (reg_domain_ids[i] == priv->reg_dom_id)
++ break;
++
++ if (sizeof(reg_domain_ids) == i) {
++ acxlog(L_INIT, "Invalid or unsupported regulatory "
++ "domain 0x%02X specified, falling back to "
++ "FCC (USA)! Please report if this sounds "
++ "fishy!\n", priv->reg_dom_id);
++ i = 0;
++ priv->reg_dom_id = reg_domain_ids[i];
++ }
++
++ priv->reg_dom_chanmask = reg_domain_channel_masks[i];
++ dom.m.bytes[0] = priv->reg_dom_id;
++ acx_s_configure(priv, &dom, ACX1xx_IE_DOT11_CURRENT_REG_DOMAIN);
++
++ mask = (1 << (priv->channel - 1));
++ if (!(priv->reg_dom_chanmask & mask)) {
++ /* hmm, need to adjust our channel to reside within domain */
++ mask = 1;
++ for (i = 1; i <= 14; i++) {
++ if (priv->reg_dom_chanmask & mask) {
++ printk("%s: adjusting "
++ "selected channel from %d "
++ "to %d due to new regulatory "
++ "domain\n", priv->netdev->name,
++ priv->channel, i);
++ priv->channel = i;
++ break;
++ }
++ mask <<= 1;
++ }
++ }
++ CLEAR_BIT(priv->set_mask, GETSET_REG_DOMAIN);
++ }
++
++ if (priv->set_mask & (GETSET_MODE|GETSET_ALL)) {
++ priv->netdev->type = ARPHRD_ETHER;
++
++ switch (priv->mode) {
++ case ACX_MODE_3_AP:
++
++ acx_lock(priv, flags);
++ acx_l_sta_list_init(priv);
++ priv->aid = 0;
++ priv->ap_client = NULL;
++ MAC_COPY(priv->bssid, priv->dev_addr);
++ /* this basically says "we're connected" */
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
++ acx_unlock(priv, flags);
++
++ acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
++ /* start sending beacons */
++ acx_s_cmd_join_bssid(priv, priv->bssid);
++ break;
++ case ACX_MODE_MONITOR:
++ /* priv->netdev->type = ARPHRD_ETHER; */
++ /* priv->netdev->type = ARPHRD_IEEE80211; */
++ priv->netdev->type = ARPHRD_IEEE80211_PRISM;
++ acx111_s_feature_on(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
++ /* this stops beacons */
++ acx_s_cmd_join_bssid(priv, priv->bssid);
++ /* this basically says "we're connected" */
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
++ SET_BIT(priv->set_mask, SET_RXCONFIG|SET_WEP_OPTIONS);
++ break;
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ acx111_s_feature_off(priv, 0, FEATURE2_NO_TXCRYPT|FEATURE2_SNIFFER);
++ priv->aid = 0;
++ priv->ap_client = NULL;
++ /* we want to start looking for peer or AP */
++ start_scan = 1;
++ break;
++ case ACX_MODE_OFF:
++ /* TODO: disable RX/TX, stop any scanning activity etc: */
++ /* priv->tx_disabled = 1; */
++ /* SET_BIT(priv->set_mask, GETSET_RX|GETSET_TX); */
++
++ /* This stops beacons (invalid macmode...) */
++ acx_s_cmd_join_bssid(priv, priv->bssid);
++ acx_set_status(priv, ACX_STATUS_0_STOPPED);
++ break;
++ }
++ CLEAR_BIT(priv->set_mask, GETSET_MODE);
++ }
++
++ if (priv->set_mask & (SET_RXCONFIG|GETSET_ALL)) {
++ acx_s_initialize_rx_config(priv);
++ CLEAR_BIT(priv->set_mask, SET_RXCONFIG);
++ }
++
++ if (priv->set_mask & (GETSET_RESCAN|GETSET_ALL)) {
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ start_scan = 1;
++ break;
++ }
++ CLEAR_BIT(priv->set_mask, GETSET_RESCAN);
++ }
++
++ if (priv->set_mask & (GETSET_WEP|GETSET_ALL)) {
++ /* encode */
++
++ ie_dot11WEPDefaultKeyID_t dkey;
++#ifdef DEBUG_WEP
++ struct {
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u8 val ACX_PACKED;
++ } keyindic;
++#endif
++ acxlog(L_INIT, "updating WEP key settings\n");
++
++ acx_s_set_wepkey(priv);
++
++ dkey.KeyID = priv->wep_current_index;
++ acxlog(L_INIT, "setting WEP key %u as default\n", dkey.KeyID);
++ acx_s_configure(priv, &dkey, ACX1xx_IE_DOT11_WEP_DEFAULT_KEY_SET);
++#ifdef DEBUG_WEP
++ keyindic.val = 3;
++ acx_s_configure(priv, &keyindic, ACX111_IE_KEY_CHOOSE);
++#endif
++ start_scan = 1;
++ CLEAR_BIT(priv->set_mask, GETSET_WEP);
++ }
++
++ if (priv->set_mask & (SET_WEP_OPTIONS|GETSET_ALL)) {
++ acx100_ie_wep_options_t options;
++
++ if (IS_ACX111(priv)) {
++ acxlog(L_DEBUG, "setting WEP Options for acx111 is not supported\n");
++ } else {
++ acxlog(L_INIT, "setting WEP Options\n");
++
++ /* let's choose maximum setting: 4 default keys,
++ * plus 10 other keys: */
++ options.NumKeys = cpu_to_le16(DOT11_MAX_DEFAULT_WEP_KEYS + 10);
++ /* don't decrypt default key only,
++ * don't override decryption: */
++ options.WEPOption = 0;
++ if (priv->mode == ACX_MODE_MONITOR) {
++ /* don't decrypt default key only,
++ * override decryption mechanism: */
++ options.WEPOption = 2;
++ }
++
++ acx_s_configure(priv, &options, ACX100_IE_WEP_OPTIONS);
++ }
++ CLEAR_BIT(priv->set_mask, SET_WEP_OPTIONS);
++ }
++
++ /* Rescan was requested */
++ if (start_scan) {
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ /* We can avoid clearing list if join code
++ ** will be a bit more clever about not picking
++ ** 'bad' AP over and over again */
++ acx_lock(priv, flags);
++ priv->ap_client = NULL;
++ acx_l_sta_list_init(priv);
++ acx_set_status(priv, ACX_STATUS_1_SCANNING);
++ acx_unlock(priv, flags);
++
++ acx_s_cmd_start_scan(priv);
++ }
++ }
++
++ /* debug, rate, and nick don't need any handling */
++ /* what about sniffing mode?? */
++
++ acxlog(L_INIT, "get_mask 0x%08X, set_mask 0x%08X - after update\n",
++ priv->get_mask, priv->set_mask);
++
++/* end: */
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++*/
++void
++acx_s_initialize_rx_config(wlandevice_t *priv)
++{
++ struct {
++ u16 id ACX_PACKED;
++ u16 len ACX_PACKED;
++ u16 rx_cfg1 ACX_PACKED;
++ u16 rx_cfg2 ACX_PACKED;
++ } cfg;
++
++ switch (priv->mode) {
++ case ACX_MODE_OFF:
++ priv->rx_config_1 = (u16) (0
++ /* | RX_CFG1_INCLUDE_RXBUF_HDR */
++ /* | RX_CFG1_FILTER_SSID */
++ /* | RX_CFG1_FILTER_BCAST */
++ /* | RX_CFG1_RCV_MC_ADDR1 */
++ /* | RX_CFG1_RCV_MC_ADDR0 */
++ /* | RX_CFG1_FILTER_ALL_MULTI */
++ /* | RX_CFG1_FILTER_BSSID */
++ /* | RX_CFG1_FILTER_MAC */
++ /* | RX_CFG1_RCV_PROMISCUOUS */
++ /* | RX_CFG1_INCLUDE_FCS */
++ /* | RX_CFG1_INCLUDE_PHY_HDR */
++ );
++ priv->rx_config_2 = (u16) (0
++ /*| RX_CFG2_RCV_ASSOC_REQ */
++ /*| RX_CFG2_RCV_AUTH_FRAMES */
++ /*| RX_CFG2_RCV_BEACON_FRAMES */
++ /*| RX_CFG2_RCV_CONTENTION_FREE */
++ /*| RX_CFG2_RCV_CTRL_FRAMES */
++ /*| RX_CFG2_RCV_DATA_FRAMES */
++ /*| RX_CFG2_RCV_BROKEN_FRAMES */
++ /*| RX_CFG2_RCV_MGMT_FRAMES */
++ /*| RX_CFG2_RCV_PROBE_REQ */
++ /*| RX_CFG2_RCV_PROBE_RESP */
++ /*| RX_CFG2_RCV_ACK_FRAMES */
++ /*| RX_CFG2_RCV_OTHER */
++ );
++ break;
++ case ACX_MODE_MONITOR:
++ priv->rx_config_1 = (u16) (0
++ /* | RX_CFG1_INCLUDE_RXBUF_HDR */
++ /* | RX_CFG1_FILTER_SSID */
++ /* | RX_CFG1_FILTER_BCAST */
++ /* | RX_CFG1_RCV_MC_ADDR1 */
++ /* | RX_CFG1_RCV_MC_ADDR0 */
++ /* | RX_CFG1_FILTER_ALL_MULTI */
++ /* | RX_CFG1_FILTER_BSSID */
++ /* | RX_CFG1_FILTER_MAC */
++ | RX_CFG1_RCV_PROMISCUOUS
++ /* | RX_CFG1_INCLUDE_FCS */
++ /* | RX_CFG1_INCLUDE_PHY_HDR */
++ );
++ priv->rx_config_2 = (u16) (0
++ | RX_CFG2_RCV_ASSOC_REQ
++ | RX_CFG2_RCV_AUTH_FRAMES
++ | RX_CFG2_RCV_BEACON_FRAMES
++ | RX_CFG2_RCV_CONTENTION_FREE
++ | RX_CFG2_RCV_CTRL_FRAMES
++ | RX_CFG2_RCV_DATA_FRAMES
++ | RX_CFG2_RCV_BROKEN_FRAMES
++ | RX_CFG2_RCV_MGMT_FRAMES
++ | RX_CFG2_RCV_PROBE_REQ
++ | RX_CFG2_RCV_PROBE_RESP
++ | RX_CFG2_RCV_ACK_FRAMES
++ | RX_CFG2_RCV_OTHER
++ );
++ break;
++ default:
++ priv->rx_config_1 = (u16) (0
++ /* | RX_CFG1_INCLUDE_RXBUF_HDR */
++ /* | RX_CFG1_FILTER_SSID */
++ /* | RX_CFG1_FILTER_BCAST */
++ /* | RX_CFG1_RCV_MC_ADDR1 */
++ /* | RX_CFG1_RCV_MC_ADDR0 */
++ /* | RX_CFG1_FILTER_ALL_MULTI */
++ /* | RX_CFG1_FILTER_BSSID */
++ | RX_CFG1_FILTER_MAC
++ /* | RX_CFG1_RCV_PROMISCUOUS */
++ /* | RX_CFG1_INCLUDE_FCS */
++ /* | RX_CFG1_INCLUDE_PHY_HDR */
++ );
++ priv->rx_config_2 = (u16) (0
++ | RX_CFG2_RCV_ASSOC_REQ
++ | RX_CFG2_RCV_AUTH_FRAMES
++ | RX_CFG2_RCV_BEACON_FRAMES
++ | RX_CFG2_RCV_CONTENTION_FREE
++ | RX_CFG2_RCV_CTRL_FRAMES
++ | RX_CFG2_RCV_DATA_FRAMES
++ /*| RX_CFG2_RCV_BROKEN_FRAMES */
++ | RX_CFG2_RCV_MGMT_FRAMES
++ | RX_CFG2_RCV_PROBE_REQ
++ | RX_CFG2_RCV_PROBE_RESP
++ /*| RX_CFG2_RCV_ACK_FRAMES */
++ | RX_CFG2_RCV_OTHER
++ );
++ break;
++ }
++#ifdef DEBUG_WEP
++ if (IS_ACX100(priv))
++ /* only ACX100 supports that */
++#endif
++ priv->rx_config_1 |= RX_CFG1_INCLUDE_RXBUF_HDR;
++
++ acxlog(L_INIT, "setting RXconfig to %04X:%04X\n",
++ priv->rx_config_1, priv->rx_config_2);
++ cfg.rx_cfg1 = cpu_to_le16(priv->rx_config_1);
++ cfg.rx_cfg2 = cpu_to_le16(priv->rx_config_2);
++ acx_s_configure(priv, &cfg, ACX1xx_IE_RXCONFIG);
++}
++
++
++/***********************************************************************
++** acx_e_after_interrupt_task
++*/
++static int
++acx_s_recalib_radio(wlandevice_t *priv)
++{
++ if (IS_ACX111(priv)) {
++ acx111_cmd_radiocalib_t cal;
++
++ printk("%s: recalibrating radio\n", priv->netdev->name);
++ /* automatic recalibration, choose all methods: */
++ cal.methods = cpu_to_le32(0x8000000f);
++ /* automatic recalibration every 60 seconds (value in TUs)
++ * FIXME: what is the firmware default here?? */
++ cal.interval = cpu_to_le32(58594);
++ return acx_s_issue_cmd_timeo(priv, ACX111_CMD_RADIOCALIB,
++ &cal, sizeof(cal), CMD_TIMEOUT_MS(100));
++ } else {
++ if (/* (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0)) &&
++ (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0)) && */
++ (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_TX, &(priv->channel), 1)) &&
++ (OK == acx_s_issue_cmd(priv, ACX1xx_CMD_ENABLE_RX, &(priv->channel), 1)) )
++ return OK;
++ return NOT_OK;
++ }
++}
++
++static void
++acx_s_after_interrupt_recalib(wlandevice_t *priv)
++{
++ int res;
++
++ /* this helps with ACX100 at least;
++ * hopefully ACX111 also does a
++ * recalibration here */
++
++ /* clear flag beforehand, since we want to make sure
++ * it's cleared; then only set it again on specific circumstances */
++ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
++
++ /* better wait a bit between recalibrations to
++ * prevent overheating due to torturing the card
++ * into working too long despite high temperature
++ * (just a safety measure) */
++ if (priv->recalib_time_last_success
++ && time_before(jiffies, priv->recalib_time_last_success
++ + RECALIB_PAUSE * 60 * HZ)) {
++ priv->recalib_msg_ratelimit++;
++ if (priv->recalib_msg_ratelimit <= 5)
++ printk("%s: less than " STRING(RECALIB_PAUSE)
++ " minutes since last radio recalibration, "
++ "not recalibrating (maybe card is too hot?)\n",
++ priv->netdev->name);
++ if (priv->recalib_msg_ratelimit == 5)
++ printk("disabling above message\n");
++ return;
++ }
++
++ priv->recalib_msg_ratelimit = 0;
++
++ /* note that commands sometimes fail (card busy),
++ * so only clear flag if we were fully successful */
++ res = acx_s_recalib_radio(priv);
++ if (res == OK) {
++ printk("%s: successfully recalibrated radio\n",
++ priv->netdev->name);
++ priv->recalib_time_last_success = jiffies;
++ priv->recalib_failure_count = 0;
++ } else {
++ /* failed: resubmit, but only limited
++ * amount of times within some time range
++ * to prevent endless loop */
++
++ priv->recalib_time_last_success = 0; /* we failed */
++
++ /* if some time passed between last
++ * attempts, then reset failure retry counter
++ * to be able to do next recalib attempt */
++ if (time_after(jiffies, priv->recalib_time_last_attempt + HZ))
++ priv->recalib_failure_count = 0;
++
++ if (++priv->recalib_failure_count <= 5) {
++ priv->recalib_time_last_attempt = jiffies;
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
++ }
++ }
++}
++
++static void
++acx_e_after_interrupt_task(void *data)
++{
++ netdevice_t *dev = (netdevice_t *) data;
++ wlandevice_t *priv = netdev_priv(dev);
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ if (!priv->after_interrupt_jobs)
++ goto end; /* no jobs to do */
++
++#if TX_CLEANUP_IN_SOFTIRQ
++ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_TX_CLEANUP) {
++ acx_lock(priv, flags);
++ acx_l_clean_tx_desc(priv);
++ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_TX_CLEANUP);
++ acx_unlock(priv, flags);
++ }
++#endif
++ /* we see lotsa tx errors */
++ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_RADIO_RECALIB) {
++ acx_s_after_interrupt_recalib(priv);
++ }
++
++ /* a poor interrupt code wanted to do update_card_settings() */
++ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_UPDATE_CARD_CFG) {
++ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
++ acx_s_update_card_settings(priv, 0, 0);
++ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
++ }
++
++ /* 1) we detected that no Scan_Complete IRQ came from fw, or
++ ** 2) we found too many STAs */
++ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_STOP_SCAN) {
++ acxlog(L_IRQ, "sending a stop scan cmd...\n");
++ acx_s_issue_cmd(priv, ACX1xx_CMD_STOP_SCAN, NULL, 0);
++ /* HACK: set the IRQ bit, since we won't get a
++ * scan complete IRQ any more on ACX111 (works on ACX100!),
++ * since _we_, not a fw, have stopped the scan */
++ SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
++ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_STOP_SCAN);
++ }
++
++ /* either fw sent Scan_Complete or we detected that
++ ** no Scan_Complete IRQ came from fw. Finish scanning,
++ ** pick join partner if any */
++ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_COMPLETE_SCAN) {
++ if (priv->status == ACX_STATUS_1_SCANNING) {
++ if (OK != acx_s_complete_scan(priv)) {
++ SET_BIT(priv->after_interrupt_jobs,
++ ACX_AFTER_IRQ_RESTART_SCAN);
++ }
++ } else {
++ /* + scan kills current join status - restore it
++ ** (do we need it for STA?) */
++ /* + does it happen only with active scans?
++ ** active and passive scans? ALL scans including
++ ** background one? */
++ /* + was not verified that everything is restored
++ ** (but at least we start to emit beacons again) */
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_3_AP:
++ acxlog(L_IRQ, "redoing cmd_join_bssid() after scan\n");
++ acx_s_cmd_join_bssid(priv, priv->bssid);
++ }
++ }
++ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_COMPLETE_SCAN);
++ }
++
++ /* STA auth or assoc timed out, start over again */
++ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_RESTART_SCAN) {
++ acxlog(L_IRQ, "sending a start_scan cmd...\n");
++ acx_s_cmd_start_scan(priv);
++ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_RESTART_SCAN);
++ }
++
++ /* whee, we got positive assoc response! 8) */
++ if (priv->after_interrupt_jobs & ACX_AFTER_IRQ_CMD_ASSOCIATE) {
++ acx_ie_generic_t pdr;
++ /* tiny race window exists, checking that we still a STA */
++ switch (priv->mode) {
++ case ACX_MODE_2_STA:
++ pdr.m.aid = cpu_to_le16(priv->aid);
++ acx_s_configure(priv, &pdr, ACX1xx_IE_ASSOC_ID);
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED);
++ acxlog(L_ASSOC|L_DEBUG, "ASSOCIATED!\n");
++ CLEAR_BIT(priv->after_interrupt_jobs, ACX_AFTER_IRQ_CMD_ASSOCIATE);
++ }
++ }
++end:
++ acx_sem_unlock(priv);
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx_schedule_after_interrupt_task
++**
++** Schedule the call of the after_interrupt method after leaving
++** the interrupt context.
++*/
++void
++acx_schedule_after_interrupt_task(wlandevice_t *priv, unsigned int set_flag)
++{
++ SET_BIT(priv->after_interrupt_jobs, set_flag);
++ SCHEDULE_WORK(&priv->after_interrupt_task);
++}
++
++
++/***********************************************************************
++*/
++void
++acx_init_task_scheduler(wlandevice_t *priv)
++{
++ /* configure task scheduler */
++ INIT_WORK(&priv->after_interrupt_task, acx_e_after_interrupt_task,
++ priv->netdev);
++}
++
++
++/***********************************************************************
++** acx_s_start
++*/
++void
++acx_s_start(wlandevice_t *priv)
++{
++ FN_ENTER;
++
++ /*
++ * Ok, now we do everything that can possibly be done with ioctl
++ * calls to make sure that when it was called before the card
++ * was up we get the changes asked for
++ */
++
++ SET_BIT(priv->set_mask, SET_TEMPLATES|SET_STA_LIST|GETSET_WEP
++ |GETSET_TXPOWER|GETSET_ANTENNA|GETSET_ED_THRESH|GETSET_CCA
++ |GETSET_REG_DOMAIN|GETSET_MODE|GETSET_CHANNEL
++ |GETSET_TX|GETSET_RX);
++
++ acxlog(L_INIT, "updating initial settings on iface activation...\n");
++ acx_s_update_card_settings(priv, 0, 0);
++
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx_update_capabilities
++*/
++void
++acx_update_capabilities(wlandevice_t *priv)
++{
++ u16 cap = 0;
++
++ switch (priv->mode) {
++ case ACX_MODE_3_AP:
++ SET_BIT(cap, WF_MGMT_CAP_ESS); break;
++ case ACX_MODE_0_ADHOC:
++ SET_BIT(cap, WF_MGMT_CAP_IBSS); break;
++ /* other types of stations do not emit beacons */
++ }
++
++ if (priv->wep_restricted) {
++ SET_BIT(cap, WF_MGMT_CAP_PRIVACY);
++ }
++ if (priv->capab_short) {
++ SET_BIT(cap, WF_MGMT_CAP_SHORT);
++ }
++ if (priv->capab_pbcc) {
++ SET_BIT(cap, WF_MGMT_CAP_PBCC);
++ }
++ if (priv->capab_agility) {
++ SET_BIT(cap, WF_MGMT_CAP_AGILITY);
++ }
++ acxlog(L_DEBUG, "caps updated from 0x%04X to 0x%04X\n",
++ priv->capabilities, cap);
++ priv->capabilities = cap;
++}
++
++#ifdef UNUSED
++/***********************************************************************
++** FIXME: check whether this function is indeed acx111 only,
++** rename ALL relevant definitions to indicate actual card scope!
++*/
++void
++acx111_s_read_configoption(wlandevice_t *priv)
++{
++ acx111_ie_configoption_t co, co2;
++ int i;
++ const u8 *pEle;
++
++ if (OK != acx_s_interrogate(priv, &co, ACX111_IE_CONFIG_OPTIONS) ) {
++ return;
++ };
++ if (!(acx_debug & L_DEBUG))
++ return;
++
++ memcpy(&co2.configoption_fixed, &co.configoption_fixed,
++ sizeof(co.configoption_fixed));
++
++ pEle = (u8 *)&co.configoption_fixed + sizeof(co.configoption_fixed) - 4;
++
++ co2.antennas.type = pEle[0];
++ co2.antennas.len = pEle[1];
++ printk("AntennaID:%02X Len:%02X Data:",
++ co2.antennas.type, co2.antennas.len);
++ for (i = 0; i < pEle[1]; i++) {
++ co2.antennas.list[i] = pEle[i+2];
++ printk("%02X ", pEle[i+2]);
++ }
++ printk("\n");
++
++ pEle += pEle[1] + 2;
++ co2.power_levels.type = pEle[0];
++ co2.power_levels.len = pEle[1];
++ printk("PowerLevelID:%02X Len:%02X Data:",
++ co2.power_levels.type, co2.power_levels.len);
++ for (i = 0; i < pEle[1]*2; i++) {
++ co2.power_levels.list[i] = pEle[i+2];
++ printk("%02X ", pEle[i+2]);
++ }
++ printk("\n");
++
++ pEle += pEle[1]*2 + 2;
++ co2.data_rates.type = pEle[0];
++ co2.data_rates.len = pEle[1];
++ printk("DataRatesID:%02X Len:%02X Data:",
++ co2.data_rates.type, co2.data_rates.len);
++ for (i = 0; i < pEle[1]; i++) {
++ co2.data_rates.list[i] = pEle[i+2];
++ printk("%02X ", pEle[i+2]);
++ }
++ printk("\n");
++
++ pEle += pEle[1] + 2;
++ co2.domains.type = pEle[0];
++ co2.domains.len = pEle[1];
++ printk("DomainID:%02X Len:%02X Data:",
++ co2.domains.type, co2.domains.len);
++ for (i = 0; i < pEle[1]; i++) {
++ co2.domains.list[i] = pEle[i+2];
++ printk("%02X ", pEle[i+2]);
++ }
++ printk("\n");
++
++ pEle += pEle[1] + 2;
++ co2.product_id.type = pEle[0];
++ co2.product_id.len = pEle[1];
++ for (i = 0; i < pEle[1]; i++) {
++ co2.product_id.list[i] = pEle[i+2];
++ }
++ printk("ProductID:%02X Len:%02X Data:%.*s\n",
++ co2.product_id.type, co2.product_id.len,
++ co2.product_id.len, (char *)co2.product_id.list);
++
++ pEle += pEle[1] + 2;
++ co2.manufacturer.type = pEle[0];
++ co2.manufacturer.len = pEle[1];
++ for (i = 0; i < pEle[1]; i++) {
++ co2.manufacturer.list[i] = pEle[i+2];
++ }
++ printk("ManufacturerID:%02X Len:%02X Data:%.*s\n",
++ co2.manufacturer.type, co2.manufacturer.len,
++ co2.manufacturer.len, (char *)co2.manufacturer.list);
++/*
++ printk("EEPROM part:\n");
++ for (i=0; i<58; i++) {
++ printk("%02X =======> 0x%02X\n",
++ i, (u8 *)co.configoption_fixed.NVSv[i-2]);
++ }
++*/
++}
++#endif
++
++
++/***********************************************************************
++*/
++static int __init
++acx_e_init_module(void)
++{
++ int r1;
++
++ acx_struct_size_check();
++
++ printk("acx: this driver is still EXPERIMENTAL\n"
++ "acx: reading README file and/or Craig's HOWTO is "
++ "recommended, visit http://acx100.sf.net in case "
++ "of further questions/discussion\n");
++
++#if defined(CONFIG_ACX_CFI)
++ r1 = acxcfi_e_init_module();
++#elif defined(CONFIG_ACX_PCI)
++ r1 = acxpci_e_init_module();
++#elif defined(CONFIG_ACX_USB)
++ r1 = acxusb_e_init_module();
++#else
++ r1 = -EINVAL;
++#endif
++ if (r1) /* both failed! */
++ return r1;
++ /* return success if at least one succeeded */
++ return 0;
++}
++
++static void __exit
++acx_e_cleanup_module(void)
++{
++#if defined(CONFIG_ACX_PCI)
++ acxcfi_e_cleanup_module();
++#elif defined(CONFIG_ACX_PCI)
++ acxpci_e_cleanup_module();
++#elif defined(CONFIG_ACX_USB)
++ acxusb_e_cleanup_module();
++#endif
++}
++
++module_init(acx_e_init_module)
++module_exit(acx_e_cleanup_module)
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/conv.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/conv.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/conv.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/conv.c 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,508 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/skbuff.h>
++#include <linux/if_arp.h>
++#include <linux/etherdevice.h>
++#include <linux/wireless.h>
++#if WIRELESS_EXT >= 13
++#include <net/iw_handler.h>
++#endif
++
++#include "acx.h"
++
++
++/*----------------------------------------------------------------
++* proto_is_stt
++*
++* Searches the 802.1h Selective Translation Table for a given
++* protocol.
++*
++* Arguments:
++* prottype protocol number (in host order) to search for.
++*
++* Returns:
++* 1 - if the table is empty or a match is found.
++* 0 - if the table is non-empty and a match is not found.
++*
++* Comment:
++* Based largely on p80211conv.c of the linux-wlan-ng project
++*----------------------------------------------------------------*/
++static inline int
++proto_is_stt(unsigned int proto)
++{
++ /* Always return found for now. This is the behavior used by the */
++ /* Zoom Win95 driver when 802.1h mode is selected */
++ /* TODO: If necessary, add an actual search we'll probably
++ need this to match the CMAC's way of doing things.
++ Need to do some testing to confirm.
++ */
++
++ if (proto == 0x80f3) /* APPLETALK */
++ return 1;
++
++ return 0;
++/* return ((prottype == ETH_P_AARP) || (prottype == ETH_P_IPX)); */
++}
++
++/* Helpers */
++
++static inline void
++store_llc_snap(struct wlan_llc *llc)
++{
++ llc->dsap = 0xaa; /* SNAP, see IEEE 802 */
++ llc->ssap = 0xaa;
++ llc->ctl = 0x03;
++}
++static inline int
++llc_is_snap(const struct wlan_llc *llc)
++{
++ return (llc->dsap == 0xaa)
++ && (llc->ssap == 0xaa)
++ && (llc->ctl == 0x03);
++}
++static inline void
++store_oui_rfc1042(struct wlan_snap *snap)
++{
++ snap->oui[0] = 0;
++ snap->oui[1] = 0;
++ snap->oui[2] = 0;
++}
++static inline int
++oui_is_rfc1042(const struct wlan_snap *snap)
++{
++ return (snap->oui[0] == 0)
++ && (snap->oui[1] == 0)
++ && (snap->oui[2] == 0);
++}
++static inline void
++store_oui_8021h(struct wlan_snap *snap)
++{
++ snap->oui[0] = 0;
++ snap->oui[1] = 0;
++ snap->oui[2] = 0xf8;
++}
++static inline int
++oui_is_8021h(const struct wlan_snap *snap)
++{
++ return (snap->oui[0] == 0)
++ && (snap->oui[1] == 0)
++ && (snap->oui[2] == 0xf8);
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_ether_to_txbuf
++*
++* Uses the contents of the ether frame to build the elements of
++* the 802.11 frame.
++*
++* We don't actually set up the frame header here. That's the
++* MAC's job. We're only handling conversion of DIXII or 802.3+LLC
++* frames to something that works with 802.11.
++*
++* Comment:
++* Based largely on p80211conv.c of the linux-wlan-ng project
++*----------------------------------------------------------------*/
++int
++acx_l_ether_to_txbuf(wlandevice_t *priv, void *txbuf, const struct sk_buff *skb)
++{
++ struct wlan_hdr_a3 *w_hdr;
++ struct wlan_ethhdr *e_hdr;
++ struct wlan_llc *e_llc;
++ struct wlan_snap *e_snap;
++ const u8 *a1, *a3;
++ int header_len, payload_len;
++ int result = -1;
++ /* protocol type or data length, depending on whether
++ * DIX or 802.3 ethernet format */
++ u16 proto;
++ u16 fc;
++
++ FN_ENTER;
++
++ if (unlikely(!skb->len)) {
++ acxlog(L_DEBUG, "zero-length skb!\n");
++ goto end;
++ }
++
++ w_hdr = (struct wlan_hdr_a3*)txbuf;
++
++ switch (priv->mode) {
++ case ACX_MODE_MONITOR:
++ /* NB: one day we might want to play with DESC_CTL2_FCS
++ ** Will need to stop doing "- WLAN_FCS_LEN" here then */
++ if (skb->len >= WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_FCS_LEN) {
++ printk("%s: can't tx oversized frame (%d bytes)\n",
++ priv->netdev->name, skb->len);
++ goto end;
++ }
++ memcpy(w_hdr, skb->data, skb->len);
++ result = skb->len;
++ goto end;
++ }
++
++ /* step 1: classify ether frame, DIX or 802.3? */
++ e_hdr = (wlan_ethhdr_t *)skb->data;
++ proto = ntohs(e_hdr->type);
++ if (proto <= 1500) {
++ acxlog(L_DEBUG, "tx: 802.3 len: %d\n", skb->len);
++ /* codes <= 1500 reserved for 802.3 lengths */
++ /* it's 802.3, pass ether payload unchanged, */
++ /* trim off ethernet header and copy payload to txdesc */
++ header_len = WLAN_HDR_A3_LEN;
++ } else {
++ /* it's DIXII, time for some conversion */
++ /* Create 802.11 packet. Header also contains llc and snap. */
++
++ acxlog(L_DEBUG, "tx: DIXII len: %d\n", skb->len);
++
++ /* size of header is 802.11 header + llc + snap */
++ header_len = WLAN_HDR_A3_LEN + sizeof(wlan_llc_t) + sizeof(wlan_snap_t);
++ /* llc is located behind the 802.11 header */
++ e_llc = (wlan_llc_t*)(w_hdr + 1);
++ /* snap is located behind the llc */
++ e_snap = (wlan_snap_t*)(e_llc + 1);
++
++ /* setup the LLC header */
++ store_llc_snap(e_llc);
++
++ /* setup the SNAP header */
++ e_snap->type = htons(proto);
++ if (proto_is_stt(proto)) {
++ store_oui_8021h(e_snap);
++ } else {
++ store_oui_rfc1042(e_snap);
++ }
++ }
++ /* trim off ethernet header and copy payload to txbuf */
++ payload_len = skb->len - sizeof(wlan_ethhdr_t);
++ /* TODO: can we just let acx DMA payload from skb instead? */
++ memcpy((u8*)txbuf + header_len, skb->data + sizeof(wlan_ethhdr_t), payload_len);
++ payload_len += header_len;
++ result = payload_len;
++
++ /* Set up the 802.11 header */
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi);
++ a1 = e_hdr->daddr;
++ a3 = priv->bssid;
++ break;
++ case ACX_MODE_2_STA:
++ fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_TODSi);
++ a1 = priv->bssid;
++ a3 = e_hdr->daddr;
++ break;
++ case ACX_MODE_3_AP:
++ fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi | WF_FC_FROMDSi);
++ a1 = e_hdr->daddr;
++ a3 = e_hdr->saddr;
++ break;
++ default:
++ printk("%s: error - converting eth to wlan in unknown mode\n",
++ priv->netdev->name);
++ result = -1;
++ goto end;
++ }
++ if (priv->wep_enabled)
++ SET_BIT(fc, WF_FC_ISWEPi);
++
++ w_hdr->fc = fc;
++ w_hdr->dur = 0;
++ MAC_COPY(w_hdr->a1, a1);
++ MAC_COPY(w_hdr->a2, priv->dev_addr);
++ MAC_COPY(w_hdr->a3, a3);
++ w_hdr->seq = 0;
++
++#ifdef DEBUG_CONVERT
++ if (acx_debug & L_DATA) {
++ printk("original eth frame [%d]: ", skb->len);
++ acx_dump_bytes(skb->data, skb->len);
++ printk("802.11 frame [%d]: ", payload_len);
++ acx_dump_bytes(w_hdr, payload_len);
++ }
++#endif
++
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_rxbuf_to_ether
++*
++* Uses the contents of a received 802.11 frame to build an ether
++* frame.
++*
++* This function extracts the src and dest address from the 802.11
++* frame to use in the construction of the eth frame.
++*
++* Based largely on p80211conv.c of the linux-wlan-ng project
++*----------------------------------------------------------------*/
++struct sk_buff*
++acx_rxbuf_to_ether(wlandevice_t *priv, rxbuffer_t *rxbuf)
++{
++ struct wlan_hdr *w_hdr;
++ struct wlan_ethhdr *e_hdr;
++ struct wlan_llc *e_llc;
++ struct wlan_snap *e_snap;
++ struct sk_buff *skb;
++ const u8 *daddr;
++ const u8 *saddr;
++ const u8 *e_payload;
++ int buflen, payload_length;
++ unsigned int payload_offset, mtu;
++ u16 fc;
++
++ FN_ENTER;
++
++ /* This looks complex because it must handle possible
++ ** phy header in rxbuff */
++ w_hdr = acx_get_wlan_hdr(priv, rxbuf);
++ payload_offset = WLAN_HDR_A3_LEN; /* it is relative to w_hdr */
++ payload_length = RXBUF_BYTES_USED(rxbuf) /* entire rxbuff... */
++ - ((u8*)w_hdr - (u8*)rxbuf) /* minus space before 802.11 frame */
++ - WLAN_HDR_A3_LEN; /* minus 802.11 header */
++
++ /* setup some vars for convenience */
++ fc = w_hdr->fc;
++ switch (WF_FC_FROMTODSi & fc) {
++ case 0:
++ daddr = w_hdr->a1;
++ saddr = w_hdr->a2;
++ break;
++ case WF_FC_FROMDSi:
++ daddr = w_hdr->a1;
++ saddr = w_hdr->a3;
++ break;
++ case WF_FC_TODSi:
++ daddr = w_hdr->a3;
++ saddr = w_hdr->a2;
++ break;
++ default: /* WF_FC_FROMTODSi */
++ payload_offset += (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
++ payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
++ daddr = w_hdr->a3;
++ saddr = w_hdr->a4;
++ }
++
++ if ((WF_FC_ISWEPi & fc) && IS_ACX100(priv)) {
++ /* chop off the IV+ICV WEP header and footer */
++ acxlog(L_DATA|L_DEBUG, "rx: WEP packet, "
++ "chopping off IV and ICV\n");
++ payload_offset += WLAN_WEP_IV_LEN;
++ payload_length -= WLAN_WEP_IV_LEN + WLAN_WEP_ICV_LEN;
++ }
++
++ if (unlikely(payload_length < 0)) {
++ printk("%s: rx frame too short, ignored\n", priv->netdev->name);
++ goto ret_null;
++ }
++
++ e_hdr = (wlan_ethhdr_t*) ((u8*) w_hdr + payload_offset);
++ e_llc = (wlan_llc_t*) e_hdr;
++ e_snap = (wlan_snap_t*) (e_llc + 1);
++ e_payload = (u8*) (e_snap + 1);
++ mtu = priv->netdev->mtu;
++
++ acxlog(L_DATA, "rx: payload_offset %d, payload_length %d\n",
++ payload_offset, payload_length);
++ acxlog(L_XFER|L_DATA,
++ "rx: frame info: llc=%02X%02X%02X "
++ "snap.oui=%02X%02X%02X snap.type=%04X\n",
++ e_llc->dsap, e_llc->ssap, e_llc->ctl,
++ e_snap->oui[0], e_snap->oui[1], e_snap->oui[2],
++ ntohs(e_snap->type));
++
++ /* Test for the various encodings */
++ if ((payload_length >= sizeof(wlan_ethhdr_t))
++ && ((e_llc->dsap != 0xaa) || (e_llc->ssap != 0xaa))
++ && ( (mac_is_equal(daddr, e_hdr->daddr))
++ || (mac_is_equal(saddr, e_hdr->saddr))
++ )
++ ) {
++ /* 802.3 Encapsulated: */
++ /* wlan frame body contains complete eth frame (header+body) */
++ acxlog(L_DEBUG|L_DATA, "rx: 802.3 ENCAP len=%d\n", payload_length);
++
++ if (unlikely(payload_length > (mtu + ETH_HLEN))) {
++ printk("%s: rx: ENCAP frame too large (%d > %d)\n",
++ priv->netdev->name,
++ payload_length, mtu + ETH_HLEN);
++ goto ret_null;
++ }
++
++ /* allocate space and setup host buffer */
++ buflen = payload_length;
++ /* Attempt to align IP header (14 bytes eth header + 2 = 16) */
++ skb = dev_alloc_skb(buflen + 2);
++ if (unlikely(!skb))
++ goto no_skb;
++ skb_reserve(skb, 2);
++ skb_put(skb, buflen); /* make room */
++
++ /* now copy the data from the 80211 frame */
++ memcpy(skb->data, e_hdr, payload_length);
++
++ } else if ( (payload_length >= sizeof(wlan_llc_t)+sizeof(wlan_snap_t))
++ && llc_is_snap(e_llc) ) {
++ /* wlan frame body contains: AA AA 03 ... (it's a SNAP) */
++
++ if ( !oui_is_rfc1042(e_snap)
++ || (proto_is_stt(ieee2host16(e_snap->type)) /* && (ethconv == WLAN_ETHCONV_8021h) */)) {
++ acxlog(L_DEBUG|L_DATA, "rx: SNAP+RFC1042 len=%d\n", payload_length);
++ /* wlan frame body contains: AA AA 03 !(00 00 00) ... -or- */
++ /* wlan frame body contains: AA AA 03 00 00 00 0x80f3 ... */
++ /* build eth hdr, type = len, copy AA AA 03... as eth body */
++ /* it's a SNAP + RFC1042 frame && protocol is in STT */
++
++ if (unlikely(payload_length > mtu)) {
++ printk("%s: rx: SNAP frame too large (%d > %d)\n",
++ priv->netdev->name,
++ payload_length, mtu);
++ goto ret_null;
++ }
++
++ /* allocate space and setup host buffer */
++ buflen = payload_length + ETH_HLEN;
++ skb = dev_alloc_skb(buflen + 2);
++ if (unlikely(!skb))
++ goto no_skb;
++ skb_reserve(skb, 2);
++ skb_put(skb, buflen); /* make room */
++
++ /* create 802.3 header */
++ e_hdr = (wlan_ethhdr_t*) skb->data;
++ MAC_COPY(e_hdr->daddr, daddr);
++ MAC_COPY(e_hdr->saddr, saddr);
++ e_hdr->type = htons(payload_length);
++
++ /* Now copy the data from the 80211 frame.
++ Make room in front for the eth header, and keep the
++ llc and snap from the 802.11 payload */
++ memcpy(skb->data + ETH_HLEN,
++ e_llc, payload_length);
++
++ } else {
++ /* wlan frame body contains: AA AA 03 00 00 00 [type] [tail] */
++ /* build eth hdr, type=[type], copy [tail] as eth body */
++ acxlog(L_DEBUG|L_DATA, "rx: 802.1h/RFC1042 len=%d\n",
++ payload_length);
++ /* it's an 802.1h frame (an RFC1042 && protocol is not in STT) */
++ /* build a DIXII + RFC894 */
++
++ payload_length -= sizeof(wlan_llc_t) + sizeof(wlan_snap_t);
++ if (unlikely(payload_length > mtu)) {
++ printk("%s: rx: DIXII frame too large (%d > %d)\n",
++ priv->netdev->name,
++ payload_length, mtu);
++ goto ret_null;
++ }
++
++ /* allocate space and setup host buffer */
++ buflen = payload_length + ETH_HLEN;
++ skb = dev_alloc_skb(buflen + 2);
++ if (unlikely(!skb))
++ goto no_skb;
++ skb_reserve(skb, 2);
++ skb_put(skb, buflen); /* make room */
++
++ /* create 802.3 header */
++ e_hdr = (wlan_ethhdr_t *) skb->data;
++ MAC_COPY(e_hdr->daddr, daddr);
++ MAC_COPY(e_hdr->saddr, saddr);
++ e_hdr->type = e_snap->type;
++
++ /* Now copy the data from the 80211 frame.
++ Make room in front for the eth header, and cut off the
++ llc and snap from the 802.11 payload */
++ memcpy(skb->data + ETH_HLEN,
++ e_payload, payload_length);
++ }
++
++ } else {
++ acxlog(L_DEBUG|L_DATA, "rx: NON-ENCAP len=%d\n", payload_length);
++ /* build eth hdr, type=len, copy wlan body as eth body */
++ /* any NON-ENCAP */
++ /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
++ /* build an 802.3 frame */
++
++ if (unlikely(payload_length > mtu)) {
++ printk("%s: rx: OTHER frame too large (%d > %d)\n",
++ priv->netdev->name, payload_length, mtu);
++ goto ret_null;
++ }
++
++ /* allocate space and setup host buffer */
++ buflen = payload_length + ETH_HLEN;
++ skb = dev_alloc_skb(buflen + 2);
++ if (unlikely(!skb))
++ goto no_skb;
++ skb_reserve(skb, 2);
++ skb_put(skb, buflen); /* make room */
++
++ /* set up the 802.3 header */
++ e_hdr = (wlan_ethhdr_t *) skb->data;
++ MAC_COPY(e_hdr->daddr, daddr);
++ MAC_COPY(e_hdr->saddr, saddr);
++ e_hdr->type = htons(payload_length);
++
++ /* now copy the data from the 80211 frame */
++ memcpy(skb->data + ETH_HLEN, e_llc, payload_length);
++ }
++
++ skb->dev = priv->netdev;
++ skb->protocol = eth_type_trans(skb, priv->netdev);
++
++#ifdef DEBUG_CONVERT
++ if (acx_debug & L_DATA) {
++ printk("p802.11 frame [%d]: ", RXBUF_BYTES_RCVD(rxbuf));
++ acx_dump_bytes(w_hdr, RXBUF_BYTES_RCVD(rxbuf));
++ printk("eth frame [%d]: ", skb->len);
++ acx_dump_bytes(skb->data, skb->len);
++ }
++#endif
++
++ FN_EXIT0;
++ return skb;
++
++no_skb:
++ printk("%s: rx: no memory for skb (%d bytes)\n",
++ priv->netdev->name, buflen + 2);
++ret_null:
++ FN_EXIT1((int)NULL);
++ return NULL;
++}
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/ioctl.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/ioctl.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/ioctl.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/ioctl.c 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,3060 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <asm/io.h>
++#include <asm/uaccess.h> /* required for 2.4.x kernels; verify_write() */
++
++#include <linux/if_arp.h>
++#include <linux/wireless.h>
++#if WIRELESS_EXT >= 13
++#include <net/iw_handler.h>
++#endif /* WE >= 13 */
++
++#include "acx.h"
++
++
++/*================================================================*/
++
++/* if you plan to reorder something, make sure to reorder all other places
++ * accordingly! */
++/* someone broke SET/GET convention: SETs must have even position, GETs odd */
++#define ACX100_IOCTL SIOCIWFIRSTPRIV
++enum {
++ ACX100_IOCTL_DEBUG = ACX100_IOCTL,
++ ACX100_IOCTL_GET__________UNUSED1,
++ ACX100_IOCTL_SET_PLED,
++ ACX100_IOCTL_GET_PLED,
++ ACX100_IOCTL_SET_RATES,
++ ACX100_IOCTL_LIST_DOM,
++ ACX100_IOCTL_SET_DOM,
++ ACX100_IOCTL_GET_DOM,
++ ACX100_IOCTL_SET_SCAN_PARAMS,
++ ACX100_IOCTL_GET_SCAN_PARAMS,
++ ACX100_IOCTL_SET_PREAMB,
++ ACX100_IOCTL_GET_PREAMB,
++ ACX100_IOCTL_SET_ANT,
++ ACX100_IOCTL_GET_ANT,
++ ACX100_IOCTL_RX_ANT,
++ ACX100_IOCTL_TX_ANT,
++ ACX100_IOCTL_SET_PHY_AMP_BIAS,
++ ACX100_IOCTL_GET_PHY_CHAN_BUSY,
++ ACX100_IOCTL_SET_ED,
++ ACX100_IOCTL_GET__________UNUSED3,
++ ACX100_IOCTL_SET_CCA,
++ ACX100_IOCTL_GET__________UNUSED4,
++ ACX100_IOCTL_MONITOR,
++ ACX100_IOCTL_TEST,
++ ACX100_IOCTL_DBG_SET_MASKS,
++ ACX111_IOCTL_INFO,
++ ACX100_IOCTL_DBG_SET_IO,
++ ACX100_IOCTL_DBG_GET_IO
++};
++
++/* channel frequencies
++ * TODO: Currently, every other 802.11 driver keeps its own copy of this. In
++ * the long run this should be integrated into ieee802_11.h or wireless.h or
++ * whatever IEEE802.11x framework evolves */
++static const u16 acx_channel_freq[] = {
++ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
++ 2447, 2452, 2457, 2462, 2467, 2472, 2484,
++};
++
++static const struct iw_priv_args acx_ioctl_private_args[] = {
++#if ACX_DEBUG
++{ cmd : ACX100_IOCTL_DEBUG,
++ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetDebug" },
++#endif
++{ cmd : ACX100_IOCTL_SET_PLED,
++ set_args : IW_PRIV_TYPE_BYTE | 2,
++ get_args : 0,
++ name : "SetLEDPower" },
++{ cmd : ACX100_IOCTL_GET_PLED,
++ set_args : 0,
++ get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2,
++ name : "GetLEDPower" },
++{ cmd : ACX100_IOCTL_SET_RATES,
++ set_args : IW_PRIV_TYPE_CHAR | 256,
++ get_args : 0,
++ name : "SetRates" },
++{ cmd : ACX100_IOCTL_LIST_DOM,
++ set_args : 0,
++ get_args : 0,
++ name : "ListRegDomain" },
++{ cmd : ACX100_IOCTL_SET_DOM,
++ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetRegDomain" },
++{ cmd : ACX100_IOCTL_GET_DOM,
++ set_args : 0,
++ get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ name : "GetRegDomain" },
++{ cmd : ACX100_IOCTL_SET_SCAN_PARAMS,
++ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
++ get_args : 0,
++ name : "SetScanParams" },
++{ cmd : ACX100_IOCTL_GET_SCAN_PARAMS,
++ set_args : 0,
++ get_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
++ name : "GetScanParams" },
++{ cmd : ACX100_IOCTL_SET_PREAMB,
++ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetSPreamble" },
++{ cmd : ACX100_IOCTL_GET_PREAMB,
++ set_args : 0,
++ get_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ name : "GetSPreamble" },
++{ cmd : ACX100_IOCTL_SET_ANT,
++ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetAntenna" },
++{ cmd : ACX100_IOCTL_GET_ANT,
++ set_args : 0,
++ get_args : 0,
++ name : "GetAntenna" },
++{ cmd : ACX100_IOCTL_RX_ANT,
++ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetRxAnt" },
++{ cmd : ACX100_IOCTL_TX_ANT,
++ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetTxAnt" },
++{ cmd : ACX100_IOCTL_SET_PHY_AMP_BIAS,
++ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetPhyAmpBias"},
++{ cmd : ACX100_IOCTL_GET_PHY_CHAN_BUSY,
++ set_args : 0,
++ get_args : 0,
++ name : "GetPhyChanBusy" },
++{ cmd : ACX100_IOCTL_SET_ED,
++ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetED" },
++{ cmd : ACX100_IOCTL_SET_CCA,
++ set_args : IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
++ get_args : 0,
++ name : "SetCCA" },
++{ cmd : ACX100_IOCTL_MONITOR,
++ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
++ get_args : 0,
++ name : "monitor" },
++{ cmd : ACX100_IOCTL_TEST,
++ set_args : 0,
++ get_args : 0,
++ name : "Test" },
++{ cmd : ACX100_IOCTL_DBG_SET_MASKS,
++ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2,
++ get_args : 0,
++ name : "DbgSetMasks" },
++{ cmd : ACX111_IOCTL_INFO,
++ set_args : 0,
++ get_args : 0,
++ name : "GetAcx111Info" },
++{ cmd : ACX100_IOCTL_DBG_SET_IO,
++ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 4,
++ get_args : 0,
++ name : "DbgSetIO" },
++{ cmd : ACX100_IOCTL_DBG_GET_IO,
++ set_args : IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
++ get_args : 0,
++ name : "DbgGetIO" },
++};
++
++
++/*------------------------------------------------------------------------------
++ * acx_ioctl_commit
++ *----------------------------------------------------------------------------*/
++static int
++acx_ioctl_commit(struct net_device *dev,
++ struct iw_request_info *info,
++ void *zwrq, char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
++ acx_s_update_card_settings(priv, 0, 0);
++ acx_sem_unlock(priv);
++
++ FN_EXIT0;
++ return OK;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_get_name(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ char *cwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ static const char * const names[] = { "IEEE 802.11b+/g+", "IEEE 802.11b+" };
++
++ strcpy(cwrq, names[IS_ACX111(priv) ? 0 : 1]);
++
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_freq
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_freq(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_freq *fwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int channel = -1;
++ unsigned int mult = 1;
++ int result;
++
++ FN_ENTER;
++
++ if (fwrq->e == 0 && fwrq->m <= 1000) {
++ /* Setting by channel number */
++ channel = fwrq->m;
++ } else {
++ /* If setting by frequency, convert to a channel */
++ int i;
++
++ for (i = 0; i < (6 - fwrq->e); i++)
++ mult *= 10;
++
++ for (i = 1; i <= 14; i++)
++ if (fwrq->m == acx_channel_freq[i - 1] * mult)
++ channel = i;
++ }
++
++ if (channel > 14) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ acx_sem_lock(priv);
++
++ priv->channel = channel;
++ /* hmm, the following code part is strange, but this is how
++ * it was being done before... */
++ acxlog(L_IOCTL, "Changing to channel %d\n", channel);
++ SET_BIT(priv->set_mask, GETSET_CHANNEL);
++
++ result = -EINPROGRESS; /* need to call commit handler */
++
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static inline int
++acx_ioctl_get_freq(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_freq *fwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ fwrq->e = 0;
++ fwrq->m = priv->channel;
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_mode
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_mode(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ u32 *uwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ switch (*uwrq) {
++ case IW_MODE_AUTO:
++ priv->mode = ACX_MODE_OFF;
++ break;
++#if WIRELESS_EXT > 14
++ case IW_MODE_MONITOR:
++ priv->mode = ACX_MODE_MONITOR;
++ break;
++#endif /* WIRELESS_EXT > 14 */
++ case IW_MODE_ADHOC:
++ priv->mode = ACX_MODE_0_ADHOC;
++ break;
++ case IW_MODE_INFRA:
++ priv->mode = ACX_MODE_2_STA;
++ break;
++ case IW_MODE_MASTER:
++ printk("acx: master mode (HostAP) is very, very "
++ "experimental! It might work partially, but "
++ "better get prepared for nasty surprises "
++ "at any time\n");
++ priv->mode = ACX_MODE_3_AP;
++ break;
++ case IW_MODE_REPEAT:
++ case IW_MODE_SECOND:
++ default:
++ result = -EOPNOTSUPP;
++ goto end_unlock;
++ }
++
++ acxlog(L_ASSOC, "new priv->mode=%d\n", priv->mode);
++ SET_BIT(priv->set_mask, GETSET_MODE);
++ result = -EINPROGRESS;
++
++end_unlock:
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_get_mode(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ u32 *uwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result = 0;
++
++ switch (priv->mode) {
++ case ACX_MODE_OFF:
++ *uwrq = IW_MODE_AUTO; break;
++#if WIRELESS_EXT > 14
++ case ACX_MODE_MONITOR:
++ *uwrq = IW_MODE_MONITOR; break;
++#endif /* WIRELESS_EXT > 14 */
++ case ACX_MODE_0_ADHOC:
++ *uwrq = IW_MODE_ADHOC; break;
++ case ACX_MODE_2_STA:
++ *uwrq = IW_MODE_INFRA; break;
++ case ACX_MODE_3_AP:
++ *uwrq = IW_MODE_MASTER; break;
++ default:
++ result = -EOPNOTSUPP;
++ }
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_set_sens(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ priv->sensitivity = (1 == vwrq->disabled) ? 0 : vwrq->value;
++ SET_BIT(priv->set_mask, GETSET_SENSITIVITY);
++
++ acx_sem_unlock(priv);
++
++ return -EINPROGRESS;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_get_sens(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ /* acx_sem_lock(priv); */
++
++ vwrq->value = priv->sensitivity;
++ vwrq->disabled = (vwrq->value == 0);
++ vwrq->fixed = 1;
++
++ /* acx_sem_unlock(priv); */
++
++ return OK;
++}
++
++
++/*------------------------------------------------------------------------------
++ * acx_ioctl_set_ap
++ *
++ * Sets the MAC address of the AP to associate with
++ *----------------------------------------------------------------------------*/
++static int
++acx_ioctl_set_ap(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct sockaddr *awrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result = 0;
++ const u8 *ap;
++
++ FN_ENTER;
++ if (NULL == awrq) {
++ result = -EFAULT;
++ goto end;
++ }
++ if (ARPHRD_ETHER != awrq->sa_family) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ ap = awrq->sa_data;
++ acxlog_mac(L_IOCTL, "Set AP=", ap, "\n");
++
++ MAC_COPY(priv->ap, ap);
++
++ /* We want to start rescan in managed or ad-hoc mode,
++ ** otherwise just set priv->ap.
++ ** "iwconfig <if> ap <mac> mode managed": we must be able
++ ** to set ap _first_ and _then_ set mode */
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ /* FIXME: if there is a convention on what zero AP means,
++ ** please add a comment about that. I don't know of any --vda */
++ if (mac_is_zero(ap)) {
++ /* "off" == 00:00:00:00:00:00 */
++ MAC_BCAST(priv->ap);
++ acxlog(L_IOCTL, "Not reassociating\n");
++ } else {
++ acxlog(L_IOCTL, "Forcing reassociation\n");
++ SET_BIT(priv->set_mask, GETSET_RESCAN);
++ }
++ break;
++ }
++ result = -EINPROGRESS;
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_get_ap(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct sockaddr *awrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ if (ACX_STATUS_4_ASSOCIATED == priv->status) {
++ /* as seen in Aironet driver, airo.c */
++ MAC_COPY(awrq->sa_data, priv->bssid);
++ } else {
++ MAC_ZERO(awrq->sa_data);
++ }
++ awrq->sa_family = ARPHRD_ETHER;
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_aplist
++*
++* Comment: deprecated in favour of iwscan.
++* We simply return the list of currently available stations in range,
++* don't do a new scan.
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_aplist(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ struct sockaddr *address = (struct sockaddr *) extra;
++ struct iw_quality qual[IW_MAX_AP];
++ int i, cur;
++ int result = OK;
++
++ FN_ENTER;
++
++ /* we have AP list only in STA mode */
++ if (ACX_MODE_2_STA != priv->mode) {
++ result = -EOPNOTSUPP;
++ goto end;
++ }
++
++ cur = 0;
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ struct client *bss = &priv->sta_list[i];
++ if (!bss->used) continue;
++ MAC_COPY(address[cur].sa_data, bss->bssid);
++ address[cur].sa_family = ARPHRD_ETHER;
++ qual[cur].level = bss->sir;
++ qual[cur].noise = bss->snr;
++#ifndef OLD_QUALITY
++ qual[cur].qual = acx_signal_determine_quality(qual[cur].level,
++ qual[cur].noise);
++#else
++ qual[cur].qual = (qual[cur].noise <= 100) ?
++ 100 - qual[cur].noise : 0;
++#endif
++ /* no scan: level/noise/qual not updated: */
++ qual[cur].updated = 0;
++ cur++;
++ }
++ if (cur) {
++ dwrq->flags = 1;
++ memcpy(extra + sizeof(struct sockaddr)*cur, &qual,
++ sizeof(struct iw_quality)*cur);
++ }
++ dwrq->length = cur;
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_set_scan(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ /* don't start scan if device is not up yet */
++ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
++ result = -EAGAIN;
++ goto end_unlock;
++ }
++
++ /* This is NOT a rescan for new AP!
++ ** Do not use SET_BIT(GETSET_RESCAN); */
++ acx_s_cmd_start_scan(priv);
++ result = OK;
++
++end_unlock:
++ acx_sem_unlock(priv);
++/* end: */
++ FN_EXIT1(result);
++ return result;
++}
++
++
++#if WIRELESS_EXT > 13
++/***********************************************************************
++** acx_s_scan_add_station
++*/
++/* helper. not sure wheter it's really a _s_leeping fn */
++static char*
++acx_s_scan_add_station(
++ wlandevice_t *priv,
++ char *ptr,
++ char *end_buf,
++ struct client *bss)
++{
++ struct iw_event iwe;
++ char *ptr_rate;
++
++ FN_ENTER;
++
++ /* MAC address has to be added first */
++ iwe.cmd = SIOCGIWAP;
++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
++ MAC_COPY(iwe.u.ap_addr.sa_data, bss->bssid);
++ acxlog_mac(L_IOCTL, "scan, station address: ", bss->bssid, "\n");
++ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_ADDR_LEN);
++
++ /* Add ESSID */
++ iwe.cmd = SIOCGIWESSID;
++ iwe.u.data.length = bss->essid_len;
++ iwe.u.data.flags = 1;
++ acxlog(L_IOCTL, "scan, essid: %s\n", bss->essid);
++ ptr = iwe_stream_add_point(ptr, end_buf, &iwe, bss->essid);
++
++ /* Add mode */
++ iwe.cmd = SIOCGIWMODE;
++ if (bss->cap_info & (WF_MGMT_CAP_ESS | WF_MGMT_CAP_IBSS)) {
++ if (bss->cap_info & WF_MGMT_CAP_ESS)
++ iwe.u.mode = IW_MODE_MASTER;
++ else
++ iwe.u.mode = IW_MODE_ADHOC;
++ acxlog(L_IOCTL, "scan, mode: %d\n", iwe.u.mode);
++ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_UINT_LEN);
++ }
++
++ /* Add frequency */
++ iwe.cmd = SIOCGIWFREQ;
++ iwe.u.freq.m = acx_channel_freq[bss->channel - 1] * 100000;
++ iwe.u.freq.e = 1;
++ acxlog(L_IOCTL, "scan, frequency: %d\n", iwe.u.freq.m);
++ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_FREQ_LEN);
++
++ /* Add link quality */
++ iwe.cmd = IWEVQUAL;
++ /* FIXME: these values should be expressed in dBm, but we don't know
++ * how to calibrate it yet */
++ iwe.u.qual.level = bss->sir;
++ iwe.u.qual.noise = bss->snr;
++#ifndef OLD_QUALITY
++ iwe.u.qual.qual = acx_signal_determine_quality(iwe.u.qual.level,
++ iwe.u.qual.noise);
++#else
++ iwe.u.qual.qual = (iwe.u.qual.noise <= 100) ?
++ 100 - iwe.u.qual.noise : 0;
++#endif
++ iwe.u.qual.updated = 7;
++ acxlog(L_IOCTL, "scan, link quality: %d/%d/%d\n",
++ iwe.u.qual.level, iwe.u.qual.noise, iwe.u.qual.qual);
++ ptr = iwe_stream_add_event(ptr, end_buf, &iwe, IW_EV_QUAL_LEN);
++
++ /* Add encryption */
++ iwe.cmd = SIOCGIWENCODE;
++ if (bss->cap_info & WF_MGMT_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;
++ acxlog(L_IOCTL, "scan, encryption flags: %X\n", iwe.u.data.flags);
++ ptr = iwe_stream_add_point(ptr, end_buf, &iwe, bss->essid);
++
++ /* add rates */
++ iwe.cmd = SIOCGIWRATE;
++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
++ ptr_rate = ptr + IW_EV_LCP_LEN;
++
++ {
++ u16 rate = bss->rate_cap;
++ const u8* p = bitpos2ratebyte;
++ while (rate) {
++ if (rate & 1) {
++ iwe.u.bitrate.value = *p * 500000; /* units of 500kb/s */
++ acxlog(L_IOCTL, "scan, rate: %d\n", iwe.u.bitrate.value);
++ ptr = iwe_stream_add_value(ptr, ptr_rate, end_buf, &iwe, IW_EV_PARAM_LEN);
++ }
++ rate >>= 1;
++ p++;
++ }}
++
++ if ((ptr_rate - ptr) > (ptrdiff_t)IW_EV_LCP_LEN)
++ ptr = ptr_rate;
++
++ /* drop remaining station data items for now */
++
++ FN_EXIT0;
++ return ptr;
++}
++
++
++/***********************************************************************
++ * acx_ioctl_get_scan
++ */
++static int
++acx_ioctl_get_scan(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ char *ptr = extra;
++ int i;
++ int result = OK;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ /* no scan available if device is not up yet */
++ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
++ acxlog(L_IOCTL, "iface not up yet\n");
++ result = -EAGAIN;
++ goto end_unlock;
++ }
++#if 0 /* Why is this needed? If needed, add a comment */
++ if (priv->scan_start && time_before(jiffies, priv->scan_start + 3*HZ)) {
++ acxlog(L_IOCTL, "scan in progress, no results yet\n");
++ result = -EAGAIN;
++ goto end_unlock;
++ }
++#endif
++
++#ifdef ENODATA_TO_BE_USED_AFTER_SCAN_ERROR_ONLY
++ if (priv->bss_table_count == 0) {
++ /* no stations found */
++ result = -ENODATA;
++ goto end_unlock;
++ }
++#endif
++
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ struct client *bss = &priv->sta_list[i];
++ if (!bss->used) continue;
++ ptr = acx_s_scan_add_station(priv, ptr,
++ extra + IW_SCAN_MAX_DATA, bss);
++ }
++ dwrq->length = ptr - extra;
++ dwrq->flags = 0;
++
++end_unlock:
++ acx_sem_unlock(priv);
++/* end: */
++ FN_EXIT1(result);
++ return result;
++}
++#endif /* WIRELESS_EXT > 13 */
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_essid
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_essid(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int len = dwrq->length;
++ int result;
++
++ FN_ENTER;
++
++ acxlog(L_IOCTL, "Set ESSID '%*s', length %d, flags 0x%04X\n",
++ len, extra, len, dwrq->flags);
++
++ if (len < 0) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ acx_sem_lock(priv);
++
++ /* ESSID disabled? */
++ if (0 == dwrq->flags) {
++ priv->essid_active = 0;
++
++ } else {
++ if (dwrq->length > IW_ESSID_MAX_SIZE+1) {
++ result = -E2BIG;
++ goto end_unlock;
++ }
++
++ if (len > sizeof(priv->essid))
++ len = sizeof(priv->essid);
++ memcpy(priv->essid, extra, len-1);
++ priv->essid[len-1] = '\0';
++ /* Paranoia: just in case there is a '\0'... */
++ priv->essid_len = strlen(priv->essid);
++ priv->essid_active = 1;
++ }
++
++ SET_BIT(priv->set_mask, GETSET_RESCAN);
++
++ result = -EINPROGRESS;
++
++end_unlock:
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_get_essid(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ dwrq->flags = priv->essid_active;
++ if (priv->essid_active) {
++ memcpy(extra, priv->essid, priv->essid_len);
++ extra[priv->essid_len] = '\0';
++ dwrq->length = priv->essid_len + 1;
++ dwrq->flags = 1;
++ }
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_update_client_rates
++*----------------------------------------------------------------*/
++static void
++acx_l_update_client_rates(wlandevice_t *priv, u16 rate)
++{
++ int i;
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ client_t *clt = &priv->sta_list[i];
++ if (!clt->used) continue;
++ clt->rate_cfg = (clt->rate_cap & rate);
++ if (!clt->rate_cfg) {
++ /* no compatible rates left: kick client */
++ acxlog_mac(L_ASSOC, "client ",clt->address," kicked: "
++ "rates are not compatible anymore\n");
++ acx_l_sta_list_del(priv, clt);
++ continue;
++ }
++ clt->rate_cur &= clt->rate_cfg;
++ if (!clt->rate_cur) {
++ /* current rate become invalid, choose a valid one */
++ clt->rate_cur = 1 << lowest_bit(clt->rate_cfg);
++ }
++ clt->fallback_count = clt->stepup_count = 0;
++ clt->ignore_count = 16;
++ }
++ switch (priv->mode) {
++ case ACX_MODE_2_STA:
++ if (priv->ap_client && !priv->ap_client->used) {
++ /* Owwww... we kicked our AP!! :) */
++ SET_BIT(priv->set_mask, GETSET_RESCAN);
++ }
++ }
++}
++
++
++/***********************************************************************
++*/
++/* maps bits from acx111 rate to rate in Mbits */
++static const unsigned int
++acx111_rate_tbl[] = {
++ 1000000, /* 0 */
++ 2000000, /* 1 */
++ 5500000, /* 2 */
++ 6000000, /* 3 */
++ 9000000, /* 4 */
++ 11000000, /* 5 */
++ 12000000, /* 6 */
++ 18000000, /* 7 */
++ 22000000, /* 8 */
++ 24000000, /* 9 */
++ 36000000, /* 10 */
++ 48000000, /* 11 */
++ 54000000, /* 12 */
++ 500000, /* 13, should not happen */
++ 500000, /* 14, should not happen */
++ 500000, /* 15, should not happen */
++};
++
++/***********************************************************************
++ * acx_ioctl_set_rate
++ */
++static int
++acx_ioctl_set_rate(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ u16 txrate_cfg = 1;
++ unsigned long flags;
++ int autorate;
++ int result = -EINVAL;
++
++ FN_ENTER;
++ acxlog(L_IOCTL,
++ "rate %d fixed 0x%X disabled 0x%X flags 0x%X\n",
++ vwrq->value, vwrq->fixed, vwrq->disabled, vwrq->flags);
++
++ if ((0 == vwrq->fixed) || (1 == vwrq->fixed)) {
++ int i = VEC_SIZE(acx111_rate_tbl)-1;
++ if (vwrq->value == -1)
++ /* "iwconfig rate auto" --> choose highest */
++ vwrq->value = IS_ACX100(priv) ? 22000000 : 54000000;
++ while (i >= 0) {
++ if (vwrq->value == acx111_rate_tbl[i]) {
++ txrate_cfg <<= i;
++ i = 0;
++ break;
++ }
++ i--;
++ }
++ if (i == -1) { /* no matching rate */
++ result = -EINVAL;
++ goto end;
++ }
++ } else { /* rate N, N<1000 (driver specific): we don't use this */
++ result = -EOPNOTSUPP;
++ goto end;
++ }
++ /* now: only one bit is set in txrate_cfg, corresponding to
++ ** indicated rate */
++
++ autorate = (vwrq->fixed == 0) && (RATE111_1 != txrate_cfg);
++ if (autorate) {
++ /* convert 00100000 -> 00111111 */
++ txrate_cfg = (txrate_cfg<<1)-1;
++ }
++
++ if (IS_ACX100(priv)) {
++ txrate_cfg &= RATE111_ACX100_COMPAT;
++ if (!txrate_cfg) {
++ result = -ENOTSUPP; /* rate is not supported by acx100 */
++ goto end;
++ }
++ }
++
++ acx_sem_lock(priv);
++ acx_lock(priv, flags);
++
++ priv->rate_auto = autorate;
++ priv->rate_oper = txrate_cfg;
++ priv->rate_basic = txrate_cfg;
++ /* only do that in auto mode, non-auto will be able to use
++ * one specific Tx rate only anyway */
++ if (autorate) {
++ /* only use 802.11b base rates, for standard 802.11b H/W
++ * compatibility */
++ priv->rate_basic &= RATE111_80211B_COMPAT;
++ }
++ priv->rate_bcast = 1 << lowest_bit(txrate_cfg);
++ if (IS_ACX100(priv))
++ priv->rate_bcast100 = acx_rate111to100(priv->rate_bcast);
++ acx_l_update_ratevector(priv);
++ acx_l_update_client_rates(priv, txrate_cfg);
++
++ /* Do/don't do tx rate fallback; beacon contents and rate */
++ SET_BIT(priv->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES);
++ result = -EINPROGRESS;
++
++ acx_unlock(priv, flags);
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_rate
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_rate(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ /* TODO: remember rate of last tx, show it. think about multiple peers... */
++ wlandevice_t *priv = netdev_priv(dev);
++ vwrq->value = acx111_rate_tbl[highest_bit(priv->rate_oper)];
++ vwrq->fixed = !priv->rate_auto;
++ vwrq->disabled = 0;
++ return OK;
++}
++
++static int
++acx_ioctl_set_rts(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int val = vwrq->value;
++
++ if (vwrq->disabled)
++ val = 2312;
++ if ((val < 0) || (val > 2312))
++ return -EINVAL;
++
++ priv->rts_threshold = val;
++ return OK;
++}
++
++static inline int
++acx_ioctl_get_rts(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ vwrq->value = priv->rts_threshold;
++ vwrq->disabled = (vwrq->value >= 2312);
++ vwrq->fixed = 1;
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_encode
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_encode(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int index;
++ int result;
++
++ FN_ENTER;
++ acxlog(L_IOCTL,
++ "Set Encoding flags=0x%04X, size=%d, key: %s\n",
++ dwrq->flags, dwrq->length, extra ? "set" : "No key");
++
++ acx_sem_lock(priv);
++
++ index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
++
++ if (dwrq->length > 0) {
++ /* if index is 0 or invalid, use default key */
++ if ((index < 0) || (index > 3))
++ index = (int)priv->wep_current_index;
++
++ if (0 == (dwrq->flags & IW_ENCODE_NOKEY)) {
++ if (dwrq->length > 29)
++ dwrq->length = 29; /* restrict it */
++
++ if (dwrq->length > 13)
++ priv->wep_keys[index].size = 29; /* 29*8 == 232, WEP256 */
++ else
++ if (dwrq->length > 5)
++ priv->wep_keys[index].size = 13; /* 13*8 == 104bit, WEP128 */
++ else
++ if (dwrq->length > 0)
++ priv->wep_keys[index].size = 5; /* 5*8 == 40bit, WEP64 */
++ else
++ /* disable key */
++ priv->wep_keys[index].size = 0;
++
++ memset(priv->wep_keys[index].key, 0, sizeof(priv->wep_keys[index].key));
++ memcpy(priv->wep_keys[index].key, extra, dwrq->length);
++ }
++
++ } else {
++ /* set transmit key */
++ if ((index >= 0) && (index <= 3))
++ priv->wep_current_index = index;
++ else
++ if (0 == (dwrq->flags & IW_ENCODE_MODE)) {
++ /* complain if we were not just setting
++ * the key mode */
++ result = -EINVAL;
++ goto end_unlock;
++ }
++ }
++
++ priv->wep_enabled = !(dwrq->flags & IW_ENCODE_DISABLED);
++
++ if (dwrq->flags & IW_ENCODE_OPEN) {
++ priv->auth_alg = WLAN_AUTH_ALG_OPENSYSTEM;
++ priv->wep_restricted = 0;
++
++ } else if (dwrq->flags & IW_ENCODE_RESTRICTED) {
++ priv->auth_alg = WLAN_AUTH_ALG_SHAREDKEY;
++ priv->wep_restricted = 1;
++ }
++
++ /* set flag to make sure the card WEP settings get updated */
++ SET_BIT(priv->set_mask, GETSET_WEP);
++
++ acxlog(L_IOCTL, "len=%d, key at 0x%p, flags=0x%X\n",
++ dwrq->length, extra,
++ dwrq->flags);
++
++ for (index = 0; index <= 3; index++) {
++ if (priv->wep_keys[index].size) {
++ acxlog(L_IOCTL,
++ "index=%d, size=%d, key at 0x%p\n",
++ priv->wep_keys[index].index,
++ (int) priv->wep_keys[index].size,
++ priv->wep_keys[index].key);
++ }
++ }
++ result = -EINPROGRESS;
++
++end_unlock:
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_encode
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_encode(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
++
++ if (priv->wep_enabled == 0) {
++ dwrq->flags = IW_ENCODE_DISABLED;
++
++ } else {
++ if ((index < 0) || (index > 3))
++ index = (int)priv->wep_current_index;
++
++ dwrq->flags =
++ (priv->wep_restricted == 1) ? IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN;
++ dwrq->length = priv->wep_keys[index].size;
++
++ memcpy(extra,
++ priv->wep_keys[index].key,
++ priv->wep_keys[index].size);
++ }
++
++ /* set the current index */
++ SET_BIT(dwrq->flags, index + 1);
++
++ acxlog(L_IOCTL, "len=%d, key=%p, flags=0x%X\n",
++ dwrq->length, dwrq->pointer,
++ dwrq->flags);
++
++ return OK;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_set_power(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acxlog(L_IOCTL, "Set 802.11 Power Save flags=0x%04X\n", vwrq->flags);
++ if (vwrq->disabled) {
++ CLEAR_BIT(priv->ps_wakeup_cfg, PS_CFG_ENABLE);
++ SET_BIT(priv->set_mask, GETSET_POWER_80211);
++ return -EINPROGRESS;
++ }
++ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
++ u16 ps_timeout = (vwrq->value * 1024) / 1000;
++
++ if (ps_timeout > 255)
++ ps_timeout = 255;
++ acxlog(L_IOCTL, "setting PS timeout value to %d time units "
++ "due to %dus\n", ps_timeout, vwrq->value);
++ priv->ps_hangover_period = ps_timeout;
++ } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
++ u16 ps_periods = vwrq->value / 1000000;
++
++ if (ps_periods > 255)
++ ps_periods = 255;
++ acxlog(L_IOCTL, "setting PS period value to %d periods "
++ "due to %dus\n", ps_periods, vwrq->value);
++ priv->ps_listen_interval = ps_periods;
++ CLEAR_BIT(priv->ps_wakeup_cfg, PS_CFG_WAKEUP_MODE_MASK);
++ SET_BIT(priv->ps_wakeup_cfg, PS_CFG_WAKEUP_EACH_ITVL);
++ }
++ switch (vwrq->flags & IW_POWER_MODE) {
++ /* FIXME: are we doing the right thing here? */
++ case IW_POWER_UNICAST_R:
++ CLEAR_BIT(priv->ps_options, PS_OPT_STILL_RCV_BCASTS);
++ break;
++ case IW_POWER_MULTICAST_R:
++ SET_BIT(priv->ps_options, PS_OPT_STILL_RCV_BCASTS);
++ break;
++ case IW_POWER_ALL_R:
++ SET_BIT(priv->ps_options, PS_OPT_STILL_RCV_BCASTS);
++ break;
++ case IW_POWER_ON:
++ break;
++ default:
++ acxlog(L_IOCTL, "unknown PS mode\n");
++ return -EINVAL;
++ }
++
++ SET_BIT(priv->ps_wakeup_cfg, PS_CFG_ENABLE);
++ SET_BIT(priv->set_mask, GETSET_POWER_80211);
++
++ return -EINPROGRESS;
++
++}
++
++
++/***********************************************************************
++*/
++static int
++acx_ioctl_get_power(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acxlog(L_IOCTL, "Get 802.11 Power Save flags = 0x%04X\n", vwrq->flags);
++ vwrq->disabled = ((priv->ps_wakeup_cfg & PS_CFG_ENABLE) == 0);
++ if (vwrq->disabled)
++ return OK;
++ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
++ vwrq->value = priv->ps_hangover_period * 1000 / 1024;
++ vwrq->flags = IW_POWER_TIMEOUT;
++ } else {
++ vwrq->value = priv->ps_listen_interval * 1000000;
++ vwrq->flags = IW_POWER_PERIOD|IW_POWER_RELATIVE;
++ }
++ if (priv->ps_options & PS_OPT_STILL_RCV_BCASTS)
++ SET_BIT(vwrq->flags, IW_POWER_ALL_R);
++ else
++ SET_BIT(vwrq->flags, IW_POWER_UNICAST_R);
++
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_txpow
++*----------------------------------------------------------------*/
++static inline int
++acx_ioctl_get_txpow(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ vwrq->flags = IW_TXPOW_DBM;
++ vwrq->disabled = 0;
++ vwrq->fixed = 1;
++ vwrq->value = priv->tx_level_dbm;
++
++ acxlog(L_IOCTL, "get txpower:%d dBm\n", priv->tx_level_dbm);
++
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_txpow
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_txpow(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++ acxlog(L_IOCTL, "set txpower:%d, disabled:%d, flags:0x%04X\n",
++ vwrq->value, vwrq->disabled, vwrq->flags);
++
++ acx_sem_lock(priv);
++
++ if (vwrq->disabled != priv->tx_disabled) {
++ SET_BIT(priv->set_mask, GETSET_TX); /* Tx status needs update later */
++ }
++
++ priv->tx_disabled = vwrq->disabled;
++ if (vwrq->value == -1) {
++ if (vwrq->disabled) {
++ priv->tx_level_dbm = 0;
++ acxlog(L_IOCTL, "disable radio tx\n");
++ } else {
++ /* priv->tx_level_auto = 1; */
++ acxlog(L_IOCTL, "set tx power auto (NIY)\n");
++ }
++ } else {
++ priv->tx_level_dbm = vwrq->value <= 20 ? vwrq->value : 20;
++ /* priv->tx_level_auto = 0; */
++ acxlog(L_IOCTL, "set txpower=%d dBm\n", priv->tx_level_dbm);
++ }
++ SET_BIT(priv->set_mask, GETSET_TXPOWER);
++
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_range
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_range(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ if (dwrq->pointer != NULL) {
++ struct iw_range *range = (struct iw_range *)extra;
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned int i;
++
++ dwrq->length = sizeof(struct iw_range);
++ memset(range, 0, sizeof(struct iw_range));
++ range->num_channels = 0;
++ for (i = 1; i <= 14; i++) {
++ if (priv->reg_dom_chanmask & (1 << (i - 1))) {
++ range->freq[range->num_channels].i = i;
++ range->freq[range->num_channels].m = acx_channel_freq[i - 1] * 100000;
++ range->freq[range->num_channels++].e = 1; /* MHz values */
++ }
++ }
++ range->num_frequency = range->num_channels;
++
++ range->min_rts = 0;
++ range->max_rts = 2312;
++ /* range->min_frag = 256;
++ * range->max_frag = 2312;
++ */
++
++ range->encoding_size[0] = 5;
++ range->encoding_size[1] = 13;
++ range->encoding_size[2] = 29;
++ range->num_encoding_sizes = 3;
++ range->max_encoding_tokens = 4;
++
++ range->min_pmp = 0;
++ range->max_pmp = 5000000;
++ range->min_pmt = 0;
++ range->max_pmt = 65535 * 1000;
++ range->pmp_flags = IW_POWER_PERIOD;
++ range->pmt_flags = IW_POWER_TIMEOUT;
++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
++
++ for (i = 0; i <= IW_MAX_TXPOWER - 1; i++)
++ range->txpower[i] = 20 * i / (IW_MAX_TXPOWER - 1);
++ range->num_txpower = IW_MAX_TXPOWER;
++ range->txpower_capa = IW_TXPOW_DBM;
++
++ range->we_version_compiled = WIRELESS_EXT;
++ range->we_version_source = 0x9;
++
++ range->retry_capa = IW_RETRY_LIMIT;
++ range->retry_flags = IW_RETRY_LIMIT;
++ range->min_retry = 1;
++ range->max_retry = 255;
++
++ range->r_time_flags = IW_RETRY_LIFETIME;
++ range->min_r_time = 0;
++ /* FIXME: lifetime ranges and orders of magnitude are strange?? */
++ range->max_r_time = 65535;
++
++ if (IS_USB(priv))
++ range->sensitivity = 0;
++ else if (IS_ACX111(priv))
++ range->sensitivity = 3;
++ else
++ range->sensitivity = 255;
++
++ for (i=0; i < priv->rate_supported_len; i++) {
++ range->bitrate[i] = (priv->rate_supported[i] & ~0x80) * 500000;
++ /* never happens, but keep it, to be safe: */
++ if (range->bitrate[i] == 0)
++ break;
++ }
++ range->num_bitrates = i;
++
++ range->max_qual.qual = 100;
++ range->max_qual.level = 100;
++ range->max_qual.noise = 100;
++ /* TODO: better values */
++ range->avg_qual.qual = 90;
++ range->avg_qual.level = 80;
++ range->avg_qual.noise = 2;
++ }
++
++ return OK;
++}
++
++
++/*================================================================*/
++/* Private functions */
++/*================================================================*/
++
++#if WIRELESS_EXT < 13
++/*----------------------------------------------------------------
++* acx_ioctl_get_iw_priv
++*
++* Comment: I added the monitor mode and changed the stuff below
++* to look more like the orinoco driver
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_iw_priv(struct iwreq *iwr)
++{
++ int result = -EINVAL;
++
++ if (!iwr->u.data.pointer)
++ return -EINVAL;
++ result = verify_area(VERIFY_WRITE, iwr->u.data.pointer,
++ sizeof(acx_ioctl_private_args));
++ if (result)
++ return result;
++
++ iwr->u.data.length = VEC_SIZE(acx_ioctl_private_args);
++ if (copy_to_user(iwr->u.data.pointer, acx_ioctl_private_args, sizeof(acx_ioctl_private_args)) != 0)
++ result = -EFAULT;
++
++ return result;
++}
++#endif
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_nick
++*----------------------------------------------------------------*/
++static inline int
++acx_ioctl_get_nick(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ /* FIXME : consider spinlock here */
++ strcpy(extra, priv->nick);
++ /* FIXME : consider spinlock here */
++
++ dwrq->length = strlen(extra) + 1;
++
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_nick
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_nick(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
++ result = -E2BIG;
++ goto end_unlock;
++ }
++
++ /* extra includes trailing \0, so it's ok */
++ strcpy(priv->nick, extra);
++ result = OK;
++
++end_unlock:
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*------------------------------------------------------------------------------
++ * acx_ioctl_get_retry
++ *----------------------------------------------------------------------------*/
++static int
++acx_ioctl_get_retry(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned int type = vwrq->flags & IW_RETRY_TYPE;
++ unsigned int modifier = vwrq->flags & IW_RETRY_MODIFIER;
++ int result;
++
++ acx_sem_lock(priv);
++
++ /* return the short retry number by default */
++ if (type == IW_RETRY_LIFETIME) {
++ vwrq->flags = IW_RETRY_LIFETIME;
++ vwrq->value = priv->msdu_lifetime;
++ } else if (modifier == IW_RETRY_MAX) {
++ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++ vwrq->value = priv->long_retry;
++ } else {
++ vwrq->flags = IW_RETRY_LIMIT;
++ if (priv->long_retry != priv->short_retry)
++ SET_BIT(vwrq->flags, IW_RETRY_MIN);
++ vwrq->value = priv->short_retry;
++ }
++
++ /* can't be disabled */
++ vwrq->disabled = (u8)0;
++ result = OK;
++
++ acx_sem_unlock(priv);
++
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_retry
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_retry(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++
++ if (!vwrq) {
++ result = -EFAULT;
++ goto end;
++ }
++ if (vwrq->disabled) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ acx_sem_lock(priv);
++
++ result = -EINVAL;
++ if (IW_RETRY_LIMIT == (vwrq->flags & IW_RETRY_TYPE)) {
++ printk("old retry limits: short %d long %d\n",
++ priv->short_retry, priv->long_retry);
++ if (vwrq->flags & IW_RETRY_MAX) {
++ priv->long_retry = vwrq->value;
++ } else if (vwrq->flags & IW_RETRY_MIN) {
++ priv->short_retry = vwrq->value;
++ } else {
++ /* no modifier: set both */
++ priv->long_retry = vwrq->value;
++ priv->short_retry = vwrq->value;
++ }
++ printk("new retry limits: short %d long %d\n",
++ priv->short_retry, priv->long_retry);
++ SET_BIT(priv->set_mask, GETSET_RETRY);
++ result = -EINPROGRESS;
++ }
++ else if (vwrq->flags & IW_RETRY_LIFETIME) {
++ priv->msdu_lifetime = vwrq->value;
++ printk("new MSDU lifetime: %d\n", priv->msdu_lifetime);
++ SET_BIT(priv->set_mask, SET_MSDU_LIFETIME);
++ result = -EINPROGRESS;
++ }
++
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/******************************* private ioctls ******************************/
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_debug
++*----------------------------------------------------------------*/
++#if ACX_DEBUG
++static int
++acx_ioctl_set_debug(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ unsigned int debug_new = *((unsigned int *)extra);
++ int result = -EINVAL;
++
++ acxlog(L_ANY, "setting debug from %04X to %04X\n", acx_debug, debug_new);
++ acx_debug = debug_new;
++
++ result = OK;
++ return result;
++
++}
++#endif
++
++/*----------------------------------------------------------------
++* acx_ioctl_list_reg_domain
++*----------------------------------------------------------------*/
++static const char * const
++reg_domain_strings[] = {
++ " 1-11 FCC (USA)",
++ " 1-11 DOC/IC (Canada)",
++ /* BTW: WLAN use in ETSI is regulated by
++ * ETSI standard EN 300 328-2 V1.1.2 */
++ " 1-13 ETSI (Europe)",
++ "10-11 Spain",
++ "10-13 France",
++ " 14 MKK (Japan)",
++ " 1-14 MKK1",
++ " 3-9 Israel (not all firmware versions)",
++ NULL /* needs to remain as last entry */
++};
++
++static int
++acx_ioctl_list_reg_domain(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++
++ int i = 1;
++ const char * const *entry = reg_domain_strings;
++
++ printk("dom# chan# domain/country\n");
++ while (*entry)
++ printk("%4d %s\n", i++, *entry++);
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_reg_domain
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_reg_domain(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++
++ if ((*extra < 1) || ((size_t)*extra > reg_domain_ids_len)) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ acx_sem_lock(priv);
++
++ priv->reg_dom_id = reg_domain_ids[*extra - 1];
++ SET_BIT(priv->set_mask, GETSET_REG_DOMAIN);
++
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_reg_domain
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_reg_domain(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int dom,i;
++
++ /* no locking */
++ dom = priv->reg_dom_id;
++
++ for (i=1; i <= 7; i++) {
++ if (reg_domain_ids[i-1] == dom) {
++ acxlog(L_IOCTL, "regulatory domain is currently set "
++ "to %d (0x%X): %s\n", i, dom,
++ reg_domain_strings[i-1]);
++ *extra = i;
++ break;
++ }
++ }
++
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_short_preamble
++*----------------------------------------------------------------*/
++static const char * const
++preamble_modes[] = {
++ "off",
++ "on",
++ "auto (peer capability dependent)",
++ "unknown mode, error"
++};
++
++static int
++acx_ioctl_set_short_preamble(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int i;
++ int result;
++
++ FN_ENTER;
++
++ if ((unsigned char)*extra > 2) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ acx_sem_lock(priv);
++
++ priv->preamble_mode = (u8)*extra;
++ switch (priv->preamble_mode) {
++ case 0: /* long */
++ priv->preamble_cur = 0;
++ break;
++ case 1:
++ /* short, kick incapable peers */
++ priv->preamble_cur = 1;
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ client_t *clt = &priv->sta_list[i];
++ if (!clt->used) continue;
++ if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) {
++ clt->used = CLIENT_EMPTY_SLOT_0;
++ }
++ }
++ switch (priv->mode) {
++ case ACX_MODE_2_STA:
++ if (priv->ap_client && !priv->ap_client->used) {
++ /* We kicked our AP :) */
++ SET_BIT(priv->set_mask, GETSET_RESCAN);
++ }
++ }
++ break;
++ case 2: /* auto. short only if all peers are short-capable */
++ priv->preamble_cur = 1;
++ for (i = 0; i < VEC_SIZE(priv->sta_list); i++) {
++ client_t *clt = &priv->sta_list[i];
++ if (!clt->used) continue;
++ if (!(clt->cap_info & WF_MGMT_CAP_SHORT)) {
++ priv->preamble_cur = 0;
++ break;
++ }
++ }
++ break;
++ }
++ printk("new short preamble setting: configured %s, active %s\n",
++ preamble_modes[priv->preamble_mode],
++ preamble_modes[priv->preamble_cur]);
++ result = OK;
++
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_short_preamble
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_short_preamble(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ printk("current short preamble setting: configured %s, active %s\n",
++ preamble_modes[priv->preamble_mode],
++ preamble_modes[priv->preamble_cur]);
++
++ *extra = (char)priv->preamble_mode;
++
++ acx_sem_unlock(priv);
++
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_antenna
++*
++* Comment: TX and RX antenna can be set separately but this function good
++* for testing 0-4 bits
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_antenna(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ printk("old antenna value: 0x%02X (COMBINED bit mask)\n"
++ "Rx antenna selection:\n"
++ "0x00 ant. 1\n"
++ "0x40 ant. 2\n"
++ "0x80 full diversity\n"
++ "0xc0 partial diversity\n"
++ "0x0f dwell time mask (in units of us)\n"
++ "Tx antenna selection:\n"
++ "0x00 ant. 2\n" /* yep, those ARE reversed! */
++ "0x20 ant. 1\n"
++ "new antenna value: 0x%02X\n",
++ priv->antenna, (u8)*extra);
++
++ priv->antenna = (u8)*extra;
++ SET_BIT(priv->set_mask, GETSET_ANTENNA);
++
++ acx_sem_unlock(priv);
++
++ return -EINPROGRESS;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_antenna
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_antenna(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ /* no locking. it's pointless to lock a single load */
++ printk("current antenna value: 0x%02X (COMBINED bit mask)\n"
++ "Rx antenna selection:\n"
++ "0x00 ant. 1\n"
++ "0x40 ant. 2\n"
++ "0x80 full diversity\n"
++ "0xc0 partial diversity\n"
++ "Tx antenna selection:\n"
++ "0x00 ant. 2\n" /* yep, those ARE reversed! */
++ "0x20 ant. 1\n", priv->antenna);
++
++ return 0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_rx_antenna
++*
++*
++* Arguments:
++* 0 = antenna1; 1 = antenna2; 2 = full diversity; 3 = partial diversity
++* Comment: Could anybody test which antenna is the external one
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_rx_antenna(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++
++ if (*extra > 3) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ printk("old antenna value: 0x%02X\n", priv->antenna);
++
++ acx_sem_lock(priv);
++
++ priv->antenna &= 0x3f;
++ SET_BIT(priv->antenna, (*extra << 6));
++ SET_BIT(priv->set_mask, GETSET_ANTENNA);
++ printk("new antenna value: 0x%02X\n", priv->antenna);
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_tx_antenna
++*
++*
++* Arguments: 0 == antenna2; 1 == antenna1;
++* Comment: Could anybody test which antenna is the external one
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_set_tx_antenna(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ FN_ENTER;
++
++ if (*extra > 1) {
++ result = -EINVAL;
++ goto end;
++ }
++
++ printk("old antenna value: 0x%02X\n", priv->antenna);
++
++ acx_sem_lock(priv);
++
++ priv->antenna &= ~0x30;
++ SET_BIT(priv->antenna, ((*extra & 0x01) << 5));
++ SET_BIT(priv->set_mask, GETSET_ANTENNA);
++ printk("new antenna value: 0x%02X\n", priv->antenna);
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_wlansniff
++*
++* can we just remove this in favor of monitor mode? --vda
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_wlansniff(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned int *params = (unsigned int*)extra;
++ unsigned int enable = (unsigned int)(params[0] > 0);
++ int result;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ /* not using printk() here, since it distorts kismet display
++ * when printk messages activated */
++ acxlog(L_IOCTL, "setting monitor to: 0x%02X\n", params[0]);
++
++ switch (params[0]) {
++ case 0:
++ priv->netdev->type = ARPHRD_ETHER;
++ break;
++ case 1:
++ priv->netdev->type = ARPHRD_IEEE80211_PRISM;
++ break;
++ case 2:
++ priv->netdev->type = ARPHRD_IEEE80211;
++ break;
++ }
++
++ if (params[0]) {
++ priv->mode = ACX_MODE_MONITOR;
++ SET_BIT(priv->set_mask, GETSET_MODE);
++ }
++
++ if (enable) {
++ priv->channel = params[1];
++ SET_BIT(priv->set_mask, GETSET_RX);
++ }
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_unknown11
++* FIXME: looks like some sort of "iwpriv kick_sta MAC" but it's broken
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_unknown11(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++#ifdef BROKEN
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ client_t client;
++ int result;
++
++ acx_sem_lock(priv);
++ acx_lock(priv, flags);
++
++ acx_l_transmit_disassoc(priv, &client);
++ result = OK;
++
++ acx_unlock(priv, flags);
++ acx_sem_unlock(priv);
++
++ return result;
++#endif
++ return -EINVAL;
++}
++
++
++/***********************************************************************
++** debug helper function to be able to debug various issues relatively easily
++*/
++static int
++acx_ioctl_dbg_set_masks(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ const unsigned int *params = (unsigned int*)extra;
++ int result;
++
++ acx_sem_lock(priv);
++
++ acxlog(L_IOCTL, "setting flags in settings mask: "
++ "get_mask %08X set_mask %08X\n"
++ "before: get_mask %08X set_mask %08X\n",
++ params[0], params[1],
++ priv->get_mask, priv->set_mask);
++ SET_BIT(priv->get_mask, params[0]);
++ SET_BIT(priv->set_mask, params[1]);
++ acxlog(L_IOCTL, "after: get_mask %08X set_mask %08X\n",
++ priv->get_mask, priv->set_mask);
++ result = -EINPROGRESS; /* immediately call commit handler */
++
++ acx_sem_unlock(priv);
++
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_rates
++*
++* This ioctl takes string parameter. Examples:
++* iwpriv wlan0 SetRates "1,2"
++* use 1 and 2 Mbit rates, both are in basic rate set
++* iwpriv wlan0 SetRates "1,2 5,11"
++* use 1,2,5.5,11 Mbit rates. 1 and 2 are basic
++* iwpriv wlan0 SetRates "1,2 5c,11c"
++* same ('c' means 'CCK modulation' and it is a default for 5 and 11)
++* iwpriv wlan0 SetRates "1,2 5p,11p"
++* use 1,2,5.5,11 Mbit, 1,2 are basic. 5 and 11 are using PBCC
++* iwpriv wlan0 SetRates "1,2,5,11 22p"
++* use 1,2,5.5,11,22 Mbit. 1,2,5.5 and 11 are basic. 22 is using PBCC
++* (this is the maximum acx100 can do (modulo x4 mode))
++* iwpriv wlan0 SetRates "1,2,5,11 22"
++* same. 802.11 defines only PBCC modulation
++* for 22 and 33 Mbit rates, so there is no ambiguity
++* iwpriv wlan0 SetRates "1,2,5,11 6o,9o,12o,18o,24o,36o,48o,54o"
++* 1,2,5.5 and 11 are basic. 11g OFDM rates are enabled but
++* they are not in basic rate set. 22 Mbit is disabled.
++* iwpriv wlan0 SetRates "1,2,5,11 6,9,12,18,24,36,48,54"
++* same. OFDM is default for 11g rates except 22 and 33 Mbit,
++* thus 'o' is optional
++* iwpriv wlan0 SetRates "1,2,5,11 6d,9d,12d,18d,24d,36d,48d,54d"
++* 1,2,5.5 and 11 are basic. 11g CCK-OFDM rates are enabled
++* (acx111 does not support CCK-OFDM, driver will reject this cmd)
++* iwpriv wlan0 SetRates "6,9,12 18,24,36,48,54"
++* 6,9,12 are basic, rest of 11g rates is enabled. Using OFDM
++*----------------------------------------------------------------*/
++#include "setrate.c"
++
++/* disallow: 33Mbit (unsupported by hw) */
++/* disallow: CCKOFDM (unsupported by hw) */
++static int
++acx111_supported(int mbit, int modulation, void *opaque)
++{
++ if (mbit==33) return -ENOTSUPP;
++ if (modulation==DOT11_MOD_CCKOFDM) return -ENOTSUPP;
++ return OK;
++}
++
++static const u16
++acx111mask[] = {
++ [DOT11_RATE_1 ] = RATE111_1 ,
++ [DOT11_RATE_2 ] = RATE111_2 ,
++ [DOT11_RATE_5 ] = RATE111_5 ,
++ [DOT11_RATE_11] = RATE111_11,
++ [DOT11_RATE_22] = RATE111_22,
++ /* [DOT11_RATE_33] = */
++ [DOT11_RATE_6 ] = RATE111_6 ,
++ [DOT11_RATE_9 ] = RATE111_9 ,
++ [DOT11_RATE_12] = RATE111_12,
++ [DOT11_RATE_18] = RATE111_18,
++ [DOT11_RATE_24] = RATE111_24,
++ [DOT11_RATE_36] = RATE111_36,
++ [DOT11_RATE_48] = RATE111_48,
++ [DOT11_RATE_54] = RATE111_54,
++};
++
++static u32
++acx111_gen_mask(int mbit, int modulation, void *opaque)
++{
++ /* lower 16 bits show selected 1, 2, CCK and OFDM rates */
++ /* upper 16 bits show selected PBCC rates */
++ u32 m = acx111mask[rate_mbit2enum(mbit)];
++ if (modulation==DOT11_MOD_PBCC)
++ return m<<16;
++ return m;
++}
++
++static int
++verify_rate(u32 rate, int chip_type)
++{
++ /* never happens. be paranoid */
++ if (!rate) return -EINVAL;
++
++ /* disallow: mixing PBCC and CCK at 5 and 11Mbit
++ ** (can be supported, but needs complicated handling in tx code) */
++ if (( rate & ((RATE111_11+RATE111_5)<<16) )
++ && ( rate & (RATE111_11+RATE111_5) )
++ ) {
++ return -ENOTSUPP;
++ }
++ if (CHIPTYPE_ACX100 == chip_type) {
++ if ( rate & ~(RATE111_ACX100_COMPAT+(RATE111_ACX100_COMPAT<<16)) )
++ return -ENOTSUPP;
++ }
++ return 0;
++}
++
++static int
++acx_ioctl_set_rates(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ int result;
++ u32 brate = 0, orate = 0; /* basic, operational rate set */
++
++ FN_ENTER;
++
++ acxlog(L_IOCTL, "set_rates %s\n", extra);
++ result = fill_ratemasks(extra, &brate, &orate,
++ acx111_supported, acx111_gen_mask, 0);
++ if (result) goto end;
++ SET_BIT(orate, brate);
++ acxlog(L_IOCTL, "brate %08X orate %08X\n", brate, orate);
++
++ result = verify_rate(brate, priv->chip_type);
++ if (result) goto end;
++ result = verify_rate(orate, priv->chip_type);
++ if (result) goto end;
++
++ acx_sem_lock(priv);
++ acx_lock(priv, flags);
++
++ priv->rate_basic = brate;
++ priv->rate_oper = orate;
++ /* TODO: ideally, we shall monitor highest basic rate
++ ** which was successfully sent to every peer
++ ** (say, last we checked, everybody could hear 5.5 Mbits)
++ ** and use that for bcasts when we want to reach all peers.
++ ** For beacons, we probably shall use lowest basic rate
++ ** because we want to reach all *potential* new peers too */
++ priv->rate_bcast = 1 << lowest_bit(brate);
++ if (IS_ACX100(priv))
++ priv->rate_bcast100 = acx_rate111to100(priv->rate_bcast);
++ priv->rate_auto = !has_only_one_bit(orate);
++ acx_l_update_client_rates(priv, orate);
++ /* TODO: get rid of ratevector, build it only when needed */
++ acx_l_update_ratevector(priv);
++
++ /* Do/don't do tx rate fallback; beacon contents and rate */
++ SET_BIT(priv->set_mask, SET_RATE_FALLBACK|SET_TEMPLATES);
++ result = -EINPROGRESS;
++
++ acx_unlock(priv, flags);
++ acx_sem_unlock(priv);
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_get_phy_chan_busy_percentage
++*----------------------------------------------------------------*/
++static int
++acx_ioctl_get_phy_chan_busy_percentage(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ struct { /* added ACX_PACKED, not tested --vda */
++ u16 type ACX_PACKED;
++ u16 len ACX_PACKED;
++ u32 busytime ACX_PACKED;
++ u32 totaltime ACX_PACKED;
++ } usage;
++
++ acx_sem_lock(priv);
++
++ if (OK != acx_s_interrogate(priv, &usage, ACX1xx_IE_MEDIUM_USAGE))
++ goto bad_unlock;
++
++ printk("%s: average busy percentage since last invocation: %d%% "
++ "(microseconds: %u of %u)\n",
++ dev->name,
++ 100 * (le32_to_cpu(usage.busytime) / 100) / (le32_to_cpu(usage.totaltime) / 100),
++ le32_to_cpu(usage.busytime), le32_to_cpu(usage.totaltime));
++ /* prevent calculation overflow */
++
++ acx_sem_unlock(priv);
++
++ return OK;
++
++bad_unlock:
++ acx_sem_unlock(priv);
++
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_ed_threshold
++*----------------------------------------------------------------*/
++static inline int
++acx_ioctl_set_ed_threshold(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ printk("old ED threshold value: %d\n", priv->ed_threshold);
++ priv->ed_threshold = (unsigned char)*extra;
++ printk("new ED threshold value: %d\n", (unsigned char)*extra);
++ SET_BIT(priv->set_mask, GETSET_ED_THRESH);
++
++ acx_sem_unlock(priv);
++
++ return -EINPROGRESS;
++}
++
++
++/*----------------------------------------------------------------
++* acx_ioctl_set_cca
++*----------------------------------------------------------------*/
++static inline int
++acx_ioctl_set_cca(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ acx_sem_lock(priv);
++
++ printk("old CCA value: 0x%02X\n", priv->cca);
++ priv->cca = (unsigned char)*extra;
++ printk("new CCA value: 0x%02X\n", (unsigned char)*extra);
++ SET_BIT(priv->set_mask, GETSET_CCA);
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static const char * const
++scan_modes[] = { "active", "passive", "background" };
++
++static void
++acx_print_scan_params(wlandevice_t *priv, const char* head)
++{
++ printk("%s: %smode %d (%s), min chan time %dTU, "
++ "max chan time %dTU, max scan rate byte: %d\n",
++ priv->netdev->name, head,
++ priv->scan_mode, scan_modes[priv->scan_mode],
++ priv->scan_probe_delay, priv->scan_duration, priv->scan_rate);
++}
++
++static int
++acx_ioctl_set_scan_params(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++ const int *params = (int *)extra;
++
++ acx_sem_lock(priv);
++
++ acx_print_scan_params(priv, "old scan parameters: ");
++ if ((params[0] != -1) && (params[0] >= 0) && (params[0] <= 2))
++ priv->scan_mode = params[0];
++ if (params[1] != -1)
++ priv->scan_probe_delay = params[1];
++ if (params[2] != -1)
++ priv->scan_duration = params[2];
++ if ((params[3] != -1) && (params[3] <= 255))
++ priv->scan_rate = params[3];
++ acx_print_scan_params(priv, "new scan parameters: ");
++ SET_BIT(priv->set_mask, GETSET_RESCAN);
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++
++ return result;
++}
++
++static int
++acx_ioctl_get_scan_params(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++ int *params = (int *)extra;
++
++ acx_sem_lock(priv);
++
++ acx_print_scan_params(priv, "current scan parameters: ");
++ params[0] = priv->scan_mode;
++ params[1] = priv->scan_probe_delay;
++ params[2] = priv->scan_duration;
++ params[3] = priv->scan_rate;
++ result = OK;
++
++ acx_sem_unlock(priv);
++
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx100_ioctl_set_led_power(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ static const char * const led_modes[] = { "off", "on", "LinkQuality" };
++
++ wlandevice_t *priv = netdev_priv(dev);
++ int result;
++
++ acx_sem_lock(priv);
++
++ printk("%s: power LED status: old %d (%s), ",
++ dev->name,
++ priv->led_power,
++ led_modes[priv->led_power]);
++ priv->led_power = extra[0];
++ if (priv->led_power > 2) priv->led_power = 2;
++ printk("new %d (%s)\n",
++ priv->led_power,
++ led_modes[priv->led_power]);
++
++ if (priv->led_power == 2) {
++ printk("%s: max link quality setting: old %d, ",
++ dev->name, priv->brange_max_quality);
++ if (extra[1])
++ priv->brange_max_quality = extra[1];
++ printk("new %d\n", priv->brange_max_quality);
++ }
++
++ SET_BIT(priv->set_mask, GETSET_LED_POWER);
++
++ result = -EINPROGRESS;
++
++ acx_sem_unlock(priv);
++
++ return result;
++}
++
++
++/***********************************************************************
++*/
++static inline int
++acx100_ioctl_get_led_power(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ extra[0] = priv->led_power;
++ if (priv->led_power == 2)
++ extra[1] = priv->brange_max_quality;
++ else
++ extra[1] = -1;
++
++ acx_sem_unlock(priv);
++
++ return OK;
++}
++
++
++/***********************************************************************
++*/
++static int
++acx111_ioctl_info(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ if (!IS_PCI((wlandevice_t*)netdev_priv(dev)))
++ return OK;
++ return acx111pci_ioctl_info(dev, info, vwrq, extra);
++}
++
++
++/***********************************************************************
++*/
++static int
++acx100_ioctl_set_phy_amp_bias(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ if (!IS_PCI((wlandevice_t*)netdev_priv(dev))) {
++ printk("acx: set_phy_amp_bias() is not supported on USB\n");
++ return OK;
++ }
++ return acx100pci_ioctl_set_phy_amp_bias(dev, info, vwrq, extra);
++}
++
++
++/***********************************************************************
++*/
++#if WIRELESS_EXT >= 13
++static const iw_handler acx_ioctl_handler[] =
++{
++ (iw_handler) acx_ioctl_commit, /* SIOCSIWCOMMIT */
++ (iw_handler) acx_ioctl_get_name, /* SIOCGIWNAME */
++ (iw_handler) NULL, /* SIOCSIWNWID */
++ (iw_handler) NULL, /* SIOCGIWNWID */
++ (iw_handler) acx_ioctl_set_freq, /* SIOCSIWFREQ */
++ (iw_handler) acx_ioctl_get_freq, /* SIOCGIWFREQ */
++ (iw_handler) acx_ioctl_set_mode, /* SIOCSIWMODE */
++ (iw_handler) acx_ioctl_get_mode, /* SIOCGIWMODE */
++ (iw_handler) acx_ioctl_set_sens, /* SIOCSIWSENS */
++ (iw_handler) acx_ioctl_get_sens, /* SIOCGIWSENS */
++ (iw_handler) NULL, /* SIOCSIWRANGE */
++ (iw_handler) acx_ioctl_get_range, /* SIOCGIWRANGE */
++ (iw_handler) NULL, /* SIOCSIWPRIV */
++ (iw_handler) NULL, /* SIOCGIWPRIV */
++ (iw_handler) NULL, /* SIOCSIWSTATS */
++ (iw_handler) NULL, /* SIOCGIWSTATS */
++#if IW_HANDLER_VERSION > 4
++ iw_handler_set_spy, /* SIOCSIWSPY */
++ iw_handler_get_spy, /* SIOCGIWSPY */
++ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
++ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
++#else /* IW_HANDLER_VERSION > 4 */
++#ifdef WIRELESS_SPY
++ (iw_handler) NULL /* acx_ioctl_set_spy FIXME */, /* SIOCSIWSPY */
++ (iw_handler) NULL /* acx_ioctl_get_spy FIXME */, /* SIOCGIWSPY */
++#else /* WSPY */
++ (iw_handler) NULL, /* SIOCSIWSPY */
++ (iw_handler) NULL, /* SIOCGIWSPY */
++#endif /* WSPY */
++ (iw_handler) NULL, /* [nothing] */
++ (iw_handler) NULL, /* [nothing] */
++#endif /* IW_HANDLER_VERSION > 4 */
++ (iw_handler) acx_ioctl_set_ap, /* SIOCSIWAP */
++ (iw_handler) acx_ioctl_get_ap, /* SIOCGIWAP */
++ (iw_handler) NULL, /* [nothing] */
++ (iw_handler) acx_ioctl_get_aplist, /* SIOCGIWAPLIST */
++#if WIRELESS_EXT > 13
++ (iw_handler) acx_ioctl_set_scan, /* SIOCSIWSCAN */
++ (iw_handler) acx_ioctl_get_scan, /* SIOCGIWSCAN */
++#else /* WE > 13 */
++ (iw_handler) NULL, /* SIOCSIWSCAN */
++ (iw_handler) NULL, /* SIOCGIWSCAN */
++#endif /* WE > 13 */
++ (iw_handler) acx_ioctl_set_essid, /* SIOCSIWESSID */
++ (iw_handler) acx_ioctl_get_essid, /* SIOCGIWESSID */
++ (iw_handler) acx_ioctl_set_nick, /* SIOCSIWNICKN */
++ (iw_handler) acx_ioctl_get_nick, /* SIOCGIWNICKN */
++ (iw_handler) NULL, /* [nothing] */
++ (iw_handler) NULL, /* [nothing] */
++ (iw_handler) acx_ioctl_set_rate, /* SIOCSIWRATE */
++ (iw_handler) acx_ioctl_get_rate, /* SIOCGIWRATE */
++ (iw_handler) acx_ioctl_set_rts, /* SIOCSIWRTS */
++ (iw_handler) acx_ioctl_get_rts, /* SIOCGIWRTS */
++ (iw_handler) NULL /* acx_ioctl_set_frag FIXME */, /* SIOCSIWFRAG */
++ (iw_handler) NULL /* acx_ioctl_get_frag FIXME */, /* SIOCGIWFRAG */
++ (iw_handler) acx_ioctl_set_txpow, /* SIOCSIWTXPOW */
++ (iw_handler) acx_ioctl_get_txpow, /* SIOCGIWTXPOW */
++ (iw_handler) acx_ioctl_set_retry, /* SIOCSIWRETRY */
++ (iw_handler) acx_ioctl_get_retry, /* SIOCGIWRETRY */
++ (iw_handler) acx_ioctl_set_encode, /* SIOCSIWENCODE */
++ (iw_handler) acx_ioctl_get_encode, /* SIOCGIWENCODE */
++ (iw_handler) acx_ioctl_set_power, /* SIOCSIWPOWER */
++ (iw_handler) acx_ioctl_get_power, /* SIOCGIWPOWER */
++};
++
++static const iw_handler acx_ioctl_private_handler[] =
++{
++#if ACX_DEBUG
++[ACX100_IOCTL_DEBUG - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_debug,
++#else
++[ACX100_IOCTL_DEBUG - ACX100_IOCTL] = (iw_handler) NULL,
++#endif
++[ACX100_IOCTL_SET_PLED - ACX100_IOCTL] = (iw_handler) acx100_ioctl_set_led_power,
++[ACX100_IOCTL_GET_PLED - ACX100_IOCTL] = (iw_handler) acx100_ioctl_get_led_power,
++[ACX100_IOCTL_SET_RATES - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_rates,
++[ACX100_IOCTL_LIST_DOM - ACX100_IOCTL] = (iw_handler) acx_ioctl_list_reg_domain,
++[ACX100_IOCTL_SET_DOM - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_reg_domain,
++[ACX100_IOCTL_GET_DOM - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_reg_domain,
++[ACX100_IOCTL_SET_SCAN_PARAMS - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_scan_params,
++[ACX100_IOCTL_GET_SCAN_PARAMS - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_scan_params,
++[ACX100_IOCTL_SET_PREAMB - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_short_preamble,
++[ACX100_IOCTL_GET_PREAMB - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_short_preamble,
++[ACX100_IOCTL_SET_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_antenna,
++[ACX100_IOCTL_GET_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_antenna,
++[ACX100_IOCTL_RX_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_rx_antenna,
++[ACX100_IOCTL_TX_ANT - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_tx_antenna,
++[ACX100_IOCTL_SET_PHY_AMP_BIAS - ACX100_IOCTL] = (iw_handler) acx100_ioctl_set_phy_amp_bias,
++[ACX100_IOCTL_GET_PHY_CHAN_BUSY - ACX100_IOCTL] = (iw_handler) acx_ioctl_get_phy_chan_busy_percentage,
++[ACX100_IOCTL_SET_ED - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_ed_threshold,
++[ACX100_IOCTL_SET_CCA - ACX100_IOCTL] = (iw_handler) acx_ioctl_set_cca,
++[ACX100_IOCTL_MONITOR - ACX100_IOCTL] = (iw_handler) acx_ioctl_wlansniff,
++[ACX100_IOCTL_TEST - ACX100_IOCTL] = (iw_handler) acx_ioctl_unknown11,
++[ACX100_IOCTL_DBG_SET_MASKS - ACX100_IOCTL] = (iw_handler) acx_ioctl_dbg_set_masks,
++[ACX111_IOCTL_INFO - ACX100_IOCTL] = (iw_handler) acx111_ioctl_info,
++};
++
++const struct iw_handler_def acx_ioctl_handler_def =
++{
++ .num_standard = VEC_SIZE(acx_ioctl_handler),
++ .num_private = VEC_SIZE(acx_ioctl_private_handler),
++ .num_private_args = VEC_SIZE(acx_ioctl_private_args),
++ .standard = (iw_handler *) acx_ioctl_handler,
++ .private = (iw_handler *) acx_ioctl_private_handler,
++ .private_args = (struct iw_priv_args *) acx_ioctl_private_args,
++};
++
++#endif /* WE >= 13 */
++
++
++#if WIRELESS_EXT < 13
++/*================================================================*/
++/* Main function */
++/*================================================================*/
++/*----------------------------------------------------------------
++* acx_e_ioctl_old
++*
++* Comment:
++* This is the *OLD* ioctl handler.
++* Make sure to not only place your additions here, but instead mainly
++* in the new one (acx_ioctl_handler[])!
++*----------------------------------------------------------------*/
++int
++acx_e_ioctl_old(netdevice_t *dev, struct ifreq *ifr, int cmd)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result = 0;
++ struct iwreq *iwr = (struct iwreq *)ifr;
++
++ acxlog(L_IOCTL, "%s cmd = 0x%04X\n", __func__, cmd);
++
++ /* This is the way it is done in the orinoco driver.
++ * Check to see if device is present.
++ */
++ if (0 == netif_device_present(dev)) {
++ return -ENODEV;
++ }
++
++ switch (cmd) {
++/* WE 13 and higher will use acx_ioctl_handler_def */
++ case SIOCGIWNAME:
++ /* get name == wireless protocol */
++ result = acx_ioctl_get_name(dev, NULL,
++ (char *)&(iwr->u.name), NULL);
++ break;
++
++ case SIOCSIWNWID: /* pre-802.11, */
++ case SIOCGIWNWID: /* not supported. */
++ result = -EOPNOTSUPP;
++ break;
++
++ case SIOCSIWFREQ:
++ /* set channel/frequency (Hz)
++ data can be frequency or channel :
++ 0-1000 = channel
++ > 1000 = frequency in Hz */
++ result = acx_ioctl_set_freq(dev, NULL, &(iwr->u.freq), NULL);
++ break;
++
++ case SIOCGIWFREQ:
++ /* get channel/frequency (Hz) */
++ result = acx_ioctl_get_freq(dev, NULL, &(iwr->u.freq), NULL);
++ break;
++
++ case SIOCSIWMODE:
++ /* set operation mode */
++ result = acx_ioctl_set_mode(dev, NULL, &(iwr->u.mode), NULL);
++ break;
++
++ case SIOCGIWMODE:
++ /* get operation mode */
++ result = acx_ioctl_get_mode(dev, NULL, &(iwr->u.mode), NULL);
++ break;
++
++ case SIOCSIWSENS:
++ /* Set sensitivity */
++ result = acx_ioctl_set_sens(dev, NULL, &(iwr->u.sens), NULL);
++ break;
++
++ case SIOCGIWSENS:
++ /* Get sensitivity */
++ result = acx_ioctl_get_sens(dev, NULL, &(iwr->u.sens), NULL);
++ break;
++
++#if WIRELESS_EXT > 10
++ case SIOCGIWRANGE:
++ /* Get range of parameters */
++ {
++ struct iw_range range;
++ result = acx_ioctl_get_range(dev, NULL,
++ &(iwr->u.data), (char *)&range);
++ if (copy_to_user(iwr->u.data.pointer, &range,
++ sizeof(struct iw_range)))
++ result = -EFAULT;
++ }
++ break;
++#endif
++
++ case SIOCGIWPRIV:
++ result = acx_ioctl_get_iw_priv(iwr);
++ break;
++
++ /* FIXME: */
++ /* case SIOCSIWSPY: */
++ /* case SIOCGIWSPY: */
++ /* case SIOCSIWTHRSPY: */
++ /* case SIOCGIWTHRSPY: */
++
++ case SIOCSIWAP:
++ /* set access point by MAC address */
++ result = acx_ioctl_set_ap(dev, NULL, &(iwr->u.ap_addr),
++ NULL);
++ break;
++
++ case SIOCGIWAP:
++ /* get access point MAC address */
++ result = acx_ioctl_get_ap(dev, NULL, &(iwr->u.ap_addr),
++ NULL);
++ break;
++
++ case SIOCGIWAPLIST:
++ /* get list of access points in range */
++ result = acx_ioctl_get_aplist(dev, NULL, &(iwr->u.data),
++ NULL);
++ break;
++
++#if NOT_FINISHED_YET
++ /* FIXME: do proper interfacing to activate that! */
++ case SIOCSIWSCAN:
++ /* start a station scan */
++ result = acx_ioctl_set_scan(iwr, priv);
++ break;
++
++ case SIOCGIWSCAN:
++ /* get list of stations found during scan */
++ result = acx_ioctl_get_scan(iwr, priv);
++ break;
++#endif
++
++ case SIOCSIWESSID:
++ /* set ESSID (network name) */
++ {
++ char essid[IW_ESSID_MAX_SIZE+1];
++
++ if (iwr->u.essid.length > IW_ESSID_MAX_SIZE)
++ {
++ result = -E2BIG;
++ break;
++ }
++ if (copy_from_user(essid, iwr->u.essid.pointer,
++ iwr->u.essid.length))
++ {
++ result = -EFAULT;
++ break;
++ }
++ result = acx_ioctl_set_essid(dev, NULL,
++ &(iwr->u.essid), essid);
++ }
++ break;
++
++ case SIOCGIWESSID:
++ /* get ESSID */
++ {
++ char essid[IW_ESSID_MAX_SIZE+1];
++ if (iwr->u.essid.pointer)
++ result = acx_ioctl_get_essid(dev, NULL,
++ &(iwr->u.essid), essid);
++ if (copy_to_user(iwr->u.essid.pointer, essid,
++ iwr->u.essid.length))
++ result = -EFAULT;
++ }
++ break;
++
++ case SIOCSIWNICKN:
++ /* set nick */
++ {
++ char nick[IW_ESSID_MAX_SIZE+1];
++
++ if (iwr->u.data.length > IW_ESSID_MAX_SIZE)
++ {
++ result = -E2BIG;
++ break;
++ }
++ if (copy_from_user(nick, iwr->u.data.pointer,
++ iwr->u.data.length))
++ {
++ result = -EFAULT;
++ break;
++ }
++ result = acx_ioctl_set_nick(dev, NULL,
++ &(iwr->u.data), nick);
++ }
++ break;
++
++ case SIOCGIWNICKN:
++ /* get nick */
++ {
++ char nick[IW_ESSID_MAX_SIZE+1];
++ if (iwr->u.data.pointer)
++ result = acx_ioctl_get_nick(dev, NULL,
++ &(iwr->u.data), nick);
++ if (copy_to_user(iwr->u.data.pointer, nick,
++ iwr->u.data.length))
++ result = -EFAULT;
++ }
++ break;
++
++ case SIOCSIWRATE:
++ /* set default bit rate (bps) */
++ result = acx_ioctl_set_rate(dev, NULL, &(iwr->u.bitrate),
++ NULL);
++ break;
++
++ case SIOCGIWRATE:
++ /* get default bit rate (bps) */
++ result = acx_ioctl_get_rate(dev, NULL, &(iwr->u.bitrate),
++ NULL);
++ break;
++
++ case SIOCSIWRTS:
++ /* set RTS threshold value */
++ result = acx_ioctl_set_rts(dev, NULL, &(iwr->u.rts), NULL);
++ break;
++ case SIOCGIWRTS:
++ /* get RTS threshold value */
++ result = acx_ioctl_get_rts(dev, NULL, &(iwr->u.rts), NULL);
++ break;
++
++ /* FIXME: */
++ /* case SIOCSIWFRAG: */
++ /* case SIOCGIWFRAG: */
++
++#if WIRELESS_EXT > 9
++ case SIOCGIWTXPOW:
++ /* get tx power */
++ result = acx_ioctl_get_txpow(dev, NULL, &(iwr->u.txpower),
++ NULL);
++ break;
++
++ case SIOCSIWTXPOW:
++ /* set tx power */
++ result = acx_ioctl_set_txpow(dev, NULL, &(iwr->u.txpower),
++ NULL);
++ break;
++#endif
++
++ case SIOCSIWRETRY:
++ result = acx_ioctl_set_retry(dev, NULL, &(iwr->u.retry), NULL);
++ break;
++
++ case SIOCGIWRETRY:
++ result = acx_ioctl_get_retry(dev, NULL, &(iwr->u.retry), NULL);
++ break;
++
++ case SIOCSIWENCODE:
++ {
++ /* set encoding token & mode */
++ u8 key[29];
++ if (iwr->u.encoding.pointer) {
++ if (iwr->u.encoding.length > 29) {
++ result = -E2BIG;
++ break;
++ }
++ if (copy_from_user(key, iwr->u.encoding.pointer,
++ iwr->u.encoding.length)) {
++ result = -EFAULT;
++ break;
++ }
++ }
++ else
++ if (iwr->u.encoding.length) {
++ result = -EINVAL;
++ break;
++ }
++ result = acx_ioctl_set_encode(dev, NULL,
++ &(iwr->u.encoding), key);
++ }
++ break;
++
++ case SIOCGIWENCODE:
++ {
++ /* get encoding token & mode */
++ u8 key[29];
++
++ result = acx_ioctl_get_encode(dev, NULL,
++ &(iwr->u.encoding), key);
++ if (iwr->u.encoding.pointer) {
++ if (copy_to_user(iwr->u.encoding.pointer,
++ key, iwr->u.encoding.length))
++ result = -EFAULT;
++ }
++ }
++ break;
++
++ /******************** iwpriv ioctls below ********************/
++#if ACX_DEBUG
++ case ACX100_IOCTL_DEBUG:
++ acx_ioctl_set_debug(dev, NULL, NULL, iwr->u.name);
++ break;
++#endif
++
++ case ACX100_IOCTL_SET_PLED:
++ acx100_ioctl_set_led_power(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_GET_PLED:
++ acx100_ioctl_get_led_power(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_LIST_DOM:
++ acx_ioctl_list_reg_domain(dev, NULL, NULL, NULL);
++ break;
++
++ case ACX100_IOCTL_SET_DOM:
++ acx_ioctl_set_reg_domain(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_GET_DOM:
++ acx_ioctl_get_reg_domain(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_SET_SCAN_PARAMS:
++ acx_ioctl_set_scan_params(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_GET_SCAN_PARAMS:
++ acx_ioctl_get_scan_params(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_SET_PREAMB:
++ acx_ioctl_set_short_preamble(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_GET_PREAMB:
++ acx_ioctl_get_short_preamble(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_SET_ANT:
++ acx_ioctl_set_antenna(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_GET_ANT:
++ acx_ioctl_get_antenna(dev, NULL, NULL, NULL);
++ break;
++
++ case ACX100_IOCTL_RX_ANT:
++ acx_ioctl_set_rx_antenna(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_TX_ANT:
++ acx_ioctl_set_tx_antenna(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_SET_ED:
++ acx_ioctl_set_ed_threshold(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_SET_CCA:
++ acx_ioctl_set_cca(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_MONITOR: /* set sniff (monitor) mode */
++ acxlog(L_IOCTL, "%s: IWPRIV monitor\n", dev->name);
++
++ /* can only be done by admin */
++ if (!capable(CAP_NET_ADMIN)) {
++ result = -EPERM;
++ break;
++ }
++ result = acx_ioctl_wlansniff(dev, NULL, NULL, iwr->u.name);
++ break;
++
++ case ACX100_IOCTL_TEST:
++ acx_ioctl_unknown11(dev, NULL, NULL, NULL);
++ break;
++
++ case ACX111_IOCTL_INFO:
++ acx111_ioctl_info(dev, NULL, NULL, NULL);
++ break;
++
++ default:
++ acxlog(L_IOCTL, "wireless ioctl 0x%04X queried "
++ "but not implemented yet\n", cmd);
++ result = -EOPNOTSUPP;
++ break;
++ }
++
++ if ((priv->dev_state_mask & ACX_STATE_IFACE_UP) && priv->set_mask) {
++ acx_sem_lock(priv);
++ acx_s_update_card_settings(priv, 0, 0);
++ acx_sem_unlock(priv);
++ }
++
++ /* older WEs don't have a commit handler,
++ * so we need to fix return code in this case */
++ if (-EINPROGRESS == result)
++ result = 0;
++
++ return result;
++}
++#endif /* WE < 13 */
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/Kconfig linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/Kconfig
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/Kconfig 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/Kconfig 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,59 @@
++config ACX
++ tristate "TI acx100/acx111 802.11b/g wireless chipsets"
++ depends on NET_RADIO && EXPERIMENTAL && FW_LOADER
++ ---help---
++ A driver for 802.11b/g wireless cards based on
++ Texas Instruments acx100 and acx111 chipsets.
++
++ This driver supports Host AP mode that allows
++ your computer to act as an IEEE 802.11 access point.
++ This driver is quite new and experimental.
++
++ These chipsets need their firmware loaded at startup.
++ You will need to provide a firmware image via hotplug.
++
++ Firmware may be in a form of single image 40-100kb in size
++ (a 'combined' firmware) or two images - main image
++ (again 40-100kb) and radio image (~10kb or less).
++
++ Firmware images are requested from hotplug using following names:
++
++ tiacx100 - main firmware image for acx100 chipset
++ tiacx100rNN - radio acx100 firmware for radio type NN
++ tiacx100cNN - combined acx100 firmware for radio type NN
++ tiacx111 - main acx111 firmware
++ tiacx111rNN - radio acx111 firmware for radio type NN
++ tiacx111cNN - combined acx111 firmware for radio type NN
++
++ Driver will attempt to load combined image first.
++ If no such image is found, it will try to load main image
++ and radio image instead.
++
++ Firmware files are not covered by GPL and are not distributed
++ with this driver for legal reasons.
++
++ Texas Instruments did not take part in development of this driver
++ in any way, shape or form.
++
++ The driver can be compiled as a module and will be named "acx".
++
++config ACX_PCI
++ bool "TI acx100/acx111 802.11b/g PCI"
++ depends on PCI && ACX
++ ---help---
++ Include PCI and CardBus support in acx.
++
++config ACX_USB
++ bool "TI acx100/acx111 802.11b/g USB"
++ depends on USB && ACX && BROKEN
++ ---help---
++ Include USB support in acx.
++
++ There is only one currently known device in this category,
++ D-Link DWL-120+, but newer devices seem to be on the horizon.
++
++config ACX_CFI
++ bool "TI acx100 802.11b/g Compact Flash"
++ depends on ACX
++ ---help---
++ Include Compact Flash support.
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/macros.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/macros.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/macros.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/macros.h 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,33 @@
++#ifndef _MACROS_H
++#define _MACROS_H
++
++
++
++#define HW_SLAVE_REG_ADDR_REG 0x00000004
++#define HW_SLAVE_REG_DATA_REG 0x00000008
++#define HW_SLAVE_REG_CTRL_REG 0x0000000c
++#define HW_SLAVE_MEM_ADDR_REG 0x00000014
++#define HW_SLAVE_MEM_DATA_REG 0x00000018
++
++#define REG_LO(b,r) ((u8 *) b + r)
++#define REG_HI(b,r) ((u8 *) b + r + 2)
++
++static inline u32 acx_readl(unsigned char *iobase, unsigned int reg)
++{
++ u16 hi,lo;
++
++ writew( 0, REG_LO(iobase, HW_SLAVE_REG_CTRL_REG));
++ writew( 1, REG_HI(iobase,HW_SLAVE_REG_CTRL_REG));
++
++ writew( reg, REG_LO(iobase, HW_SLAVE_REG_ADDR_REG));
++ writew( 0, REG_HI(iobase,HW_SLAVE_REG_ADDR_REG));
++
++ lo = readw(REG_LO(iobase,HW_SLAVE_REG_DATA_REG));
++ hi = readw(REG_HI(iobase,HW_SLAVE_REG_DATA_REG));
++
++ printk("hi=%04x,lo=%04x\n",hi,lo);
++
++ return ((u32)hi<<16) | lo;
++}
++
++#endif
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/Makefile linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/Makefile
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/Makefile 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/Makefile 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,9 @@
++#Use this if you have proper Kconfig integration:
++
++obj-$(CONFIG_ACX) += acx.o
++
++acx-obj-$(CONFIG_ACX_PCI) += pci.o
++acx-obj-$(CONFIG_ACX_USB) += usb.o
++acx-obj-$(CONFIG_ACX_CFI) += cfi.o
++
++acx-objs := wlan.o conv.o ioctl.o common.o $(acx-obj-y)
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/pci.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/pci.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/pci.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/pci.c 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,4840 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++#define ACX_PCI 1
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
++#include <linux/moduleparam.h>
++#endif
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/if_arp.h>
++#include <linux/rtnetlink.h>
++#include <linux/wireless.h>
++#if WIRELESS_EXT >= 13
++#include <net/iw_handler.h>
++#endif
++#include <linux/netdevice.h>
++#include <linux/ioport.h>
++#include <linux/pci.h>
++#include <linux/pm.h>
++
++#include "acx.h"
++
++
++/*================================================================*/
++/* Local Constants */
++#define PCI_TYPE (PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
++#define PCI_ACX100_REGION1 0x01
++#define PCI_ACX100_REGION1_SIZE 0x1000 /* Memory size - 4K bytes */
++#define PCI_ACX100_REGION2 0x02
++#define PCI_ACX100_REGION2_SIZE 0x10000 /* Memory size - 64K bytes */
++
++#define PCI_ACX111_REGION1 0x00
++#define PCI_ACX111_REGION1_SIZE 0x2000 /* Memory size - 8K bytes */
++#define PCI_ACX111_REGION2 0x01
++#define PCI_ACX111_REGION2_SIZE 0x20000 /* Memory size - 128K bytes */
++
++/* Texas Instruments Vendor ID */
++#define PCI_VENDOR_ID_TI 0x104c
++
++/* ACX100 22Mb/s WLAN controller */
++#define PCI_DEVICE_ID_TI_TNETW1100A 0x8400
++#define PCI_DEVICE_ID_TI_TNETW1100B 0x8401
++
++/* ACX111 54Mb/s WLAN controller */
++#define PCI_DEVICE_ID_TI_TNETW1130 0x9066
++
++/* PCI Class & Sub-Class code, Network-'Other controller' */
++#define PCI_CLASS_NETWORK_OTHERS 0x280
++
++#define CARD_EEPROM_ID_SIZE 6
++#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* a la orinoco.c */
++
++
++/***********************************************************************
++*/
++static void acx_l_disable_irq(wlandevice_t *priv);
++static void acx_l_enable_irq(wlandevice_t *priv);
++static int acx_e_probe_pci(struct pci_dev *pdev,
++ const struct pci_device_id *id);
++static void acx_e_remove_pci(struct pci_dev *pdev);
++
++#ifdef CONFIG_PM
++static int acx_e_suspend(struct pci_dev *pdev, pm_message_t state);
++static int acx_e_resume(struct pci_dev *pdev);
++#endif
++
++static void acx_i_tx_timeout(netdevice_t *dev);
++static struct net_device_stats *acx_e_get_stats(netdevice_t *dev);
++static struct iw_statistics *acx_e_get_wireless_stats(netdevice_t *dev);
++
++static irqreturn_t acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static void acx_i_set_multicast_list(netdevice_t *dev);
++
++static int acx_e_open(netdevice_t *dev);
++static int acx_e_close(netdevice_t *dev);
++static void acx_s_up(netdevice_t *dev);
++static void acx_s_down(netdevice_t *dev);
++
++
++/***********************************************************************
++** Register access
++*/
++
++/* Pick one */
++/* #define INLINE_IO static */
++#define INLINE_IO static inline
++
++INLINE_IO u32
++acx_read_reg32(wlandevice_t *priv, unsigned int offset)
++{
++#if ACX_IO_WIDTH == 32
++ return readl((u8 *)priv->iobase + priv->io[offset]);
++#else
++ return readw((u8 *)priv->iobase + priv->io[offset])
++ + (readw((u8 *)priv->iobase + priv->io[offset] + 2) << 16);
++#endif
++}
++
++INLINE_IO u16
++acx_read_reg16(wlandevice_t *priv, unsigned int offset)
++{
++ return readw((u8 *)priv->iobase + priv->io[offset]);
++}
++
++INLINE_IO u8
++acx_read_reg8(wlandevice_t *priv, unsigned int offset)
++{
++ return readb((u8 *)priv->iobase + priv->io[offset]);
++}
++
++INLINE_IO void
++acx_write_reg32(wlandevice_t *priv, unsigned int offset, u32 val)
++{
++#if ACX_IO_WIDTH == 32
++ writel(val, (u8 *)priv->iobase + priv->io[offset]);
++#else
++ writew(val & 0xffff, (u8 *)priv->iobase + priv->io[offset]);
++ writew(val >> 16, (u8 *)priv->iobase + priv->io[offset] + 2);
++#endif
++}
++
++INLINE_IO void
++acx_write_reg16(wlandevice_t *priv, unsigned int offset, u16 val)
++{
++ writew(val, (u8 *)priv->iobase + priv->io[offset]);
++}
++
++INLINE_IO void
++acx_write_reg8(wlandevice_t *priv, unsigned int offset, u8 val)
++{
++ writeb(val, (u8 *)priv->iobase + priv->io[offset]);
++}
++
++/* Handle PCI posting properly:
++ * Make sure that writes reach the adapter in case they require to be executed
++ * *before* the next write, by reading a random (and safely accessible) register.
++ * This call has to be made if there is no read following (which would flush the data
++ * to the adapter), yet the written data has to reach the adapter immediately. */
++INLINE_IO void
++acx_write_flush(wlandevice_t *priv)
++{
++ /* readb(priv->iobase + priv->io[IO_ACX_INFO_MAILBOX_OFFS]); */
++ /* faster version (accesses the first register, IO_ACX_SOFT_RESET,
++ * which should also be safe): */
++ readb(priv->iobase);
++}
++
++
++/***********************************************************************
++*/
++static const char name_acx100[] = "ACX100";
++static const char name_tnetw1100a[] = "TNETW1100A";
++static const char name_tnetw1100b[] = "TNETW1100B";
++
++static const char name_acx111[] = "ACX111";
++static const char name_tnetw1130[] = "TNETW1130";
++
++static const struct pci_device_id
++acx_pci_id_tbl[] __devinitdata = {
++ {
++ .vendor = PCI_VENDOR_ID_TI,
++ .device = PCI_DEVICE_ID_TI_TNETW1100A,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = CHIPTYPE_ACX100,
++ },
++ {
++ .vendor = PCI_VENDOR_ID_TI,
++ .device = PCI_DEVICE_ID_TI_TNETW1100B,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = CHIPTYPE_ACX100,
++ },
++ {
++ .vendor = PCI_VENDOR_ID_TI,
++ .device = PCI_DEVICE_ID_TI_TNETW1130,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = CHIPTYPE_ACX111,
++ },
++ {
++ .vendor = 0,
++ .device = 0,
++ .subvendor = 0,
++ .subdevice = 0,
++ .driver_data = 0,
++ }
++};
++
++MODULE_DEVICE_TABLE(pci, acx_pci_id_tbl);
++
++/* FIXME: checks should be removed once driver is included in the kernel */
++#ifndef __devexit_p
++#warning *** your kernel is EXTREMELY old since it does not even know about
++#warning __devexit_p - this driver could easily FAIL to work, so better
++#warning upgrade your kernel! ***
++#define __devexit_p(x) x
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
++/* pci_name() got introduced at start of 2.6.x,
++ * got mandatory (slot_name member removed) in 2.6.11-bk1 */
++#define pci_name(x) x->slot_name
++#endif
++
++static struct pci_driver acx_pci_drv_id = {
++ .name = "acx_pci",
++ .id_table = acx_pci_id_tbl,
++ .probe = acx_e_probe_pci,
++ .remove = __devexit_p(acx_e_remove_pci),
++#ifdef CONFIG_PM
++ .suspend = acx_e_suspend,
++ .resume = acx_e_resume
++#endif /* CONFIG_PM */
++};
++
++typedef struct acx_device {
++ netdevice_t *newest;
++} acx_device_t;
++
++/* if this driver was only about PCI devices, then we probably wouldn't
++ * need this linked list.
++ * But if we want to register ALL kinds of devices in one global list,
++ * then we need it and need to maintain it properly. */
++static struct acx_device root_acx_dev = {
++ .newest = NULL,
++};
++DECLARE_MUTEX(root_acx_dev_sem);
++
++
++/***********************************************************************
++*/
++static inline txdesc_t*
++get_txdesc(wlandevice_t* priv, int index)
++{
++ return (txdesc_t*) (((u8*)priv->txdesc_start) + index * priv->txdesc_size);
++}
++
++static inline txdesc_t*
++move_txdesc(wlandevice_t* priv, txdesc_t* txdesc, int inc)
++{
++ return (txdesc_t*) (((u8*)txdesc) + inc * priv->txdesc_size);
++}
++
++static txhostdesc_t*
++acx_get_txhostdesc(wlandevice_t* priv, txdesc_t* txdesc)
++{
++ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
++ if (ACX_DEBUG && (index % priv->txdesc_size)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ index /= priv->txdesc_size;
++ if (ACX_DEBUG && (index >= TX_CNT)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ return &priv->txhostdesc_start[index*2];
++}
++
++static client_t*
++acx_get_txc(wlandevice_t* priv, txdesc_t* txdesc)
++{
++ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
++ if (ACX_DEBUG && (index % priv->txdesc_size)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ index /= priv->txdesc_size;
++ if (ACX_DEBUG && (index >= TX_CNT)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return NULL;
++ }
++ return priv->txc[index];
++}
++
++static void
++acx_put_txc(wlandevice_t* priv, txdesc_t* txdesc, client_t* c)
++{
++ int index = (u8*)txdesc - (u8*)priv->txdesc_start;
++ if (ACX_DEBUG && (index % priv->txdesc_size)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return;
++ }
++ index /= priv->txdesc_size;
++ if (ACX_DEBUG && (index >= TX_CNT)) {
++ printk("bad txdesc ptr %p\n", txdesc);
++ return;
++ }
++ priv->txc[index] = c;
++}
++
++/***********************************************************************
++** EEPROM and PHY read/write helpers
++*/
++/***********************************************************************
++** acx_read_eeprom_offset
++**
++** Function called to read an octet in the EEPROM.
++**
++** This function is used by acx_probe_pci to check if the
++** connected card is a legal one or not.
++**
++** Arguments:
++** priv ptr to wlandevice structure
++** addr address to read in the EEPROM
++** charbuf ptr to a char. This is where the read octet
++** will be stored
++**
++** Returns:
++** zero (0) - failed
++** one (1) - success
++**
++** NOT ADAPTED FOR ACX111!!
++*/
++int
++acx_read_eeprom_offset(wlandevice_t *priv, u32 addr, u8 *charbuf)
++{
++ int result = NOT_OK;
++ int count;
++
++ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
++ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
++
++ count = 0xffff;
++ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
++ /* scheduling away instead of CPU burning loop
++ * doesn't seem to work here at all:
++ * awful delay, sometimes also failure.
++ * Doesn't matter anyway (only small delay). */
++ if (unlikely(!--count)) {
++ printk("%s: timeout waiting for EEPROM read\n",
++ priv->netdev->name);
++ goto fail;
++ }
++ }
++
++ *charbuf = acx_read_reg8(priv, IO_ACX_EEPROM_DATA);
++ acxlog(L_DEBUG, "EEPROM at 0x%04X = 0x%02X\n", addr, *charbuf);
++ result = OK;
++
++fail:
++ return result;
++}
++
++
++/***********************************************************************
++** Dummy EEPROM read? why?!
++*/
++static int
++acx_read_eeprom_area(wlandevice_t *priv)
++{
++ int offs;
++ u8 tmp[0x3b];
++
++ for (offs = 0x8c; offs < 0xb9; offs++) {
++ acx_read_eeprom_offset(priv, offs, &tmp[offs - 0x8c]);
++ }
++ return OK;
++}
++
++
++/***********************************************************************
++** We don't lock hw accesses here since we never r/w eeprom in IRQ
++** Note: this function sleeps only because of GFP_KERNEL alloc
++*/
++#ifdef UNUSED
++int
++acx_s_write_eeprom_offset(wlandevice_t *priv, u32 addr, u32 len, const u8 *charbuf)
++{
++ u8 *data_verify = NULL;
++ unsigned long flags;
++ int count, i;
++ int result = NOT_OK;
++ u16 gpio_orig;
++
++ printk("acx: WARNING! I would write to EEPROM now. "
++ "Since I really DON'T want to unless you know "
++ "what you're doing (THIS CODE WILL PROBABLY "
++ "NOT WORK YET!), I will abort that now. And "
++ "definitely make sure to make a "
++ "/proc/driver/acx_wlan0_eeprom backup copy first!!! "
++ "(the EEPROM content includes the PCI config header!! "
++ "If you kill important stuff, then you WILL "
++ "get in trouble and people DID get in trouble already)\n");
++ return OK;
++
++ FN_ENTER;
++
++ data_verify = kmalloc(len, GFP_KERNEL);
++ if (!data_verify) {
++ goto end;
++ }
++
++ /* first we need to enable the OE (EEPROM Output Enable) GPIO line
++ * to be able to write to the EEPROM.
++ * NOTE: an EEPROM writing success has been reported,
++ * but you probably have to modify GPIO_OUT, too,
++ * and you probably need to activate a different GPIO
++ * line instead! */
++ gpio_orig = acx_read_reg16(priv, IO_ACX_GPIO_OE);
++ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig & ~1);
++ acx_write_flush(priv);
++
++ /* ok, now start writing the data out */
++ for (i = 0; i < len; i++) {
++ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
++ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
++ acx_write_reg32(priv, IO_ACX_EEPROM_DATA, *(charbuf + i));
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 1);
++
++ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
++ if (unlikely(++count > 0xffff)) {
++ printk("WARNING, DANGER!!! "
++ "Timeout waiting for EEPROM write\n");
++ goto end;
++ }
++ }
++ }
++
++ /* disable EEPROM writing */
++ acx_write_reg16(priv, IO_ACX_GPIO_OE, gpio_orig);
++ acx_write_flush(priv);
++
++ /* now start a verification run */
++ count = 0xffff;
++ for (i = 0; i < len; i++) {
++ acx_write_reg32(priv, IO_ACX_EEPROM_CFG, 0);
++ acx_write_reg32(priv, IO_ACX_EEPROM_ADDR, addr + i);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_EEPROM_CTL, 2);
++
++ while (acx_read_reg16(priv, IO_ACX_EEPROM_CTL)) {
++ if (unlikely(!--count)) {
++ printk("timeout waiting for EEPROM read\n");
++ goto end;
++ }
++ }
++
++ data_verify[i] = acx_read_reg16(priv, IO_ACX_EEPROM_DATA);
++ }
++
++ if (0 == memcmp(charbuf, data_verify, len))
++ result = OK; /* read data matches, success */
++
++end:
++ kfree(data_verify);
++ FN_EXIT1(result);
++ return result;
++}
++#endif /* UNUSED */
++
++
++/***********************************************************************
++** acxpci_s_read_phy_reg
++**
++** Messing with rx/tx disabling and enabling here
++** (acx_write_reg32(priv, IO_ACX_ENABLE, 0b000000xx)) kills traffic
++*/
++int
++acxpci_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
++{
++ int result = NOT_OK;
++ int count;
++
++ FN_ENTER;
++
++ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_PHY_CTL, 2);
++
++ count = 0xffff;
++ while (acx_read_reg32(priv, IO_ACX_PHY_CTL)) {
++ /* scheduling away instead of CPU burning loop
++ * doesn't seem to work here at all:
++ * awful delay, sometimes also failure.
++ * Doesn't matter anyway (only small delay). */
++ if (unlikely(!--count)) {
++ printk("%s: timeout waiting for phy read\n",
++ priv->netdev->name);
++ *charbuf = 0;
++ goto fail;
++ }
++ }
++
++ acxlog(L_DEBUG, "count was %u\n", count);
++ *charbuf = acx_read_reg8(priv, IO_ACX_PHY_DATA);
++
++ acxlog(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg);
++ result = OK;
++ goto fail; /* silence compiler warning */
++fail:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++*/
++int
++acxpci_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
++{
++ FN_ENTER;
++
++ /* FIXME: we didn't use 32bit access here since mprusko said that
++ * it results in distorted sensitivity on his card (huh!?!?
++ * doesn't happen with my setup...)
++ * But with the access reordering and flushing it
++ * shouldn't happen any more...
++ * FIXME: which radio is in the problematic card? My working one
++ * is 0x11 */
++ acx_write_reg32(priv, IO_ACX_PHY_DATA, value);
++ acx_write_reg32(priv, IO_ACX_PHY_ADDR, reg);
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_PHY_CTL, 1);
++ acx_write_flush(priv);
++ acxlog(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg);
++
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++#define NO_AUTO_INCREMENT 1
++
++/***********************************************************************
++** acx_s_write_fw
++**
++** Write the firmware image into the card.
++**
++** Arguments:
++** priv wlan device structure
++** apfw_image firmware image.
++**
++** Returns:
++** 1 firmware image corrupted
++** 0 success
++*/
++static int
++acx_s_write_fw(wlandevice_t *priv, const firmware_image_t *apfw_image, u32 offset)
++{
++ int len, size;
++ u32 sum, v32;
++ /* we skip the first four bytes which contain the control sum */
++ const u8 *image = (u8*)apfw_image + 4;
++
++ /* start the image checksum by adding the image size value */
++ sum = image[0]+image[1]+image[2]+image[3];
++ image += 4;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
++
++#if NO_AUTO_INCREMENT
++ acxlog(L_INIT, "not using auto increment for firmware loading\n");
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
++#else
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
++ acx_write_flush(priv);
++#endif
++
++ len = 0;
++ size = le32_to_cpu(apfw_image->size) & (~3);
++
++ while (likely(len < size)) {
++ v32 = be32_to_cpu(*(u32*)image);
++ sum += image[0]+image[1]+image[2]+image[3];
++ image += 4;
++ len += 4;
++
++#if NO_AUTO_INCREMENT
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
++ acx_write_flush(priv);
++#endif
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, v32);
++ }
++
++ acxlog(L_DEBUG, "%s: firmware written\n", __func__);
++
++ /* compare our checksum with the stored image checksum */
++ return (sum != le32_to_cpu(apfw_image->chksum));
++}
++
++
++/***********************************************************************
++** acx_s_validate_fw
++**
++** Compare the firmware image given with
++** the firmware image written into the card.
++**
++** Arguments:
++** priv wlan device structure
++** apfw_image firmware image.
++**
++** Returns:
++** NOT_OK firmware image corrupted or not correctly written
++** OK success
++*/
++static int
++acx_s_validate_fw(wlandevice_t *priv, const firmware_image_t *apfw_image,
++ u32 offset)
++{
++ u32 v32, w32, sum;
++ int len, size;
++ int result = OK;
++ /* we skip the first four bytes which contain the control sum */
++ const u8 *image = (u8*)apfw_image + 4;
++
++ /* start the image checksum by adding the image size value */
++ sum = image[0]+image[1]+image[2]+image[3];
++ image += 4;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0);
++
++#if NO_AUTO_INCREMENT
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0); /* use basic mode */
++#else
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 1); /* use autoincrement mode */
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset); /* configure start address */
++#endif
++
++ len = 0;
++ size = le32_to_cpu(apfw_image->size) & (~3);
++
++ while (likely(len < size)) {
++ v32 = be32_to_cpu(*(u32*)image);
++ image += 4;
++ len += 4;
++
++#if NO_AUTO_INCREMENT
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR, offset + len - 4);
++#endif
++ w32 = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++
++ if (unlikely(w32 != v32)) {
++ printk("acx: FATAL: firmware upload: "
++ "data parts at offset %d don't match (0x%08X vs. 0x%08X)! "
++ "I/O timing issues or defective memory, with DWL-xx0+? "
++ "ACX_IO_WIDTH=16 may help. Please report\n",
++ len, v32, w32);
++ result = NOT_OK;
++ break;
++ }
++
++ sum += (u8)w32 + (u8)(w32>>8) + (u8)(w32>>16) + (u8)(w32>>24);
++ }
++
++ /* sum control verification */
++ if (result != NOT_OK) {
++ if (sum != le32_to_cpu(apfw_image->chksum)) {
++ printk("acx: FATAL: firmware upload: "
++ "checksums don't match!\n");
++ result = NOT_OK;
++ }
++ }
++
++ return result;
++}
++
++
++/***********************************************************************
++** acx_s_upload_fw
++**
++** Arguments:
++** wlandevice: private device that contains card device
++** Returns:
++** NOT_OK: failed
++** OK: success
++** Call context:
++** acx_reset_dev
++*/
++static int
++acx_s_upload_fw(wlandevice_t *priv)
++{
++ firmware_image_t *apfw_image = NULL;
++ int res = NOT_OK;
++ int try;
++ u32 size;
++ char filename[sizeof("tiacx1NNcNN")];
++
++ FN_ENTER;
++
++ /* Try combined, then main image */
++ priv->need_radio_fw = 0;
++ sprintf(filename, "tiacx1%02dc%02X",
++ IS_ACX111(priv)*11, priv->radio_type);
++
++ apfw_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
++ if (!apfw_image) {
++ priv->need_radio_fw = 1;
++ filename[sizeof("tiacx1NN")-1] = '\0';
++ apfw_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
++ if (!apfw_image) {
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++ }
++ }
++
++ for (try = 1; try <= 5; try++) {
++ res = acx_s_write_fw(priv, apfw_image, 0);
++ acxlog(L_DEBUG|L_INIT, "acx_write_fw (main/combined):%d\n", res);
++ if (OK == res) {
++ res = acx_s_validate_fw(priv, apfw_image, 0);
++ acxlog(L_DEBUG|L_INIT, "acx_validate_fw "
++ "(main/combined):%d\n", res);
++ }
++
++ if (OK == res) {
++ SET_BIT(priv->dev_state_mask, ACX_STATE_FW_LOADED);
++ break;
++ }
++ printk("acx: firmware upload attempt #%d FAILED, "
++ "retrying...\n", try);
++ acx_s_msleep(1000); /* better wait for a while... */
++ }
++
++ vfree(apfw_image);
++
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/***********************************************************************
++** acx_s_upload_radio
++**
++** Uploads the appropriate radio module firmware
++** into the card.
++*/
++int
++acx_s_upload_radio(wlandevice_t *priv)
++{
++ acx_ie_memmap_t mm;
++ firmware_image_t *radio_image = NULL;
++ acx_cmd_radioinit_t radioinit;
++ int res = NOT_OK;
++ int try;
++ u32 offset;
++ u32 size;
++ char filename[sizeof("tiacx1NNrNN")];
++
++ if (!priv->need_radio_fw) return OK;
++
++ FN_ENTER;
++
++ acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
++ offset = le32_to_cpu(mm.CodeEnd);
++
++ sprintf(filename, "tiacx1%02dr%02X",
++ IS_ACX111(priv)*11,
++ priv->radio_type);
++ radio_image = acx_s_read_fw(&priv->pdev->dev, filename, &size);
++ if (!radio_image) {
++ printk("acx: can't load radio module '%s'\n", filename);
++ goto fail;
++ }
++
++ acx_s_issue_cmd(priv, ACX1xx_CMD_SLEEP, NULL, 0);
++
++ for (try = 1; try <= 5; try++) {
++ res = acx_s_write_fw(priv, radio_image, offset);
++ acxlog(L_DEBUG|L_INIT, "acx_write_fw (radio): %d\n", res);
++ if (OK == res) {
++ res = acx_s_validate_fw(priv, radio_image, offset);
++ acxlog(L_DEBUG|L_INIT, "acx_validate_fw (radio): %d\n", res);
++ }
++
++ if (OK == res)
++ break;
++ printk("acx: radio firmware upload attempt #%d FAILED, "
++ "retrying...\n", try);
++ acx_s_msleep(1000); /* better wait for a while... */
++ }
++
++ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
++ radioinit.offset = cpu_to_le32(offset);
++ /* no endian conversion needed, remains in card CPU area: */
++ radioinit.len = radio_image->size;
++
++ vfree(radio_image);
++
++ if (OK != res)
++ goto fail;
++
++ /* will take a moment so let's have a big timeout */
++ acx_s_issue_cmd_timeo(priv, ACX1xx_CMD_RADIOINIT,
++ &radioinit, sizeof(radioinit), CMD_TIMEOUT_MS(1000));
++
++ res = acx_s_interrogate(priv, &mm, ACX1xx_IE_MEMORY_MAP);
++fail:
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/***********************************************************************
++** acx_l_reset_mac
++**
++** Arguments:
++** wlandevice: private device that contains card device
++** Side effects:
++** MAC will be reset
++** Call context:
++** acx_reset_dev
++** Comment:
++** resets onboard acx100 MAC
++**
++** Requires lock to be taken
++*/
++static void
++acx_l_reset_mac(wlandevice_t *priv)
++{
++ u16 temp;
++
++ FN_ENTER;
++
++ /* halt eCPU */
++ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
++ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
++
++ /* now do soft reset of eCPU */
++ temp = acx_read_reg16(priv, IO_ACX_SOFT_RESET) | 0x1;
++ acxlog(L_DEBUG, "%s: enable soft reset...\n", __func__);
++ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp);
++ acx_write_flush(priv);
++
++ /* now reset bit again */
++ acxlog(L_DEBUG, "%s: disable soft reset and go to init mode...\n", __func__);
++ /* deassert eCPU reset */
++ acx_write_reg16(priv, IO_ACX_SOFT_RESET, temp & ~0x1);
++
++ /* now start a burst read from initial flash EEPROM */
++ temp = acx_read_reg16(priv, IO_ACX_EE_START) | 0x1;
++ acx_write_reg16(priv, IO_ACX_EE_START, temp);
++ acx_write_flush(priv);
++
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx_s_verify_init
++*/
++static int
++acx_s_verify_init(wlandevice_t *priv)
++{
++ int result = NOT_OK;
++ int timer;
++
++ FN_ENTER;
++
++ for (timer = 40; timer > 0; timer--) {
++ u16 irqstat = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
++ if (irqstat & HOST_INT_FCS_THRESHOLD) {
++ result = OK;
++ acx_write_reg16(priv, IO_ACX_IRQ_ACK, HOST_INT_FCS_THRESHOLD);
++ break;
++ }
++ /* HZ / 50 resulted in 24 schedules for ACX100 on my machine,
++ * so better schedule away longer for greater efficiency,
++ * decrease loop count */
++ acx_s_msleep(50);
++ }
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** A few low-level helpers
++**
++** Note: these functions are not protected by lock
++** and thus are never allowed to be called from IRQ.
++** Also they must not race with fw upload which uses same hw regs
++*/
++
++/***********************************************************************
++** acx_read_info_status
++*/
++/* Info mailbox format:
++2 bytes: type
++2 bytes: status
++more bytes may follow
++ docs say about status:
++ 0x0000 info available (set by hw)
++ 0x0001 information received (must be set by host)
++ 0x1000 info available, mailbox overflowed (messages lost) (set by hw)
++ but in practice we've seen:
++ 0x9000 when we did not set status to 0x0001 on prev message
++ 0x1001 when we did set it
++ 0x0000 was never seen
++ conclusion: this is really a bitfield:
++ 0x1000 is 'info available' bit
++ 'mailbox overflowed' bit is 0x8000, not 0x1000
++ value of 0x0000 probably means that there is no message at all
++ P.S. I dunno how in hell hw is supposed to notice that messages are lost -
++ it does NOT clear bit 0x0001, and this bit will probably stay forever set
++ after we set it once. Let's hope this will be fixed in firmware someday
++*/
++static void
++acx_read_info_status(wlandevice_t *priv)
++{
++ u32 value;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1);
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
++ acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS));
++
++ /* make sure we only read the data once all cfg registers are written: */
++ acx_write_flush(priv);
++ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++
++ priv->info_type = (u16)value;
++ priv->info_status = (value >> 16);
++
++ /* inform hw that we have read this info message */
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, priv->info_type | 0x00010000);
++ acx_write_flush(priv);
++ /* now bother hw to notice it: */
++ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_INFOACK);
++ acx_write_flush(priv);
++
++ acxlog(L_CTL, "info_type 0x%04X, info_status 0x%04X\n",
++ priv->info_type, priv->info_status);
++}
++
++
++/***********************************************************************
++** acx_write_cmd_type_or_status
++*/
++static void
++acx_write_cmd_type_or_status(wlandevice_t *priv, u32 val)
++{
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
++ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
++
++ /* make sure we only write the data once all config registers are written */
++ acx_write_flush(priv);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_DATA, val);
++ acx_write_flush(priv);
++}
++static inline void
++acx_write_cmd_type(wlandevice_t *priv, u32 val)
++{
++ acx_write_cmd_type_or_status(priv, val);
++}
++static inline void
++acx_write_cmd_status(wlandevice_t *priv, u32 val)
++{
++ acx_write_cmd_type_or_status(priv, val<<16);
++}
++
++
++/***********************************************************************
++** acx_read_cmd_status
++*/
++static void
++acx_read_cmd_status(wlandevice_t *priv)
++{
++ u32 value;
++
++ acx_write_reg32(priv, IO_ACX_SLV_END_CTL, 0x0);
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_CTL, 0x1); /* FIXME: why auto increment?? */
++
++ acx_write_reg32(priv, IO_ACX_SLV_MEM_ADDR,
++ acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS));
++
++ /* make sure we only read the data once all config registers are written */
++ acx_write_flush(priv);
++ value = acx_read_reg32(priv, IO_ACX_SLV_MEM_DATA);
++
++ priv->cmd_type = (u16)value;
++ priv->cmd_status = (value >> 16);
++
++ acxlog(L_CTL, "cmd_type 0x%04X, cmd_status 0x%04X [%s]\n",
++ priv->cmd_type, priv->cmd_status,
++ acx_cmd_status_str(priv->cmd_status));
++}
++
++
++/***********************************************************************
++** acx_s_reset_dev
++**
++** Arguments:
++** netdevice that contains the wlandevice priv variable
++** Returns:
++** NOT_OK on fail
++** OK on success
++** Side effects:
++** device is hard reset
++** Call context:
++** acx_probe_pci
++** Comment:
++** This resets the acx100 device using low level hardware calls
++** as well as uploads and verifies the firmware to the card
++*/
++static int
++acx_s_reset_dev(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ const char* msg = "";
++ unsigned long flags;
++ int result = NOT_OK;
++ u16 hardware_info;
++ u16 ecpu_ctrl;
++
++ FN_ENTER;
++
++ /* we're doing a reset, so hardware is unavailable */
++
++ /* reset the device to make sure the eCPU is stopped
++ * to upload the firmware correctly */
++
++ acx_lock(priv, flags);
++
++ acx_l_reset_mac(priv);
++
++ ecpu_ctrl = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) & 1;
++ if (!ecpu_ctrl) {
++ msg = "eCPU is already running. ";
++ goto fail_unlock;
++ }
++
++#ifdef WE_DONT_NEED_THAT_DO_WE
++ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 2) {
++ /* eCPU most likely means "embedded CPU" */
++ msg = "eCPU did not start after boot from flash. ";
++ goto fail_unlock;
++ }
++
++ /* check sense on reset flags */
++ if (acx_read_reg16(priv, IO_ACX_SOR_CFG) & 0x10) {
++ printk("%s: eCPU did not start after boot (SOR), "
++ "is this fatal?\n", dev->name);
++ }
++#endif
++ /* scan, if any, is stopped now, setting corresponding IRQ bit */
++ priv->irq_status |= HOST_INT_SCAN_COMPLETE;
++
++ acx_unlock(priv, flags);
++
++ /* without this delay acx100 may fail to report hardware_info
++ ** (see below). Most probably eCPU runs some init code */
++ acx_s_msleep(10);
++
++ /* Need to know radio type before fw load */
++ hardware_info = acx_read_reg16(priv, IO_ACX_EEPROM_INFORMATION);
++ priv->form_factor = hardware_info & 0xff;
++ priv->radio_type = hardware_info >> 8;
++
++ /* load the firmware */
++ if (OK != acx_s_upload_fw(priv))
++ goto fail;
++
++ acx_s_msleep(10);
++
++ /* now start eCPU by clearing bit */
++ acxlog(L_DEBUG, "booted eCPU up and waiting for completion...\n");
++ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, ecpu_ctrl & ~0x1);
++
++ /* wait for eCPU bootup */
++ if (OK != acx_s_verify_init(priv)) {
++ msg = "timeout waiting for eCPU. ";
++ goto fail;
++ }
++
++ acxlog(L_DEBUG, "eCPU has woken up, card is ready to be configured\n");
++
++ if (IS_ACX111(priv)) {
++ acxlog(L_DEBUG, "cleaning up cmd mailbox access area\n");
++ acx_write_cmd_status(priv, 0);
++ acx_read_cmd_status(priv);
++ if (priv->cmd_status) {
++ msg = "error cleaning cmd mailbox area. ";
++ goto fail;
++ }
++ }
++
++ /* TODO what is this one doing ?? adapt for acx111 */
++ if ((OK != acx_read_eeprom_area(priv)) && IS_ACX100(priv)) {
++ /* does "CIS" mean "Card Information Structure"?
++ * If so, then this would be a PCMCIA message...
++ */
++ msg = "CIS error. ";
++ goto fail;
++ }
++
++ result = OK;
++ FN_EXIT1(result);
++ return result;
++
++/* Finish error message. Indicate which function failed */
++fail_unlock:
++ acx_unlock(priv, flags);
++fail:
++ printk("acx: %sreset_dev() FAILED\n", msg);
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx_init_mboxes
++*/
++void
++acx_init_mboxes(wlandevice_t *priv)
++{
++ u32 cmd_offs, info_offs;
++
++ FN_ENTER;
++
++ cmd_offs = acx_read_reg32(priv, IO_ACX_CMD_MAILBOX_OFFS);
++ info_offs = acx_read_reg32(priv, IO_ACX_INFO_MAILBOX_OFFS);
++ priv->cmd_area = (u8 *)priv->iobase2 + cmd_offs + 0x4;
++ priv->info_area = (u8 *)priv->iobase2 + info_offs + 0x4;
++ acxlog(L_DEBUG, "iobase2=%p\n"
++ "cmd_mbox_offset=%X cmd_area=%p\n"
++ "info_mbox_offset=%X info_area=%p\n",
++ priv->iobase2,
++ cmd_offs, priv->cmd_area,
++ info_offs, priv->info_area);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_issue_cmd_timeo
++* Excecutes a command in the command mailbox
++*
++* Arguments:
++* *pcmdparam = an pointer to the data. The data mustn't include
++* the 4 byte command header!
++*
++* NB: we do _not_ take lock inside, so be sure to not touch anything
++* which may interfere with IRQ handler operation
++*
++* TODO: busy wait is a bit silly, so:
++* 1) stop doing many iters - go to sleep after first
++* 2) go to waitqueue based approach: wait, not poll!
++*----------------------------------------------------------------*/
++#undef FUNC
++#define FUNC "issue_cmd"
++
++#if !ACX_DEBUG
++int
++acxpci_s_issue_cmd_timeo(
++ wlandevice_t *priv,
++ unsigned int cmd,
++ void *buffer,
++ unsigned buflen,
++ unsigned timeout)
++{
++#else
++int
++acxpci_s_issue_cmd_timeo_debug(
++ wlandevice_t *priv,
++ unsigned cmd,
++ void *buffer,
++ unsigned buflen,
++ unsigned timeout,
++ const char* cmdstr)
++{
++ unsigned long start = jiffies;
++#endif
++ const char *devname;
++ unsigned counter;
++ u16 irqtype;
++ u16 cmd_status;
++
++ FN_ENTER;
++
++ devname = priv->netdev->name;
++ if (!devname || !devname[0])
++ devname = "acx";
++
++ acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,timeout:%ums,type:0x%04X)\n",
++ cmdstr, buflen, timeout,
++ buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
++
++ if (!(priv->dev_state_mask & ACX_STATE_FW_LOADED)) {
++ printk("%s: "FUNC"(): firmware is not loaded yet, "
++ "cannot execute commands!\n", devname);
++ goto bad;
++ }
++
++ if ((acx_debug & L_DEBUG) && (cmd != ACX1xx_CMD_INTERROGATE)) {
++ printk("input pdr (len=%u):\n", buflen);
++ acx_dump_bytes(buffer, buflen);
++ }
++
++ /* wait for firmware to become idle for our command submission */
++ counter = 199; /* in ms */
++ do {
++ acx_read_cmd_status(priv);
++ /* Test for IDLE state */
++ if (!priv->cmd_status)
++ break;
++ if (counter % 10 == 0) {
++ /* we waited 10 iterations, no luck. Sleep 10 ms */
++ acx_s_msleep(10);
++ }
++ } while (--counter);
++
++ if (!counter) {
++ /* the card doesn't get idle, we're in trouble */
++ printk("%s: "FUNC"(): cmd_status is not IDLE: 0x%04X!=0\n",
++ devname, priv->cmd_status);
++ goto bad;
++ } else if (counter < 190) { /* if waited >10ms... */
++ acxlog(L_CTL|L_DEBUG, FUNC"(): waited for IDLE %dms. "
++ "Please report\n", 199 - counter);
++ }
++
++ /* now write the parameters of the command if needed */
++ if (buffer && buflen) {
++ /* if it's an INTERROGATE command, just pass the length
++ * of parameters to read, as data */
++#if CMD_DISCOVERY
++ if (cmd == ACX1xx_CMD_INTERROGATE)
++ memset(priv->cmd_area, 0xAA, buflen);
++#endif
++ memcpy(priv->cmd_area, buffer,
++ (cmd == ACX1xx_CMD_INTERROGATE) ? 4 : buflen);
++ }
++ /* now write the actual command type */
++ priv->cmd_type = cmd;
++ acx_write_cmd_type(priv, cmd);
++ /* execute command */
++ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_CMD);
++ acx_write_flush(priv);
++
++ /* wait for firmware to process command */
++
++ /* Ensure nonzero and not too large timeout.
++ ** Also converts e.g. 100->99, 200->199
++ ** which is nice but not essential */
++ timeout = (timeout-1) | 1;
++ if (unlikely(timeout > 1199))
++ timeout = 1199;
++ /* clear CMD_COMPLETE bit. can be set only by IRQ handler: */
++ priv->irq_status &= ~HOST_INT_CMD_COMPLETE;
++
++ /* we schedule away sometimes (timeout can be large) */
++ counter = timeout;
++ do {
++ if (!priv->irqs_active) { /* IRQ disabled: poll */
++ irqtype = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_NON_DES);
++ if (irqtype & HOST_INT_CMD_COMPLETE) {
++ acx_write_reg16(priv, IO_ACX_IRQ_ACK,
++ HOST_INT_CMD_COMPLETE);
++ break;
++ }
++ } else { /* Wait when IRQ will set the bit */
++ irqtype = priv->irq_status;
++ if (irqtype & HOST_INT_CMD_COMPLETE)
++ break;
++ }
++
++ if (counter % 10 == 0) {
++ /* we waited 10 iterations, no luck. Sleep 10 ms */
++ acx_s_msleep(10);
++ }
++ } while (--counter);
++
++ /* save state for debugging */
++ acx_read_cmd_status(priv);
++ cmd_status = priv->cmd_status;
++
++ /* put the card in IDLE state */
++ priv->cmd_status = 0;
++ acx_write_cmd_status(priv, 0);
++
++ if (!counter) { /* timed out! */
++ printk("%s: "FUNC"(): timed out %s for CMD_COMPLETE. "
++ "irq bits:0x%04X irq_status:0x%04X timeout:%dms "
++ "cmd_status:%d (%s)\n",
++ devname, (priv->irqs_active) ? "waiting" : "polling",
++ irqtype, priv->irq_status, timeout,
++ cmd_status, acx_cmd_status_str(cmd_status));
++ goto bad;
++ } else if (timeout - counter > 30) { /* if waited >30ms... */
++ acxlog(L_CTL|L_DEBUG, FUNC"(): %s for CMD_COMPLETE %dms. "
++ "count:%d. Please report\n",
++ (priv->irqs_active) ? "waited" : "polled",
++ timeout - counter, counter);
++ }
++
++ if (1 != cmd_status) { /* it is not a 'Success' */
++ printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s). "
++ "Took %dms of %d\n",
++ devname, cmd_status, acx_cmd_status_str(cmd_status),
++ timeout - counter, timeout);
++ /* zero out result buffer */
++ if (buffer && buflen)
++ memset(buffer, 0, buflen);
++ goto bad;
++ }
++
++ /* read in result parameters if needed */
++ if (buffer && buflen && (cmd == ACX1xx_CMD_INTERROGATE)) {
++ memcpy(buffer, priv->cmd_area, buflen);
++ if (acx_debug & L_DEBUG) {
++ printk("output buffer (len=%u): ", buflen);
++ acx_dump_bytes(buffer, buflen);
++ }
++ }
++/* ok: */
++ acxlog(L_CTL, FUNC"(%s): took %ld jiffies to complete\n",
++ cmdstr, jiffies - start);
++ FN_EXIT1(OK);
++ return OK;
++
++bad:
++ /* Give enough info so that callers can avoid
++ ** printing their own diagnostic messages */
++#if ACX_DEBUG
++ printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
++#else
++ printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
++#endif
++ dump_stack();
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_get_firmware_version
++*----------------------------------------------------------------*/
++static void
++acx_s_get_firmware_version(wlandevice_t *priv)
++{
++ fw_ver_t fw;
++ u8 hexarr[4] = { 0, 0, 0, 0 };
++ int hexidx = 0, val = 0;
++ const char *num;
++ char c;
++
++ FN_ENTER;
++
++ acx_s_interrogate(priv, &fw, ACX1xx_IE_FWREV);
++ memcpy(priv->firmware_version, fw.fw_id, FW_ID_SIZE);
++ priv->firmware_version[FW_ID_SIZE] = '\0';
++ acxlog(L_DEBUG, "fw_ver: fw_id='%s' hw_id=%08X\n",
++ priv->firmware_version, fw.hw_id);
++
++ if (strncmp(fw.fw_id, "Rev ", 4) != 0) {
++ printk("acx: strange firmware version string "
++ "'%s', please report\n", priv->firmware_version);
++ priv->firmware_numver = 0x01090407; /* assume 1.9.4.7 */
++ } else {
++ num = &fw.fw_id[4];
++ while (1) {
++ c = *num++;
++ if ((c == '.') || (c == '\0')) {
++ hexarr[hexidx++] = val;
++ if ((hexidx > 3) || (c == '\0')) /* end? */
++ break;
++ val = 0;
++ continue;
++ }
++ if ((c >= '0') && (c <= '9'))
++ c -= '0';
++ else
++ c = c - 'a' + (char)10;
++ val = val*16 + c;
++ }
++
++ priv->firmware_numver = (u32)(
++ (hexarr[0] << 24) + (hexarr[1] << 16)
++ + (hexarr[2] << 8) + hexarr[3]);
++ acxlog(L_DEBUG, "firmware_numver 0x%08X\n", priv->firmware_numver);
++ }
++ if (IS_ACX111(priv)) {
++ if (priv->firmware_numver == 0x00010011) {
++ /* This one does not survive floodpinging */
++ printk("acx: firmware '%s' is known to be buggy, "
++ "please upgrade\n", priv->firmware_version);
++ }
++ if (priv->firmware_numver == 0x02030131) {
++ /* With this one, all rx packets look mangled
++ ** Most probably we simply do not know how to use it
++ ** properly */
++ printk("acx: firmware '%s' does not work well "
++ "with this driver\n", priv->firmware_version);
++ }
++ }
++
++ priv->firmware_id = le32_to_cpu(fw.hw_id);
++
++ /* we're able to find out more detailed chip names now */
++ switch (priv->firmware_id & 0xffff0000) {
++ case 0x01010000:
++ case 0x01020000:
++ priv->chip_name = name_tnetw1100a;
++ break;
++ case 0x01030000:
++ priv->chip_name = name_tnetw1100b;
++ break;
++ case 0x03000000:
++ case 0x03010000:
++ priv->chip_name = name_tnetw1130;
++ break;
++ default:
++ printk("acx: unknown chip ID 0x%08X, "
++ "please report\n", priv->firmware_id);
++ break;
++ }
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_display_hardware_details
++*
++* Arguments:
++* priv: ptr to wlandevice that contains all the details
++* displayed by this function
++* Call context:
++* acx_probe_pci
++* Comment:
++* This function will display strings to the system log according
++* to device form_factor and radio type. It will needed to be
++*----------------------------------------------------------------*/
++static void
++acx_display_hardware_details(wlandevice_t *priv)
++{
++ const char *radio_str, *form_str;
++
++ FN_ENTER;
++
++ switch (priv->radio_type) {
++ case RADIO_MAXIM_0D:
++ /* hmm, the DWL-650+ seems to have two variants,
++ * according to a windows driver changelog comment:
++ * RFMD and Maxim. */
++ radio_str = "Maxim";
++ break;
++ case RADIO_RFMD_11:
++ radio_str = "RFMD";
++ break;
++ case RADIO_RALINK_15:
++ radio_str = "Ralink";
++ break;
++ case RADIO_RADIA_16:
++ radio_str = "Radia";
++ break;
++ case RADIO_UNKNOWN_17:
++ /* TI seems to have a radio which is
++ * additionally 802.11a capable, too */
++ radio_str = "802.11a/b/g radio?! Please report";
++ break;
++ case RADIO_UNKNOWN_19:
++ radio_str = "A radio used by Safecom cards?! Please report";
++ break;
++ default:
++ radio_str = "UNKNOWN, please report the radio type name!";
++ break;
++ }
++
++ switch (priv->form_factor) {
++ case 0x00:
++ form_str = "unspecified";
++ break;
++ case 0x01:
++ form_str = "(mini-)PCI / CardBus";
++ break;
++ case 0x02:
++ form_str = "USB";
++ break;
++ case 0x03:
++ form_str = "Compact Flash";
++ break;
++ default:
++ form_str = "UNKNOWN, Please report";
++ break;
++ }
++
++ printk("acx: form factor 0x%02X (%s), "
++ "radio type 0x%02X (%s), EEPROM version 0x%02X, "
++ "uploaded firmware '%s' (0x%08X)\n",
++ priv->form_factor, form_str, priv->radio_type, radio_str,
++ priv->eeprom_version, priv->firmware_version,
++ priv->firmware_id);
++
++ FN_EXIT0;
++}
++
++/***********************************************************************
++*/
++#ifdef NONESSENTIAL_FEATURES
++typedef struct device_id {
++ unsigned char id[6];
++ char *descr;
++ char *type;
++} device_id_t;
++
++static const device_id_t
++device_ids[] =
++{
++ {
++ {'G', 'l', 'o', 'b', 'a', 'l'},
++ NULL,
++ NULL,
++ },
++ {
++ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
++ "uninitialized",
++ "SpeedStream SS1021 or Gigafast WF721-AEX"
++ },
++ {
++ {0x80, 0x81, 0x82, 0x83, 0x84, 0x85},
++ "non-standard",
++ "DrayTek Vigor 520"
++ },
++ {
++ {'?', '?', '?', '?', '?', '?'},
++ "non-standard",
++ "Level One WPC-0200"
++ },
++ {
++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
++ "empty",
++ "DWL-650+ variant"
++ }
++};
++
++static void
++acx_show_card_eeprom_id(wlandevice_t *priv)
++{
++ unsigned char buffer[CARD_EEPROM_ID_SIZE];
++ int i;
++
++ memset(&buffer, 0, CARD_EEPROM_ID_SIZE);
++ /* use direct EEPROM access */
++ for (i = 0; i < CARD_EEPROM_ID_SIZE; i++) {
++ if (OK != acx_read_eeprom_offset(priv,
++ ACX100_EEPROM_ID_OFFSET + i,
++ &buffer[i]))
++ {
++ printk("acx: reading EEPROM FAILED\n");
++ break;
++ }
++ }
++
++ for (i = 0; i < VEC_SIZE(device_ids); i++) {
++ if (!memcmp(&buffer, device_ids[i].id, CARD_EEPROM_ID_SIZE)) {
++ if (device_ids[i].descr) {
++ printk("acx: EEPROM card ID string check "
++ "found %s card ID: is this %s?\n",
++ device_ids[i].descr, device_ids[i].type);
++ }
++ break;
++ }
++ }
++ if (i == VEC_SIZE(device_ids)) {
++ printk("acx: EEPROM card ID string check found "
++ "unknown card: expected 'Global', got '%.*s\'. "
++ "Please report\n", CARD_EEPROM_ID_SIZE, buffer);
++ }
++}
++#endif /* NONESSENTIAL_FEATURES */
++
++
++/***********************************************************************
++*/
++static void
++acx_s_device_chain_add(struct net_device *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ down(&root_acx_dev_sem);
++ priv->prev_nd = root_acx_dev.newest;
++ root_acx_dev.newest = dev;
++ priv->netdev = dev;
++ up(&root_acx_dev_sem);
++}
++
++static void
++acx_s_device_chain_remove(struct net_device *dev)
++{
++ struct net_device *querydev;
++ struct net_device *olderdev;
++ struct net_device *newerdev;
++
++ down(&root_acx_dev_sem);
++ querydev = root_acx_dev.newest;
++ newerdev = NULL;
++ while (querydev) {
++ olderdev = ((wlandevice_t*)netdev_priv(querydev))->prev_nd;
++ if (0 == strcmp(querydev->name, dev->name)) {
++ if (!newerdev) {
++ /* if we were at the beginning of the
++ * list, then it's the list head that
++ * we need to update to point at the
++ * next older device */
++ root_acx_dev.newest = olderdev;
++ } else {
++ /* it's the device that is newer than us
++ * that we need to update to point at
++ * the device older than us */
++ ((wlandevice_t*)netdev_priv(newerdev))->
++ prev_nd = olderdev;
++ }
++ break;
++ }
++ /* "newerdev" is actually the device of the old iteration,
++ * but since the list starts (root_acx_dev.newest)
++ * with the newest devices,
++ * it's newer than the ones following.
++ * Oh the joys of iterating from newest to oldest :-\ */
++ newerdev = querydev;
++
++ /* keep checking old devices for matches until we hit the end
++ * of the list */
++ querydev = olderdev;
++ }
++ up(&root_acx_dev_sem);
++}
++
++
++/***********************************************************************
++** acx_free_desc_queues
++**
++** Releases the queues that have been allocated, the
++** others have been initialised to NULL so this
++** function can be used if only part of the queues were allocated.
++*/
++static inline void
++acx_free_coherent(struct pci_dev *hwdev, size_t size,
++ void *vaddr, dma_addr_t dma_handle)
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 53)
++ dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev,
++ size, vaddr, dma_handle);
++#else
++ pci_free_consistent(hwdev, size, vaddr, dma_handle);
++#endif
++}
++
++void
++acx_free_desc_queues(wlandevice_t *priv)
++{
++#define ACX_FREE_QUEUE(size, ptr, phyaddr) \
++ if (ptr) { \
++ acx_free_coherent(0, size, ptr, phyaddr); \
++ ptr = NULL; \
++ size = 0; \
++ }
++
++ FN_ENTER;
++
++ ACX_FREE_QUEUE(priv->txhostdesc_area_size, priv->txhostdesc_start, priv->txhostdesc_startphy);
++ ACX_FREE_QUEUE(priv->txbuf_area_size, priv->txbuf_start, priv->txbuf_startphy);
++
++ priv->txdesc_start = NULL;
++
++ ACX_FREE_QUEUE(priv->rxhostdesc_area_size, priv->rxhostdesc_start, priv->rxhostdesc_startphy);
++ ACX_FREE_QUEUE(priv->rxbuf_area_size, priv->rxbuf_start, priv->rxbuf_startphy);
++
++ priv->rxdesc_start = NULL;
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_delete_dma_regions
++*----------------------------------------------------------------*/
++static void
++acx_s_delete_dma_regions(wlandevice_t *priv)
++{
++ unsigned long flags;
++
++ FN_ENTER;
++ /* disable radio Tx/Rx. Shouldn't we use the firmware commands
++ * here instead? Or are we that much down the road that it's no
++ * longer possible here? */
++ acx_write_reg16(priv, IO_ACX_ENABLE, 0);
++
++ acx_s_msleep(100);
++
++ acx_lock(priv, flags);
++ acx_free_desc_queues(priv);
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_probe_pci
++*
++* Probe routine called when a PCI device w/ matching ID is found.
++* Here's the sequence:
++* - Allocate the PCI resources.
++* - Read the PCMCIA attribute memory to make sure we have a WLAN card
++* - Reset the MAC
++* - Initialize the dev and wlan data
++* - Initialize the MAC
++*
++* Arguments:
++* pdev ptr to pci device structure containing info about
++* pci configuration.
++* id ptr to the device id entry that matched this device.
++*
++* Returns:
++* zero - success
++* negative - failed
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++static const u16
++IO_ACX100[] =
++{
++ 0x0000, /* IO_ACX_SOFT_RESET */
++
++ 0x0014, /* IO_ACX_SLV_MEM_ADDR */
++ 0x0018, /* IO_ACX_SLV_MEM_DATA */
++ 0x001c, /* IO_ACX_SLV_MEM_CTL */
++ 0x0020, /* IO_ACX_SLV_END_CTL */
++
++ 0x0034, /* IO_ACX_FEMR */
++
++ 0x007c, /* IO_ACX_INT_TRIG */
++ 0x0098, /* IO_ACX_IRQ_MASK */
++ 0x00a4, /* IO_ACX_IRQ_STATUS_NON_DES */
++ 0x00a8, /* IO_ACX_IRQ_STATUS_CLEAR */
++ 0x00ac, /* IO_ACX_IRQ_ACK */
++ 0x00b0, /* IO_ACX_HINT_TRIG */
++
++ 0x0104, /* IO_ACX_ENABLE */
++
++ 0x0250, /* IO_ACX_EEPROM_CTL */
++ 0x0254, /* IO_ACX_EEPROM_ADDR */
++ 0x0258, /* IO_ACX_EEPROM_DATA */
++ 0x025c, /* IO_ACX_EEPROM_CFG */
++
++ 0x0268, /* IO_ACX_PHY_ADDR */
++ 0x026c, /* IO_ACX_PHY_DATA */
++ 0x0270, /* IO_ACX_PHY_CTL */
++
++ 0x0290, /* IO_ACX_GPIO_OE */
++
++ 0x0298, /* IO_ACX_GPIO_OUT */
++
++ 0x02a4, /* IO_ACX_CMD_MAILBOX_OFFS */
++ 0x02a8, /* IO_ACX_INFO_MAILBOX_OFFS */
++ 0x02ac, /* IO_ACX_EEPROM_INFORMATION */
++
++ 0x02d0, /* IO_ACX_EE_START */
++ 0x02d4, /* IO_ACX_SOR_CFG */
++ 0x02d8 /* IO_ACX_ECPU_CTRL */
++};
++
++static const u16
++IO_ACX111[] =
++{
++ 0x0000, /* IO_ACX_SOFT_RESET */
++
++ 0x0014, /* IO_ACX_SLV_MEM_ADDR */
++ 0x0018, /* IO_ACX_SLV_MEM_DATA */
++ 0x001c, /* IO_ACX_SLV_MEM_CTL */
++ 0x0020, /* IO_ACX_SLV_END_CTL */
++
++ 0x0034, /* IO_ACX_FEMR */
++
++ 0x00b4, /* IO_ACX_INT_TRIG */
++ 0x00d4, /* IO_ACX_IRQ_MASK */
++ /* we need NON_DES (0xf0), not NON_DES_MASK which is at 0xe0: */
++ 0x00f0, /* IO_ACX_IRQ_STATUS_NON_DES */
++ 0x00e4, /* IO_ACX_IRQ_STATUS_CLEAR */
++ 0x00e8, /* IO_ACX_IRQ_ACK */
++ 0x00ec, /* IO_ACX_HINT_TRIG */
++
++ 0x01d0, /* IO_ACX_ENABLE */
++
++ 0x0338, /* IO_ACX_EEPROM_CTL */
++ 0x033c, /* IO_ACX_EEPROM_ADDR */
++ 0x0340, /* IO_ACX_EEPROM_DATA */
++ 0x0344, /* IO_ACX_EEPROM_CFG */
++
++ 0x0350, /* IO_ACX_PHY_ADDR */
++ 0x0354, /* IO_ACX_PHY_DATA */
++ 0x0358, /* IO_ACX_PHY_CTL */
++
++ 0x0374, /* IO_ACX_GPIO_OE */
++
++ 0x037c, /* IO_ACX_GPIO_OUT */
++
++ 0x0388, /* IO_ACX_CMD_MAILBOX_OFFS */
++ 0x038c, /* IO_ACX_INFO_MAILBOX_OFFS */
++ 0x0390, /* IO_ACX_EEPROM_INFORMATION */
++
++ 0x0100, /* IO_ACX_EE_START */
++ 0x0104, /* IO_ACX_SOR_CFG */
++ 0x0108, /* IO_ACX_ECPU_CTRL */
++};
++
++static void
++acx_netdev_init(struct net_device *dev) {}
++
++//FIXME: do the same for USB
++static int
++acx_change_mtu(struct net_device *dev, int mtu)
++{
++ enum {
++ MIN_MTU = 256,
++ MAX_MTU = WLAN_DATA_MAXLEN - (ETH_HLEN)
++ };
++
++ if (mtu < MIN_MTU || mtu > MAX_MTU)
++ return -EINVAL;
++
++ dev->mtu = mtu;
++ return 0;
++}
++
++static int __devinit
++acx_e_probe_pci(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++ unsigned long mem_region1 = 0;
++ unsigned long mem_region2 = 0;
++ unsigned long mem_region1_size;
++ unsigned long mem_region2_size;
++ unsigned long phymem1;
++ unsigned long phymem2;
++ void *mem1 = NULL;
++ void *mem2 = NULL;
++ wlandevice_t *priv = NULL;
++ struct net_device *dev = NULL;
++ const char *chip_name;
++ int result = -EIO;
++ int err;
++ u8 chip_type;
++
++#if SEPARATE_DRIVER_INSTANCES
++ struct pci_dev *tdev;
++ unsigned int inited;
++ static int turn = 0;
++#endif /* SEPARATE_DRIVER_INSTANCES */
++
++ FN_ENTER;
++
++#if SEPARATE_DRIVER_INSTANCES
++ if (card) {
++ turn++;
++ inited = 0;
++ pci_for_each_dev(tdev) {
++ if (tdev->vendor != PCI_VENDOR_ID_TI)
++ continue;
++
++ if (tdev == pdev)
++ break;
++ if (pci_get_drvdata(tdev))
++ inited++;
++ }
++ if (inited + turn != card) {
++ result = -ENODEV;
++ goto done;
++ }
++ }
++#endif /* SEPARATE_DRIVER_INSTANCES */
++
++ /* Enable the PCI device */
++ if (pci_enable_device(pdev)) {
++ printk("acx: pci_enable_device() FAILED\n");
++ result = -ENODEV;
++ goto fail_pci_enable_device;
++ }
++
++ /* enable busmastering (required for CardBus) */
++ pci_set_master(pdev);
++
++ /* chiptype is u8 but id->driver_data is ulong
++ ** Works for now (possible values are 1 and 2) */
++ chip_type = (u8)id->driver_data;
++ /* acx100 and acx111 have different PCI memory regions */
++ if (chip_type == CHIPTYPE_ACX100) {
++ chip_name = name_acx100;
++ mem_region1 = PCI_ACX100_REGION1;
++ mem_region1_size = PCI_ACX100_REGION1_SIZE;
++
++ mem_region2 = PCI_ACX100_REGION2;
++ mem_region2_size = PCI_ACX100_REGION2_SIZE;
++ } else if (chip_type == CHIPTYPE_ACX111) {
++ chip_name = name_acx111;
++ mem_region1 = PCI_ACX111_REGION1;
++ mem_region1_size = PCI_ACX111_REGION1_SIZE;
++
++ mem_region2 = PCI_ACX111_REGION2;
++ mem_region2_size = PCI_ACX111_REGION2_SIZE;
++ } else {
++ printk("acx: unknown chip type 0x%04X\n", chip_type);
++ goto fail_unknown_chiptype;
++ }
++
++ /* Figure out our resources */
++ phymem1 = pci_resource_start(pdev, mem_region1);
++ phymem2 = pci_resource_start(pdev, mem_region2);
++
++ if (!request_mem_region(phymem1, pci_resource_len(pdev, mem_region1), "ACX1xx_1")) {
++ printk("acx: cannot reserve PCI memory region 1 (are you sure "
++ "you have CardBus support in kernel?)\n");
++ goto fail_request_mem_region1;
++ }
++
++ if (!request_mem_region(phymem2, pci_resource_len(pdev, mem_region2), "ACX1xx_2")) {
++ printk("acx: cannot reserve PCI memory region 2\n");
++ goto fail_request_mem_region2;
++ }
++
++ mem1 = ioremap(phymem1, mem_region1_size);
++ if (NULL == mem1) {
++ printk("acx: ioremap() FAILED\n");
++ goto fail_ioremap1;
++ }
++
++ mem2 = ioremap(phymem2, mem_region2_size);
++ if (NULL == mem2) {
++ printk("acx: ioremap() #2 FAILED\n");
++ goto fail_ioremap2;
++ }
++
++ /* Log the device */
++ printk("acx: found %s-based wireless network card at %s, irq:%d, "
++ "phymem1:0x%lX, phymem2:0x%lX, mem1:0x%p, mem1_size:%ld, "
++ "mem2:0x%p, mem2_size:%ld\n",
++ chip_name, pci_name(pdev), pdev->irq, phymem1, phymem2,
++ mem1, mem_region1_size,
++ mem2, mem_region2_size);
++ acxlog(L_ANY, "initial debug setting is 0x%04X\n", acx_debug);
++
++ if (0 == pdev->irq) {
++ printk("acx: can't use IRQ 0\n");
++ goto fail_irq;
++ }
++
++ dev = alloc_netdev(sizeof(wlandevice_t), "wlan%d", acx_netdev_init);
++ /* (NB: memsets to 0 entire area) */
++ if (!dev) {
++ printk("acx: no memory for netdevice structure\n");
++ goto fail_alloc_netdev;
++ }
++
++ ether_setup(dev);
++ dev->open = &acx_e_open;
++ dev->stop = &acx_e_close;
++ dev->hard_start_xmit = &acx_i_start_xmit;
++ dev->get_stats = &acx_e_get_stats;
++ dev->get_wireless_stats = &acx_e_get_wireless_stats;
++#if WIRELESS_EXT >= 13
++ dev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
++#else
++ dev->do_ioctl = &acx_e_ioctl_old;
++#endif
++ dev->set_multicast_list = &acx_i_set_multicast_list;
++ dev->tx_timeout = &acx_i_tx_timeout;
++ dev->change_mtu = &acx_change_mtu;
++ dev->watchdog_timeo = 4 * HZ;
++ dev->irq = pdev->irq;
++ dev->base_addr = pci_resource_start(pdev, 0);
++
++ priv = netdev_priv(dev);
++ spin_lock_init(&priv->lock); /* initial state: unlocked */
++ /* We do not start with downed sem: we want PARANOID_LOCKING to work */
++ sema_init(&priv->sem, 1); /* initial state: 1 (upped) */
++ /* since nobody can see new netdev yet, we can as well
++ ** just _presume_ that we're under sem (instead of actually taking it): */
++ /* acx_sem_lock(priv); */
++ priv->pdev = pdev;
++ priv->dev_type = DEVTYPE_PCI;
++ priv->chip_type = chip_type;
++ priv->chip_name = chip_name;
++ priv->io = (CHIPTYPE_ACX100 == chip_type) ? IO_ACX100 : IO_ACX111;
++ priv->membase = phymem1;
++ priv->iobase = mem1;
++ priv->membase2 = phymem2;
++ priv->iobase2 = mem2;
++ /* to find crashes due to weird driver access
++ * to unconfigured interface (ifup) */
++ priv->mgmt_timer.function = (void (*)(unsigned long))0x0000dead;
++
++#ifdef NONESSENTIAL_FEATURES
++ acx_show_card_eeprom_id(priv);
++#endif /* NONESSENTIAL_FEATURES */
++
++ /* now we have our device, so make sure the kernel doesn't try
++ * to send packets even though we're not associated to a network yet */
++ acx_stop_queue(dev, "after setup");
++
++#ifdef SET_MODULE_OWNER
++ SET_MODULE_OWNER(dev);
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70)
++ /* this define and its netdev member exist since 2.5.70 */
++ SET_NETDEV_DEV(dev, &pdev->dev);
++#endif
++
++ /* register new dev in linked list */
++ acx_s_device_chain_add(dev);
++
++ acxlog(L_IRQ|L_INIT, "using IRQ %d\n", pdev->irq);
++
++ /* need to be able to restore PCI state after a suspend */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
++ /* 2.6.9-rc3-mm2 (2.6.9-bk4, too) introduced this shorter version,
++ then it made its way into 2.6.10 */
++ pci_save_state(pdev);
++#else
++ pci_save_state(pdev, priv->pci_state);
++#endif
++
++ /* NB: acx_read_reg() reads may return bogus data before reset_dev().
++ ** acx100 seems to be more affected than acx111 */
++ if (OK != acx_s_reset_dev(dev)) {
++ goto fail_reset;
++ }
++
++ /* ok, basic setup is finished, now start initialising the card */
++
++ if (OK != acx_read_eeprom_offset(priv, 0x05, &priv->eeprom_version)) {
++ goto fail_read_eeprom_version;
++ }
++
++ if (OK != acx_s_init_mac(dev)) {
++ printk("acx: init_mac() FAILED\n");
++ goto fail_init_mac;
++ }
++ if (OK != acx_s_set_defaults(priv)) {
++ printk("acx: set_defaults() FAILED\n");
++ goto fail_set_defaults;
++ }
++
++ /* needs to be after acx_s_init_mac() due to necessary init stuff */
++ acx_s_get_firmware_version(priv);
++
++ acx_display_hardware_details(priv);
++
++ pci_set_drvdata(pdev, dev);
++
++ /* ...and register the card, AFTER everything else has been set up,
++ * since otherwise an ioctl could step on our feet due to
++ * firmware operations happening in parallel or uninitialized data */
++ err = register_netdev(dev);
++ if (OK != err) {
++ printk("acx: register_netdev() FAILED: %d\n", err);
++ goto fail_register_netdev;
++ }
++
++ acx_carrier_off(dev, "on probe");
++
++#ifdef CONFIG_PROC_FS
++ if (OK != acx_proc_register_entries(dev)) {
++ goto fail_proc_register_entries;
++ }
++#endif
++
++ /* after register_netdev() userspace may start working with dev
++ * (in particular, on other CPUs), we only need to up the sem */
++ /* acx_sem_unlock(priv); */
++
++ printk("acx "WLAN_RELEASE": net device %s, driver compiled "
++ "against wireless extensions %d and Linux %s\n",
++ dev->name, WIRELESS_EXT, UTS_RELEASE);
++
++#if CMD_DISCOVERY
++ great_inquisitor(priv);
++#endif
++
++ result = OK;
++ goto done;
++
++ /* error paths: undo everything in reverse order... */
++
++#ifdef CONFIG_PROC_FS
++fail_proc_register_entries:
++
++ if (priv->dev_state_mask & ACX_STATE_IFACE_UP)
++ acx_s_down(dev);
++
++ unregister_netdev(dev);
++
++ /* after unregister_netdev() userspace is guaranteed to finish
++ * working with it. netdev does not exist anymore.
++ * For paranoid reasons I am taking sem anyway */
++ acx_sem_lock(priv);
++#endif
++
++fail_register_netdev:
++
++ acx_s_delete_dma_regions(priv);
++ pci_set_drvdata(pdev, NULL);
++
++fail_set_defaults:
++fail_init_mac:
++fail_read_eeprom_version:
++fail_reset:
++
++ acx_s_device_chain_remove(dev);
++ free_netdev(dev);
++fail_alloc_netdev:
++fail_irq:
++
++ iounmap(mem2);
++fail_ioremap2:
++
++ iounmap(mem1);
++fail_ioremap1:
++
++ release_mem_region(pci_resource_start(pdev, mem_region2),
++ pci_resource_len(pdev, mem_region2));
++fail_request_mem_region2:
++
++ release_mem_region(pci_resource_start(pdev, mem_region1),
++ pci_resource_len(pdev, mem_region1));
++fail_request_mem_region1:
++fail_unknown_chiptype:
++
++ pci_disable_device(pdev);
++fail_pci_enable_device:
++
++ pci_set_power_state(pdev, 3);
++
++done:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_remove_pci
++*
++* Deallocate PCI resources for the ACX100 chip.
++*
++* This should NOT execute any other hardware operations on the card,
++* since the card might already be ejected. Instead, that should be done
++* in cleanup_module, since the card is most likely still available there.
++*
++* Arguments:
++* pdev ptr to PCI device structure containing info about
++* PCI configuration.
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++static void __devexit
++acx_e_remove_pci(struct pci_dev *pdev)
++{
++ struct net_device *dev;
++ wlandevice_t *priv;
++ unsigned long mem_region1, mem_region2;
++
++ FN_ENTER;
++
++ dev = (struct net_device *) pci_get_drvdata(pdev);
++ if (!dev) {
++ acxlog(L_DEBUG, "%s: card is unused. Skipping any release code\n",
++ __func__);
++ goto end;
++ }
++
++ priv = netdev_priv(dev);
++
++ /* unregister the device to not let the kernel
++ * (e.g. ioctls) access a half-deconfigured device
++ * NB: this will cause acx_e_close() to be called,
++ * thus we shouldn't call it under sem! */
++ acxlog(L_INIT, "removing device %s\n", dev->name);
++ unregister_netdev(dev);
++
++ /* unregister_netdev ensures that no references to us left.
++ * For paranoid reasons we continue to follow the rules */
++ acx_sem_lock(priv);
++
++ if (IS_ACX100(priv)) {
++ mem_region1 = PCI_ACX100_REGION1;
++ mem_region2 = PCI_ACX100_REGION2;
++ } else {
++ mem_region1 = PCI_ACX111_REGION1;
++ mem_region2 = PCI_ACX111_REGION2;
++ }
++
++#ifdef CONFIG_PROC_FS
++ acx_proc_unregister_entries(dev);
++#endif
++
++ /* find our PCI device in the global acx list and remove it */
++ acx_s_device_chain_remove(dev);
++
++ if (priv->dev_state_mask & ACX_STATE_IFACE_UP)
++ acx_s_down(dev);
++
++ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
++
++ acx_s_delete_dma_regions(priv);
++
++ /* finally, clean up PCI bus state */
++ if (priv->iobase) iounmap(priv->iobase);
++ if (priv->iobase2) iounmap(priv->iobase2);
++
++ release_mem_region(pci_resource_start(pdev, mem_region1),
++ pci_resource_len(pdev, mem_region1));
++
++ release_mem_region(pci_resource_start(pdev, mem_region2),
++ pci_resource_len(pdev, mem_region2));
++
++ pci_disable_device(pdev);
++
++ /* remove dev registration */
++ pci_set_drvdata(pdev, NULL);
++
++ /* Free netdev (quite late,
++ * since otherwise we might get caught off-guard
++ * by a netdev timeout handler execution
++ * expecting to see a working dev...)
++ * But don't use free_netdev() here,
++ * it's supported by newer kernels only */
++ free_netdev(dev);
++
++ /* put device into ACPI D3 mode (shutdown) */
++ pci_set_power_state(pdev, 3);
++
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++*/
++#ifdef CONFIG_PM
++static int if_was_up = 0; /* FIXME: HACK, do it correctly sometime instead */
++static int
++acx_e_suspend(struct pci_dev *pdev, pm_message_t state)
++{
++ struct net_device *dev = pci_get_drvdata(pdev);
++ wlandevice_t *priv = netdev_priv(dev);
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ printk("acx: experimental suspend handler called for %p\n", priv);
++ if (netif_device_present(dev)) {
++ if_was_up = 1;
++ acx_s_down(dev);
++ }
++ else
++ if_was_up = 0;
++
++ netif_device_detach(dev); /* This one cannot sleep */
++ acx_s_delete_dma_regions(priv);
++
++ acx_sem_unlock(priv);
++
++ FN_EXIT0;
++ return OK;
++}
++
++static int
++acx_e_resume(struct pci_dev *pdev)
++{
++ struct net_device *dev;
++ wlandevice_t *priv;
++
++ printk(KERN_WARNING "rsm: resume\n");
++ dev = pci_get_drvdata(pdev);
++ printk(KERN_WARNING "rsm: got dev\n");
++
++ if (!netif_running(dev))
++ return 0;
++
++ priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ printk(KERN_WARNING "rsm: got priv\n");
++ FN_ENTER;
++ printk("acx: experimental resume handler called for %p!\n", priv);
++ pci_set_power_state(pdev, 0);
++ acxlog(L_DEBUG, "rsm: power state set\n");
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
++ /* 2.6.9-rc3-mm2 (2.6.9-bk4, too) introduced this shorter version,
++ then it made its way into 2.6.10 */
++ pci_restore_state(pdev);
++#else
++ pci_restore_state(pdev, priv->pci_state);
++#endif
++ acxlog(L_DEBUG, "rsm: PCI state restored\n");
++ acx_s_reset_dev(dev);
++ acxlog(L_DEBUG, "rsm: device reset done\n");
++
++ if (OK != acx_s_init_mac(dev)) {
++ printk("rsm: init_mac FAILED\n");
++ goto fail;
++ }
++ acxlog(L_DEBUG, "rsm: init MAC done\n");
++
++ if (1 == if_was_up)
++ acx_s_up(dev);
++ acxlog(L_DEBUG, "rsm: acx up\n");
++
++ /* now even reload all card parameters as they were before suspend,
++ * and possibly be back in the network again already :-)
++ * FIXME: should this be done in that scheduled task instead?? */
++ if (ACX_STATE_IFACE_UP & priv->dev_state_mask)
++ acx_s_update_card_settings(priv, 0, 1);
++ acxlog(L_DEBUG, "rsm: settings updated\n");
++ netif_device_attach(dev);
++ acxlog(L_DEBUG, "rsm: device attached\n");
++fail: /* we need to return OK here anyway, right? */
++ acx_sem_unlock(priv);
++ FN_EXIT0;
++ return OK;
++}
++#endif /* CONFIG_PM */
++
++
++/*----------------------------------------------------------------
++* acx_s_up
++*
++* Side effects:
++* - Enables on-card interrupt requests
++* - calls acx_start
++* Call context:
++* - process thread
++* Comment:
++* This function is called by acx_open (when ifconfig sets the
++* device as up).
++*----------------------------------------------------------------*/
++static void
++acx_s_up(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++ acx_l_enable_irq(priv);
++ acx_unlock(priv, flags);
++
++ /* acx fw < 1.9.3.e has a hardware timer, and older drivers
++ ** used to use it. But we don't do that anymore, our OS
++ ** has reliable software timers */
++ init_timer(&priv->mgmt_timer);
++ priv->mgmt_timer.function = acx_i_timer;
++ priv->mgmt_timer.data = (unsigned long)priv;
++
++ /* Need to set ACX_STATE_IFACE_UP first, or else
++ ** timer won't be started by acx_set_status() */
++ SET_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_2_STA:
++ /* actual scan cmd will happen in start() */
++ acx_set_status(priv, ACX_STATUS_1_SCANNING); break;
++ case ACX_MODE_3_AP:
++ case ACX_MODE_MONITOR:
++ acx_set_status(priv, ACX_STATUS_4_ASSOCIATED); break;
++ }
++
++ acx_s_start(priv);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_down
++*
++* Side effects:
++* - disables on-card interrupt request
++* Call context:
++* process thread
++* Comment:
++* this disables the netdevice
++*----------------------------------------------------------------*/
++static void
++acx_s_down(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++
++ FN_ENTER;
++
++ /* Disable IRQs first, so that IRQs cannot race with us */
++ acx_lock(priv, flags);
++ acx_l_disable_irq(priv);
++ acx_unlock(priv, flags);
++
++ /* we really don't want to have an asynchronous tasklet disturb us
++ ** after something vital for its job has been shut down, so
++ ** end all remaining work now.
++ **
++ ** NB: carrier_off (done by set_status below) would lead to
++ ** not yet fully understood deadlock in FLUSH_SCHEDULED_WORK().
++ ** That's why we do FLUSH first.
++ **
++ ** NB2: we have a bad locking bug here: FLUSH_SCHEDULED_WORK()
++ ** waits for acx_e_after_interrupt_task to complete if it is running
++ ** on another CPU, but acx_e_after_interrupt_task
++ ** will sleep on sem forever, because it is taken by us!
++ ** Work around that by temporary sem unlock.
++ ** This will fail miserably if we'll be hit by concurrent
++ ** iwconfig or something in between. TODO! */
++ acx_sem_unlock(priv);
++ FLUSH_SCHEDULED_WORK();
++ acx_sem_lock(priv);
++
++ /* This is possible:
++ ** FLUSH_SCHEDULED_WORK -> acx_e_after_interrupt_task ->
++ ** -> set_status(ASSOCIATED) -> wake_queue()
++ ** That's why we stop queue _after_ FLUSH_SCHEDULED_WORK
++ ** lock/unlock is just paranoia, maybe not needed */
++ acx_lock(priv, flags);
++ acx_stop_queue(dev, "during close");
++ acx_set_status(priv, ACX_STATUS_0_STOPPED);
++ acx_unlock(priv, flags);
++
++ /* kernel/timer.c says it's illegal to del_timer_sync()
++ ** a timer which restarts itself. We guarantee this cannot
++ ** ever happen because acx_i_timer() never does this if
++ ** status is ACX_STATUS_0_STOPPED */
++ del_timer_sync(&priv->mgmt_timer);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_open
++*
++* WLAN device open method. Called from p80211netdev when kernel
++* device open (start) method is called in response to the
++* SIOCSIFFLAGS ioctl changing the flags bit IFF_UP
++* from clear to set.
++*
++* Returns:
++* 0 success
++* >0 f/w reported error
++* <0 driver reported error
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++static int
++acx_e_open(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ int result = OK;
++
++ FN_ENTER;
++
++ acxlog(L_INIT, "module count++\n");
++ WLAN_MOD_INC_USE_COUNT;
++
++ acx_sem_lock(priv);
++
++ acx_init_task_scheduler(priv);
++
++ /* request shared IRQ handler */
++ if (request_irq(dev->irq, acx_i_interrupt, SA_SHIRQ, dev->name, dev)) {
++ printk("%s: request_irq FAILED\n", dev->name);
++ result = -EAGAIN;
++ goto done;
++ }
++ acxlog(L_DEBUG|L_IRQ, "request_irq %d successful\n", dev->irq);
++
++ /* ifup device */
++ acx_s_up(dev);
++
++ /* We don't currently have to do anything else.
++ * The setup of the MAC should be subsequently completed via
++ * the mlme commands.
++ * Higher layers know we're ready from dev->start==1 and
++ * dev->tbusy==0. Our rx path knows to pass up received/
++ * frames because of dev->flags&IFF_UP is true.
++ */
++done:
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_close
++*
++* WLAN device close method. Called from network core when kernel
++* device close method is called in response to the
++* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
++* from set to clear.
++* (i.e. called for "ifconfig DEV down")
++*
++* Returns:
++* 0 success
++* >0 f/w reported error
++* <0 driver reported error
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++static int
++acx_e_close(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ /* ifdown device */
++ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
++ if (netif_device_present(dev)) {
++ acx_s_down(dev);
++ }
++
++ /* disable all IRQs, release shared IRQ handler */
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
++ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
++ free_irq(dev->irq, dev);
++
++ /* We currently don't have to do anything else.
++ * Higher layers know we're not ready from dev->start==0 and
++ * dev->tbusy==1. Our rx path knows to not pass up received
++ * frames because of dev->flags&IFF_UP is false.
++ */
++ acxlog(L_INIT, "module count--\n");
++ WLAN_MOD_DEC_USE_COUNT;
++
++ acx_sem_unlock(priv);
++
++ acxlog(L_INIT, "closed device\n");
++ FN_EXIT0;
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_i_tx_timeout
++*
++* Called from network core. Must not sleep!
++*----------------------------------------------------------------*/
++static void
++acx_i_tx_timeout(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ unsigned int tx_num_cleaned;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++
++ /* clean processed tx descs, they may have been completely full */
++ tx_num_cleaned = acx_l_clean_tx_desc(priv);
++
++ /* nothing cleaned, yet (almost) no free buffers available?
++ * --> clean all tx descs, no matter which status!!
++ * Note that I strongly suspect that doing emergency cleaning
++ * may confuse the firmware. This is a last ditch effort to get
++ * ANYTHING to work again...
++ *
++ * TODO: it's best to simply reset & reinit hw from scratch...
++ */
++ if ((priv->tx_free <= TX_EMERG_CLEAN) && (tx_num_cleaned == 0)) {
++ printk("%s: FAILED to free any of the many full tx buffers. "
++ "Switching to emergency freeing. "
++ "Please report!\n", dev->name);
++ acx_l_clean_tx_desc_emergency(priv);
++ }
++
++ if (acx_queue_stopped(dev) && (ACX_STATUS_4_ASSOCIATED == priv->status))
++ acx_wake_queue(dev, "after tx timeout");
++
++ /* stall may have happened due to radio drift, so recalib radio */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
++
++ /* do unimportant work last */
++ printk("%s: tx timeout!\n", dev->name);
++ priv->stats.tx_errors++;
++
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_get_stats
++*----------------------------------------------------------------*/
++static struct net_device_stats*
++acx_e_get_stats(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ return &priv->stats;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_get_wireless_stats
++*----------------------------------------------------------------*/
++static struct iw_statistics*
++acx_e_get_wireless_stats(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ return &priv->wstats;
++}
++
++
++/*----------------------------------------------------------------
++* acx_i_set_multicast_list
++* FIXME: most likely needs refinement
++*----------------------------------------------------------------*/
++static void
++acx_i_set_multicast_list(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++
++ /* firmwares don't have allmulti capability,
++ * so just use promiscuous mode instead in this case. */
++ if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
++ SET_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
++ CLEAR_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
++ SET_BIT(priv->set_mask, SET_RXCONFIG);
++ /* let kernel know in case *we* needed to set promiscuous */
++ dev->flags |= (IFF_PROMISC|IFF_ALLMULTI);
++ } else {
++ CLEAR_BIT(priv->rx_config_1, RX_CFG1_RCV_PROMISCUOUS);
++ SET_BIT(priv->rx_config_1, RX_CFG1_FILTER_ALL_MULTI);
++ SET_BIT(priv->set_mask, SET_RXCONFIG);
++ dev->flags &= ~(IFF_PROMISC|IFF_ALLMULTI);
++ }
++
++ /* cannot update card settings directly here, atomic context */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_UPDATE_CARD_CFG);
++
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++
++static void
++acx_l_update_link_quality_led(wlandevice_t *priv)
++{
++ int qual;
++
++ qual = acx_signal_determine_quality(priv->wstats.qual.level, priv->wstats.qual.noise);
++ if (qual > priv->brange_max_quality)
++ qual = priv->brange_max_quality;
++
++ if (time_after(jiffies, priv->brange_time_last_state_change +
++ (HZ/2 - HZ/2 * (unsigned long) qual/priv->brange_max_quality ) )) {
++ acx_l_power_led(priv, (priv->brange_last_state == 0));
++ priv->brange_last_state ^= 1; /* toggle */
++ priv->brange_time_last_state_change = jiffies;
++ }
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_enable_irq
++*----------------------------------------------------------------*/
++static void
++acx_l_enable_irq(wlandevice_t *priv)
++{
++ FN_ENTER;
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask);
++ acx_write_reg16(priv, IO_ACX_FEMR, 0x8000);
++ priv->irqs_active = 1;
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_disable_irq
++*----------------------------------------------------------------*/
++static void
++acx_l_disable_irq(wlandevice_t *priv)
++{
++ FN_ENTER;
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, priv->irq_mask_off);
++ acx_write_reg16(priv, IO_ACX_FEMR, 0x0);
++ priv->irqs_active = 0;
++ FN_EXIT0;
++}
++
++/* scan is complete. all frames now on the receive queue are valid */
++#define INFO_SCAN_COMPLETE 0x0001
++#define INFO_WEP_KEY_NOT_FOUND 0x0002
++/* hw has been reset as the result of a watchdog timer timeout */
++#define INFO_WATCH_DOG_RESET 0x0003
++/* failed to send out NULL frame from PS mode notification to AP */
++/* recommended action: try entering 802.11 PS mode again */
++#define INFO_PS_FAIL 0x0004
++/* encryption/decryption process on a packet failed */
++#define INFO_IV_ICV_FAILURE 0x0005
++
++static void
++acx_l_handle_info_irq(wlandevice_t *priv)
++{
++#if ACX_DEBUG
++ static const char * const info_type_msg[] = {
++ "(unknown)",
++ "scan complete",
++ "WEP key not found",
++ "internal watchdog reset was done",
++ "failed to send powersave (NULL frame) notification to AP",
++ "encrypt/decrypt on a packet has failed",
++ "TKIP tx keys disabled",
++ "TKIP rx keys disabled",
++ "TKIP rx: key ID not found",
++ "???",
++ "???",
++ "???",
++ "???",
++ "???",
++ "???",
++ "???",
++ "TKIP IV value exceeds thresh"
++ };
++#endif
++ acx_read_info_status(priv);
++ acxlog(L_IRQ, "got Info IRQ: status 0x%04X type 0x%04X: %s\n",
++ priv->info_status, priv->info_type,
++ info_type_msg[(priv->info_type >= VEC_SIZE(info_type_msg)) ?
++ 0 : priv->info_type]
++ );
++}
++
++
++/*----------------------------------------------------------------
++* acx_i_interrupt
++*
++* IRQ handler (atomic context, must not sleep, blah, blah)
++*----------------------------------------------------------------*/
++static void
++acx_log_unusual_irq(u16 irqtype) {
++ /*
++ if (!printk_ratelimit())
++ return;
++ */
++
++ printk("acx: got");
++ if (irqtype & HOST_INT_RX_DATA) {
++ printk(" Rx_Data");
++ }
++ /* HOST_INT_TX_COMPLETE */
++ if (irqtype & HOST_INT_TX_XFER) {
++ printk(" Tx_Xfer");
++ }
++ /* HOST_INT_RX_COMPLETE */
++ if (irqtype & HOST_INT_DTIM) {
++ printk(" DTIM");
++ }
++ if (irqtype & HOST_INT_BEACON) {
++ printk(" Beacon");
++ }
++ if (irqtype & HOST_INT_TIMER) {
++ acxlog(L_IRQ, " Timer");
++ }
++ if (irqtype & HOST_INT_KEY_NOT_FOUND) {
++ printk(" Key_Not_Found");
++ }
++ if (irqtype & HOST_INT_IV_ICV_FAILURE) {
++ printk(" IV_ICV_Failure");
++ }
++ /* HOST_INT_CMD_COMPLETE */
++ /* HOST_INT_INFO */
++ if (irqtype & HOST_INT_OVERFLOW) {
++ printk(" Overflow");
++ }
++ if (irqtype & HOST_INT_PROCESS_ERROR) {
++ printk(" Process_Error");
++ }
++ /* HOST_INT_SCAN_COMPLETE */
++ if (irqtype & HOST_INT_FCS_THRESHOLD) {
++ printk(" FCS_Threshold");
++ }
++ if (irqtype & HOST_INT_UNKNOWN) {
++ printk(" Unknown");
++ }
++ printk(" IRQ(s)\n");
++}
++
++static irqreturn_t
++acx_i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ wlandevice_t *priv;
++ unsigned long flags;
++ unsigned int irqcount = MAX_IRQLOOPS_PER_JIFFY;
++ u16 irqtype, unmasked;
++
++ priv = (wlandevice_t *) (((netdevice_t *) dev_id)->priv);
++
++ /* LOCKING: can just spin_lock() since IRQs are disabled anyway.
++ * I am paranoid */
++ acx_lock(priv, flags);
++
++ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
++ if (unlikely(0xffff == unmasked)) {
++ /* 0xffff value hints at missing hardware,
++ * so don't do anything.
++ * FIXME: that's not very clean - maybe we are able to
++ * establish a flag which definitely tells us that some
++ * hardware is absent and which we could check here?
++ * Hmm, but other drivers do the very same thing... */
++ acxlog(L_IRQ, "IRQ type:FFFF - device removed? IRQ_NONE\n");
++ goto none;
++ }
++
++ /* We will check only "interesting" IRQ types */
++ irqtype = unmasked & ~priv->irq_mask;
++ if (!irqtype) {
++ /* We are on a shared IRQ line and it wasn't our IRQ */
++ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X - all are masked, IRQ_NONE\n",
++ unmasked, priv->irq_mask);
++ goto none;
++ }
++
++ /* Done here because IRQ_NONEs taking three lines of log
++ ** drive me crazy */
++ FN_ENTER;
++
++#define IRQ_ITERATE 1
++#if IRQ_ITERATE
++if (jiffies != priv->irq_last_jiffies) {
++ priv->irq_loops_this_jiffy = 0;
++ priv->irq_last_jiffies = jiffies;
++}
++
++/* safety condition; we'll normally abort loop below
++ * in case no IRQ type occurred */
++while (--irqcount) {
++#endif
++ /* ACK all IRQs asap */
++ acx_write_reg16(priv, IO_ACX_IRQ_ACK, 0xffff);
++
++ acxlog(L_IRQ, "IRQ type:%04X, mask:%04X, type & ~mask:%04X\n",
++ unmasked, priv->irq_mask, irqtype);
++
++ /* Handle most important IRQ types first */
++ if (irqtype & HOST_INT_RX_COMPLETE) {
++ acxlog(L_IRQ, "got Rx_Complete IRQ\n");
++ acx_l_process_rx_desc(priv);
++ }
++ if (irqtype & HOST_INT_TX_COMPLETE) {
++ acxlog(L_IRQ, "got Tx_Complete IRQ\n");
++ /* don't clean up on each Tx complete, wait a bit
++ * unless we're going towards full, in which case
++ * we do it immediately, too (otherwise we might lockup
++ * with a full Tx buffer if we go into
++ * acx_l_clean_tx_desc() at a time when we won't wakeup
++ * the net queue in there for some reason...) */
++ if (priv->tx_free <= TX_START_CLEAN) {
++#if TX_CLEANUP_IN_SOFTIRQ
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_TX_CLEANUP);
++#else
++ acx_l_clean_tx_desc(priv);
++#endif
++ }
++ }
++
++ /* Less frequent ones */
++ if (irqtype & (0
++ | HOST_INT_CMD_COMPLETE
++ | HOST_INT_INFO
++ | HOST_INT_SCAN_COMPLETE
++ )) {
++ if (irqtype & HOST_INT_CMD_COMPLETE) {
++ acxlog(L_IRQ, "got Command_Complete IRQ\n");
++ /* save the state for the running issue_cmd() */
++ SET_BIT(priv->irq_status, HOST_INT_CMD_COMPLETE);
++ }
++ if (irqtype & HOST_INT_INFO) {
++ acx_l_handle_info_irq(priv);
++ }
++ if (irqtype & HOST_INT_SCAN_COMPLETE) {
++ acxlog(L_IRQ, "got Scan_Complete IRQ\n");
++ /* need to do that in process context */
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_COMPLETE_SCAN);
++ /* remember that fw is not scanning anymore */
++ SET_BIT(priv->irq_status, HOST_INT_SCAN_COMPLETE);
++ }
++ }
++
++ /* These we just log, but either they happen rarely
++ * or we keep them masked out */
++ if (irqtype & (0
++ | HOST_INT_RX_DATA
++ /* | HOST_INT_TX_COMPLETE */
++ | HOST_INT_TX_XFER
++ /* | HOST_INT_RX_COMPLETE */
++ | HOST_INT_DTIM
++ | HOST_INT_BEACON
++ | HOST_INT_TIMER
++ | HOST_INT_KEY_NOT_FOUND
++ | HOST_INT_IV_ICV_FAILURE
++ /* | HOST_INT_CMD_COMPLETE */
++ /* | HOST_INT_INFO */
++ | HOST_INT_OVERFLOW
++ | HOST_INT_PROCESS_ERROR
++ /* | HOST_INT_SCAN_COMPLETE */
++ | HOST_INT_FCS_THRESHOLD
++ | HOST_INT_UNKNOWN
++ )) {
++ acx_log_unusual_irq(irqtype);
++ }
++
++#if IRQ_ITERATE
++ unmasked = acx_read_reg16(priv, IO_ACX_IRQ_STATUS_CLEAR);
++ irqtype = unmasked & ~priv->irq_mask;
++ /* Bail out if no new IRQ bits or if all are masked out */
++ if (!irqtype)
++ break;
++
++ if (unlikely(++priv->irq_loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY)) {
++ printk(KERN_ERR "acx: too many interrupts per jiffy!\n");
++ /* Looks like card floods us with IRQs! Try to stop that */
++ acx_write_reg16(priv, IO_ACX_IRQ_MASK, 0xffff);
++ /* This will short-circuit all future attempts to handle IRQ.
++ * We cant do much more... */
++ priv->irq_mask = 0;
++ break;
++ }
++}
++#endif
++ /* Routine to perform blink with range */
++ if (unlikely(priv->led_power == 2))
++ acx_l_update_link_quality_led(priv);
++
++/* handled: */
++ /* acx_write_flush(priv); - not needed, last op was read anyway */
++ acx_unlock(priv, flags);
++ FN_EXIT0;
++ return IRQ_HANDLED;
++
++none:
++ acx_unlock(priv, flags);
++ return IRQ_NONE;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_power_led
++*----------------------------------------------------------------*/
++void
++acx_l_power_led(wlandevice_t *priv, int enable)
++{
++ u16 gpio_pled = IS_ACX111(priv) ? 0x0040 : 0x0800;
++
++ /* A hack. Not moving message rate limiting to priv->xxx
++ * (it's only a debug message after all) */
++ static int rate_limit = 0;
++
++ if (rate_limit++ < 3)
++ acxlog(L_IOCTL, "Please report in case toggling the power "
++ "LED doesn't work for your card!\n");
++ if (enable)
++ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
++ acx_read_reg16(priv, IO_ACX_GPIO_OUT) & ~gpio_pled);
++ else
++ acx_write_reg16(priv, IO_ACX_GPIO_OUT,
++ acx_read_reg16(priv, IO_ACX_GPIO_OUT) | gpio_pled);
++}
++
++
++/***********************************************************************
++** Ioctls
++*/
++
++/***********************************************************************
++*/
++int
++acx111pci_ioctl_info(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++#if ACX_DEBUG
++ wlandevice_t *priv = netdev_priv(dev);
++ rxdesc_t *rxdesc;
++ txdesc_t *txdesc;
++ rxhostdesc_t *rxhostdesc;
++ txhostdesc_t *txhostdesc;
++ struct acx111_ie_memoryconfig memconf;
++ struct acx111_ie_queueconfig queueconf;
++ unsigned long flags;
++ int i;
++ char memmap[0x34];
++ char rxconfig[0x8];
++ char fcserror[0x8];
++ char ratefallback[0x5];
++
++ if ( !(acx_debug & (L_IOCTL|L_DEBUG)) )
++ return OK;
++ /* using printk() since we checked debug flag already */
++
++ acx_sem_lock(priv);
++
++ if (!IS_ACX111(priv)) {
++ printk("acx111-specific function called "
++ "with non-acx111 chip, aborting\n");
++ goto end_ok;
++ }
++
++ /* get Acx111 Memory Configuration */
++ memset(&memconf, 0, sizeof(memconf));
++ /* BTW, fails with 12 (Write only) error code.
++ ** Retained for easy testing of issue_cmd error handling :) */
++ acx_s_interrogate(priv, &memconf, ACX1xx_IE_QUEUE_CONFIG);
++
++ /* get Acx111 Queue Configuration */
++ memset(&queueconf, 0, sizeof(queueconf));
++ acx_s_interrogate(priv, &queueconf, ACX1xx_IE_MEMORY_CONFIG_OPTIONS);
++
++ /* get Acx111 Memory Map */
++ memset(memmap, 0, sizeof(memmap));
++ acx_s_interrogate(priv, &memmap, ACX1xx_IE_MEMORY_MAP);
++
++ /* get Acx111 Rx Config */
++ memset(rxconfig, 0, sizeof(rxconfig));
++ acx_s_interrogate(priv, &rxconfig, ACX1xx_IE_RXCONFIG);
++
++ /* get Acx111 fcs error count */
++ memset(fcserror, 0, sizeof(fcserror));
++ acx_s_interrogate(priv, &fcserror, ACX1xx_IE_FCS_ERROR_COUNT);
++
++ /* get Acx111 rate fallback */
++ memset(ratefallback, 0, sizeof(ratefallback));
++ acx_s_interrogate(priv, &ratefallback, ACX1xx_IE_RATE_FALLBACK);
++
++ /* force occurrence of a beacon interrupt */
++ /* TODO: comment why is this necessary */
++ acx_write_reg16(priv, IO_ACX_HINT_TRIG, HOST_INT_BEACON);
++
++ /* dump Acx111 Mem Configuration */
++ printk("dump mem config:\n"
++ "data read: %d, struct size: %d\n"
++ "Number of stations: %1X\n"
++ "Memory block size: %1X\n"
++ "tx/rx memory block allocation: %1X\n"
++ "count rx: %X / tx: %X queues\n"
++ "options %1X\n"
++ "fragmentation %1X\n"
++ "Rx Queue 1 Count Descriptors: %X\n"
++ "Rx Queue 1 Host Memory Start: %X\n"
++ "Tx Queue 1 Count Descriptors: %X\n"
++ "Tx Queue 1 Attributes: %X\n",
++ memconf.len, (int) sizeof(memconf),
++ memconf.no_of_stations,
++ memconf.memory_block_size,
++ memconf.tx_rx_memory_block_allocation,
++ memconf.count_rx_queues, memconf.count_tx_queues,
++ memconf.options,
++ memconf.fragmentation,
++ memconf.rx_queue1_count_descs,
++ acx2cpu(memconf.rx_queue1_host_rx_start),
++ memconf.tx_queue1_count_descs,
++ memconf.tx_queue1_attributes);
++
++ /* dump Acx111 Queue Configuration */
++ printk("dump queue head:\n"
++ "data read: %d, struct size: %d\n"
++ "tx_memory_block_address (from card): %X\n"
++ "rx_memory_block_address (from card): %X\n"
++ "rx1_queue address (from card): %X\n"
++ "tx1_queue address (from card): %X\n"
++ "tx1_queue attributes (from card): %X\n",
++ queueconf.len, (int) sizeof(queueconf),
++ queueconf.tx_memory_block_address,
++ queueconf.rx_memory_block_address,
++ queueconf.rx1_queue_address,
++ queueconf.tx1_queue_address,
++ queueconf.tx1_attributes);
++
++ /* dump Acx111 Mem Map */
++ printk("dump mem map:\n"
++ "data read: %d, struct size: %d\n"
++ "Code start: %X\n"
++ "Code end: %X\n"
++ "WEP default key start: %X\n"
++ "WEP default key end: %X\n"
++ "STA table start: %X\n"
++ "STA table end: %X\n"
++ "Packet template start: %X\n"
++ "Packet template end: %X\n"
++ "Queue memory start: %X\n"
++ "Queue memory end: %X\n"
++ "Packet memory pool start: %X\n"
++ "Packet memory pool end: %X\n"
++ "iobase: %p\n"
++ "iobase2: %p\n",
++ *((u16 *)&memmap[0x02]), (int) sizeof(memmap),
++ *((u32 *)&memmap[0x04]),
++ *((u32 *)&memmap[0x08]),
++ *((u32 *)&memmap[0x0C]),
++ *((u32 *)&memmap[0x10]),
++ *((u32 *)&memmap[0x14]),
++ *((u32 *)&memmap[0x18]),
++ *((u32 *)&memmap[0x1C]),
++ *((u32 *)&memmap[0x20]),
++ *((u32 *)&memmap[0x24]),
++ *((u32 *)&memmap[0x28]),
++ *((u32 *)&memmap[0x2C]),
++ *((u32 *)&memmap[0x30]),
++ priv->iobase,
++ priv->iobase2);
++
++ /* dump Acx111 Rx Config */
++ printk("dump rx config:\n"
++ "data read: %d, struct size: %d\n"
++ "rx config: %X\n"
++ "rx filter config: %X\n",
++ *((u16 *)&rxconfig[0x02]), (int) sizeof(rxconfig),
++ *((u16 *)&rxconfig[0x04]),
++ *((u16 *)&rxconfig[0x06]));
++
++ /* dump Acx111 fcs error */
++ printk("dump fcserror:\n"
++ "data read: %d, struct size: %d\n"
++ "fcserrors: %X\n",
++ *((u16 *)&fcserror[0x02]), (int) sizeof(fcserror),
++ *((u32 *)&fcserror[0x04]));
++
++ /* dump Acx111 rate fallback */
++ printk("dump rate fallback:\n"
++ "data read: %d, struct size: %d\n"
++ "ratefallback: %X\n",
++ *((u16 *)&ratefallback[0x02]), (int) sizeof(ratefallback),
++ *((u8 *)&ratefallback[0x04]));
++
++ /* protect against IRQ */
++ acx_lock(priv, flags);
++
++ /* dump acx111 internal rx descriptor ring buffer */
++ rxdesc = priv->rxdesc_start;
++
++ /* loop over complete receive pool */
++ if (rxdesc) for (i = 0; i < RX_CNT; i++) {
++ printk("\ndump internal rxdesc %d:\n"
++ "mem pos %p\n"
++ "next 0x%X\n"
++ "acx mem pointer (dynamic) 0x%X\n"
++ "CTL (dynamic) 0x%X\n"
++ "Rate (dynamic) 0x%X\n"
++ "RxStatus (dynamic) 0x%X\n"
++ "Mod/Pre (dynamic) 0x%X\n",
++ i,
++ rxdesc,
++ acx2cpu(rxdesc->pNextDesc),
++ acx2cpu(rxdesc->ACXMemPtr),
++ rxdesc->Ctl_8,
++ rxdesc->rate,
++ rxdesc->error,
++ rxdesc->SNR);
++ rxdesc++;
++ }
++
++ /* dump host rx descriptor ring buffer */
++
++ rxhostdesc = priv->rxhostdesc_start;
++
++ /* loop over complete receive pool */
++ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
++ printk("\ndump host rxdesc %d:\n"
++ "mem pos %p\n"
++ "buffer mem pos 0x%X\n"
++ "buffer mem offset 0x%X\n"
++ "CTL 0x%X\n"
++ "Length 0x%X\n"
++ "next 0x%X\n"
++ "Status 0x%X\n",
++ i,
++ rxhostdesc,
++ acx2cpu(rxhostdesc->data_phy),
++ rxhostdesc->data_offset,
++ le16_to_cpu(rxhostdesc->Ctl_16),
++ le16_to_cpu(rxhostdesc->length),
++ acx2cpu(rxhostdesc->desc_phy_next),
++ rxhostdesc->Status);
++ rxhostdesc++;
++ }
++
++ /* dump acx111 internal tx descriptor ring buffer */
++ txdesc = priv->txdesc_start;
++
++ /* loop over complete transmit pool */
++ if (txdesc) for (i = 0; i < TX_CNT; i++) {
++ printk("\ndump internal txdesc %d:\n"
++ "size 0x%X\n"
++ "mem pos %p\n"
++ "next 0x%X\n"
++ "acx mem pointer (dynamic) 0x%X\n"
++ "host mem pointer (dynamic) 0x%X\n"
++ "length (dynamic) 0x%X\n"
++ "CTL (dynamic) 0x%X\n"
++ "CTL2 (dynamic) 0x%X\n"
++ "Status (dynamic) 0x%X\n"
++ "Rate (dynamic) 0x%X\n",
++ i,
++ (int) sizeof(struct txdesc),
++ txdesc,
++ acx2cpu(txdesc->pNextDesc),
++ acx2cpu(txdesc->AcxMemPtr),
++ acx2cpu(txdesc->HostMemPtr),
++ le16_to_cpu(txdesc->total_length),
++ txdesc->Ctl_8,
++ txdesc->Ctl2_8, txdesc->error,
++ txdesc->u.r1.rate);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++
++ /* dump host tx descriptor ring buffer */
++
++ txhostdesc = priv->txhostdesc_start;
++
++ /* loop over complete host send pool */
++ if (txhostdesc) for (i = 0; i < TX_CNT * 2; i++) {
++ printk("\ndump host txdesc %d:\n"
++ "mem pos %p\n"
++ "buffer mem pos 0x%X\n"
++ "buffer mem offset 0x%X\n"
++ "CTL 0x%X\n"
++ "Length 0x%X\n"
++ "next 0x%X\n"
++ "Status 0x%X\n",
++ i,
++ txhostdesc,
++ acx2cpu(txhostdesc->data_phy),
++ txhostdesc->data_offset,
++ le16_to_cpu(txhostdesc->Ctl_16),
++ le16_to_cpu(txhostdesc->length),
++ acx2cpu(txhostdesc->desc_phy_next),
++ le32_to_cpu(txhostdesc->Status));
++ txhostdesc++;
++ }
++
++ /* acx_write_reg16(priv, 0xb4, 0x4); */
++
++ acx_unlock(priv, flags);
++end_ok:
++
++ acx_sem_unlock(priv);
++#endif /* ACX_DEBUG */
++ return OK;
++}
++
++
++/***********************************************************************
++*/
++int
++acx100pci_ioctl_set_phy_amp_bias(
++ struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq,
++ char *extra)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ u16 gpio_old;
++
++ if (!IS_ACX100(priv)) {
++ /* WARNING!!!
++ * Removing this check *might* damage
++ * hardware, since we're tweaking GPIOs here after all!!!
++ * You've been warned...
++ * WARNING!!! */
++ printk("acx: sorry, setting bias level for non-acx100 "
++ "is not supported yet\n");
++ return OK;
++ }
++
++ if (*extra > 7) {
++ printk("acx: invalid bias parameter, range is 0-7\n");
++ return -EINVAL;
++ }
++
++ acx_sem_lock(priv);
++
++ /* Need to lock accesses to [IO_ACX_GPIO_OUT]:
++ * IRQ handler uses it to update LED */
++ acx_lock(priv, flags);
++ gpio_old = acx_read_reg16(priv, IO_ACX_GPIO_OUT);
++ acx_write_reg16(priv, IO_ACX_GPIO_OUT, (gpio_old & 0xf8ff) | ((u16)*extra << 8));
++ acx_unlock(priv, flags);
++
++ acxlog(L_DEBUG, "gpio_old: 0x%04X\n", gpio_old);
++ printk("%s: PHY power amplifier bias: old:%d, new:%d\n",
++ dev->name,
++ (gpio_old & 0x0700) >> 8, (unsigned char)*extra);
++
++ acx_sem_unlock(priv);
++
++ return OK;
++}
++
++
++/***************************************************************
++** acxpci_l_alloc_tx
++** Actually returns a txdesc_t* ptr
++*/
++tx_t*
++acxpci_l_alloc_tx(wlandevice_t* priv)
++{
++ struct txdesc *txdesc;
++ u8 ctl8;
++
++ FN_ENTER;
++
++ txdesc = get_txdesc(priv, priv->tx_head);
++ ctl8 = txdesc->Ctl_8;
++ if (unlikely(DESC_CTL_HOSTOWN != (ctl8 & DESC_CTL_DONE))) {
++ /* whoops, descr at current index is not free, so probably
++ * ring buffer already full */
++ /* FIXME: this causes a deadlock situation (endless
++ * loop) in case the current descriptor remains busy,
++ * so handle it a bit better in the future!! */
++ printk("acx: BUG: tx_head->Ctl8=0x%02X, (0x%02X & "
++ "0x"DESC_CTL_DONE_STR") != 0x"DESC_CTL_HOSTOWN_STR
++ ": failed to find free tx descr\n",
++ ctl8, ctl8);
++ txdesc = NULL;
++ goto end;
++ }
++
++ priv->tx_free--;
++ acxlog(L_BUFT, "tx: got desc %u, %u remain\n",
++ priv->tx_head, priv->tx_free);
++
++/*
++ * This comment is probably not entirely correct, needs further discussion
++ * (restored commented-out code below to fix Tx ring buffer overflow,
++ * since it's much better to have a slightly less efficiently used ring
++ * buffer rather than one which easily overflows):
++ *
++ * This doesn't do anything other than limit our maximum number of
++ * buffers used at a single time (we might as well just declare
++ * TX_STOP_QUEUE less descriptors when we open up.) We should just let it
++ * slide here, and back off TX_STOP_QUEUE in acx_l_clean_tx_desc, when given the
++ * opportunity to let the queue start back up.
++ */
++ if (priv->tx_free < TX_STOP_QUEUE) {
++ acxlog(L_BUF, "stop queue (%u tx desc left)\n",
++ priv->tx_free);
++ acx_stop_queue(priv->netdev, NULL);
++ }
++
++ /* returning current descriptor, so advance to next free one */
++ priv->tx_head = (priv->tx_head + 1) % TX_CNT;
++end:
++ FN_EXIT0;
++
++ return (tx_t*)txdesc;
++}
++
++
++/***********************************************************************
++*/
++void*
++acxpci_l_get_txbuf(wlandevice_t *priv, tx_t* tx_opaque)
++{
++ return acx_get_txhostdesc(priv, (txdesc_t*)tx_opaque)->data;
++}
++
++
++/***********************************************************************
++** acxpci_l_tx_data
++**
++** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
++** Can be called from acx_i_start_xmit (data frames from net core).
++*/
++void
++acxpci_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int len)
++{
++ txdesc_t *txdesc = (txdesc_t*)tx_opaque;
++ txhostdesc_t *hostdesc1, *hostdesc2;
++ client_t *clt;
++ u8 Ctl_8, Ctl2_8;
++
++ FN_ENTER;
++
++ /* fw doesn't tx such packets anyhow */
++ if (len < WLAN_HDR_A3_LEN)
++ goto end;
++
++ hostdesc1 = acx_get_txhostdesc(priv, txdesc);
++ hostdesc2 = hostdesc1 + 1;
++
++ /* modify flag status in separate variable to be able to write it back
++ * in one big swoop later (also in order to have less device memory
++ * accesses) */
++ Ctl_8 = txdesc->Ctl_8;
++ Ctl2_8 = txdesc->Ctl2_8;
++
++ /* DON'T simply set Ctl field to 0 here globally,
++ * it needs to maintain a consistent flag status (those are state flags!!),
++ * otherwise it may lead to severe disruption. Only set or reset particular
++ * flags at the exact moment this is needed...
++ * FIXME: what about Ctl2? Equally problematic? */
++
++ /* let chip do RTS/CTS handshaking before sending
++ * in case packet size exceeds threshold */
++ if (len > priv->rts_threshold)
++ SET_BIT(Ctl2_8, DESC_CTL2_RTS);
++ else
++ CLEAR_BIT(Ctl2_8, DESC_CTL2_RTS);
++
++#ifdef DEBUG_WEP
++ if (priv->wep_enabled)
++ SET_BIT(Ctl2_8, DESC_CTL2_WEP);
++ else
++ CLEAR_BIT(Ctl2_8, DESC_CTL2_WEP);
++#endif
++
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_3_AP:
++ clt = acx_l_sta_list_get(priv, ((wlan_hdr_t*)hostdesc1->data)->a1);
++ break;
++ case ACX_MODE_2_STA:
++ clt = priv->ap_client;
++ break;
++#if 0
++/* testing was done on acx111: */
++ case ACX_MODE_MONITOR:
++ SET_BIT(Ctl2_8, 0
++/* sends CTS to self before packet */
++ + DESC_CTL2_SEQ /* don't increase sequence field */
++/* not working (looks like good fcs is still added) */
++ + DESC_CTL2_FCS /* don't add the FCS */
++/* not tested */
++ + DESC_CTL2_MORE_FRAG
++/* not tested */
++ + DESC_CTL2_RETRY /* don't increase retry field */
++/* not tested */
++ + DESC_CTL2_POWER /* don't increase power mgmt. field */
++/* no effect */
++ + DESC_CTL2_WEP /* encrypt this frame */
++/* not tested */
++ + DESC_CTL2_DUR /* don't increase duration field */
++ );
++ /* fallthrough */
++#endif
++ default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
++ clt = NULL;
++ break;
++ }
++
++ if (unlikely(clt && !clt->rate_cur)) {
++ printk("acx: driver bug! bad ratemask\n");
++ goto end;
++ }
++
++ /* used in tx cleanup routine for auto rate and accounting: */
++ acx_put_txc(priv, txdesc, clt);
++
++ txdesc->total_length = cpu_to_le16(len);
++ hostdesc2->length = cpu_to_le16(len - WLAN_HDR_A3_LEN);
++ if (IS_ACX111(priv)) {
++ u16 rate_cur = clt ? clt->rate_cur : priv->rate_bcast;
++ /* note that if !txdesc->do_auto, txrate->cur
++ ** has only one nonzero bit */
++ txdesc->u.r2.rate111 = cpu_to_le16(
++ rate_cur
++ /* WARNING: I was never able to make it work with prism54 AP.
++ ** It was falling down to 1Mbit where shortpre is not applicable,
++ ** and not working at all at "5,11 basic rates only" setting.
++ ** I even didn't see tx packets in radio packet capture.
++ ** Disabled for now --vda */
++ /*| ((clt->shortpre && clt->cur!=RATE111_1) ? RATE111_SHORTPRE : 0) */
++ );
++#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
++ /* should add this to rate111 above as necessary */
++ | (clt->pbcc511 ? RATE111_PBCC511 : 0)
++#endif
++ hostdesc1->length = cpu_to_le16(len);
++ } else { /* ACX100 */
++ u8 rate_100 = clt ? clt->rate_100 : priv->rate_bcast100;
++ txdesc->u.r1.rate = rate_100;
++#ifdef TODO_FIGURE_OUT_WHEN_TO_SET_THIS
++ if (clt->pbcc511) {
++ if (n == RATE100_5 || n == RATE100_11)
++ n |= RATE100_PBCC511;
++ }
++
++ if (clt->shortpre && (clt->cur != RATE111_1))
++ SET_BIT(Ctl_8, DESC_CTL_SHORT_PREAMBLE); /* set Short Preamble */
++#endif
++ /* set autodma and reclaim and 1st mpdu */
++ SET_BIT(Ctl_8, DESC_CTL_AUTODMA | DESC_CTL_RECLAIM | DESC_CTL_FIRSTFRAG);
++ hostdesc1->length = cpu_to_le16(WLAN_HDR_A3_LEN);
++ }
++ /* don't need to clean ack/rts statistics here, already
++ * done on descr cleanup */
++
++ /* clears Ctl DESC_CTL_HOSTOWN bit, thus telling that the descriptors
++ * are now owned by the acx100; do this as LAST operation */
++ CLEAR_BIT(Ctl_8, DESC_CTL_HOSTOWN);
++ /* flush writes before we release hostdesc to the adapter here */
++ wmb();
++ CLEAR_BIT(hostdesc1->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++ CLEAR_BIT(hostdesc2->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++
++ /* write back modified flags */
++ txdesc->Ctl2_8 = Ctl2_8;
++ txdesc->Ctl_8 = Ctl_8;
++
++ /* unused: txdesc->tx_time = cpu_to_le32(jiffies); */
++//TODO: should it be a mmiowb() instead? we are protecting against race with write[bwl]()
++ /* flush writes before we tell the adapter that it's its turn now */
++ wmb();
++ acx_write_reg16(priv, IO_ACX_INT_TRIG, INT_TRIG_TXPRC);
++ acx_write_flush(priv);
++
++ /* log the packet content AFTER sending it,
++ * in order to not delay sending any further than absolutely needed
++ * Do separate logs for acx100/111 to have human-readable rates */
++ if (unlikely(acx_debug & (L_XFER|L_DATA))) {
++ u16 fc = ((wlan_hdr_t*)hostdesc1->data)->fc;
++ if (IS_ACX111(priv))
++ printk("tx: pkt (%s): len %d "
++ "rate %04X%s status %u\n",
++ acx_get_packet_type_string(le16_to_cpu(fc)), len,
++ le16_to_cpu(txdesc->u.r2.rate111),
++ (le16_to_cpu(txdesc->u.r2.rate111) & RATE111_SHORTPRE) ? "(SPr)" : "",
++ priv->status);
++ else
++ printk("tx: pkt (%s): len %d rate %03u%s status %u\n",
++ acx_get_packet_type_string(fc), len,
++ txdesc->u.r1.rate,
++ (Ctl_8 & DESC_CTL_SHORT_PREAMBLE) ? "(SPr)" : "",
++ priv->status);
++
++ if (acx_debug & L_DATA) {
++ printk("tx: 802.11 [%d]: ", len);
++ acx_dump_bytes(hostdesc1->data, len);
++ }
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++*/
++static void
++acx_l_handle_tx_error(wlandevice_t *priv, u8 error, unsigned int finger)
++{
++ const char *err = "unknown error";
++
++ /* hmm, should we handle this as a mask
++ * of *several* bits?
++ * For now I think only caring about
++ * individual bits is ok... */
++ switch (error) {
++ case 0x01:
++ err = "no Tx due to error in other fragment";
++ priv->wstats.discard.fragment++;
++ break;
++ case 0x02:
++ err = "Tx aborted";
++ priv->stats.tx_aborted_errors++;
++ break;
++ case 0x04:
++ err = "Tx desc wrong parameters";
++ priv->wstats.discard.misc++;
++ break;
++ case 0x08:
++ err = "WEP key not found";
++ priv->wstats.discard.misc++;
++ break;
++ case 0x10:
++ err = "MSDU lifetime timeout? - try changing "
++ "'iwconfig retry lifetime XXX'";
++ priv->wstats.discard.misc++;
++ break;
++ case 0x20:
++ err = "excessive Tx retries due to either distance "
++ "too high or unable to Tx or Tx frame error - "
++ "try changing 'iwconfig txpower XXX' or "
++ "'sens'itivity or 'retry'";
++ priv->wstats.discard.retries++;
++ /* FIXME: set (GETSET_TX|GETSET_RX) here
++ * (this seems to recalib radio on ACX100)
++ * after some more jiffies passed??
++ * But OTOH Tx error 0x20 also seems to occur on
++ * overheating, so I'm not sure whether we
++ * actually want that, since people maybe won't notice
++ * then that their hardware is slowly getting
++ * cooked...
++ * Or is it still a safe long distance from utter
++ * radio non-functionality despite many radio
++ * recalibs
++ * to final destructive overheating of the hardware?
++ * In this case we really should do recalib here...
++ * I guess the only way to find out is to do a
++ * potentially fatal self-experiment :-\
++ * Or maybe only recalib in case we're using Tx
++ * rate auto (on errors switching to lower speed
++ * --> less heat?) or 802.11 power save mode? */
++
++ /* ok, just do it.
++ * ENABLE_TX|ENABLE_RX helps, so even do
++ * DISABLE_TX and DISABLE_RX in order to perhaps
++ * have more impact. */
++ if (++priv->retry_errors_msg_ratelimit % 4 == 0) {
++ if (priv->retry_errors_msg_ratelimit <= 20)
++ printk("%s: several excessive Tx "
++ "retry errors occurred, attempting "
++ "to recalibrate radio. Radio "
++ "drift might be caused by increasing "
++ "card temperature, please check the card "
++ "before it's too late!\n",
++ priv->netdev->name);
++ if (priv->retry_errors_msg_ratelimit == 20)
++ printk("disabling above "
++ "notification message\n");
++
++ acx_schedule_after_interrupt_task(priv, ACX_AFTER_IRQ_CMD_RADIO_RECALIB);
++ }
++ break;
++ case 0x40:
++ err = "Tx buffer overflow";
++ priv->stats.tx_fifo_errors++;
++ break;
++ case 0x80:
++ err = "DMA error";
++ priv->wstats.discard.misc++;
++ break;
++ }
++ priv->stats.tx_errors++;
++ if (priv->stats.tx_errors <= 20)
++ printk("%s: tx error 0x%02X, buf %02u! (%s)\n",
++ priv->netdev->name, error, finger, err);
++ else
++ printk("%s: tx error 0x%02X, buf %02u!\n",
++ priv->netdev->name, error, finger);
++}
++
++
++/***********************************************************************
++*/
++/* Theory of operation:
++** client->rate_cap is a bitmask of rates client is capable of.
++** client->rate_cfg is a bitmask of allowed (configured) rates.
++** It is set as a result of iwconfig rate N [auto]
++** or iwpriv set_rates "N,N,N N,N,N" commands.
++** It can be fixed (e.g. 0x0080 == 18Mbit only),
++** auto (0x00ff == 18Mbit or any lower value),
++** and code handles any bitmask (0x1081 == try 54Mbit,18Mbit,1Mbit _only_).
++**
++** client->rate_cur is a value for rate111 field in tx descriptor.
++** It is always set to txrate_cfg sans zero or more most significant
++** bits. This routine handles selection of new rate_cur value depending on
++** outcome of last tx event.
++**
++** client->rate_100 is a precalculated rate value for acx100
++** (we can do without it, but will need to calculate it on each tx).
++**
++** You cannot configure mixed usage of 5.5 and/or 11Mbit rate
++** with PBCC and CCK modulation. Either both at CCK or both at PBCC.
++** In theory you can implement it, but so far it is considered not worth doing.
++**
++** 22Mbit, of course, is PBCC always. */
++
++/* maps acx100 tx descr rate field to acx111 one */
++static u16
++rate100to111(u8 r)
++{
++ switch (r) {
++ case RATE100_1: return RATE111_1;
++ case RATE100_2: return RATE111_2;
++ case RATE100_5:
++ case (RATE100_5 | RATE100_PBCC511): return RATE111_5;
++ case RATE100_11:
++ case (RATE100_11 | RATE100_PBCC511): return RATE111_11;
++ case RATE100_22: return RATE111_22;
++ default:
++ printk("acx: unexpected acx100 txrate: %u! "
++ "Please report\n", r);
++ return RATE111_2;
++ }
++}
++
++
++static void
++acx_l_handle_txrate_auto(wlandevice_t *priv, struct client *txc,
++ unsigned int idx, u8 rate100, u16 rate111, u8 error)
++{
++ u16 sent_rate;
++ u16 cur = txc->rate_cur;
++ int slower_rate_was_used;
++
++ /* FIXME: need to implement some kind of rate success memory
++ * which stores the success percentage per rate, to be taken
++ * into account when considering allowing a new rate, since it
++ * doesn't really help to stupidly count fallback/stepup,
++ * since one invalid rate will spoil the party anyway
++ * (such as 22M in case of 11M-only peers) */
++
++ /* vda: hmm. current code will do this:
++ ** 1. send packets at 11 Mbit, stepup++
++ ** 2. will try to send at 22Mbit. hardware will see no ACK,
++ ** retries at 11Mbit, success. code notes that used rate
++ ** is lower. stepup = 0, fallback++
++ ** 3. repeat step 2 fallback_count times. Fall back to
++ ** 11Mbit. go to step 1.
++ ** If stepup_count is large (say, 16) and fallback_count
++ ** is small (3), this wouldn't be too bad wrt throughput */
++
++ /* do some preparations, i.e. calculate the one rate that was
++ * used to send this packet */
++ if (IS_ACX111(priv)) {
++ sent_rate = 1 << highest_bit(rate111 & RATE111_ALL);
++ } else {
++ sent_rate = rate100to111(rate100);
++ }
++ /* sent_rate has only one bit set now, corresponding to tx rate
++ * which was used by hardware to tx this particular packet */
++
++ /* now do the actual auto rate management */
++ acxlog(L_DEBUG, "tx: %sclient=%p/"MACSTR" used=%04X cur=%04X cfg=%04X "
++ "__=%u/%u ^^=%u/%u\n",
++ (txc->ignore_count > 0) ? "[IGN] " : "",
++ txc, MAC(txc->address), sent_rate, cur, txc->rate_cfg,
++ txc->fallback_count, priv->fallback_threshold,
++ txc->stepup_count, priv->stepup_threshold
++ );
++
++ /* we need to ignore old packets already in the tx queue since
++ * they use older rate bytes configured before our last rate change,
++ * otherwise our mechanism will get confused by interpreting old data.
++ * Do it here only, in order to have the logging above */
++ if (txc->ignore_count) {
++ txc->ignore_count--;
++ return;
++ }
++
++ /* true only if the only nonzero bit in sent_rate is
++ ** less significant than highest nonzero bit in cur */
++ slower_rate_was_used = ( cur > ((sent_rate<<1)-1) );
++
++ if (slower_rate_was_used || (error & 0x30)) {
++ txc->stepup_count = 0;
++ if (++txc->fallback_count <= priv->fallback_threshold)
++ return;
++ txc->fallback_count = 0;
++
++ /* clear highest 1 bit in cur */
++ sent_rate = RATE111_54;
++ while (!(cur & sent_rate)) sent_rate >>= 1;
++ CLEAR_BIT(cur, sent_rate);
++
++ if (cur) { /* we can't disable all rates! */
++ acxlog(L_XFER, "tx: falling back to ratemask %04X\n", cur);
++ txc->rate_cur = cur;
++ txc->ignore_count = TX_CNT - priv->tx_free;
++ }
++ } else if (!slower_rate_was_used) {
++ txc->fallback_count = 0;
++ if (++txc->stepup_count <= priv->stepup_threshold)
++ return;
++ txc->stepup_count = 0;
++
++ /* sanitize. Sort of not needed, but I dont trust hw that much...
++ ** what if it can report bogus tx rates sometimes? */
++ while (!(cur & sent_rate)) sent_rate >>= 1;
++ /* try to find a higher sent_rate that isn't yet in our
++ * current set, but is an allowed cfg */
++ while (1) {
++ sent_rate <<= 1;
++ if (sent_rate > txc->rate_cfg)
++ /* no higher rates allowed by config */
++ return;
++ if (!(cur & sent_rate) && (txc->rate_cfg & sent_rate))
++ /* found */
++ break;
++ /* not found, try higher one */
++ }
++ SET_BIT(cur, sent_rate);
++ acxlog(L_XFER, "tx: stepping up to ratemask %04X\n", cur);
++ txc->rate_cur = cur;
++ /* FIXME: totally bogus - we could be sending to many peers at once... */
++ txc->ignore_count = TX_CNT - priv->tx_free;
++ }
++
++ /* calculate acx100 style rate byte if needed */
++ if (IS_ACX100(priv)) {
++ txc->rate_100 = bitpos2rate100[highest_bit(cur)];
++ }
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_log_txbuffer
++*----------------------------------------------------------------*/
++#if !ACX_DEBUG
++static inline void acx_l_log_txbuffer(const wlandevice_t *priv) {}
++#else
++static void
++acx_l_log_txbuffer(wlandevice_t *priv)
++{
++ txdesc_t *txdesc;
++ int i;
++
++ /* no FN_ENTER here, we don't want that */
++ /* no locks here, since it's entirely non-critical code */
++ txdesc = priv->txdesc_start;
++ if (!txdesc) return;
++ for (i = 0; i < TX_CNT; i++) {
++ if ((txdesc->Ctl_8 & DESC_CTL_DONE) == DESC_CTL_DONE)
++ printk("tx: buf %d done\n", i);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++}
++#endif
++
++
++/*----------------------------------------------------------------
++* acx_l_clean_tx_desc
++*
++* This function resets the txdescs' status when the ACX100
++* signals the TX done IRQ (txdescs have been processed), starting with
++* the pool index of the descriptor which we would use next,
++* in order to make sure that we can be as fast as possible
++* in filling new txdescs.
++* Oops, now we have our own index, so everytime we get called we know
++* where the next packet to be cleaned is.
++* Hmm, still need to loop through the whole ring buffer now,
++* since we lost sync for some reason when ping flooding or so...
++* (somehow we don't get the IRQ for acx_l_clean_tx_desc any more when
++* too many packets are being sent!)
++* FIXME: currently we only process one packet, but this gets out of
++* sync for some reason when ping flooding, so we need to loop,
++* but the previous smart loop implementation causes the ping latency
++* to rise dramatically (~3000 ms), at least on CardBus PheeNet WL-0022.
++* Dunno what to do :-\
++*----------------------------------------------------------------*/
++unsigned int
++acx_l_clean_tx_desc(wlandevice_t *priv)
++{
++ txdesc_t *txdesc;
++ struct client *txc;
++ int finger;
++ int num_cleaned;
++ int to_process;
++ u16 r111;
++ u8 error, ack_failures, rts_failures, rts_ok, r100;
++
++ FN_ENTER;
++
++ if (unlikely(acx_debug & L_DEBUG))
++ acx_l_log_txbuffer(priv);
++
++ acxlog(L_BUFT, "tx: cleaning up bufs from %u\n", priv->tx_tail);
++
++ finger = priv->tx_tail;
++ num_cleaned = 0;
++ to_process = TX_CNT;
++ do {
++ txdesc = get_txdesc(priv, finger);
++
++ /* abort if txdesc is not marked as "Tx finished" and "owned" */
++ if ((txdesc->Ctl_8 & DESC_CTL_DONE) != DESC_CTL_DONE) {
++ /* we do need to have at least one cleaned,
++ * otherwise we wouldn't get called in the first place
++ */
++ if (num_cleaned)
++ break;
++ }
++
++ /* remember descr values... */
++ error = txdesc->error;
++ ack_failures = txdesc->ack_failures;
++ rts_failures = txdesc->rts_failures;
++ rts_ok = txdesc->rts_ok;
++ r100 = txdesc->u.r1.rate;
++ r111 = txdesc->u.r2.rate111;
++
++#if WIRELESS_EXT > 13 /* wireless_send_event() and IWEVTXDROP are WE13 */
++ /* need to check for certain error conditions before we
++ * clean the descriptor: we still need valid descr data here */
++ if (unlikely(0x30 & error)) {
++ /* only send IWEVTXDROP in case of retry or lifetime exceeded;
++ * all other errors mean we screwed up locally */
++ union iwreq_data wrqu;
++ wlan_hdr_t *hdr;
++ txhostdesc_t *hostdesc;
++
++ hostdesc = acx_get_txhostdesc(priv, txdesc);
++ hdr = (wlan_hdr_t *)hostdesc->data;
++ MAC_COPY(wrqu.addr.sa_data, hdr->a1);
++ wireless_send_event(priv->netdev, IWEVTXDROP, &wrqu, NULL);
++ }
++#endif
++ /* ...and free the descr */
++ txdesc->error = 0;
++ txdesc->ack_failures = 0;
++ txdesc->rts_failures = 0;
++ txdesc->rts_ok = 0;
++ /* signal host owning it LAST, since ACX already knows that this
++ * descriptor is finished since it set Ctl_8 accordingly:
++ * if _OWN is set at the beginning instead, our own get_tx
++ * might choose a Tx desc that isn't fully cleared
++ * (in case of bad locking). */
++ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
++ priv->tx_free++;
++ num_cleaned++;
++
++ if ((priv->tx_free >= TX_START_QUEUE)
++ && (priv->status == ACX_STATUS_4_ASSOCIATED)
++ && (acx_queue_stopped(priv->netdev))
++ ) {
++ acxlog(L_BUF, "tx: wake queue (avail. Tx desc %u)\n",
++ priv->tx_free);
++ acx_wake_queue(priv->netdev, NULL);
++ }
++
++ /* do error checking, rate handling and logging
++ * AFTER having done the work, it's faster */
++
++ /* do rate handling */
++ txc = acx_get_txc(priv, txdesc);
++ if (txc && priv->rate_auto) {
++ acx_l_handle_txrate_auto(priv, txc, finger, r100, r111, error);
++ }
++
++ if (unlikely(error))
++ acx_l_handle_tx_error(priv, error, finger);
++
++ if (IS_ACX111(priv))
++ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u r111=%04X\n",
++ finger, ack_failures, rts_failures, rts_ok, r111);
++ else
++ acxlog(L_BUFT, "tx: cleaned %u: !ACK=%u !RTS=%u RTS=%u rate=%u\n",
++ finger, ack_failures, rts_failures, rts_ok, r100);
++
++ /* update pointer for descr to be cleaned next */
++ finger = (finger + 1) % TX_CNT;
++ } while (--to_process);
++
++ /* remember last position */
++ priv->tx_tail = finger;
++/* end: */
++ FN_EXIT1(num_cleaned);
++ return num_cleaned;
++}
++
++/* clean *all* Tx descriptors, and regardless of their previous state.
++ * Used for brute-force reset handling. */
++void
++acx_l_clean_tx_desc_emergency(wlandevice_t *priv)
++{
++ txdesc_t *txdesc;
++ unsigned int i;
++
++ FN_ENTER;
++
++ for (i = 0; i < TX_CNT; i++) {
++ txdesc = get_txdesc(priv, i);
++
++ /* free it */
++ txdesc->ack_failures = 0;
++ txdesc->rts_failures = 0;
++ txdesc->rts_ok = 0;
++ txdesc->error = 0;
++ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
++ }
++
++ priv->tx_free = TX_CNT;
++
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_l_log_rxbuffer
++*
++* Called from IRQ context only
++*----------------------------------------------------------------*/
++#if !ACX_DEBUG
++static inline void acx_l_log_rxbuffer(const wlandevice_t *priv) {}
++#else
++static void
++acx_l_log_rxbuffer(const wlandevice_t *priv)
++{
++ const struct rxhostdesc *rxhostdesc;
++ int i;
++
++ /* no FN_ENTER here, we don't want that */
++
++ rxhostdesc = priv->rxhostdesc_start;
++ if (!rxhostdesc) return;
++ for (i = 0; i < RX_CNT; i++) {
++ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
++ printk("rx: buf %d full\n", i);
++ rxhostdesc++;
++ }
++}
++#endif
++
++
++/***************************************************************
++** acx_l_process_rx_desc
++**
++** Called directly and only from the IRQ handler
++*/
++void
++acx_l_process_rx_desc(wlandevice_t *priv)
++{
++ rxhostdesc_t *hostdesc;
++ /* unsigned int curr_idx; */
++ unsigned int count = 0;
++
++ FN_ENTER;
++
++ if (unlikely(acx_debug & L_BUFR)) {
++ acx_l_log_rxbuffer(priv);
++ }
++
++ /* First, have a loop to determine the first descriptor that's
++ * full, just in case there's a mismatch between our current
++ * rx_tail and the full descriptor we're supposed to handle. */
++ while (1) {
++ /* curr_idx = priv->rx_tail; */
++ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
++ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
++ if ((hostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && (hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) {
++ /* found it! */
++ break;
++ }
++ count++;
++ if (unlikely(count > RX_CNT)) {
++ /* hmm, no luck: all descriptors empty, bail out */
++ goto end;
++ }
++ }
++
++ /* now process descriptors, starting with the first we figured out */
++ while (1) {
++ acxlog(L_BUFR, "rx: tail=%u Ctl_16=%04X Status=%08X\n",
++ priv->rx_tail, hostdesc->Ctl_16, hostdesc->Status);
++
++ acx_l_process_rxbuf(priv, hostdesc->data);
++
++ hostdesc->Status = 0;
++ /* flush all writes before adapter sees CTL_HOSTOWN change */
++ wmb();
++ /* Host no longer owns this, needs to be LAST */
++ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++
++ /* ok, descriptor is handled, now check the next descriptor */
++ /* curr_idx = priv->rx_tail; */
++ hostdesc = &priv->rxhostdesc_start[priv->rx_tail];
++
++ /* if next descriptor is empty, then bail out */
++ /* FIXME: is this check really entirely correct?? */
++ /*
++//FIXME: inconsistent with check in prev while() loop
++ if (!(hostdesc->Ctl & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && !(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL))) */
++ if (!(hostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)))
++ break;
++
++ priv->rx_tail = (priv->rx_tail + 1) % RX_CNT;
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/*----------------------------------------------------------------
++* acx_s_create_tx_host_desc_queue
++*----------------------------------------------------------------*/
++static inline void*
++acx_alloc_coherent(struct pci_dev *hwdev, size_t size,
++ dma_addr_t *dma_handle, int flag)
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 53)
++ return dma_alloc_coherent(hwdev == NULL ? NULL : &hwdev->dev,
++ size, dma_handle, flag);
++#else
++#warning Using old PCI-specific DMA allocation, may fail with out-of-mem!
++#warning Upgrade kernel if it does...
++ return pci_alloc_consistent(hwdev, size, dma_handle);
++#endif
++}
++
++static void*
++allocate(wlandevice_t *priv, size_t size, dma_addr_t *phy, const char *msg)
++{
++ void *ptr = acx_alloc_coherent(priv->pdev, size, phy, GFP_KERNEL);
++ if (ptr) {
++ acxlog(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n",
++ msg, (int)size, ptr, (unsigned long long)*phy);
++ memset(ptr, 0, size);
++ return ptr;
++ }
++ printk(KERN_ERR "acx: %s allocation FAILED (%d bytes)\n",
++ msg, (int)size);
++ return NULL;
++}
++
++static int
++acx_s_create_tx_host_desc_queue(wlandevice_t *priv)
++{
++ txhostdesc_t *hostdesc;
++ u8 *txbuf;
++ dma_addr_t hostdesc_phy;
++ dma_addr_t txbuf_phy;
++ int i;
++
++ FN_ENTER;
++
++ /* allocate TX buffer */
++ priv->txbuf_area_size = TX_CNT * WLAN_A4FR_MAXLEN_WEP_FCS;
++ priv->txbuf_start = allocate(priv, priv->txbuf_area_size,
++ &priv->txbuf_startphy, "txbuf_start");
++ if (!priv->txbuf_start)
++ goto fail;
++
++ /* allocate the TX host descriptor queue pool */
++ priv->txhostdesc_area_size = TX_CNT * 2*sizeof(txhostdesc_t);
++ priv->txhostdesc_start = allocate(priv, priv->txhostdesc_area_size,
++ &priv->txhostdesc_startphy, "txhostdesc_start");
++ if (!priv->txhostdesc_start)
++ goto fail;
++ /* check for proper alignment of TX host descriptor pool */
++ if ((long) priv->txhostdesc_start & 3) {
++ printk("acx: driver bug: dma alloc returns unaligned address\n");
++ goto fail;
++ }
++
++/* Each tx frame buffer is accessed by hardware via
++** txdesc -> txhostdesc(s) -> framebuffer(s)
++** We use only one txhostdesc per txdesc, but it looks like
++** acx111 is buggy: it accesses second txhostdesc
++** (via hostdesc.desc_phy_next field) even if
++** txdesc->length == hostdesc->length and thus
++** entire packet was placed into first txhostdesc.
++** Due to this bug acx111 hangs unless second txhostdesc
++** has hostdesc.length = 3 (or larger)
++** Storing NULL into hostdesc.desc_phy_next
++** doesn't seem to help.
++*/
++/* It is not known whether we need to have 'extra' second
++** txhostdescs for acx100. Maybe it is acx111-only bug.
++*/
++ hostdesc = priv->txhostdesc_start;
++ hostdesc_phy = priv->txhostdesc_startphy;
++ txbuf = priv->txbuf_start;
++ txbuf_phy = priv->txbuf_startphy;
++
++#if 0
++/* Works for xterasys xn2522g, does not for WG311v2 !!? */
++ for (i = 0; i < TX_CNT*2; i++) {
++ hostdesc_phy += sizeof(txhostdesc_t);
++ if (!(i & 1)) {
++ hostdesc->data_phy = cpu2acx(txbuf_phy);
++ /* hostdesc->data_offset = ... */
++ /* hostdesc->reserved = ... */
++ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
++ /* hostdesc->length = ... */
++ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
++ hostdesc->pNext = ptr2acx(NULL);
++ /* hostdesc->Status = ... */
++ /* below: non-hardware fields */
++ hostdesc->data = txbuf;
++
++ txbuf += WLAN_A4FR_MAXLEN_WEP_FCS;
++ txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS;
++ } else {
++ /* hostdesc->data_phy = ... */
++ /* hostdesc->data_offset = ... */
++ /* hostdesc->reserved = ... */
++ /* hostdesc->Ctl_16 = ... */
++ hostdesc->length = 3; /* bug workaround */
++ /* hostdesc->desc_phy_next = ... */
++ /* hostdesc->pNext = ... */
++ /* hostdesc->Status = ... */
++ /* below: non-hardware fields */
++ /* hostdesc->data = ... */
++ }
++ hostdesc++;
++ }
++#endif
++ for (i = 0; i < TX_CNT*2; i++) {
++ hostdesc_phy += sizeof(txhostdesc_t);
++ if (!(i & 1)) {
++ hostdesc->data_phy = cpu2acx(txbuf_phy);
++ /* done by memset(0): hostdesc->data_offset = 0; */
++ /* hostdesc->reserved = ... */
++ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
++ /* hostdesc->length = ... */
++ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
++ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
++ /* hostdesc->Status = ... */
++ /* below: non-hardware fields */
++ hostdesc->data = txbuf;
++
++ txbuf += WLAN_HDR_A3_LEN;
++ txbuf_phy += WLAN_HDR_A3_LEN;
++ } else {
++ hostdesc->data_phy = cpu2acx(txbuf_phy);
++ /* done by memset(0): hostdesc->data_offset = 0; */
++ /* hostdesc->reserved = ... */
++ hostdesc->Ctl_16 = cpu_to_le16(DESC_CTL_HOSTOWN);
++ /* hostdesc->length = ...; */
++ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
++ /* done by memset(0): hostdesc->pNext = ptr2acx(NULL); */
++ /* hostdesc->Status = ... */
++ /* below: non-hardware fields */
++ hostdesc->data = txbuf;
++
++ txbuf += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
++ txbuf_phy += WLAN_A4FR_MAXLEN_WEP_FCS - WLAN_HDR_A3_LEN;
++ }
++ hostdesc++;
++ }
++ hostdesc--;
++ hostdesc->desc_phy_next = cpu2acx(priv->txhostdesc_startphy);
++
++ FN_EXIT1(OK);
++ return OK;
++fail:
++ printk("acx: create_tx_host_desc_queue FAILED\n");
++ /* dealloc will be done by free function on error case */
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/***************************************************************
++** acx_s_create_rx_host_desc_queue
++*/
++/* the whole size of a data buffer (header plus data body)
++ * plus 32 bytes safety offset at the end */
++#define RX_BUFFER_SIZE (sizeof(rxbuffer_t) + 32)
++
++static int
++acx_s_create_rx_host_desc_queue(wlandevice_t *priv)
++{
++ rxhostdesc_t *hostdesc;
++ rxbuffer_t *rxbuf;
++ dma_addr_t hostdesc_phy;
++ dma_addr_t rxbuf_phy;
++ int i;
++
++ FN_ENTER;
++
++ /* allocate the RX host descriptor queue pool */
++ priv->rxhostdesc_area_size = RX_CNT * sizeof(rxhostdesc_t);
++ priv->rxhostdesc_start = allocate(priv, priv->rxhostdesc_area_size,
++ &priv->rxhostdesc_startphy, "rxhostdesc_start");
++ if (!priv->rxhostdesc_start)
++ goto fail;
++ /* check for proper alignment of RX host descriptor pool */
++ if ((long) priv->rxhostdesc_start & 3) {
++ printk("acx: driver bug: dma alloc returns unaligned address\n");
++ goto fail;
++ }
++
++ /* allocate Rx buffer pool which will be used by the acx
++ * to store the whole content of the received frames in it */
++ priv->rxbuf_area_size = RX_CNT * RX_BUFFER_SIZE;
++ priv->rxbuf_start = allocate(priv, priv->rxbuf_area_size,
++ &priv->rxbuf_startphy, "rxbuf_start");
++ if (!priv->rxbuf_start)
++ goto fail;
++
++ rxbuf = priv->rxbuf_start;
++ rxbuf_phy = priv->rxbuf_startphy;
++ hostdesc = priv->rxhostdesc_start;
++ hostdesc_phy = priv->rxhostdesc_startphy;
++
++ /* don't make any popular C programming pointer arithmetic mistakes
++ * here, otherwise I'll kill you...
++ * (and don't dare asking me why I'm warning you about that...) */
++ for (i = 0; i < RX_CNT; i++) {
++ hostdesc->data = rxbuf;
++ hostdesc->data_phy = cpu2acx(rxbuf_phy);
++ hostdesc->length = cpu_to_le16(RX_BUFFER_SIZE);
++ CLEAR_BIT(hostdesc->Ctl_16, cpu_to_le16(DESC_CTL_HOSTOWN));
++ rxbuf++;
++ rxbuf_phy += sizeof(rxbuffer_t);
++ hostdesc_phy += sizeof(rxhostdesc_t);
++ hostdesc->desc_phy_next = cpu2acx(hostdesc_phy);
++ hostdesc++;
++ }
++ hostdesc--;
++ hostdesc->desc_phy_next = cpu2acx(priv->rxhostdesc_startphy);
++ FN_EXIT1(OK);
++ return OK;
++fail:
++ printk("acx: create_rx_host_desc_queue FAILED\n");
++ /* dealloc will be done by free function on error case */
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/***************************************************************
++** acx_s_create_hostdesc_queues
++*/
++int
++acx_s_create_hostdesc_queues(wlandevice_t *priv)
++{
++ int result;
++ result = acx_s_create_tx_host_desc_queue(priv);
++ if (OK != result) return result;
++ result = acx_s_create_rx_host_desc_queue(priv);
++ return result;
++}
++
++
++/***************************************************************
++** acx_create_tx_desc_queue
++*/
++static void
++acx_create_tx_desc_queue(wlandevice_t *priv, u32 tx_queue_start)
++{
++ txdesc_t *txdesc;
++ txhostdesc_t *hostdesc;
++ dma_addr_t hostmemptr;
++ u32 mem_offs;
++ int i;
++
++ FN_ENTER;
++
++ priv->txdesc_size = sizeof(txdesc_t);
++
++ if (IS_ACX111(priv)) {
++ /* the acx111 txdesc is 4 bytes larger */
++ priv->txdesc_size = sizeof(txdesc_t) + 4;
++ }
++
++ priv->txdesc_start = (txdesc_t *) (priv->iobase2 + tx_queue_start);
++
++ acxlog(L_DEBUG, "priv->iobase2=%p\n"
++ "tx_queue_start=%08X\n"
++ "priv->txdesc_start=%p\n",
++ priv->iobase2,
++ tx_queue_start,
++ priv->txdesc_start);
++
++ priv->tx_free = TX_CNT;
++ /* done by memset: priv->tx_head = 0; */
++ /* done by memset: priv->tx_tail = 0; */
++ txdesc = priv->txdesc_start;
++ mem_offs = tx_queue_start;
++ hostmemptr = priv->txhostdesc_startphy;
++ hostdesc = priv->txhostdesc_start;
++
++ if (IS_ACX111(priv)) {
++ /* ACX111 has a preinitialized Tx buffer! */
++ /* loop over whole send pool */
++ /* FIXME: do we have to do the hostmemptr stuff here?? */
++ for (i = 0; i < TX_CNT; i++) {
++ txdesc->HostMemPtr = ptr2acx(hostmemptr);
++ txdesc->Ctl_8 = DESC_CTL_HOSTOWN;
++ /* reserve two (hdr desc and payload desc) */
++ hostdesc += 2;
++ hostmemptr += 2 * sizeof(txhostdesc_t);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++ } else {
++ /* ACX100 Tx buffer needs to be initialized by us */
++ /* clear whole send pool. sizeof is safe here (we are acx100) */
++ memset(priv->txdesc_start, 0, TX_CNT * sizeof(txdesc_t));
++
++ /* loop over whole send pool */
++ for (i = 0; i < TX_CNT; i++) {
++ acxlog(L_DEBUG, "configure card tx descriptor: 0x%p, "
++ "size: 0x%X\n", txdesc, priv->txdesc_size);
++
++ /* pointer to hostdesc memory */
++ /* FIXME: type-incorrect assignment, might cause trouble
++ * in some cases */
++ txdesc->HostMemPtr = ptr2acx(hostmemptr);
++ /* initialise ctl */
++ txdesc->Ctl_8 = DESC_CTL_INIT;
++ txdesc->Ctl2_8 = 0;
++ /* point to next txdesc */
++ txdesc->pNextDesc = cpu2acx(mem_offs + priv->txdesc_size);
++ /* reserve two (hdr desc and payload desc) */
++ hostdesc += 2;
++ hostmemptr += 2 * sizeof(txhostdesc_t);
++ /* go to the next one */
++ mem_offs += priv->txdesc_size;
++ /* ++ is safe here (we are acx100) */
++ txdesc++;
++ }
++ /* go back to the last one */
++ txdesc--;
++ /* and point to the first making it a ring buffer */
++ txdesc->pNextDesc = cpu2acx(tx_queue_start);
++ }
++ FN_EXIT0;
++}
++
++
++/***************************************************************
++** acx_create_rx_desc_queue
++*/
++static void
++acx_create_rx_desc_queue(wlandevice_t *priv, u32 rx_queue_start)
++{
++ rxdesc_t *rxdesc;
++ u32 mem_offs;
++ int i;
++
++ FN_ENTER;
++
++ /* done by memset: priv->rx_tail = 0; */
++
++ /* ACX111 doesn't need any further config: preconfigures itself.
++ * Simply print ring buffer for debugging */
++ if (IS_ACX111(priv)) {
++ /* rxdesc_start already set here */
++
++ priv->rxdesc_start = (rxdesc_t *) ((u8 *)priv->iobase2 + rx_queue_start);
++
++ rxdesc = priv->rxdesc_start;
++ for (i = 0; i < RX_CNT; i++) {
++ acxlog(L_DEBUG, "rx descriptor %d @ 0x%p\n", i, rxdesc);
++ rxdesc = priv->rxdesc_start = (rxdesc_t *)
++ (priv->iobase2 + acx2cpu(rxdesc->pNextDesc));
++ }
++ } else {
++ /* we didn't pre-calculate rxdesc_start in case of ACX100 */
++ /* rxdesc_start should be right AFTER Tx pool */
++ priv->rxdesc_start = (rxdesc_t *)
++ ((u8 *) priv->txdesc_start + (TX_CNT * sizeof(txdesc_t)));
++ /* NB: sizeof(txdesc_t) above is valid because we know
++ ** we are in if(acx100) block. Beware of cut-n-pasting elsewhere!
++ ** acx111's txdesc is larger! */
++
++ memset(priv->rxdesc_start, 0, RX_CNT * sizeof(rxdesc_t));
++
++ /* loop over whole receive pool */
++ rxdesc = priv->rxdesc_start;
++ mem_offs = rx_queue_start;
++ for (i = 0; i < RX_CNT; i++) {
++ acxlog(L_DEBUG, "rx descriptor @ 0x%p\n", rxdesc);
++ rxdesc->Ctl_8 = DESC_CTL_RECLAIM | DESC_CTL_AUTODMA;
++ /* point to next rxdesc */
++ rxdesc->pNextDesc = cpu2acx(mem_offs + sizeof(rxdesc_t));
++ /* go to the next one */
++ mem_offs += sizeof(rxdesc_t);
++ rxdesc++;
++ }
++ /* go to the last one */
++ rxdesc--;
++
++ /* and point to the first making it a ring buffer */
++ rxdesc->pNextDesc = cpu2acx(rx_queue_start);
++ }
++ FN_EXIT0;
++}
++
++
++/***************************************************************
++** acx_create_desc_queues
++*/
++void
++acx_create_desc_queues(wlandevice_t *priv, u32 tx_queue_start, u32 rx_queue_start)
++{
++ acx_create_tx_desc_queue(priv, tx_queue_start);
++ acx_create_rx_desc_queue(priv, rx_queue_start);
++}
++
++
++/***************************************************************
++** acxpci_s_proc_diag_output
++*/
++char*
++acxpci_s_proc_diag_output(char *p, wlandevice_t *priv)
++{
++ const char *rtl, *thd, *ttl;
++ rxhostdesc_t *rxhostdesc;
++ txdesc_t *txdesc;
++ int i;
++
++ FN_ENTER;
++
++ p += sprintf(p, "** Rx buf **\n");
++ rxhostdesc = priv->rxhostdesc_start;
++ if (rxhostdesc) for (i = 0; i < RX_CNT; i++) {
++ rtl = (i == priv->rx_tail) ? " [tail]" : "";
++ if ((rxhostdesc->Ctl_16 & cpu_to_le16(DESC_CTL_HOSTOWN))
++ && (rxhostdesc->Status & cpu_to_le32(DESC_STATUS_FULL)) )
++ p += sprintf(p, "%02u FULL%s\n", i, rtl);
++ else
++ p += sprintf(p, "%02u empty%s\n", i, rtl);
++ rxhostdesc++;
++ }
++ p += sprintf(p, "** Tx buf (free %d, Linux netqueue %s) **\n", priv->tx_free,
++ acx_queue_stopped(priv->netdev) ? "STOPPED" : "running");
++ txdesc = priv->txdesc_start;
++ if (txdesc) for (i = 0; i < TX_CNT; i++) {
++ thd = (i == priv->tx_head) ? " [head]" : "";
++ ttl = (i == priv->tx_tail) ? " [tail]" : "";
++ if (txdesc->Ctl_8 & DESC_CTL_ACXDONE)
++ p += sprintf(p, "%02u DONE (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
++ else
++ if (!(txdesc->Ctl_8 & DESC_CTL_HOSTOWN))
++ p += sprintf(p, "%02u TxWait (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
++ else
++ p += sprintf(p, "%02u empty (%02X)%s%s\n", i, txdesc->Ctl_8, thd, ttl);
++ txdesc = move_txdesc(priv, txdesc, 1);
++ }
++ p += sprintf(p,
++ "\n"
++ "** PCI data **\n"
++ "txbuf_start %p, txbuf_area_size %u, txbuf_startphy %08llx\n"
++ "txdesc_size %u, txdesc_start %p\n"
++ "txhostdesc_start %p, txhostdesc_area_size %u, txhostdesc_startphy %08llx\n"
++ "rxdesc_start %p\n"
++ "rxhostdesc_start %p, rxhostdesc_area_size %u, rxhostdesc_startphy %08llx\n"
++ "rxbuf_start %p, rxbuf_area_size %u, rxbuf_startphy %08llx\n",
++ priv->txbuf_start, priv->txbuf_area_size, (u64)priv->txbuf_startphy,
++ priv->txdesc_size, priv->txdesc_start,
++ priv->txhostdesc_start, priv->txhostdesc_area_size, (u64)priv->txhostdesc_startphy,
++ priv->rxdesc_start,
++ priv->rxhostdesc_start, priv->rxhostdesc_area_size, (u64)priv->rxhostdesc_startphy,
++ priv->rxbuf_start, priv->rxbuf_area_size, (u64)priv->rxbuf_startphy);
++
++ FN_EXIT0;
++ return p;
++}
++
++
++/***********************************************************************
++*/
++int
++acx_proc_eeprom_output(char *buf, wlandevice_t *priv)
++{
++ char *p = buf;
++ int i;
++
++ FN_ENTER;
++
++ for (i = 0; i < 0x400; i++) {
++ acx_read_eeprom_offset(priv, i, p++);
++ }
++
++ FN_EXIT1(p - buf);
++ return p - buf;
++}
++
++
++/***********************************************************************
++*/
++void
++acx_set_interrupt_mask(wlandevice_t *priv)
++{
++ if (IS_ACX111(priv)) {
++ priv->irq_mask = (u16) ~(0
++ /* | HOST_INT_RX_DATA */
++ | HOST_INT_TX_COMPLETE
++ /* | HOST_INT_TX_XFER */
++ | HOST_INT_RX_COMPLETE
++ /* | HOST_INT_DTIM */
++ /* | HOST_INT_BEACON */
++ /* | HOST_INT_TIMER */
++ /* | HOST_INT_KEY_NOT_FOUND */
++ | HOST_INT_IV_ICV_FAILURE
++ | HOST_INT_CMD_COMPLETE
++ | HOST_INT_INFO
++ /* | HOST_INT_OVERFLOW */
++ /* | HOST_INT_PROCESS_ERROR */
++ | HOST_INT_SCAN_COMPLETE
++ | HOST_INT_FCS_THRESHOLD
++ /* | HOST_INT_UNKNOWN */
++ );
++ priv->irq_mask_off = (u16)~( HOST_INT_CMD_COMPLETE ); /* 0xfdff */
++ } else {
++ priv->irq_mask = (u16) ~(0
++ /* | HOST_INT_RX_DATA */
++ | HOST_INT_TX_COMPLETE
++ /* | HOST_INT_TX_XFER */
++ | HOST_INT_RX_COMPLETE
++ /* | HOST_INT_DTIM */
++ /* | HOST_INT_BEACON */
++ /* | HOST_INT_TIMER */
++ /* | HOST_INT_KEY_NOT_FOUND */
++ /* | HOST_INT_IV_ICV_FAILURE */
++ | HOST_INT_CMD_COMPLETE
++ | HOST_INT_INFO
++ /* | HOST_INT_OVERFLOW */
++ /* | HOST_INT_PROCESS_ERROR */
++ | HOST_INT_SCAN_COMPLETE
++ /* | HOST_INT_FCS_THRESHOLD */
++ /* | HOST_INT_UNKNOWN */
++ );
++ priv->irq_mask_off = (u16)~( HOST_INT_UNKNOWN ); /* 0x7fff */
++ }
++}
++
++
++/***********************************************************************
++*/
++int
++acx100_s_set_tx_level(wlandevice_t *priv, u8 level_dbm)
++{
++ /* since it can be assumed that at least the Maxim radio has a
++ * maximum power output of 20dBm and since it also can be
++ * assumed that these values drive the DAC responsible for
++ * setting the linear Tx level, I'd guess that these values
++ * should be the corresponding linear values for a dBm value,
++ * in other words: calculate the values from that formula:
++ * Y [dBm] = 10 * log (X [mW])
++ * then scale the 0..63 value range onto the 1..100mW range (0..20 dBm)
++ * and you're done...
++ * Hopefully that's ok, but you never know if we're actually
++ * right... (especially since Windows XP doesn't seem to show
++ * actual Tx dBm values :-P) */
++
++ /* NOTE: on Maxim, value 30 IS 30mW, and value 10 IS 10mW - so the
++ * values are EXACTLY mW!!! Not sure about RFMD and others,
++ * though... */
++ static const u8 dbm2val_maxim[21] = {
++ 63, 63, 63, 62,
++ 61, 61, 60, 60,
++ 59, 58, 57, 55,
++ 53, 50, 47, 43,
++ 38, 31, 23, 13,
++ 0
++ };
++ static const u8 dbm2val_rfmd[21] = {
++ 0, 0, 0, 1,
++ 2, 2, 3, 3,
++ 4, 5, 6, 8,
++ 10, 13, 16, 20,
++ 25, 32, 41, 50,
++ 63
++ };
++ const u8 *table;
++
++ switch (priv->radio_type) {
++ case RADIO_MAXIM_0D:
++ table = &dbm2val_maxim[0];
++ break;
++ case RADIO_RFMD_11:
++ case RADIO_RALINK_15:
++ table = &dbm2val_rfmd[0];
++ break;
++ default:
++ printk("%s: unknown/unsupported radio type, "
++ "cannot modify tx power level yet!\n",
++ priv->netdev->name);
++ return NOT_OK;
++ }
++ printk("%s: changing radio power level to %u dBm (%u)\n",
++ priv->netdev->name, level_dbm, table[level_dbm]);
++ acxpci_s_write_phy_reg(priv, 0x11, table[level_dbm]);
++ return OK;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_init_module
++*
++* Module initialization routine, called once at module load time.
++*
++* Returns:
++* 0 - success
++* ~0 - failure, module is unloaded.
++*
++* Call context:
++* process thread (insmod or modprobe)
++----------------------------------------------------------------*/
++int __init
++acxpci_e_init_module(void)
++{
++ int res;
++
++ FN_ENTER;
++
++#if (ACX_IO_WIDTH==32)
++ printk("acx: compiled to use 32bit I/O access. "
++ "I/O timing issues might occur, such as "
++ "non-working firmware upload. Report them\n");
++#else
++ printk("acx: compiled to use 16bit I/O access only "
++ "(compatibility mode)\n");
++#endif
++
++#ifdef __LITTLE_ENDIAN
++ acxlog(L_INIT, "running on a little-endian CPU\n");
++#else
++ acxlog(L_INIT, "running on a BIG-ENDIAN CPU\n");
++#endif
++ acxlog(L_INIT, "PCI module " WLAN_RELEASE " initialized, "
++ "waiting for cards to probe...\n");
++
++ res = pci_module_init(&acx_pci_drv_id);
++ FN_EXIT1(res);
++ return res;
++}
++
++
++/*----------------------------------------------------------------
++* acx_e_cleanup_module
++*
++* Called at module unload time. This is our last chance to
++* clean up after ourselves.
++*
++* Call context:
++* process thread
++----------------------------------------------------------------*/
++void __exit
++acxpci_e_cleanup_module(void)
++{
++ struct net_device *dev;
++ unsigned long flags;
++
++ FN_ENTER;
++
++ /* Since the whole module is about to be unloaded,
++ * we recursively shutdown all cards we handled instead
++ * of doing it in remove_pci() (which will be activated by us
++ * via pci_unregister_driver at the end).
++ * remove_pci() might just get called after a card eject,
++ * that's why hardware operations have to be done here instead
++ * when the hardware is available. */
++
++ down(&root_acx_dev_sem);
++
++ dev = root_acx_dev.newest;
++ while (dev != NULL) {
++ /* doh, netdev_priv() doesn't have const! */
++ wlandevice_t *priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ /* disable both Tx and Rx to shut radio down properly */
++ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0);
++
++#ifdef REDUNDANT
++ /* put the eCPU to sleep to save power
++ * Halting is not possible currently,
++ * since not supported by all firmware versions */
++ acx_s_issue_cmd(priv, ACX100_CMD_SLEEP, NULL, 0);
++#endif
++ acx_lock(priv, flags);
++
++ /* disable power LED to save power :-) */
++ acxlog(L_INIT, "switching off power LED to save power :-)\n");
++ acx_l_power_led(priv, 0);
++
++ /* stop our eCPU */
++ if (IS_ACX111(priv)) {
++ /* FIXME: does this actually keep halting the eCPU?
++ * I don't think so...
++ */
++ acx_l_reset_mac(priv);
++ } else {
++ u16 temp;
++
++ /* halt eCPU */
++ temp = acx_read_reg16(priv, IO_ACX_ECPU_CTRL) | 0x1;
++ acx_write_reg16(priv, IO_ACX_ECPU_CTRL, temp);
++ acx_write_flush(priv);
++ }
++
++ acx_unlock(priv, flags);
++
++ acx_sem_unlock(priv);
++
++ dev = priv->prev_nd;
++ }
++
++ up(&root_acx_dev_sem);
++
++ /* now let the PCI layer recursively remove
++ * all PCI related things (acx_e_remove_pci()) */
++ pci_unregister_driver(&acx_pci_drv_id);
++
++ FN_EXIT0;
++}
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/setrate.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/setrate.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/setrate.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/setrate.c 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,213 @@
++/* TODO: stop #including, move into wireless.c
++ * until then, keep in sync copies in prism54/ and acx/ dirs
++ * code+data size: less than 1k */
++
++enum {
++ DOT11_RATE_1,
++ DOT11_RATE_2,
++ DOT11_RATE_5,
++ DOT11_RATE_11,
++ DOT11_RATE_22,
++ DOT11_RATE_33,
++ DOT11_RATE_6,
++ DOT11_RATE_9,
++ DOT11_RATE_12,
++ DOT11_RATE_18,
++ DOT11_RATE_24,
++ DOT11_RATE_36,
++ DOT11_RATE_48,
++ DOT11_RATE_54
++};
++enum {
++ DOT11_MOD_DBPSK,
++ DOT11_MOD_DQPSK,
++ DOT11_MOD_CCK,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_CCKOFDM,
++ DOT11_MOD_PBCC
++};
++static const u8 ratelist[] = { 1,2,5,11,22,33,6,9,12,18,24,36,48,54 };
++static const u8 dot11ratebyte[] = { 1*2,2*2,11,11*2,22*2,33*2,6*2,9*2,12*2,18*2,24*2,36*2,48*2,54*2 };
++static const u8 default_modulation[] = {
++ DOT11_MOD_DBPSK,
++ DOT11_MOD_DQPSK,
++ DOT11_MOD_CCK,
++ DOT11_MOD_CCK,
++ DOT11_MOD_PBCC,
++ DOT11_MOD_PBCC,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_OFDM,
++ DOT11_MOD_OFDM
++};
++
++static /* TODO: remove 'static' when moved to wireless.c */
++int
++rate_mbit2enum(int n) {
++ int i=0;
++ while(i<sizeof(ratelist)) {
++ if(n==ratelist[i]) return i;
++ i++;
++ }
++ return -EINVAL;
++}
++
++static int
++get_modulation(int r_enum, char suffix) {
++ if(suffix==',' || suffix==' ' || suffix=='\0') {
++ /* could shorten default_mod by 8 bytes:
++ if(r_enum>=DOT11_RATE_6) return DOT11_MOD_OFDM; */
++ return default_modulation[r_enum];
++ }
++ if(suffix=='c') {
++ if(r_enum<DOT11_RATE_5 || r_enum>DOT11_RATE_11) return -EINVAL;
++ return DOT11_MOD_CCK;
++ }
++ if(suffix=='p') {
++ if(r_enum<DOT11_RATE_5 || r_enum>DOT11_RATE_33) return -EINVAL;
++ return DOT11_MOD_PBCC;
++ }
++ if(suffix=='o') {
++ if(r_enum<DOT11_RATE_6) return -EINVAL;
++ return DOT11_MOD_OFDM;
++ }
++ if(suffix=='d') {
++ if(r_enum<DOT11_RATE_6) return -EINVAL;
++ return DOT11_MOD_CCKOFDM;
++ }
++ return -EINVAL;
++}
++
++#ifdef UNUSED
++static int
++fill_ratevector(const char **pstr, u8 *vector, int size,
++ int (*supported)(int mbit, int mod, void *opaque), void *opaque, int or_mask)
++{
++ unsigned long rate_mbit;
++ int rate_enum,mod;
++ const char *str = *pstr;
++ char c;
++
++ do {
++ rate_mbit = simple_strtoul(str, (char**)&str, 10);
++ if(rate_mbit>INT_MAX) return -EINVAL;
++
++ rate_enum = rate_mbit2enum(rate_mbit);
++ if(rate_enum<0) return rate_enum;
++
++ c = *str;
++ mod = get_modulation(rate_enum, c);
++ if(mod<0) return mod;
++
++ if(c>='a' && c<='z') c = *++str;
++ if(c!=',' && c!=' ' && c!='\0') return -EINVAL;
++
++ if(supported) {
++ int r = supported(rate_mbit, mod, opaque);
++ if(r) return r;
++ }
++
++ *vector++ = dot11ratebyte[rate_enum] | or_mask;
++
++ size--;
++ str++;
++ } while(size>0 && c==',');
++
++ if(size<1) return -E2BIG;
++ *vector=0; /* TODO: sort, remove dups? */
++
++ *pstr = str-1;
++ return 0;
++}
++
++static /* TODO: remove 'static' when moved to wireless.c */
++int
++fill_ratevectors(const char *str, u8 *brate, u8 *orate, int size,
++ int (*supported)(int mbit, int mod, void *opaque), void *opaque)
++{
++ int r;
++
++ r = fill_ratevector(&str, brate, size, supported, opaque, 0x80);
++ if(r) return r;
++
++ orate[0] = 0;
++ if(*str==' ') {
++ str++;
++ r = fill_ratevector(&str, orate, size, supported, opaque, 0);
++ if(r) return r;
++ /* TODO: sanitize, e.g. remove/error on rates already in basic rate set? */
++ }
++ if(*str)
++ return -EINVAL;
++
++ return 0;
++}
++#endif
++
++/* TODO: use u64 masks? */
++
++static int
++fill_ratemask(const char **pstr, u32* mask,
++ int (*supported)(int mbit, int mod,void *opaque),
++ u32 (*gen_mask)(int mbit, int mod,void *opaque),
++ void *opaque)
++{
++ unsigned long rate_mbit;
++ int rate_enum,mod;
++ u32 m = 0;
++ const char *str = *pstr;
++ char c;
++
++ do {
++ rate_mbit = simple_strtoul(str, (char**)&str, 10);
++ if(rate_mbit>INT_MAX) return -EINVAL;
++
++ rate_enum = rate_mbit2enum(rate_mbit);
++ if(rate_enum<0) return rate_enum;
++
++ c = *str;
++ mod = get_modulation(rate_enum, c);
++ if(mod<0) return mod;
++
++ if(c>='a' && c<='z') c = *++str;
++ if(c!=',' && c!=' ' && c!='\0') return -EINVAL;
++
++ if(supported) {
++ int r = supported(rate_mbit, mod, opaque);
++ if(r) return r;
++ }
++
++ m |= gen_mask(rate_mbit, mod, opaque);
++ str++;
++ } while(c==',');
++
++ *pstr = str-1;
++ *mask |= m;
++ return 0;
++}
++
++static /* TODO: remove 'static' when moved to wireless.c */
++int
++fill_ratemasks(const char *str, u32 *bmask, u32 *omask,
++ int (*supported)(int mbit, int mod,void *opaque),
++ u32 (*gen_mask)(int mbit, int mod,void *opaque),
++ void *opaque)
++{
++ int r;
++
++ r = fill_ratemask(&str, bmask, supported, gen_mask, opaque);
++ if(r) return r;
++
++ if(*str==' ') {
++ str++;
++ r = fill_ratemask(&str, omask, supported, gen_mask, opaque);
++ if(r) return r;
++ }
++ if(*str)
++ return -EINVAL;
++ return 0;
++}
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/usb.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/usb.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/usb.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/usb.c 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,1700 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++/***********************************************************************
++** USB support for TI ACX100 based devices. Many parts are taken from
++** the PCI driver.
++**
++** Authors:
++** Martin Wawro <martin.wawro AT uni-dortmund.de>
++** Andreas Mohr <andi AT lisas.de>
++**
++** Issues:
++** - Note that this driver relies on a native little-endian byteformat
++** at some points
++**
++** LOCKING
++** callback functions called by USB core are running in interrupt context
++** and thus have names with _i_.
++*/
++#define ACX_USB 1
++
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
++#include <linux/moduleparam.h>
++#endif
++#include <linux/kernel.h>
++#include <linux/usb.h>
++#include <linux/netdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/etherdevice.h>
++#include <linux/wireless.h>
++#if WIRELESS_EXT >= 13
++#include <net/iw_handler.h>
++#endif
++
++#include "acx.h"
++
++/* number of endpoints of an interface */
++#define NUM_EP(intf) (intf)->altsetting[0].desc.bNumEndpoints
++#define EP(intf, nr) (intf)->altsetting[0].endpoint[(nr)].desc
++#define GET_DEV(udev) usb_get_dev((udev))
++#define PUT_DEV(udev) usb_put_dev((udev))
++#define SET_NETDEV_OWNER(ndev, owner) /* not needed anymore ??? */
++
++#define QUEUE_BULK 0
++#define ZERO_PACKET URB_ZERO_PACKET
++
++static inline int
++submit_urb(struct urb *urb, int mem_flags)
++{
++ return usb_submit_urb(urb, mem_flags);
++}
++static inline struct urb*
++alloc_urb(int iso_pk, int mem_flags)
++{
++ return usb_alloc_urb(iso_pk, mem_flags);
++}
++
++
++/***********************************************************************
++*/
++#define ACX100_VENDOR_ID 0x2001
++#define ACX100_PRODUCT_ID_UNBOOTED 0x3B01
++#define ACX100_PRODUCT_ID_BOOTED 0x3B00
++
++/* RX-Timeout: NONE (request waits forever) */
++#define ACX100_USB_RX_TIMEOUT (0)
++
++#define ACX100_USB_TX_TIMEOUT (4*HZ)
++
++#define USB_CTRL_HARD_TIMEOUT 5500 /* steps in ms */
++
++
++/***********************************************************************
++** Prototypes
++*/
++static int acx100usb_e_probe(struct usb_interface *, const struct usb_device_id *);
++static void acx100usb_e_disconnect(struct usb_interface *);
++static void acx100usb_i_complete_tx(struct urb *, struct pt_regs *);
++static void acx100usb_i_complete_rx(struct urb *, struct pt_regs *);
++static int acx100usb_e_open(struct net_device *);
++static int acx100usb_e_close(struct net_device *);
++static void acx100usb_i_set_rx_mode(struct net_device *);
++static int acx100usb_e_init_network_device(struct net_device *);
++static int acx100usb_boot(struct usb_device *);
++
++static struct net_device_stats * acx_e_get_stats(struct net_device *);
++static struct iw_statistics *acx_e_get_wireless_stats(struct net_device *);
++
++static void acx100usb_l_poll_rx(wlandevice_t *, int number);
++
++static void acx100usb_i_tx_timeout(struct net_device *);
++
++/* static void dump_device(struct usb_device *); */
++/* static void dump_device_descriptor(struct usb_device_descriptor *); */
++/* static void dump_config_descriptor(struct usb_config_descriptor *); */
++
++/***********************************************************************
++** Module Data
++*/
++#define TXBUFSIZE sizeof(usb_txbuffer_t)
++//// Bogus! We CANNOT pretend that rxbuffer_t is larger than it is.
++/* make it a multiply of 64 */
++/* #define RXBUFSIZE ((sizeof(rxbuffer_t)+63) & ~63) */
++#define RXBUFSIZE sizeof(rxbuffer_t)
++
++static const struct usb_device_id
++acx100usb_ids[] = {
++ { USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_BOOTED) },
++ { USB_DEVICE(ACX100_VENDOR_ID, ACX100_PRODUCT_ID_UNBOOTED) },
++ {}
++};
++
++
++/* USB driver data structure as required by the kernel's USB core */
++static struct usb_driver
++acx100usb_driver = {
++ .name = "acx_usb",
++ .owner = THIS_MODULE,
++ .probe = acx100usb_e_probe,
++ .disconnect = acx100usb_e_disconnect,
++ .id_table = acx100usb_ids
++};
++
++
++/***********************************************************************
++** USB helper
++**
++** ldd3 ch13 says:
++** When the function is usb_kill_urb, the urb lifecycle is stopped. This
++** function is usually used when the device is disconnected from the system,
++** in the disconnect callback. For some drivers, the usb_unlink_urb function
++** should be used to tell the USB core to stop an urb. This function does not
++** wait for the urb to be fully stopped before returning to the caller.
++** This is useful for stoppingthe urb while in an interrupt handler or when
++** a spinlock is held, as waiting for a urb to fully stop requires the ability
++** for the USB core to put the calling process to sleep. This function requires
++** that the URB_ASYNC_UNLINK flag value be set in the urb that is being asked
++** to be stopped in order to work properly.
++**
++** URB_ASYNC_UNLINK is osolete, usb_unlink_urb will always be
++** asynchronuos while usb_kill_urb is synchronuos and should be called
++** directly. -> drivers/usb/core/urb.c
++**
++** In light of this, timeout is just for paranoid reasons...
++*/
++static void
++acx_unlink_and_free_urb(struct urb* urb)
++{
++ if (!urb)
++ return;
++
++ if (urb->status == -EINPROGRESS) {
++ int timeout = 10;
++
++ usb_unlink_urb(urb);
++ while (--timeout && urb->status == -EINPROGRESS) {
++ mdelay(1);
++ }
++ /* if (!timeout) then what?? */
++ }
++
++ /* just a refcounted kfree, safe undef lock */
++ usb_free_urb(urb);
++}
++
++
++/***********************************************************************
++*/
++#if ACX_DEBUG
++static char*
++acx100usb_pstatus(int val)
++{
++ static char status[20];
++
++ if (val < 0)
++ sprintf(status, "errno %d", -val);
++ else
++ sprintf(status, "length %d", val);
++
++ return status;
++}
++#endif /* ACX_DEBUG */
++
++
++/***********************************************************************
++** EEPROM and PHY read/write helpers
++*/
++/***********************************************************************
++** acxusb_s_read_phy_reg
++*/
++int
++acxusb_s_read_phy_reg(wlandevice_t *priv, u32 reg, u8 *charbuf)
++{
++ mem_read_write_t mem;
++
++ FN_ENTER;
++
++ mem.addr = cpu_to_le16(reg);
++ mem.type = cpu_to_le16(0x82);
++ mem.len = cpu_to_le32(4);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_MEM_READ, &mem, sizeof(mem) - 4);
++ *charbuf = mem.data;
++ acxlog(L_DEBUG, "radio PHY at 0x%04X = 0x%02X\n", *charbuf, reg);
++
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++/***********************************************************************
++*/
++int
++acxusb_s_write_phy_reg(wlandevice_t *priv, u32 reg, u8 value)
++{
++ mem_read_write_t mem;
++
++ FN_ENTER;
++
++ mem.addr = cpu_to_le16(reg);
++ mem.type = cpu_to_le16(0x82);
++ mem.len = cpu_to_le32(4);
++ mem.data = value;
++//FIXME: maybe sizeof() - 4?
++ acx_s_issue_cmd(priv, ACX1xx_CMD_MEM_WRITE, &mem, sizeof(mem));
++ acxlog(L_DEBUG, "radio PHY write 0x%02X at 0x%04X\n", value, reg);
++
++ FN_EXIT1(OK);
++ return OK;
++}
++
++
++/***********************************************************************
++** acx_s_issue_cmd_timeo
++** Excecutes a command in the command mailbox
++**
++** buffer = a pointer to the data.
++** The data must not include 4 byte command header
++*/
++
++/* TODO: ideally we shall always know how much we need
++** and this shall be 0 */
++#define BOGUS_SAFETY_PADDING 0x40
++
++#undef FUNC
++#define FUNC "issue_cmd"
++
++#if !ACX_DEBUG
++int
++acxusb_s_issue_cmd_timeo(
++ wlandevice_t *priv,
++ unsigned cmd,
++ void *buffer,
++ unsigned buflen,
++ unsigned timeout)
++{
++#else
++int
++acxusb_s_issue_cmd_timeo_debug(
++ wlandevice_t *priv,
++ unsigned cmd,
++ void *buffer,
++ unsigned buflen,
++ unsigned timeout,
++ const char* cmdstr)
++{
++#endif
++ /* USB ignores timeout param */
++
++ struct usb_device *usbdev;
++ struct {
++ u16 cmd ACX_PACKED;
++ u16 status ACX_PACKED;
++ u8 data[1] ACX_PACKED;
++ } *loc;
++ const char *devname;
++ int acklen, blocklen, inpipe, outpipe;
++ int cmd_status;
++ int result;
++
++ FN_ENTER;
++
++ devname = priv->netdev->name;
++ if (!devname || !devname[0])
++ devname = "acx";
++
++ acxlog(L_CTL, FUNC"(cmd:%s,buflen:%u,type:0x%04X)\n",
++ cmdstr, buflen,
++ buffer ? le16_to_cpu(((acx_ie_generic_t *)buffer)->type) : -1);
++
++ loc = kmalloc(buflen + 4 + BOGUS_SAFETY_PADDING, GFP_KERNEL);
++ if (!loc) {
++ printk("%s: "FUNC"(): no memory for data buffer\n", devname);
++ goto bad;
++ }
++
++ /* get context from wlandevice */
++ usbdev = priv->usbdev;
++
++ /* check which kind of command was issued */
++ loc->cmd = cpu_to_le16(cmd);
++ loc->status = 0;
++
++/* NB: buflen == frmlen + 4
++**
++** Interrogate: write 8 bytes: (cmd,status,rid,frmlen), then
++** read (cmd,status,rid,frmlen,data[frmlen]) back
++**
++** Configure: write (cmd,status,rid,frmlen,data[frmlen])
++**
++** Possibly bogus special handling of ACX1xx_IE_SCAN_STATUS removed
++*/
++
++ /* now write the parameters of the command if needed */
++ acklen = buflen + 4 + BOGUS_SAFETY_PADDING;
++ blocklen = buflen;
++ if (buffer && buflen) {
++ /* if it's an INTERROGATE command, just pass the length
++ * of parameters to read, as data */
++ if (cmd == ACX1xx_CMD_INTERROGATE) {
++ blocklen = 4;
++ acklen = buflen + 4;
++ }
++ memcpy(loc->data, buffer, blocklen);
++ }
++ blocklen += 4; /* account for cmd,status */
++
++ /* obtain the I/O pipes */
++ outpipe = usb_sndctrlpipe(usbdev, 0);
++ inpipe = usb_rcvctrlpipe(usbdev, 0);
++ acxlog(L_CTL, "ctrl inpipe=0x%X outpipe=0x%X\n", inpipe, outpipe);
++ acxlog(L_CTL, "sending USB control msg (out) (blocklen=%d)\n", blocklen);
++ if (acx_debug & L_DATA)
++ acx_dump_bytes(loc, blocklen);
++
++ result = usb_control_msg(usbdev, outpipe,
++ ACX_USB_REQ_CMD, /* request */
++ USB_TYPE_VENDOR|USB_DIR_OUT, /* requesttype */
++ 0, /* value */
++ 0, /* index */
++ loc, /* dataptr */
++ blocklen, /* size */
++ USB_CTRL_HARD_TIMEOUT /* timeout in ms */
++ );
++ acxlog(L_CTL, "wrote %d bytes\n", result);
++ if (result < 0) {
++ goto bad;
++ }
++
++ /* check for device acknowledge */
++ acxlog(L_CTL, "sending USB control msg (in) (acklen=%d)\n", acklen);
++ loc->status = 0; /* delete old status flag -> set to IDLE */
++//shall we zero out the rest?
++ result = usb_control_msg(usbdev, inpipe,
++ ACX_USB_REQ_CMD, /* request */
++ USB_TYPE_VENDOR|USB_DIR_IN, /* requesttype */
++ 0, /* value */
++ 0, /* index */
++ loc, /* dataptr */
++ acklen, /* size */
++ USB_CTRL_HARD_TIMEOUT /* timeout in ms */
++ );
++ if (result < 0) {
++ printk("%s: "FUNC"(): USB read error %d\n", devname, result);
++ goto bad;
++ }
++ if (acx_debug & L_CTL) {
++ printk("read %d bytes: ", result);
++ acx_dump_bytes(loc, result);
++ }
++
++//check for result==buflen+4? Was seen:
++//interrogate(type:ACX100_IE_DOT11_ED_THRESHOLD,len:4)
++//issue_cmd(cmd:ACX1xx_CMD_INTERROGATE,buflen:8,type:4111)
++//ctrl inpipe=0x80000280 outpipe=0x80000200
++//sending USB control msg (out) (blocklen=8)
++//01 00 00 00 0F 10 04 00
++//wrote 8 bytes
++//sending USB control msg (in) (acklen=12) sizeof(loc->data
++//read 4 bytes <==== MUST BE 12!!
++
++ cmd_status = le16_to_cpu(loc->status);
++ if (cmd_status != 1) {
++ printk("%s: "FUNC"(): cmd_status is not SUCCESS: %d (%s)\n",
++ devname, cmd_status, acx_cmd_status_str(cmd_status));
++ /* TODO: goto bad; ? */
++ }
++ if ((cmd == ACX1xx_CMD_INTERROGATE) && buffer && buflen) {
++ memcpy(buffer, loc->data, buflen);
++ acxlog(L_CTL, "response frame: cmd=0x%04X status=%d\n",
++ le16_to_cpu(loc->cmd),
++ cmd_status);
++ }
++ kfree(loc);
++ FN_EXIT1(OK);
++ return OK;
++bad:
++ kfree(loc);
++ /* Give enough info so that callers can avoid
++ ** printing their own diagnostic messages */
++#if ACX_DEBUG
++ printk("%s: "FUNC"(cmd:%s) FAILED\n", devname, cmdstr);
++#else
++ printk("%s: "FUNC"(cmd:0x%04X) FAILED\n", devname, cmd);
++#endif
++ dump_stack();
++ FN_EXIT1(NOT_OK);
++ return NOT_OK;
++}
++
++
++/***********************************************************************
++** acx100usb_e_probe()
++**
++** Inputs:
++** dev -> Pointer to usb_device structure that may or may not be claimed
++** ifNum -> Interface number
++** devID -> Device ID (vendor and product specific stuff)
++************************************************************************
++** Returns:
++** (void *) Pointer to (custom) driver context or NULL if we are not interested
++** or unable to handle the offered device.
++**
++** Description:
++** This function is invoked by the kernel's USB core whenever a new device is
++** attached to the system or the module is loaded. It is presented a usb_device
++** structure from which information regarding the device is obtained and evaluated.
++** In case this driver is able to handle one of the offered devices, it returns
++** a non-null pointer to a driver context and thereby claims the device.
++*/
++static void
++acx_netdev_init(struct net_device *dev) {}
++
++static int
++acx100usb_e_probe(struct usb_interface *intf, const struct usb_device_id *devID)
++{
++ struct usb_device *usbdev = interface_to_usbdev(intf);
++ wlandevice_t *priv = NULL;
++ struct net_device *dev = NULL;
++ struct usb_config_descriptor *config;
++ struct usb_endpoint_descriptor *epdesc;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
++ struct usb_host_endpoint *ep;
++#endif
++ struct usb_interface_descriptor *ifdesc;
++ const char* msg;
++ int numconfigs, numfaces, numep;
++ int result = OK;
++ int i;
++
++ FN_ENTER;
++
++ /* First check if this is the "unbooted" hardware */
++ if ((usbdev->descriptor.idVendor == ACX100_VENDOR_ID)
++ && (usbdev->descriptor.idProduct == ACX100_PRODUCT_ID_UNBOOTED)) {
++ /* Boot the device (i.e. upload the firmware) */
++ acx100usb_boot(usbdev);
++
++ /* OK, we are done with booting. Normally, the
++ ** ID for the unbooted device should disappear
++ ** and it will not need a driver anyway...so
++ ** return a NULL
++ */
++ acxlog(L_INIT, "finished booting, returning from probe()\n");
++ result = OK; /* success */
++ goto end;
++ }
++
++ if ((usbdev->descriptor.idVendor != ACX100_VENDOR_ID)
++ || (usbdev->descriptor.idProduct != ACX100_PRODUCT_ID_BOOTED)) {
++ goto end_nodev;
++ }
++
++ /* Ok, so it's our device and it is already booted */
++
++ /* Allocate memory for a network device */
++ dev = alloc_netdev(sizeof(wlandevice_t), "wlan%d", acx_netdev_init);
++ /* (NB: memsets to 0 entire area) */
++ if (!dev) {
++ msg = "acx: no memory for netdev\n";
++ goto end_nomem;
++ }
++ dev->init = (void *)&acx100usb_e_init_network_device;
++
++ /* Setup private driver context */
++ priv = netdev_priv(dev);
++ priv->netdev = dev;
++ priv->dev_type = DEVTYPE_USB;
++ priv->chip_type = CHIPTYPE_ACX100;
++ /* FIXME: should be read from register (via firmware) using standard ACX code */
++ priv->radio_type = RADIO_MAXIM_0D;
++ priv->usbdev = usbdev;
++
++ spin_lock_init(&priv->lock); /* initial state: unlocked */
++ sema_init(&priv->sem, 1); /* initial state: 1 (upped) */
++
++ /* Initialize the device context and also check
++ ** if this is really the hardware we know about.
++ ** If not sure, at least notify the user that he
++ ** may be in trouble...
++ */
++ numconfigs = (int)usbdev->descriptor.bNumConfigurations;
++ if (numconfigs != 1)
++ printk("acx: number of configurations is %d, "
++ "this driver only knows how to handle 1, "
++ "be prepared for surprises\n", numconfigs);
++
++ config = &usbdev->config->desc;
++ numfaces = config->bNumInterfaces;
++ if (numfaces != 1)
++ printk("acx: number of interfaces is %d, "
++ "this driver only knows how to handle 1, "
++ "be prepared for surprises\n", numfaces);
++
++ ifdesc = &intf->altsetting->desc;
++ numep = ifdesc->bNumEndpoints;
++ acxlog(L_DEBUG, "# of endpoints: %d\n", numep);
++
++ /* obtain information about the endpoint
++ ** addresses, begin with some default values
++ */
++ priv->bulkoutep = 1;
++ priv->bulkinep = 1;
++ for (i = 0; i < numep; i++) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
++ ep = usbdev->ep_in[i];
++ if (!ep)
++ continue;
++ epdesc = &ep->desc;
++#else
++ epdesc = usb_epnum_to_ep_desc(usbdev, i);
++ if (!epdesc)
++ continue;
++#endif
++ if (epdesc->bmAttributes & USB_ENDPOINT_XFER_BULK) {
++ if (epdesc->bEndpointAddress & 0x80)
++ priv->bulkinep = epdesc->bEndpointAddress & 0xF;
++ else
++ priv->bulkoutep = epdesc->bEndpointAddress & 0xF;
++ }
++ }
++ acxlog(L_DEBUG, "bulkout ep: 0x%X\n", priv->bulkoutep);
++ acxlog(L_DEBUG, "bulkin ep: 0x%X\n", priv->bulkinep);
++
++ /* Set the packet-size equivalent to the buffer size */
++ /* already done by memset: priv->rxtruncsize = 0; */
++ acxlog(L_DEBUG, "TXBUFSIZE=%d RXBUFSIZE=%d\n",
++ (int) TXBUFSIZE, (int) RXBUFSIZE);
++
++ priv->tx_free = ACX100_USB_NUM_BULK_URBS;
++ /* already done by memset:
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ priv->usb_tx[i].busy = 0;
++ }
++ */
++
++ /* Setup URBs for bulk-in/out messages */
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ priv->bulkrx_urbs[i] = alloc_urb(0, GFP_KERNEL);
++ if (!priv->bulkrx_urbs[i]) {
++ msg = "acx: no memory for input URB\n";
++ goto end_nomem;
++ }
++ priv->bulkrx_urbs[i]->status = 0;
++
++ priv->usb_tx[i].urb = alloc_urb(0, GFP_KERNEL);
++ if (!priv->usb_tx[i].urb) {
++ msg = "acx: no memory for output URB\n";
++ goto end_nomem;
++ }
++ priv->usb_tx[i].urb->status = 0;
++
++ priv->usb_tx[i].priv = priv;
++ }
++
++ usb_set_intfdata(intf, priv);
++ SET_NETDEV_DEV(dev, &intf->dev);
++
++ /* Register the network device */
++ acxlog(L_INIT, "registering network device\n");
++ result = register_netdev(dev);
++ if (result != 0) {
++ msg = "acx: failed to register network device "
++ "for USB WLAN (errcode=%d)\n";
++ goto end_nomem;
++ }
++#ifdef CONFIG_PROC_FS
++ if (OK != acx_proc_register_entries(dev)) {
++ printk("acx: /proc registration failed\n");
++ }
++#endif
++
++ printk("acx: USB module " WLAN_RELEASE " loaded successfully\n");
++
++#if CMD_DISCOVERY
++ great_inquisitor(priv);
++#endif
++
++ /* Everything went OK, we are happy now */
++ result = OK;
++ goto end;
++
++end_nomem:
++ printk(msg, result);
++
++ if (dev) {
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ usb_free_urb(priv->bulkrx_urbs[i]);
++ usb_free_urb(priv->usb_tx[i].urb);
++ }
++ free_netdev(dev);
++ }
++ result = -ENOMEM;
++ goto end;
++
++end_nodev:
++
++ /* no device we could handle, return error. */
++ result = -EIO;
++
++end:
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx100usb_e_disconnect():
++** Inputs:
++** dev -> Pointer to usb_device structure handled by this module
++** devContext -> Pointer to own device context (acx100usb_context)
++************************************************************************
++** Description:
++** This function is invoked whenever the user pulls the plug from the USB
++** device or the module is removed from the kernel. In these cases, the
++** network devices have to be taken down and all allocated memory has
++** to be freed.
++*/
++static void
++acx100usb_e_disconnect(struct usb_interface *intf)
++{
++ wlandevice_t *priv = usb_get_intfdata(intf);
++ unsigned long flags;
++ int i;
++
++ FN_ENTER;
++
++ /* No WLAN device...no sense */
++ if (!priv)
++ goto end;
++
++ /*
++ * We get the sem *after* FLUSH to avoid a deadlock.
++ * See pci.c:acx_s_down() for deails.
++ */
++ FLUSH_SCHEDULED_WORK();
++ acx_sem_lock(priv);
++
++ acx_lock(priv, flags);
++
++ /* I wonder if above is enough to prevent tx/rx callbacks
++ ** to start queue again? Like this:
++ ** complete_rx -> acx_l_process_rxbuf -> associated -> acx_start_queue()
++ ** Oh well... */
++
++ /* This device exists no more. */
++ usb_set_intfdata(intf, NULL);
++
++ /* stop the transmit queue */
++ if (priv->netdev) {
++ acx_stop_queue(priv->netdev, "on USB disconnect");
++#ifdef CONFIG_PROC_FS
++ acx_proc_unregister_entries(priv->netdev);
++#endif
++ }
++
++ /* now abort pending URBs and free them */
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ acx_unlink_and_free_urb(priv->bulkrx_urbs[i]);
++ acx_unlink_and_free_urb(priv->usb_tx[i].urb);
++ }
++
++ acx_unlock(priv, flags);
++ acx_sem_unlock(priv);
++
++ /* Unregister the network devices */
++ if (priv->netdev) {
++ unregister_netdev(priv->netdev);
++ free_netdev(priv->netdev);
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx100usb_boot():
++** Inputs:
++** usbdev -> Pointer to kernel's usb_device structure
++** endpoint -> Address of the endpoint for control transfers
++************************************************************************
++** Returns:
++** (int) Errorcode or 0 on success
++**
++** Description:
++** This function triggers the loading of the firmware image from harddisk
++** and then uploads the firmware to the USB device. After uploading the
++** firmware and transmitting the checksum, the device resets and appears
++** as a new device on the USB bus (the device we can finally deal with)
++*/
++static int
++acx100usb_boot(struct usb_device *usbdev)
++{
++ static const char filename[] = "tiacx100usb";
++
++ char *firmware = NULL;
++ char *usbbuf;
++ unsigned int offset;
++ unsigned int len, inpipe, outpipe;
++ u32 checksum;
++ u32 size;
++ int result;
++
++ FN_ENTER;
++
++ usbbuf = kmalloc(ACX100_USB_RWMEM_MAXLEN, GFP_KERNEL);
++ if (!usbbuf) {
++ printk(KERN_ERR "acx: no memory for USB transfer buffer ("
++ STRING(ACX100_USB_RWMEM_MAXLEN)" bytes)\n");
++ result = -ENOMEM;
++ goto end;
++ }
++ firmware = (char *)acx_s_read_fw(&usbdev->dev, filename, &size);
++ if (!firmware) {
++ result = -EIO;
++ goto end;
++ }
++ acxlog(L_INIT, "firmware size: %d bytes\n", size);
++
++ /* Obtain the I/O pipes */
++ outpipe = usb_sndctrlpipe(usbdev, 0);
++ inpipe = usb_rcvctrlpipe(usbdev, 0);
++
++ /* now upload the firmware, slice the data into blocks */
++ offset = 8;
++ while (offset < size) {
++ len = size - offset;
++ if (len >= ACX100_USB_RWMEM_MAXLEN) {
++ len = ACX100_USB_RWMEM_MAXLEN;
++ }
++ acxlog(L_INIT, "uploading firmware (%d bytes, offset=%d)\n",
++ len, offset);
++ result = 0;
++ memcpy(usbbuf, firmware + offset, len);
++ result = usb_control_msg(usbdev, outpipe,
++ ACX_USB_REQ_UPLOAD_FW,
++ USB_TYPE_VENDOR|USB_DIR_OUT,
++ size - 8, /* value */
++ 0, /* index */
++ usbbuf, /* dataptr */
++ len, /* size */
++ 3000 /* timeout in ms */
++ );
++ offset += len;
++ if (result < 0) {
++#if ACX_DEBUG
++ printk(KERN_ERR "acx: error %d (%s) during upload "
++ "of firmware, aborting\n", result,
++ acx100usb_pstatus(result));
++#else
++ printk(KERN_ERR "acx: error %d during upload "
++ "of firmware, aborting\n", result);
++#endif
++ goto end;
++ }
++ }
++
++ /* finally, send the checksum and reboot the device */
++ checksum = le32_to_cpu(*(u32 *)firmware);
++ /* is this triggers the reboot? */
++ result = usb_control_msg(usbdev, outpipe,
++ ACX_USB_REQ_UPLOAD_FW,
++ USB_TYPE_VENDOR|USB_DIR_OUT,
++ checksum & 0xffff, /* value */
++ checksum >> 16, /* index */
++ NULL, /* dataptr */
++ 0, /* size */
++ 3000 /* timeout in ms */
++ );
++ if (result < 0) {
++ printk(KERN_ERR "acx: error %d during tx of checksum, "
++ "aborting\n", result);
++ goto end;
++ }
++ result = usb_control_msg(usbdev, inpipe,
++ ACX_USB_REQ_ACK_CS,
++ USB_TYPE_VENDOR|USB_DIR_IN,
++ checksum & 0xffff, /* value */
++ checksum >> 16, /* index */
++ usbbuf, /* dataptr */
++ 8, /* size */
++ 3000 /* timeout in ms */
++ );
++ if (result < 0) {
++ printk(KERN_ERR "acx: error %d during ACK of checksum, "
++ "aborting\n", result);
++ goto end;
++ }
++ if (*usbbuf != 0x10) {
++ kfree(usbbuf);
++ printk(KERN_ERR "acx: invalid checksum?\n");
++ result = -EINVAL;
++ goto end;
++ }
++ result = 0;
++end:
++ vfree(firmware);
++ kfree(usbbuf);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx100usb_e_init_network_device():
++** Inputs:
++** dev -> Pointer to network device
++************************************************************************
++** Description:
++** Basic setup of a network device for use with the WLAN device.
++*/
++static int
++acx100usb_e_init_network_device(struct net_device *dev)
++{
++ wlandevice_t *priv;
++ int result = 0;
++
++ FN_ENTER;
++
++ /* Setup the device and stop the queue */
++ ether_setup(dev);
++ acx_stop_queue(dev, "on init");
++
++ priv = netdev_priv(dev);
++
++ acx_sem_lock(priv);
++
++ /* put the ACX100 out of sleep mode */
++ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
++
++ /* Register the callbacks for the network device functions */
++ dev->open = &acx100usb_e_open;
++ dev->stop = &acx100usb_e_close;
++ dev->hard_start_xmit = (void *)&acx_i_start_xmit;
++ dev->get_stats = (void *)&acx_e_get_stats;
++ dev->get_wireless_stats = (void *)&acx_e_get_wireless_stats;
++#if WIRELESS_EXT >= 13
++ dev->wireless_handlers = (struct iw_handler_def *)&acx_ioctl_handler_def;
++#else
++ dev->do_ioctl = (void *)&acx_e_ioctl_old;
++#endif
++ dev->set_multicast_list = (void *)&acx100usb_i_set_rx_mode;
++#ifdef HAVE_TX_TIMEOUT
++ dev->tx_timeout = &acx100usb_i_tx_timeout;
++ dev->watchdog_timeo = 4 * HZ;
++#endif
++ result = acx_s_init_mac(dev);
++ if (OK != result)
++ goto end;
++ result = acx_s_set_defaults(priv);
++ if (OK != result) {
++ printk("%s: acx_set_defaults FAILED\n", dev->name);
++ goto end;
++ }
++
++ SET_MODULE_OWNER(dev);
++end:
++ acx_sem_unlock(priv);
++
++ FN_EXIT1(result);
++ return result;
++}
++
++
++/***********************************************************************
++** acx100usb_e_open
++** This function is called when the user sets up the network interface.
++** It initializes a management timer, sets up the USB card and starts
++** the network tx queue and USB receive.
++*/
++static int
++acx100usb_e_open(struct net_device *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ int i;
++
++ FN_ENTER;
++
++ acx_sem_lock(priv);
++
++ /* put the ACX100 out of sleep mode */
++ acx_s_issue_cmd(priv, ACX1xx_CMD_WAKE, NULL, 0);
++
++ acx_init_task_scheduler(priv);
++
++ init_timer(&priv->mgmt_timer);
++ priv->mgmt_timer.function = acx_i_timer;
++ priv->mgmt_timer.data = (unsigned long)priv;
++
++ /* set ifup to 1, since acx_start needs it */
++ SET_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
++ acx_s_start(priv);
++
++ acx_start_queue(dev, "on open");
++
++ acx_lock(priv, flags);
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ acx100usb_l_poll_rx(priv, i);
++ }
++ acx_unlock(priv, flags);
++
++ WLAN_MOD_INC_USE_COUNT;
++
++ acx_sem_unlock(priv);
++
++ FN_EXIT0;
++ return 0;
++}
++
++
++/***********************************************************************
++** acx100usb_l_poll_rx
++** This function initiates a bulk-in USB transfer (in case the interface
++** is up).
++*/
++static void
++acx100usb_l_poll_rx(wlandevice_t *priv, int number)
++{
++ struct usb_device *usbdev;
++ rxbuffer_t *inbuf;
++ acx_usb_bulk_context_t *rxcon;
++ struct urb *rxurb;
++ int errcode;
++ unsigned int inpipe;
++
++ FN_ENTER;
++
++ if (!(priv->dev_state_mask & ACX_STATE_IFACE_UP)) {
++ goto end;
++ }
++
++ rxcon = &priv->rxcons[number];
++ inbuf = &priv->bulkins[number];
++ rxurb = priv->bulkrx_urbs[number];
++ usbdev = priv->usbdev;
++
++ rxcon->device = priv;
++ rxcon->number = number;
++ inpipe = usb_rcvbulkpipe(usbdev, priv->bulkinep);
++ if (rxurb->status == -EINPROGRESS) {
++ printk(KERN_ERR "acx: error, rx triggered while rx urb in progress\n");
++ /* FIXME: this is nasty, receive is being cancelled by this code
++ * on the other hand, this should not happen anyway...
++ */
++ usb_unlink_urb(rxurb);
++ }
++ rxurb->actual_length = 0;
++ usb_fill_bulk_urb(rxurb, usbdev, inpipe,
++ inbuf, /* dataptr */
++ RXBUFSIZE, /* size */
++ acx100usb_i_complete_rx, /* handler */
++ rxcon /* handler param */
++ );
++ rxurb->transfer_flags = QUEUE_BULK;
++
++ /* ATOMIC: we may be called from complete_rx() usb callback */
++ errcode = submit_urb(rxurb, GFP_ATOMIC);
++ /* FIXME: evaluate the error code! */
++ acxlog(L_USBRXTX, "SUBMIT RX (%d) inpipe=0x%X size=%d errcode=%d\n",
++ number, inpipe, (int) RXBUFSIZE, errcode);
++
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx100usb_i_complete_rx():
++** Inputs:
++** urb -> Pointer to USB request block
++** regs -> Pointer to register-buffer for syscalls (see asm/ptrace.h)
++************************************************************************
++** Description:
++** This function is invoked by USB subsystem whenever a bulk receive
++** request returns.
++** The received data is then committed to the network stack and the next
++** USB receive is triggered.
++*/
++static void
++acx100usb_i_complete_rx(struct urb *urb, struct pt_regs *regs)
++{
++ wlandevice_t *priv;
++ rxbuffer_t *ptr;
++ rxbuffer_t *inbuf;
++ unsigned long flags;
++ int size, number, remsize, packetsize;
++
++ FN_ENTER;
++
++ if (!urb->context) {
++ printk(KERN_ERR "acx: error, urb context was NULL\n");
++ goto end; /* at least try to prevent the worst */
++ }
++
++ priv = ((acx_usb_bulk_context_t *)urb->context)->device;
++
++ acx_lock(priv, flags);
++
++ /* TODO: we maybe need to check whether urb was unlinked
++ ** (happens on disconnect and close, see there). How? */
++
++ number = ((acx_usb_bulk_context_t *)urb->context)->number;
++ size = urb->actual_length;
++ remsize = size;
++
++ acxlog(L_USBRXTX, "RETURN RX (%d) status=%d size=%d\n",
++ number, urb->status, size);
++
++ inbuf = &priv->bulkins[number];
++ ptr = inbuf;
++
++ /* check if the transfer was aborted */
++ switch (urb->status) {
++ case 0: /* No error */
++ break;
++ case -EOVERFLOW:
++ printk(KERN_ERR "acx: error in rx, data overrun -> emergency stop\n");
++ /* LOCKING BUG! acx100usb_e_close(priv->netdev); */
++ goto end_unlock;
++ case -ECONNRESET:
++ goto do_poll_rx;
++ default:
++ priv->stats.rx_errors++;
++ printk("acx: rx error (urb status=%d)\n", urb->status);
++ goto do_poll_rx;
++ }
++
++ if (!size)
++ printk("acx: warning, encountered zerolength rx packet\n");
++
++ if (urb->transfer_buffer != inbuf)
++ goto do_poll_rx;
++
++ /* check if previous frame was truncated
++ ** FIXME: this code can only handle truncation
++ ** of consecutive packets!
++ */
++ if (priv->rxtruncsize) {
++ int tail_size;
++
++ ptr = &priv->rxtruncbuf;
++ packetsize = RXBUF_BYTES_RCVD(ptr) + RXBUF_HDRSIZE;
++ if (acx_debug & L_USBRXTX) {
++ printk("handling truncated frame (truncsize=%d size=%d "
++ "packetsize(from trunc)=%d)\n",
++ priv->rxtruncsize, size, packetsize);
++ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
++ acx_dump_bytes(inbuf, RXBUF_HDRSIZE);
++ }
++
++ /* bytes needed for rxtruncbuf completion: */
++ tail_size = packetsize - priv->rxtruncsize;
++
++ if (size < tail_size) {
++ /* there is not enough data to complete this packet,
++ ** simply append the stuff to the truncation buffer
++ */
++ memcpy(((char *)ptr) + priv->rxtruncsize, inbuf, size);
++ priv->rxtruncsize += size;
++ remsize = 0;
++ } else {
++ /* ok, this data completes the previously
++ ** truncated packet. copy it into a descriptor
++ ** and give it to the rest of the stack */
++
++ /* append tail to previously truncated part
++ ** NB: priv->rxtruncbuf (pointed to by ptr) can't
++ ** overflow because this is already checked before
++ ** truncation buffer was filled. See below,
++ ** "if (packetsize > sizeof(rxbuffer_t))..." code */
++ memcpy(((char *)ptr) + priv->rxtruncsize, inbuf, tail_size);
++
++ if (acx_debug & L_USBRXTX) {
++ printk("full trailing packet + 12 bytes:\n");
++ acx_dump_bytes(inbuf, tail_size + RXBUF_HDRSIZE);
++ }
++ acx_l_process_rxbuf(priv, ptr);
++ priv->rxtruncsize = 0;
++ ptr = (rxbuffer_t *) (((char *)inbuf) + tail_size);
++ remsize -= tail_size;
++ }
++ acxlog(L_USBRXTX, "post-merge size=%d remsize=%d\n",
++ size, remsize);
++ }
++
++ /* size = USB data block size
++ ** remsize = unprocessed USB bytes left
++ ** ptr = current pos in USB data block
++ */
++ while (remsize) {
++ if (remsize < RXBUF_HDRSIZE) {
++ printk("acx: truncated rx header (%d bytes)!\n",
++ remsize);
++ break;
++ }
++ packetsize = RXBUF_BYTES_RCVD(ptr) + RXBUF_HDRSIZE;
++ acxlog(L_USBRXTX, "packet with packetsize=%d\n", packetsize);
++ if (packetsize > sizeof(rxbuffer_t)) {
++ printk("acx: packet exceeds max wlan "
++ "frame size (%d > %d). size=%d\n",
++ packetsize, (int) sizeof(rxbuffer_t), size);
++ /* FIXME: put some real error-handling in here! */
++ break;
++ }
++
++ /* skip null packets (does this really happen?!) */
++ if (packetsize == RXBUF_HDRSIZE) {
++ remsize -= RXBUF_HDRSIZE;
++ if (acx_debug & L_USBRXTX) {
++ printk("acx: null packet, new remsize=%d. "
++ "header follows:\n", remsize);
++ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
++ }
++ ptr = (rxbuffer_t *)(((char *)ptr) + RXBUF_HDRSIZE);
++ continue;
++ }
++
++ if (packetsize > remsize) {
++ /* frame truncation handling */
++ if (acx_debug & L_USBRXTX) {
++ printk("need to truncate packet, "
++ "packetsize=%d remsize=%d "
++ "size=%d\n",
++ packetsize, remsize, size);
++ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
++ }
++ memcpy(&priv->rxtruncbuf, ptr, remsize);
++ priv->rxtruncsize = remsize;
++ break;
++ } else { /* packetsize <= remsize */
++ /* now handle the received data */
++ acx_l_process_rxbuf(priv, ptr);
++
++ ptr = (rxbuffer_t *)(((char *)ptr) + packetsize);
++ remsize -= packetsize;
++ if ((acx_debug & L_USBRXTX) && remsize) {
++ printk("more than one packet in buffer, "
++ "second packet hdr follows\n");
++ acx_dump_bytes(ptr, RXBUF_HDRSIZE);
++ }
++ }
++ }
++
++do_poll_rx:
++ /* look for the next rx */
++ if (priv->dev_state_mask & ACX_STATE_IFACE_UP) {
++ /* receive of frame completed, now look for the next one */
++ acx100usb_l_poll_rx(priv, number);
++ }
++
++end_unlock:
++ acx_unlock(priv, flags);
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx100usb_i_complete_tx():
++** Inputs:
++** urb -> Pointer to USB request block
++** regs -> Pointer to register-buffer for syscalls (see asm/ptrace.h)
++************************************************************************
++** Description:
++** This function is invoked upon termination of a USB transfer. As the
++** USB device is only capable of sending a limited amount of bytes per
++** transfer to the bulk-out endpoint, this routine checks if there are
++** more bytes to send and triggers subsequent transfers. In case the
++** transfer size exactly matches the maximum bulk-out size, it triggers
++** a transfer of a null-frame, telling the card that this is it. Upon
++** completion of a frame, it checks whether the Tx ringbuffer contains
++** more data to send and invokes the Tx routines if this is the case.
++** If there are no more occupied Tx descriptors, the Tx Mutex is unlocked
++** and the network queue is switched back to life again.
++**
++** FIXME: unlike PCI code, we do not analyze tx rate used, retries, etc...
++** Thus we have no automatic rate control in USB!
++*/
++static void
++acx100usb_i_complete_tx(struct urb *urb, struct pt_regs *regs)
++{
++ wlandevice_t *priv;
++ usb_tx_t *tx;
++ unsigned long flags;
++
++ FN_ENTER;
++
++ if (!urb->context) {
++ printk(KERN_ERR "acx: error, NULL context in tx completion callback\n");
++ /* FIXME: real error-handling code must go here! */
++ goto end;
++ }
++
++ tx = (usb_tx_t *)urb->context;
++ priv = tx->priv;
++
++ acx_lock(priv, flags);
++
++ /* TODO: we maybe need to check whether urb was unlinked
++ ** (happens on disconnect and close, see there). How? */
++
++ acxlog(L_USBRXTX, "RETURN TX (%p): status=%d size=%d\n",
++ tx, urb->status, urb->actual_length);
++
++ /* handle USB transfer errors */
++ switch (urb->status) {
++ case 0: /* No error */
++ break;
++ case -ECONNRESET:
++ break;
++ /* FIXME: real error-handling code here please */
++ default:
++ printk(KERN_ERR "acx: tx error, urb status=%d\n", urb->status);
++ /* FIXME: real error-handling code here please */
++ }
++
++ /* free the URB and check for more data */
++ priv->tx_free++;
++ tx->busy = 0;
++
++/* end_unlock: */
++ acx_unlock(priv, flags);
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++** acx100usb_e_close():
++**
++** This function stops the network functionality of the interface (invoked
++** when the user calls ifconfig <wlan> down). The tx queue is halted and
++** the device is marked as down. In case there were any pending USB bulk
++** transfers, these are unlinked (asynchronously). The module in-use count
++** is also decreased in this function.
++*/
++static int
++acx100usb_e_close(struct net_device *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ int i;
++
++ FN_ENTER;
++
++#if WE_STILL_DONT_CARE_ABOUT_IT
++ /* Transmit a disassociate frame */
++ lock
++ acx_l_transmit_disassoc(priv, &client);
++ unlock
++#endif
++
++ /*
++ * We get the sem *after* FLUSH to avoid a deadlock.
++ * See pci.c:acx_s_down() for deails.
++ */
++ FLUSH_SCHEDULED_WORK();
++ acx_sem_lock(priv);
++
++ /* stop the transmit queue, mark the device as DOWN */
++ acx_lock(priv, flags);
++ acx_stop_queue(dev, "on iface stop");
++ CLEAR_BIT(priv->dev_state_mask, ACX_STATE_IFACE_UP);
++
++ /* I wonder if above is enough to prevent tx/rx callbacks
++ ** to start queue again? Like this:
++ ** complete_rx -> acx_l_process_rxbuf -> associated -> acx_start_queue()
++ ** Oh well... */
++
++ /* stop pending rx/tx urb transfers */
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ acx_unlink_and_free_urb(priv->bulkrx_urbs[i]);
++ acx_unlink_and_free_urb(priv->usb_tx[i].urb);
++ }
++ acx_unlock(priv, flags);
++
++ /* disable rx and tx */
++ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_TX, NULL, 0);
++ acx_s_issue_cmd(priv, ACX1xx_CMD_DISABLE_RX, NULL, 0);
++
++ /* power down the device */
++ acx_s_issue_cmd(priv, ACX1xx_CMD_SLEEP, NULL, 0);
++
++ acx_sem_unlock(priv);
++
++ /* decrease module-in-use count (if necessary) */
++
++ WLAN_MOD_DEC_USE_COUNT;
++
++ FN_EXIT0;
++ return 0;
++}
++
++
++/***************************************************************
++** acxusb_l_alloc_tx
++** Actually returns a usb_tx_t* ptr
++*/
++tx_t*
++acxusb_l_alloc_tx(wlandevice_t* priv)
++{
++ int i;
++ usb_tx_t *tx = NULL;
++
++ FN_ENTER;
++
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ if (!priv->usb_tx[i].busy) {
++ tx = &priv->usb_tx[i];
++ tx->busy = 1;
++ break;
++ }
++ }
++ if (i >= ACX100_USB_NUM_BULK_URBS) {
++ printk("acx: tx buffers full\n");
++ }
++
++ FN_EXIT0;
++
++ return (tx_t*)tx;
++}
++
++
++/***************************************************************
++*/
++void*
++acxusb_l_get_txbuf(wlandevice_t *priv, tx_t* tx_opaque)
++{
++ usb_tx_t* tx = (usb_tx_t*)tx_opaque;
++ return &tx->bulkout.data;
++}
++
++
++/***************************************************************
++** acxusb_l_tx_data
++**
++** Can be called from IRQ (rx -> (AP bridging or mgmt response) -> tx).
++** Can be called from acx_i_start_xmit (data frames from net core).
++*/
++void
++acxusb_l_tx_data(wlandevice_t *priv, tx_t* tx_opaque, int wlanpkt_len)
++{
++ struct usb_device *usbdev;
++ struct urb* txurb;
++ usb_tx_t* tx;
++ usb_txbuffer_t* txbuf;
++ client_t *clt;
++ wlan_hdr_t* whdr;
++ unsigned int outpipe;
++ int ucode;
++ u8 rate100;
++
++ FN_ENTER;
++
++ tx = ((usb_tx_t *)tx_opaque);
++ txurb = tx->urb;
++ txbuf = &tx->bulkout;
++ whdr = (wlan_hdr_t *)txbuf->data;
++
++ priv->tx_free--;
++ acxlog(L_DEBUG, "using buf#%d free=%d len=%d\n",
++ (int)(tx - priv->usb_tx),
++ priv->tx_free, wlanpkt_len);
++
++ switch (priv->mode) {
++ case ACX_MODE_0_ADHOC:
++ case ACX_MODE_3_AP:
++ clt = acx_l_sta_list_get(priv, whdr->a1);
++ break;
++ case ACX_MODE_2_STA:
++ clt = priv->ap_client;
++ break;
++ default: /* ACX_MODE_OFF, ACX_MODE_MONITOR */
++ clt = NULL;
++ break;
++ }
++
++ if (unlikely(clt && !clt->rate_cur)) {
++ printk("acx: driver bug! bad ratemask\n");
++ goto end;
++ }
++
++ /* used in tx cleanup routine for auto rate and accounting: */
++//TODO: currently unused - fix that
++ tx->txc = clt;
++
++ rate100 = clt ? clt->rate_100 : priv->rate_bcast100;
++
++ /* fill the USB transfer header */
++ txbuf->desc = cpu_to_le16(USB_TXBUF_TXDESC);
++ txbuf->MPDUlen = cpu_to_le16(wlanpkt_len);
++ txbuf->ctrl1 = 0;
++ txbuf->ctrl2 = 0;
++ txbuf->hostData = cpu_to_le32(wlanpkt_len | (rate100 << 24));
++ if (1 == priv->preamble_cur)
++ SET_BIT(txbuf->ctrl1, DESC_CTL_SHORT_PREAMBLE);
++ SET_BIT(txbuf->ctrl1, DESC_CTL_FIRSTFRAG);
++ txbuf->txRate = rate100;
++ txbuf->index = 1;
++ txbuf->dataLength = cpu_to_le16(wlanpkt_len);
++
++ if ( (WF_FC_FTYPEi & whdr->fc) == WF_FTYPE_DATAi )
++ SET_BIT(txbuf->hostData, cpu_to_le32(USB_TXBUF_HD_ISDATA));
++ if (mac_is_directed(whdr->a1))
++ SET_BIT(txbuf->hostData, cpu_to_le32(USB_TXBUF_HD_DIRECTED));
++ else if (mac_is_bcast(whdr->a1))
++ SET_BIT(txbuf->hostData, cpu_to_le32(USB_TXBUF_HD_BROADCAST));
++
++ if (acx_debug & L_DATA) {
++ printk("dump of bulk out urb:\n");
++ acx_dump_bytes(txbuf, wlanpkt_len + USB_TXBUF_HDRSIZE);
++ }
++
++ if (txurb->status == -EINPROGRESS) {
++ printk("acx: trying to submit tx urb while already in progress\n");
++ }
++
++ /* now schedule the USB transfer */
++ usbdev = priv->usbdev;
++ outpipe = usb_sndbulkpipe(usbdev, priv->bulkoutep);
++//can be removed, please try & test:
++ tx->priv = priv;
++
++ usb_fill_bulk_urb(txurb, usbdev, outpipe,
++ txbuf, /* dataptr */
++ wlanpkt_len + USB_TXBUF_HDRSIZE, /* size */
++ acx100usb_i_complete_tx, /* handler */
++ tx /* handler param */
++ );
++
++ txurb->transfer_flags = QUEUE_BULK|ZERO_PACKET;
++ ucode = submit_urb(txurb, GFP_ATOMIC);
++ acxlog(L_USBRXTX, "SUBMIT TX (%p): outpipe=0x%X buf=%p txsize=%d "
++ "errcode=%d\n", tx, outpipe, txbuf,
++ wlanpkt_len + USB_TXBUF_HDRSIZE, ucode);
++
++ if (ucode) {
++ printk(KERN_ERR "acx: submit_urb() error=%d txsize=%d\n",
++ ucode, wlanpkt_len + USB_TXBUF_HDRSIZE);
++
++ /* on error, just mark the frame as done and update
++ ** the statistics
++ */
++ priv->stats.tx_errors++;
++ tx->busy = 0;
++ priv->tx_free++;
++ }
++end:
++ FN_EXIT0;
++}
++
++
++/***********************************************************************
++*/
++static struct net_device_stats*
++acx_e_get_stats(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ return &priv->stats;
++}
++
++
++/***********************************************************************
++*/
++static struct iw_statistics*
++acx_e_get_wireless_stats(netdevice_t *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ FN_ENTER;
++ FN_EXIT0;
++ return &priv->wstats;
++}
++
++
++/***********************************************************************
++*/
++static void
++acx100usb_i_set_rx_mode(struct net_device *dev)
++{
++}
++
++
++/***********************************************************************
++*/
++#ifdef HAVE_TX_TIMEOUT
++static void
++acx100usb_i_tx_timeout(struct net_device *dev)
++{
++ wlandevice_t *priv = netdev_priv(dev);
++ unsigned long flags;
++ int i;
++
++ FN_ENTER;
++
++ acx_lock(priv, flags);
++ /* unlink the URBs */
++ for (i = 0; i < ACX100_USB_NUM_BULK_URBS; i++) {
++ if (priv->usb_tx[i].urb->status == -EINPROGRESS)
++ usb_unlink_urb(priv->usb_tx[i].urb);
++ }
++ /* TODO: stats update */
++ acx_unlock(priv, flags);
++
++ FN_EXIT0;
++}
++#endif
++
++
++/***********************************************************************
++** init_module():
++**
++** This function is invoked upon loading of the kernel module.
++** It registers itself at the kernel's USB subsystem.
++**
++** Returns: Errorcode on failure, 0 on success
++*/
++int __init
++acxusb_e_init_module(void)
++{
++ acxlog(L_INIT, "USB module " WLAN_RELEASE " initialized, "
++ "probing for devices...\n");
++ return usb_register(&acx100usb_driver);
++}
++
++
++
++/***********************************************************************
++** cleanup_module():
++**
++** This function is invoked as last step of the module unloading. It simply
++** deregisters this module at the kernel's USB subsystem.
++*/
++void __exit
++acxusb_e_cleanup_module()
++{
++ usb_deregister(&acx100usb_driver);
++}
++
++
++/***********************************************************************
++** DEBUG STUFF
++*/
++#if ACX_DEBUG
++
++#ifdef UNUSED
++static void
++dump_device(struct usb_device *usbdev)
++{
++ int i;
++ struct usb_config_descriptor *cd;
++
++ printk("acx device dump:\n");
++ printk(" devnum: %d\n", usbdev->devnum);
++ printk(" speed: %d\n", usbdev->speed);
++ printk(" tt: 0x%X\n", (unsigned int)(usbdev->tt));
++ printk(" ttport: %d\n", (unsigned int)(usbdev->ttport));
++ printk(" toggle[0]: 0x%X toggle[1]: 0x%X\n", (unsigned int)(usbdev->toggle[0]), (unsigned int)(usbdev->toggle[1]));
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
++ /* halted removed in 2.6.9-rc1 */
++ /* DOH, Canbreak... err... Mandrake decided to do their very own very
++ * special version "2.6.8.1" which already includes this change, so we
++ * need to blacklist that version already (i.e. 2.6.8) */
++ printk(" halted[0]: 0x%X halted[1]: 0x%X\n", usbdev->halted[0], usbdev->halted[1]);
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
++ /* This saw a change after 2.6.10 */
++ printk(" ep_in wMaxPacketSize: ");
++ for (i = 0; i < 16; ++i)
++ printk("%d ", usbdev->ep_in[i]->desc.wMaxPacketSize);
++ printk("\n");
++ printk(" ep_out wMaxPacketSize: ");
++ for (i = 0; i < 15; ++i)
++ printk("%d ", usbdev->ep_out[i]->desc.wMaxPacketSize);
++ printk("\n");
++#else
++ printk(" epmaxpacketin: ");
++ for (i = 0; i < 16; i++)
++ printk("%d ", usbdev->epmaxpacketin[i]);
++ printk("\n");
++ printk(" epmaxpacketout: ");
++ for (i = 0; i < 16; i++)
++ printk("%d ", usbdev->epmaxpacketout[i]);
++ printk("\n");
++#endif
++ printk(" parent: 0x%X\n", (unsigned int)usbdev->parent);
++ printk(" bus: 0x%X\n", (unsigned int)usbdev->bus);
++#if NO_DATATYPE
++ printk(" configs: ");
++ for (i = 0; i < usbdev->descriptor.bNumConfigurations; i++)
++ printk("0x%X ", usbdev->config[i]);
++ printk("\n");
++#endif
++ printk(" actconfig: %p\n", usbdev->actconfig);
++ dump_device_descriptor(&usbdev->descriptor);
++
++ cd = &usbdev->config->desc;
++ dump_config_descriptor(cd);
++}
++
++
++/***********************************************************************
++*/
++static void
++dump_config_descriptor(struct usb_config_descriptor *cd)
++{
++ printk("Configuration Descriptor:\n");
++ if (!cd) {
++ printk("NULL\n");
++ return;
++ }
++ printk(" bLength: %d (0x%X)\n", cd->bLength, cd->bLength);
++ printk(" bDescriptorType: %d (0x%X)\n", cd->bDescriptorType, cd->bDescriptorType);
++ printk(" bNumInterfaces: %d (0x%X)\n", cd->bNumInterfaces, cd->bNumInterfaces);
++ printk(" bConfigurationValue: %d (0x%X)\n", cd->bConfigurationValue, cd->bConfigurationValue);
++ printk(" iConfiguration: %d (0x%X)\n", cd->iConfiguration, cd->iConfiguration);
++ printk(" bmAttributes: %d (0x%X)\n", cd->bmAttributes, cd->bmAttributes);
++ /* printk(" MaxPower: %d (0x%X)\n", cd->bMaxPower, cd->bMaxPower); */
++}
++
++
++static void
++dump_device_descriptor(struct usb_device_descriptor *dd)
++{
++ printk("Device Descriptor:\n");
++ if (!dd) {
++ printk("NULL\n");
++ return;
++ }
++ printk(" bLength: %d (0x%X)\n", dd->bLength, dd->bLength);
++ printk(" bDescriptortype: %d (0x%X)\n", dd->bDescriptorType, dd->bDescriptorType);
++ printk(" bcdUSB: %d (0x%X)\n", dd->bcdUSB, dd->bcdUSB);
++ printk(" bDeviceClass: %d (0x%X)\n", dd->bDeviceClass, dd->bDeviceClass);
++ printk(" bDeviceSubClass: %d (0x%X)\n", dd->bDeviceSubClass, dd->bDeviceSubClass);
++ printk(" bDeviceProtocol: %d (0x%X)\n", dd->bDeviceProtocol, dd->bDeviceProtocol);
++ printk(" bMaxPacketSize0: %d (0x%X)\n", dd->bMaxPacketSize0, dd->bMaxPacketSize0);
++ printk(" idVendor: %d (0x%X)\n", dd->idVendor, dd->idVendor);
++ printk(" idProduct: %d (0x%X)\n", dd->idProduct, dd->idProduct);
++ printk(" bcdDevice: %d (0x%X)\n", dd->bcdDevice, dd->bcdDevice);
++ printk(" iManufacturer: %d (0x%X)\n", dd->iManufacturer, dd->iManufacturer);
++ printk(" iProduct: %d (0x%X)\n", dd->iProduct, dd->iProduct);
++ printk(" iSerialNumber: %d (0x%X)\n", dd->iSerialNumber, dd->iSerialNumber);
++ printk(" bNumConfigurations: %d (0x%X)\n", dd->bNumConfigurations, dd->bNumConfigurations);
++}
++#endif /* UNUSED */
++
++#endif /* ACX_DEBUG */
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan.c linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan.c
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan.c 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,392 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++/***********************************************************************
++** This code is based on elements which are
++** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
++** info@linux-wlan.com
++** http://www.linux-wlan.com
++*/
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/types.h>
++#include <linux/if_arp.h>
++#include <linux/wireless.h>
++#if WIRELESS_EXT >= 13
++#include <net/iw_handler.h>
++#endif
++
++#include "acx.h"
++
++
++/***********************************************************************
++*/
++#define LOG_BAD_EID(hdr,len,ie_ptr) acx_log_bad_eid(hdr, len, ((wlan_ie_t*)ie_ptr))
++
++#define IE_EID(ie_ptr) (((wlan_ie_t*)(ie_ptr))->eid)
++#define IE_LEN(ie_ptr) (((wlan_ie_t*)(ie_ptr))->len)
++#define OFFSET(hdr,off) (WLAN_HDR_A3_DATAP(hdr) + (off))
++
++
++/***********************************************************************
++** wlan_mgmt_decode_XXX
++**
++** Given a complete frame in f->hdr, sets the pointers in f to
++** the areas that correspond to the parts of the frame.
++**
++** Assumptions:
++** 1) f->len and f->hdr are already set
++** 2) f->len is the length of the MAC header + data, the FCS
++** is NOT included
++** 3) all members except len and hdr are zero
++** Arguments:
++** f frame structure
++**
++** Returns:
++** nothing
++**
++** Side effects:
++** frame structure members are pointing at their
++** respective portions of the frame buffer.
++*/
++void
++wlan_mgmt_decode_beacon(wlan_fr_beacon_t * f)
++{
++ u8 *ie_ptr;
++ u8 *end = (u8*)f->hdr + f->len;
++
++ f->type = WLAN_FSTYPE_BEACON;
++
++ /*-- Fixed Fields ----*/
++ f->ts = (u64 *) OFFSET(f->hdr, WLAN_BEACON_OFF_TS);
++ f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_BCN_INT);
++ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_BEACON_OFF_CAPINFO);
++
++ /*-- Information elements */
++ ie_ptr = OFFSET(f->hdr, WLAN_BEACON_OFF_SSID);
++ while (ie_ptr < end) {
++ switch (IE_EID(ie_ptr)) {
++ case WLAN_EID_SSID:
++ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
++ break;
++ case WLAN_EID_SUPP_RATES:
++ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ case WLAN_EID_EXT_RATES:
++ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ case WLAN_EID_FH_PARMS:
++ f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr;
++ break;
++ case WLAN_EID_DS_PARMS:
++ f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr;
++ break;
++ case WLAN_EID_CF_PARMS:
++ f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr;
++ break;
++ case WLAN_EID_IBSS_PARMS:
++ f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr;
++ break;
++ case WLAN_EID_TIM:
++ f->tim = (wlan_ie_tim_t *) ie_ptr;
++ break;
++ case WLAN_EID_ERP_INFO:
++ f->erp = (wlan_ie_erp_t *) ie_ptr;
++ break;
++ case WLAN_EID_COUNTRY:
++ /* was seen: 07 06 47 42 20 01 0D 14 */
++ case WLAN_EID_NONERP:
++ /* was seen from WRT54GS with OpenWrt: 2F 01 07 */
++ case WLAN_EID_GENERIC:
++ /* WPA: hostap code:
++ if (pos[1] >= 4 &&
++ pos[2] == 0x00 && pos[3] == 0x50 &&
++ pos[4] == 0xf2 && pos[5] == 1) {
++ wpa = pos;
++ wpa_len = pos[1] + 2;
++ }
++ TI x4 mode: seen DD 04 08 00 28 00
++ (08 00 28 is TI's OUI)
++ last byte is probably 0/1 - disabled/enabled
++ */
++ case WLAN_EID_RSN:
++ /* hostap does something with it:
++ rsn = pos;
++ rsn_len = pos[1] + 2;
++ */
++ break;
++ default:
++ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
++ break;
++ }
++ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
++ }
++}
++
++
++#ifdef UNUSED
++void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t * f)
++{
++ f->type = WLAN_FSTYPE_ATIM;
++ /*-- Fixed Fields ----*/
++ /*-- Information elements */
++}
++#endif /* UNUSED */
++
++void
++wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t * f)
++{
++ f->type = WLAN_FSTYPE_DISASSOC;
++
++ /*-- Fixed Fields ----*/
++ f->reason = (u16 *) OFFSET(f->hdr, WLAN_DISASSOC_OFF_REASON);
++
++ /*-- Information elements */
++}
++
++
++void
++wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t * f)
++{
++ u8 *ie_ptr;
++ u8 *end = (u8*)f->hdr + f->len;
++
++
++ f->type = WLAN_FSTYPE_ASSOCREQ;
++
++ /*-- Fixed Fields ----*/
++ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_CAP_INFO);
++ f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_LISTEN_INT);
++
++ /*-- Information elements */
++ ie_ptr = OFFSET(f->hdr, WLAN_ASSOCREQ_OFF_SSID);
++ while (ie_ptr < end) {
++ switch (IE_EID(ie_ptr)) {
++ case WLAN_EID_SSID:
++ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
++ break;
++ case WLAN_EID_SUPP_RATES:
++ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ case WLAN_EID_EXT_RATES:
++ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ default:
++ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
++ break;
++ }
++ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
++ }
++}
++
++
++void
++wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t * f)
++{
++ f->type = WLAN_FSTYPE_ASSOCRESP;
++
++ /*-- Fixed Fields ----*/
++ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_CAP_INFO);
++ f->status = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_STATUS);
++ f->aid = (u16 *) OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_AID);
++
++ /*-- Information elements */
++ f->supp_rates = (wlan_ie_supp_rates_t *)
++ OFFSET(f->hdr, WLAN_ASSOCRESP_OFF_SUPP_RATES);
++}
++
++
++void
++wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t * f)
++{
++ u8 *ie_ptr;
++ u8 *end = (u8*)f->hdr + f->len;
++
++ f->type = WLAN_FSTYPE_REASSOCREQ;
++
++ /*-- Fixed Fields ----*/
++ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CAP_INFO);
++ f->listen_int = (u16 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_LISTEN_INT);
++ f->curr_ap = (u8 *) OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_CURR_AP);
++
++ /*-- Information elements */
++ ie_ptr = OFFSET(f->hdr, WLAN_REASSOCREQ_OFF_SSID);
++ while (ie_ptr < end) {
++ switch (IE_EID(ie_ptr)) {
++ case WLAN_EID_SSID:
++ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
++ break;
++ case WLAN_EID_SUPP_RATES:
++ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ case WLAN_EID_EXT_RATES:
++ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ default:
++ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
++ break;
++ }
++ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
++ }
++}
++
++
++void
++wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t * f)
++{
++ f->type = WLAN_FSTYPE_REASSOCRESP;
++
++ /*-- Fixed Fields ----*/
++ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_CAP_INFO);
++ f->status = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_STATUS);
++ f->aid = (u16 *) OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_AID);
++
++ /*-- Information elements */
++ f->supp_rates = (wlan_ie_supp_rates_t *)
++ OFFSET(f->hdr, WLAN_REASSOCRESP_OFF_SUPP_RATES);
++}
++
++
++void
++wlan_mgmt_decode_probereq(wlan_fr_probereq_t * f)
++{
++ u8 *ie_ptr;
++ u8 *end = (u8*)f->hdr + f->len;
++
++ f->type = WLAN_FSTYPE_PROBEREQ;
++
++ /*-- Fixed Fields ----*/
++
++ /*-- Information elements */
++ ie_ptr = OFFSET(f->hdr, WLAN_PROBEREQ_OFF_SSID);
++ while (ie_ptr < end) {
++ switch (IE_EID(ie_ptr)) {
++ case WLAN_EID_SSID:
++ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
++ break;
++ case WLAN_EID_SUPP_RATES:
++ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ case WLAN_EID_EXT_RATES:
++ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ default:
++ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
++ break;
++ }
++ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
++ }
++}
++
++
++/* TODO: decoding of beacon and proberesp can be merged (similar structure) */
++void
++wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t * f)
++{
++ u8 *ie_ptr;
++ u8 *end = (u8*)f->hdr + f->len;
++
++ f->type = WLAN_FSTYPE_PROBERESP;
++
++ /*-- Fixed Fields ----*/
++ f->ts = (u64 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_TS);
++ f->bcn_int = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_BCN_INT);
++ f->cap_info = (u16 *) OFFSET(f->hdr, WLAN_PROBERESP_OFF_CAP_INFO);
++
++ /*-- Information elements */
++ ie_ptr = OFFSET(f->hdr, WLAN_PROBERESP_OFF_SSID);
++ while (ie_ptr < end) {
++ switch (IE_EID(ie_ptr)) {
++ case WLAN_EID_SSID:
++ f->ssid = (wlan_ie_ssid_t *) ie_ptr;
++ break;
++ case WLAN_EID_SUPP_RATES:
++ f->supp_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ case WLAN_EID_EXT_RATES:
++ f->ext_rates = (wlan_ie_supp_rates_t *) ie_ptr;
++ break;
++ case WLAN_EID_FH_PARMS:
++ f->fh_parms = (wlan_ie_fh_parms_t *) ie_ptr;
++ break;
++ case WLAN_EID_DS_PARMS:
++ f->ds_parms = (wlan_ie_ds_parms_t *) ie_ptr;
++ break;
++ case WLAN_EID_CF_PARMS:
++ f->cf_parms = (wlan_ie_cf_parms_t *) ie_ptr;
++ break;
++ case WLAN_EID_IBSS_PARMS:
++ f->ibss_parms = (wlan_ie_ibss_parms_t *) ie_ptr;
++ break;
++ default:
++ LOG_BAD_EID(f->hdr, f->len, ie_ptr);
++ break;
++ }
++
++ ie_ptr = ie_ptr + 2 + IE_LEN(ie_ptr);
++ }
++}
++
++
++void
++wlan_mgmt_decode_authen(wlan_fr_authen_t * f)
++{
++ u8 *ie_ptr;
++ u8 *end = (u8*)f->hdr + f->len;
++
++ f->type = WLAN_FSTYPE_AUTHEN;
++
++ /*-- Fixed Fields ----*/
++ f->auth_alg = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_ALG);
++ f->auth_seq = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_AUTH_SEQ);
++ f->status = (u16 *) OFFSET(f->hdr, WLAN_AUTHEN_OFF_STATUS);
++
++ /*-- Information elements */
++ ie_ptr = OFFSET(f->hdr, WLAN_AUTHEN_OFF_CHALLENGE);
++ if ((ie_ptr < end) && (IE_EID(ie_ptr) == WLAN_EID_CHALLENGE)) {
++ f->challenge = (wlan_ie_challenge_t *) ie_ptr;
++ }
++}
++
++
++void
++wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t * f)
++{
++ f->type = WLAN_FSTYPE_DEAUTHEN;
++
++ /*-- Fixed Fields ----*/
++ f->reason = (u16 *) OFFSET(f->hdr, WLAN_DEAUTHEN_OFF_REASON);
++
++ /*-- Information elements */
++}
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan_compat.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan_compat.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan_compat.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan_compat.h 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,297 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++/***********************************************************************
++** This code is based on elements which are
++** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
++** info@linux-wlan.com
++** http://www.linux-wlan.com
++*/
++
++/*=============================================================*/
++/*------ Establish Platform Identity --------------------------*/
++/*=============================================================*/
++/* Key macros: */
++/* WLAN_CPU_FAMILY */
++#define WLAN_Ix86 1
++#define WLAN_PPC 2
++#define WLAN_Ix96 3
++#define WLAN_ARM 4
++#define WLAN_ALPHA 5
++#define WLAN_MIPS 6
++#define WLAN_HPPA 7
++#define WLAN_SPARC 8
++#define WLAN_SH 9
++#define WLAN_x86_64 10
++/* WLAN_CPU_CORE */
++#define WLAN_I386CORE 1
++#define WLAN_PPCCORE 2
++#define WLAN_I296 3
++#define WLAN_ARMCORE 4
++#define WLAN_ALPHACORE 5
++#define WLAN_MIPSCORE 6
++#define WLAN_HPPACORE 7
++/* WLAN_CPU_PART */
++#define WLAN_I386PART 1
++#define WLAN_MPC860 2
++#define WLAN_MPC823 3
++#define WLAN_I296SA 4
++#define WLAN_PPCPART 5
++#define WLAN_ARMPART 6
++#define WLAN_ALPHAPART 7
++#define WLAN_MIPSPART 8
++#define WLAN_HPPAPART 9
++/* WLAN_SYSARCH */
++#define WLAN_PCAT 1
++#define WLAN_MBX 2
++#define WLAN_RPX 3
++#define WLAN_LWARCH 4
++#define WLAN_PMAC 5
++#define WLAN_SKIFF 6
++#define WLAN_BITSY 7
++#define WLAN_ALPHAARCH 7
++#define WLAN_MIPSARCH 9
++#define WLAN_HPPAARCH 10
++/* WLAN_HOSTIF (generally set on the command line, not detected) */
++#define WLAN_PCMCIA 1
++#define WLAN_ISA 2
++#define WLAN_PCI 3
++#define WLAN_USB 4
++#define WLAN_PLX 5
++
++/* Note: the PLX HOSTIF above refers to some vendors implementations for */
++/* PCI. It's a PLX chip that is a PCI to PCMCIA adapter, but it */
++/* isn't a real PCMCIA host interface adapter providing all the */
++/* card&socket services. */
++
++#ifdef __powerpc__
++#ifndef __ppc__
++#define __ppc__
++#endif
++#endif
++
++#if (defined(CONFIG_PPC) || defined(CONFIG_8xx))
++#ifndef __ppc__
++#define __ppc__
++#endif
++#endif
++
++#if defined(__x86_64__)
++ #define WLAN_CPU_FAMILY WLAN_x86_64
++ #define WLAN_SYSARCH WLAN_PCAT
++#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
++ #define WLAN_CPU_FAMILY WLAN_Ix86
++ #define WLAN_CPU_CORE WLAN_I386CORE
++ #define WLAN_CPU_PART WLAN_I386PART
++ #define WLAN_SYSARCH WLAN_PCAT
++#elif defined(__ppc__)
++ #define WLAN_CPU_FAMILY WLAN_PPC
++ #define WLAN_CPU_CORE WLAN_PPCCORE
++ #if defined(CONFIG_MBX)
++ #define WLAN_CPU_PART WLAN_MPC860
++ #define WLAN_SYSARCH WLAN_MBX
++ #elif defined(CONFIG_RPXLITE)
++ #define WLAN_CPU_PART WLAN_MPC823
++ #define WLAN_SYSARCH WLAN_RPX
++ #elif defined(CONFIG_RPXCLASSIC)
++ #define WLAN_CPU_PART WLAN_MPC860
++ #define WLAN_SYSARCH WLAN_RPX
++ #else
++ #define WLAN_CPU_PART WLAN_PPCPART
++ #define WLAN_SYSARCH WLAN_PMAC
++ #endif
++#elif defined(__arm__)
++ #define WLAN_CPU_FAMILY WLAN_ARM
++ #define WLAN_CPU_CORE WLAN_ARMCORE
++ #define WLAN_CPU_PART WLAN_ARM_PART
++ #define WLAN_SYSARCH WLAN_SKIFF
++#elif defined(__alpha__)
++ #define WLAN_CPU_FAMILY WLAN_ALPHA
++ #define WLAN_CPU_CORE WLAN_ALPHACORE
++ #define WLAN_CPU_PART WLAN_ALPHAPART
++ #define WLAN_SYSARCH WLAN_ALPHAARCH
++#elif defined(__mips__)
++ #define WLAN_CPU_FAMILY WLAN_MIPS
++ #define WLAN_CPU_CORE WLAN_MIPSCORE
++ #define WLAN_CPU_PART WLAN_MIPSPART
++ #define WLAN_SYSARCH WLAN_MIPSARCH
++#elif defined(__hppa__)
++ #define WLAN_CPU_FAMILY WLAN_HPPA
++ #define WLAN_CPU_CORE WLAN_HPPACORE
++ #define WLAN_CPU_PART WLAN_HPPAPART
++ #define WLAN_SYSARCH WLAN_HPPAARCH
++#elif defined(__sparc__)
++ #define WLAN_CPU_FAMILY WLAN_SPARC
++ #define WLAN_SYSARCH WLAN_SPARC
++#elif defined(__sh__)
++ #define WLAN_CPU_FAMILY WLAN_SH
++ #define WLAN_SYSARCH WLAN_SHARCH
++ #ifndef __LITTLE_ENDIAN__
++ #define __LITTLE_ENDIAN__
++ #endif
++#else
++ #error "No CPU identified!"
++#endif
++
++/*
++ Some big endian machines implicitly do all I/O in little endian mode.
++
++ In particular:
++ Linux/PPC on PowerMacs (PCI)
++ Arm/Intel Xscale (PCI)
++
++ This may also affect PLX boards and other BE &| PPC platforms;
++ as new ones are discovered, add them below.
++*/
++
++#if ((WLAN_SYSARCH == WLAN_SKIFF) || (WLAN_SYSARCH == WLAN_PMAC))
++#define REVERSE_ENDIAN
++#endif
++
++/*=============================================================*/
++/*------ Hardware Portability Macros --------------------------*/
++/*=============================================================*/
++#if (WLAN_CPU_FAMILY == WLAN_PPC)
++#define wlan_inw(a) in_be16((unsigned short *)((a)+_IO_BASE))
++#define wlan_inw_le16_to_cpu(a) inw((a))
++#define wlan_outw(v,a) out_be16((unsigned short *)((a)+_IO_BASE), (v))
++#define wlan_outw_cpu_to_le16(v,a) outw((v),(a))
++#else
++#define wlan_inw(a) inw((a))
++#define wlan_inw_le16_to_cpu(a) __cpu_to_le16(inw((a)))
++#define wlan_outw(v,a) outw((v),(a))
++#define wlan_outw_cpu_to_le16(v,a) outw(__cpu_to_le16((v)),(a))
++#endif
++
++/*=============================================================*/
++/*------ Bit settings -----------------------------------------*/
++/*=============================================================*/
++#define ieee2host16(n) __le16_to_cpu(n)
++#define ieee2host32(n) __le32_to_cpu(n)
++#define host2ieee16(n) __cpu_to_le16(n)
++#define host2ieee32(n) __cpu_to_le32(n)
++
++/* for constants */
++#ifdef __LITTLE_ENDIAN
++ #define IEEE16(a,n) a = n, a##i = n,
++#else
++ #ifdef __BIG_ENDIAN
++ /* shifts would produce gcc warnings. Oh well... */
++ #define IEEE16(a,n) a = n, a##i = ((n&0xff)*256 + ((n&0xff00)/256)),
++ #else
++ #error give me endianness or give me death
++ #endif
++#endif
++
++/*=============================================================*/
++/*------ Compiler Portability Macros --------------------------*/
++/*=============================================================*/
++#define __WLAN_ATTRIB_PACK__ __attribute__ ((packed))
++#define __WLAN_PRAGMA_PACK1__
++#define __WLAN_PRAGMA_PACKDFLT__
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38))
++ typedef struct device netdevice_t;
++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4))
++ typedef struct net_device netdevice_t;
++#else
++ #undef netdevice_t
++ typedef struct net_device netdevice_t;
++#endif
++
++#ifdef WIRELESS_EXT
++#if (WIRELESS_EXT < 13)
++struct iw_request_info {
++ __u16 cmd; /* Wireless Extension command */
++ __u16 flags; /* More to come ;-) */
++};
++#endif
++#endif
++
++/* Interrupt handler backwards compatibility stuff */
++#ifndef IRQ_NONE
++#define IRQ_NONE
++#define IRQ_HANDLED
++typedef void irqreturn_t;
++#endif
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) /* more or less */
++#define WLAN_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
++#define WLAN_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
++#else
++#define WLAN_MOD_INC_USE_COUNT
++#define WLAN_MOD_DEC_USE_COUNT
++#endif
++
++#ifndef ARPHRD_IEEE80211_PRISM
++#define ARPHRD_IEEE80211_PRISM 802
++#endif
++
++#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
++
++/*============================================================================*
++ * Constants *
++ *============================================================================*/
++#define WLAN_IEEE_OUI_LEN 3
++/* unused
++#define WLAN_ETHHDR_LEN 14
++#define WLAN_ETHCONV_ENCAP 1
++#define WLAN_ETHCONV_RFC1042 2
++#define WLAN_ETHCONV_8021h 3
++#define WLAN_MIN_ETHFRM_LEN 60
++#define WLAN_MAX_ETHFRM_LEN 1514
++*/
++
++/*============================================================================*
++ * Types *
++ *============================================================================*/
++
++/* local ether header type */
++typedef struct wlan_ethhdr {
++ u8 daddr[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 saddr[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 type __WLAN_ATTRIB_PACK__;
++} wlan_ethhdr_t;
++
++/* local llc header type */
++typedef struct wlan_llc {
++ u8 dsap __WLAN_ATTRIB_PACK__;
++ u8 ssap __WLAN_ATTRIB_PACK__;
++ u8 ctl __WLAN_ATTRIB_PACK__;
++} wlan_llc_t;
++
++/* local snap header type */
++typedef struct wlan_snap {
++ u8 oui[WLAN_IEEE_OUI_LEN] __WLAN_ATTRIB_PACK__;
++ u16 type __WLAN_ATTRIB_PACK__;
++} wlan_snap_t;
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan_hdr.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan_hdr.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan_hdr.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan_hdr.h 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,497 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++/***********************************************************************
++** This code is based on elements which are
++** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
++** info@linux-wlan.com
++** http://www.linux-wlan.com
++*/
++
++/* mini-doc
++
++Here are all 11b/11g/11a rates and modulations:
++
++ 11b 11g 11a
++ --- --- ---
++ 1 |B |B |
++ 2 |Q |Q |
++ 5.5|Cp |C p|
++ 6 | |Od |O
++ 9 | |od |o
++11 |Cp |C p|
++12 | |Od |O
++18 | |od |o
++22 | | p|
++24 | |Od |O
++33 | | p|
++36 | |od |o
++48 | |od |o
++54 | |od |o
++
++Mandatory:
++ B - DBPSK (Differential Binary Phase Shift Keying)
++ Q - DQPSK (Differential Quaternary Phase Shift Keying)
++ C - CCK (Complementary Code Keying, a form of DSSS
++ (Direct Sequence Spread Spectrum) modulation)
++ O - OFDM (Orthogonal Frequency Division Multiplexing)
++Optional:
++ o - OFDM
++ d - CCK-OFDM (also known as DSSS-OFDM)
++ p - PBCC (Packet Binary Convolutional Coding)
++
++The term CCK-OFDM may be used interchangeably with DSSS-OFDM
++(the IEEE 802.11g-2003 standard uses the latter terminology).
++In the CCK-OFDM, the PLCP header of the frame uses the CCK form of DSSS,
++while the PLCP payload (the MAC frame) is modulated using OFDM.
++
++Basically, you must use CCK-OFDM if you have mixed 11b/11g environment,
++or else (pure OFDM) 11b equipment may not realize that AP
++is sending a packet and start sending its own one.
++Sadly, looks like acx111 does not support CCK-OFDM, only pure OFDM.
++
++Re PBCC: avoid using it. It makes sense only if you have
++TI "11b+" hardware. You _must_ use PBCC in order to reach 22Mbps on it.
++
++Preambles:
++
++Long preamble (at 1Mbit rate, takes 144 us):
++ 16 bytes ones
++ 2 bytes 0xF3A0 (lsb sent first)
++PLCP header follows (at 1Mbit also):
++ 1 byte Signal: speed, in 0.1Mbit units, except for:
++ 33Mbit: 33 (instead of 330 - doesn't fit in octet)
++ all CCK-OFDM rates: 30
++ 1 byte Service
++ 0,1,4: reserved
++ 2: 1=locked clock
++ 3: 1=PBCC
++ 5: Length Extension (PBCC 22,33Mbit (11g only)) <-
++ 6: Length Extension (PBCC 22,33Mbit (11g only)) <- BLACK MAGIC HERE
++ 7: Length Extension <-
++ 2 bytes Length (time needed to tx this frame)
++ a) 5.5 Mbit/s CCK
++ Length = octets*8/5.5, rounded up to integer
++ b) 11 Mbit/s CCK
++ Length = octets*8/11, rounded up to integer
++ Service bit 7:
++ 0 = rounding took less than 8/11
++ 1 = rounding took more than or equal to 8/11
++ c) 5.5 Mbit/s PBCC
++ Length = (octets+1)*8/5.5, rounded up to integer
++ d) 11 Mbit/s PBCC
++ Length = (octets+1)*8/11, rounded up to integer
++ Service bit 7:
++ 0 = rounding took less than 8/11
++ 1 = rounding took more than or equal to 8/11
++ e) 22 Mbit/s PBCC
++ Length = (octets+1)*8/22, rounded up to integer
++ Service bits 6,7:
++ 00 = rounding took less than 8/22ths
++ 01 = rounding took 8/22...15/22ths
++ 10 = rounding took 16/22ths or more.
++ f) 33 Mbit/s PBCC
++ Length = (octets+1)*8/33, rounded up to integer
++ Service bits 5,6,7:
++ 000 rounding took less than 8/33
++ 001 rounding took 8/33...15/33
++ 010 rounding took 16/33...23/33
++ 011 rounding took 24/33...31/33
++ 100 rounding took 32/33 or more
++ 2 bytes CRC
++
++PSDU follows (up to 2346 bytes at selected rate)
++
++While Signal value alone is not enough to determine rate and modulation,
++Signal+Service is always sufficient.
++
++Short preamble (at 1Mbit rate, takes 72 us):
++ 7 bytes zeroes
++ 2 bytes 0x05CF (lsb sent first)
++PLCP header follows *at 2Mbit/s*. Format is the same as in long preamble.
++PSDU follows (up to 2346 bytes at selected rate)
++
++OFDM preamble is completely different, uses OFDM
++modulation from the start and thus easily identifiable.
++Not shown here.
++*/
++
++
++/***********************************************************************
++** Constants
++*/
++
++#define WLAN_HDR_A3_LEN 24
++#define WLAN_HDR_A4_LEN 30
++/* IV structure:
++** 3 bytes: Initialization Vector (24 bits)
++** 1 byte: 0..5: padding, must be 0; 6..7: key selector (0-3)
++*/
++#define WLAN_WEP_IV_LEN 4
++/* 802.11 says 2312 but looks like 2312 is a max size of _WEPed data_ */
++#define WLAN_DATA_MAXLEN 2304
++#define WLAN_WEP_ICV_LEN 4
++#define WLAN_FCS_LEN 4
++#define WLAN_A3FR_MAXLEN (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN)
++#define WLAN_A4FR_MAXLEN (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN)
++#define WLAN_A3FR_MAXLEN_FCS (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN + 4)
++#define WLAN_A4FR_MAXLEN_FCS (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + 4)
++#define WLAN_A3FR_MAXLEN_WEP (WLAN_A3FR_MAXLEN + 8)
++#define WLAN_A4FR_MAXLEN_WEP (WLAN_A4FR_MAXLEN + 8)
++#define WLAN_A3FR_MAXLEN_WEP_FCS (WLAN_A3FR_MAXLEN_FCS + 8)
++#define WLAN_A4FR_MAXLEN_WEP_FCS (WLAN_A4FR_MAXLEN_FCS + 8)
++
++#define WLAN_BSS_TS_LEN 8
++#define WLAN_SSID_MAXLEN 32
++#define WLAN_BEACON_FR_MAXLEN (WLAN_HDR_A3_LEN + 334)
++#define WLAN_ATIM_FR_MAXLEN (WLAN_HDR_A3_LEN + 0)
++#define WLAN_DISASSOC_FR_MAXLEN (WLAN_HDR_A3_LEN + 2)
++#define WLAN_ASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 48)
++#define WLAN_ASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16)
++#define WLAN_REASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 54)
++#define WLAN_REASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16)
++#define WLAN_PROBEREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 44)
++#define WLAN_PROBERESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 78)
++#define WLAN_AUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 261)
++#define WLAN_DEAUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 2)
++#define WLAN_CHALLENGE_IE_LEN 130
++#define WLAN_CHALLENGE_LEN 128
++#define WLAN_WEP_MAXKEYLEN 13
++#define WLAN_WEP_NKEYS 4
++
++/*--- Frame Control Field -------------------------------------*/
++/* Frame Types */
++#define WLAN_FTYPE_MGMT 0x00
++#define WLAN_FTYPE_CTL 0x01
++#define WLAN_FTYPE_DATA 0x02
++
++/* Frame subtypes */
++/* Management */
++#define WLAN_FSTYPE_ASSOCREQ 0x00
++#define WLAN_FSTYPE_ASSOCRESP 0x01
++#define WLAN_FSTYPE_REASSOCREQ 0x02
++#define WLAN_FSTYPE_REASSOCRESP 0x03
++#define WLAN_FSTYPE_PROBEREQ 0x04
++#define WLAN_FSTYPE_PROBERESP 0x05
++#define WLAN_FSTYPE_BEACON 0x08
++#define WLAN_FSTYPE_ATIM 0x09
++#define WLAN_FSTYPE_DISASSOC 0x0a
++#define WLAN_FSTYPE_AUTHEN 0x0b
++#define WLAN_FSTYPE_DEAUTHEN 0x0c
++
++/* Control */
++#define WLAN_FSTYPE_PSPOLL 0x0a
++#define WLAN_FSTYPE_RTS 0x0b
++#define WLAN_FSTYPE_CTS 0x0c
++#define WLAN_FSTYPE_ACK 0x0d
++#define WLAN_FSTYPE_CFEND 0x0e
++#define WLAN_FSTYPE_CFENDCFACK 0x0f
++
++/* Data */
++#define WLAN_FSTYPE_DATAONLY 0x00
++#define WLAN_FSTYPE_DATA_CFACK 0x01
++#define WLAN_FSTYPE_DATA_CFPOLL 0x02
++#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03
++#define WLAN_FSTYPE_NULL 0x04
++#define WLAN_FSTYPE_CFACK 0x05
++#define WLAN_FSTYPE_CFPOLL 0x06
++#define WLAN_FSTYPE_CFACK_CFPOLL 0x07
++
++/*--- FC Constants v. 2.0 ------------------------------------*/
++/* Each constant is defined twice: WF_CONST is in host */
++/* byteorder, WF_CONSTi is in ieee byteorder. */
++/* Usage: */
++/* printf("the frame subtype is %X", WF_FC_FTYPEi & rx.fc); */
++/* tx.fc = WF_FTYPE_CTLi | WF_FSTYPE_RTSi; */
++/*------------------------------------------------------------*/
++
++enum {
++/*--- Frame Control Field -------------------------------------*/
++/* Protocol version: always 0 for current 802.11 standards */
++IEEE16(WF_FC_PVER, 0x0003)
++IEEE16(WF_FC_FTYPE, 0x000c)
++IEEE16(WF_FC_FSTYPE, 0x00f0)
++IEEE16(WF_FC_TODS, 0x0100)
++IEEE16(WF_FC_FROMDS, 0x0200)
++IEEE16(WF_FC_FROMTODS, 0x0300)
++IEEE16(WF_FC_MOREFRAG, 0x0400)
++IEEE16(WF_FC_RETRY, 0x0800)
++/* Indicates PS mode in which STA will be after successful completion
++** of current frame exchange sequence. Always 0 for AP frames */
++IEEE16(WF_FC_PWRMGT, 0x1000)
++/* What MoreData=1 means:
++** From AP to STA in PS mode: don't sleep yet, I have more frames for you
++** From Contention-Free (CF) Pollable STA in response to a CF-Poll:
++** STA has buffered frames for transmission in response to next CF-Poll
++** Bcast/mcast frames transmitted from AP:
++** when additional bcast/mcast frames remain to be transmitted by AP
++** during this beacon interval
++** In all other cases MoreData=0 */
++IEEE16(WF_FC_MOREDATA, 0x2000)
++IEEE16(WF_FC_ISWEP, 0x4000)
++IEEE16(WF_FC_ORDER, 0x8000)
++
++/* Frame Types */
++IEEE16(WF_FTYPE_MGMT, 0x00)
++IEEE16(WF_FTYPE_CTL, 0x04)
++IEEE16(WF_FTYPE_DATA, 0x08)
++
++/* Frame subtypes */
++/* Management */
++IEEE16(WF_FSTYPE_ASSOCREQ, 0x00)
++IEEE16(WF_FSTYPE_ASSOCRESP, 0x10)
++IEEE16(WF_FSTYPE_REASSOCREQ, 0x20)
++IEEE16(WF_FSTYPE_REASSOCRESP, 0x30)
++IEEE16(WF_FSTYPE_PROBEREQ, 0x40)
++IEEE16(WF_FSTYPE_PROBERESP, 0x50)
++IEEE16(WF_FSTYPE_BEACON, 0x80)
++IEEE16(WF_FSTYPE_ATIM, 0x90)
++IEEE16(WF_FSTYPE_DISASSOC, 0xa0)
++IEEE16(WF_FSTYPE_AUTHEN, 0xb0)
++IEEE16(WF_FSTYPE_DEAUTHEN, 0xc0)
++
++/* Control */
++IEEE16(WF_FSTYPE_PSPOLL, 0xa0)
++IEEE16(WF_FSTYPE_RTS, 0xb0)
++IEEE16(WF_FSTYPE_CTS, 0xc0)
++IEEE16(WF_FSTYPE_ACK, 0xd0)
++IEEE16(WF_FSTYPE_CFEND, 0xe0)
++IEEE16(WF_FSTYPE_CFENDCFACK, 0xf0)
++
++/* Data */
++IEEE16(WF_FSTYPE_DATAONLY, 0x00)
++IEEE16(WF_FSTYPE_DATA_CFACK, 0x10)
++IEEE16(WF_FSTYPE_DATA_CFPOLL, 0x20)
++IEEE16(WF_FSTYPE_DATA_CFACK_CFPOLL, 0x30)
++IEEE16(WF_FSTYPE_NULL, 0x40)
++IEEE16(WF_FSTYPE_CFACK, 0x50)
++IEEE16(WF_FSTYPE_CFPOLL, 0x60)
++IEEE16(WF_FSTYPE_CFACK_CFPOLL, 0x70)
++};
++
++
++/***********************************************************************
++** Macros
++*/
++
++/*--- Duration Macros ----------------------------------------*/
++/* Macros to get/set the bitfields of the Duration Field */
++/* - the duration value is only valid when bit15 is zero */
++/* - the firmware handles these values, so I'm not going */
++/* these macros right now. */
++/*------------------------------------------------------------*/
++
++/*--- Sequence Control Macros -------------------------------*/
++/* Macros to get/set the bitfields of the Sequence Control */
++/* Field. */
++/*------------------------------------------------------------*/
++#define WLAN_GET_SEQ_FRGNUM(n) ((u16)(n) & 0x000f)
++#define WLAN_GET_SEQ_SEQNUM(n) (((u16)(n) & 0xfff0) >> 4)
++
++/*--- Data ptr macro -----------------------------------------*/
++/* Creates a u8* to the data portion of a frame */
++/* Assumes you're passing in a ptr to the beginning of the hdr*/
++/*------------------------------------------------------------*/
++#define WLAN_HDR_A3_DATAP(p) (((u8*)(p)) + WLAN_HDR_A3_LEN)
++#define WLAN_HDR_A4_DATAP(p) (((u8*)(p)) + WLAN_HDR_A4_LEN)
++
++
++/***********************************************************************
++** Types
++*/
++
++/* 802.11 header type
++**
++** Note the following:
++** a1 *always* is receiver's mac or bcast/mcast
++** a2 *always* is transmitter's mac, if a2 exists
++** seq: [0:3] frag#, [4:15] seq# - used for dup detection
++** (dups from retries have same seq#) */
++typedef struct wlan_hdr {
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 a1[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 a2[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 a3[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++ u8 a4[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} wlan_hdr_t;
++
++/* Separate structs for use if frame type is known */
++typedef struct wlan_hdr_a3 {
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 a1[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 a2[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 a3[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++} wlan_hdr_a3_t;
++
++typedef struct wlan_hdr_mgmt {
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++} wlan_hdr_mgmt_t;
++
++#ifdef NOT_NEEDED_YET
++typedef struct { /* ad-hoc peer->peer (to/from DS = 0/0) */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++} ibss;
++typedef struct { /* ap->sta (to/from DS = 0/1) */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++} fromap;
++typedef struct { /* sta->ap (to/from DS = 1/0) */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++} toap;
++typedef struct { /* wds->wds (to/from DS = 1/1), the only 4addr pkt */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} wds;
++typedef struct { /* all management packets */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 da[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 sa[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u16 seq __WLAN_ATTRIB_PACK__;
++} mgmt;
++typedef struct { /* has no body, just a FCS */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} rts;
++typedef struct { /* has no body, just a FCS */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} cts;
++typedef struct { /* has no body, just a FCS */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} ack;
++typedef struct { /* has no body, just a FCS */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ /* NB: this one holds Assoc ID in dur field: */
++ u16 aid __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 ta[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} pspoll;
++typedef struct { /* has no body, just a FCS */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} cfend;
++typedef struct { /* has no body, just a FCS */
++ u16 fc __WLAN_ATTRIB_PACK__;
++ u16 dur __WLAN_ATTRIB_PACK__;
++ u8 ra[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ u8 bssid[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++} cfendcfack;
++#endif
++
++/* Prism header emulation (monitor mode) */
++typedef struct wlanitem_u32 {
++ u32 did __WLAN_ATTRIB_PACK__;
++ u16 status __WLAN_ATTRIB_PACK__;
++ u16 len __WLAN_ATTRIB_PACK__;
++ u32 data __WLAN_ATTRIB_PACK__;
++} wlanitem_u32_t;
++#define WLANITEM_STATUS_data_ok 0
++#define WLANITEM_STATUS_no_value 1
++#define WLANITEM_STATUS_invalid_itemname 2
++#define WLANITEM_STATUS_invalid_itemdata 3
++#define WLANITEM_STATUS_missing_itemdata 4
++#define WLANITEM_STATUS_incomplete_itemdata 5
++#define WLANITEM_STATUS_invalid_msg_did 6
++#define WLANITEM_STATUS_invalid_mib_did 7
++#define WLANITEM_STATUS_missing_conv_func 8
++#define WLANITEM_STATUS_string_too_long 9
++#define WLANITEM_STATUS_data_out_of_range 10
++#define WLANITEM_STATUS_string_too_short 11
++#define WLANITEM_STATUS_missing_valid_func 12
++#define WLANITEM_STATUS_unknown 13
++#define WLANITEM_STATUS_invalid_did 14
++#define WLANITEM_STATUS_missing_print_func 15
++
++#define WLAN_DEVNAMELEN_MAX 16
++typedef struct wlansniffrm {
++ u32 msgcode __WLAN_ATTRIB_PACK__;
++ u32 msglen __WLAN_ATTRIB_PACK__;
++ u8 devname[WLAN_DEVNAMELEN_MAX] __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t hosttime __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t mactime __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t channel __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t rssi __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t sq __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t signal __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t noise __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t rate __WLAN_ATTRIB_PACK__;
++ wlanitem_u32_t istx __WLAN_ATTRIB_PACK__; /* tx? 0:no 1:yes */
++ wlanitem_u32_t frmlen __WLAN_ATTRIB_PACK__;
++} wlansniffrm_t;
++#define WLANSNIFFFRM 0x0041
++#define WLANSNIFFFRM_hosttime 0x1041
++#define WLANSNIFFFRM_mactime 0x2041
++#define WLANSNIFFFRM_channel 0x3041
++#define WLANSNIFFFRM_rssi 0x4041
++#define WLANSNIFFFRM_sq 0x5041
++#define WLANSNIFFFRM_signal 0x6041
++#define WLANSNIFFFRM_noise 0x7041
++#define WLANSNIFFFRM_rate 0x8041
++#define WLANSNIFFFRM_istx 0x9041
++#define WLANSNIFFFRM_frmlen 0xA041
+diff -Naur linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan_mgmt.h linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan_mgmt.h
+--- linux-2.6.14-omap2/drivers/net/wireless/tiacx/wlan_mgmt.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/net/wireless/tiacx/wlan_mgmt.h 2005-09-28 23:54:23.000000000 +0300
+@@ -0,0 +1,579 @@
++/***********************************************************************
++** Copyright (C) 2003 ACX100 Open Source Project
++**
++** The contents of this file are subject to the Mozilla Public
++** License Version 1.1 (the "License"); you may not use this file
++** except in compliance with the License. You may obtain a copy of
++** the License at http://www.mozilla.org/MPL/
++**
++** Software distributed under the License is distributed on an "AS
++** IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++** implied. See the License for the specific language governing
++** rights and limitations under the License.
++**
++** Alternatively, the contents of this file may be used under the
++** terms of the GNU Public License version 2 (the "GPL"), in which
++** case the provisions of the GPL are applicable instead of the
++** above. If you wish to allow the use of your version of this file
++** only under the terms of the GPL and not to allow others to use
++** your version of this file under the MPL, indicate your decision
++** by deleting the provisions above and replace them with the notice
++** and other provisions required by the GPL. If you do not delete
++** the provisions above, a recipient may use your version of this
++** file under either the MPL or the GPL.
++** ---------------------------------------------------------------------
++** Inquiries regarding the ACX100 Open Source Project can be
++** made directly to:
++**
++** acx100-users@lists.sf.net
++** http://acx100.sf.net
++** ---------------------------------------------------------------------
++*/
++
++/***********************************************************************
++** This code is based on elements which are
++** Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
++** info@linux-wlan.com
++** http://www.linux-wlan.com
++*/
++
++/***********************************************************************
++** Constants
++*/
++
++/*-- Information Element IDs --------------------*/
++#define WLAN_EID_SSID 0
++#define WLAN_EID_SUPP_RATES 1
++#define WLAN_EID_FH_PARMS 2
++#define WLAN_EID_DS_PARMS 3
++#define WLAN_EID_CF_PARMS 4
++#define WLAN_EID_TIM 5
++#define WLAN_EID_IBSS_PARMS 6
++#define WLAN_EID_COUNTRY 7 /* 802.11d */
++#define WLAN_EID_FH_HOP_PARMS 8 /* 802.11d */
++#define WLAN_EID_FH_TABLE 9 /* 802.11d */
++#define WLAN_EID_REQUEST 10 /* 802.11d */
++/*-- values 11-15 reserved --*/
++#define WLAN_EID_CHALLENGE 16
++/*-- values 17-31 reserved for challenge text extension --*/
++#define WLAN_EID_ERP_INFO 42
++#define WLAN_EID_NONERP 47 /* was seen from WRT54GS with OpenWrt */
++#define WLAN_EID_RSN 48
++#define WLAN_EID_EXT_RATES 50
++#define WLAN_EID_GENERIC 221
++
++#if 0
++#define WLAN_EID_PWR_CONSTRAINT 32 /* 11H PowerConstraint */
++#define WLAN_EID_PWR_CAP 33 /* 11H PowerCapability */
++#define WLAN_EID_TPC_REQUEST 34 /* 11H TPC Request */
++#define WLAN_EID_TPC_REPORT 35 /* 11H TPC Report */
++#define WLAN_EID_SUPP_CHANNELS 36 /* 11H Supported Channels */
++#define WLAN_EID_CHANNEL_SWITCH 37 /* 11H ChannelSwitch */
++#define WLAN_EID_MEASURE_REQUEST 38 /* 11H MeasurementRequest */
++#define WLAN_EID_MEASURE_REPORT 39 /* 11H MeasurementReport */
++#define WLAN_EID_QUIET_ID 40 /* 11H Quiet */
++#define WLAN_EID_IBSS_DFS_ID 41 /* 11H IBSS_DFS */
++#endif
++
++/*-- Reason Codes -------------------------------*/
++#define WLAN_MGMT_REASON_RSVD 0
++#define WLAN_MGMT_REASON_UNSPEC 1
++#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID 2
++#define WLAN_MGMT_REASON_DEAUTH_LEAVING 3
++#define WLAN_MGMT_REASON_DISASSOC_INACTIVE 4
++#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY 5
++#define WLAN_MGMT_REASON_CLASS2_NONAUTH 6
++#define WLAN_MGMT_REASON_CLASS3_NONASSOC 7
++#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT 8
++#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH 9
++
++/*-- Status Codes -------------------------------*/
++#define WLAN_MGMT_STATUS_SUCCESS 0
++#define WLAN_MGMT_STATUS_UNSPEC_FAILURE 1
++#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED 10
++#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC 11
++#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC 12
++#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG 13
++#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ 14
++#define WLAN_MGMT_STATUS_CHALLENGE_FAIL 15
++#define WLAN_MGMT_STATUS_AUTH_TIMEOUT 16
++#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY 17
++#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES 18
++/* p80211b additions */
++#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOSHORT 19
++#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOPBCC 20
++#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOAGILITY 21
++
++/*-- Auth Algorithm Field ---------------------------*/
++#define WLAN_AUTH_ALG_OPENSYSTEM 0
++#define WLAN_AUTH_ALG_SHAREDKEY 1
++
++/*-- Management Frame Field Offsets -------------*/
++/* Note: Not all fields are listed because of variable lengths */
++/* Note: These offsets are from the start of the frame data */
++
++#define WLAN_BEACON_OFF_TS 0
++#define WLAN_BEACON_OFF_BCN_INT 8
++#define WLAN_BEACON_OFF_CAPINFO 10
++#define WLAN_BEACON_OFF_SSID 12
++
++#define WLAN_DISASSOC_OFF_REASON 0
++
++#define WLAN_ASSOCREQ_OFF_CAP_INFO 0
++#define WLAN_ASSOCREQ_OFF_LISTEN_INT 2
++#define WLAN_ASSOCREQ_OFF_SSID 4
++
++#define WLAN_ASSOCRESP_OFF_CAP_INFO 0
++#define WLAN_ASSOCRESP_OFF_STATUS 2
++#define WLAN_ASSOCRESP_OFF_AID 4
++#define WLAN_ASSOCRESP_OFF_SUPP_RATES 6
++
++#define WLAN_REASSOCREQ_OFF_CAP_INFO 0
++#define WLAN_REASSOCREQ_OFF_LISTEN_INT 2
++#define WLAN_REASSOCREQ_OFF_CURR_AP 4
++#define WLAN_REASSOCREQ_OFF_SSID 10
++
++#define WLAN_REASSOCRESP_OFF_CAP_INFO 0
++#define WLAN_REASSOCRESP_OFF_STATUS 2
++#define WLAN_REASSOCRESP_OFF_AID 4
++#define WLAN_REASSOCRESP_OFF_SUPP_RATES 6
++
++#define WLAN_PROBEREQ_OFF_SSID 0
++
++#define WLAN_PROBERESP_OFF_TS 0
++#define WLAN_PROBERESP_OFF_BCN_INT 8
++#define WLAN_PROBERESP_OFF_CAP_INFO 10
++#define WLAN_PROBERESP_OFF_SSID 12
++
++#define WLAN_AUTHEN_OFF_AUTH_ALG 0
++#define WLAN_AUTHEN_OFF_AUTH_SEQ 2
++#define WLAN_AUTHEN_OFF_STATUS 4
++#define WLAN_AUTHEN_OFF_CHALLENGE 6
++
++#define WLAN_DEAUTHEN_OFF_REASON 0
++
++enum {
++IEEE16(WF_MGMT_CAP_ESS, 0x0001)
++IEEE16(WF_MGMT_CAP_IBSS, 0x0002)
++/* In (re)assoc request frames by STA:
++** Pollable=0, PollReq=0: STA is not CF-Pollable
++** 0 1: STA is CF-Pollable, not requesting to be placed on the CF-Polling list
++** 1 0: STA is CF-Pollable, requesting to be placed on the CF-Polling list
++** 1 1: STA is CF-Pollable, requesting never to be polled
++** In beacon, proberesp, (re)assoc resp frames by AP:
++** 0 0: No point coordinator at AP
++** 0 1: Point coordinator at AP for delivery only (no polling)
++** 1 0: Point coordinator at AP for delivery and polling
++** 1 1: Reserved */
++IEEE16(WF_MGMT_CAP_CFPOLLABLE, 0x0004)
++IEEE16(WF_MGMT_CAP_CFPOLLREQ, 0x0008)
++/* 1=non-WEP data frames are disallowed */
++IEEE16(WF_MGMT_CAP_PRIVACY, 0x0010)
++/* In beacon, proberesp, (re)assocresp by AP/AdHoc:
++** 1=use of shortpre is allowed ("I can receive shortpre") */
++IEEE16(WF_MGMT_CAP_SHORT, 0x0020)
++IEEE16(WF_MGMT_CAP_PBCC, 0x0040)
++IEEE16(WF_MGMT_CAP_AGILITY, 0x0080)
++/* In (re)assoc request frames by STA:
++** 1=short slot time implemented and enabled
++** NB: AP shall use long slot time beginning at the next Beacon after assoc
++** of STA with this bit set to 0
++** In beacon, proberesp, (re)assoc resp frames by AP:
++** currently used slot time value: 0/1 - long/short */
++IEEE16(WF_MGMT_CAP_SHORTSLOT, 0x0400)
++/* In (re)assoc request frames by STA: 1=CCK-OFDM is implemented and enabled
++** In beacon, proberesp, (re)assoc resp frames by AP/AdHoc:
++** 1=CCK-OFDM is allowed */
++IEEE16(WF_MGMT_CAP_CCKOFDM, 0x2000)
++};
++
++
++/***********************************************************************
++** Types
++*/
++
++/* Information Element types */
++
++/* prototype structure, all IEs start with these members */
++typedef struct wlan_ie {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++} wlan_ie_t;
++
++/*-- Service Set Identity (SSID) -----------------*/
++typedef struct wlan_ie_ssid {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u8 ssid[1] __WLAN_ATTRIB_PACK__; /* may be zero */
++} wlan_ie_ssid_t;
++
++/*-- Supported Rates -----------------------------*/
++typedef struct wlan_ie_supp_rates {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u8 rates[1] __WLAN_ATTRIB_PACK__; /* had better be at LEAST one! */
++} wlan_ie_supp_rates_t;
++
++/*-- FH Parameter Set ----------------------------*/
++typedef struct wlan_ie_fh_parms {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u16 dwell __WLAN_ATTRIB_PACK__;
++ u8 hopset __WLAN_ATTRIB_PACK__;
++ u8 hoppattern __WLAN_ATTRIB_PACK__;
++ u8 hopindex __WLAN_ATTRIB_PACK__;
++} wlan_ie_fh_parms_t;
++
++/*-- DS Parameter Set ----------------------------*/
++typedef struct wlan_ie_ds_parms {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u8 curr_ch __WLAN_ATTRIB_PACK__;
++} wlan_ie_ds_parms_t;
++
++/*-- CF Parameter Set ----------------------------*/
++typedef struct wlan_ie_cf_parms {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u8 cfp_cnt __WLAN_ATTRIB_PACK__;
++ u8 cfp_period __WLAN_ATTRIB_PACK__;
++ u16 cfp_maxdur __WLAN_ATTRIB_PACK__;
++ u16 cfp_durremaining __WLAN_ATTRIB_PACK__;
++} wlan_ie_cf_parms_t;
++
++/*-- TIM ------------------------------------------*/
++typedef struct wlan_ie_tim {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u8 dtim_cnt __WLAN_ATTRIB_PACK__;
++ u8 dtim_period __WLAN_ATTRIB_PACK__;
++ u8 bitmap_ctl __WLAN_ATTRIB_PACK__;
++ u8 virt_bm[1] __WLAN_ATTRIB_PACK__;
++} wlan_ie_tim_t;
++
++/*-- IBSS Parameter Set ---------------------------*/
++typedef struct wlan_ie_ibss_parms {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u16 atim_win __WLAN_ATTRIB_PACK__;
++} wlan_ie_ibss_parms_t;
++
++/*-- Challenge Text ------------------------------*/
++typedef struct wlan_ie_challenge {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ u8 challenge[1] __WLAN_ATTRIB_PACK__;
++} wlan_ie_challenge_t;
++
++/*-- ERP (42) -------------------------------------*/
++typedef struct wlan_ie_erp {
++ u8 eid __WLAN_ATTRIB_PACK__;
++ u8 len __WLAN_ATTRIB_PACK__;
++ /* bit 0:Non ERP present
++ ** 1:Use Protection
++ ** 2:Barker Preamble mode
++ ** 3-7:reserved */
++ u8 erp __WLAN_ATTRIB_PACK__;
++} wlan_ie_erp_t;
++
++/* Types for parsing mgmt frames */
++
++/* prototype structure, all mgmt frame types will start with these members */
++typedef struct wlan_fr_mgmt {
++ u16 type;
++ u16 len; /* DOES NOT include FCS */
++ wlan_hdr_t *hdr;
++ /* used for target specific data, skb in Linux */
++ /*-- fixed fields -----------*/
++ /*-- info elements ----------*/
++} wlan_fr_mgmt_t;
++
++/*-- Beacon ---------------------------------------*/
++typedef struct wlan_fr_beacon {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u64 *ts;
++ u16 *bcn_int;
++ u16 *cap_info;
++ /*-- info elements ----------*/
++ wlan_ie_ssid_t *ssid;
++ wlan_ie_supp_rates_t *supp_rates;
++ wlan_ie_supp_rates_t *ext_rates;
++ wlan_ie_fh_parms_t *fh_parms;
++ wlan_ie_ds_parms_t *ds_parms;
++ wlan_ie_cf_parms_t *cf_parms;
++ wlan_ie_ibss_parms_t *ibss_parms;
++ wlan_ie_tim_t *tim; /* in beacon only, not proberesp */
++ wlan_ie_erp_t *erp; /* in beacon only, not proberesp */
++} wlan_fr_beacon_t;
++#define wlan_fr_proberesp wlan_fr_beacon
++#define wlan_fr_proberesp_t wlan_fr_beacon_t
++
++/*-- IBSS ATIM ------------------------------------*/
++typedef struct wlan_fr_ibssatim {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ /*-- info elements ----------*/
++ /* this frame type has a null body */
++} wlan_fr_ibssatim_t;
++
++/*-- Disassociation -------------------------------*/
++typedef struct wlan_fr_disassoc {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u16 *reason;
++ /*-- info elements ----------*/
++} wlan_fr_disassoc_t;
++
++/*-- Association Request --------------------------*/
++typedef struct wlan_fr_assocreq {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u16 *cap_info;
++ u16 *listen_int;
++ /*-- info elements ----------*/
++ wlan_ie_ssid_t *ssid;
++ wlan_ie_supp_rates_t *supp_rates;
++ wlan_ie_supp_rates_t *ext_rates;
++} wlan_fr_assocreq_t;
++
++/*-- Association Response -------------------------*/
++typedef struct wlan_fr_assocresp {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u16 *cap_info;
++ u16 *status;
++ u16 *aid;
++ /*-- info elements ----------*/
++ wlan_ie_supp_rates_t *supp_rates;
++ wlan_ie_supp_rates_t *ext_rates;
++} wlan_fr_assocresp_t;
++
++/*-- Reassociation Request ------------------------*/
++typedef struct wlan_fr_reassocreq {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u16 *cap_info;
++ u16 *listen_int;
++ u8 *curr_ap;
++ /*-- info elements ----------*/
++ wlan_ie_ssid_t *ssid;
++ wlan_ie_supp_rates_t *supp_rates;
++ wlan_ie_supp_rates_t *ext_rates;
++} wlan_fr_reassocreq_t;
++
++/*-- Reassociation Response -----------------------*/
++typedef struct wlan_fr_reassocresp {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u16 *cap_info;
++ u16 *status;
++ u16 *aid;
++ /*-- info elements ----------*/
++ wlan_ie_supp_rates_t *supp_rates;
++ wlan_ie_supp_rates_t *ext_rates;
++} wlan_fr_reassocresp_t;
++
++/*-- Probe Request --------------------------------*/
++typedef struct wlan_fr_probereq {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ /*-- info elements ----------*/
++ wlan_ie_ssid_t *ssid;
++ wlan_ie_supp_rates_t *supp_rates;
++ wlan_ie_supp_rates_t *ext_rates;
++} wlan_fr_probereq_t;
++
++/*-- Authentication -------------------------------*/
++typedef struct wlan_fr_authen {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u16 *auth_alg;
++ u16 *auth_seq;
++ u16 *status;
++ /*-- info elements ----------*/
++ wlan_ie_challenge_t *challenge;
++} wlan_fr_authen_t;
++
++/*-- Deauthenication -----------------------------*/
++typedef struct wlan_fr_deauthen {
++ u16 type;
++ u16 len;
++ wlan_hdr_t *hdr;
++ /*-- fixed fields -----------*/
++ u16 *reason;
++ /*-- info elements ----------*/
++} wlan_fr_deauthen_t;
++
++/* Types for building mgmt frames */
++
++/* Warning. Several types used in below structs are
++** in fact variable length. Use structs with such fields with caution */
++typedef struct auth_frame_body {
++ u16 auth_alg __WLAN_ATTRIB_PACK__;
++ u16 auth_seq __WLAN_ATTRIB_PACK__;
++ u16 status __WLAN_ATTRIB_PACK__;
++ wlan_ie_challenge_t challenge __WLAN_ATTRIB_PACK__;
++} auth_frame_body_t;
++
++typedef struct assocresp_frame_body {
++ u16 cap_info __WLAN_ATTRIB_PACK__;
++ u16 status __WLAN_ATTRIB_PACK__;
++ u16 aid __WLAN_ATTRIB_PACK__;
++ wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
++} assocresp_frame_body_t;
++
++typedef struct reassocreq_frame_body {
++ u16 cap_info __WLAN_ATTRIB_PACK__;
++ u16 listen_int __WLAN_ATTRIB_PACK__;
++ u8 current_ap[ETH_ALEN] __WLAN_ATTRIB_PACK__;
++ wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
++/* access to this one is disabled since ssid_t is variable length: */
++ /* wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__; */
++} reassocreq_frame_body_t;
++
++typedef struct reassocresp_frame_body {
++ u16 cap_info __WLAN_ATTRIB_PACK__;
++ u16 status __WLAN_ATTRIB_PACK__;
++ u16 aid __WLAN_ATTRIB_PACK__;
++ wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
++} reassocresp_frame_body_t;
++
++typedef struct deauthen_frame_body {
++ u16 reason __WLAN_ATTRIB_PACK__;
++} deauthen_frame_body_t;
++
++typedef struct disassoc_frame_body {
++ u16 reason __WLAN_ATTRIB_PACK__;
++} disassoc_frame_body_t;
++
++typedef struct probereq_frame_body {
++ wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
++ wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__;
++} probereq_frame_body_t;
++
++typedef struct proberesp_frame_body {
++ u8 timestamp[8] __WLAN_ATTRIB_PACK__;
++ u16 beacon_int __WLAN_ATTRIB_PACK__;
++ u16 cap_info __WLAN_ATTRIB_PACK__;
++ wlan_ie_ssid_t ssid __WLAN_ATTRIB_PACK__;
++/* access to these is disabled since ssid_t is variable length: */
++ /* wlan_ie_supp_rates_t rates __WLAN_ATTRIB_PACK__; */
++ /* fhps_t fhps __WLAN_ATTRIB_PACK__; */
++ /* dsps_t dsps __WLAN_ATTRIB_PACK__; */
++ /* cfps_t cfps __WLAN_ATTRIB_PACK__; */
++} proberesp_frame_body_t;
++
++
++/***********************************************************************
++** Functions
++*/
++
++/* Helpers for parsing mgmt frames */
++void wlan_mgmt_decode_ibssatim(wlan_fr_ibssatim_t *f);
++void wlan_mgmt_decode_assocreq(wlan_fr_assocreq_t *f);
++void wlan_mgmt_decode_assocresp(wlan_fr_assocresp_t *f);
++void wlan_mgmt_decode_authen(wlan_fr_authen_t *f);
++void wlan_mgmt_decode_beacon(wlan_fr_beacon_t *f);
++void wlan_mgmt_decode_deauthen(wlan_fr_deauthen_t *f);
++void wlan_mgmt_decode_disassoc(wlan_fr_disassoc_t *f);
++void wlan_mgmt_decode_probereq(wlan_fr_probereq_t *f);
++void wlan_mgmt_decode_proberesp(wlan_fr_proberesp_t *f);
++void wlan_mgmt_decode_reassocreq(wlan_fr_reassocreq_t *f);
++void wlan_mgmt_decode_reassocresp(wlan_fr_reassocresp_t *f);
++
++/* Helpers for building mgmt frames */
++static inline u8*
++wlan_fill_ie_ssid(u8 *p, int len, const char *ssid)
++{
++ struct wlan_ie_ssid *ie = (void*)p;
++ ie->eid = WLAN_EID_SSID;
++ ie->len = len;
++ memcpy(ie->ssid, ssid, len);
++ return p + len + 2;
++}
++/* This controls whether we create 802.11g 'ext supported rates' IEs
++** or just create overlong 'supported rates' IEs instead
++** (non-11g compliant) */
++#define WE_OBEY_802_11G 1
++static inline u8*
++wlan_fill_ie_rates(u8 *p, int len, const u8 *rates)
++{
++ struct wlan_ie_supp_rates *ie = (void*)p;
++#if WE_OBEY_802_11G
++ if (len > 8 ) len = 8;
++#endif
++ /* supported rates (1 to 8 octets) */
++ ie->eid = WLAN_EID_SUPP_RATES;
++ ie->len = len;
++ memcpy(ie->rates, rates, len);
++ return p + len + 2;
++}
++/* This one wouldn't create an IE at all if not needed */
++static inline u8*
++wlan_fill_ie_rates_ext(u8 *p, int len, const u8 *rates)
++{
++ struct wlan_ie_supp_rates *ie = (void*)p;
++#if !WE_OBEY_802_11G
++ return p;
++#endif
++ len -= 8;
++ if (len < 0) return p;
++ /* ext supported rates */
++ ie->eid = WLAN_EID_EXT_RATES;
++ ie->len = len;
++ memcpy(ie->rates, rates+8, len);
++ return p + len + 2;
++}
++static inline u8*
++wlan_fill_ie_ds_parms(u8 *p, int channel)
++{
++ struct wlan_ie_ds_parms *ie = (void*)p;
++ ie->eid = WLAN_EID_DS_PARMS;
++ ie->len = 1;
++ ie->curr_ch = channel;
++ return p + sizeof(*ie);
++}
++static inline u8*
++wlan_fill_ie_ibss_parms(u8 *p, int atim_win)
++{
++ struct wlan_ie_ibss_parms *ie = (void*)p;
++ ie->eid = WLAN_EID_IBSS_PARMS;
++ ie->len = 2;
++ ie->atim_win = atim_win;
++ return p + sizeof(*ie);
++}
++static inline u8*
++wlan_fill_ie_tim(u8 *p, int rem, int period, int bcast,
++ int ofs, int len, const u8 *vbm)
++{
++ struct wlan_ie_tim *ie = (void*)p;
++ ie->eid = WLAN_EID_TIM;
++ ie->len = len + 3;
++ ie->dtim_cnt = rem;
++ ie->dtim_period = period;
++ ie->bitmap_ctl = ofs | (bcast!=0);
++ if (vbm)
++ memcpy(ie->virt_bm, vbm, len); /* min 1 byte */
++ else
++ ie->virt_bm[0] = 0;
++ return p + len + 3 + 2;
++}
+diff -Naur linux-2.6.14-omap2/drivers/ssi/omap-tsc2101.c linux-h6300-omap2-2.6.14.3/drivers/ssi/omap-tsc2101.c
+--- linux-2.6.14-omap2/drivers/ssi/omap-tsc2101.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/ssi/omap-tsc2101.c 2005-10-22 03:52:45.000000000 +0300
+@@ -36,10 +36,11 @@
+ #include <asm/arch/hardware.h>
+ #include <asm/hardware/tsc2101.h>
+ #include <asm/arch/gpioexpander.h>
++#include <asm/arch/gpio.h>
+
+ #include "omap-tsc2101.h"
+
+-#if CONFIG_ARCH_OMAP16XX
++#if CONFIG_ARCH_OMAP1
+ #include <../drivers/ssi/omap-uwire.h>
+ #else
+ #error "Unsupported configuration"
+@@ -66,27 +67,28 @@
+ if (count++ == 0) {
+ int ret = 0;
+ /* set the Mux to provide MCLK to TSC2101 */
+- if (machine_is_omap_h3()) {
++ if (machine_is_omap_h3())
+ ret = omap_cfg_reg(V5_1710_MCLK_ON);
+- } else {
+- if (machine_is_omap_h2()) {
+- ret = omap_cfg_reg(R10_1610_MCLK_ON);
++ else if (machine_is_omap_h2())
++ ret = omap_cfg_reg(R10_1610_MCLK_ON);
++ else if (machine_is_h6300 ())
++ ret = omap_cfg_reg(R10_1510_MCLK_ON);
++
++ if (!cpu_is_omap1510 ()) {
++ /* Get the MCLK */
++ tsc2101_mclk_ck = clk_get(NULL, "mclk");
++ if (NULL == tsc2101_mclk_ck) {
++ printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
++ ret = -EPERM;
++ goto done;
+ }
+- }
+-
+- /* Get the MCLK */
+- tsc2101_mclk_ck = clk_get(NULL, "mclk");
+- if (NULL == tsc2101_mclk_ck) {
+- printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
+- ret = -EPERM;
+- goto done;
+- }
+- if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
+- printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
+- ret = -EPERM;
+- goto done;
+- }
+- clk_enable(tsc2101_mclk_ck);
++ if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
++ printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
++ ret = -EPERM;
++ goto done;
++ }
++ clk_enable(tsc2101_mclk_ck);
++ } /* if (!cpu_is_omap1510 ()) */
+
+ ret = omap_tsc2101_configure();
+
+@@ -116,10 +118,16 @@
+ }
+ }
+
+- /* Release the MCLK */
+- clk_disable(tsc2101_mclk_ck);
+- clk_put(tsc2101_mclk_ck);
+- tsc2101_mclk_ck = NULL;
++ if (!cpu_is_omap1510 ()) {
++ /* Release the MCLK */
++ clk_disable(tsc2101_mclk_ck);
++ clk_put(tsc2101_mclk_ck);
++ tsc2101_mclk_ck = NULL;
++ }
++
++#if defined(CONFIG_MACH_OMAP_H6300)
++ omap_free_gpio(8);
++#endif
+
+ module_put(THIS_MODULE);
+ }
+@@ -150,7 +158,10 @@
+ return;
+ }
+ }
+- if (machine_is_omap_h3()) {
++ if (machine_is_omap_h3() || machine_is_h6300 ()) {
++
++ if (machine_is_h6300 ())
++ omap_set_gpio_dataout (8, 0);
+
+ ret =
+ omap_uwire_data_transfer(0, ((page << 11) | (address << 5)),
+@@ -159,6 +170,8 @@
+ printk(KERN_ERR
+ "uwire-write returned error for address %x\n",
+ address);
++ if (machine_is_h6300 ())
++ omap_set_gpio_dataout (8, 1);
+ return;
+ }
+ ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0);
+@@ -166,10 +179,14 @@
+ printk(KERN_ERR
+ "uwire-write returned error for address %x\n",
+ address);
++ if (machine_is_h6300 ())
++ omap_set_gpio_dataout (8, 1);
+ return;
+ }
+- }
+
++ if (machine_is_h6300 ())
++ omap_set_gpio_dataout (8, 1);
++ }
+ }
+
+ void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs)
+@@ -178,9 +195,13 @@
+ if (machine_is_omap_h2()) {
+ cs = 1;
+ }
+- if (machine_is_omap_h3()) {
++ if (machine_is_omap_h3() || machine_is_h6300 ()) {
+ cs = 0;
+ }
++
++ if (machine_is_h6300 ())
++ omap_set_gpio_dataout(8, 0);
++
+ (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11)
+ | (startaddress << 5)),
+ 16, 0, NULL, 1);
+@@ -188,6 +209,9 @@
+ omap_uwire_data_transfer(cs, 0, 0, 16, data, 1);
+ }
+ omap_uwire_data_transfer(cs, 0, 0, 16, data, 0);
++
++ if (machine_is_h6300 ())
++ omap_set_gpio_dataout(8, 1);
+ }
+
+ u16 omap_tsc2101_read(int page, u8 address)
+@@ -228,9 +252,24 @@
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+ omap_uwire_configure_mode(0, uwire_flags);
+ }
++ if (machine_is_h6300()) {
++ uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
++ omap_cfg_reg(N14_1510_UWIRE_CS0);
++ omap_uwire_configure_mode(0, uwire_flags);
++
++ omap_request_gpio(8);
++ omap_set_gpio_dataout(8, 0);
++ omap_set_gpio_direction (8, 0);
++ }
+
+ /* Configure MCLK enable */
+- omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);
++ if (cpu_is_omap16xx() || cpu_is_omap1710())
++ omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);
++ if (machine_is_h6300()) {
++ omap_cfg_reg(V19_1510_UWIRE_SCLK);
++ omap_cfg_reg(W21_1510_UWIRE_SDO);
++ omap_cfg_reg(U18_1510_UWIRE_SDI);
++ }
+
+ return 0;
+ }
+@@ -243,5 +282,5 @@
+
+ MODULE_AUTHOR("Texas Instruments");
+ MODULE_DESCRIPTION
+- ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
++ ("Glue audio driver for the TI OMAP1510/1610/OMAP1710 TSC2101 codec.");
+ MODULE_LICENSE("GPL");
+diff -Naur linux-2.6.14-omap2/drivers/ssi/omap-uwire.c linux-h6300-omap2-2.6.14.3/drivers/ssi/omap-uwire.c
+--- linux-2.6.14-omap2/drivers/ssi/omap-uwire.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/ssi/omap-uwire.c 2005-08-12 13:46:22.000000000 +0300
+@@ -212,6 +212,10 @@
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+ omap_cfg_reg(P15_1610_UWIRE_CS3);
+ }
++ if (machine_is_h6300 ()) {
++ omap_cfg_reg(N14_1510_UWIRE_CS0);
++ omap_cfg_reg(P15_1510_UWIRE_CS3);
++ }
+ if (machine_is_omap_perseus2()) {
+ /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+ int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+diff -Naur linux-2.6.14-omap2/drivers/telephony/Kconfig linux-h6300-omap2-2.6.14.3/drivers/telephony/Kconfig
+--- linux-2.6.14-omap2/drivers/telephony/Kconfig 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/telephony/Kconfig 2005-10-06 02:34:39.000000000 +0300
+@@ -41,7 +41,18 @@
+ help
+ Say Y here to configure in PCMCIA service support for the Quicknet
+ cards manufactured by Quicknet Technologies, Inc. This changes the
+- card initialization code to work with the card manager daemon.
++ card initialization code to work with the card manager daemon.
++
++config GSM_H6300
++ tristate "H6300 P5186 GSM/GPRS DRIVER"
++ depends on PHONE && I2C && PCA9535
++ help
++ Bluetooth H6300 P5186 gsm/gprs driver.
++ This driver provides the firmware loading mechanism for the P5185
++ gsm/gprs hardware in iPAQ h6300.
++
++ Say Y here to compile support for P5186 gsm/gprs devices into the
++ kernel or say M to compile it as module (h6300_gsm).
+
+ endmenu
+
+diff -Naur linux-2.6.14-omap2/drivers/telephony/Makefile linux-h6300-omap2-2.6.14.3/drivers/telephony/Makefile
+--- linux-2.6.14-omap2/drivers/telephony/Makefile 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/telephony/Makefile 2005-10-06 02:34:39.000000000 +0300
+@@ -2,6 +2,7 @@
+ # Makefile for drivers/telephony
+ #
+
+-obj-$(CONFIG_PHONE) += phonedev.o
+-obj-$(CONFIG_PHONE_IXJ) += ixj.o
+-obj-$(CONFIG_PHONE_IXJ_PCMCIA) += ixj_pcmcia.o
++obj-$(CONFIG_PHONE) += phonedev.o
++obj-$(CONFIG_PHONE_IXJ) += ixj.o
++obj-$(CONFIG_PHONE_IXJ_PCMCIA) += ixj_pcmcia.o
++obj-$(CONFIG_GSM_H6300) += omap/
+diff -Naur linux-2.6.14-omap2/drivers/telephony/omap/h6300_gsm_led.c linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/h6300_gsm_led.c
+--- linux-2.6.14-omap2/drivers/telephony/omap/h6300_gsm_led.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/h6300_gsm_led.c 2005-10-06 02:34:39.000000000 +0300
+@@ -0,0 +1,40 @@
++/*
++ * GSM interface driver helper for controlling bluetooth leds available in iPAQ h6300.
++ *
++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
++ *
++ * 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/kernel.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++
++#include <asm/hardware.h>
++#include <asm/arch/gpio.h>
++
++/*
++ * Low level access for disabling h6300 gsm led.
++ *
++ * TODO: implement for h6300
++ */
++void h6300_clear_gsm_led(int led_num)
++{
++ printk(KERN_NOTICE "h6300_gsm_led.c h6300_clear_gsm_led() done\n");
++ //hx4700_set_led(led_num, 0, 16);
++}
++EXPORT_SYMBOL(h6300_clear_gsm_led);
++
++/*
++ * Low level access for setting up the gsm led.
++ *
++ * TODO: implement for h6300
++ */
++void h6300_set_gsm_led(int led_num, int duty_time, int cycle_time)
++{
++ printk(KERN_NOTICE "h6300_gsm_led.c h6300_set_gsm_led() done\n");
++}
++EXPORT_SYMBOL(h6300_set_gsm_led);
+diff -Naur linux-2.6.14-omap2/drivers/telephony/omap/h6300_gsm_led.h linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/h6300_gsm_led.h
+--- linux-2.6.14-omap2/drivers/telephony/omap/h6300_gsm_led.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/h6300_gsm_led.h 2005-10-06 02:34:39.000000000 +0300
+@@ -0,0 +1,10 @@
++#ifndef H6300_GSM_LED_H_
++#define H6300_GSM_LED_H_
++
++#define INDEX_GSM_LED 1
++
++void h6300_clear_gsm_led(int led_num);
++void h6300_set_gsm_led(int led_num, int duty_time, int cycle_time);
++
++
++#endif /*H6300_GSM_LED_H_*/
+diff -Naur linux-2.6.14-omap2/drivers/telephony/omap/h6300_gsm_p5186.c linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/h6300_gsm_p5186.c
+--- linux-2.6.14-omap2/drivers/telephony/omap/h6300_gsm_p5186.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/h6300_gsm_p5186.c 2005-10-20 20:57:07.000000000 +0300
+@@ -0,0 +1,171 @@
++/*
++ * Wavecom P5186 GPRS and GSM module driver for iPAQ h6300.
++ *
++ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi>
++ *
++ * 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/kernel.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++
++#include <asm/hardware.h>
++#include <asm/arch/gpio.h>
++
++#include <asm/arch/pca9535.h>
++#include <asm/arch/h6300_uart_info.h>
++#include "h6300_gsm_led.h"
++
++static void
++h6300_gsm_configure(struct uart_omap_port *up, int enable)
++{
++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_configure() started, enable = %d\n", enable);
++
++ // printk( KERN_NOTICE "h6300 configure bluetooth: %d\n", enable );
++ if (enable == 0) {
++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_OFF); // turn off gpio
++ mdelay(5);
++ h6300_clear_gsm_led(INDEX_GSM_LED);
++ }
++ else if (enable == 1) {
++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_ON); // turn on gpio
++ mdelay(5);
++ }
++ else if (enable == 2) {
++ h6300_set_gsm_led(INDEX_GSM_LED, 16, 16);
++ }
++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_configure() done\n");
++}
++
++static void
++h6300_gsm_set_txrx(struct uart_omap_port *up, int txrx)
++{
++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_set_txrx(), txrx = %d done\n", txrx);
++ /* do nothing */
++}
++
++static int
++h6300_gsm_get_txrx(struct uart_omap_port *up)
++{
++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_get_txrx() done\n");
++ /* do nothing */
++ return 0;
++}
++
++static int
++h6300_gsm_probe(struct device *dev)
++{
++ int ii;
++ int curVal;
++
++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
++/*
++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_probe() started\n");
++ for (ii = 0; ii < 8; ii++)
++ {
++ curVal = pca9535_gpio_read(ii);
++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
++ }
++ for (ii = 10; ii < 18; ii++)
++ {
++ curVal = pca9535_gpio_read(ii);
++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
++ }
++ printk(KERN_NOTICE "\nfirst check done\n");
++*/
++ pca9535_gpio_direction(GPIO_I2C_GPRS_RESET, GPIO_DIR_OUTPUT); // set gpio direction to be output
++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, GPIO_VALUE_ON); // turn on gpio
++ mdelay(200);
++
++ pca9535_gpio_direction(GPIO_I2C_MIC_OP_EN, GPIO_DIR_OUTPUT); // set gpio direction to be output
++ pca9535_gpio_write(GPIO_I2C_MIC_OP_EN, GPIO_VALUE_ON); // turn on gpio
++ mdelay(200);
++
++ pca9535_gpio_direction(GPIO_I2C_SPK_OP_PD, GPIO_DIR_OUTPUT); // set gpio direction to be output
++ pca9535_gpio_write(GPIO_I2C_SPK_OP_PD, GPIO_VALUE_ON); // pd = pulldown?, normal off = on
++
++ mdelay(200);
++
++ //pca9535_gpio_direction(
++ /* configure bluetooth UART */
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_RXD_MD);
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_TXD_MD);
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_CTS_MD);
++ //h6300_gpio_mode(GPIO_NR_H6300_BT_UART_RTS_MD);
++
++ funcs->configure = h6300_gsm_configure;
++ funcs->set_txrx = h6300_gsm_set_txrx;
++ funcs->get_txrx = h6300_gsm_get_txrx;
++
++ /* Make sure the LED is off */
++ h6300_clear_gsm_led(INDEX_GSM_LED);
++/*
++ for (ii = 0; ii < 8; ii++)
++ {
++ curVal = pca9535_gpio_read(ii);
++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
++ }
++ for (ii = 10; ii < 18; ii++)
++ {
++ curVal = pca9535_gpio_read(ii);
++ printk(KERN_NOTICE "I2C[%d] = %d ", ii, curVal);
++ }
++*/
++ printk(KERN_NOTICE "\nh6300_gsm_p5186.c h6300_gsm_probe() done\n");
++
++ return 0;
++}
++
++static int
++h6300_gsm_remove(struct device *dev)
++{
++ struct h6300_uart_funcs *funcs = (struct h6300_uart_funcs *)dev->platform_data;
++
++ printk(KERN_NOTICE "h6300_gsm_p5186.c h6300_gsm_remove() started\n");
++
++ pca9535_gpio_write(GPIO_I2C_GPRS_RESET, 0); // turn off gpio
++
++ funcs->configure = NULL;
++ funcs->set_txrx = NULL;
++ funcs->get_txrx = NULL;
++
++ /* Make sure the LED is off */
++ h6300_clear_gsm_led(INDEX_GSM_LED);
++
++ printk(KERN_NOTICE "h6300_gsm_p5186.c, h6300_gsm_remove() done\n");
++
++ return 0;
++}
++
++static struct device_driver gsm_driver = {
++ .name = "h6300_gsm",
++ .bus = &platform_bus_type,
++ .probe = h6300_gsm_probe,
++ .remove = h6300_gsm_remove,
++};
++
++static int __init
++h6300_gsm_init(void)
++{
++ printk(KERN_NOTICE "h6300 GSM Driver init()\n");
++ return driver_register(&gsm_driver);
++}
++
++static void __exit
++h6300_gsm_exit(void)
++{
++ printk(KERN_NOTICE "h6300 GSM Driver exit()\n");
++ driver_unregister(&gsm_driver);
++}
++
++module_init(h6300_gsm_init);
++module_exit(h6300_gsm_exit);
++
++MODULE_AUTHOR("Mika Laitio, <lamikr@cc.jyu.fi>");
++MODULE_DESCRIPTION("iPAQ h6300 Wavecom P5186 GPRS and GSM module driver.");
++MODULE_LICENSE("GPL");
++
+diff -Naur linux-2.6.14-omap2/drivers/telephony/omap/Makefile linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/Makefile
+--- linux-2.6.14-omap2/drivers/telephony/omap/Makefile 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/telephony/omap/Makefile 2005-10-06 02:34:39.000000000 +0300
+@@ -0,0 +1,6 @@
++#
++# Makefile for the Linux iPAQ H6300 BRF6100 Bluetooth device drivers.
++#
++
++h6300_gsm-objs := h6300_gsm_led.o h6300_gsm_p5186.o
++obj-$(CONFIG_GSM_H6300) += h6300_gsm.o
+diff -Naur linux-2.6.14-omap2/drivers/usb/core/sysfs.c linux-h6300-omap2-2.6.14.3/drivers/usb/core/sysfs.c
+--- linux-2.6.14-omap2/drivers/usb/core/sysfs.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/usb/core/sysfs.c 2005-11-23 01:44:02.000000000 +0200
+@@ -292,30 +292,23 @@
+ {
+ struct usb_interface *intf;
+ struct usb_device *udev;
+- int len;
++ struct usb_host_interface *alt;
+
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
++ alt = intf->cur_altsetting;
+
+- len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic",
+- le16_to_cpu(udev->descriptor.idVendor),
+- le16_to_cpu(udev->descriptor.idProduct),
+- le16_to_cpu(udev->descriptor.bcdDevice),
+- udev->descriptor.bDeviceClass,
+- udev->descriptor.bDeviceSubClass,
+- udev->descriptor.bDeviceProtocol);
+- buf += len;
+-
+- if (udev->descriptor.bDeviceClass == 0) {
+- struct usb_host_interface *alt = intf->cur_altsetting;
+-
+- return len + sprintf(buf, "%02Xisc%02Xip%02X\n",
+- alt->desc.bInterfaceClass,
+- alt->desc.bInterfaceSubClass,
+- alt->desc.bInterfaceProtocol);
+- } else {
+- return len + sprintf(buf, "*isc*ip*\n");
+- }
++ return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
++ "ic%02Xisc%02Xip%02X\n",
++ le16_to_cpu(udev->descriptor.idVendor),
++ le16_to_cpu(udev->descriptor.idProduct),
++ le16_to_cpu(udev->descriptor.bcdDevice),
++ udev->descriptor.bDeviceClass,
++ udev->descriptor.bDeviceSubClass,
++ udev->descriptor.bDeviceProtocol,
++ alt->desc.bInterfaceClass,
++ alt->desc.bInterfaceSubClass,
++ alt->desc.bInterfaceProtocol);
+ }
+ static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+
+diff -Naur linux-2.6.14-omap2/drivers/usb/core/usb.c linux-h6300-omap2-2.6.14.3/drivers/usb/core/usb.c
+--- linux-2.6.14-omap2/drivers/usb/core/usb.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/drivers/usb/core/usb.c 2005-11-23 01:44:02.000000000 +0200
+@@ -557,6 +557,7 @@
+ {
+ struct usb_interface *intf;
+ struct usb_device *usb_dev;
++ struct usb_host_interface *alt;
+ int i = 0;
+ int length = 0;
+
+@@ -573,7 +574,8 @@
+
+ intf = to_usb_interface(dev);
+ usb_dev = interface_to_usbdev (intf);
+-
++ alt = intf->cur_altsetting;
++
+ if (usb_dev->devnum < 0) {
+ pr_debug ("usb %s: already deleted?\n", dev->bus_id);
+ return -ENODEV;
+@@ -615,46 +617,27 @@
+ usb_dev->descriptor.bDeviceProtocol))
+ return -ENOMEM;
+
+- if (usb_dev->descriptor.bDeviceClass == 0) {
+- struct usb_host_interface *alt = intf->cur_altsetting;
++ if (add_hotplug_env_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "INTERFACE=%d/%d/%d",
++ alt->desc.bInterfaceClass,
++ alt->desc.bInterfaceSubClass,
++ alt->desc.bInterfaceProtocol))
++ return -ENOMEM;
+
+- /* 2.4 only exposed interface zero. in 2.5, hotplug
+- * agents are called for all interfaces, and can use
+- * $DEVPATH/bInterfaceNumber if necessary.
+- */
+- if (add_hotplug_env_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "INTERFACE=%d/%d/%d",
+- alt->desc.bInterfaceClass,
+- alt->desc.bInterfaceSubClass,
+- alt->desc.bInterfaceProtocol))
+- return -ENOMEM;
+-
+- if (add_hotplug_env_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+- le16_to_cpu(usb_dev->descriptor.idVendor),
+- le16_to_cpu(usb_dev->descriptor.idProduct),
+- le16_to_cpu(usb_dev->descriptor.bcdDevice),
+- usb_dev->descriptor.bDeviceClass,
+- usb_dev->descriptor.bDeviceSubClass,
+- usb_dev->descriptor.bDeviceProtocol,
+- alt->desc.bInterfaceClass,
+- alt->desc.bInterfaceSubClass,
+- alt->desc.bInterfaceProtocol))
+- return -ENOMEM;
+- } else {
+- if (add_hotplug_env_var(envp, num_envp, &i,
+- buffer, buffer_size, &length,
+- "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*",
+- le16_to_cpu(usb_dev->descriptor.idVendor),
+- le16_to_cpu(usb_dev->descriptor.idProduct),
+- le16_to_cpu(usb_dev->descriptor.bcdDevice),
+- usb_dev->descriptor.bDeviceClass,
+- usb_dev->descriptor.bDeviceSubClass,
+- usb_dev->descriptor.bDeviceProtocol))
+- return -ENOMEM;
+- }
++ if (add_hotplug_env_var(envp, num_envp, &i,
++ buffer, buffer_size, &length,
++ "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
++ le16_to_cpu(usb_dev->descriptor.idVendor),
++ le16_to_cpu(usb_dev->descriptor.idProduct),
++ le16_to_cpu(usb_dev->descriptor.bcdDevice),
++ usb_dev->descriptor.bDeviceClass,
++ usb_dev->descriptor.bDeviceSubClass,
++ usb_dev->descriptor.bDeviceProtocol,
++ alt->desc.bInterfaceClass,
++ alt->desc.bInterfaceSubClass,
++ alt->desc.bInterfaceProtocol))
++ return -ENOMEM;
+
+ envp[i] = NULL;
+
+diff -Naur linux-2.6.14-omap2/drivers/usb/gadget/omap_udc.c linux-h6300-omap2-2.6.14.3/drivers/usb/gadget/omap_udc.c
+--- linux-2.6.14-omap2/drivers/usb/gadget/omap_udc.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/usb/gadget/omap_udc.c 2005-11-11 04:13:42.000000000 +0200
+@@ -59,7 +59,8 @@
+ #undef USB_TRACE
+
+ /* bulk DMA seems to be behaving for both IN and OUT */
+-#define USE_DMA
++//#define USE_DMA
++#undef USE_DMA
+
+ /* ISO too */
+ #define USE_ISO
+@@ -2109,7 +2110,7 @@
+ /* boards that don't have VBUS sensing can't autogate 48MHz;
+ * can't enter deep sleep while a gadget driver is active.
+ */
+- if (machine_is_omap_innovator() || machine_is_omap_osk())
++ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_h6300())
+ omap_vbus_session(&udc->gadget, 1);
+
+ done:
+@@ -2127,7 +2128,7 @@
+ if (!driver || driver != udc->driver)
+ return -EINVAL;
+
+- if (machine_is_omap_innovator() || machine_is_omap_osk())
++ if (machine_is_omap_innovator() || machine_is_omap_osk() || machine_is_h6300())
+ omap_vbus_session(&udc->gadget, 0);
+
+ if (udc->transceiver)
+@@ -2735,7 +2736,7 @@
+ hmc = HMC_1510;
+ type = "(unknown)";
+
+- if (machine_is_omap_innovator()) {
++ if (machine_is_omap_innovator() || machine_is_h6300()) {
+ /* just set up software VBUS detect, and then
+ * later rig it so we always report VBUS.
+ * FIXME without really sensing VBUS, we can't
+diff -Naur linux-2.6.14-omap2/drivers/video/omap/lcd_h6300.c linux-h6300-omap2-2.6.14.3/drivers/video/omap/lcd_h6300.c
+--- linux-2.6.14-omap2/drivers/video/omap/lcd_h6300.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/video/omap/lcd_h6300.c 2005-11-11 04:13:42.000000000 +0200
+@@ -0,0 +1,107 @@
++/*
++ * File: drivers/video/omap_new/lcd-h6300.c
++ *
++ * LCD panel support for the TI OMAP1510 Innovator board
++ *
++ * Copyright (C) 2004 Nokia Corporation
++ * Author: Imre Deak <imre.deak@nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <linux/module.h>
++#include <asm/io.h>
++
++#include <asm/hardware/clock.h>
++#include <asm/arch/omapfb.h>
++
++/* #define OMAPFB_DBG 1 */
++
++#include "debug.h"
++
++//static struct clk *h6300_lcd_ck;
++
++static int h6300_panel_init(struct omapfb_device *fbdev)
++{
++ DBGENTER(1);
++/*
++ if ((h6300_lcd_ck = clk_get (NULL, "lcd_ck")) == NULL) {
++ printk(KERN_ERR "Unable to get the clock LCD_CK!!!\n");
++ return -EPERM;
++ } clk_enable(h6300_lcd_ck);
++*/
++ DBGLEAVE(1);
++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_init() done\n");
++ return 0;
++}
++
++static void h6300_panel_cleanup(void)
++{
++ DBGENTER(1);
++/*
++ if (h6300_lcd_ck) {
++ clk_disable(h6300_lcd_ck);
++ clk_put (h6300_lcd_ck);
++ h6300_lcd_ck = NULL;
++ }
++*/
++ DBGLEAVE(1);
++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_cleanup() done\n");
++}
++
++static int h6300_panel_enable(void)
++{
++ DBGENTER(1);
++ DBGLEAVE(1);
++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_enable() done\n");
++ return 0;
++}
++
++static void h6300_panel_disable(void)
++{
++ DBGENTER(1);
++ DBGLEAVE(1);
++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_disable() done\n");
++}
++
++static unsigned long h6300_panel_get_caps(void)
++{
++ printk(KERN_INFO "lcd_h6300.c: h6300_panel_get_caps() called\n");
++ return 0;
++}
++
++struct lcd_panel h6300_panel = {
++ .name = "h6300",
++ .config = OMAP_LCDC_PANEL_TFT,
++
++ .bpp = 16,
++ .data_lines = 16,
++ .x_res = 240,
++ .y_res = 320,
++ .pixel_clock = 21000,
++ .hsw = 12,
++ .hfp = 10,
++ .hbp = 10,
++ .vsw = 3,
++ .vfp = 10,
++ .vbp = 3,
++ .pcd = 0,
++
++ .init = h6300_panel_init,
++ .cleanup = h6300_panel_cleanup,
++ .enable = h6300_panel_enable,
++ .disable = h6300_panel_disable,
++ .get_caps = h6300_panel_get_caps,
++};
+diff -Naur linux-2.6.14-omap2/drivers/video/omap/Makefile linux-h6300-omap2-2.6.14.3/drivers/video/omap/Makefile
+--- linux-2.6.14-omap2/drivers/video/omap/Makefile 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/video/omap/Makefile 2005-10-22 03:52:45.000000000 +0300
+@@ -21,6 +21,7 @@
+ objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
+ objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
+ objs-y$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o
++objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_H6300) += lcd_h6300.o
+
+ omapfb-objs := $(objs-yy)
+
+diff -Naur linux-2.6.14-omap2/drivers/video/omap/omapfb_main.c linux-h6300-omap2-2.6.14.3/drivers/video/omap/omapfb_main.c
+--- linux-2.6.14-omap2/drivers/video/omap/omapfb_main.c 2005-12-02 01:53:33.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/drivers/video/omap/omapfb_main.c 2005-10-24 19:16:46.000000000 +0300
+@@ -89,6 +89,7 @@
+ extern struct lcd_panel innovator1610_panel;
+ extern struct lcd_panel innovator1510_panel;
+ extern struct lcd_panel lph8923_panel;
++extern struct lcd_panel h6300_panel;
+
+ static struct lcd_panel *panels[] = {
+ #ifdef CONFIG_MACH_OMAP_H2
+@@ -109,6 +110,9 @@
+ #ifdef CONFIG_MACH_OMAP_PALMTE
+ &palmte_panel,
+ #endif
++#ifdef CONFIG_MACH_OMAP_H6300
++ &h6300_panel,
++#endif
+
+ #ifdef CONFIG_MACH_OMAP_INNOVATOR
+
+diff -Naur linux-2.6.14-omap2/fs/exec.c linux-h6300-omap2-2.6.14.3/fs/exec.c
+--- linux-2.6.14-omap2/fs/exec.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/fs/exec.c 2005-11-23 01:44:02.000000000 +0200
+@@ -593,6 +593,7 @@
+ struct signal_struct *sig = tsk->signal;
+ struct sighand_struct *newsighand, *oldsighand = tsk->sighand;
+ spinlock_t *lock = &oldsighand->siglock;
++ struct task_struct *leader = NULL;
+ int count;
+
+ /*
+@@ -668,7 +669,7 @@
+ * and to assume its PID:
+ */
+ if (!thread_group_leader(current)) {
+- struct task_struct *leader = current->group_leader, *parent;
++ struct task_struct *parent;
+ struct dentry *proc_dentry1, *proc_dentry2;
+ unsigned long exit_state, ptrace;
+
+@@ -677,6 +678,7 @@
+ * It should already be zombie at this point, most
+ * of the time.
+ */
++ leader = current->group_leader;
+ while (leader->exit_state != EXIT_ZOMBIE)
+ yield();
+
+@@ -736,7 +738,6 @@
+ proc_pid_flush(proc_dentry2);
+
+ BUG_ON(exit_state != EXIT_ZOMBIE);
+- release_task(leader);
+ }
+
+ /*
+@@ -746,8 +747,11 @@
+ sig->flags = 0;
+
+ no_thread_group:
+- BUG_ON(atomic_read(&sig->count) != 1);
+ exit_itimers(sig);
++ if (leader)
++ release_task(leader);
++
++ BUG_ON(atomic_read(&sig->count) != 1);
+
+ if (atomic_read(&oldsighand->count) == 1) {
+ /*
+diff -Naur linux-2.6.14-omap2/fs/locks.c linux-h6300-omap2-2.6.14.3/fs/locks.c
+--- linux-2.6.14-omap2/fs/locks.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/fs/locks.c 2005-12-02 01:34:35.000000000 +0200
+@@ -1418,7 +1418,7 @@
+ lock_kernel();
+
+ error = __setlease(filp, arg, &flp);
+- if (error)
++ if (error || arg == F_UNLCK)
+ goto out_unlock;
+
+ error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
+diff -Naur linux-2.6.14-omap2/fs/xfs/Kconfig linux-h6300-omap2-2.6.14.3/fs/xfs/Kconfig
+--- linux-2.6.14-omap2/fs/xfs/Kconfig 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/fs/xfs/Kconfig 2005-11-23 01:44:02.000000000 +0200
+@@ -24,7 +24,7 @@
+ default y
+
+ config XFS_QUOTA
+- tristate "XFS Quota support"
++ bool "XFS Quota support"
+ depends on XFS_FS
+ help
+ If you say Y here, you will be able to set limits for disk usage on
+diff -Naur linux-2.6.14-omap2/include/asm-alpha/barrier.h linux-h6300-omap2-2.6.14.3/include/asm-alpha/barrier.h
+--- linux-2.6.14-omap2/include/asm-alpha/barrier.h 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/include/asm-alpha/barrier.h 2005-11-23 01:44:02.000000000 +0200
+@@ -1,6 +1,8 @@
+ #ifndef __BARRIER_H
+ #define __BARRIER_H
+
++#include <asm/compiler.h>
++
+ #define mb() \
+ __asm__ __volatile__("mb": : :"memory")
+
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/board-h6300.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/board-h6300.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/board-h6300.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/board-h6300.h 2005-08-12 13:46:22.000000000 +0300
+@@ -0,0 +1,40 @@
++/*
++ * linux/include/asm-arm/arch-omap/board-innovator.h
++ *
++ * Copyright (C) 2001 RidgeRun, 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#ifndef __ASM_ARCH_H6300_H
++#define __ASM_ARCH_H6300_H
++
++#ifndef OMAP_SDRAM_DEVICE
++#define OMAP_SDRAM_DEVICE D256M_1X16_4B
++#endif
++
++#define OMAP1510P1_IMIF_PRI_VALUE 0x00
++#define OMAP1510P1_EMIFS_PRI_VALUE 0x00
++#define OMAP1510P1_EMIFF_PRI_VALUE 0x00
++
++#define NR_FPGA_IRQS 24
++#define NR_IRQS IH_BOARD_BASE + NR_FPGA_IRQS
++
++#endif /* __ASM_ARCH_H6300_H */
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/h6300_uart_info.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/h6300_uart_info.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/h6300_uart_info.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/h6300_uart_info.h 2005-10-14 18:55:31.000000000 +0300
+@@ -0,0 +1,33 @@
++/*
++ * Support file for calling h6300 uart configuration functions.
++ * Used at least by h6300_bt driver.
++ *
++ * Copyright (c) 2005 SDG Systems, LLC
++ * 2005-03-29 Todd Blumer Converted basic structure to support hx4700
++ * 2005-10-03 Mika Laitio (lamikr@cc.jyu.fi) Reorganized for the iPAQ h6300 bt driver.
++ */
++
++#ifndef _H6300_UART_INFO_H
++#define _H6300_UART_INFO_H
++
++#include "omap_serial.h"
++
++#define GPIO_BT_PWR_EN 3
++#define GPIO_N_BT_RST 9
++
++#define GPIO_I2C_GPRS_RESET 16
++#define GPIO_I2C_MIC_OP_EN 10
++#define GPIO_I2C_SPK_OP_PD 11
++
++#define GPIO_VALUE_OFF 0
++#define GPIO_VALUE_ON 1
++
++#define GPIO_DIR_OUTPUT 1
++
++struct h6300_uart_funcs {
++ void (*configure)( struct uart_omap_port *up, int state);
++ void (*set_txrx)( struct uart_omap_port *up, int txrx);
++ int (*get_txrx)( struct uart_omap_port *up);
++};
++
++#endif
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/hardware.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/hardware.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/hardware.h 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/hardware.h 2005-10-22 03:52:45.000000000 +0300
+@@ -290,6 +290,10 @@
+ #include "board-innovator.h"
+ #endif
+
++#ifdef CONFIG_MACH_OMAP_H6300
++#include "board-h6300.h"
++#endif
++
+ #ifdef CONFIG_MACH_OMAP_H2
+ #include "board-h2.h"
+ #endif
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/irqs.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/irqs.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/irqs.h 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/irqs.h 2005-11-11 04:13:42.000000000 +0200
+@@ -237,7 +237,7 @@
+ #define INT_24XX_SDMA_IRQ1 13
+ #define INT_24XX_SDMA_IRQ2 14
+ #define INT_24XX_SDMA_IRQ3 15
+-#define INT_24XX_DSS_IRQ 25
++#define INT_24XX_DSS_IRQ 25
+ #define INT_24XX_GPIO_BANK1 29
+ #define INT_24XX_GPIO_BANK2 30
+ #define INT_24XX_GPIO_BANK3 31
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/mux.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/mux.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/mux.h 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/mux.h 2005-10-14 18:55:31.000000000 +0300
+@@ -316,6 +316,13 @@
+ P15_1610_UWIRE_CS3,
+ N15_1610_UWIRE_CS1,
+
++ /* OMAP-1510 uWire */
++ P15_1510_UWIRE_CS3,
++ N14_1510_UWIRE_CS0,
++ V19_1510_UWIRE_SCLK,
++ W21_1510_UWIRE_SDO,
++ U18_1510_UWIRE_SDI,
++
+ /* OMAP-1610 Flash */
+ L3_1610_FLASH_CS2B_OE,
+ M8_1610_FLASH_CS2B_WE,
+@@ -380,6 +387,7 @@
+ T20_1610_LOW_PWR,
+
+ /* MCLK Settings */
++ R10_1510_MCLK_ON,
+ V5_1710_MCLK_ON,
+ V5_1710_MCLK_OFF,
+ R10_1610_MCLK_ON,
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/omapfb.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/omapfb.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/omapfb.h 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/omapfb.h 2005-11-11 04:13:42.000000000 +0200
+@@ -267,6 +267,7 @@
+ extern struct lcd_panel osk_panel;
+ extern struct lcd_panel innovator1610_panel;
+ extern struct lcd_panel innovator1510_panel;
++extern struct lcd_panel h6300_panel;
+
+ #ifdef CONFIG_ARCH_OMAP1
+ extern struct lcd_ctrl omap1_lcd_ctrl;
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/omap_serial.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/omap_serial.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/omap_serial.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/omap_serial.h 2005-10-04 00:58:34.000000000 +0300
+@@ -0,0 +1,62 @@
++/*
++ * Omap/h6300 serial driver private interface.
++ * Code originates from the pxa-serial.h available in the handheld org drivers
++ * for iPAQ PXA4700.
++ *
++ * Copyright (c) 2005 SDG Systems, LLC
++ * 2005-03-29 Todd Blumer Converted basic structure to support hx4700
++ * 2005-10-03 Mika Laitio (lamikr@cc.jyu.fi) Reorganized for the iPAQ h6300 bt driver.
++ */
++
++#ifndef _OMAP_SERIAL_H
++#define _OMAP_SERIAL_H
++
++#define OMAP_SERIAL_TX 1
++#define OMAP_SERIAL_RX 2
++
++#include <linux/tty.h>
++#include <linux/serial_core.h>
++
++struct platform_omap_serial_funcs;
++
++struct uart_omap_port {
++ struct uart_port port;
++ unsigned char ier;
++ unsigned char lcr;
++ unsigned char mcr;
++ unsigned int lsr_break_flag;
++ unsigned int cken;
++ char *name;
++ struct platform_omap_serial_funcs *pf;
++};
++
++/* A pointer to such a structure can be contained in the platform_data
++ * field of every PXA UART platform_device. If the field is NULL, the
++ * serial port works as usual.
++ *
++ * For the sake of simplicity/performance no one of the function pointers
++ * in the structure below can be NULL.
++ */
++struct platform_omap_serial_funcs {
++ /* Platform-specific function to initialize whatever is connected
++ to this serial port... enable=1 -> enable transceiver,
++ 0 -> disable transceiver. */
++ void (*configure) (struct uart_omap_port *up, int enable);
++ /* Platform-specific function to enable or disable the individual
++ transmitter/receiver submodules. On transceivers without echo
++ cancellation (e.g. SIR) transmitter always has priority, e.g.
++ if both bits are set, only the transmitter is enabled. */
++ void (*set_txrx) (struct uart_omap_port *up, int txrx);
++ /* Get the current state of tx/rx (see bitflags above) */
++ int (*get_txrx) (struct uart_omap_port *up);
++};
++
++/*
++ * The variables below are located in arch/arm/mach-omap/board_h6300.c
++ * Machine-specific code may want to put a pointer to a static
++ * platform_pxa_serial_funcs structure in the dev.platform_data
++ * field of the respective port device.
++ */
++extern struct platform_device btuart_device;
++
++#endif
+diff -Naur linux-2.6.14-omap2/include/asm-arm/arch-omap/pca9535.h linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/pca9535.h
+--- linux-2.6.14-omap2/include/asm-arm/arch-omap/pca9535.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/include/asm-arm/arch-omap/pca9535.h 2005-10-25 03:24:45.000000000 +0300
+@@ -0,0 +1,39 @@
++#ifndef _PCA9535_H
++#define _PCA9535_H
++
++enum pca9535_gpios {
++ GPIO0 = 0,
++ GPIO1 = 1,
++ GPIO2 = 2,
++ GPIO3 = 3,
++ GPIO4 = 4,
++ GPIO5 = 5,
++ GPIO6 = 6,
++ GPIO7 = 7,
++ GPIO8 = 8,
++ GPIO9 = 9,
++ GPIO10 = 10,
++ GPIO11 = 11,
++ GPIO12 = 12,
++ GPIO13 = 13,
++ GPIO14 = 14,
++ GPIO15 = 15,
++ GPIO16 = 16,
++ GPIO17 = 17
++};
++
++enum gpio_values {
++ HI = 0,
++ LOW = 1
++};
++
++enum gpio_direction {
++ GPIO_INPUT = 0,
++ GPIO_OUTPUT = 1
++};
++
++extern int pca9535_gpio_read(int gpio);
++extern int pca9535_gpio_write(int gpio, unsigned char val);
++extern int pca9535_gpio_direction(int gpio, unsigned char direction);
++
++#endif
+diff -Naur linux-2.6.14-omap2/include/linux/proc_fs.h linux-h6300-omap2-2.6.14.3/include/linux/proc_fs.h
+--- linux-2.6.14-omap2/include/linux/proc_fs.h 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/include/linux/proc_fs.h 2005-11-23 01:44:02.000000000 +0200
+@@ -66,6 +66,7 @@
+ write_proc_t *write_proc;
+ atomic_t count; /* use count */
+ int deleted; /* delete flag */
++ void *set;
+ };
+
+ struct kcore_list {
+diff -Naur linux-2.6.14-omap2/include/linux/sysctl.h linux-h6300-omap2-2.6.14.3/include/linux/sysctl.h
+--- linux-2.6.14-omap2/include/linux/sysctl.h 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/include/linux/sysctl.h 2005-11-23 01:44:02.000000000 +0200
+@@ -24,6 +24,7 @@
+ #include <linux/compiler.h>
+
+ struct file;
++struct completion;
+
+ #define CTL_MAXNAME 10 /* how many path components do we allow in a
+ call to sysctl? In other words, what is
+@@ -925,6 +926,8 @@
+ {
+ ctl_table *ctl_table;
+ struct list_head ctl_entry;
++ int used;
++ struct completion *unregistering;
+ };
+
+ struct ctl_table_header * register_sysctl_table(ctl_table * table,
+diff -Naur linux-2.6.14-omap2/include/net/ipv6.h linux-h6300-omap2-2.6.14.3/include/net/ipv6.h
+--- linux-2.6.14-omap2/include/net/ipv6.h 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/include/net/ipv6.h 2005-12-02 01:34:35.000000000 +0200
+@@ -237,6 +237,8 @@
+ int newtype,
+ struct ipv6_opt_hdr __user *newopt,
+ int newoptlen);
++struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
++ struct ipv6_txoptions *opt);
+
+ extern int ip6_frag_nqueues;
+ extern atomic_t ip6_frag_mem;
+diff -Naur linux-2.6.14-omap2/kernel/ptrace.c linux-h6300-omap2-2.6.14.3/kernel/ptrace.c
+--- linux-2.6.14-omap2/kernel/ptrace.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/kernel/ptrace.c 2005-11-23 01:44:02.000000000 +0200
+@@ -152,7 +152,7 @@
+ retval = -EPERM;
+ if (task->pid <= 1)
+ goto bad;
+- if (task == current)
++ if (task->tgid == current->tgid)
+ goto bad;
+ /* the same process cannot be attached many times */
+ if (task->ptrace & PT_PTRACED)
+diff -Naur linux-2.6.14-omap2/kernel/signal.c linux-h6300-omap2-2.6.14.3/kernel/signal.c
+--- linux-2.6.14-omap2/kernel/signal.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/kernel/signal.c 2005-12-02 01:34:35.000000000 +0200
+@@ -406,6 +406,8 @@
+
+ void exit_signal(struct task_struct *tsk)
+ {
++ atomic_dec(&tsk->signal->live);
++
+ write_lock_irq(&tasklist_lock);
+ __exit_signal(tsk);
+ write_unlock_irq(&tasklist_lock);
+@@ -1522,7 +1524,7 @@
+
+ psig = tsk->parent->sighand;
+ spin_lock_irqsave(&psig->siglock, flags);
+- if (sig == SIGCHLD &&
++ if (!tsk->ptrace && sig == SIGCHLD &&
+ (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
+ (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) {
+ /*
+diff -Naur linux-2.6.14-omap2/kernel/sysctl.c linux-h6300-omap2-2.6.14.3/kernel/sysctl.c
+--- linux-2.6.14-omap2/kernel/sysctl.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/kernel/sysctl.c 2005-11-23 01:44:02.000000000 +0200
+@@ -169,7 +169,7 @@
+
+ extern struct proc_dir_entry *proc_sys_root;
+
+-static void register_proc_table(ctl_table *, struct proc_dir_entry *);
++static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *);
+ static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
+ #endif
+
+@@ -992,10 +992,51 @@
+
+ extern void init_irq_proc (void);
+
++static DEFINE_SPINLOCK(sysctl_lock);
++
++/* called under sysctl_lock */
++static int use_table(struct ctl_table_header *p)
++{
++ if (unlikely(p->unregistering))
++ return 0;
++ p->used++;
++ return 1;
++}
++
++/* called under sysctl_lock */
++static void unuse_table(struct ctl_table_header *p)
++{
++ if (!--p->used)
++ if (unlikely(p->unregistering))
++ complete(p->unregistering);
++}
++
++/* called under sysctl_lock, will reacquire if has to wait */
++static void start_unregistering(struct ctl_table_header *p)
++{
++ /*
++ * if p->used is 0, nobody will ever touch that entry again;
++ * we'll eliminate all paths to it before dropping sysctl_lock
++ */
++ if (unlikely(p->used)) {
++ struct completion wait;
++ init_completion(&wait);
++ p->unregistering = &wait;
++ spin_unlock(&sysctl_lock);
++ wait_for_completion(&wait);
++ spin_lock(&sysctl_lock);
++ }
++ /*
++ * do not remove from the list until nobody holds it; walking the
++ * list in do_sysctl() relies on that.
++ */
++ list_del_init(&p->ctl_entry);
++}
++
+ void __init sysctl_init(void)
+ {
+ #ifdef CONFIG_PROC_FS
+- register_proc_table(root_table, proc_sys_root);
++ register_proc_table(root_table, proc_sys_root, &root_table_header);
+ init_irq_proc();
+ #endif
+ }
+@@ -1004,6 +1045,7 @@
+ void __user *newval, size_t newlen)
+ {
+ struct list_head *tmp;
++ int error = -ENOTDIR;
+
+ if (nlen <= 0 || nlen >= CTL_MAXNAME)
+ return -ENOTDIR;
+@@ -1012,20 +1054,30 @@
+ if (!oldlenp || get_user(old_len, oldlenp))
+ return -EFAULT;
+ }
++ spin_lock(&sysctl_lock);
+ tmp = &root_table_header.ctl_entry;
+ do {
+ struct ctl_table_header *head =
+ list_entry(tmp, struct ctl_table_header, ctl_entry);
+ void *context = NULL;
+- int error = parse_table(name, nlen, oldval, oldlenp,
++
++ if (!use_table(head))
++ continue;
++
++ spin_unlock(&sysctl_lock);
++
++ error = parse_table(name, nlen, oldval, oldlenp,
+ newval, newlen, head->ctl_table,
+ &context);
+ kfree(context);
++
++ spin_lock(&sysctl_lock);
++ unuse_table(head);
+ if (error != -ENOTDIR)
+- return error;
+- tmp = tmp->next;
+- } while (tmp != &root_table_header.ctl_entry);
+- return -ENOTDIR;
++ break;
++ } while ((tmp = tmp->next) != &root_table_header.ctl_entry);
++ spin_unlock(&sysctl_lock);
++ return error;
+ }
+
+ asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
+@@ -1236,12 +1288,16 @@
+ return NULL;
+ tmp->ctl_table = table;
+ INIT_LIST_HEAD(&tmp->ctl_entry);
++ tmp->used = 0;
++ tmp->unregistering = NULL;
++ spin_lock(&sysctl_lock);
+ if (insert_at_head)
+ list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
+ else
+ list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
++ spin_unlock(&sysctl_lock);
+ #ifdef CONFIG_PROC_FS
+- register_proc_table(table, proc_sys_root);
++ register_proc_table(table, proc_sys_root, tmp);
+ #endif
+ return tmp;
+ }
+@@ -1255,10 +1311,13 @@
+ */
+ void unregister_sysctl_table(struct ctl_table_header * header)
+ {
+- list_del(&header->ctl_entry);
++ might_sleep();
++ spin_lock(&sysctl_lock);
++ start_unregistering(header);
+ #ifdef CONFIG_PROC_FS
+ unregister_proc_table(header->ctl_table, proc_sys_root);
+ #endif
++ spin_unlock(&sysctl_lock);
+ kfree(header);
+ }
+
+@@ -1269,7 +1328,7 @@
+ #ifdef CONFIG_PROC_FS
+
+ /* Scan the sysctl entries in table and add them all into /proc */
+-static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
++static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set)
+ {
+ struct proc_dir_entry *de;
+ int len;
+@@ -1305,13 +1364,14 @@
+ de = create_proc_entry(table->procname, mode, root);
+ if (!de)
+ continue;
++ de->set = set;
+ de->data = (void *) table;
+ if (table->proc_handler)
+ de->proc_fops = &proc_sys_file_operations;
+ }
+ table->de = de;
+ if (de->mode & S_IFDIR)
+- register_proc_table(table->child, de);
++ register_proc_table(table->child, de, set);
+ }
+ }
+
+@@ -1336,6 +1396,13 @@
+ continue;
+ }
+
++ /*
++ * In any case, mark the entry as goner; we'll keep it
++ * around if it's busy, but we'll know to do nothing with
++ * its fields. We are under sysctl_lock here.
++ */
++ de->data = NULL;
++
+ /* Don't unregister proc entries that are still being used.. */
+ if (atomic_read(&de->count))
+ continue;
+@@ -1349,27 +1416,38 @@
+ size_t count, loff_t *ppos)
+ {
+ int op;
+- struct proc_dir_entry *de;
++ struct proc_dir_entry *de = PDE(file->f_dentry->d_inode);
+ struct ctl_table *table;
+ size_t res;
+- ssize_t error;
+-
+- de = PDE(file->f_dentry->d_inode);
+- if (!de || !de->data)
+- return -ENOTDIR;
+- table = (struct ctl_table *) de->data;
+- if (!table || !table->proc_handler)
+- return -ENOTDIR;
+- op = (write ? 002 : 004);
+- if (ctl_perm(table, op))
+- return -EPERM;
++ ssize_t error = -ENOTDIR;
+
+- res = count;
+-
+- error = (*table->proc_handler) (table, write, file, buf, &res, ppos);
+- if (error)
+- return error;
+- return res;
++ spin_lock(&sysctl_lock);
++ if (de && de->data && use_table(de->set)) {
++ /*
++ * at that point we know that sysctl was not unregistered
++ * and won't be until we finish
++ */
++ spin_unlock(&sysctl_lock);
++ table = (struct ctl_table *) de->data;
++ if (!table || !table->proc_handler)
++ goto out;
++ error = -EPERM;
++ op = (write ? 002 : 004);
++ if (ctl_perm(table, op))
++ goto out;
++
++ /* careful: calling conventions are nasty here */
++ res = count;
++ error = (*table->proc_handler)(table, write, file,
++ buf, &res, ppos);
++ if (!error)
++ error = res;
++ out:
++ spin_lock(&sysctl_lock);
++ unuse_table(de->set);
++ }
++ spin_unlock(&sysctl_lock);
++ return error;
+ }
+
+ static int proc_opensys(struct inode *inode, struct file *file)
+diff -Naur linux-2.6.14-omap2/Makefile linux-h6300-omap2-2.6.14.3/Makefile
+--- linux-2.6.14-omap2/Makefile 2005-12-02 01:53:31.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/Makefile 2005-12-02 01:34:34.000000000 +0200
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 14
+-EXTRAVERSION =
++EXTRAVERSION = .3
+ NAME=Affluent Albatross
+
+ # *DOCUMENTATION*
+@@ -11,7 +11,7 @@
+ # expect to learn how to build the kernel reading this file.
+
+ # Add custom flags here to avoid conflict with updates
+-EXTRAVERSION := $(EXTRAVERSION)-omap2
++EXTRAVERSION := $(EXTRAVERSION)-omap1-h6300
+
+ # Do not print "Entering directory ..."
+ MAKEFLAGS += --no-print-directory
+diff -Naur linux-2.6.14-omap2/net/core/datagram.c linux-h6300-omap2-2.6.14.3/net/core/datagram.c
+--- linux-2.6.14-omap2/net/core/datagram.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/core/datagram.c 2005-11-23 01:44:02.000000000 +0200
+@@ -213,6 +213,10 @@
+ {
+ int i, err, fraglen, end = 0;
+ struct sk_buff *next = skb_shinfo(skb)->frag_list;
++
++ if (!len)
++ return 0;
++
+ next_skb:
+ fraglen = skb_headlen(skb);
+ i = -1;
+diff -Naur linux-2.6.14-omap2/net/ipv4/ipvs/ip_vs_core.c linux-h6300-omap2-2.6.14.3/net/ipv4/ipvs/ip_vs_core.c
+--- linux-2.6.14-omap2/net/ipv4/ipvs/ip_vs_core.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/ipvs/ip_vs_core.c 2005-11-23 01:44:02.000000000 +0200
+@@ -1009,11 +1009,10 @@
+ if (sysctl_ip_vs_expire_nodest_conn) {
+ /* try to expire the connection immediately */
+ ip_vs_conn_expire_now(cp);
+- } else {
+- /* don't restart its timer, and silently
+- drop the packet. */
+- __ip_vs_conn_put(cp);
+ }
++ /* don't restart its timer, and silently
++ drop the packet. */
++ __ip_vs_conn_put(cp);
+ return NF_DROP;
+ }
+
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_ftp.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_ftp.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_ftp.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_ftp.c 2005-12-02 01:34:35.000000000 +0200
+@@ -29,9 +29,9 @@
+ static DEFINE_SPINLOCK(ip_ftp_lock);
+
+ #define MAX_PORTS 8
+-static short ports[MAX_PORTS];
++static unsigned short ports[MAX_PORTS];
+ static int ports_c;
+-module_param_array(ports, short, &ports_c, 0400);
++module_param_array(ports, ushort, &ports_c, 0400);
+
+ static int loose;
+ module_param(loose, int, 0600);
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_irc.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_irc.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_irc.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_irc.c 2005-12-02 01:34:35.000000000 +0200
+@@ -34,7 +34,7 @@
+ #include <linux/moduleparam.h>
+
+ #define MAX_PORTS 8
+-static short ports[MAX_PORTS];
++static unsigned short ports[MAX_PORTS];
+ static int ports_c;
+ static int max_dcc_channels = 8;
+ static unsigned int dcc_timeout = 300;
+@@ -52,7 +52,7 @@
+ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+ MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
+ MODULE_LICENSE("GPL");
+-module_param_array(ports, short, &ports_c, 0400);
++module_param_array(ports, ushort, &ports_c, 0400);
+ MODULE_PARM_DESC(ports, "port numbers of IRC servers");
+ module_param(max_dcc_channels, int, 0400);
+ MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_netlink.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_netlink.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_netlink.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_netlink.c 2005-12-02 01:34:35.000000000 +0200
+@@ -58,14 +58,17 @@
+ const struct ip_conntrack_tuple *tuple)
+ {
+ struct ip_conntrack_protocol *proto;
++ int ret = 0;
+
+ NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
+
+ proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
+- if (proto && proto->tuple_to_nfattr)
+- return proto->tuple_to_nfattr(skb, tuple);
++ if (likely(proto && proto->tuple_to_nfattr)) {
++ ret = proto->tuple_to_nfattr(skb, tuple);
++ ip_conntrack_proto_put(proto);
++ }
+
+- return 0;
++ return ret;
+
+ nfattr_failure:
+ return -1;
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_proto_icmp.c 2005-12-02 01:34:35.000000000 +0200
+@@ -296,7 +296,8 @@
+ struct ip_conntrack_tuple *tuple)
+ {
+ if (!tb[CTA_PROTO_ICMP_TYPE-1]
+- || !tb[CTA_PROTO_ICMP_CODE-1])
++ || !tb[CTA_PROTO_ICMP_CODE-1]
++ || !tb[CTA_PROTO_ICMP_ID-1])
+ return -1;
+
+ tuple->dst.u.icmp.type =
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-12-02 01:34:35.000000000 +0200
+@@ -362,6 +362,11 @@
+ struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1];
+ struct nfattr *tb[CTA_PROTOINFO_TCP_MAX];
+
++ /* updates could not contain anything about the private
++ * protocol info, in that case skip the parsing */
++ if (!attr)
++ return 0;
++
+ if (nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr) < 0)
+ goto nfattr_failure;
+
+@@ -813,6 +818,7 @@
+ {
+ [TH_SYN] = 1,
+ [TH_SYN|TH_ACK] = 1,
++ [TH_SYN|TH_PUSH] = 1,
+ [TH_SYN|TH_ACK|TH_PUSH] = 1,
+ [TH_RST] = 1,
+ [TH_RST|TH_ACK] = 1,
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_tftp.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_tftp.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_conntrack_tftp.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_conntrack_tftp.c 2005-12-02 01:34:35.000000000 +0200
+@@ -26,9 +26,9 @@
+ MODULE_LICENSE("GPL");
+
+ #define MAX_PORTS 8
+-static short ports[MAX_PORTS];
++static unsigned short ports[MAX_PORTS];
+ static int ports_c;
+-module_param_array(ports, short, &ports_c, 0400);
++module_param_array(ports, ushort, &ports_c, 0400);
+ MODULE_PARM_DESC(ports, "port numbers of tftp servers");
+
+ #if 0
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_core.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_core.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_core.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_core.c 2005-12-02 01:34:35.000000000 +0200
+@@ -66,10 +66,8 @@
+ * removed until we've grabbed the reference */
+ preempt_disable();
+ p = __ip_nat_proto_find(protonum);
+- if (p) {
+- if (!try_module_get(p->me))
+- p = &ip_nat_unknown_protocol;
+- }
++ if (!try_module_get(p->me))
++ p = &ip_nat_unknown_protocol;
+ preempt_enable();
+
+ return p;
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_helper_pptp.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_helper_pptp.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_helper_pptp.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_helper_pptp.c 2005-12-02 01:34:35.000000000 +0200
+@@ -73,6 +73,7 @@
+ struct ip_conntrack_tuple t;
+ struct ip_ct_pptp_master *ct_pptp_info;
+ struct ip_nat_pptp *nat_pptp_info;
++ struct ip_nat_range range;
+
+ ct_pptp_info = &master->help.ct_pptp_info;
+ nat_pptp_info = &master->nat.help.nat_pptp_info;
+@@ -110,7 +111,30 @@
+ DEBUGP("not found!\n");
+ }
+
+- ip_nat_follow_master(ct, exp);
++ /* This must be a fresh one. */
++ BUG_ON(ct->status & IPS_NAT_DONE_MASK);
++
++ /* Change src to where master sends to */
++ range.flags = IP_NAT_RANGE_MAP_IPS;
++ range.min_ip = range.max_ip
++ = ct->master->tuplehash[!exp->dir].tuple.dst.ip;
++ if (exp->dir == IP_CT_DIR_ORIGINAL) {
++ range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
++ range.min = range.max = exp->saved_proto;
++ }
++ /* hook doesn't matter, but it has to do source manip */
++ ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
++
++ /* For DST manip, map port here to where it's expected. */
++ range.flags = IP_NAT_RANGE_MAP_IPS;
++ range.min_ip = range.max_ip
++ = ct->master->tuplehash[!exp->dir].tuple.src.ip;
++ if (exp->dir == IP_CT_DIR_REPLY) {
++ range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
++ range.min = range.max = exp->saved_proto;
++ }
++ /* hook doesn't matter, but it has to do destination manip */
++ ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+ }
+
+ /* outbound packets == from PNS to PAC */
+@@ -213,7 +237,7 @@
+
+ /* alter expectation for PNS->PAC direction */
+ invert_tuplepr(&inv_t, &expect_orig->tuple);
+- expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id);
++ expect_orig->saved_proto.gre.key = htons(ct_pptp_info->pns_call_id);
+ expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id);
+ expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);
+ inv_t.src.ip = reply_t->src.ip;
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_proto_gre.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_proto_gre.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_proto_gre.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_proto_gre.c 2005-12-02 01:34:35.000000000 +0200
+@@ -139,8 +139,8 @@
+ break;
+ case GRE_VERSION_PPTP:
+ DEBUGP("call_id -> 0x%04x\n",
+- ntohl(tuple->dst.u.gre.key));
+- pgreh->call_id = htons(ntohl(tuple->dst.u.gre.key));
++ ntohs(tuple->dst.u.gre.key));
++ pgreh->call_id = tuple->dst.u.gre.key;
+ break;
+ default:
+ DEBUGP("can't nat unknown GRE version\n");
+diff -Naur linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_proto_unknown.c linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_proto_unknown.c
+--- linux-2.6.14-omap2/net/ipv4/netfilter/ip_nat_proto_unknown.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/netfilter/ip_nat_proto_unknown.c 2005-12-02 01:34:35.000000000 +0200
+@@ -62,7 +62,7 @@
+
+ struct ip_nat_protocol ip_nat_unknown_protocol = {
+ .name = "unknown",
+- .me = THIS_MODULE,
++ /* .me isn't set: getting a ref to this cannot fail. */
+ .manip_pkt = unknown_manip_pkt,
+ .in_range = unknown_in_range,
+ .unique_tuple = unknown_unique_tuple,
+diff -Naur linux-2.6.14-omap2/net/ipv4/tcp_bic.c linux-h6300-omap2-2.6.14.3/net/ipv4/tcp_bic.c
+--- linux-2.6.14-omap2/net/ipv4/tcp_bic.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv4/tcp_bic.c 2005-11-23 01:44:02.000000000 +0200
+@@ -27,7 +27,7 @@
+ */
+
+ static int fast_convergence = 1;
+-static int max_increment = 32;
++static int max_increment = 16;
+ static int low_window = 14;
+ static int beta = 819; /* = 819/1024 (BICTCP_BETA_SCALE) */
+ static int low_utilization_threshold = 153;
+diff -Naur linux-2.6.14-omap2/net/ipv6/datagram.c linux-h6300-omap2-2.6.14.3/net/ipv6/datagram.c
+--- linux-2.6.14-omap2/net/ipv6/datagram.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv6/datagram.c 2005-12-02 01:34:35.000000000 +0200
+@@ -437,7 +437,7 @@
+ break;
+ case IPPROTO_AH:
+ nexthdr = ptr[0];
+- len = (ptr[1] + 1) << 2;
++ len = (ptr[1] + 2) << 2;
+ break;
+ default:
+ nexthdr = ptr[0];
+diff -Naur linux-2.6.14-omap2/net/ipv6/exthdrs.c linux-h6300-omap2-2.6.14.3/net/ipv6/exthdrs.c
+--- linux-2.6.14-omap2/net/ipv6/exthdrs.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv6/exthdrs.c 2005-12-02 01:34:35.000000000 +0200
+@@ -628,6 +628,7 @@
+ if (!tot_len)
+ return NULL;
+
++ tot_len += sizeof(*opt2);
+ opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
+ if (!opt2)
+ return ERR_PTR(-ENOBUFS);
+@@ -668,7 +669,26 @@
+
+ return opt2;
+ out:
+- sock_kfree_s(sk, p, tot_len);
++ sock_kfree_s(sk, opt2, opt2->tot_len);
+ return ERR_PTR(err);
+ }
+
++struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
++ struct ipv6_txoptions *opt)
++{
++ /*
++ * ignore the dest before srcrt unless srcrt is being included.
++ * --yoshfuji
++ */
++ if (opt && opt->dst0opt && !opt->srcrt) {
++ if (opt_space != opt) {
++ memcpy(opt_space, opt, sizeof(*opt_space));
++ opt = opt_space;
++ }
++ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
++ opt->dst0opt = NULL;
++ }
++
++ return opt;
++}
++
+diff -Naur linux-2.6.14-omap2/net/ipv6/ip6_flowlabel.c linux-h6300-omap2-2.6.14.3/net/ipv6/ip6_flowlabel.c
+--- linux-2.6.14-omap2/net/ipv6/ip6_flowlabel.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv6/ip6_flowlabel.c 2005-12-02 01:34:35.000000000 +0200
+@@ -225,20 +225,16 @@
+ struct ip6_flowlabel * fl,
+ struct ipv6_txoptions * fopt)
+ {
+- struct ipv6_txoptions * fl_opt = fl ? fl->opt : NULL;
++ struct ipv6_txoptions * fl_opt = fl->opt;
+
+- if (fopt == NULL || fopt->opt_flen == 0) {
+- if (!fl_opt || !fl_opt->dst0opt || fl_opt->srcrt)
+- return fl_opt;
+- }
++ if (fopt == NULL || fopt->opt_flen == 0)
++ return fl_opt;
+
+ if (fl_opt != NULL) {
+ opt_space->hopopt = fl_opt->hopopt;
+- opt_space->dst0opt = fl_opt->srcrt ? fl_opt->dst0opt : NULL;
++ opt_space->dst0opt = fl_opt->dst0opt;
+ opt_space->srcrt = fl_opt->srcrt;
+ opt_space->opt_nflen = fl_opt->opt_nflen;
+- if (fl_opt->dst0opt && !fl_opt->srcrt)
+- opt_space->opt_nflen -= ipv6_optlen(fl_opt->dst0opt);
+ } else {
+ if (fopt->opt_nflen == 0)
+ return fopt;
+diff -Naur linux-2.6.14-omap2/net/ipv6/raw.c linux-h6300-omap2-2.6.14.3/net/ipv6/raw.c
+--- linux-2.6.14-omap2/net/ipv6/raw.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv6/raw.c 2005-12-02 01:34:35.000000000 +0200
+@@ -756,7 +756,9 @@
+ }
+ if (opt == NULL)
+ opt = np->opt;
+- opt = fl6_merge_options(&opt_space, flowlabel, opt);
++ if (flowlabel)
++ opt = fl6_merge_options(&opt_space, flowlabel, opt);
++ opt = ipv6_fixup_options(&opt_space, opt);
+
+ fl.proto = proto;
+ rawv6_probe_proto_opt(&fl, msg);
+diff -Naur linux-2.6.14-omap2/net/ipv6/udp.c linux-h6300-omap2-2.6.14.3/net/ipv6/udp.c
+--- linux-2.6.14-omap2/net/ipv6/udp.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/ipv6/udp.c 2005-12-02 01:34:35.000000000 +0200
+@@ -778,7 +778,9 @@
+ }
+ if (opt == NULL)
+ opt = np->opt;
+- opt = fl6_merge_options(&opt_space, flowlabel, opt);
++ if (flowlabel)
++ opt = fl6_merge_options(&opt_space, flowlabel, opt);
++ opt = ipv6_fixup_options(&opt_space, opt);
+
+ fl->proto = IPPROTO_UDP;
+ ipv6_addr_copy(&fl->fl6_dst, daddr);
+diff -Naur linux-2.6.14-omap2/net/netfilter/nf_queue.c linux-h6300-omap2-2.6.14.3/net/netfilter/nf_queue.c
+--- linux-2.6.14-omap2/net/netfilter/nf_queue.c 2005-10-28 03:02:08.000000000 +0300
++++ linux-h6300-omap2-2.6.14.3/net/netfilter/nf_queue.c 2005-12-02 01:34:35.000000000 +0200
+@@ -117,7 +117,7 @@
+
+ /* QUEUE == DROP if noone is waiting, to be safe. */
+ read_lock(&queue_handler_lock);
+- if (!queue_handler[pf]->outfn) {
++ if (!queue_handler[pf] || !queue_handler[pf]->outfn) {
+ read_unlock(&queue_handler_lock);
+ kfree_skb(*skb);
+ return 1;
+diff -Naur linux-2.6.14-omap2/sound/arm/Kconfig linux-h6300-omap2-2.6.14.3/sound/arm/Kconfig
+--- linux-2.6.14-omap2/sound/arm/Kconfig 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/Kconfig 2005-11-13 02:15:10.000000000 +0200
+@@ -45,5 +45,15 @@
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-omap-aic23.
++
++config SND_OMAP_TSC2101
++ tristate "OMAP TSC2101 driver (iPaq H63xx)"
++ depends ARCH_OMAP && SND
++ select SND_PCM
++ help
++ ALSA driver for TI TSC2101.
++
++ To compile this driver as a module, choose M here: the module
++ will be called snd-omap-tsc2101.
+
+ endmenu
+diff -Naur linux-2.6.14-omap2/sound/arm/Makefile linux-h6300-omap2-2.6.14.3/sound/arm/Makefile
+--- linux-2.6.14-omap2/sound/arm/Makefile 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/Makefile 2005-11-13 02:15:10.000000000 +0200
+@@ -16,3 +16,6 @@
+
+ obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-aic23.o
+ snd-omap-aic23-objs := omap-aic23.o omap-alsa-dma.o omap-alsa-mixer.o
++
++obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-tsc2101.o
++snd-omap-tsc2101-objs := omap-tsc2101.o omap-alsa-dma.o
+diff -Naur linux-2.6.14-omap2/sound/arm/omap-aic23.c linux-h6300-omap2-2.6.14.3/sound/arm/omap-aic23.c
+--- linux-2.6.14-omap2/sound/arm/omap-aic23.c 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/omap-aic23.c 2005-11-13 02:15:10.000000000 +0200
+@@ -262,144 +262,6 @@
+ }
+
+ /*
+- * DMA functions
+- * Depends on omap-aic23-dma.c functions and (omap) dma.c
+- *
+- */
+-#define DMA_BUF_SIZE 1024 * 8
+-
+-static int audio_dma_request(struct audio_stream *s,
+- void (*callback) (void *))
+-{
+- int err;
+-
+- err = omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);
+- if (err < 0)
+- printk(KERN_ERR "unable to grab audio dma 0x%x\n",
+- s->dma_dev);
+- return err;
+-}
+-
+-static int audio_dma_free(struct audio_stream *s)
+-{
+- int err = 0;
+-
+- err = omap_free_sound_dma(s, &s->lch);
+- if (err < 0)
+- printk(KERN_ERR "Unable to free audio dma channels!\n");
+- return err;
+-}
+-
+-/*
+- * This function should calculate the current position of the dma in the
+- * buffer. It will help alsa middle layer to continue update the buffer.
+- * Its correctness is crucial for good functioning.
+- */
+-static u_int audio_get_dma_pos(struct audio_stream *s)
+-{
+- snd_pcm_substream_t *substream = s->stream;
+- snd_pcm_runtime_t *runtime = substream->runtime;
+- unsigned int offset;
+- unsigned long flags;
+- dma_addr_t count;
+- ADEBUG();
+-
+- /* this must be called w/ interrupts locked as requested in dma.c */
+- spin_lock_irqsave(&s->dma_lock, flags);
+-
+- /* For the current period let's see where we are */
+- count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
+-
+- spin_unlock_irqrestore(&s->dma_lock, flags);
+-
+- /* Now, the position related to the end of that period */
+- offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
+-
+- if (offset >= runtime->buffer_size || offset < 0)
+- offset = 0;
+-
+- return offset;
+-}
+-
+-/*
+- * this stops the dma and clears the dma ptrs
+- */
+-static void audio_stop_dma(struct audio_stream *s)
+-{
+- unsigned long flags;
+- ADEBUG();
+-
+- spin_lock_irqsave(&s->dma_lock, flags);
+- s->active = 0;
+- s->period = 0;
+- s->periods = 0;
+-
+- /* this stops the dma channel and clears the buffer ptrs */
+- omap_audio_stop_dma(s);
+-
+- omap_clear_sound_dma(s);
+-
+- spin_unlock_irqrestore(&s->dma_lock, flags);
+-}
+-
+-/*
+- * Main dma routine, requests dma according where you are in main alsa buffer
+- */
+-static void audio_process_dma(struct audio_stream *s)
+-{
+- snd_pcm_substream_t *substream = s->stream;
+- snd_pcm_runtime_t *runtime;
+- unsigned int dma_size;
+- unsigned int offset;
+- int ret;
+-
+- runtime = substream->runtime;
+- if (s->active) {
+- dma_size = frames_to_bytes(runtime, runtime->period_size);
+- offset = dma_size * s->period;
+- snd_assert(dma_size <= DMA_BUF_SIZE,);
+- ret =
+- omap_start_sound_dma(s,
+- (dma_addr_t) runtime->dma_area +
+- offset, dma_size);
+- if (ret) {
+- printk(KERN_ERR
+- "audio_process_dma: cannot queue DMA buffer (%i)\n",
+- ret);
+- return;
+- }
+-
+- s->period++;
+- s->period %= runtime->periods;
+- s->periods++;
+- s->offset = offset;
+- }
+-}
+-
+-/*
+- * This is called when dma IRQ occurs at the end of each transmited block
+- */
+-void audio_dma_callback(void *data)
+-{
+- struct audio_stream *s = data;
+-
+- /*
+- * If we are getting a callback for an active stream then we inform
+- * the PCM middle layer we've finished a period
+- */
+- if (s->active)
+- snd_pcm_period_elapsed(s->stream);
+-
+- spin_lock(&s->dma_lock);
+- if (s->periods > 0) {
+- s->periods--;
+- }
+- audio_process_dma(s);
+- spin_unlock(&s->dma_lock);
+-}
+-
+-
+-/*
+ * Alsa section
+ * PCM settings and callbacks
+ */
+diff -Naur linux-2.6.14-omap2/sound/arm/omap-aic23.h linux-h6300-omap2-2.6.14.3/sound/arm/omap-aic23.h
+--- linux-2.6.14-omap2/sound/arm/omap-aic23.h 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/omap-aic23.h 2005-11-13 02:15:10.000000000 +0200
+@@ -43,6 +43,7 @@
+ #include <asm/arch/dma.h>
+ #include <sound/core.h>
+ #include <sound/pcm.h>
++#include "omap-alsa-dma.h"
+
+ #define DEFAULT_OUTPUT_VOLUME 0x60
+ #define DEFAULT_INPUT_VOLUME 0x00 /* 0 ==> mute line in */
+@@ -67,27 +68,6 @@
+ #define DEFAULT_ANALOG_AUDIO_CONTROL DAC_SELECTED | STE_ENABLED | BYPASS_ON | INSEL_MIC | MICB_20DB
+
+ /*
+- * Buffer management for alsa and dma
+- */
+-struct audio_stream {
+- char *id; /* identification string */
+- int stream_id; /* numeric identification */
+- int dma_dev; /* dma number of that device */
+- int *lch; /* Chain of channels this stream is linked to */
+- char started; /* to store if the chain was started or not */
+- int dma_q_head; /* DMA Channel Q Head */
+- int dma_q_tail; /* DMA Channel Q Tail */
+- char dma_q_count; /* DMA Channel Q Count */
+- int active:1; /* we are using this stream for transfer now */
+- int period; /* current transfer period */
+- int periods; /* current count of periods registerd in the DMA engine */
+- spinlock_t dma_lock; /* for locking in DMA operations */
+- snd_pcm_substream_t *stream; /* the pcm stream */
+- unsigned linked:1; /* dma channels linked */
+- int offset; /* store start position of the last period in the alsa buffer */
+-};
+-
+-/*
+ * Alsa card structure for aic23
+ */
+ struct snd_card_omap_aic23 {
+@@ -99,7 +79,6 @@
+
+ /*********** Function Prototypes *************************/
+
+-void audio_dma_callback(void *);
+ int snd_omap_mixer(struct snd_card_omap_aic23 *);
+ void snd_omap_init_mixer(void);
+ /* Clock functions */
+diff -Naur linux-2.6.14-omap2/sound/arm/omap-alsa-dma.c linux-h6300-omap2-2.6.14.3/sound/arm/omap-alsa-dma.c
+--- linux-2.6.14-omap2/sound/arm/omap-alsa-dma.c 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/omap-alsa-dma.c 2005-11-13 02:15:10.000000000 +0200
+@@ -440,6 +440,134 @@
+ return;
+ }
+
++int audio_dma_request(struct audio_stream *s,
++ void (*callback) (void *))
++{
++ int err;
++
++ err = omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);
++ if (err < 0)
++ printk(KERN_ERR "unable to grab audio dma 0x%x\n",
++ s->dma_dev);
++ return err;
++}
++
++int audio_dma_free(struct audio_stream *s)
++{
++ int err = 0;
++
++ err = omap_free_sound_dma(s, &s->lch);
++ if (err < 0)
++ printk(KERN_ERR "Unable to free audio dma channels!\n");
++ return err;
++}
++
++/*
++ * This function should calculate the current position of the dma in the
++ * buffer. It will help alsa middle layer to continue update the buffer.
++ * Its correctness is crucial for good functioning.
++ */
++u_int audio_get_dma_pos(struct audio_stream *s)
++{
++ snd_pcm_substream_t *substream = s->stream;
++ snd_pcm_runtime_t *runtime = substream->runtime;
++ unsigned int offset;
++ unsigned long flags;
++ dma_addr_t count;
++
++ /* this must be called w/ interrupts locked as requested in dma.c */
++ spin_lock_irqsave(&s->dma_lock, flags);
++
++ /* For the current period let's see where we are */
++ count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
++
++ spin_unlock_irqrestore(&s->dma_lock, flags);
++
++ /* Now, the position related to the end of that period */
++ offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
++
++ if (offset >= runtime->buffer_size || offset < 0)
++ offset = 0;
++
++ return offset;
++}
++
++/*
++ * this stops the dma and clears the dma ptrs
++ */
++void audio_stop_dma(struct audio_stream *s)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&s->dma_lock, flags);
++ s->active = 0;
++ s->period = 0;
++ s->periods = 0;
++
++ /* this stops the dma channel and clears the buffer ptrs */
++ omap_audio_stop_dma(s);
++
++ omap_clear_sound_dma(s);
++
++ spin_unlock_irqrestore(&s->dma_lock, flags);
++}
++
++/*
++ * Main dma routine, requests dma according where you are in main alsa buffer
++ */
++void audio_process_dma(struct audio_stream *s)
++{
++ snd_pcm_substream_t *substream = s->stream;
++ snd_pcm_runtime_t *runtime;
++ unsigned int dma_size;
++ unsigned int offset;
++ int ret;
++
++ runtime = substream->runtime;
++ if (s->active) {
++ dma_size = frames_to_bytes(runtime, runtime->period_size);
++ offset = dma_size * s->period;
++ snd_assert(dma_size <= DMA_BUF_SIZE,);
++ ret =
++ omap_start_sound_dma(s,
++ (dma_addr_t) runtime->dma_area +
++ offset, dma_size);
++ if (ret) {
++ printk(KERN_ERR
++ "audio_process_dma: cannot queue DMA buffer (%i)\n",
++ ret);
++ return;
++ }
++
++ s->period++;
++ s->period %= runtime->periods;
++ s->periods++;
++ s->offset = offset;
++ }
++}
++
++/*
++ * This is called when dma IRQ occurs at the end of each transmited block
++ */
++void audio_dma_callback(void *data)
++{
++ struct audio_stream *s = data;
++
++ /*
++ * If we are getting a callback for an active stream then we inform
++ * the PCM middle layer we've finished a period
++ */
++ if (s->active)
++ snd_pcm_period_elapsed(s->stream);
++
++ spin_lock(&s->dma_lock);
++ if (s->periods > 0) {
++ s->periods--;
++ }
++ audio_process_dma(s);
++ spin_unlock(&s->dma_lock);
++}
++
+ MODULE_AUTHOR("Texas Instruments");
+ MODULE_DESCRIPTION
+ ("Common DMA handling for Audio driver on OMAP processors");
+diff -Naur linux-2.6.14-omap2/sound/arm/omap-alsa-dma.h linux-h6300-omap2-2.6.14.3/sound/arm/omap-alsa-dma.h
+--- linux-2.6.14-omap2/sound/arm/omap-alsa-dma.h 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/omap-alsa-dma.h 2005-11-13 02:15:10.000000000 +0200
+@@ -30,7 +30,13 @@
+
+ /************************** INCLUDES *************************************/
+
+-#include "omap-aic23.h"
++/* h6300 tsc2101 changes start */
++//#include "omap-aic23.h"
++#include <sound/driver.h>
++#include <asm/arch/dma.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++/* h6300 tsc2101 changes end */
+
+ /************************** GLOBAL MACROS *************************************/
+
+@@ -39,8 +45,33 @@
+ #define DMA_FREE(s) omap_free_sound_dma(s, &s->lch)
+ #define DMA_CLEAR(s) omap_clear_sound_dma(s)
+
++/* h6300 tsc2101 changes start */
++#define DMA_BUF_SIZE 1024 * 8
++
+ /************************** GLOBAL DATA STRUCTURES *********************************/
+
++/*
++ * Buffer management for alsa and dma
++ */
++struct audio_stream {
++ char *id; /* identification string */
++ int stream_id; /* numeric identification */
++ int dma_dev; /* dma number of that device */
++ int *lch; /* Chain of channels this stream is linked to */
++ char started; /* to store if the chain was started or not */
++ int dma_q_head; /* DMA Channel Q Head */
++ int dma_q_tail; /* DMA Channel Q Tail */
++ char dma_q_count; /* DMA Channel Q Count */
++ int active:1; /* we are using this stream for transfer now */
++ int period; /* current transfer period */
++ int periods; /* current count of periods registerd in the DMA engine */
++ spinlock_t dma_lock; /* for locking in DMA operations */
++ snd_pcm_substream_t *stream; /* the pcm stream */
++ unsigned linked:1; /* dma channels linked */
++ int offset; /* store start position of the last period in the alsa buffer */
++};
++/* h6300 tsc2101 changes end */
++
+ typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+ /**************** ARCH SPECIFIC FUNCIONS *******************************************/
+@@ -54,6 +85,14 @@
+ int omap_start_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
+ u_int dma_size);
+
++/* h6300 tsc2101 changes start */
+ void omap_audio_stop_dma(struct audio_stream *s);
++void audio_dma_callback(void *);
++void audio_process_dma(struct audio_stream *s);
++u_int audio_get_dma_pos(struct audio_stream *s);
++int audio_dma_request(struct audio_stream *s, void (*callback) (void *));
++int audio_dma_free(struct audio_stream *s);
++void audio_stop_dma(struct audio_stream *s);
++/* h6300 tsc2101 changes end */
+
+ #endif
+diff -Naur linux-2.6.14-omap2/sound/arm/omap-tsc2101.c linux-h6300-omap2-2.6.14.3/sound/arm/omap-tsc2101.c
+--- linux-2.6.14-omap2/sound/arm/omap-tsc2101.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/omap-tsc2101.c 2005-11-13 02:15:10.000000000 +0200
+@@ -0,0 +1,665 @@
++#include <linux/config.h>
++#include <sound/driver.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/ioctl.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++
++#ifdef CONFIG_PM
++#include <linux/pm.h>
++#endif
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/arch/dma.h>
++#include <asm/hardware/tsc2101.h>
++#include <../drivers/ssi/omap-tsc2101.h>
++#include <asm/arch/mcbsp.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/initval.h>
++#include <sound/memalloc.h>
++
++#include "omap-alsa-dma.h"
++#include "omap-tsc2101.h"
++
++//#undef DEBUG
++#define DEBUG
++
++#ifdef DEBUG
++#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __FUNCTION__, __LINE__)
++#else
++#define ADEBUG() /* nop */
++#endif
++
++#define TSC2101_MASTER
++
++#define DEFAULT_BITPERSAMPLE 16
++#define AUDIO_RATE_DEFAULT 44100
++#define AUDIO_MCBSP OMAP_MCBSP1
++#define NUMBER_SAMPLE_RATES_SUPPORTED 16
++#define PAGE2_AUDIO_CODEC_REGISTERS (2)
++
++MODULE_AUTHOR("Everett Coleman, Daniel Petrini, David Cohen, Anderson Briglia - INdT");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("OMAP TSC2101 driver for ALSA");
++MODULE_SUPPORTED_DEVICE("{{TSC2101,OMAP TSC2101}}");
++MODULE_ALIAS("omap_mcbsp.1");
++
++static char *id = NULL;
++MODULE_PARM_DESC(id, "OMAP ALSA Driver for TSC2101 chip.");
++
++static struct snd_card_omap_tsc2101 *omap_tsc2101 = NULL;
++
++static struct omap_mcbsp_reg_cfg initial_config_mcbsp = {
++#ifdef CONFIG_MACH_H6300
++ .spcr2 = 0x0005,
++ .spcr1 = 0x0005,
++ .rcr2 = 0x8041,
++ .rcr1 = 0x8041,
++ .xcr2 = 0x00a1,
++ .xcr1 = 0x00a1,
++ .srgr2 = 0xb000,
++ .srgr1 = 0xb000,
++ .pcr0 = 0x0081,
++#else
++ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
++ .spcr1 = RINTM(3) | RRST,
++ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
++ RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
++ .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
++ .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
++ XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
++ .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
++ .srgr1 = FWID(15),
++ .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
++
++ /* platform specific initialization */
++# if defined(CONFIG_MACH_OMAP_H2)
++ .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
++# elif defined(CONFIG_MACH_OMAP_H3)
++
++# ifndef TSC2101_MASTER
++ .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
++# else
++ .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP,
++# endif /* !TSC2101_MASTER */
++# endif /* CONFIG_MACH_OMAP_H2 */
++#endif /* CONFIG_MACH_H6300 */
++};
++
++static unsigned int rates[] = {
++ 7350, 8000, 8018, 8727,
++ 8820, 9600, 11025, 12000,
++ 14700, 16000, 22050, 24000,
++ 29400, 32000, 44100, 48000
++};
++
++static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
++ .count = ARRAY_SIZE(rates),
++ .list = rates,
++ .mask = 0,
++};
++
++struct sample_rate_reg_info {
++ u16 sample_rate;
++ u8 divisor;
++ u8 fs_44kHz;
++};
++
++static const struct sample_rate_reg_info
++reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
++ {48000, 0, 0}, {44100, 0, 1}, {32000, 1, 0}, {29400, 1, 1},
++ {24000, 2, 0}, {22050, 2, 1}, {16000, 3, 0}, {14700, 3, 1},
++ {12000, 4, 0}, {11025, 4, 1}, {9600, 5, 0}, {8820, 5, 1},
++ {8727, 6, 0}, {8018, 6, 1}, {8000, 7, 0}, {7350, 7, 1}
++};
++
++static snd_pcm_hardware_t snd_omap_tsc2101_capture = {
++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
++ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
++ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
++ SNDRV_PCM_RATE_KNOT),
++ .rate_min = 7350,
++ .rate_max = 48000,
++ .channels_min = 2,
++ .channels_max = 2,
++ .buffer_bytes_max = 128 * 1024,
++ .period_bytes_min = 32,
++ .period_bytes_max = 8 * 1024,
++ .periods_min = 16,
++ .periods_max = 255,
++ .fifo_size = 0,
++};
++
++static snd_pcm_hardware_t snd_omap_tsc2101_playback = {
++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE),
++ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
++ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
++ SNDRV_PCM_RATE_KNOT),
++ .rate_min = 7350,
++ .rate_max = 48000,
++ .channels_min = 2,
++ .channels_max = 2,
++ .buffer_bytes_max = 128 * 1024,
++ .period_bytes_min = 32,
++ .period_bytes_max = 8 * 1024,
++ .periods_min = 16,
++ .periods_max = 255,
++ .fifo_size = 0,
++};
++
++static __inline__ void
++audio_tsc2101_write (u8 address, u16 data) {
++ omap_tsc2101_write (PAGE2_AUDIO_CODEC_REGISTERS, address, data);
++} /* audio_tsc2101_write */
++
++static __inline__ u16
++audio_tsc2101_read (u8 address) {
++ return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
++} /* audio_tsc2101_read */
++
++
++
++
++
++
++
++
++
++
++void
++snd_omap_tsc2101_free (snd_card_t * card) {
++ struct snd_card_omap_tsc2101 *chip = card->private_data;
++ ADEBUG();
++
++ /* TODO
++ * Turn off codec after it is done.
++ * Can't do it immediately, since it may still have
++ * buffered data.
++ */
++
++
++
++
++ audio_dma_free (&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
++ audio_dma_free (&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
++} /* snd_omap_tsc2101_free */
++
++#ifdef CONFIG_PM
++static int
++snd_omap_tsc2101_suspend (snd_card_t * card, pm_message_t state) {
++ // TODO: function
++ return 0;
++} /* snd_omap_tsc2101_suspend */
++
++static int
++snd_omap_tsc2101_resume (snd_card_t * card) {
++ // TODO: function
++ return 0;
++} /* snd_omap_tsc2101_resume */
++
++static int
++omap_tsc2101_suspend (struct device *dev, pm_message_t state, u32 level) {
++ // TODO: function
++ return 0;
++} /* omap_tsc2101_suspend */
++
++static int
++omap_tsc2101_resume (struct device *dev, u32 level) {
++ // TODO: function
++ return 0;
++} /* omap_tsc2101_resume */
++
++#else
++# define snd_omap_tsc2101_suspend NULL
++# define snd_omap_tsc2101_resume NULL
++# define omap_tsc2101_suspend NULL
++# define omap_tsc2101_resume NULL
++#endif /* CONFIG_PM */
++
++static inline void
++tsc2101_configure (void) {
++ audio_tsc2101_write (TSC2101_CODEC_POWER_CTRL, 0x0000);
++
++ /*Mute Analog Sidetone */
++ /*Select MIC_INHED input for headset */
++ /*Cell Phone In not connected */
++ audio_tsc2101_write (TSC2101_MIXER_PGA_CTRL,
++ MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC);
++
++ /* Set record source */
++ // TODO:MIXER tsc2101_update (SET_RECSRC, tsc2101_local.recsrc);
++
++ /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
++ /* 1dB AGC hysteresis */
++ /* MICes bias 2V */
++ audio_tsc2101_write (TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
++
++ /* Set codec output volume */
++ audio_tsc2101_write (TSC2101_DAC_GAIN_CTRL, 0x0000);
++
++ /* DAC left and right routed to SPK2 */
++ /* SPK1/2 unmuted */
++ audio_tsc2101_write (TSC2101_AUDIO_CTRL_5,
++ AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
++ AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
++ AC5_HDSCPTC);
++
++ /* OUT8P/N muted, CPOUT muted */
++
++ audio_tsc2101_write (TSC2101_AUDIO_CTRL_6,
++ AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
++ AC6_VGNDSCPTC);
++
++ /* Headset/Hook switch detect disabled */
++ audio_tsc2101_write (TSC2101_AUDIO_CTRL_7, 0x0000);
++
++ /* Left line input volume control */
++ // TODO:MIXER tsc2101_update (SET_LINE, tsc2101_local.line);
++
++ /* mic input volume control */
++ // TODO:MIXER tsc2101_update(SET_MIC, tsc2101_local.mic);
++
++ /* Left/Right headphone channel volume control */
++ /* Zero-cross detect on */
++ // TODO:MIXER tsc2101_update (SET_VOLUME, tsc2101_local.volume);
++} /* tsc2101_configure */
++
++static int
++snd_card_omap_tsc2101_open (snd_pcm_substream_t * substream) {
++ struct snd_card_omap_tsc2101 *chip = snd_pcm_substream_chip(substream);
++ snd_pcm_runtime_t *runtime = substream->runtime;
++ int stream_id = substream->pstr->stream;
++ int err;
++ ADEBUG();
++
++ chip->s[stream_id].stream = substream;
++
++// TODO: turn audio on, power on
++
++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
++ runtime->hw = snd_omap_tsc2101_playback;
++ else
++ runtime->hw = snd_omap_tsc2101_capture;
++ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
++ return err;
++ if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)
++ return err;
++ return 0;
++} /* snd_card_omap_tsc2101_open */
++
++static int
++snd_card_omap_tsc2101_close (snd_pcm_substream_t *substream) {
++ struct snd_card_omap_tsc2101 *chip = snd_pcm_substream_chip(substream);
++ ADEBUG();
++
++ // TODO: omap_tsc2101_clock_off();
++ chip->s[substream->pstr->stream].stream = NULL;
++ return 0;
++} /* snd_card_omap_tsc2101_close */
++
++static int
++snd_omap_tsc2101_hw_params (snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params) {
++ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
++} /* snd_omap_tsc2101_hw_params */
++
++static int
++snd_omap_tsc2101_hw_free (snd_pcm_substream_t *substream) {
++ return snd_pcm_lib_free_pages(substream);
++} /* snd_omap_tsc2101_hw_free */
++
++static int
++omap_tsc2101_set_samplerate (struct snd_card_omap_tsc2101 *omap_tsc2101, long rate) {
++ u8 count = 0;
++ u16 data = 0;
++ int clkgdv = 0;
++
++ if (rate >= 48000)
++ rate = 48000;
++ else if (rate >= 44100)
++ rate = 44100;
++ else if (rate >= 32000)
++ rate = 32000;
++ else if (rate >= 29400)
++ rate = 29400;
++ else if (rate >= 24000)
++ rate = 24000;
++ else if (rate >= 22050)
++ rate = 22050;
++ else if (rate >= 16000)
++ rate = 16000;
++ else if (rate >= 14700)
++ rate = 14700;
++ else if (rate >= 12000)
++ rate = 12000;
++ else if (rate >= 11025)
++ rate = 11025;
++ else if (rate >= 9600)
++ rate = 9600;
++ else if (rate >= 8820)
++ rate = 8820;
++ else if (rate >= 8727)
++ rate = 8727;
++ else if (rate >= 8018)
++ rate = 8018;
++ else if (rate >= 8000)
++ rate = 8000;
++ else
++ rate = 7350;
++
++ /* wait for any frame to complete */
++ udelay(125);
++
++ /* Search for the right sample rate */
++ while ((reg_info[count].sample_rate != rate) &&
++ (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
++ count++;
++ }
++ if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
++ printk(KERN_ERR "Invalid Sample Rate %d requested\n",
++ (int)rate);
++ return -EPERM;
++ }
++
++ /* Set AC1 */
++ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1);
++ /*Clear prev settings */
++ data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
++ data |=
++ AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count].
++ divisor);
++ audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data);
++
++ /* Set the AC3 */
++ data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3);
++ /*Clear prev settings */
++ data &= ~(AC3_REFFS | AC3_SLVMS);
++ data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
++#ifdef TSC2101_MASTER
++ data |= AC3_SLVMS;
++#endif /* #ifdef TSC2101_MASTER */
++ audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data);
++
++ /* program the PLLs */
++ if (reg_info[count].fs_44kHz) {
++ /* 44.1 khz - 12 MHz Mclk */
++ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */
++ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */
++ } else {
++ /* 48 khz - 12 Mhz Mclk */
++ audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */
++ audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */
++ }
++
++ omap_tsc2101->samplerate = rate;
++
++ /* Set the sample rate */
++#ifndef TSC2101_MASTER
++ clkgdv =
++ DEFAULT_MCBSP_CLOCK / (rate *
++ (DEFAULT_BITPERSAMPLE * 2 - 1));
++ if (clkgdv)
++ initial_config_mcbsp.srgr1 =
++ (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
++ else
++ return (1);
++
++ /* Stereo Mode */
++ initial_config_mcbsp.srgr2 =
++ (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
++#else
++ initial_config_mcbsp.srgr1 =
++ (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
++ initial_config_mcbsp.srgr2 =
++ ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
++
++#endif /* end of #ifdef TSC2101_MASTER */
++ omap_mcbsp_config(AUDIO_MCBSP, &initial_config_mcbsp);
++ return 0;
++} /* omap_tsc2101_set_samplerate */
++
++static int
++snd_omap_tsc2101_prepare (snd_pcm_substream_t *substream) {
++ struct snd_card_omap_tsc2101 *chip = snd_pcm_substream_chip(substream);
++ snd_pcm_runtime_t *runtime = substream->runtime;
++ struct audio_stream *s = &chip->s[substream->pstr->stream];
++
++ /* set requested samplerate */
++ omap_tsc2101_set_samplerate (chip, runtime->rate);
++
++ s->period = 0;
++ s->periods = 0;
++ return 0;
++} /* snd_omap_tsc2101_prepare */
++
++static int
++snd_omap_tsc2101_trigger (snd_pcm_substream_t *substream, int cmd) {
++ struct snd_card_omap_tsc2101 *chip = snd_pcm_substream_chip(substream);
++ int stream_id = substream->pstr->stream;
++ struct audio_stream *s = &chip->s[stream_id];
++ int err = 0;
++ ADEBUG();
++
++ /* note local interrupts are already disabled in the midlevel code */
++ spin_lock(&s->dma_lock);
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ /* requested stream startup */
++ s->active = 1;
++ audio_process_dma(s);
++ break;
++ case SNDRV_PCM_TRIGGER_STOP:
++ /* requested stream shutdown */
++ audio_stop_dma(s);
++ break;
++ default:
++ err = -EINVAL;
++ break;
++ }
++ spin_unlock(&s->dma_lock);
++ return err;
++} /* snd_omap_tsc2101_trigger */
++
++static snd_pcm_uframes_t
++snd_omap_tsc2101_pointer (snd_pcm_substream_t *substream) {
++ struct snd_card_omap_tsc2101 *chip = snd_pcm_substream_chip(substream);
++ return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
++} /* snd_omap_tsc2101_pointer */
++
++static snd_pcm_ops_t snd_card_omap_tsc2101_playback_ops = {
++ .open = snd_card_omap_tsc2101_open,
++ .close = snd_card_omap_tsc2101_close,
++ .ioctl = snd_pcm_lib_ioctl,
++ .hw_params = snd_omap_tsc2101_hw_params,
++ .hw_free = snd_omap_tsc2101_hw_free,
++ .prepare = snd_omap_tsc2101_prepare,
++ .trigger = snd_omap_tsc2101_trigger,
++ .pointer = snd_omap_tsc2101_pointer,
++};
++
++static snd_pcm_ops_t snd_card_omap_tsc2101_capture_ops = {
++ .open = snd_card_omap_tsc2101_open,
++ .close = snd_card_omap_tsc2101_close,
++ .ioctl = snd_pcm_lib_ioctl,
++ .hw_params = snd_omap_tsc2101_hw_params,
++ .hw_free = snd_omap_tsc2101_hw_free,
++ .prepare = snd_omap_tsc2101_prepare,
++ .trigger = snd_omap_tsc2101_trigger,
++ .pointer = snd_omap_tsc2101_pointer,
++};
++
++static void
++omap_tsc2101_audio_init (struct snd_card_omap_tsc2101 *omap_tsc2101) {
++ /* Setup DMA stuff */
++ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa TSC2101 out";
++ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
++ SNDRV_PCM_STREAM_PLAYBACK;
++ omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
++ OMAP_DMA_MCBSP1_TX;
++
++ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa TSC2101 in";
++ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
++ SNDRV_PCM_STREAM_CAPTURE;
++ omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
++ OMAP_DMA_MCBSP1_RX;
++
++ /* configuring the McBSP */
++ omap_mcbsp_request (AUDIO_MCBSP);
++
++ /* if configured, then stop mcbsp */
++ omap_mcbsp_stop (AUDIO_MCBSP);
++
++ omap_mcbsp_config (AUDIO_MCBSP, &initial_config_mcbsp);
++ omap_mcbsp_start (AUDIO_MCBSP);
++
++ tsc2101_configure ();
++} /* omap_tsc2101_audio_init */
++
++static int __init
++snd_card_omap_tsc2101_pcm (struct snd_card_omap_tsc2101 *omap_tsc2101, int device) {
++ snd_pcm_t *pcm;
++ int err;
++ ADEBUG();
++
++ if ((err = snd_pcm_new (omap_tsc2101->card, "TSC2101 PCM", device, 1, 1, &pcm)) < 0)
++ return err;
++
++ snd_pcm_lib_preallocate_pages_for_all (pcm,
++ SNDRV_DMA_TYPE_CONTINUOUS,
++ snd_dma_continuous_data (GFP_KERNEL),
++ 128 * 1024, 128 * 1024);
++
++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
++ &snd_card_omap_tsc2101_playback_ops);
++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
++ &snd_card_omap_tsc2101_capture_ops);
++
++ pcm->private_data = omap_tsc2101;
++ pcm->info_flags = 0;
++ strcpy (pcm->name, "omap tsc2101 pcm");
++
++ omap_tsc2101_audio_init (omap_tsc2101);
++
++ audio_dma_request(&omap_tsc2101->s[SNDRV_PCM_STREAM_PLAYBACK],
++ audio_dma_callback);
++ audio_dma_request(&omap_tsc2101->s[SNDRV_PCM_STREAM_CAPTURE],
++ audio_dma_callback);
++
++ omap_tsc2101->pcm = pcm;
++ return 0;
++} /* snd_card_omap_tsc2101_pcm */
++
++static int __init
++snd_omap_tsc2101_probe (struct device *dev) {
++ int err = 0;
++ snd_card_t *card;
++ ADEBUG();
++
++ if ((card = snd_card_new (-1, id, THIS_MODULE, sizeof (omap_tsc2101))) == NULL)
++ return -ENOMEM;
++ if ((omap_tsc2101 = kcalloc (1, sizeof (*omap_tsc2101), GFP_KERNEL)) == NULL)
++ return -ENOMEM;
++
++ card->private_data = (void *)omap_tsc2101;
++ card->private_free = snd_omap_tsc2101_free;
++ omap_tsc2101->card = card;
++ omap_tsc2101->samplerate = AUDIO_RATE_DEFAULT;
++
++ spin_lock_init(&omap_tsc2101->s[0].dma_lock);
++ spin_lock_init(&omap_tsc2101->s[1].dma_lock);
++
++ // TODO: setup mixer (fail, goto nodev)
++
++ if ((err = snd_card_omap_tsc2101_pcm (omap_tsc2101, 0)) < 0)
++ goto nodev;
++
++ snd_card_set_pm_callback (card, snd_omap_tsc2101_suspend, snd_omap_tsc2101_resume, omap_tsc2101);
++
++ strcpy (card->driver, "TSC2101");
++ strcpy (card->shortname, "TI TSC2101");
++ strcpy (card->longname, "TI OMAP TSC2101");
++
++ // TODO: init mixer
++
++ if ((err = snd_card_register (card)) == 0) {
++ printk(KERN_INFO "TSC2101 audio support initialized\n");
++ dev_set_drvdata(dev, card);
++ return 0;
++ }
++
++nodev:
++ printk (KERN_ERR "failed to initialize TSC2101\n");
++ snd_omap_tsc2101_free (card);
++ return err;
++} /* snd_omap_tsc2101_probe */
++
++static int
++snd_omap_tsc2101_remove (struct device *dev) {
++ snd_card_t *card = dev_get_drvdata(dev);
++ struct snd_card_omap_tsc2101 *chip = card->private_data;
++
++ snd_card_free(card);
++ omap_tsc2101 = NULL;
++ card->private_data = NULL;
++ kfree (chip);
++ dev_set_drvdata (dev, NULL);
++ return 0;
++} /* snd_omap_tsc2101_remove */
++
++static struct device_driver omap_alsa_driver = {
++ .name = "omap_mcbsp",
++ .bus = &platform_bus_type,
++ .probe = snd_omap_tsc2101_probe,
++ .remove = snd_omap_tsc2101_remove,
++ .suspend = omap_tsc2101_suspend,
++ .resume = omap_tsc2101_resume,
++};
++
++static void
++omap_alsa_device_release (struct device *dev) {
++ /* Nothing */
++}
++
++static struct platform_device omap_alsa_device = {
++ .name = "omap_mcbsp",
++ .id = -1,
++ .dev = {
++ .release = omap_alsa_device_release,
++ },
++};
++
++static int __init
++omap_tsc2101_init (void) {
++ int err;
++
++ ADEBUG();
++ if ((err = platform_device_register (&omap_alsa_device)) != 0)
++ return err;
++ if ((err = driver_register (&omap_alsa_driver)) != 0)
++ platform_device_unregister (&omap_alsa_device);
++ return err;
++} /* omap_tsc2101_init */
++
++static void __exit
++omap_tsc2101_exit (void) {
++ ADEBUG();
++ driver_unregister (&omap_alsa_driver);
++ platform_device_unregister (&omap_alsa_device);
++} /* omap_tsc2101_exit */
++
++module_init (omap_tsc2101_init);
++module_exit (omap_tsc2101_exit);
+diff -Naur linux-2.6.14-omap2/sound/arm/omap-tsc2101.h linux-h6300-omap2-2.6.14.3/sound/arm/omap-tsc2101.h
+--- linux-2.6.14-omap2/sound/arm/omap-tsc2101.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/arm/omap-tsc2101.h 2005-11-13 02:15:10.000000000 +0200
+@@ -0,0 +1,13 @@
++#ifndef __OMAP_AUDIO_TSC2101_H
++#define __OMAP_AUDIO_TSC2101_H
++
++# include "omap-alsa-dma.h"
++
++struct snd_card_omap_tsc2101 {
++ snd_card_t *card;
++ snd_pcm_t *pcm;
++ long samplerate;
++ struct audio_stream s[2]; /* playback & capture */
++};
++
++#endif /* __OMAP_AUDIO_TSC2101_H */
+diff -Naur linux-2.6.14-omap2/sound/oss/Kconfig linux-h6300-omap2-2.6.14.3/sound/oss/Kconfig
+--- linux-2.6.14-omap2/sound/oss/Kconfig 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/oss/Kconfig 2005-10-22 03:52:45.000000000 +0300
+@@ -12,7 +12,7 @@
+
+ config SOUND_OMAP_TSC2101
+ tristate "TSC2101 Stereo Codec"
+- depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 )
++ depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H6300)
+ select OMAP_TSC2101
+ select OMAP_UWIRE if ARCH_OMAP
+ ---help---
+diff -Naur linux-2.6.14-omap2/sound/oss/omap-audio-tsc2101.c linux-h6300-omap2-2.6.14.3/sound/oss/omap-audio-tsc2101.c
+--- linux-2.6.14-omap2/sound/oss/omap-audio-tsc2101.c 2005-12-02 01:53:34.000000000 +0200
++++ linux-h6300-omap2-2.6.14.3/sound/oss/omap-audio-tsc2101.c 2005-10-22 03:52:45.000000000 +0300
+@@ -48,7 +48,7 @@
+ #include "omap-audio.h"
+ #include "omap-audio-dma-intfc.h"
+ #include <asm/arch/mcbsp.h>
+-#if CONFIG_ARCH_OMAP16XX
++#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_MACH_OMAP_H6300)
+ #include <../drivers/ssi/omap-uwire.h>
+ #include <asm/arch/dsp_common.h>
+ #else
+@@ -72,6 +72,8 @@
+
+ #if CONFIG_ARCH_OMAP16XX
+ #define PLATFORM_NAME "OMAP16XX"
++#elif CONFIG_MACH_OMAP_H6300
++#define PLATFORM_NAME "OMAP15XX"
+ #endif
+
+ #if CONFIG_ARCH_OMAP16XX
+@@ -90,7 +92,7 @@
+ #define LEAVE_CS 0x80
+
+ /* Select the McBSP For Audio */
+-#if CONFIG_ARCH_OMAP16XX
++#if defined (CONFIG_ARCH_OMAP16XX) || defined(CONFIG_MACH_OMAP_H6300)
+ #define AUDIO_MCBSP OMAP_MCBSP1
+ #else
+ #error "UnSupported Configuration"
+@@ -124,7 +126,7 @@
+ /*********** Debug Macros ********/
+ /* To Generate a rather shrill tone -test the entire path */
+ //#define TONE_GEN
+-/* To Generate a tone for each keyclick - test the tsc,spi paths*/
++///* To Generate a tone for each keyclick - test the tsc,spi paths*/
+ //#define TEST_KEYCLICK
+ /* To dump the tsc registers for debug */
+ //#define TSC_DUMP_REGISTERS
+@@ -215,6 +217,17 @@
+ };
+
+ static struct omap_mcbsp_reg_cfg initial_config = {
++#ifdef CONFIG_MACH_OMAP_H6300
++ .spcr2 = 0x0005,
++ .spcr1 = 0x0005,
++ .rcr2 = 0x8041,
++ .rcr1 = 0x8041,
++ .xcr2 = 0x00a1,
++ .xcr1 = 0x00a1,
++ .srgr2 = 0xb000,
++ .srgr1 = 0xb000,
++ .pcr0 = 0x0081,
++#else
+ .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
+ .spcr1 = RINTM(3) | RRST,
+ .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
+@@ -238,6 +251,7 @@
+ #endif /* tsc Master defs */
+
+ #endif /* platform specific inits */
++#endif /* CONFIG_MACH_OMAP_H6300 */
+ };
+
+ /***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/
+++ /dev/null
-DESCRIPTION = "Linux kernel for h6300 devices."
-MAINTAINER = "Mika Laitio <lamikr@cc.jyu.fi>"
-SECTION = "kernel"
-LICENSE = "GPL"
-
-SRC_URI = "http://www.kernel.org/pub/linux/kernel/v2.6/testing/linux-2.6.14-rc5.tar.bz2 \
- http://www.muru.com/linux/omap/patches/patch-2.6.14-rc5-omap1.bz2;patch=1 \
- file://h6300_omap1_2614rc5.patch;patch=1 \
- file://defconfig"
-
-S = "${WORKDIR}/linux-2.6.14-rc5"
-
-inherit kernel
-
-do_configure_prepend() {
- install -m 0644 ${WORKDIR}/defconfig ${S}/.config
- oe_runmake oldconfig
-}
--- /dev/null
+DESCRIPTION = "Linux kernel for h6300 devices."
+MAINTAINER = "Mika Laitio <lamikr@cc.jyu.fi>"
+SECTION = "kernel"
+LICENSE = "GPL"
+
+SRC_URI = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.14.tar.bz2 \
+ http://www.muru.com/linux/omap/patches/patch-2.6.14-omap2.bz2;patch=1 \
+ file://patch-linux-2614-omap2-to-2614_3-omap1-h6300;patch=1 \
+ file://defconfig"
+
+S = "${WORKDIR}/linux-2.6.14"
+
+inherit kernel
+
+do_configure_prepend() {
+ install -m 0644 ${WORKDIR}/defconfig ${S}/.config
+ oe_runmake oldconfig
+}